Browse Source

第一次上次

YaolongHan 4 years ago
commit
58d11fa26e

+ 3 - 0
.browserslistrc

@@ -0,0 +1,3 @@
+> 1%
+last 2 versions
+not dead

+ 18 - 0
.eslintrc.js

@@ -0,0 +1,18 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true
+  },
+  'extends': [
+    'plugin:vue/essential',
+    'eslint:recommended',
+    '@vue/typescript/recommended'
+  ],
+  parserOptions: {
+    ecmaVersion: 2020
+  },
+  rules: {
+    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
+  }
+}

+ 24 - 0
.gitignore

@@ -0,0 +1,24 @@
+.DS_Store
+node_modules
+/dist
+
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+package-lock.json
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 39 - 0
README.md

@@ -0,0 +1,39 @@
+# plan-demo
+
+## 拉取依赖
+1. 先删除 package.json 中关于平面图依赖包 以下部分
+```
+    "@persagy-web/base": "2.2.1",
+    "@persagy-web/big": "2.2.43",
+    "@persagy-web/draw": "2.2.10",
+    "@persagy-web/graph": "2.2.40",
+```
+2. 设置 npm 指向
+
+```
+npm config set registry https://registry.npmjs.org/
+```
+
+3. 下载其他依赖
+
+```
+npm i
+```
+4. 设置 npm 指向到私服
+
+```
+npm config set registry http://dev.dp.sagacloud.cn:8082/repository/npm-saga/
+```
+5 下载图相关依赖包
+将以下依赖粘贴入 package.json 然后下载
+```
+    "@persagy-web/base": "2.2.1",
+    "@persagy-web/big": "2.2.43",
+    "@persagy-web/draw": "2.2.10",
+    "@persagy-web/graph": "2.2.40",
+```
+6. 下载引擎依赖
+
+```
+npm i
+```

+ 5 - 0
babel.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  presets: [
+    '@vue/cli-plugin-babel/preset'
+  ]
+}

+ 40 - 0
package.json

@@ -0,0 +1,40 @@
+{
+  "name": "plan-demo",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "@persagy-web/base": "2.2.1",
+    "@persagy-web/big": "2.2.43",
+    "@persagy-web/draw": "2.2.10",
+    "@persagy-web/graph": "2.2.40",
+    "axios": "^0.21.0",
+    "core-js": "^3.6.5",
+    "vue": "^2.6.11",
+    "vue-class-component": "^7.2.3",
+    "vue-property-decorator": "^8.4.2",
+    "vue-router": "^3.2.0",
+    "vuex": "^3.4.0"
+  },
+  "devDependencies": {
+    "@typescript-eslint/eslint-plugin": "^2.33.0",
+    "@typescript-eslint/parser": "^2.33.0",
+    "@vue/cli-plugin-babel": "^4.5.0",
+    "@vue/cli-plugin-eslint": "^4.5.0",
+    "@vue/cli-plugin-router": "^4.5.0",
+    "@vue/cli-plugin-typescript": "^4.5.0",
+    "@vue/cli-plugin-vuex": "^4.5.0",
+    "@vue/cli-service": "^4.5.0",
+    "@vue/eslint-config-typescript": "^5.0.2",
+    "eslint": "^6.7.2",
+    "eslint-plugin-vue": "^6.2.2",
+    "less": "^3.0.4",
+    "less-loader": "^5.0.0",
+    "typescript": "~3.9.3",
+    "vue-template-compiler": "^2.6.11"
+  }
+}

BIN
public/favicon.ico


+ 30 - 0
public/index.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title><%= htmlWebpackPlugin.options.title %></title>
+    <script src="<%= BASE_URL %>systemConf.js"></script>
+    <script>
+      window.topo_baseurl = 'http://39.102.40.239:8080'
+      window.img_baseurl = "http://39.97.179.199:8891"
+
+
+      function callByU3d (data) {
+        console.log('here...callByU3d', data)
+      }
+    </script>
+    <style>
+      * {
+        margin: 0;
+        padding: 0;
+      }
+    </style>
+  </head>
+  <body>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 317 - 0
public/systemConf.js

@@ -0,0 +1,317 @@
+/**
+ * 项目配置文件
+ * 主要修改设备类的图标
+ * @author yunxing
+ *
+ * eg:
+ * 如果新增一个设备类的样式,在 __systemConf 下的 equipStyle 中新增一个对象(新增时放到代码的最下边)
+ * equipStyle :{
+ *  defaultEquipStyle,
+ * ...
+ * //新增的设备类样式
+ *  
+ * // 通风风口
+        AAAAAA: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611299075489.svg", // 对应文件服务器中,图片对应的的键值 -----只需要改动此值即可,其他值使用统一的
+            formula: [],
+        },
+ * 
+ * }
+ */
+
+// eslint-disable-next-line no-var
+var __systemConf = {
+    // 设备类样式,
+    equipStyle: {
+        // 默认设备类样式 (设备类名匹配不到时,使用默认类图标 比如: 文件服务器中没有油烟机的图标时,使用此默认样式)
+        defaultEquipStyle: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611558340113.svg", // 对应文件服务器中,图片对应的的键值
+            formula: [],
+        },
+        // 空调机组
+        ACATAH: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993135.svg",
+            formula: [],
+        },
+        // 新风机组
+        ACATFU: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993094.svg",
+            formula: [],
+        },
+        // 风机盘管
+        ACATFC: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993150.svg",
+            formula: [],
+        },
+        // 通风风机
+        ACVTSF: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993108.svg",
+            formula: [],
+        },
+        // 热风幕
+        ACVTAC: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993120.svg",
+            formula: [],
+        },
+        // 温度传感器
+        OTSETP: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993105.svg",
+            formula: [],
+        },
+        // 湿度传感器
+        OTSERH: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993112.svg",
+            formula: [],
+        },
+        // 浓度传感器
+        OTSECT: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993125.svg",
+            formula: [],
+        },
+        // 监控摄像头
+        SPVSCM: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993139.svg",
+            formula: [],
+        },
+        // 生活给水储水箱
+        WSDWWT: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993117.svg",
+            formula: [],
+        },
+        // 生活给水水泵
+        WSDWPP: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993115.svg",
+            formula: [],
+        },
+        // 生活热水水泵
+        WSDHHP: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993114.svg",
+            formula: [],
+        },
+        // 位移传感器
+        OTSEDP: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993107.svg",
+            formula: [],
+        },
+        // 污废水一体式提升机组
+        WSSTLU: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993104.svg",
+            formula: [],
+        },
+        // 潜污泵
+        WSSTSP: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993122.svg",
+            formula: [],
+        },
+        // 集水坑
+        WSSTCP: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993142.svg",
+            formula: [],
+        },
+        // 隔油池
+        WSSTOS: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993145.svg",
+            formula: [],
+        },
+        // 照明控制箱
+        SELTCU: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993091.svg",
+            formula: [],
+        },
+        // 直梯
+        SEELEL: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993087.svg",
+            formula: [],
+        },
+        // 扶梯
+        SEELES: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993148.svg",
+            formula: [],
+        },
+        // 变压器
+        SETDTF: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993155.svg",
+            formula: [],
+        },
+        // 高压开关柜
+        SETDHS: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993146.svg",
+            formula: [],
+        },
+        // 直流屏
+        SETDDS: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993089.svg",
+            formula: [],
+        },
+        // 消火栓供水加压泵
+        FFFSHP: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993097.svg",
+            formula: [],
+        },
+        // 喷淋供水加压泵
+        FFFSSP: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993124.svg",
+            formula: [],
+        },
+        // 消防水箱
+        FFFSWT: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993099.svg",
+            formula: [],
+        },
+        // 消防喷头
+        FFFSSN: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993102.svg",
+            formula: [],
+        },
+        // 窗
+        CFBEWN: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993153.svg",
+            formula: [],
+        },
+        // 楼梯
+        CFCSSW: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993134.svg",
+            formula: [],
+        },
+        // 消火栓箱
+        FFFSHB: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993096.svg",
+            formula: [],
+        },
+        // 防火卷帘门
+        FFFRFR: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993151.svg",
+            formula: [],
+        },
+        // 火灾探测器
+        FFFASE: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993143.svg",
+            formula: [],
+        },
+        // 消防手动报警按钮
+        FFFAMA: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993100.svg",
+            formula: [],
+        },
+        // 监控主机
+        SPVSHT: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993137.svg",
+            formula: [],
+        },
+        // 监控前端设备
+        SPVSFE: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993140.svg",
+            formula: [],
+        },
+        // 硬盘录像机
+        SPVSDR: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993092.svg",
+            formula: [],
+        },
+        // 门禁主机
+        SPEGHT: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993127.svg",
+            formula: [],
+        },
+        // 门禁控制箱
+        SPEGCU: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993131.svg",
+            formula: [],
+        },
+        // 门禁门锁
+        SPEGDL: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993129.svg",
+            formula: [],
+        },
+        // 人流量传感器
+        OTSEPF: {
+            color: "#1F2429",
+            size: 12,
+            url: "1611310993119.svg",
+            formula: [],
+        },
+    },
+};
+window.__systemConf = __systemConf;

+ 13 - 0
src/App.vue

@@ -0,0 +1,13 @@
+<template>
+  <div id="app">
+    <router-view/>
+  </div>
+</template>
+
+<style lang="less">
+#app {
+ width: 100%;
+ height: 100vh;
+}
+
+</style>

+ 179 - 0
src/api/httputils.js

@@ -0,0 +1,179 @@
+import axios from "axios"
+
+const CancelToken = axios.CancelToken
+let cancel
+
+// 创建axios实例
+const axiosservice = axios.create({
+    timeout: 30000, // 请求超时时间
+    retry: 4, //重新请求次数
+    retryDelay: 1000, //重新请求的间隔
+    credentials: true, // 接口每次请求会跨域携带cookie
+    cancelToken: new CancelToken(function executor(c) {
+        // executor 函数接收一个 cancel 函数作为参数
+        cancel = c
+    }),
+})
+
+axiosservice.interceptors.request.use(
+    (config) => {
+        config.withCredentials = true // 允许携带token ,这个是解决跨域产生的相关问题
+        config.headers = {
+            // projectId: "Pj4403070003"
+            projectId: window._projectId
+        }
+        return config
+    },
+    (error) => {
+        return Promise.reject(error)
+    }
+)
+
+axiosservice.interceptors.response.use(
+    function (res) {
+        //在这里对返回的数据进行处理
+        //console.log('axios interceptors res = ', res.status, res)
+        const resp = res.data
+        if (resp.result === "unauthc") {
+            store.commit("logined", false)
+            // MessageBox.confirm("未登陆或登陆信息已失效, 是否重新登陆?", "提示", {
+            //     confirmButtonText: "确定",
+            //     cancelButtonText: "取消",
+            //     type: "error",
+            // })
+            //     .then((resp) => {
+            //         //console.log('--------------------------- confirm', resp)
+            //         //router.push('/login')
+            //         window.location.reload()
+            //     })
+            //     .catch((error) => {
+            //         //console.log('--------------------------- cancel', error)
+            //         console.log("")
+            //     })
+        } else if (resp.result == "unauthorization") {
+            // MessageBox.alert("无权操作", { title: "警告", type: "error" })
+        }
+        //console.log('axios interceptors resp2 = ', resp.success, resp.errorCode, resp.errorMessage, res)
+        return res
+    },
+    function (err) {
+        //Do something with response error
+        console.log("axios interceptors err = ", err)
+        return Promise.reject(err)
+    }
+)
+
+/* 下载方法 */
+function downFile(blob, fileName) {
+    // 非IE下载
+    if ("download" in document.createElement("a")) {
+        const link = document.createElement("a")
+        link.href = window.URL.createObjectURL(blob) // 创建下载的链接
+        link.download = fileName // 下载后文件名
+        link.style.display = "none"
+        document.body.appendChild(link)
+        link.click() // 点击下载
+        window.URL.revokeObjectURL(link.href) // 释放掉blob对象
+        document.body.removeChild(link) // 下载完成移除元素
+    } else {
+        // IE10+下载
+        window.navigator.msSaveBlob(blob, fileName)
+    }
+}
+
+export default {
+    //获取cookie
+    getCookie(name) {
+        let arr,
+            reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)")
+        if ((arr = document.cookie.match(reg))) {
+            return unescape(arr[2])
+        } else {
+            /* 如果没有参数,那么就获取本域下的所有cookie */
+            return document.cookie
+        }
+    },
+
+    async getJson(url, params) {
+        try {
+            const response = await axiosservice({
+                url,
+                params,
+                method: "get",
+            })
+            return response.data
+        } catch (err) {
+            throw err
+        }
+    },
+    async postJson(url, data) {
+        try {
+            const response = await axiosservice({
+                url,
+                data,
+                method: "post",
+            })
+            return response.data
+        } catch (err) {
+            throw err
+        }
+    },
+    async fetchJson(url, params, data) {
+        try {
+            const response = await axiosservice({
+                url,
+                params,
+                data,
+                method: "post",
+            })
+            return response
+        } catch (err) {
+            throw err
+        }
+    },
+    async postupload(url, data) {
+        try {
+            const response = await axiosservice({
+                url,
+                data,
+                method: "post",
+                headers: {
+                    "Content-Type": "multipart/form-data",
+                },
+            })
+            return response.data
+        } catch (err) {
+            throw err
+        }
+    },
+    download(url, requestData) {
+        // 响应类型:arraybuffer, blob
+        axiosservice
+            .post(url, requestData, { responseType: "blob" })
+            .then((resp) => {
+                const headers = resp.headers
+                const contentType = headers["content-type"]
+
+                console.log("响应头信息", headers)
+                if (!resp.data) {
+                    console.error("响应异常:", resp)
+                    return false
+                } else {
+                    console.log("下载文件:", resp)
+                    const blob = new Blob([resp.data], { type: contentType })
+
+                    const contentDisposition = resp.headers["content-disposition"]
+                    let fileName = "unknown"
+                    if (contentDisposition) {
+                        fileName = window.decodeURI(resp.headers["content-disposition"].split("=")[1])
+                    }
+                    console.log("文件名称:", fileName)
+                    downFile(blob, fileName)
+                }
+            })
+            .catch(function (error) {
+                console.log(error)
+            })
+    },
+    axios: axiosservice,
+}

+ 486 - 0
src/api/plan.js

@@ -0,0 +1,486 @@
+import httputils from "@/api/httputils";
+import axios from "axios";
+
+// 已发布 - 查询图形以及所有节点信息
+export function pubPlanerRead(postParams) {
+    return httputils.postJson(`/labsl/planar/graph/pub/read`, postParams);
+}
+// 查询设备列表
+export function equipQuery(postParams) {
+    return httputils.postJson(`/equip-component/planar/equip`, postParams);
+}
+// 查询空间信息
+export function spaceQuery(postParams) {
+    return httputils.postJson(`/equip-component/planar/space`, postParams);
+}
+
+//读取系统图-已发布
+export function readPubGroup(postParams) {
+    // return httputils.postJson(`${window.topo_baseurl}/labsl/graph/pub/read`, postParams)
+    // return httputils.postJson(`/labsl/graph/pub/read`, postParams)
+    return axios.post(`${window.topo_baseurl}/labsl/graph/pub/read`, postParams);
+}
+
+// 读取系统图状态
+export function readDeviceStatus(postParams) {
+    if (false) {
+        return new Promise((resolve, reject) => {
+            resolve({
+                result: "Success",
+                reason: "",
+                content: [
+                    {
+                        objectId: "Eq11010500292ef58cce08f14400ba8a59eef8aeeed1",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq110105002900b49e50f37b4a7093cb458f8e0e70cb",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500290236905f8e404dd194caba72c18ee4f7",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029038aeb94f6bb403c8e61c2522e229428",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq110105002906b496d1972d4bfd943d7041184dfa62",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq110105002906e7061c52b346e38d82e595b4e8ad57",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500291885405e72d74f94a99e83333a3ad1ba",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq110105002918fc7920901d46b9b9de47a879bf0a15",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500292a45259335684970bfb0947b57575fe5",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500293162f7813d2e4fcd88208e239939779a",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500293276dd9793df4c9d95443d45fdbc4d38",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500293eecc87a3aa24b43b0118a859576f921",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029489dacec7c9d48f8a0d1cd55d57b21fc",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500294b3a67de47494743bda953995bb2a44f",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500294db52b9408e2465081a6575b690789d0",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029511114ca135b4c2fab6b1b763c8ba84d",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500296049a991c6c84e5ea986fdf47b6dc430",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq110105002968b7001eee83465184279a2de33d5f05",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500296bc83cfc489f4476a7b2fb430858f8d5",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq110105002973a82c3453874739b086ba58de67ebd4",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500297a75138745cb416d91e5b0e7708ed16b",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500297a946a5029c3436b8d37324780131cbf",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500297c40c0dd42aa4a0283210d655040119b",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029814dbdbd01f14f2a9b824d99f5787107",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029831e56776cc541868db4d1b73d97a62e",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq110105002984730605552146e7b86a4d2f652a43db",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq110105002985439a25f15244d3bf2c035b12031cbb",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq110105002985def8013f824614935efc06e4f42ba1",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029927bb343e9e543cab5978a07a795a185",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029984a8acc66f94a6793b47b553f33449f",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq11010500299b115c5d30b6491586a2bc7395a365d4",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029a242f4a954bb46dfa1db7be5b5499123",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029aab5ecc924404f2197442f7db6a96277",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029ac2242d5ca3d49f88737ae7b1779b819",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029ac437b5f6388403798014edd8358347c",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029b4665f0959af42fd9af6e2b8fc42589a",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029b95972a00da24117a920495ab0a7b1ec",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029b9b55d6e5aa1465b8d0f1b48d4d2e6ac",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029c91bcb8540544ad09642856e2e800b08",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029cbc5709e424948399b7b2206433c35ed",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029d13490e84dc2462a9479416d7874d0dc",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029d571ea8454634336958fd497d2a64a33",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029da7586ee57a9438d896cfd0cce934ea3",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029dfaa4f674e0b443fb62010de77691fea",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029e7240a9357b245a79fa28074aa413e43",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029e9418f9666f0442fb5e4a61b4233f467",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029e97ccf08db434484be755a249f554de7",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029e9a859867fe44c44a7b6119c7daf452a",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029ea79ee69b4dc471d9aa8791091e0dc0b",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029ea8927b06d8946939fd0969a73a41412",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029ebb829fe0445489996717d8097711695",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029f5c911f289b441e688dabc0199890b40",
+                        status: 2,
+                        status_name: "关",
+                    },
+                    {
+                        objectId: "Eq1101050029fe6434f1925e4ef1b090a9baf2a29870",
+                        status: 2,
+                        status_name: "关",
+                    },
+                ],
+                totalCount: 0,
+            });
+        });
+    }
+    return httputils.postJson(`${window._url}/api/common/GetEquipmentRunningStateList`, postParams);
+}
+
+// 读取某个系统图 运行参数
+export function readDeviceParams(postParams) {
+    if (false) {
+        let data = {
+            result: "Success",
+            reason: "",
+            content: [
+                {
+                    firstTag: "运行参数",
+                    infoCode: "inCloudStatus",
+                    infoName: "云端控制状态",
+                    data: "0",
+                    dataType: "BOOLEAN",
+                    meterId: "ACATAH_0_inCloudStatus",
+                    funcId: "901",
+                    dataSource: [
+                        {
+                            code: "0",
+                            name: "非云端",
+                        },
+                        {
+                            code: "1",
+                            name: "云端",
+                        },
+                    ],
+                },
+                {
+                    firstTag: "运行参数",
+                    infoCode: "returnAirTemp",
+                    infoName: "回风温度",
+                    data: "0.69",
+                    dataType: "DOUBLE",
+                    meterId: "ACATAH_0_returnAirTemp",
+                    funcId: "901",
+                    unit: "℃",
+                },
+                {
+                    firstTag: "运行参数",
+                    infoCode: "onlineStatus",
+                    infoName: "在线状态",
+                    data: "0",
+                    dataType: "BOOLEAN",
+                    meterId: "ACATAH_0_onlineStatus",
+                    funcId: "901",
+                    dataSource: [
+                        {
+                            code: "0",
+                            name: "离线",
+                        },
+                        {
+                            code: "1",
+                            name: "在线",
+                        },
+                    ],
+                },
+                {
+                    firstTag: "运行参数",
+                    infoCode: "faultStatus",
+                    infoName: "故障状态",
+                    data: "0",
+                    dataType: "BOOLEAN",
+                    meterId: "ACATAH_0_faultStatus",
+                    funcId: "901",
+                    dataSource: [
+                        {
+                            code: "0",
+                            name: "正常",
+                        },
+                        {
+                            code: "1",
+                            name: "故障",
+                        },
+                    ],
+                },
+                {
+                    firstTag: "运行参数",
+                    infoCode: "returnAirRH",
+                    infoName: "回风相对湿度",
+                    data: "0.7",
+                    dataType: "DOUBLE",
+                    meterId: "ACATAH_0_returnAirRH",
+                    funcId: "901",
+                    unit: "%RH",
+                },
+                {
+                    firstTag: "运行参数",
+                    infoCode: "returnAirValveOpening",
+                    infoName: "回风阀开度",
+                    data: "0.7",
+                    dataType: "DOUBLE",
+                    meterId: "ACATAH_0_returnAirValveOpening",
+                    funcId: "901",
+                    unit: "%",
+                },
+                {
+                    firstTag: "运行参数",
+                    infoCode: "manualAutoStatus",
+                    infoName: "手自动状态",
+                    data: "0",
+                    dataType: "BOOLEAN",
+                    meterId: "ACATAH_0_manualAutoStatus",
+                    funcId: "901",
+                    dataSource: [
+                        {
+                            code: "0",
+                            name: "手动",
+                        },
+                        {
+                            code: "1",
+                            name: "自动",
+                        },
+                    ],
+                },
+                {
+                    firstTag: "运行参数",
+                    infoCode: "chillWaterValveOpening",
+                    infoName: "冷水阀开度",
+                    data: "0.7",
+                    dataType: "DOUBLE",
+                    meterId: "ACATAH_0_chillWaterValveOpening",
+                    funcId: "901",
+                    unit: "%",
+                },
+                {
+                    firstTag: "运行参数",
+                    infoCode: "supplyAirTemp",
+                    infoName: "送风温度",
+                    data: "0.69",
+                    dataType: "DOUBLE",
+                    meterId: "ACATAH_0_supplyAirTemp",
+                    funcId: "901",
+                    unit: "℃",
+                },
+                {
+                    firstTag: "运行参数",
+                    infoCode: "runStatus",
+                    infoName: "运行状态",
+                    data: "0",
+                    dataType: "BOOLEAN",
+                    meterId: "ACATAH_0_runStatus",
+                    funcId: "901",
+                    dataSource: [
+                        {
+                            code: "0",
+                            name: "停止",
+                        },
+                        {
+                            code: "1",
+                            name: "运行",
+                        },
+                    ],
+                },
+                {
+                    firstTag: "运行参数",
+                    infoCode: "freshAirValveOpening",
+                    infoName: "新风阀开度",
+                    data: "0.7",
+                    dataType: "DOUBLE",
+                    meterId: "ACATAH_0_freshAirValveOpening",
+                    funcId: "901",
+                    unit: "%",
+                },
+                {
+                    firstTag: "运行参数",
+                    infoCode: "chillWaterOutTemp",
+                    infoName: "冷水出口温度",
+                    data: "0.69",
+                    dataType: "DOUBLE",
+                    meterId: "ACATAH_0_chillWaterOutTemp",
+                    funcId: "901",
+                    unit: "℃",
+                },
+            ],
+            totalCount: 0,
+        };
+        // return data
+        return new Promise((resolve, reject) => {
+            resolve(data);
+        });
+    }
+    return httputils.postJson(window._url + `/api/common/FindRuntimeDatas`, postParams);
+}

BIN
src/assets/logo.png


+ 4 - 0
src/assets/plus.svg

@@ -0,0 +1,4 @@
+<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0.974976 9.58203H19.725C20.35 9.58203 20.6625 9.89453 20.6625 10.5195C20.6625 11.1445 20.35 11.457 19.725 11.457H0.974976C0.349976 11.457 0.0374756 11.1445 0.0374756 10.5195C0.0374756 9.89453 0.349976 9.58203 0.974976 9.58203V9.58203Z" fill="#E9E9E9"/>
+<path d="M8.99811 19.9633V1.13828C8.99811 0.641225 9.40105 0.238281 9.89811 0.238281C10.3952 0.238281 10.7981 0.641225 10.7981 1.13828V19.9633C10.7981 20.4603 10.3952 20.8633 9.89811 20.8633C9.40105 20.8633 8.99811 20.4603 8.99811 19.9633H8.99811Z" fill="#E9E9E9"/>
+</svg>

+ 3 - 0
src/assets/sub.svg

@@ -0,0 +1,3 @@
+<svg width="20" height="2" viewBox="0 0 20 2" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1.04999 0.0498047H19.05C19.65 0.0498047 19.95 0.349805 19.95 0.949805C19.95 1.5498 19.65 1.8498 19.05 1.8498H1.04999C0.449994 1.8498 0.149994 1.5498 0.149994 0.949805C0.149994 0.349805 0.449994 0.0498047 1.04999 0.0498047V0.0498047Z" fill="#E9E9E9"/>
+</svg>

+ 511 - 0
src/components/basePlan.vue

@@ -0,0 +1,511 @@
+<!-- 画板 -->
+<template>
+    <div ref="basePlan" class="base-plan">
+        <canvas id="floor_plan" :width="canvasWidth" :height="canvasHeight" tabindex="0"></canvas>
+        <scaleBtn v-show="hasShowContro" class="sacle-btn" @sacle="changeSize"></scaleBtn>
+    </div>
+</template>
+<script>
+import { planScene } from "./planClass/planScene";
+import { FloorView } from "./planClass/FloorView";
+import { pubPlanerRead, equipQuery, spaceQuery } from "@/api/plan"; // 引入获取底图得接口
+import scaleBtn from "./scale";
+import { PlanParser } from "./planClass/PlanParser";
+import { planFactory } from "./planClass/planFactory";
+
+import { SColor, SFont, SPoint } from "@persagy-web/draw";
+import { SLineStyle } from "@persagy-web/graph";
+import { SFloorParser, getJsonz } from "@persagy-web/big";
+import { SImageItem, STextItem, SAnchorItem } from "@persagy-web/graph";
+export default {
+    components: { scaleBtn },
+    props: {
+        // 是否展示大小控制器
+        hasShowContro: {
+            type: Boolean,
+            default: true,
+            required: false,
+        },
+    },
+    data() {
+        return {
+            canvasWidth: 0, // 画布的宽
+            canvasHeight: 0, // 画布的高
+            view: null, // 视图 view
+            scene: null, // 场景类
+            baseMapStyle: {
+                // 底图样式
+                default: {
+                    strokeColor: "#F0F3F7",
+                    fillColor: "#F0F3F7",
+                    lineWidth: 1,
+                    effect: {},
+                },
+            },
+            equipItemMap: {}, // 图上相关的设备实例
+            equipItemNum: 0, // 图上相关的设备的数量
+            zoneIteMap: {}, // 图上相关的空间实例
+            zoneItemNum: 0, // 图上相关的空间实例的数量
+            styleMap: {}, // 样式库信息
+            outline: null, // 区域显示,返回有轮廓点坐标时,区域显示,否则不进行区域显示
+            ruleList: [], //规则列表
+            objExtInfo: {}, // 对象实例信息
+            zoneItem: [], //保存空间实例队形
+        };
+    },
+    methods: {
+        fixWindow() {
+            this.view.fitSceneToView();
+        },
+        // 初始化
+        init() {
+            this.clearImg();
+            this.view ? (this.view.scene = this.scene) : null;
+            // 读取平面图数据
+            this.readPlanMsg();
+        },
+
+        // 读取平面图数据
+        readPlanMsg() {
+            if (false) {
+                const obj = {
+                    // graphId: "0314991b0cd148ba89da60eddf30efd1",
+                    projectId: "Pj4403070003",
+                    graphId: "994d0f65d647426f854d2a5f7f0173a4",
+                    id: "be4c75daf4d44cb89b447eb7581614da",
+                };
+            }
+            const obj = {
+                graphId: window._graphId,
+                id: window._id,
+                // projectId: window._projectId,
+            };
+            // 查询已发布的图
+            pubPlanerRead(obj).then((res) => {
+                // this.statDeviceIds(res);
+                this.getDataSuc(res);
+                // 获取压缩包数据并解压
+                if (window._floorMap) {
+                    // TODO: 底图
+                    this.getMapBlob();
+                }
+            });
+        },
+        // 请求获取地图的压缩包
+        getMapBlob(showBaseMap) {
+            if (window._floorMap.includes("png") || window._floorMap.includes("jpg")) {
+                const url = `/image-service/common/image_get?systemId=dataPlatform&key=${window._floorMap}`;
+                this.getImage(url);
+            } else {
+                const url = `/image-service/common/file_get?systemId=revit&key=${window._floorMap}`;
+                getJsonz(url).then((data) => {
+                    // 解析数据并放入压缩包中
+                    this.parserData(data, showBaseMap);
+                });
+            }
+        },
+        // 获取图片
+        getImage(url) {
+            const imgItem = new SImageItem(null, url);
+            imgItem.showType = SImageShowType.AutoFit;
+            imgItem.connect("imgLoadOver", this, () => {
+                // 画板是否可拖动;
+                this.scene.addItem(imgItem);
+                this.view.DragMove = true;
+                this.view.fitSceneToView();
+            });
+        },
+        // 解析底图数据并注入 scene 类中
+        parserData(data, showBaseMap = true) {
+            const parser = new SFloorParser();
+            parser.parseData(data);
+            this.parser = parser;
+            parser.spaceList.forEach((t) => {
+                t.visible = showBaseMap;
+                //设置样式
+                Object.assign(t, this.baseMapStyle.default);
+                t.selectable = false;
+                this.scene.addItem(t);
+            });
+            parser.wallList.forEach((t) => {
+                t.visible = showBaseMap;
+                t.selectable = false;
+                this.scene.addItem(t);
+            });
+            parser.virtualWallList.forEach((t) => {
+                t.visible = showBaseMap;
+                t.selectable = false;
+                this.scene.addItem(t);
+            });
+            parser.doorList.forEach((t) => {
+                t.visible = showBaseMap;
+                t.selectable = false;
+                this.scene.addItem(t);
+            });
+            parser.columnList.forEach((t) => {
+                t.visible = showBaseMap;
+                t.selectable = false;
+                this.scene.addItem(t);
+            });
+            parser.casementList.forEach((t) => {
+                t.visible = showBaseMap;
+                t.selectable = false;
+                this.scene.addItem(t);
+            });
+            // 画板是否可拖动
+            this.view.DragMove = true;
+            this.view.fitSceneToView();
+        },
+        // 读图成功回调
+        async getDataSuc(res) {
+            let anchorList = []; //保存锚点对象
+            // 'url 新增路径'
+            if (res.result == "failure") return;
+            const parse = new PlanParser();
+            if (this.scene) {
+                // const backgroundColor = res.data.content.viewBackground ? res.data.content.viewBackground : "#1f1f27";
+                // this.scene.changeBackgroundColor(backgroundColor);
+            }
+            // 初始化对象实例信息
+            if (res.content.elements.objExtInfo?.length) {
+                const objExtInfo = {};
+                if (res.content.elements.objExtInfo?.length) {
+                    res.content.elements.objExtInfo.forEach((item) => {
+                        if (item?.properties?.id) objExtInfo[item.properties.id] = item;
+                    });
+                }
+                this.objExtInfo = objExtInfo;
+            }
+            // 初始化样式信息
+            if (res.content.style) {
+                // 拼接设备默认样式
+                this.styleMap = res.content.style;
+            } else {
+                this.styleMap = {};
+            }
+            // 加载规则,显示实例数据
+            if (res.content.ruleList?.length) {
+                // this.INITRULELIST(res.content.ruleList);
+                // this.ruleNum = res.content.ruleList.length;
+
+                const ruleList = res.content.ruleList;
+                // 同步执行规则,进行设备/设备组/空间的添加,删除
+                for (let index = 0; index < ruleList.length; index++) {
+                    const rule = ruleList[index];
+                    // 查询规则
+                    if (rule.commond && rule.commond === "query") {
+                        const params = { ...rule.params, buildingId: window._buildingId, floorId: window._floorId };
+                        if (rule?.returnType === "equip") {
+                            const res = await equipQuery(params);
+                            if (res.result === "success") this.mergeEquipData(res.content);
+                        } else if (rule?.returnType === "zone") {
+                            const res = await spaceQuery(params);
+                            if (res.result === "success") this.mergeZoneData(res.content);
+                        } else if (rule?.returnType === "equipGroup") {
+                            console.error("请求设备组数据");
+                            // this.loadedRuleNum++;
+                            // if (this.ruleNum === this.loadedRuleNum) this.loadMarkRelation();
+                        }
+                    } else if (rule.commond && rule.commond === "delete") {
+                        // 删除规则
+                        // console.error("删除命令!!!", rule);
+                        // 删除设备实例
+                        if (rule?.returnType === "equip") {
+                            const classCode = rule?.params?.classCode;
+                            if (classCode) {
+                                this.removeEquipment(classCode);
+                            }
+                        } else if (rule?.returnType === "zone") {
+                            // 删除空间实例
+                            const classCode = rule?.params?.classCode;
+                            if (classCode) {
+                                this.removeZone(classCode);
+                            }
+                        } else if (rule?.returnType === "equipGroup") {
+                            // 删除设备组
+                            //
+                            // this.loadedRuleNum++;
+                            // if (this.ruleNum === this.loadedRuleNum) this.loadMarkRelation();
+                        }
+                    }
+                }
+            }
+
+            window.parse = parse;
+
+            // 图片url修改
+            if (res.content.elements.markers?.length) {
+                //
+                res.content.elements.markers.map((item, index, arr) => {
+                    if (["BaseImage", "BgImage"].includes(item.properties.type)) {
+                        if (item.style.default.url) {
+                            arr[index].style.default.url =
+                                window.img_baseurl + "/image-service/common/image_get?systemId=dataPlatform&key=" + arr[index].style.default.url;
+                        } else {
+                            // 默认图片
+                            arr[index].style.default.url =
+                                window.img_baseurl + "/image-service/common/image_get?systemId=dataPlatform&key=" + "1611739392546.png";
+                        }
+                    }
+                });
+            }
+            parse.parseData(res.content.elements);
+            parse.markers.forEach((item) => {
+                // console.log(' parse.markers',item)
+                item && this.scene.addItem(item);
+            });
+
+            parse.relations.forEach((t) => {
+                // 设置锚点
+                if (t.anchor1Id) {
+                    let startAnc = null;
+                    anchorList.forEach((aItem) => {
+                        if (aItem.id == t.anchor1Id) {
+                            startAnc = aItem;
+                        }
+                    });
+                    if (startAnc) {
+                        startAnc.isConnected = true;
+                        startAnc.parent?.connect("changePos", t, t.changePos);
+                        t.startAnchor = startAnc || null;
+                    }
+                }
+                if (t.anchor12d) {
+                    let endAnc = null;
+                    anchorList.forEach((aItem) => {
+                        if (aItem.id == t.anchor12d) {
+                            endAnc = aItem;
+                        }
+                    });
+                    if (endAnc) {
+                        endAnc.isConnected = true;
+                        endAnc.parent?.connect("changePos", t, t.changePos);
+                        t.endAnchor = endAnc || null;
+                    }
+                }
+                this.scene.addItem(t);
+            });
+            // 设置画布背景色
+            const backgroundColor = res.content.style?.defaultMapStyle?.backgroundColor;
+            if (backgroundColor) {
+                this.scene.changeBackgroundColor(backgroundColor);
+            }
+            // 区域显示,绘制maskItem,并将maskItem适配屏幕
+            if (res.content.outline && res.content.style?.defaultMapStyle?.showBaseMap) {
+                const maskItem = new planFactory().createBaseMaskItem(res.content.outline);
+                maskItem.fillColor = new SColor("#ffffffff");
+
+                this.scene.addItem(maskItem);
+                this.view.fitItemToView([maskItem]);
+            } else {
+                this.fixWindow();
+            }
+        },
+        // 读图成功回调
+        statDeviceIds(res) {
+            let anchorList = []; //保存锚点对象
+            // 'url 新增路径'
+            if (res.result == "failure") return;
+            const parse = new PlanParser();
+            if (res.data.content.elements.nodes && res.data.content.elements.nodes.length) {
+                let tempDatas = res.data.content.elements.nodes.map((obj) => {
+                    return obj.attachObjectIds[0];
+                });
+                // console.log('tempDatas:', tempDatas)
+                setInterval(() => {
+                    this.$emit("postDeviceIds", tempDatas);
+                }, 5000);
+                this.$emit("postDeviceIds", tempDatas);
+            }
+        },
+        // 图片缩小
+        changeSize(isbiger) {
+            if (isbiger) {
+                this.view.scaleByPoint((this.view.scale * 1.1) / this.view.scale, this.canvasWidth / 2, this.canvasHeight / 2);
+            } else {
+                this.view.scaleByPoint((this.view.scale * 0.9) / this.view.scale, this.canvasWidth / 2, this.canvasHeight / 2);
+            }
+        },
+        // 清空画布
+        clearImg() {
+            this.scene = new planScene();
+            this.scene.vueOnMouseDown = this.onMousedown;
+            if (this.view) {
+                this.view.update();
+            }
+        },
+        // 鼠标点击事件
+        onMousedown(item, e) {
+            console.log("鼠标按下!", item, e);
+            this.$emit("onMousedown", item, e);
+        },
+        // 鼠标抬起事件
+        onMouseup(item, e) {
+            // console.log("鼠标抬起!", item, e);
+        },
+        // 鼠标事件移入
+        onMouseenter(item, e) {
+            // 判断是否为设备图例
+            item.showImgShadow = true;
+            console.log("鼠标移入!", item, e);
+        },
+        // 鼠标事件移出
+        onMouseleave(item, e) {
+            item.showImgShadow = false;
+            console.log("鼠标移出!", item, e);
+        },
+        // 解析设备数据
+        mergeEquipData(equipList) {
+            equipList.forEach((equip) => {
+                if (!this.equipItemMap[equip.id]) {
+                    if (this.objExtInfo[equip.id]) {
+                        equip = { ...this.objExtInfo[equip.id], ...equip };
+                    }
+                    if (!equip.pos) {
+                        //如果未维护设备在图中的坐标
+                        if (equip.locationJson) {
+                            // 判断设备是否维护BIM坐标
+                            const { x, y, z } = equip.locationJson;
+                            equip.pos = { x, y: -y, z };
+                        } else {
+                            // 否则显示默认坐标位置
+                            equip.pos = { x: 0, y: 0, z: 0 };
+                        }
+                    }
+                    // 添加设备对象类型
+                    equip.properties = { type: "BaseEquipment" };
+                    equip.style = {
+                        default: {},
+                    };
+
+                    const equipStyle = window.__systemConf.equipStyle;
+                    // 设备/设备类样式
+                    let style = {};
+                    if (this.styleMap[equip.id]) {
+                        style = this.styleMap[equip.id];
+                    } else if (this.styleMap[equip.classCode]) {
+                        style = this.styleMap[equip.classCode];
+                    } else if (equipStyle[equip.classCode]) {
+                        style = equipStyle[equip.classCode];
+                    } else {
+                        style = equipStyle["defaultEquipStyle"];
+                    }
+
+                    equip.style = {
+                        default: {
+                            ...style,
+                            url: window.img_baseurl + "/image-service/common/image_get?systemId=dataPlatform&key=" + style.url, //+  '1607752841478.svg'
+                        },
+                    };
+                    const equipItem = new planFactory().createBaseSEquipment(equip);
+                    equipItem.connect("onMouseDown", this, this.onMousedown);
+                    equipItem.connect("onMouseUp", this, this.onMouseup);
+                    equipItem.connect("onMouseLeave", this, this.onMouseleave);
+                    equipItem.connect("onMouseEnter", this, this.onMouseenter);
+                    this.scene.addItem(equipItem);
+                    // 保存设备到 equipItemMap
+                    this.equipItemMap[equip.id] = equipItem;
+                }
+            });
+            // this.loadedRuleNum++;
+            // if (this.ruleNum === this.loadedRuleNum) this.loadMarkRelation();
+        },
+        // 按照classCode 删除设备
+        removeEquipment(classCode) {
+            for (const key in this.equipItemMap) {
+                const equipItem = this.equipItemMap[key];
+                if (equipItem?.data?.classCode === classCode) {
+                    // 删除equipItemMap中保存的设备实例
+                    delete this.equipItemMap[equipItem.id];
+                    // 删除图上的设备实例
+                    this.scene.removeItem(equipItem);
+                }
+            }
+        },
+        // 解析空间数据
+        mergeZoneData(zoneList) {
+            zoneList.forEach((zone) => {
+                if (!this.zoneIteMap[zone.id]) {
+                    if (this.objExtInfo[zone.id]) {
+                        zone = { ...this.objExtInfo[zone.id], ...zone };
+                    }
+                    // 添加设备对象类型
+                    zone.properties = { type: "BaseZone" };
+                    let style = {};
+                    if (this.styleMap[zone.id]) {
+                        style = this.styleMap[zone.id];
+                    } else if (this.styleMap[zone.classCode]) {
+                        style = this.styleMap[zone.classCode];
+                    } else {
+                        style = this.styleMap["defaultZoneStyle"];
+                    }
+                    zone.style = {
+                        default: { ...style },
+                    };
+                    zone.outLine = zone.outline;
+                    const zoneItem = new planFactory().createBaseSZone(zone);
+                    zoneItem.connect("onMouseDown", this, this.onMousedown);
+                    zoneItem.connect("onMouseUp", this, this.onMouseup);
+                    zoneItem.connect("onMouseLeave", this, this.onMouseleave);
+                    zoneItem.connect("onMouseEnter", this, this.onMouseenter);
+                    this.scene.addItem(zoneItem);
+                    this.zoneItem.push(zoneItem);
+                    // 设置比例,调整文本位置
+                    zoneItem.setScale(this.view.scale);
+                    // 添加空间实例到 zoneIteMap
+                    this.zoneIteMap[zone.id] = zoneItem;
+                }
+            });
+            // this.loadedRuleNum++;
+            // if (this.ruleNum === this.loadedRuleNum) this.loadMarkRelation();
+        },
+        // 按照classCode 删除空间
+        removeZone(classCode) {
+            for (const key in this.zoneIteMap) {
+                const zoneItem = this.zoneIteMap[key];
+                if (zoneItem?.data?.classCode === classCode) {
+                    // 删除equipItemMap中保存的设备实例
+                    delete this.zoneIteMap[zoneItem.data.id];
+                    // 删除图上的设备实例
+                    this.scene.removeItem(zoneItem);
+                }
+            }
+        },
+    },
+    watch: {
+        // 监听视图比例,调整空间中的信息点位置
+        "view.scale"(val) {
+            this.zoneItem.forEach((item) => {
+                item.setScale(val);
+            });
+        },
+    },
+    created() {
+        window.vm = this;
+        this.clearImg();
+    },
+    mounted() {
+        // 获取 canvas 的宽高
+        this.canvasWidth = this.$refs.basePlan.offsetWidth;
+        this.canvasHeight = this.$refs.basePlan.offsetHeight;
+        // 初始化场景类
+        this.view = new FloorView("floor_plan");
+        if (this.scene) {
+            this.view.scene = this.scene;
+        }
+        this.init();
+    },
+};
+</script>
+<style lang="less" scoped>
+.base-plan {
+    width: 100%;
+    height: 100%;
+    position: relative;
+    .sacle-btn {
+        position: absolute;
+        right: 20px;
+        bottom: 20px;
+    }
+}
+</style>

+ 95 - 0
src/components/planClass/FloorView.ts

@@ -0,0 +1,95 @@
+/*
+ * *********************************************************************************************************************
+ *
+ *          !!
+ *        .F88X
+ *        X8888Y
+ *      .}888888N;
+ *        i888888N;        .:!              .I$WI:
+ *          R888888I      .'N88~            i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
+ *          .R888888I    .;N8888~          .X8'  "8I.!,/8"  !%NY8`"8I8~~8>,88I
+ *            +888888N;  .8888888Y                                  "&&8Y.}8,
+ *            ./888888N;  .R888888Y        .'}~    .>}'.`+>  i}!    "i'  +/'  .'i~  !11,.:">,  .~]!  .i}i
+ *              ~888888%:  .I888888l      .]88~`1/iY88Ii+1'.R$8$8]"888888888>  Y8$  W8E  X8E  W8888'188Il}Y88$*
+ *              18888888    E8888881    .]W%8$`R8X'&8%++N8i,8N%N8+l8%`  .}8N:.R$RE%N88N%N$K$R  188,FE$8%~Y88I
+ *            .E888888I  .i8888888'      .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
+ *            8888888I  .,N888888~        ~88i"8W,!N8*.I88.}888%F,i$88"F88"  888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
+ *          i888888N'      I888Y          ]88;/EX*IFKFK88X  K8R  .l8W  88Y  ~88}'88E&%8W.X8N``]88!.$8K  .:W8I
+ *        .i888888N;        I8Y          .&8$  .X88!  i881.:%888>I88  ;88]  +88+.';;;;:.Y88X  18N.,88l  .+88/
+ *      .:R888888I
+ *      .&888888I                                          Copyright (c) 2009-2020.  博锐尚格科技股份有限公司
+ *        ~8888'
+ *        .!88~                                                                     All rights reserved.
+ *
+ * *********************************************************************************************************************
+ */
+
+import { SGraphView } from "@persagy-web/graph";
+import { SMouseButton, SMouseEvent } from "@persagy-web/base/";
+import { SPoint, SColor } from "@persagy-web/draw/";
+
+/**
+ * 楼层视图
+ *
+ * @author  贠星 <yunxing0102@163.com>
+ */
+export class FloorView extends SGraphView {
+    /** 鼠标左键键按下时位置 */
+    private _leftKeyPos = new SPoint();
+
+    /** 保存左键的坐标 */
+    private _downPoint = new SPoint();
+
+    /** 是否拖拽 */
+    isDrag: boolean = false;
+    constructor(id: string) {
+        super(id);
+    }
+    /** 背景色 */
+    // backgroundColor: SColor = new SColor('#1f1f27');
+    backgroundColor: SColor = new SColor("#ffffff");
+    /**
+     * 鼠标按下事件
+     *
+     * @param   event       事件参数
+     */
+    protected onMouseDown(event: MouseEvent): void {
+        let se = new SMouseEvent(event);
+        if (se.buttons & SMouseButton.LeftButton) {
+            this._leftKeyPos.x = se.x;
+            this._leftKeyPos.y = se.y;
+            this._downPoint.x = se.x;
+            this._downPoint.y = se.y;
+        }
+        super.onMouseDown(event);
+    }
+
+    /**
+     * 鼠标移动事件
+     *
+     * @param   event       事件参数
+     */
+    protected onMouseMove(event: MouseEvent): void {
+        super.onMouseMove(event);
+        // 按左键移动
+        let se = new SMouseEvent(event);
+        if (se.buttons & SMouseButton.LeftButton) {
+            this.origin.x += se.x - this._leftKeyPos.x;
+            this.origin.y += se.y - this._leftKeyPos.y;
+            this.update();
+        }
+        this._leftKeyPos.x = se.x;
+        this._leftKeyPos.y = se.y;
+    } // Function onMouseMove()
+
+    protected onMouseUp(event: MouseEvent): void {
+        let se = new SMouseEvent(event);
+        // 通过判断是否按住左键拖动来判断是否是拖动还是单击
+        if (this._downPoint.x == se.x && this._downPoint.y == se.y) {
+            this.isDrag = false;
+        } else {
+            this.isDrag = true;
+        }
+        super.onMouseUp(event);
+    }
+}

+ 161 - 0
src/components/planClass/PlanParser.ts

@@ -0,0 +1,161 @@
+/*
+ * *********************************************************************************************************************
+ *
+ *          !!
+ *        .F88X
+ *        X8888Y
+ *      .}888888N;
+ *        i888888N;        .:!              .I$WI:
+ *          R888888I      .'N88~            i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
+ *          .R888888I    .;N8888~          .X8'  "8I.!,/8"  !%NY8`"8I8~~8>,88I
+ *            +888888N;  .8888888Y                                  "&&8Y.}8,
+ *            ./888888N;  .R888888Y        .'}~    .>}'.`+>  i}!    "i'  +/'  .'i~  !11,.:">,  .~]!  .i}i
+ *              ~888888%:  .I888888l      .]88~`1/iY88Ii+1'.R$8$8]"888888888>  Y8$  W8E  X8E  W8888'188Il}Y88$*
+ *              18888888    E8888881    .]W%8$`R8X'&8%++N8i,8N%N8+l8%`  .}8N:.R$RE%N88N%N$K$R  188,FE$8%~Y88I
+ *            .E888888I  .i8888888'      .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
+ *            8888888I  .,N888888~        ~88i"8W,!N8*.I88.}888%F,i$88"F88"  888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
+ *          i888888N'      I888Y          ]88;/EX*IFKFK88X  K8R  .l8W  88Y  ~88}'88E&%8W.X8N``]88!.$8K  .:W8I
+ *        .i888888N;        I8Y          .&8$  .X88!  i881.:%888>I88  ;88]  +88+.';;;;:.Y88X  18N.,88l  .+88/
+ *      .:R888888I
+ *      .&888888I                                          Copyright (c) 2009-2020.  博锐尚格科技股份有限公司
+ *        ~8888'
+ *        .!88~                                                                     All rights reserved.
+ *
+ * ****/
+
+import { SParser } from '@persagy-web/big/lib';
+import { Legend, Marker, Relation, ElementData } from "@persagy-web/big"
+import { planFactory } from "./planFactory"
+
+/**
+ * 平面图解析器
+ *
+ *  @author  贠星 <yunxing0102@163.com>
+ */
+export class PlanParser extends SParser {
+    /**图例节点 */
+    nodes: any = [];  // 图例节点,所有与工程信息化相关的图例(图标类型与区域)
+    /**图例节点 */  // 与工程信息无关的标识对象(增加文本注释,图上的图片说明)
+    markers: any = [];
+    /**  管线对象 */
+    relations: any = [];
+    factory:planFactory = new planFactory()
+    constructor() {
+        super(new planFactory());
+    }
+
+    /**
+     * 解析平面图绘制数据
+     *
+     * @param data    业务空间数据
+     */
+    parseData(data: ElementData): void {
+        // 生成遍历基本图例
+        // debugger
+        // console.log('------',data)
+        if (data.markers && data.markers.length) {
+            data.markers.forEach((item) => {
+                
+                this.addMarker(item);
+            })
+        }
+
+        // 生成遍历Node图例
+        if (data.objExtInfo?.length) {
+            data.objExtInfo.forEach((item: any) => {
+                this.addObjExtInfo(item)
+            })
+        }
+
+        // 生成遍历关系图例
+        if (data.relations && data.relations.length) {
+            data.relations.forEach((item: any) => {
+                this.addRelation(item)
+            })
+        }
+    }
+
+    /**
+     * 添加生成 mark 实例
+     *
+     * @param data Marker   图例类型数据
+     */
+    addMarker(data: Marker) {
+        if ( data.properties?.type) {
+            switch (data.properties.type) {
+                case "BaseLine":
+                    this.markers.push(this.factory.createBaseLineEdit(data));
+                    break;
+                case "BaseText":
+                    this.markers.push(this.factory.createBaseTextEdit(data));
+                    break;
+                case "BaseImage":
+                    this.markers.push(this.factory.createBaseImageEdit(data));
+                    break;
+                case "BgImage":
+                    this.markers.push(this.factory.createBgImageEdit(data));
+                    break;
+                case "BaseExplain":
+                    this.markers.push(this.factory.createBaseExpainEdit(data));
+                    break;
+                case "BaseCircle":
+                    this.markers.push(this.factory.createBaseCircleEdit(data));
+                    break;
+                case "BaseArrow":
+                    this.markers.push(this.factory.createBaseArrow(data));
+                    break;
+                case "BaseRect":
+                    this.markers.push(this.factory.createBaseRectEdit(data));
+                    break;
+                case "BasePolygon":
+                    this.markers.push(this.factory.createBasePolygonEdit(data));
+                    break;
+                case "BaseArrowPolygon":
+                    this.markers.push(this.factory.createBasePolygonArrowEdit(data));
+            }
+        }
+    }
+
+    /**
+     * 添加生成 Node 实例
+     *
+     * @param data Legend   图例类型数据
+     */
+    addObjExtInfo(data: Legend) {
+        // let objExtInfo = null;
+        // if (data.properties && data.properties.type) {
+        //     switch (data.properties.type) {
+        //         case "BaseEquipment":
+        //             objExtInfo = this.factory.createBaseSEquipment(data)
+        //             break;
+        //     }
+        // }
+        // if (objExtInfo) {
+        //     this.nodes.push(objExtInfo);
+        // }
+
+        // return objExtInfo
+    }
+
+    /**
+     * 添加生成 Re 实例
+     *
+     * @param data Legend   图例类型数据
+     */
+    addRelation(data: Relation) {
+        let relation = null;
+        if (data.properties && data.properties.type) {
+            switch (data.properties.type) {
+                case "BasePipe":
+                    relation = this.factory.createBasePipe(data)
+                    break;
+            }
+        }
+
+        if (relation) {
+            this.relations.push(relation);
+        }
+
+        return relation
+    }
+}

+ 87 - 0
src/components/planClass/items/SCircleItem.ts

@@ -0,0 +1,87 @@
+/*
+ * *********************************************************************************************************************
+ *
+ *          !!
+ *        .F88X
+ *        X8888Y
+ *      .}888888N;
+ *        i888888N;        .:!              .I$WI:
+ *          R888888I      .'N88~            i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
+ *          .R888888I    .;N8888~          .X8'  "8I.!,/8"  !%NY8`"8I8~~8>,88I
+ *            +888888N;  .8888888Y                                  "&&8Y.}8,
+ *            ./888888N;  .R888888Y        .'}~    .>}'.`+>  i}!    "i'  +/'  .'i~  !11,.:">,  .~]!  .i}i
+ *              ~888888%:  .I888888l      .]88~`1/iY88Ii+1'.R$8$8]"888888888>  Y8$  W8E  X8E  W8888'188Il}Y88$*
+ *              18888888    E8888881    .]W%8$`R8X'&8%++N8i,8N%N8+l8%`  .}8N:.R$RE%N88N%N$K$R  188,FE$8%~Y88I
+ *            .E888888I  .i8888888'      .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
+ *            8888888I  .,N888888~        ~88i"8W,!N8*.I88.}888%F,i$88"F88"  888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
+ *          i888888N'      I888Y          ]88;/EX*IFKFK88X  K8R  .l8W  88Y  ~88}'88E&%8W.X8N``]88!.$8K  .:W8I
+ *        .i888888N;        I8Y          .&8$  .X88!  i881.:%888>I88  ;88]  +88+.';;;;:.Y88X  18N.,88l  .+88/
+ *      .:R888888I
+ *      .&888888I                                          Copyright (c) 2009-2020.  博锐尚格科技股份有限公司
+ *        ~8888'
+ *        .!88~                                                                     All rights reserved.
+ *
+ * *********************************************************************************************************************
+ */
+
+/**
+ * 圆
+ *
+ *  @author  贠星 <yunxing0102@163.com>
+ */
+import { SGraphStyleItem, SGraphItem, SLineStyle } from "@persagy-web/graph"
+import { SPainter, SColor, SFont, SPoint } from "@persagy-web/draw";
+
+export class SCircleItem extends SGraphStyleItem {
+    // 圆坐标
+    set localtion(v) {
+        this._localtion = new SPoint(v);
+        this.update()
+    }
+    get localtion(): SPoint {
+        return this._localtion
+    }
+    _localtion: SPoint = new SPoint(0, 0);
+    // 圆半径
+    set radius(v: number) {
+        this._radius = v;
+        this.update();
+    }
+    get radius(): number {
+        return this._radius
+    }
+    _radius: number = 0;
+
+    /**
+     * 构造函数
+     *
+     * @param parent
+     */
+    constructor(parent: SGraphItem | null) {
+        super(parent)
+    }
+
+    /**
+    * Item 绘制操作
+    *
+    * @param painter    绘制对象
+    */
+    onDraw(painter: SPainter): void {
+        painter.pen.color = this.strokeColor;
+        painter.brush.color = this.fillColor;
+        painter.pen.lineWidth = this.lineWidth;
+        if (this.lineStyle == SLineStyle.Dashed) {
+            painter.pen.lineDash = [
+                painter.toPx(this.lineWidth * 3),
+                painter.toPx(this.lineWidth * 7)
+            ];
+        } else if (this.lineStyle == SLineStyle.Dotted) {
+            painter.pen.lineDash = [
+                painter.toPx(this.lineWidth * 2),
+                painter.toPx(this.lineWidth * 2)
+            ];
+        }
+
+        painter.drawCircle(this.localtion.x, this.localtion.y, this.radius);
+    } // Function onDraw()
+}

+ 239 - 0
src/components/planClass/items/equipment.ts

@@ -0,0 +1,239 @@
+/*
+ * *********************************************************************************************************************
+ *
+ *          !!
+ *        .F88X
+ *        X8888Y
+ *      .}888888N;
+ *        i888888N;        .:!              .I$WI:
+ *          R888888I      .'N88~            i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
+ *          .R888888I    .;N8888~          .X8'  "8I.!,/8"  !%NY8`"8I8~~8>,88I
+ *            +888888N;  .8888888Y                                  "&&8Y.}8,
+ *            ./888888N;  .R888888Y        .'}~    .>}'.`+>  i}!    "i'  +/'  .'i~  !11,.:">,  .~]!  .i}i
+ *              ~888888%:  .I888888l      .]88~`1/iY88Ii+1'.R$8$8]"888888888>  Y8$  W8E  X8E  W8888'188Il}Y88$*
+ *              18888888    E8888881    .]W%8$`R8X'&8%++N8i,8N%N8+l8%`  .}8N:.R$RE%N88N%N$K$R  188,FE$8%~Y88I
+ *            .E888888I  .i8888888'      .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
+ *            8888888I  .,N888888~        ~88i"8W,!N8*.I88.}888%F,i$88"F88"  888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
+ *          i888888N'      I888Y          ]88;/EX*IFKFK88X  K8R  .l8W  88Y  ~88}'88E&%8W.X8N``]88!.$8K  .:W8I
+ *        .i888888N;        I8Y          .&8$  .X88!  i881.:%888>I88  ;88]  +88+.';;;;:.Y88X  18N.,88l  .+88/
+ *      .:R888888I
+ *      .&888888I                                          Copyright (c) 2009-2020.  博锐尚格科技股份有限公司
+ *        ~8888'
+ *        .!88~                                                                     All rights reserved.
+ *
+ * *********************************************************************************************************************
+ */
+import { SMouseEvent } from "@persagy-web/base";
+import { SEquipItem } from "@persagy-web/big";
+import { SGraphItem, STextItem, SGraphCircleItem } from "@persagy-web/graph/lib";
+import { SColor, SFont, SPoint, SPainter } from "@persagy-web/draw/lib";
+import { SCircleItem } from "./SCircleItem";
+// 样式接口
+interface Style {
+    // 字体颜色
+    color: string;
+    // 字体大小
+    fontSize: number;
+    // 公式(信息点)
+    formula: any[];
+    // 图标地址
+    url: string;
+}
+/**
+ * 平面图派生设备类
+ *
+ *  @author  贠星 <yunxing0102@163.com>
+ */
+
+export class EquipItem extends SEquipItem {
+    StatusPoint: SCircleItem | null = null;
+
+    // 颜色
+    private _color: SColor = new SColor();
+    get color() {
+        return this._color;
+    }
+    set color(val) {
+        this._color = val;
+    }
+
+    // 字体
+    private _font: SFont = new SFont("sans-serif", 12);
+    get font() {
+        return this._font;
+    }
+    set font(val) {
+        this._font = val;
+    }
+
+    // 设置设备类样式
+    setStyle(style: Style) {
+        const { color, fontSize, formula, url } = style;
+        this.url = url;
+        // 更改颜色,字体
+        this.color = new SColor(color);
+        this.font = new SFont("sans-serif", fontSize);
+        this.formula = formula;
+        this.update();
+    }
+
+    /** 公式(信息点) */
+    private _formula: any[] = [];
+    get formula(): any[] {
+        return this._formula;
+    }
+    set formula(val) {
+        this._formula = val;
+        try {
+            // const textList = JSON.parse(this._formula);
+            if (this.scene) {
+                this.textItemList.forEach((textItem) => {
+                    this.scene?.removeItem(textItem);
+                });
+            }
+            if (this._formula.length) {
+                // if (textList.length) {
+                const textItemList: any[] = [];
+                this._formula.forEach((item: any, index: number) => {
+                    // textList.forEach((item: any, index: number) => {
+                    const obj = new STextItem(this);
+                    // @ts-ignore
+                    obj.propertyData = { ...item };
+                    obj.text = item.name;
+                    if (item.pos) {
+                        obj.moveTo(item.pos.x, item.pos.y);
+                    } else {
+                        obj.moveTo(this.img.width * 0.5, this.font.size * (index - 0.125 - 0.5 * this._formula.length));
+                    }
+                    // TODO: obj.moveTo(this.img.width * 0.5, -(this.font.size * 1.25 * 0.5) + (index * this.font.size) - (textList.length - 1) * 0.5 * this.font.size);
+                    // obj.moveTo(this.img.width * 0.5, this.font.size * (index - 0.125 - 0.5 * textList.length));
+                    // obj.connect("onMove", this, this.textMove.bind(this));
+                    // console.log("::::", this.font, this.color);
+                    obj.font = this.font;
+                    obj.color = this.color;
+                    obj.isTransform = false;
+                    obj.showSelect = false;
+                    // console.log("::::::", obj);
+                    textItemList.push(obj);
+                });
+                this.textItemList = textItemList;
+            } else {
+                this.textItemList = [];
+            }
+            this.update();
+        } catch (error) {
+            console.error("公式数据错误", error);
+        }
+    }
+
+    constructor(parent: SGraphItem | null, data: Style) {
+        super(parent);
+        this.zOrder = 9700;
+        this.isTransform = false;
+        this.sWidth = 32;
+        this.sHeight = 32;
+        this.img.showSelect = false;
+        this.setStyle(data);
+    }
+    // 设置设备名称
+    setEquipName() {
+        const item = new STextItem(this);
+        item.text = this.data.localName;
+        // item.strokeColor = new SColor('#6b7086');
+        item.color = new SColor("#6b7086");
+        item.font = new SFont("sans-serif", 12);
+        item.isTransform = true;
+        // item.font = new SFont("sans-serif", 16);
+        // item.moveTo(-this.width / 2, this.height / 2);
+        item.moveTo(-this.width / 2, 20);
+        this.setStatusPoint(item);
+    }
+
+    /**
+     * 设置状态点
+     *
+     * @param parent 父类
+     */
+    setStatusPoint(parent: STextItem | null) {
+        const item = new SCircleItem(parent);
+        const h = parent ? parent.height : 0;
+        item.localtion = new SPoint(0, 0);
+        item.radius = 4;
+        item.fillColor = new SColor("#de6466");
+        item.strokeColor = new SColor("#de6466");
+        item.moveTo(-item.radius * 2, h);
+        this.StatusPoint = item;
+    }
+
+    /**
+     * 设置状态远点颜色
+     *
+     * @param val 颜色字符
+     */
+    setStatusPointColor(val: string) {
+        if (!this.StatusPoint) return;
+        this.StatusPoint.fillColor = new SColor(val);
+        this.StatusPoint.strokeColor = new SColor(val);
+    }
+
+    /**
+     * 获取信息点数组
+     */
+    getMsgList(): any {
+        return this.textItemList;
+    }
+
+    onMouseMove(event: SMouseEvent): boolean {
+        const scene = this.scene;
+        if (null != scene) {
+            if (scene.hoverItem == null || scene.hoverItem !== this) {
+                if (scene.hoverItem != null) {
+                    scene.hoverItem.onMouseLeave(event);
+                }
+                this.onMouseEnter(event);
+                scene.hoverItem = this;
+            }
+        }
+        return true;
+    }
+    /**
+     * 鼠标进入事件
+     *''
+     * @param event   保存事件参数
+     * @return 是否处理事件
+     */
+    onMouseEnter(event: SMouseEvent): boolean {
+        this.$emit("onMouseEnter");
+        return false;
+    }
+
+    /**
+     * 鼠标离开事件
+     *
+     * @param event   保存事件参数
+     * @return 是否处理事件
+     */
+    onMouseLeave(event: SMouseEvent): boolean {
+        this.$emit("onMouseLeave");
+        return false;
+    }
+    // 显示图片阴影
+    _showImgShadow = false;
+    get showImgShadow(): boolean {
+        return this._showImgShadow;
+    }
+    set showImgShadow(v: boolean) {
+        this._showImgShadow = v;
+        this.update();
+    }
+    onDraw(painter: SPainter): void {
+        if (this.showImgShadow) {
+            painter.shadow.shadowBlur = 20;
+            painter.shadow.shadowColor = new SColor(`#000000`);
+            painter.shadow.shadowOffsetX = 10;
+            painter.shadow.shadowOffsetY = 10;
+        } else {
+            painter.shadow.shadowColor = SColor.Transparent;
+        }
+    }
+}

+ 179 - 0
src/components/planClass/items/pipe.ts

@@ -0,0 +1,179 @@
+/*
+ * *********************************************************************************************************************
+ *
+ *          !!
+ *        .F88X
+ *        X8888Y
+ *      .}888888N;
+ *        i888888N;        .:!              .I$WI:
+ *          R888888I      .'N88~            i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
+ *          .R888888I    .;N8888~          .X8'  "8I.!,/8"  !%NY8`"8I8~~8>,88I
+ *            +888888N;  .8888888Y                                  "&&8Y.}8,
+ *            ./888888N;  .R888888Y        .'}~    .>}'.`+>  i}!    "i'  +/'  .'i~  !11,.:">,  .~]!  .i}i
+ *              ~888888%:  .I888888l      .]88~`1/iY88Ii+1'.R$8$8]"888888888>  Y8$  W8E  X8E  W8888'188Il}Y88$*
+ *              18888888    E8888881    .]W%8$`R8X'&8%++N8i,8N%N8+l8%`  .}8N:.R$RE%N88N%N$K$R  188,FE$8%~Y88I
+ *            .E888888I  .i8888888'      .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
+ *            8888888I  .,N888888~        ~88i"8W,!N8*.I88.}888%F,i$88"F88"  888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
+ *          i888888N'      I888Y          ]88;/EX*IFKFK88X  K8R  .l8W  88Y  ~88}'88E&%8W.X8N``]88!.$8K  .:W8I
+ *        .i888888N;        I8Y          .&8$  .X88!  i881.:%888>I88  ;88]  +88+.';;;;:.Y88X  18N.,88l  .+88/
+ *      .:R888888I
+ *      .&888888I                                          Copyright (c) 2009-2020.  博锐尚格科技股份有限公司
+ *        ~8888'
+ *        .!88~                                                                     All rights reserved.
+ *
+ * *********************************************************************************************************************
+ */
+
+import { SGraphItem, SLineStyle } from "@persagy-web/graph/lib";
+import { SPainter, SColor, SFont, SPoint } from "@persagy-web/draw/lib";
+import { SCircleCornerPolylineItem } from "@persagy-web/big"
+export class Pipe extends SGraphItem {
+    pointList: SGraphItem | null;
+    // 底部默认的管道
+    pipe_default: SCircleCornerPolylineItem
+    // 管道上部的流动像素
+    pipe_flow: SCircleCornerPolylineItem
+
+    // 设置弧度
+    private _radius: number = 5;
+    get radius(): number {
+        return this.pipe_default.radius;
+    }
+    set radius(v: number) {
+        if (v === this._radius) {
+            return;
+        }
+        // 设置弧度
+        this.pipe_default.radius = v;
+        this.pipe_flow.radius = v;
+    }
+
+    /** 圆角半径是否需要转像素值 */
+    private _radiusIsPx: boolean = false;
+    get radiusIsPx(): boolean {
+        return this.pipe_default.radiusIsPx;
+    }
+    set radiusIsPx(v: boolean) {
+        if (v === this._radiusIsPx) {
+            return;
+        }
+        // 设置弧度
+        this.pipe_default.radiusIsPx = v;
+        this.pipe_flow.radiusIsPx = v;
+    }
+
+    get strokeColor(): SColor {
+        return this.pipe_default.strokeColor
+    }
+    set strokeColor(v: SColor) {
+        // 设置弧度
+        this.pipe_default.strokeColor = v;
+    }
+    get data(): any {
+        return this.pipe_default.data
+    }
+    set data(v: any) {
+        // 设置弧度
+        this.pipe_default.data = v;
+    }
+
+    //    内管道颜色
+    get flowStrokeColor(): SColor {
+        return this.pipe_flow.strokeColor
+    }
+    set flowStrokeColor(v: SColor) {
+        // 设置弧度
+        this.pipe_flow.strokeColor = v;
+    }
+
+    get fillColor(): SColor {
+        return this.pipe_default.fillColor;
+    }
+    set fillColor(v: SColor) {
+        this.pipe_default.fillColor = v;
+    }
+    // 内管道填充颜色
+    get flowFillColor(): SColor {
+        return this.pipe_flow.strokeColor
+    }
+    set flowFillColor(v: SColor) {
+        // 设置弧度
+        this.pipe_flow.strokeColor = v;
+    }
+
+    get lineWidth(): number {
+        return this.pipe_default.lineWidth;
+    }
+    set lineWidth(v: number) {
+        this.pipe_default.lineWidth = v;
+        this.pipe_flow.lineWidth = this.pipe_default.lineWidth * this._flowWithScale
+    }
+    // 内外管道比
+    _flowWithScale: number = 0.6;
+    set flowWithScale(val: number) {
+        this._flowWithScale = val;
+        this.pipe_flow.lineWidth = this.pipe_default.lineWidth * this._flowWithScale
+    }
+    get flowWithScale(): number {
+        return this._flowWithScale
+    }
+
+    // 线样式
+    get lineStyle(): SLineStyle {
+        return this.pipe_default.lineStyle;
+    }
+    set lineStyle(v: SLineStyle) {
+        this.pipe_default.lineStyle = v;
+    }
+    // 内管道线样式
+    get flowLineStyle(): SLineStyle {
+        return this.pipe_flow.lineStyle;
+    }
+    set flowLineStyle(v: SLineStyle) {
+        this.pipe_flow.lineStyle = v;
+    }
+    // 是否显示滚动
+    _showScroll = true
+    get showScroll(): boolean {
+        return this._showScroll;
+    }
+    set showScroll(v: boolean) {
+        this._showScroll = v;
+        if(v){
+            this._flowScroll()
+        }else{
+            if(this._setInteveal){
+                clearInterval(this._setInteveal);
+                this._setInteveal = null;
+            }
+        }
+    }
+    _setInteveal :any = null;
+
+    constructor(parent: SGraphItem | null, pointList: any) {
+        super(parent)
+        this.pointList = pointList;
+        // 底部默认的管道
+        this.pipe_default = new SCircleCornerPolylineItem(this, pointList)
+        // 管道上部的流动像素
+        this.pipe_flow = new SCircleCornerPolylineItem(this, pointList)
+
+        this.flowFillColor = new SColor('#ffffff');    //内管颜色
+        this.flowStrokeColor = new SColor('#ffffff'); // 内管颜色
+        this.flowLineStyle = SLineStyle.Dashed;  //线型
+        this.pipe_default.widthIsPx = true; //显示像素宽
+        this.pipe_flow.widthIsPx = true; //像素宽
+        this.showScroll = true; //是否滚动
+    }
+    _flowScroll(){
+        this._setInteveal =  setInterval(()=>{
+            this.update()
+        },60)
+    }
+    onDraw(painter: SPainter): void{
+        if(this.showScroll){
+            painter.pen.dashOffset = new Date().getTime() / 50 % 40;
+        }
+    }
+
+}

+ 416 - 0
src/components/planClass/items/zone.ts

@@ -0,0 +1,416 @@
+/*
+ * *********************************************************************************************************************
+ *
+ *          !!
+ *        .F88X
+ *        X8888Y
+ *      .}888888N;
+ *        i888888N;        .:!              .I$WI:
+ *          R888888I      .'N88~            i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
+ *          .R888888I    .;N8888~          .X8'  "8I.!,/8"  !%NY8`"8I8~~8>,88I
+ *            +888888N;  .8888888Y                                  "&&8Y.}8,
+ *            ./888888N;  .R888888Y        .'}~    .>}'.`+>  i}!    "i'  +/'  .'i~  !11,.:">,  .~]!  .i}i
+ *              ~888888%:  .I888888l      .]88~`1/iY88Ii+1'.R$8$8]"888888888>  Y8$  W8E  X8E  W8888'188Il}Y88$*
+ *              18888888    E8888881    .]W%8$`R8X'&8%++N8i,8N%N8+l8%`  .}8N:.R$RE%N88N%N$K$R  188,FE$8%~Y88I
+ *            .E888888I  .i8888888'      .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
+ *            8888888I  .,N888888~        ~88i"8W,!N8*.I88.}888%F,i$88"F88"  888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
+ *          i888888N'      I888Y          ]88;/EX*IFKFK88X  K8R  .l8W  88Y  ~88}'88E&%8W.X8N``]88!.$8K  .:W8I
+ *        .i888888N;        I8Y          .&8$  .X88!  i881.:%888>I88  ;88]  +88+.';;;;:.Y88X  18N.,88l  .+88/
+ *      .:R888888I
+ *      .&888888I                                          Copyright (c) 2009-2020.  博锐尚格科技股份有限公司
+ *        ~8888'
+ *        .!88~                                                                     All rights reserved.
+ *
+ * *********************************************************************************************************************
+ */
+import { SGraphItem, STextItem, SLineStyle, STextOrigin, Point } from "@persagy-web/graph";
+import { SColor, SFont, SPainter, SLineCapStyle, SPoint, SPath, SPolygonUtil, SRect } from "@persagy-web/draw";
+import { SMouseEvent } from "@persagy-web/base";
+// 样式接口
+interface Style {
+    // 轮廓线
+    outline?: any[];
+    // 字体颜色
+    color: string;
+    // 填充颜色
+    fillColor: string;
+    // 边框颜色
+    strokeColor: string;
+    // 字体大小
+    fontSize: number;
+    // 公式(信息点)
+    formula: any[];
+    // 线型
+    lineStyle: number;
+    // 线宽
+    lineWidth: number;
+}
+
+/**
+ * 平面图派生空间类
+ *
+ *  @author  贠星 <yunxing0102@163.com>
+ */
+export class ZoneItem extends SGraphItem {
+    /** X 坐标最小值 */
+    private minX = Number.MAX_SAFE_INTEGER;
+    /** X 坐标最大值 */
+    private maxX = Number.MIN_SAFE_INTEGER;
+    /** Y 坐标最小值 */
+    private minY = Number.MAX_SAFE_INTEGER;
+    /** Y 坐标最大值 */
+    private maxY = Number.MIN_SAFE_INTEGER;
+    /** 墙轮廓线坐标 list */
+    private pointList: SPoint[][][] = [];
+    /** path 对象 */
+    private pathList: SPath[] = [];
+    /** 文本数组 */
+    textItemList: STextItem[] = [];
+
+    /** 线型 */
+    _lineStyle: number = SLineStyle.Solid;
+    get lineStyle() {
+        return this._lineStyle;
+    }
+    set lineStyle(val) {
+        this._lineStyle = val;
+        this.update();
+    }
+
+    /** 线宽 */
+    _lineWidth = 1;
+    get lineWidth() {
+        return this._lineWidth;
+    }
+    set lineWidth(val) {
+        this._lineWidth = val;
+        this.update();
+    }
+
+    /** 颜色 */
+    _color: SColor = SColor.Black;
+    get color(): SColor {
+        return this._color;
+    }
+    set color(v: SColor) {
+        this._color = new SColor(v);
+        this.update();
+    }
+    /** 边框颜色 */
+    _strokeColor: SColor = SColor.Black;
+    get strokeColor(): SColor {
+        return this._strokeColor;
+    }
+    set strokeColor(v: SColor) {
+        this._strokeColor = new SColor(v);
+        this.update();
+    }
+
+    /** 填充颜色 */
+    _fillColor: SColor = SColor.Black;
+    get fillColor(): SColor {
+        return this._fillColor;
+    }
+    set fillColor(v: SColor) {
+        this._fillColor = new SColor(v);
+        this.update();
+    }
+    // 字体
+    private _font: SFont = new SFont("sans-serif", 12);
+    get font() {
+        return this._font;
+    }
+    set font(val) {
+        this._font = val;
+    }
+    /** 是否显示文字 */
+    _showText = true;
+    get showText(): boolean {
+        return this._showText;
+    }
+    set showText(v: boolean) {
+        if (v === this._showText) {
+            return;
+        }
+        this._showText = v;
+        if (v) {
+            this.textItemList.map((item) => {
+                item.show();
+            });
+        } else {
+            this.textItemList.map((item) => {
+                item.hide();
+            });
+        }
+    }
+    /** 公式(信息点) */
+    private _formula: any[] = [];
+    get formula(): any[] {
+        return this._formula;
+    }
+    set formula(val) {
+        this._formula = val;
+        try {
+            if (this.scene) {
+                this.textItemList.forEach((textItem) => {
+                    this.scene?.removeItem(textItem);
+                });
+            }
+            if (val.length) {
+                const textItemList: any[] = [];
+                val.forEach((item: any, index: number) => {
+                    const obj = new STextItem(this);
+                    obj.propertyData = { ...item };
+                    obj.text = item.name;
+                    if (item.pos) {
+                        obj.moveTo(item.pos.x, item.pos.y);
+                    } else {
+                        const avgPos = this.getAverageVal();
+                        const scale = this.scene?.view?.scale;
+                        if (scale) {
+                            obj.moveTo(avgPos.avgX, avgPos.avgY - (this.font.size * (0.5 * val.length - 0.5 - index)) / scale);
+                        } else {
+                            obj.moveTo(avgPos.avgX, avgPos.avgY - this.font.size * (0.5 * val.length - 0.5 - index));
+                        }
+                    }
+
+                    obj.connect("onMove", this, this.textMove.bind(this));
+                    obj.font = this.font;
+                    obj.color = this.color;
+                    obj.originPosition = STextOrigin.Center;
+                    obj.isTransform = false;
+                    obj.showSelect = false;
+                    textItemList.push(obj);
+                });
+                this.textItemList = textItemList;
+            } else {
+                this.textItemList = [];
+            }
+            this.update();
+        } catch (error) {
+            console.error("公式数据错误", error);
+        }
+    }
+
+    constructor(parent: SGraphItem | null, style: Style) {
+        super(parent);
+        this.zOrder = 9500;
+        this.setStyle(style);
+    }
+    /** 设置空间样式 */
+    setStyle(style: Style) {
+        const { outline, color, fillColor, strokeColor, fontSize, formula, lineStyle, lineWidth } = style;
+        this.color = new SColor(color);
+        this.fillColor = new SColor(fillColor);
+        this.strokeColor = new SColor(strokeColor);
+        this.lineStyle = lineStyle;
+        this.lineWidth = lineWidth;
+
+        this.font = new SFont("sans-serif", fontSize);
+        this.setOutline(outline);
+        this.formula = formula;
+    }
+    /**设置轮廓线 */
+    setOutline(outline) {
+        if (outline) {
+            const _outline = outline.map((t): Point[][] => {
+                return t.map((it): Point[] => {
+                    return it.map(
+                        (item): Point => {
+                            return { x: item.X, y: -item.Y };
+                        }
+                    );
+                });
+            });
+            this.minX = outline[0][0][0].x;
+            this.maxX = this.minX;
+            this.minY = outline[0][0][0].y;
+            this.maxY = this.minY;
+            // 处理轮廓点数组,同时计算最大最小值
+            this.pointList = _outline.map((t): SPoint[][] => {
+                const sPath = new SPath();
+                const tempArr = t.map((it): SPoint[] => {
+                    const array = it.map(
+                        (item): SPoint => {
+                            const x = item.x,
+                                y = item.y;
+                            if (x < this.minX) {
+                                this.minX = x;
+                            }
+                            if (y < this.minY) {
+                                this.minY = y;
+                            }
+                            if (x > this.maxX) {
+                                this.maxX = x;
+                            }
+                            if (y > this.maxY) {
+                                this.maxY = y;
+                            }
+                            return new SPoint(x, y);
+                        }
+                    );
+                    sPath.polygon(array);
+                    return array;
+                });
+                this.pathList.push(sPath);
+                return tempArr;
+            });
+        } else {
+            this.minX = 0;
+            this.maxX = 0;
+            this.minY = 0;
+            this.maxY = 0;
+        }
+    }
+    /** 设置缩放比例,缩放后,调整信息点的位置 */
+    setScale(scale: number) {
+        this.textItemList.forEach((item, index) => {
+            if (item.propertyData.pos) {
+                item.moveTo(item.propertyData.pos.x, item.propertyData.pos.y);
+            } else {
+                const avgPos = this.getAverageVal();
+                item.moveTo(avgPos.avgX, avgPos.avgY - (this.font.size * (0.5 * this.textItemList.length - 0.5 - index)) / scale);
+            }
+        });
+    }
+
+    /**
+     * 获取轮廓线第一块区域的坐标平均值
+     */
+    getAverageVal() {
+        let avgX = 0,
+            avgY = 0;
+        if (this.pointList[0] && this.pointList[0][0] && this.pointList[0][0].length) {
+            const firstOutline = this.pointList[0][0];
+            avgX =
+                firstOutline.reduce((val, pos) => {
+                    return val + pos.x;
+                }, 0) / firstOutline.length;
+            avgY =
+                firstOutline.reduce((val, pos) => {
+                    return val + pos.y;
+                }, 0) / firstOutline.length;
+        }
+        return { avgX, avgY };
+    }
+
+    /**
+     * 文本位置移动回调函数
+     *
+     * @param textItem 移动的文本元素
+     * @param pointList 移动前后位置坐标信息
+     */
+    textMove(textItem: STextItem, pointList: SPoint[]) {
+        this.moveText();
+    }
+    moveText() {}
+    onMouseDown(event: SMouseEvent): boolean {
+        this.$emit("onMouseDown");
+        return false;
+    }
+    onMouseMove(event: SMouseEvent): boolean {
+        const scene = this.scene;
+        if (null != scene) {
+            if (scene.hoverItem == null || scene.hoverItem !== this) {
+                if (scene.hoverItem != null) {
+                    scene.hoverItem.onMouseLeave(event);
+                }
+                this.onMouseEnter(event);
+                scene.hoverItem = this;
+            }
+        }
+        return true;
+    }
+    /**
+     * 鼠标进入事件
+     *''
+     * @param event   保存事件参数
+     * @return 是否处理事件
+     */
+    onMouseEnter(event: SMouseEvent): boolean {
+        this.$emit("onMouseEnter");
+        return false;
+    }
+
+    /**
+     * 鼠标离开事件
+     *
+     * @param event   保存事件参数
+     * @return 是否处理事件
+     */
+    onMouseLeave(event: SMouseEvent): boolean {
+        this.$emit("onMouseLeave");
+        return false;
+    }
+    /**
+     * Item 对象边界区域
+     *
+     * @return 对象边界区域
+     */
+    boundingRect(): SRect {
+        let rect = new SRect(this.minX, this.minY, this.maxX - this.minX, this.maxY - this.minY);
+        // if (this.showText) {
+        //     this.textItemList.forEach((item) => {
+        //         rect = rect.unioned(item.boundingRect().adjusted(item.pos.x, item.pos.y, 0, 0));
+        //     });
+        // }
+        return rect.adjusted(-5, -5, 10, 10);
+    }
+    /**
+     * 判断点是否在区域内
+     *
+     * @param x 点 x 坐标
+     * @param y 点 y 坐标
+     * @return 是否在区域内
+     */
+    contains(x: number, y: number): boolean {
+        for (let j = 0; j < this.pointList.length; j++) {
+            const arr = this.pointList[j];
+            if (arr.length < 1 || !SPolygonUtil.pointIn(x, y, arr[0])) {
+                continue;
+            }
+            if (arr.length == 1) {
+                return true;
+            }
+            let flag = false;
+            for (let i = 1; i < arr.length; i++) {
+                if (SPolygonUtil.pointIn(x, y, arr[i])) {
+                    flag = true;
+                    break;
+                }
+            }
+            if (flag) {
+                continue;
+            }
+            return true;
+        }
+        return false;
+    }
+    onDraw(painter: SPainter): void {
+        const rect = this.boundingRect();
+
+        painter.pen.lineCapStyle = SLineCapStyle.Square;
+        painter.pen.color = this.strokeColor;
+        painter.brush.color = this.fillColor;
+        painter.pen.lineWidth = painter.toPx(this.lineWidth);
+
+        if (this.lineStyle == SLineStyle.Dashed) {
+            painter.pen.lineDash = [painter.toPx(this.lineWidth * 3), painter.toPx(this.lineWidth * 7)];
+        } else if (this.lineStyle == SLineStyle.Dotted) {
+            painter.pen.lineDash = [painter.toPx(this.lineWidth), painter.toPx(this.lineWidth)];
+        }
+        // 是否选中
+        if (this.selected) {
+            painter.shadow.shadowBlur = 10;
+            painter.shadow.shadowColor = new SColor(`#00000033`);
+            painter.shadow.shadowOffsetX = 5;
+            painter.shadow.shadowOffsetY = 5;
+        } else {
+            painter.shadow.shadowColor = SColor.Transparent;
+        }
+
+        this.pathList.forEach((t): void => {
+            painter.drawPath(t);
+        });
+    }
+}

+ 350 - 0
src/components/planClass/planFactory.ts

@@ -0,0 +1,350 @@
+/*
+ * *********************************************************************************************************************
+ *
+ *          !!
+ *        .F88X
+ *        X8888Y
+ *      .}888888N;
+ *        i888888N;        .:!              .I$WI:
+ *          R888888I      .'N88~            i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
+ *          .R888888I    .;N8888~          .X8'  "8I.!,/8"  !%NY8`"8I8~~8>,88I
+ *            +888888N;  .8888888Y                                  "&&8Y.}8,
+ *            ./888888N;  .R888888Y        .'}~    .>}'.`+>  i}!    "i'  +/'  .'i~  !11,.:">,  .~]!  .i}i
+ *              ~888888%:  .I888888l      .]88~`1/iY88Ii+1'.R$8$8]"888888888>  Y8$  W8E  X8E  W8888'188Il}Y88$*
+ *              18888888    E8888881    .]W%8$`R8X'&8%++N8i,8N%N8+l8%`  .}8N:.R$RE%N88N%N$K$R  188,FE$8%~Y88I
+ *            .E888888I  .i8888888'      .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
+ *            8888888I  .,N888888~        ~88i"8W,!N8*.I88.}888%F,i$88"F88"  888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
+ *          i888888N'      I888Y          ]88;/EX*IFKFK88X  K8R  .l8W  88Y  ~88}'88E&%8W.X8N``]88!.$8K  .:W8I
+ *        .i888888N;        I8Y          .&8$  .X88!  i881.:%888>I88  ;88]  +88+.';;;;:.Y88X  18N.,88l  .+88/
+ *      .:R888888I
+ *      .&888888I                                          Copyright (c) 2016-2020.  博锐尚格科技股份有限公司
+ *        ~8888'
+ *        .!88~                                                                     All rights reserved.
+ *
+ * *********************************************************************************************************************
+ */
+
+import { SColor, SFont, SPoint, SArrowStyleType } from "@persagy-web/draw";
+import { Marker, Legend, Relation, SMaskItem } from "@persagy-web/big";
+import { SArrowItem, SPolygonItem, SArrowPoly, SItemFactory, ItemOrder, SPolylineItem } from "@persagy-web/big";
+import { SGraphCircleItem, STextItem, SImageItem, SGraphLineItem, SGraphRectItem } from "@persagy-web/graph/lib";
+import { EquipItem } from "./items/equipment";
+import { SLineStyle } from "@persagy-web/graph";
+import { Pipe } from "./items/pipe";
+import { ZoneItem } from "./items/zone";
+
+/**
+ * item 创建工厂
+ *
+ * @author 贠星 <yunxing0102@163.com>
+ */
+export class planFactory extends SItemFactory {
+    /**
+     * 构造函数
+     */
+    constructor() {
+        super();
+    }
+
+    /**
+     * 创建基础直线
+     *
+     * @param data  数据
+     * @return 线
+     */
+    createBaseLineEdit(data: Marker): SGraphLineItem {
+        const item = new SGraphLineItem(
+            null,
+            data.style.Line[0].x,
+            data.style.Line[0].y,
+            data.style.Line[1].x,
+            data.style.Line[1].y,
+            data.style.default.lineWidth,
+            data.style.default.strokeColor
+        );
+        item.data = data;
+        return item;
+    }
+
+    /**
+     * 创建基础文本
+     *
+     * @param data  数据
+     * @return 文本
+     */
+    createBaseTextEdit(data: Marker): STextItem {
+        const item = new STextItem(null);
+        if (data.size) {
+            item.width = data.size.width;
+            item.height = data.size.height;
+        }
+        item.isTransform = false;
+        item.zOrder = data.style.default.zOrder;
+        item.text = data.style.default.text;
+        item.color = new SColor(data.style.default.color);
+        item.font = new SFont("sans-serif", data.style.default.font);
+        item.backgroundColor = new SColor(data.style.default.backgroundColor);
+        item.x = data.pos.x;
+        item.y = data.pos.y;
+        item.data = data;
+        return item;
+    }
+
+    /**
+     * 创建基础图片
+     *
+     * @param data  数据
+     * @return 图片
+     */
+    createBaseImageEdit(data: Marker): SImageItem {
+        console.log("createBaseImageEdit:::", data);
+        const item = new SImageItem(null);
+
+        item.zOrder = data.style.default.zOrder;
+        item.url = data.style.default.url;
+        item.name = data.name;
+        item.lineWidth = data.style.default.lineWidth;
+        if (data.size) {
+            item.width = data.size.width;
+            item.height = data.size.height;
+        }
+        item.lineStyle = data.style.default.lineStyle;
+        item.strokeColor = new SColor(data.style.default.strokeColor);
+        // item.moveTo(data.pos.x - item.width / 2, data.pos.y + item.height / 2);
+        item.x = data.pos.x - (data.size?.width || 0);
+        item.y = data.pos.y - (data.size?.height || 0);
+        item.data = data;
+        item.isTransform = false;
+        return item;
+    }
+    /**
+     * 创建背景图片
+     *
+     * @param data  数据
+     * @return 图片
+     */
+    createBgImageEdit(data: Marker): SImageItem {
+        const item = new SImageItem(null);
+        const line = data.style.default.line;
+        item.zOrder = data.style.default.zOrder;
+        item.url = data.style.default.url;
+        item.name = data.name;
+        // TODO: 边框宽度
+        item.lineWidth = data.style.default.lineWidth * 300;
+        //
+        const width = Math.abs(line[1].x - line[0].x);
+        const height = Math.abs(line[1].y - line[0].y);
+        item.width = width;
+        item.height = height;
+        item.lineStyle = data.style.default.lineStyle;
+        item.strokeColor = new SColor(data.style.default.strokeColor);
+        item.x = line[0].x;
+        item.y = line[0].y;
+        item.data = data;
+        return item;
+    }
+
+    /**
+     * 创建基础矩形
+     *
+     * @param data  数据
+     * @return 矩形
+     */
+    createBaseRectEdit(data: Marker) {
+        let line = data.style.default.line;
+        const item = new SGraphRectItem(null, line);
+        item.lineStyle = data.style.default.lineStyle;
+        // TODO: 边框宽度
+        item.lineWidth = data.style.default.lineWidth * 300;
+        item.fillColor = new SColor(data.style.default.fillColor);
+        item.strokeColor = new SColor(data.style.default.strokeColor);
+        item.zOrder = data.style.default.zOrder;
+        item.data = data;
+        return item;
+    }
+
+    /**
+     * 创建基础圆
+     *
+     * @param data  数据
+     * @return
+     */
+    createBaseCircleEdit(data: Marker): SGraphCircleItem {
+        const line = data.style.line;
+        const item = new SGraphCircleItem(null, line);
+        // item.data = data;
+        item.lineStyle = data.style.default.lineStyle;
+        // TODO: 边框宽度???
+        item.lineWidth = data.style.default.lineWidth * 300;
+        item.fillColor = new SColor(data.style.default.fillColor);
+        item.strokeColor = new SColor(data.style.default.strokeColor);
+        item.zOrder = data.style.default.zOrder;
+        item.data = data;
+        return item;
+    }
+
+    /**
+     * 创建基础注释
+     *
+     * @param data     数据
+     * @return 注释
+     */
+    createBaseExpainEdit(data: Marker): STextItem {
+        const item = new STextItem(null);
+        if (data.size) {
+            item.width = data.size.width;
+            item.height = data.size.height;
+        }
+        item.zOrder = data.style.default.zOrder;
+        item.text = data.style.default.text;
+        item.strokeColor = new SColor(data.style.default.strokeColor);
+        item.font = new SFont("sans-serif", data.style.default.font);
+        item.backgroundColor = new SColor(data.style.default.backgroundColor);
+        item.data = data;
+        return item;
+    }
+
+    /**
+     * 创建基础多边形
+     *
+     * @param data     数据
+     * @return 注释
+     */
+    createBasePolygonEdit(data: Marker): SPolygonItem {
+        const item = new SPolygonItem(null);
+        const setPointList = data.style.outLine.map((i: any) => {
+            return new SPoint(i.x, i.y);
+        });
+        item.setPointList = setPointList;
+        item.lineStyle = data.style.default.lineStyle;
+        item.lineWidth = data.style.default.lineWidth;
+        item.zOrder = data.style.default.zOrder;
+        item.strokeColor = new SColor(data.style.default.strokeColor);
+        item.fillColor = new SColor(data.style.default.fillColor);
+        item.data = data;
+        return item;
+    }
+
+    /**
+     * 创建基础基础箭头(折线)
+     *
+     * @param data     数据
+     * @return  注释
+     */
+    createBaseArrow(data: Marker): SArrowItem {
+        const setPointList = data.style.outLine.map((i: any) => {
+            return new SPoint(i.x, i.y);
+        });
+        const item = new SArrowItem(null, setPointList);
+        item.strokeColor = new SColor(data.style.default.strokeColor);
+        item.lineWidth = data.style.default.lineWidth;
+        // 线样式
+        if (data.style.default.lineStyle) {
+            item.lineStyle = data.style.default.lineStyle;
+        }
+        if (data && data.style) {
+            item.begin = data.style.begin ? data.style.begin : SArrowStyleType.None;
+            item.end = data.style.end ? data.style.end : SArrowStyleType.None;
+        }
+        item.zOrder = data.style.default.zOrder;
+        item.data = data;
+        return item;
+    }
+
+    /**
+     * 创建基础基础箭头(折线)
+     *
+     * @param data     数据
+     * @return  注释
+     */
+    createBasePolygonArrowEdit(data: Marker): SArrowPoly {
+        const item = new SArrowPoly(null);
+        const setPointList = data.style.line.map((i: any) => {
+            return new SPoint(i.x, i.y);
+        });
+        item.pointList = setPointList;
+        item.data = data;
+        return item;
+    }
+
+    /*
+     * 创建基础设备
+     *
+     * @param data     数据
+     * @return 注释
+     */
+    createBaseSEquipment(data: Legend): EquipItem {
+        // console.log(data);
+        const style = {
+            color: data.style.default.color,
+            fontSize: data.style.default.size,
+            formula: data.style.default.formula,
+            url: data.style.default.url,
+        };
+        const item = new EquipItem(null, style);
+        item.nodeId = data.nodeId ? data.nodeId : "";
+        item.x = data.pos.x;
+        item.y = data.pos.y;
+
+        item.data = data;
+        // console.log(item);
+        // 设置设备名称
+        // item.setEquipName();
+        return item;
+    }
+    /*
+     * 创建空间
+     *
+     * @param data     数据
+     * @return 注释
+     */
+    createBaseSZone(data: Legend): ZoneItem {
+        // console.log(data);
+        const style = {
+            outline: data.outLine,
+            color: data.style.default.color,
+            fillColor: data.style.default.fillColor,
+            strokeColor: data.style.default.strokeColor,
+            fontSize: data.style.default.size,
+            formula: data.style.default.formula,
+            lineStyle: data.style.default.lineStyle,
+            lineWidth: data.style.default.lineWidth,
+        };
+        const item = new ZoneItem(null, style);
+        item.selectable = true;
+        // item.nodeId = data.nodeId ? data.nodeId : "";
+        // item.x = data.pos.x;
+        // item.y = data.pos.y;
+
+        item.data = data;
+        // console.log(item);
+        // 设置设备名称
+        // item.setEquipName();
+        return item;
+    }
+    createBaseMaskItem(data: SPoint[]): SMaskItem {
+        const item = new SMaskItem(null, data);
+        return item;
+    }
+    /*
+     * 创建基础管道
+     *
+     * @param data     数据
+     * @return 注释
+     */
+    createBasePipe(data: Relation): Pipe {
+        const setPointList = data.pointList.map((i: any) => {
+            return new SPoint(i.x, i.y);
+        });
+        const item = new Pipe(null, setPointList);
+        item.lineStyle = data.style.default.lineStyle;
+        // item.lineStyle = SLineStyle.Dotted
+        item.lineWidth = data.style.default.lineWidth;
+        item.zOrder = data.style.default.zOrder;
+        item.strokeColor = new SColor(data.style.default.strokeColor);
+        item.fillColor = new SColor(data.style.default.backgroundColor);
+        item.radius = 20; //设置弧度
+        item.data = data;
+        return item;
+    }
+}

+ 64 - 0
src/components/planClass/planScene.ts

@@ -0,0 +1,64 @@
+/*
+ * *********************************************************************************************************************
+ *
+ *          !!
+ *        .F88X
+ *        X8888Y
+ *      .}888888N;
+ *        i888888N;        .:!              .I$WI:
+ *          R888888I      .'N88~            i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
+ *          .R888888I    .;N8888~          .X8'  "8I.!,/8"  !%NY8`"8I8~~8>,88I
+ *            +888888N;  .8888888Y                                  "&&8Y.}8,
+ *            ./888888N;  .R888888Y        .'}~    .>}'.`+>  i}!    "i'  +/'  .'i~  !11,.:">,  .~]!  .i}i
+ *              ~888888%:  .I888888l      .]88~`1/iY88Ii+1'.R$8$8]"888888888>  Y8$  W8E  X8E  W8888'188Il}Y88$*
+ *              18888888    E8888881    .]W%8$`R8X'&8%++N8i,8N%N8+l8%`  .}8N:.R$RE%N88N%N$K$R  188,FE$8%~Y88I
+ *            .E888888I  .i8888888'      .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
+ *            8888888I  .,N888888~        ~88i"8W,!N8*.I88.}888%F,i$88"F88"  888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
+ *          i888888N'      I888Y          ]88;/EX*IFKFK88X  K8R  .l8W  88Y  ~88}'88E&%8W.X8N``]88!.$8K  .:W8I
+ *        .i888888N;        I8Y          .&8$  .X88!  i881.:%888>I88  ;88]  +88+.';;;;:.Y88X  18N.,88l  .+88/
+ *      .:R888888I
+ *      .&888888I                                          Copyright (c) 2009-2020.  博锐尚格科技股份有限公司
+ *        ~8888'
+ *        .!88~                                                                     All rights reserved.
+ *
+ * *********************************************************************************************************************
+ */
+
+import { SGraphScene } from "@persagy-web/graph/lib";
+import { SMouseEvent } from "@persagy-web/base/lib";
+import { SColor } from '@persagy-web/draw/lib';
+
+/**
+ * plan 图场景
+ *
+ * @author  贠星 <yunxing0102@163.com>
+ */
+export class planScene extends SGraphScene {
+    constructor() {
+        super()
+    }
+    onMouseDown(event: SMouseEvent): any {
+        if (!super.onMouseDown(event)) {
+            this.vueOnMouseDown(null,event) //外部调用
+        }
+    }
+
+    /**
+     *  改变 view 背景色
+     *  
+     * @param val 颜色值 
+     */
+    changeBackgroundColor(val: any) {
+        // console.log('valval',val)
+        if (!this.view) return;
+        if (val) {
+            if (val.includes('#')) {
+                this.view.backgroundColor = new SColor(val)
+            }
+            this.view.update()
+        }
+    }
+
+    vueOnMouseDown(item:any=null,event: SMouseEvent) {
+    }
+}

+ 67 - 0
src/components/scale.vue

@@ -0,0 +1,67 @@
+<!-- 放大比例缩小组件 -->
+<template>
+  <div class="scale-btn">
+    <div class="icon-svg sub" @click="sacle(0)">
+      <svg width="20" height="2" viewBox="0 0 20 2" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1.04999 0.0498047H19.05C19.65 0.0498047 19.95 0.349805 19.95 0.949805C19.95 1.5498 19.65 1.8498 19.05 1.8498H1.04999C0.449994 1.8498 0.149994 1.5498 0.149994 0.949805C0.149994 0.349805 0.449994 0.0498047 1.04999 0.0498047V0.0498047Z" fill="#E9E9E9"/>
+</svg>
+
+    </div>
+    <div class="icon-svg plus" @click="sacle(1)"><svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0.974976 9.58203H19.725C20.35 9.58203 20.6625 9.89453 20.6625 10.5195C20.6625 11.1445 20.35 11.457 19.725 11.457H0.974976C0.349976 11.457 0.0374756 11.1445 0.0374756 10.5195C0.0374756 9.89453 0.349976 9.58203 0.974976 9.58203V9.58203Z" fill="#E9E9E9"/>
+<path d="M8.99811 19.9633V1.13828C8.99811 0.641225 9.40105 0.238281 9.89811 0.238281C10.3952 0.238281 10.7981 0.641225 10.7981 1.13828V19.9633C10.7981 20.4603 10.3952 20.8633 9.89811 20.8633C9.40105 20.8633 8.99811 20.4603 8.99811 19.9633H8.99811Z" fill="#E9E9E9"/>
+</svg></div>
+  </div>
+</template>
+<script>
+export default {
+  data() {
+    return {};
+  },
+  methods: {
+    sacle(data) {
+      this.$emit("sacle", data);
+    },
+  },
+};
+</script>
+<style lang="less" scoped>
+.scale-btn {
+  display: flex;
+  align-items: center;
+  // padding-top: 4px;
+  // padding-bottom: 4px;
+  border: 1px solid #5D6177;
+  border-radius: 4px;
+  width: 93px;
+  height: 36px;
+  line-height: 36px;
+  font-size: 0;
+  .icon-svg {
+    width: 50%;
+    //height: 28px;
+    text-align: center;
+    cursor: pointer;
+    svg {
+      width: 16px;
+      height: 16px;
+      vertical-align: middle;
+      path {
+          transition: fill .3s;
+        }
+    }
+
+    &:hover {
+      svg {
+        path {
+          fill: #5D6177;
+        }
+      }
+    }
+  }
+  .plus {
+    border-left: 1px solid #5D6177;
+    
+  }
+}
+</style>

+ 31 - 0
src/components/tooltip.vue

@@ -0,0 +1,31 @@
+<template >
+  <div id="tooltip">
+    <slot></slot>
+  </div>
+</template>
+<script>
+export default {
+  data() {
+    return {};
+  },
+  mounted() {
+    // const dom = this.$refs.tooltip_map;
+    // document.onmousemove = (ev) => {
+    //   const event = window.event || ev;
+    //   dom.style.left = `${event.clientX}px`;
+    //   dom.style.top = `${event.clientY}px`;
+    // };
+  },
+};
+</script>
+<style lang="less" scoped>
+#tooltip {
+  min-width: 260px;
+  min-height: 40px;
+  background:#1D2129;
+  position: absolute;
+  z-index: 99;
+  left: 0;
+  top: 0;
+}
+</style>

+ 12 - 0
src/main.ts

@@ -0,0 +1,12 @@
+import Vue from 'vue'
+import App from './App.vue'
+import router from './router'
+import store from './store'
+
+Vue.config.productionTip = false
+
+new Vue({
+  router,
+  store,
+  render: h => h(App)
+}).$mount('#app')

+ 19 - 0
src/router/index.ts

@@ -0,0 +1,19 @@
+import Vue from 'vue'
+import VueRouter, { RouteConfig } from 'vue-router'
+import Home from '../views/Home.vue'
+
+Vue.use(VueRouter)
+
+const routes: Array<RouteConfig> = [
+  {
+    path: '/',
+    name: 'Home',
+    component: Home
+  },
+]
+
+const router = new VueRouter({
+  routes
+})
+
+export default router

+ 13 - 0
src/shims-tsx.d.ts

@@ -0,0 +1,13 @@
+import Vue, { VNode } from 'vue'
+
+declare global {
+  namespace JSX {
+    // tslint:disable no-empty-interface
+    interface Element extends VNode {}
+    // tslint:disable no-empty-interface
+    interface ElementClass extends Vue {}
+    interface IntrinsicElements {
+      [elem: string]: any;
+    }
+  }
+}

+ 4 - 0
src/shims-vue.d.ts

@@ -0,0 +1,4 @@
+declare module '*.vue' {
+  import Vue from 'vue'
+  export default Vue
+}

+ 15 - 0
src/store/index.ts

@@ -0,0 +1,15 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex)
+
+export default new Vuex.Store({
+  state: {
+  },
+  mutations: {
+  },
+  actions: {
+  },
+  modules: {
+  }
+})

+ 295 - 0
src/views/Home.vue

@@ -0,0 +1,295 @@
+<template>
+    <div class="persagyPlan">
+        <basePlan @onMousedown="onMousedown" @postDeviceIds="postDeviceIds" ref="planEl"></basePlan>
+        <tooltip ref="tooltip_map" v-show="showtip" class="toolTip">
+            <div class="title">
+                {{ this.tooltipName }}
+            </div>
+            <div class="tip-body">
+                <div class="info">
+                    <p v-for="(item, index) in device_params" :key="index">
+                        <span class="label">{{ item.infoName }}:</span>
+                        <span class="value">{{ showData(item) }}</span>
+                        <span class="unit">{{ item.unit }}</span>
+                    </p>
+                </div>
+            </div>
+            <div class="tip-footer">查看设备详情</div>
+        </tooltip>
+    </div>
+</template>
+<script>
+import { readPubGroup, readDeviceParams, readDeviceStatus } from "@/api/plan"; // 引入获取底图得接口
+import basePlan from "@/components/basePlan.vue";
+import tooltip from "@/components/tooltip.vue";
+export default {
+    components: { basePlan, tooltip },
+    data() {
+        return {
+            showtip: false,
+            tooltipName: "",
+            device_params: [],
+            deviceIds: [],
+            graphId: "e4c6b131ced74032b02b5721cb496b77",
+            id: "ad1195f2492f41e3a06f792d6701365c",
+        };
+    },
+    mounted() {
+        let _this = this;
+        let canvasEl = document.getElementsByTagName("canvas")[0];
+        window._resizeTimer = null;
+        window.addEventListener("resize", () => {
+            clearTimeout(window._resizeTimer);
+            window._resizeTimer = setTimeout(() => {
+                canvasEl.height = document.body.clientHeight;
+                canvasEl.width = document.body.clientWidth;
+                _this.$refs.planEl.fixWindow();
+            }, 50);
+        });
+    },
+    beforeMount() {
+        let searchStr = window.location.search.substr(1);
+        // 设备
+        // searchStr =
+        //     'projectId=Pj1101050029&&buildingId=Bd1101050029cb77fbd1846611eaac87cd1cd6a961c6&floorId=Fl11010500295de391e3e5564ce58003c7e5391dc5e4&id=c57264b1252245e6b2713f1cbb9c4148&graphId=cbe7180ead0f420782acf1c39382319a&floorMap=base/ebd53bb00d3511eb9a1db95f725712e8.jsonz'
+
+        // 设备 + 空间
+        searchStr =
+            "projectId=Pj1101050029&&buildingId=Bd1101050029cb77fbd1846611eaac87cd1cd6a961c6&floorId=Fl1101050029f18b92c5ceaf408d893e257bf03692df&id=0234df7a9a7b40dca38358b7e0a71ce9&graphId=e43a9c03d9bb482ca96b3b545735be35&floorMap=base/a5f453020d4111eb9a1d57eee76e51f1.jsonz";
+        // buildingId=Bd1101050029cb77fbd1846611eaac87cd1cd6a961c6&floorId=Fl1101050029f18b92c5ceaf408d893e257bf03692df&name=%E5%BE%88%E8%B4%B9%E5%8A%B2&id=0234df7a9a7b40dca38358b7e0a71ce9&graphId=e43a9c03d9bb482ca96b3b545735be35&version=1.1.1&floorMap=base%2Fa5f453020d4111eb9a1d57eee76e51f1.jsonz
+        // 项目id,建筑id,楼层id,图id,图graphId,底图floorMap
+        const params = this.queryURLParams(searchStr);
+        Object.entries(params).map((arr) => {
+            this[arr[0]] = arr[1];
+            window[`_${arr[0]}`] = arr[1];
+        });
+        console.log(params);
+        // console.log("here");
+        // console.log("id:", this.id);
+        // console.log("graphId:", this.graphId);
+        // console.log("url:", this.url);
+        // console.log("projectId:", this.projectId);
+    },
+
+    methods: {
+        /**
+         * 查询url参数
+         */
+        queryURLParams(url) {
+            let obj = {};
+            url.replace(/([^?=&#]+)=([^?=&#]+)/g, (_, key, value) => (obj[key] = value));
+            url.replace(/#([^?=&#]+)/g, (_, hash) => (obj["HASH"] = hash));
+            return obj;
+        },
+        postDeviceIds(ids) {
+            this.deviceIds = ids;
+            if (ids.length > 0) {
+                readDeviceStatus({ objectIds: ids }).then((res) => {
+                    // console.log('res')
+                    // console.log(res)
+                    window.parse.nodes.forEach((nodeItem) => {
+                        let sItem = res.content.find((_item) => {
+                            return _item.objectId == nodeItem._data.attachObjectIds[0];
+                        });
+
+                        // if(sItem == null){
+                        //   sItem = res.content[0]
+                        // }
+                        let key = null;
+                        /**
+             *  0: 灰
+                1:蓝
+                2:红
+                3:黄
+                4:绿
+                5:棕
+             *
+             */
+                        if (sItem) {
+                            switch (sItem.status) {
+                                case 0:
+                                    // 空
+                                    key = 0;
+                                    break;
+                                case 1:
+                                    // 运行
+                                    key = 1;
+                                    break;
+                                case 2:
+                                    // 关闭
+                                    key = 0;
+                                    break;
+                                default:
+                                    break;
+                            }
+                            let picUrl = nodeItem._data.properties.state.find((item) => {
+                                return item.state == key;
+                            }).pic;
+                            if (nodeItem.__picUrl && nodeItem.__picUrl == picUrl) {
+                            } else {
+                                nodeItem.__picUrl = picUrl;
+                                nodeItem.url = window.img_baseurl + "/image-service/common/image_get?systemId=dataPlatform&key=" + picUrl;
+                                // nodeItem.url ='/dp-auxiliary/image-service/common/image_get?systemId=dataPlatform&key='+picUrl
+                            }
+                        }
+                    });
+                });
+            }
+        },
+        showData(item) {
+            if (item.dataSource) {
+                return item.dataSource.find((item) => {
+                    return item.code == "0";
+                }).name;
+            } else {
+                return item.data;
+            }
+        },
+        onMousedown(item, e) {
+            let time = new Date().getTime();
+            window._now = console.log("item:", item);
+            setTimeout(() => {
+                if (item) {
+                    clearTimeout(window._caller);
+                    let operationType = "click";
+                    console.log(111);
+                    this.showtip = true;
+                    this.tooltipName = "test";
+                    this.device_params = [
+                        {
+                            infoName: "hhh",
+                            unit: "g",
+                        },
+                    ];
+                    this.$refs.tooltip_map.$el.style.left = e[0].offsetX + "px";
+                    this.$refs.tooltip_map.$el.style.top = e[0].offsetY + "px";
+                    return;
+                    let deviceId = item.data.attachObjectIds[0];
+                    if (window._now) {
+                        let diff = time - window._now;
+                        console.log("diff:", diff);
+                        if (diff < 400) {
+                            operationType = "dbclick";
+                            // 双击
+                        } else {
+                            // 单击
+                        }
+                    }
+                    window._now = time;
+                    if (operationType == "click") {
+                        // 单击
+                        window._caller = setTimeout(() => {
+                            readDeviceParams({ objectId: deviceId }).then((res) => {
+                                this.tooltipName = item.data.name;
+                                this.device_params = res.content;
+                                this.$refs.tooltip_map.$el.style.left = e[0].offsetX + "px";
+                                this.$refs.tooltip_map.$el.style.top = e[0].offsetY + "px";
+                                this.showtip = true;
+                            });
+                        }, 300);
+                    } else {
+                        // 双击
+                        try {
+                            window.postMsgToU3d(JSON.stringify({ time: new Date(), data: { deviceId: deviceId } }));
+                        } catch (error) {
+                            console.error("to u3d error", error);
+                        }
+                    }
+                } else {
+                    this.showtip = false;
+                }
+            }, 200);
+        },
+
+        // 移入
+        onMousedownx(item, e) {
+            // return false;
+
+            let deviceId = item.data.attachObjectIds[0];
+            let res = readDeviceParams(deviceId);
+            this.tooltipName = item.data.name;
+            this.device_params = res.content;
+            this.showtip = true;
+            console.log(e[0].offsetX + "px");
+            this.$refs.tooltip_map.$el.style.left = e[0].offsetX + "px";
+            this.$refs.tooltip_map.$el.style.top = e[0].offsetY + "px";
+        },
+    },
+};
+</script>
+<style lang="less">
+.persagyPlan {
+    padding: 6 px 10px 6px 10px;
+    width: 100%;
+    height: 100%;
+    overflow: hidden;
+}
+.title {
+    padding: 10px 16px;
+    line-height: 22px;
+    color: #ebeef5;
+    font-size: 16px;
+    font-weight: 600;
+}
+.toolTip {
+    min-width: 40px;
+    box-shadow: 0px 2px 4px 0px rgba(31, 36, 41, 0.1);
+    border: 1px solid #5d6177;
+    // padding: 6px 10px 6px 10px;
+    position: absolute;
+    border-radius: 8px;
+    box-shadow: 0px 1px 13px rgba(0, 0, 0, 0.189549), 0px 1px 11px rgba(0, 0, 0, 0.5);
+}
+.tip-body {
+    border-top: 1px solid #5d6177;
+    border-bottom: 1px solid #5d6177;
+}
+.info {
+    padding: 16px;
+    max-height: 280px;
+    overflow: auto;
+    line-height: 29px;
+    span {
+        color: #a7abc0;
+    }
+    .value {
+        color: #fff;
+        // margin-left: 12px;
+    }
+    .unit {
+        margin-left: 0;
+    }
+}
+.tip-footer {
+    width: 100%;
+    height: 50px;
+    line-height: 50px;
+    font-size: 16px;
+    text-align: center;
+    color: #a7abc0;
+    transition: background-color 0.3s;
+    cursor: pointer;
+    &:hover {
+        color: #fff;
+        background-color: rgba(0, 145, 255, 0.295974);
+    }
+}
+
+::-webkit-scrollbar {
+    width: 6px;
+    height: 6px;
+}
+
+::-webkit-scrollbar-track {
+    border-radius: 0;
+}
+
+::-webkit-scrollbar-thumb {
+    background-color: #21262f;
+    border-radius: 3px;
+
+    &:hover {
+        background-color: #21262f;
+    }
+}
+</style>

+ 40 - 0
tsconfig.json

@@ -0,0 +1,40 @@
+{
+  "compilerOptions": {
+    "target": "esnext",
+    "module": "esnext",
+    "strict": true,
+    "jsx": "preserve",
+    "importHelpers": true,
+    "moduleResolution": "node",
+    "experimentalDecorators": true,
+    "skipLibCheck": true,
+    "esModuleInterop": true,
+    "allowSyntheticDefaultImports": true,
+    "sourceMap": true,
+    "baseUrl": ".",
+    "types": [
+      "webpack-env"
+    ],
+    "paths": {
+      "@/*": [
+        "src/*"
+      ]
+    },
+    "lib": [
+      "esnext",
+      "dom",
+      "dom.iterable",
+      "scripthost"
+    ]
+  },
+  "include": [
+    "src/**/*.ts",
+    "src/**/*.tsx",
+    "src/**/*.vue",
+    "tests/**/*.ts",
+    "tests/**/*.tsx"
+  ],
+  "exclude": [
+    "node_modules"
+  ]
+}

+ 33 - 0
vue.config.js

@@ -0,0 +1,33 @@
+module.exports = {
+    devServer: {
+        hot: true,
+        proxy: {
+            '/labsl': {
+                // target: 'http://39.102.40.239:8080',
+                target: 'http://60.205.177.43:28888',
+                changeOrigin: true,
+                secure: false,
+            },
+            '/equip-component': {
+                // target: 'http://39.102.40.239:8080',
+                target: 'http://60.205.177.43:28888',
+                changeOrigin: true,
+                secure: false,
+            },
+            // 图片服务器
+            '/image-service': {
+                // target: 'http://39.102.40.239',
+                target: "http://39.97.179.199:8891",
+                changeOrigin: true,
+                secure: false,
+            }
+        },
+        // 关闭esline
+        overlay: {
+            warnings: false,
+            errors: false
+        },
+        // lintOnSave: false
+    },
+    lintOnSave: false,
+};