Browse Source

Merge branch 'master' of http://39.106.8.246:3003/web/ibms

# Conflicts:
#	src/router/sagacloud.js
chuwu 6 years ago
parent
commit
e521b2bd4f
44 changed files with 6318 additions and 9 deletions
  1. 70 0
      src/assets/js/items/SGraphyCircleItem.js
  2. 59 0
      src/assets/js/items/SGraphyImageItem.js
  3. 66 0
      src/assets/js/items/SGraphyLineItem.js
  4. 76 0
      src/assets/js/items/SGraphyPillarItems.js
  5. 257 0
      src/assets/js/items/SGraphyPolygonItem.js
  6. 100 0
      src/assets/js/items/SGraphyRectItem.js
  7. 51 0
      src/assets/js/items/SGraphyTextItems.js
  8. 66 0
      src/assets/js/items/SGraphyVirtualItem.js
  9. 44 0
      src/assets/node-templete/SGraphy/SCanvas.js
  10. 30 0
      src/assets/node-templete/SGraphy/SGraphyEnums.js
  11. 396 0
      src/assets/node-templete/SGraphy/SGraphyItem.js
  12. 201 0
      src/assets/node-templete/SGraphy/SGraphyScene.js
  13. 280 0
      src/assets/node-templete/SGraphy/SGraphyView.js
  14. 53 0
      src/assets/node-templete/SGraphy/SMouseEvent.js
  15. 201 0
      src/assets/node-templete/SGraphy/items/SGraphyClockItem.js
  16. 58 0
      src/assets/node-templete/SGraphy/items/SGraphyLineItem.js
  17. 57 0
      src/assets/node-templete/SGraphy/items/SGraphyPolygonItem.js
  18. 64 0
      src/assets/node-templete/SGraphy/items/SGraphyRectItem.js
  19. 61 0
      src/assets/node-templete/SGraphy/items/SGraphyVirtualItem.js
  20. 40 0
      src/assets/node-templete/SGraphy/types/SPoint.js
  21. 169 0
      src/assets/node-templete/SGraphy/types/SRect.js
  22. 9 0
      src/assets/node-templete/index.js
  23. 1 0
      src/components/common/search_input.vue
  24. 1 0
      src/components/data_admin/buildData/style.less
  25. 1 0
      src/components/data_admin/input.vue
  26. 148 0
      src/views/data_admin/buildGraphy/buildGraphy.vue
  27. 922 0
      src/views/data_admin/buildGraphy/graphyCanvas.vue
  28. 543 0
      src/views/data_admin/buildGraphy/graphyTabs.vue
  29. 92 0
      src/views/data_admin/buildGraphy/graphyTree.vue
  30. 156 0
      src/views/data_admin/buildGraphy/index.vue
  31. 114 0
      src/views/data_admin/buildGraphy/lib/cascaders/assets.vue
  32. 120 0
      src/views/data_admin/buildGraphy/lib/cascaders/system.vue
  33. 75 0
      src/views/data_admin/buildGraphy/lib/detailsDia.vue
  34. 119 0
      src/views/data_admin/buildGraphy/lib/floorCascader.vue
  35. 315 0
      src/views/data_admin/buildGraphy/lib/formInput.vue
  36. 180 0
      src/views/data_admin/buildGraphy/lib/lookImages.vue
  37. 58 0
      src/views/data_admin/buildGraphy/lib/myPagination.vue
  38. 57 0
      src/views/data_admin/buildGraphy/lib/qrcode.vue
  39. 207 0
      src/views/data_admin/buildGraphy/lib/uploadFiles.vue
  40. 109 0
      src/views/data_admin/buildGraphy/lib/uploadImg.vue
  41. 321 0
      src/views/data_admin/buildGraphy/lib/uploadImgs.vue
  42. 365 0
      src/views/data_admin/buildGraphy/lib/uploadImgsName.vue
  43. 4 3
      src/views/data_admin/buildLog/index.vue
  44. 2 6
      src/views/data_admin/buildUser/index.vue

+ 70 - 0
src/assets/js/items/SGraphyCircleItem.js

@@ -0,0 +1,70 @@
+/**
+ * 线条
+ */
+import SGraphyItem from '../../node-templete/SGraphy/SGraphyItem'
+import SRect from '../../node-templete/SGraphy/types/SRect';
+
+export default class SGraphyCircleItem extends SGraphyItem {
+    /**
+     * 构造函数
+     * 
+     * @param X  圆中心点X
+     * @param Y  圆中心点Y
+     * @param Radius   圆的半径
+     * 
+     * @param color  线的颜色
+     * @param isVirtual    是否为虚线
+     */
+    constructor(X, Y, color, Radius, isSolid, name, parent = null) {
+        super(parent)
+        this.X = X
+        this.Y = Y
+        this.color = color
+        this.Radius = Radius
+        this.isSolid = isSolid
+        this.minX = this.X - this.Radius
+        this.minY = this.Y - this.Radius
+        this.maxX = this.X + this.Radius
+        this.maxY = this.Y + this.Radius
+        this.sAngle = null || 0
+        this.eAngle = null || 2 * Math.PI
+        this.name = name
+        this.type = 6
+        this.lineWidth = null
+    }
+
+    /**
+     * Item对象边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect() {
+        return new SRect(this.minX, this.minY, this.maxX - this.minX, this.maxY - this.minY)
+    }
+
+    /**
+     * 绘制线条
+     * 
+     * @param canvas 画布
+     * @param rect   绘制区域
+     */
+
+    onDraw(canvas, rect) {
+        canvas.lineWidth = this.lineWidth || 240
+        canvas.strokeStyle = this.color || '#000'
+        canvas.fillStyle = this.color || '#000'
+        canvas.beginPath();
+        canvas.arc(this.X, this.Y, this.Radius, this.sAngle, this.eAngle);
+        if (!!this.isSolid) {
+            canvas.fillStyle = this.color; //填充颜色,默认是黑色
+            canvas.fill(); //画实心圆
+        }
+        canvas.stroke()
+        if (!!this.name) {
+            canvas.font = "oblique small-caps bold " + this.lineWidth * 10 + "px Arial";
+            // canvas.font = "oblique small-caps bold " + 10 + "px Arial";
+            canvas.fillStyle = 'green'
+            canvas.fillText(this.name, this.X, this.Y);
+        }
+    }
+}

+ 59 - 0
src/assets/js/items/SGraphyImageItem.js

@@ -0,0 +1,59 @@
+/**
+ * 图片
+ * 
+ * 
+ */
+import SGraphyItem from '../../node-templete/SGraphy/SGraphyItem'
+import SRect from '../../node-templete/SGraphy/types/SRect'
+export default class SGraphyImageItem extends SGraphyItem {
+    /**
+     * 构造函数
+     * 
+     * @param width  图片宽度
+     * @param height  图片高度
+     * @param url    图片url
+     * @param id     point的Id
+     * @param X      图片向x轴的偏移量
+     * @param Y      图片向y轴的偏移量
+     * @param downUrl 图片按下时的url
+     * @param parent  指向父元素
+     */
+    constructor(width, height, url, id, X, Y, downUrl, parent = null) {
+            super(parent)
+            this.width = width
+            this.height = height
+            this.url = url
+            this.id = id
+            this.X = X
+            this.Y = Y
+            this.downUrl = downUrl
+            this.imgFalg = false
+            this.img = new Image()
+            this.img.src = this.url
+            this.img.style.width = this.width
+            this.img.style.height = this.height
+            this.canMove = true
+            this.type = 1
+        } //constructor
+
+    /**
+     * Item对象边界区域
+     *
+     * @return  SRect
+     */
+    boundingRect() {
+            return new SRect(0, 0, this.width * 100, this.height * 100)
+        } // Function boundingRect()
+
+    /**
+     * 绘制图片
+     * 
+     * @param canvas 画布
+     * @param rect   绘制区域
+     */
+    onDraw(canvas, rect) {
+        // canvas.moveTo(this.X, this.Y)
+        // canvas.drawImage(this.img, 0, 0, this.width, this.height, this.X, this.Y, this.width * 100, this.height * 100)
+        canvas.drawImage(this.img, 0, 0, this.width, this.height, 0, 0, this.width * 100, this.height * 100)
+    }
+}

+ 66 - 0
src/assets/js/items/SGraphyLineItem.js

@@ -0,0 +1,66 @@
+/**
+ * 线条
+ */
+import SGraphyItem from '../../node-templete/SGraphy/SGraphyItem'
+import SRect from '../../node-templete/SGraphy/types/SRect';
+
+export default class SGraphyLineItem extends SGraphyItem {
+    /**
+     * 构造函数
+     * 
+     * @param startX  线的起始x坐标
+     * @param startY  线的起始y坐标
+     * @param endX    线的终止x坐标
+     * @param endY    线的终止y坐标
+     * @param width   线的宽度
+     * 
+     * @param color  线的颜色
+     * @param isVirtual    是否为虚线
+     */
+    constructor(startX, startY, endX, endY, color, width, isVirtual, parent = null) {
+        super(parent)
+        this.startX = startX
+        this.startY = startY
+        this.endX = endX
+        this.endY = endY
+        this.color = color
+        this.width = width
+        this.isVirtual = isVirtual
+        this.minX = Math.min(this.startX, this.endX)
+        this.minY = Math.min(this.startY, this.endY)
+        this.maxX = Math.max(this.startX, this.endX)
+        this.maxY = Math.max(this.startY, this.endY)
+        this.name = null
+        this.type = 2
+        this.lineWidth = null
+    }
+
+    /**
+     * Item对象边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect() {
+        return new SRect(this.minX, this.minY, this.maxX - this.minX, this.maxY - this.minY)
+    }
+
+    /**
+     * 绘制线条
+     * 
+     * @param canvas 画布
+     * @param rect   绘制区域
+     */
+
+    onDraw(canvas, rect) {
+        canvas.lineWidth = this.lineWidth || this.width || 240
+        canvas.strokeStyle = this.color || '#000'
+        if (this.isVirtual) {
+            canvas.setLineDash([100, 80])
+            canvas.strokeStyle = 'green'
+        }
+        canvas.beginPath();
+        canvas.moveTo(this.startX, this.startY)
+        canvas.lineTo(this.endX, this.endY)
+        canvas.stroke()
+    }
+}

+ 76 - 0
src/assets/js/items/SGraphyPillarItems.js

@@ -0,0 +1,76 @@
+/**
+ * 不规则多边形,元空间
+ */
+import SGraphyItem from '../../node-templete/SGraphy/SGraphyItem'
+import SRect from '../../node-templete/SGraphy/types/SRect';
+
+function getItem(arr, name) {
+    if (arr && arr.length) {
+        return arr.map(item => {
+            return item[name]
+        })
+    } else {
+        return [0]
+    }
+}
+
+
+export default class SGraphyPolygonItem extends SGraphyItem {
+    /**
+     * 
+     * 构造函数
+     * 
+     * @param jsonArr  空间线条数组
+     * @param lineWidth    空间线条的宽度
+     * @param color    空间线条的颜色
+     * @param fillColor  空间的填充颜色
+     * 
+     */
+    constructor(jsonArr, lineWidth, color, fillColor, parent = null) {
+            super(parent)
+            this.jsonArr = jsonArr
+            this.lineWidth = lineWidth
+            this.color = color
+            this.fillColor = fillColor
+            let xArr = getItem(this.jsonArr, 'X')
+            let yArr = getItem(this.jsonArr, 'Y')
+            this.minX = Math.min.apply(null, xArr) || 0
+            this.minY = Math.min.apply(null, yArr) || 0
+            this.width = Math.max.apply(null, xArr) - this.minX || 0
+            this.height = Math.max.apply(null, yArr) - this.minY || 0
+            this.type = 5
+        } //constructor
+
+    /**
+     * Item的边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect() {
+        return new SRect(this.minX, this.minY, this.width, this.height)
+    }
+
+    /**
+     * 绘制不规则多边形
+     * 
+     * @param canvas 画布
+     * @param rect   绘制区域
+     */
+    onDraw(canvas, rect) {
+        if (this.jsonArr && this.jsonArr.length) {
+            canvas.beginPath();
+            canvas.lineWidth = 240
+            canvas.lineCap = 'butt';
+            canvas.strokeStyle = this.color || '#000'
+            canvas.fillStyle = this.fillColor || '#fff'
+            canvas.moveTo(this.jsonArr[0].X, this.jsonArr[0].Y)
+            for (let i = 1; i < this.jsonArr.length; i++) {
+                canvas.lineTo(this.jsonArr[i].X, this.jsonArr[i].Y)
+            }
+            canvas.lineTo(this.jsonArr[0].X, this.jsonArr[0].Y)
+            canvas.closePath()
+            canvas.fill()
+            canvas.stroke()
+        }
+    }
+}

+ 257 - 0
src/assets/js/items/SGraphyPolygonItem.js

@@ -0,0 +1,257 @@
+/**
+ * 不规则多边形,元空间
+ */
+import SGraphyItem from '../../node-templete/SGraphy/SGraphyItem'
+import SRect from '../../node-templete/SGraphy/types/SRect';
+
+function getItem(arr, name) {
+    if (arr && arr.length) {
+        return arr.map(item => {
+            return item[name]
+        })
+    } else {
+        return [0]
+    }
+}
+
+function changeArr(arr) {
+    if (arr && arr.length) {
+        return arr.map(item => {
+            return [
+                item.X, item.Y
+            ]
+        })
+    } else {
+        return [0]
+    }
+}
+/**
+ * 求不规则多边形重点
+ * @param {points} 数组,多个点位坐标
+ *  
+ * @return {x, y} 重点点位坐标
+ */
+// function getCenterOfGravityPoint(points) {
+//     let area = 0,
+//         gx = 0,
+//         gy = 0,
+//         i = 1,
+//         px1, px2, py1, py2, temp, length = points.length;
+//     for (i; i <= length; i++) {
+//         px1 = points[(i % length)].X;
+//         px2 = points[(i - 1)].X;
+//         py1 = points[(i % length)].Y;
+//         py2 = points[(i - 1)].Y;
+//         temp = (px1 * py2 - py1 * px2) / 2
+//         area += temp;
+//         gx += temp * (px1 + px2) / 3
+//         gy += temp * (py1 + py2) / 3
+//     }
+
+//     gx = gx / area
+//     gy = gy / area
+
+//     return {
+//         x: gx,
+//         y: gy
+//     }
+// }
+
+
+export default class SGraphyPolygonItem extends SGraphyItem {
+    /**
+     * 
+     * 构造函数
+     * 
+     * @param jsonArr  空间线条数组
+     * @param lineWidth    空间线条的宽度
+     * @param color    空间线条的颜色
+     * @param fillColor  空间的填充颜色
+     * 
+     */
+    constructor(jsonArr, lineWidth, color, fillColor, id, centerOfGravityPoint, name, paths, faceColor, businessColor, isBusiness, parent = null) {
+            super(parent)
+            this.jsonArr = jsonArr
+            this.lineWidth = lineWidth
+            this.color = color
+            this.id = id
+            this.name = name //实际渲染名字
+            this.fillColor = fillColor
+            let xArr = getItem(this.jsonArr, 'X')
+            let yArr = getItem(this.jsonArr, 'Y')
+            this.minX = Math.min.apply(null, xArr) || 0
+            this.maxX = Math.max.apply(null, xArr) || 0
+            this.maxY = Math.max.apply(null, yArr) || 0
+            this.minY = Math.min.apply(null, yArr) || 0
+            this.width = this.maxX - this.minX || 0
+            this.height = this.maxY - this.minY || 0
+            this.type = 3
+            this.businessName = null
+            this.faceColor = faceColor || '#cacaca' //颜色
+            this.businessId = null //业务空间id
+            this.isBusiness = isBusiness || 1 //状态
+            this.businessColor = businessColor || 'rgba(68,161,140,.4)' //业务空间颜色
+            this.businessFaceColor = "#333"
+            this.containsArr = changeArr(this.jsonArr)
+            this.paths = null
+            if (paths && paths.length > 1) {
+                this.paths = paths.map(item => {
+                    if (item && item.length) {
+                        return changeArr(item)
+                    } else {
+                        return undefined
+                    }
+                }).filter(d => d)
+            }
+            this.centerOfGravityPoint = centerOfGravityPoint
+        } //constructor
+
+    /**
+     * Item的边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect() {
+        return new SRect(this.minX, this.minY, this.width, this.height)
+    }
+
+
+    /**
+     * 判断item是否包含点x,y
+     *
+     * @param   x       横坐标(当前item)
+     * @param   y       纵坐标(当前item)
+     *
+     * @return  boolean
+     */
+    contains(x, y) {
+        let falg = false,
+            isFullIn = false //是否在镂空图形内
+        if (this.paths instanceof Array) {
+            for (let i = 1; i < this.paths.length; i++) {
+                if (this.isIn(x, y, this.paths[i])) {
+                    //位置信息在镂空图形内
+                    isFullIn = true
+                    break
+                }
+            }
+            // //如果鼠标在大图形内切在镂空图形中返回false
+            if (this.isIn(x, y, this.containsArr) && isFullIn) {
+                falg = false
+            } else if (this.isIn(x, y, this.containsArr) && !isFullIn) {
+                falg = true
+            } else {
+                falg = this.isIn(x, y, this.containsArr)
+            }
+        } else {
+            falg = this.isIn(x, y, this.containsArr)
+        }
+        return falg
+    }
+
+
+    isIn(x, y, json) {
+        let nCross = 0,
+            point = typeof(x) == 'object' ? [x.x, x.y] : [x, y],
+            APoints = json,
+            length = APoints.length,
+            p1, p2, i, xinters;
+        p1 = APoints[0];
+        for (i = 1; i <= length; i++) {
+            p2 = APoints[i % length];
+            if (
+                point[0] > Math.min(p1[0], p2[0]) &&
+                point[0] <= Math.max(p1[0], p2[0])
+            ) {
+                if (point[1] <= Math.max(p1[1], p2[1])) {
+                    if (p1[0] != p2[0]) {
+                        //计算位置信息
+                        xinters = (point[0] - p1[0]) * (p2[1] - p1[1]) / (p2[0] - p1[0]) + p1[1];
+                        if (p1[1] == p2[1] || point[1] <= xinters) {
+                            nCross++
+                        }
+                    }
+                }
+            }
+            p1 = p2;
+        }
+        if (nCross % 2 == 0) {
+            return false
+        } else {
+            return true
+        }
+
+    }
+
+    /**
+     * 绘制不规则多边形
+     * 
+     * @param canvas 画布
+     * @param rect   绘制区域
+     */
+    onDraw(canvas, rect) {
+        if (this.jsonArr && this.jsonArr.length) {
+            canvas.beginPath();
+            canvas.lineWidth = 220
+            canvas.lineCap = 'butt';
+            if (this.isBusiness == 1) {
+                canvas.strokeStyle = this.color || '#000'
+                canvas.fillStyle = this.fillColor
+            } else if (this.isBusiness == 2) {
+                //已有id 的业务空间
+                canvas.strokeStyle = this.color || '#000'
+                canvas.fillStyle = this.businessColor || '#fff'
+            } else if (this.isBusiness == 3) {
+                //被选择的元空间
+                canvas.strokeStyle = this.color || '#000'
+                canvas.lineWidth = 800
+                canvas.fillStyle = '#1abc9c'
+            } else if (this.isBusiness == 4) {
+                canvas.strokeStyle = 'rgba(251,226,1,.8)' || '#000'
+                canvas.fillStyle = '#fff' || '#fff'
+            } else if (this.isBusiness == 5) {
+                canvas.fillStyle = 'rgba(11,12,12,.2)' || '#fff'
+            } else if (this.isBusiness == 6) {
+                canvas.fillStyle = '#1abc9c'
+                canvas.lineWidth = 800
+                canvas.strokeStyle = 'rgba(68,161,140,.4)' || '#fff'
+            } else if (this.isBusiness == 7) {
+                canvas.strokeStyle = this.color || '#000'
+                canvas.fillStyle = this.businessColor || '#fff'
+            }
+            canvas.moveTo(this.jsonArr[0].X, this.jsonArr[0].Y)
+            for (let i = 1; i < this.jsonArr.length; i++) {
+                canvas.lineTo(this.jsonArr[i].X, this.jsonArr[i].Y)
+            }
+            canvas.lineTo(this.jsonArr[0].X, this.jsonArr[0].Y)
+            canvas.closePath()
+            canvas.fill()
+            canvas.stroke()
+            if (!!this.name) {
+                canvas.font = "normal small-caps bold 500px Arial";
+                if (this.isBusiness == 1) {
+                    canvas.fillStyle = this.faceColor
+                } else if (this.isBusiness == 2) {
+                    canvas.fillStyle = this.businessFaceColor;
+                } else if (this.isBusiness == 3) {
+                    //业务空间异常状态
+                    canvas.fillStyle = '#fff'
+                } else if (this.isBusiness == 4) {
+                    canvas.fillStyle = '#cacaca'
+                } else if (this.isBusiness == 6) {
+                    canvas.fillStyle = '#fff'
+                } else if (this.isBusiness == 7) {
+                    canvas.fillStyle = 'red'
+                }
+                if (!!this.businessName || !!this.businessId) {
+                    name = '👇   ' + this.businessName
+                } else {
+                    name = '⬇️   ' + this.name
+                }
+                canvas.fillText(name, this.centerOfGravityPoint.x, this.centerOfGravityPoint.y);
+                // canvas.fillText(this.name, (this.maxX - this.minX) / 2 + this.minX, (this.maxY - this.minY) / 2 + this.minY);
+            }
+            // canvas.fillText(this.name, this.jsonArr[0].X, this.jsonArr[0].Y);
+        }
+    }
+}

+ 100 - 0
src/assets/js/items/SGraphyRectItem.js

@@ -0,0 +1,100 @@
+/**
+ * 线条
+ */
+import SGraphyItem from '../../node-templete/SGraphy/SGraphyItem'
+import SRect from '../../node-templete/SGraphy/types/SRect';
+
+export default class SGraphyRectItem extends SGraphyItem {
+    /**
+     * 构造函数
+     * 
+     * @param X  矩形的开始点X
+     * @param Y  矩形的开始点Y
+     * @param width   矩形的宽度
+     * @param height  矩形的高度
+     * 
+     * @param isFill  矩形的是否填充
+     * @param fillColor  矩形的填充色彩
+     * @param text  矩形的文字
+     * @param textSize  矩形的文字大小
+     * @param color  矩形的颜色
+     * @param Tip   提示
+     */
+    constructor(X, Y, width, height, isFill, fillColor, text, textSize, color, Tip, parent = null) {
+        super(parent)
+        this.X = X
+        this.Y = Y
+        this.width = width
+        this.height = height
+        this.isFill = isFill
+        this.fillColor = fillColor
+        this.color = color
+        this.textSize = textSize || 6
+        this.type = 10
+        this.hoverColor = null
+        this.text = text.split(",")
+        this.fontStart = this.X
+        this.Tip = Tip
+    }
+
+    /**
+     * Item对象边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect() {
+        return new SRect(this.X, this.Y, this.width, this.height)
+    }
+
+    /**
+     * 判断item是否包含点x,y
+     *
+     * @param   x       横坐标(当前item)
+     * @param   y       纵坐标(当前item)
+     *
+     * @return  boolean
+     */
+    contains(x) {
+        if (this.X + this.width > x.x && x.x > this.X && this.Y + this.height > x.y && x.y > this.Y) {
+            return true
+        } else {
+            return false
+        }
+    }
+
+    /**
+     * 绘制线条
+     * 
+     * @param canvas 画布
+     * @param rect   绘制区域
+     */
+
+    onDraw(canvas, rect) {
+        canvas.beginPath();
+        canvas.lineWidth = "1";
+        if (this.isFill) {
+            if (!!this.hoverColor) {
+                canvas.fillStyle = this.hoverColor
+            } else {
+                canvas.fillStyle = this.fillColor
+            }
+            canvas.fillRect(this.X, this.Y, this.width, this.height);
+        } else {
+            canvas.rect(this.X, this.Y, this.width, this.height);
+        }
+        canvas.stroke();
+        if (!!this.text && this.text.length <= 1) {
+            canvas.font = this.textSize + "px 宋体";
+            canvas.fillStyle = this.color
+            canvas.fillText(this.text[0], this.fontStart, this.Y + this.height / 2);
+        } else if (!!this.text && this.text.length > 1) {
+            canvas.font = this.textSize + "px 宋体";
+            canvas.fillStyle = this.color
+            for (let i = 0; i < this.text.length; i++) {
+                canvas.fillText(this.text[i], this.fontStart, this.Y + this.height / 2 - this.textSize * i);
+            }
+        } else {
+            return
+        }
+    }
+}

+ 51 - 0
src/assets/js/items/SGraphyTextItems.js

@@ -0,0 +1,51 @@
+/**
+ * 线条
+ */
+import SGraphyItem from '../../node-templete/SGraphy/SGraphyItem'
+import SRect from '../../node-templete/SGraphy/types/SRect';
+
+export default class SGraphyTextItem extends SGraphyItem {
+    /**
+     * 构造函数
+     * 
+     * @param X  文字的开始点X
+     * @param Y  文字的开始点Y
+     * @param width   文字的宽度
+     * 
+     * @param color  文字的颜色
+     * @param text   文字的文字
+     */
+    constructor(X, Y, width, color, text, falg, font, parent = null) {
+        super(parent)
+        this.X = X
+        this.Y = Y
+        this.lineWidth = width
+        this.color = color
+        this.font = font ? font : "6px 宋体"
+        this.text = falg ? text + '→' : text
+    }
+
+    /**
+     * Item对象边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect() {
+        return new SRect(this.X, this.Y, 0, 0)
+    }
+
+    /**
+     * 绘制线条
+     * 
+     * @param canvas 画布
+     * @param rect   绘制区域
+     */
+
+    onDraw(canvas, rect) {
+        if (!!this.text) {
+            canvas.font = this.font;
+            canvas.fillStyle = this.color
+            canvas.fillText(this.text, this.X, this.Y);
+        }
+    }
+}

+ 66 - 0
src/assets/js/items/SGraphyVirtualItem.js

@@ -0,0 +1,66 @@
+/**
+ * 线条
+ */
+import SGraphyItem from '../../node-templete/SGraphy/SGraphyItem'
+import SRect from '../../node-templete/SGraphy/types/SRect';
+
+export default class SGraphyLineItem extends SGraphyItem {
+    /**
+     * 构造函数
+     * 
+     * @param startX  线的起始x坐标
+     * @param startY  线的起始y坐标
+     * @param endX    线的终止x坐标
+     * @param endY    线的终止y坐标
+     * @param width   线的宽度
+     * 
+     * @param color  线的颜色
+     * @param isVirtual    是否为虚线
+     * 
+     * @param canMove  移动
+     */
+    constructor(startX, startY, endX, endY, color, width, isVirtual, canMove, parent = null) {
+        super(parent)
+        this.startX = startX
+        this.startY = startY
+        this.endX = endX
+        this.endY = endY
+        this.color = color
+        this.width = width
+        this.isVirtual = isVirtual
+        this.minX = Math.min(this.startX, this.endX)
+        this.minY = Math.min(this.startY, this.endY)
+        this.maxX = Math.max(this.startX, this.endX)
+        this.maxY = Math.max(this.startY, this.endY)
+        this.type = 4
+            // this.canMove = true
+    }
+
+    /**
+     * Item对象边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect() {
+        return new SRect(this.minX, this.minY, (this.maxX - this.minX), (this.maxY - this.minY))
+    }
+
+    /**
+     * 绘制线条
+     * 
+     * @param canvas 画布
+     * @param rect   绘制区域
+     */
+
+    onDraw(canvas, rect) {
+        if (this.isVirtual) {
+            canvas.setLineDash([240, 240])
+        }
+        canvas.lineWidth = 240
+        canvas.strokeStyle = this.color || '#000'
+        canvas.beginPath();
+        canvas.moveTo(this.startX, this.startY)
+        canvas.lineTo(this.endX, this.endY)
+        canvas.stroke()
+    }
+}

+ 44 - 0
src/assets/node-templete/SGraphy/SCanvas.js

@@ -0,0 +1,44 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2018.  斯伯坦机器人世界
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+/**
+ * Canvas功能扩展
+ *
+ * @author  Andy
+ */
+Object.assign(CanvasRenderingContext2D.prototype, {
+  /**
+   * 绘制线段
+   *
+   * @param   x0    起点x坐标
+   * @param   y0    起点y坐标
+   * @param   x1    终点x坐标
+   * @param   y1    终点y坐标
+   */
+  drawLine (x0, y0, x1, y1) {
+    this.beginPath()
+    this.moveTo(x0, y0)
+    this.lineTo(x1, y1)
+    this.stroke()
+  } // Function drawLine()
+}) // Class CanvasRenderingContext2D

+ 30 - 0
src/assets/node-templete/SGraphy/SGraphyEnums.js

@@ -0,0 +1,30 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2018.  斯伯坦机器人世界
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+const SGraphyItemFlag = {
+  ItemIsMovable: 1,
+  ItemIsSelectable: 2
+}
+
+if (Object.freeze)
+  Object.freeze(SGraphyItemFlag)

+ 396 - 0
src/assets/node-templete/SGraphy/SGraphyItem.js

@@ -0,0 +1,396 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2018.  斯伯坦机器人世界
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+import SPoint from './types/SPoint'
+import SRect from './types/SRect'
+import SMouseEvent from './SMouseEvent'
+
+const sortItemZOrder = Symbol('sortItemZOrder')
+const toChildMouseEvent = Symbol('toChildMouseEvent')
+const grabItem = Symbol('grabItem')
+const releaseItem = Symbol('releaseItem')
+
+/**
+ * SGraphyItem
+ *
+ * @author  Andy
+ */
+export default class SGraphyItem {
+    /**
+     * 构造函数
+     */
+    constructor(parent) {
+            this.name = 'item'
+            this._scene = null
+            this._parent = parent
+            this.children = []
+
+            /** Z轴顺序 */
+            this.zOrder = 0
+                /** item位置 */
+            this._pos = new SPoint(0, 0)
+                /** 缩放比例 */
+            this._scale = new SPoint(1, 1)
+                /** 是否可见 */
+            this._isVisible = true
+
+            /** 鼠标按下时位置 */
+            this._mouseDownPos = new SPoint(4, 21)
+            this._isMove = false
+            this.canMove = false
+        } // Function constructor()
+
+    // ===================================================================================================================
+    // 属性
+    /** parent属性存值函数 */
+    get parent() {
+        return this._parent
+    }
+    set parent(value) {
+            if (this._parent === value) {
+                return
+            }
+            if (this._parent != null) { // 如果原parent不为空
+                // 将节点从原parent节点中摘除
+                let i = this._parent.children.indexOf(this)
+                this._parent.children.splice(i, 1)
+            }
+            this._parent = value
+
+            if (this._parent != null) { // 如果新parent不为空
+                // 将节点加入到新parent节点中
+                this._parent.children.push(this)
+                this._parent.children.sort(this[sortItemZOrder])
+            }
+            this._parent = value
+        } // Function set Parent()
+
+    /** scene属性 */
+    get scene() {
+        if (this._parent != null) {
+            return this._parent.scene
+        } else {
+            return this._scene
+        }
+    }
+
+    /** pos属性 */
+    get pos() {
+        return this._pos
+    }
+    set pos(value) {
+        this._pos = value
+    }
+
+    /** scale属性 */
+    get scale() {
+        return this._scale
+    }
+    set scale(value) {
+        this._scale = value
+    }
+
+    /** visible属性 */
+    get visible() {
+        return this._isVisible
+    }
+    set visible(value) {
+        this._isVisible = value
+    }
+
+    // ===================================================================================================================
+    // 函数
+    /**
+     * Item对象边界区域
+     *
+     * @return  SRect
+     */
+    boundingRect() {
+            return new SRect(0, 0, 10, 10)
+        } // Function boundingRect()
+
+    /**
+     * Item绘制操作
+     *
+     * @param   canvas        画布对象
+     * @param   rect          绘制区域
+     */
+    onDraw(canvas, rect) {
+            for (let item of this.children) {
+                // 保存画布状态
+                canvas.save()
+                    // item位移到指定位置绘制
+                canvas.translate(item.pos.x, item.pos.y)
+                    // 设置绘制区域
+                    // canvas.clip(item.boundingRect())
+                    // 绘制item
+                item.onDraw(canvas, rect)
+                    // 恢复画布状态
+                canvas.restore()
+            }
+        } // Function onDraw()
+
+    /**
+     * 更新Item
+     */
+    update() {
+            // TODO: PLX
+            // scene?.update()
+        } // Function update()
+
+    /**
+     * 移动item到指定位置
+     *
+     * @param   x           新位置的x坐标
+     * @param   y           新位置的y坐标
+     */
+    moveTo(x, y) {
+            this.pos = new SPoint(x, y)
+        } // moveTo()
+
+    /**
+     * 判断item是否包含点x,y
+     *
+     * @param   x       横坐标(当前item)
+     * @param   y       纵坐标(当前item)
+     *
+     * @return  boolean
+     */
+    contains(x, y) {
+            return this.boundingRect().contains(x - this.pos.x, y - this.pos.y)
+        } // Function contains()
+
+    /**
+     * 获得item的路径节点列表。(该节点被加载到场景中,如果未被加载到场景中,计算会出错)
+     *
+     * @return  *[]
+     */
+    itemPath() {
+            if (this.parent != null) {
+                let list = this.parent.itemPath()
+                list.push(this)
+                return list
+            }
+
+            return [this]
+        } // Function itemPath()
+
+    /**
+     * 将场景中的xy坐标转换成item坐标。(该节点被加载到场景中,如果未被加载到场景中,计算会出错)
+     *
+     * @param   x       场景中的横坐标
+     * @param   y       场景中的纵坐标
+     *
+     * @return  在item中的坐标
+     */
+    mapFromScene(x, y) {
+            let list = this.itemPath()
+            let x0 = x
+            let y0 = y
+            for (let item of list) {
+                x0 = (x0 - item.pos.x) / item.scale.x
+                y0 = (y0 - item.pos.y) / item.scale.y
+            }
+
+            return new SPoint(x0, y0)
+        } // Function mapFromScene()
+
+    /**
+     * 将item中的xy坐标转换成场景坐标。(该节点被加载到场景中,如果未被加载到场景中,计算会出错)
+     *
+     * @param   x       item中的横坐标
+     * @param   y       item中的纵坐标
+     *
+     * @return  在场景中的坐标
+     */
+    mapToScene(x, y) {
+            if (this.parent == null) {
+                return new SPoint(x, y)
+            }
+
+            return this.parent.mapToScene(x * this.scale.x + this.pos.x, y * this.scale.y + this.pos.y)
+        } // Function mapToScene()
+
+    // ===================================================================================================================
+    // 事件
+    /**
+     * 鼠标单击事件
+     *
+     * @param   e   保存事件参数
+     * @return  boolean
+     */
+    onClick(e) {
+            for (let item of this.children) {
+                if (!item.visible) { // 如果项目不可见
+                    continue
+                }
+                let ce = this[toChildMouseEvent](item, e)
+                if (item.contains(e.x, e.y) && item.onClick(ce)) { // 如果点在子项目上且子项目处理了事件
+                    return true
+                }
+            }
+
+            return false
+        } // Function onClick()
+
+    /**
+     * 鼠标双击事件
+     *
+     * @param   e   保存事件参数
+     * @return  boolean
+     */
+    onDbClick(e) {
+            for (let item of this.children) {
+                if (!item.visible) { // 如果项目不可见
+                    continue
+                }
+                let ce = this[toChildMouseEvent](item, e)
+                if (item.contains(e.x, e.y) && item.onDbClick(ce)) { // 如果点在子项目上且子项目处理了事件
+                    return true
+                }
+            }
+
+            return false
+        } // Function onClick()
+
+    /**
+     * 鼠标按下事件
+     *
+     * @param   e   保存事件参数
+     * @return  boolean
+     */
+    onMouseDown(e) {
+            // console.log(e)
+
+            for (let item of this.children) {
+                if (!item.visible) { // 如果项目不可见
+                    continue
+                }
+                let ce = this[toChildMouseEvent](item, e)
+                if (item.contains(e.x, e.y) && item.onMouseDown(ce)) { // 如果点在子项目上且子项目处理了事件
+                    return true
+                }
+            }
+
+            if (this.canMove) {
+                this._mouseDownPos = new SPoint(e.x, e.y)
+                this._isMove = true
+                this[grabItem](this)
+                    // console.log(this.scene.grabItem)
+                return true
+            }
+            return false
+        } // Function onMouseDown()
+
+    /**
+     * 鼠标移动事件
+     *
+     * @param   e   保存事件参数
+     * @return  boolean
+     */
+    onMouseMove(e) {
+            for (let item of this.children) {
+                if (!item.visible) { // 如果项目不可见
+                    continue
+                }
+                let ce = this[toChildMouseEvent](item, e)
+                if (item.contains(e.x, e.y) && item.onMouseMove(ce)) { // 如果点在子项目上且子项目处理了事件
+                    return true
+                }
+            }
+
+            if (e.buttons & SMouseEvent.LEFT_BUTTON && this.canMove && this._isMove) {
+                this.moveTo(this.pos.x + e.x - this._mouseDownPos.x, this.pos.y + e.y - this._mouseDownPos.y)
+            }
+
+            return false
+        } // Function onMouseMove()
+
+    /**
+     * 释放鼠标事件
+     *
+     * @param   e   保存事件参数
+     * @return  boolean
+     */
+    onMouseUp(e) {
+            for (let item of this.children) {
+                if (!item.visible) { // 如果项目不可见
+                    continue
+                }
+                let ce = this[toChildMouseEvent](item, e)
+                if (item.contains(e.x, e.y) && item.onMouseUp(ce)) { // 如果点在子项目上且子项目处理了事件
+                    return true
+                }
+            }
+
+            this._isMove = false
+            this[releaseItem]()
+            return false
+        } // Function onMouseUp()
+
+    // ===================================================================================================================
+    // 私有方法
+    /**
+     * 按ZOrder排序
+     *
+     * @param   a   比较元素1
+     * @param   b   比较元素2
+     * @return {number}
+     */
+    [sortItemZOrder](a, b) {
+        return a.zOrder - b.zOrder
+    } // Function sortItemZOrder()
+
+    /**
+     * 鼠标事件转子对象鼠标事件
+     *
+     * @param   child   子对象e
+     * @param   e       事件参数
+     * @return  {}
+     */
+    [toChildMouseEvent](child, e) {
+        let ce = {...e }
+        ce.x = (e.x - child.pos.x) / child.scale.x
+        ce.y = (e.y - child.pos.y) / child.scale.y
+        return ce
+    } // Function toChildMouseEvent()
+
+    /**
+     * 锁定item
+     *
+     * @param   item    被锁定的item
+     */
+    [grabItem](item) {
+        if (this.scene != null) {
+            this.scene.grabItem = item
+        }
+    } // Function grabItem
+
+    /**
+     * 释放被锁定的item
+     */
+    [releaseItem]() {
+        if (this.scene != null) {
+            this.scene.grabItem = null
+        }
+    } // Function grabItem
+} // Class SGraphyItem

+ 201 - 0
src/assets/node-templete/SGraphy/SGraphyScene.js

@@ -0,0 +1,201 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2018.  斯伯坦机器人世界
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+import SPoint from './types/SPoint'
+import SRect from './types/SRect'
+import SGraphyItem from './SGraphyItem'
+
+const toGrabItemMotionEvent = Symbol('toGrabItemMotionEvent')
+
+/**
+ * SGraphy图形引擎场景类
+ *
+ * @author  Andy
+ */
+export default class SGraphyScene {
+    /**
+     * 构造函数
+     */
+    constructor() {
+            this.view = null
+            console.log(this, 'this')
+            this.root = new SGraphyItem(null)
+            this.root._scene = this
+            this.pos = new SPoint(0, 0)
+            this.scale = new SPoint(1, 1)
+            this.grabItem = null
+        } // Function constructor()
+
+    /**
+     * 添加item对象到场景。
+     *
+     * @param   item        添加的对象
+     */
+    addItem(item) {
+            item.parent = this.root
+        } // Function addItem()
+
+    /**
+     * 从场景中移除Item。
+     *
+     * @param   item        被移除的对象
+     */
+    removeItem(item) {
+            item.parent = null
+        } // Function removeItem()
+
+    /**
+     * 绘制场景
+     *
+     * @param   canvas      画布
+     * @param   rect        更新绘制区域
+     */
+    drawScene(canvas, rect) {
+            this.root.onDraw(canvas, rect)
+        } // Function drawScene()
+
+    /**
+     * 绘制背景
+     *
+     * @param   canvas      画布
+     * @param   rect        更新绘制区域
+     */
+    drawBackground(canvas, rect) {
+            // DO NOTHING
+        } // Function drawBackground()
+
+    /**
+     * 绘制前景
+     *
+     * @param   canvas      画布
+     * @param   rect        更新绘制区域
+     */
+    drawForeground(canvas, rect) {
+            // DO NOTHING
+        } // Function drawForeground()
+
+    /**
+     * 返回场景的item边界。即所有item边界的并集。
+     *
+     * @return  SRect
+     */
+    worldRect() {
+            let rect = null
+
+            for (let item of this.root.children) { // 依次取item列中的所有item。将所有item的边界做并焦处理。
+                if (rect == null) {
+                    rect = item.boundingRect().adjusted(item.pos)
+                } else {
+                    rect.union(item.boundingRect().adjusted(item.pos))
+                }
+            }
+
+            return rect
+        } // Function worldsRect()
+
+    /**
+     * 更新
+     */
+    update() {} // Function update()
+        // ===================================================================================================================
+        // 事件
+        /**
+         * 鼠标单击事件
+         *
+         * @param   e   保存事件参数
+         * @return  boolean
+         */
+    onClick(e) {
+            if (this.grabItem != null) {
+                return this.grabItem.onClick(this[toGrabItemMotionEvent](this.grabItem, e))
+            }
+            return this.root.onClick(e)
+        } // onClick
+
+    /**
+     * 鼠标双击事件
+     *
+     * @param   e   保存事件参数
+     * @return  boolean
+     */
+    onDbClick(e) {
+            if (this.grabItem != null) {
+                return this.grabItem.onDbClick(this[toGrabItemMotionEvent](this.grabItem, e))
+            }
+            return this.root.onDbClick(e)
+        } // onClick
+
+    /**
+     * 鼠标按下事件
+     *
+     * @param   e   保存事件参数
+     * @return  boolean
+     */
+    onMouseDown(e) {
+            if (this.grabItem != null) {
+                return this.grabItem.onMouseDown(this[toGrabItemMotionEvent](this.grabItem, e))
+            }
+            return this.root.onMouseDown(e)
+        } // onMouseDown
+
+    /**
+     * 鼠标移动事件
+     *
+     * @param   e   保存事件参数
+     * @return  boolean
+     */
+    onMouseMove(e) {
+            if (this.grabItem != null) {
+                return this.grabItem.onMouseMove(this[toGrabItemMotionEvent](this.grabItem, e))
+            }
+            return this.root.onMouseMove(e)
+        } // onMouseMove
+
+    /**
+     * 释放鼠标事件
+     *
+     * @param   e   保存事件参数
+     * @return  boolean
+     */
+    onMouseUp(e) {
+            if (this.grabItem != null) {
+                return this.grabItem.onMouseUp(this[toGrabItemMotionEvent](this.grabItem, e))
+            }
+            return this.root.onMouseUp(e)
+        } // onMouseUp
+
+    /**
+     * 转换场景事件坐标到指定Item坐标事件
+     *
+     * @param   item        指定的item对象
+     * @param   e           场景事件
+     * @return  {}
+     */
+    [toGrabItemMotionEvent](item, e) {
+        let se = {...e }
+        let p = item.mapFromScene(e.x, e.y)
+        se.x = p.x
+        se.y = p.y
+        return se
+    } // Function toGrabItemMotionEvent()
+} // Class SGraphyScene

+ 280 - 0
src/assets/node-templete/SGraphy/SGraphyView.js

@@ -0,0 +1,280 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2018.  斯伯坦机器人世界
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+import './SCanvas'
+import SPoint from './types/SPoint'
+import SMouseEvent from './SMouseEvent'
+
+const bindEvent = Symbol('bindEvent')
+const toSceneMotionEvent = Symbol('toSceneMotionEvent')
+    /**
+     * Graphy图形引擎视图类
+     *
+     * @author  Andy
+     */
+export default class SGraphyView {
+    /**
+     * 构造函数
+     *
+     * @param   id    Canvas对象ID
+     */
+    constructor(id, scene) {
+            this.canvasView = document.getElementById(id)
+            this.canvas = this.canvasView.getContext('2d')
+            this[bindEvent](this.canvasView)
+            this.scene = scene
+            this.pos = new SPoint(10, 0)
+            this.scale = 1
+            this.minScale = 0.004
+            this.maxScale = 0.5
+            this._midKeyX = 0
+            this._midKeyY = 0
+            this.wheelZoom = 1.05
+
+            window.requestAnimationFrame(this.onDraw.bind(this))
+        } // Function constructor()
+
+    /**
+     * 绑定canvas事件
+     *
+     * @param   canvas      canvas对象
+     * @private
+     */
+    [bindEvent](canvasView) {
+        canvasView.onclick = this.onClick.bind(this)
+        canvasView.ondblclick = this.onDbClick.bind(this)
+        canvasView.onmousedown = this.onMouseDown.bind(this)
+        canvasView.onmousemove = this.onMouseMove.bind(this)
+        canvasView.onmouseup = this.onMouseUp.bind(this)
+        canvasView.onmousewheel = this.onMouseWheel.bind(this)
+        canvasView.onresize = this.onResize.bind(this)
+    } // Function [bindEvent]()
+
+    /**
+     * 获取canvas的宽度  
+     */
+
+    get width() {
+        return this.canvasView.width
+    }
+
+    get height() {
+        return this.canvasView.height
+    }
+
+    /**
+     * 将场景中的xy坐标转换成视图坐标。
+     *
+     * @param   x       场景中的横坐标
+     * @param   y       场景中的纵坐标
+     *
+     * @return  SPoint
+     */
+    mapFromScene(x, y = null) {
+            if (typeof(x) === 'object') { // 如果传入的是SPoint对象
+                return new SPoint(x.x * this.scale + this.pos.x, x.y * this.scale + this.pos.y)
+            }
+
+            return new SPoint(x * this.scale + this.pos.x, y * this.scale + this.pos.y)
+        } // Function mapFromScene()
+
+    /**
+     * 将item中的xy坐标转换成场景坐标。
+     *
+     * @param   x       item中的横坐标
+     * @param   y       item中的纵坐标
+     * @return  SPoint
+     */
+    mapToScene(x, y = null) {
+            if (typeof(x) === 'object') { // 如果传入的是SPoint对象
+                return new SPoint((x.x - this.pos.x) / this.scale, (x.y - this.pos.y) / this.scale)
+            }
+
+            return new SPoint((x - this.pos.x) / this.scale, (y - this.pos.y) / this.scale)
+        } // Function mapToScene()
+
+    /**
+     * 缩放视图时计算视图的位置与缩放比例
+     *
+     * @param   zoom        缩放比例
+     * @param   x0          缩放计算的中心点X坐标
+     * @param   y0          缩放计算的中心点Y坐标
+     */
+    scaleByPoint(zoom, x0, y0) {
+            let z = zoom
+                /**
+                 * 缩放比例在最小比例和最大比例范围内
+                 */
+            if (this.scale * zoom >= this.maxScale) { // 大于最大缩放比例
+                z = this.maxScale / this.scale
+                this.scale = this.maxScale
+            } else if (this.scale * zoom <= this.minScale) { // 小于最小绽放比例
+                z = this.minScale / this.scale
+                this.scale = this.minScale
+            } else {
+                this.scale *= zoom
+            }
+
+            this.pos.x = x0 - (x0 - this.pos.x) * z
+            this.pos.y = y0 - (y0 - this.pos.y) * z
+
+            // EventBus.getDefault().post(SGraphyViewZoomEvent(this, scale))
+            // EventBus.getDefault().post(SGraphyViewMoveEvent(this, pos.x, pos.y))
+            // return
+        } // Function scaleByPoint()
+        // ===================================================================================================================
+        // 事件
+    onDraw() {
+            this.canvas.save()
+            this.canvas.clearRect(0, 0, this.canvasView.width, this.canvasView.height)
+            this.canvas.restore()
+
+            if (this.scene != null) {
+                // 绘制背景
+                this.canvas.save()
+                this.scene.drawBackground(this.canvas)
+                this.canvas.restore()
+
+                // 绘制场景
+                this.canvas.save()
+                this.canvas.translate(this.pos.x, this.pos.y)
+                this.canvas.scale(this.scale, this.scale)
+                this.scene.drawScene(this.canvas)
+                this.canvas.restore()
+
+                // 绘制前景
+                this.canvas.save()
+                this.scene.drawForeground(this.canvas)
+                this.canvas.restore()
+            }
+
+            window.requestAnimationFrame(this.onDraw.bind(this))
+        } // Function onDraw()
+
+    /**
+     * 鼠标单击事件
+     *
+     * @param   e   保存事件参数
+     */
+    onClick(e) {
+            if (this.scene != null) {
+                let se = this[toSceneMotionEvent](e)
+                this.scene.onClick(se)
+            }
+        } // Function onClick()
+
+    /**
+     * 鼠标双击事件
+     *
+     * @param   e   保存事件参数
+     */
+    onDbClick(e) {
+            if (this.scene != null) {
+                let ce = this[toSceneMotionEvent](e)
+                this.scene.onDbClick(ce)
+            }
+        } // Function onDbClick()
+
+    /**
+     * 鼠标按下事件
+     *
+     * @param   e   保存事件参数
+     */
+    onMouseDown(e) {
+            let se = new SMouseEvent(e)
+            if (se.buttons & SMouseEvent.MIDDLE_BUTTON) { // 如果按下中键
+                this._midKeyX = e.x
+                this._midKeyY = e.y
+            }
+
+            if (this.scene != null) {
+                let ce = this[toSceneMotionEvent](e)
+                this.scene.onMouseDown(ce)
+            }
+        } // Function onMouseDown()
+
+    /**
+     * 鼠标移动事件
+     *
+     * @param   e   保存事件参数
+     */
+    onMouseMove(e) {
+            let se = new SMouseEvent(e)
+            if (se.buttons & SMouseEvent.MIDDLE_BUTTON) { // 如果按下中键,则移动视图
+                this.pos.x += e.x - this._midKeyX
+                this.pos.y += e.y - this._midKeyY
+                this._midKeyX = e.x
+                this._midKeyY = e.y
+                return
+            }
+            if (this.scene != null) {
+                let ce = this[toSceneMotionEvent](e)
+                this.scene.onMouseMove(ce)
+            }
+        } // Function onMouseMove()
+
+    /**
+     * 释放鼠标事件
+     *
+     * @param   e   保存事件参数
+     */
+    onMouseUp(e) {
+            if (this.scene != null) {
+                let ce = this[toSceneMotionEvent](e)
+                this.scene.onMouseUp(ce)
+            }
+        } // Function onMouseUp()
+
+    /**
+     * 鼠标滚轮事件
+     *
+     * @param   e   保存事件参数
+     */
+    onMouseWheel(e) {
+            let se = new SMouseEvent(e)
+            if (e.wheelDelta < 0) {
+                this.scaleByPoint(1 / this.wheelZoom, se.x, se.y)
+            } else {
+                this.scaleByPoint(this.wheelZoom, se.x, se.y)
+            }
+        } // Function onMouseWheel()
+
+    /**
+     * View大小发生变化事件
+     *
+     * @param   e   保存事件参数
+     */
+    onResize(e) {} // Function onResize()
+
+    /**
+     * MotionEvent转场景对象MotionEvent
+     *
+     * @param   e       MotionEvent
+     * @return  子对象MotionEvent
+     */
+    [toSceneMotionEvent](e) {
+        let se = new SMouseEvent(e)
+        se.x = (se.x - this.pos.x) / this.scale
+        se.y = (se.y - this.pos.y) / this.scale
+        return se
+    } // Function toSceneMotionEvent()
+} // Class SGraphyView

+ 53 - 0
src/assets/node-templete/SGraphy/SMouseEvent.js

@@ -0,0 +1,53 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2018.  斯伯坦机器人世界
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+/**
+ * 鼠标事件
+ *
+ * @author  Andy
+ */
+export default class SMouseEvent {
+  /**
+   * 构造函数
+   *
+   * @param   e       系统鼠标事件
+   */
+  constructor(e) {
+    let bbox          = e.srcElement.getBoundingClientRect()
+    this.type         = e.type
+    this.x            = e.clientX - bbox.left
+    this.y            = e.clientY - bbox.top
+    this.screenX      = e.screenX
+    this.screenY      = e.screenY
+    this.clientX      = e.clientX
+    this.clientY      = e.clientY
+    this.altKey       = e.altKey
+    this.ctrlKey      = e.ctrlKey
+    this.buttons      = e.buttons
+    this.wheelDelta   = e.wheelDelta
+  } // Function constructor()
+} // Class MouseEvent
+
+SMouseEvent.LEFT_BUTTON   = 0x01
+SMouseEvent.RIGHT_BUTTON  = 0x02
+SMouseEvent.MIDDLE_BUTTON = 0x04

+ 201 - 0
src/assets/node-templete/SGraphy/items/SGraphyClockItem.js

@@ -0,0 +1,201 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2018.  斯伯坦机器人世界
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+import SGraphyItem from '../SGraphyItem'
+import SRect from '../types/SRect'
+
+/** 定义符号,用于定义私有成员变晴儿 */
+const drawScale     = Symbol('drawScale')
+const drawScaleText = Symbol('drawScaleText')
+const drawHour      = Symbol('drawHour')
+const drawMinute    = Symbol('drawMinute')
+const drawSecond    = Symbol('drawSecond')
+
+/**
+ * SGraphy引擎时钟Item
+ *
+ * @author  Andy
+ */
+export default class SGraphyClockItem extends SGraphyItem {
+  /**
+   * 构造函数
+   *
+   * @param   parent    指向父对象
+   */
+  constructor(width, height, parent = null) {
+    super(parent)
+    this.name = 'ClockItem'
+    this.width = width
+    this.height = height
+    /** 是否显示刻度 */
+    this.isShowScale = true
+    /** 刻度颜色 */
+    this.scaleColor = '#000'
+    /** 刻度文本颜色 */
+    this.textColor = '#000'
+    /** 时针颜色 */
+    this.hourColor = '#000'
+    /** 分针颜色 */
+    this.minuteColor = '#000'
+    /** 秒针颜色 */
+    this.secondColor = '#F00'
+    /** 是否显示钞针 */
+    this.isShowSecond = true
+    /** 是否平滑移动秒针 */
+    this.isSmooth = true
+    /** 边缘宽度 */
+    this.padding = 100.0
+  } // Function constructor()
+
+  /**
+   * Item对象边界区域
+   *
+   * @return  SRect
+   */
+  boundingRect() {
+    return new SRect(0, 0, this.width / 2, this.height / 2)
+  } // Function boundingRect()
+
+  /**
+   * 时钟半径,只读属性
+   *
+   * @return  number
+   */
+  get radius() {
+    return Math.min(this.width, this.height) / 2.0
+  } // getter radius()
+
+  /**
+   * 绘制时钟
+   *
+   * @param   canvas      画布
+   * @param   rect        绘制区域
+   */
+  onDraw(canvas, rect) {
+    canvas.translate(this.width / 2, this.height / 2)
+    canvas.arc(0, 0, this.radius, 0, 2 * Math.PI)
+    let t = new Date()
+
+    this[drawScale](canvas)
+    this[drawHour](canvas, t.getHours(), t.getMinutes(), t.getSeconds())
+    this[drawMinute](canvas, t.getMinutes(), t.getSeconds())
+    this[drawSecond](canvas, t.getSeconds() + t.getMilliseconds() / 1000.0)
+  } // Function onDraw()
+
+  /**
+   * 绘制刻度
+   *
+   * @param   canvas      画布
+   */
+  [drawScale](canvas) {
+    let scaleLength = Math.max(this.radius / 10.0, 2.0)
+    let scaleLength1 = scaleLength * 1.2
+    let strokeWidth = Math.max(this.radius / 100.0, 2.0)
+    let strokeWidth1 = strokeWidth * 2.0
+
+    canvas.save()
+    canvas.strokeStyle = this.scaleColor
+
+    for (let i = 1; i <= 12; i++) {          // 12小时刻度
+      canvas.lineWidth = strokeWidth1
+      canvas.drawLine(0, -this.radius, 0, -this.radius + scaleLength1)
+
+      if (this.radius >= 40) {              // 如果半度大于40显示分钟刻度
+        canvas.rotate(6 * Math.PI / 180)
+        for (let j = 1; j <= 4; j++) {       // 分钟刻度
+          canvas.lineWidth = strokeWidth
+          canvas.drawLine(0, -this.radius, 0, -this.radius + scaleLength)
+          canvas.rotate(6 * Math.PI / 180)
+        }
+      } else {
+        canvas.rotate(30 * Math.PI / 180)
+      }
+    }
+
+    canvas.restore()
+  } // Function drawScale()
+
+  /**
+   * 绘制刻度数字
+   *
+   * @param   canvas      画布
+   */
+  [drawScaleText](canvas) {
+
+  } // Function drawScaleText()
+
+  /**
+   * 绘制时针
+   *
+   * @param   canvas      画布
+   * @param   hour        时
+   * @param   minute      分
+   * @param   second      秒
+   */
+  [drawHour](canvas, hour, minute, second) {
+    canvas.save()
+    canvas.lineCap = 'round'
+    canvas.lineWidth = Math.max(this.radius / 30.0, 4.0)
+    canvas.strokeStyle = this.hourColor
+    canvas.rotate((hour * 30.0 + minute * 30.0 / 60 + second * 30.0 / 60 / 60) * Math.PI / 180)
+    canvas.drawLine(0, this.radius / 10.0, 0, -this.radius / 2.0)
+    canvas.restore()
+  } // Function drawHour()
+
+  /**
+   * 绘制分针
+   *
+   * @param   canvas      画布
+   * @param   minute      分
+   * @param   second      秒
+   */
+  [drawMinute](canvas, minute, second) {
+    canvas.save()
+    canvas.lineCap = 'round'
+    canvas.lineWidth = Math.max(this.radius / 40.0, 4.0)
+    canvas.strokeStyle = this.minuteColor
+    canvas.rotate((minute * 6 + second * 6 / 60.0) * Math.PI / 180.0)
+    canvas.drawLine(0, this.radius / 10.0, 0, -this.radius * 2.0 / 3.0)
+    canvas.restore()
+  } // Function drawMinute()
+
+  /**
+   * 绘制秒针
+   *
+   * @param   canvas      画布
+   * @param   second      秒
+   */
+  [drawSecond](canvas, second) {
+    canvas.save()
+    canvas.lineCap = 'round'
+    canvas.lineWidth = Math.max(this.radius / 100.0, 3.0)
+    canvas.strokeStyle = this.secondColor
+    canvas.rotate(second * 6 * Math.PI / 180)
+    canvas.drawLine(0, this.radius / 5.0, 0, -this.radius + this.radius / 10.0)
+    // canvas.drawCircle(0, 0, this.radius / 30.0)
+    // canvas.drawCircle(0, -this.radius + this.radius / 5.0, this.radius / 60.0)
+    // canvas.strokeStyle = Color.YELLOW
+    // canvas.drawCircle(0, 0, this.radius / 100.0)
+    canvas.restore()
+  } // Function drawSecond()
+} // Class SGraphyClockItem

+ 58 - 0
src/assets/node-templete/SGraphy/items/SGraphyLineItem.js

@@ -0,0 +1,58 @@
+/**
+ * 线条
+ */
+import SGraphyItem from '../SGraphyItem'
+import SRect from './../types/SRect';
+
+export default class SGraphyLineItem extends SGraphyItem {
+    /**
+     * 构造函数
+     * 
+     * @param startX  线的起始x坐标
+     * @param startY  线的起始y坐标
+     * @param endX    线的终止x坐标
+     * @param endY    线的终止y坐标
+     * @param width   线的宽度
+     * 
+     * @param color  线的颜色
+     * @param isVirtual    是否为虚线
+     */
+    constructor(startX, startY, endX, endY, color, width, isVirtual, parent = null) {
+        super(parent)
+        this.startX = startX
+        this.startY = startY
+        this.endX = endX
+        this.endY = endY
+        this.color = color
+        this.width = width
+        this.isVirtual = isVirtual
+    }
+
+    /**
+     * Item对象边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect() {
+        return new SRect(0, 0, this.width, this.height)
+    }
+
+    /**
+     * 绘制线条
+     * 
+     * @param canvas 画布
+     * @param rect   绘制区域
+     */
+
+    onDraw(canvas, rect) {
+        if (this.isVirtual) {
+            canvas.setLineDash([15, 5])
+        }
+        canvas.lineWidth = this.width || 1
+        canvas.strokeStyle = this.color || '#000'
+        canvas.beginPath();
+        canvas.moveTo(this.startX, this.startY)
+        canvas.lineTo(this.endX, this.endY)
+        canvas.stroke()
+    }
+}

+ 57 - 0
src/assets/node-templete/SGraphy/items/SGraphyPolygonItem.js

@@ -0,0 +1,57 @@
+/**
+ * 不规则多边形,元空间
+ */
+import SGraphyItem from '../SGraphyItem'
+import SRect from './../types/SRect';
+
+export default class SGraphyPolygonItem extends SGraphyItem {
+    /**
+     * 
+     * 构造函数
+     * 
+     * @param jsonArr  空间线条数组
+     * @param lineWidth    空间线条的宽度
+     * @param color    空间线条的颜色
+     * @param fillColor  空间的填充颜色
+     * 
+     */
+    constructor(jsonArr, lineWidth, color, fillColor, parent = null) {
+            super(parent)
+            this.jsonArr = jsonArr
+            this.lineWidth = lineWidth
+            this.color = color
+            this.fillColor = fillColor
+        } //constructor
+
+    /**
+     * Item的边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect() {
+        return new SRect(0, 0, this.width, this.height)
+    }
+
+    /**
+     * 绘制不规则多边形
+     * 
+     * @param canvas 画布
+     * @param rect   绘制区域
+     */
+    onDraw(canvas, rect) {
+        if (this.jsonArr && this.jsonArr.length) {
+            canvas.beginPath();
+            canvas.lineWidth = this.lineWidth || 1
+            canvas.strokeStyle = this.color || '#000'
+            canvas.fillStyle = this.fillColor || '#fff'
+            canvas.moveTo(this.jsonArr[0].X / 120 * -1, this.jsonArr[0].Y / 120)
+            for (let i = 1; i < this.jsonArr.length - 1; i++) {
+                canvas.lineTo(this.jsonArr[i].X / 120 * -1, this.jsonArr[i].Y / 120)
+            }
+            canvas.lineTo(this.jsonArr[0].X / 120 * -1, this.jsonArr[0].Y / 120)
+            canvas.closePath()
+            canvas.fill()
+            canvas.stroke()
+        }
+    }
+}

+ 64 - 0
src/assets/node-templete/SGraphy/items/SGraphyRectItem.js

@@ -0,0 +1,64 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2018.  斯伯坦机器人世界
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+import SGraphyItem from '../SGraphyItem'
+import SRect from '../types/SRect'
+
+/**
+ * SGraphy引擎时钟Item
+ *
+ * @author  Andy
+ */
+export default class SGraphyRectItem extends SGraphyItem {
+  /**
+   * 构造函数
+   */
+  constructor(width, height, parent) {
+    super(parent)
+    this.name = 'RectItem'
+    this.width = width
+    this.height = height
+    this.style = '#f00'
+    this.canMove = true
+  } // Function constructor()
+
+  /**
+   * Item对象边界区域
+   *
+   * @return  SRect
+   */
+  boundingRect() {
+    return new SRect(0, 0, this.width, this.height)
+  } // Function boundingRect()
+
+  /**
+   * 绘制时钟
+   *
+   * @param   canvas      画布
+   * @param   rect        绘制区域
+   */
+  onDraw(canvas, rect) {
+    canvas.fillStyle = this.style
+    canvas.fillRect(0, 0, this.width, this.height)
+  } // Function onDraw()
+} // Class SGraphyRectItem

+ 61 - 0
src/assets/node-templete/SGraphy/items/SGraphyVirtualItem.js

@@ -0,0 +1,61 @@
+/**
+ * 线条
+ */
+import SGraphyItem from '../SGraphyItem'
+import SRect from './../types/SRect';
+
+export default class SGraphyLineItem extends SGraphyItem {
+    /**
+     * 构造函数
+     * 
+     * @param startX  线的起始x坐标
+     * @param startY  线的起始y坐标
+     * @param endX    线的终止x坐标
+     * @param endY    线的终止y坐标
+     * @param width   线的宽度
+     * 
+     * @param color  线的颜色
+     * @param isVirtual    是否为虚线
+     * 
+     * @param canMove  移动
+     */
+    constructor(startX, startY, endX, endY, color, width, isVirtual, canMove, parent = null) {
+        super(parent)
+        this.startX = startX
+        this.startY = startY
+        this.endX = endX
+        this.endY = endY
+        this.color = color
+        this.width = width
+        this.isVirtual = isVirtual
+        this.canMove = canMove
+    }
+
+    /**
+     * Item对象边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect() {
+        return new SRect(0, 0, this.width, this.height)
+    }
+
+    /**
+     * 绘制线条
+     * 
+     * @param canvas 画布
+     * @param rect   绘制区域
+     */
+
+    onDraw(canvas, rect) {
+        if (this.isVirtual) {
+            canvas.setLineDash([15, 5])
+        }
+        canvas.lineWidth = this.width || 1
+        canvas.strokeStyle = this.color || '#000'
+        canvas.beginPath();
+        canvas.moveTo(this.startX, this.startY)
+        canvas.lineTo(this.endX, this.endY)
+        canvas.stroke()
+    }
+}

+ 40 - 0
src/assets/node-templete/SGraphy/types/SPoint.js

@@ -0,0 +1,40 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2018.  斯伯坦机器人世界
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+/**
+ * 坐标点
+ *
+ * @author  Andy
+ */
+export default class SPoint {
+  /**
+   * 构造函数
+   *
+   * @param   x     X坐标
+   * @param   y     Y坐标
+   */
+  constructor(x, y) {
+    this.x = x
+    this.y = y
+  } // constructor
+} // Class SPoint

+ 169 - 0
src/assets/node-templete/SGraphy/types/SRect.js

@@ -0,0 +1,169 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2018.  斯伯坦机器人世界
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+/**
+ * 矩形
+ *
+ * @author  Andy
+ */
+export default class SRect {
+  /**
+   * 构造函数
+   *
+   * @param   x       X坐标
+   * @param   y       Y坐标
+   * @param   width   宽度
+   * @param   height  高度
+   */
+  constructor(x = 0, y = 0, width = 0, height = 0) {
+    this._x = x
+    this._y = y
+    this._width = Math.max(width, 0)
+    this._height = Math.max(height, 0)
+  } // constructor
+
+  /**
+   * left属性
+   */
+  get left() {
+    return this._x
+  }
+  set left(value) {
+    this._x = value
+  }
+
+  /**
+   * right属性
+   */
+  get right() {
+    return this._x + this._width
+  }
+  set right(value) {
+    this._width = Math.max(value - this._x, 0)
+  }
+
+  /**
+   * top属性
+   */
+  get top() {
+    return this._y
+  }
+  set top(value) {
+    this._y = value
+  }
+
+  /**
+   * top属性
+   */
+  get bottom() {
+    return this._y + this._height
+  }
+  set bottom(value) {
+    this._height = Math.max(value - this._y, 0)
+  }
+
+  /**
+   * x属性
+   *
+   * @return {*}
+   */
+  get x() {
+    return this._x
+  }
+  set x(value) {
+    this._x = value
+  }
+
+  /**
+   * x属性
+   *
+   * @return {*}
+   */
+  get y() {
+    return this._y
+  }
+  set y(value) {
+    this._y = value
+  }
+
+  /**
+   * width 属性
+   *
+   * @return {number}
+   */
+  get width() {
+    return this._width
+  }
+  set width(value) {
+    this._width = Math.max(value, 0)
+  }
+
+  /**
+   * height 属性
+   * @return {number}
+   */
+  get height() {
+    return this._height
+  }
+  set height(value) {
+    this._height = Math.max(value, 0)
+  }
+
+  /**
+   * 判断矩形空间是否包含点x,y
+   *
+   * @param   x       横坐标(当前item)
+   * @param   y       纵坐标(当前item)
+   * @return  boolean
+   */
+  contains(x, y) {
+    return (x >= this.x && x <= this.right) && (y >= this.top && y <= this.bottom)
+  } // Function contains()
+
+  /**
+   * 调整Rect位置
+   *
+   * @param x
+   * @param y
+   * @return  SRect
+   */
+  adjusted(x, y = null) {
+    if (typeof (x) === 'object') {     // 如果传入的是SPoint对象
+      return new SRect(this.x + x.x, this.y + x.y, this.width, this.height)
+    }
+
+    return new SRect(this.x + x, this.y + y, this.width, this.height)
+  } // Function adjusted()
+
+  /**
+   * 合并rect
+   *
+   * @param   rect
+   */
+  union(rect) {
+    this.left = Math.min(this.left, rect.left)
+    this.top = Math.min(this.top, rect.top)
+    this.right = Math.max(this.right, rect.right)
+    this.bottom = Math.max(this.bottom, rect.bottom)
+  } // Function union()
+} // Class SRect

+ 9 - 0
src/assets/node-templete/index.js

@@ -0,0 +1,9 @@
+import SGraphyView from './SGraphy/SGraphyView'
+import SGraphyScene from './SGraphy/SGraphyScene'
+import SGraphyClockItem from './SGraphy/items/SGraphyClockItem'
+import SGraphyRectItem from './SGraphy/items/SGraphyRectItem'
+// import SGraphyImageItem from './SGraphy/items/SGraphyImageItem'
+import SGraphyLineItem from './SGraphy/items/SGraphyLineItem'
+import SGraphyPolygonItem from './SGraphy/items/SGraphyPolygonItem'
+
+export { SGraphyView, SGraphyScene, SGraphyClockItem, SGraphyRectItem, SGraphyLineItem, SGraphyPolygonItem }

+ 1 - 0
src/components/common/search_input.vue

@@ -26,6 +26,7 @@ export default {
     display: inline-block;
     width: 23rem;
     height: 2rem;
+    line-height: 2rem;
     font-size: 1.4rem;
     position: relative;
     input{

+ 1 - 0
src/components/data_admin/buildData/style.less

@@ -63,6 +63,7 @@
       border: 2px solid #409eff !important;
     }
     .build_header {
+      min-width: 800px;
       height: 3rem;
       width: 100%;
       border-bottom: 0.01rem solid #ccc;

+ 1 - 0
src/components/data_admin/input.vue

@@ -26,6 +26,7 @@ export default {
     display: inline-block;
     width: 23rem;
     height: 2rem;
+    line-height: 2rem;
     font-size: 1.4rem;
     position: relative;
     input{

+ 148 - 0
src/views/data_admin/buildGraphy/buildGraphy.vue

@@ -0,0 +1,148 @@
+<!--
+  revit空间管理
+ -->
+<template>
+  <div id="graphy">
+    <div class="graphy-left">
+      <graphy-tree :param="param" @change="getPoint"></graphy-tree>
+    </div>
+    <div class="graphy-main">
+      <graphy-canvas :param="param" @getDetails="getDetails" @resetPoint="resetPoint" ref="canvas"></graphy-canvas>
+    </div>
+    <div class="graphy-right">
+      <graphy-tabs
+        ref="tabs"
+        :pointParam="pointParam"
+        @setFalg="setFalg"
+        @getLocation="getLocation"
+        @getPointList="sendPointList"
+      ></graphy-tabs>
+    </div>
+  </div>
+</template>
+
+<script>
+//接口
+import graphyTree from "./graphyTree";
+import graphyTabs from "./graphyTabs";
+import graphyCanvas from "./graphyCanvas";
+import {
+    mapGetters,
+    mapActions
+} from "vuex"
+import {
+  getPT //获取点位坐标
+} from "@/api/scan/request";
+export default {
+  components: {
+    graphyTree,
+    graphyTabs,
+    graphyCanvas
+  },
+  data() {
+    return {
+      param: {
+        ProjId: this.projectId, //项目id
+        UserId: this.userId //用户id
+      },
+      pointParam: {
+        //point请求参数
+        ProjId: this.projectId, //项目id
+        UserId: this.userId, //用户id
+        fllorName: ""
+      },
+      map: null,
+      pointId: null
+    };
+  },
+  computed: {
+        ...mapGetters("peojMess", [
+        "projectId",
+        "userId",
+        "secret"
+    ])
+    },
+  created() { },
+  methods: {
+    getPoint(data) {
+      this.pointParam.FloorId = data.code;
+      this.pointParam.fllorName = data.name;
+      this.$refs.tabs.reset(this.pointParam, data.map);
+      if (this.map != data.map) {
+        this.map = data.map;
+        this.$refs.canvas.getData(data);
+      } else {
+        return;
+      }
+    },
+
+    //获取到点位标签坐标
+    sendPointList(list) {
+      if (list && list.length && list[0].Id == this.pointId) {
+        this.$refs.canvas.doPoint(list);
+      } else {
+        if (list.length) {
+          this.pointId = list[0].Id;
+          this.$refs.canvas.doPoint(list);
+        } else {
+          this.$refs.canvas.doPoint([]);
+        }
+      }
+    },
+
+    //插旗setFalg
+    setFalg(item) {
+      this.$refs.canvas.addPoint(item);
+    },
+
+    //定位getLocation
+    getLocation(item) {
+      this.$refs.canvas.locationGraphy({ X: item.X, Y: item.Y * -1 });
+    },
+
+    //重新获取点位信息resetPoint
+    resetPoint() {
+      this.$refs.tabs.reset(this.pointParam, true);
+    },
+
+    //查看详情
+    getDetails(item) {
+      this.$refs.tabs.getDetails(item);
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+#graphy {
+  position: relative;
+  height: 100%;
+  .graphy-left {
+    width: 200px;
+    height: 100%;
+    position: absolute;
+    overflow-y: auto;
+    left: 0;
+    top: 0;
+    bottom: 0;
+    border-right: 1px solid #ccc;
+  }
+  .graphy-main {
+    position: absolute;
+    left: 200px;
+    top: 0;
+    right: 400px;
+    bottom: 0;
+    overflow: auto;
+  }
+  .graphy-right {
+    position: absolute;
+    right: 0;
+    width: 400px;
+    top: 0;
+    bottom: 0;
+    border-left: 1px solid #ccc;
+    overflow: hidden;
+  }
+}
+</style>

+ 922 - 0
src/views/data_admin/buildGraphy/graphyCanvas.vue

@@ -0,0 +1,922 @@
+<template>
+  <div ref="graphyMain" class="canvasGraphy" style="width:100%;">
+    <div class="saga-message" v-if="type != 3">{{type == 1 ? '请选择楼层' : '当前楼层尚无平面图,请去空间管理根据模型生成'}}</div>
+    <div style="width:100%;" v-else>
+      <canvas id="canvas" :width="canvasW" :height="canvasH"></canvas>
+    </div>
+    <el-button
+      v-if="type == 3"
+      size="small"
+      @click="pointToSpace"
+      style="height: 30px;z-index:999;overflow: hidden;transform: translateX(-50%);position: absolute;top: 10%;right: 5%;"
+      type="primary"
+    >标签与空间关联</el-button>
+    <div
+      v-if="type == 3"
+      style="height: 30px;z-index:999;overflow: hidden;transform: translateX(-50%);position: absolute;bottom: 10%;left: 50%;"
+    >
+      <el-button size="small" @click="smallSize" type="primary">- 缩小</el-button>
+      <el-button size="small" @click="suitableSize" type="primary">合适比例</el-button>
+      <el-button size="small" @click="bigSize" type="primary">+ 放大</el-button>
+    </div>
+    <!-- <button @click="addPoint">添加标记</button> -->
+    <!-- <button @click="locationGraphy({ X: -35146.875, Y: 40680 })">定位</button> -->
+    <!-- <button @click="addLine">添加虚拟墙</button> -->
+    <div v-show="menuShow" id="menu" ref="menu">
+      <p v-if="pointShow" @click="getDatails">编辑该标签</p>
+      <p v-if="pointShow" @click="clearXY">清除该点位的坐标</p>
+      <p v-if="pointShow" @click="noLocate">修改为无法定位到楼层的点位</p>
+      <!-- <p v-if="lineShow" @click="detaleWall">虚拟墙删除</p> -->
+    </div>
+  </div>
+</template>
+
+<script>
+import axios from "axios";
+
+//引擎的引用
+import {
+  SGraphyView,
+  SGraphyScene,
+  SGraphyRectItem
+} from "@/assets/node-templete";
+
+//item组件
+import SGraphyLineItem from "@/assets/js/items/SGraphyLineItem";
+import SGraphyPolygonItem from "@/assets/js/items/SGraphyPolygonItem";
+import SGraphyVirtualItem from "@/assets/js/items/SGraphyVirtualItem";
+import SGraphyImageItem from "@/assets/js/items/SGraphyImageItem";
+import tools from "@/utils/scan/tools";
+let data = "";
+let scale = 120; //缩放比例
+let myData = [];
+let colorArr = [
+  "rgba(0,245,255,.05)",
+  "rgba(255,218,185,.05)",
+  "rgba(132,112,255,.05)",
+  "rgba(127,255,0,.05)",
+  "rgba(238,92,66,.05)",
+  "rgba(255,255,224,.05)",
+  "rgba(238,233,233,.05)",
+  "rgba(156,156,156,.05)",
+  "rgba(144,238,144,.05)",
+  "rgba(180,205,205,.05)"
+];
+function changeXY(arr) {
+  let data;
+  if (arr && arr.length) {
+    data = arr.map(item => {
+      (item.X = item.X), (item.Y = item.Y);
+    });
+  }
+  return data;
+}
+
+class MainScene extends SGraphyScene {
+  constructor() {
+    super();
+    //资产id
+  } // Function constructor()
+
+  /**
+   * 绘制背景
+   *
+   * @param   canvas      画布
+   * @param   rect        更新绘制区域
+   */
+  // drawBackground(canvas, rect) {}
+}
+
+import { updatePoint, getPoint, formBIMToPri, getPointList, updateBusiness } from "@/api/scan/request";
+import pako from '@/assets/pako/pako'
+
+export default {
+  name: "HelloWorld",
+  props: {
+    param: null
+  },
+  data() {
+    return {
+      view: "",
+      mainScene: new MainScene(),
+      dataMax: "", //最大值最小值数据
+      scene: {
+        x: 0,
+        y: 0
+      },
+      id: null,
+      menuShow: false, //右键菜单的显示
+      lineShow: false,
+      pointShow: false,
+      canvasH: 600,
+      canvasW: 800,
+      detaleItem: null, //需要删除的数组
+      wallArr: [], //虚拟墙添加时的数组
+      wallList: [], //处理后的墙的线条
+      detaleLine: [], //需要删除的虚拟墙
+      type: 1, //1  没有选择楼层, 2没有平面图, 3有平面图
+      data: {},
+      list: "",
+      buildMess: {},
+      imageUrl:
+        "http://prod.dp.sagacloud.cn:28888/image-service/common/image_get?systemId=dev&key=graphy.png"
+    };
+  },
+  created() { },
+  mounted() {
+    this.resize()
+  },
+  methods: {
+    resize() {
+      this.canvasW =
+        document.getElementsByClassName("graphy-main")[0].offsetWidth - 2;
+      this.canvasH =
+        document.getElementsByTagName("body")[0].offsetHeight - 20;
+    },
+
+    pointToSpace() {
+      let data = []//空间数组列表
+      this.mainScene.root.children.map(item => {
+        if (item.type == 3) {
+          data.push(item)
+        }
+      })
+      let relation = []
+      this.list.map(item => {
+        data.map(child => {
+          if (tools.isIn(item.X, item.Y * -1, child.containsArr)) {
+            relation.push({
+              pointId: item.id,
+              spaceId: child.id,
+              pointName: item.Name
+            })
+          }
+        })
+      })
+      //找到没有元空间id的对象,取出对应的array
+      let noIdList = [], hasIdList = []
+      relation.map(item => {
+        if (!!item.spaceId) {
+          hasIdList.push(item)
+        } else {
+          noIdList.push(item)
+        }
+      })
+      let name = ""
+      if (noIdList.length) {
+        for (let i = 0; i < noIdList.length; i++) {
+          name += noIdList[i].pointName + "、"
+        }
+      }
+      let msg = noIdList.length ? "一个空间下重复的点位标签信息录入将会被覆盖!以下标签所在的元空间不存在元空间id:" + name + ",是否继续" : "一个空间下重复的点位标签信息录入将会被覆盖!是否将其标签所在的信息录入元空间中?"
+      this.$confirm(msg, "提示").then(_ => {
+        this.getPointList(hasIdList)
+      }).catch(_ => {
+        this.$message("取消关联")
+      })
+    },
+
+    //获取标签列表
+    getPointList(hasIdList) {
+      let idList = hasIdList.map(item => { return item.pointId })
+      let param = {
+        IdList: idList,
+        ProjId: this.param.ProjId,
+        UserId: this.param.UserId,
+      }
+      getPointList(param, res => {
+        console.log(res)
+        if (res.PointList && res.PointList.length) {
+          hasIdList.map(item => {
+            res.PointList.map(child => {
+              if (child.PointId == item.pointId) {
+                item.Pic = child.ImageList
+                item.LocalId = child.PointLocalId
+              }
+            })
+          })
+          this.setMess(hasIdList)
+        }
+      })
+    },
+
+    //给空间中写入信息
+    setMess(hasIdList) {
+      let param = {
+        data: { criterias: null },
+        ProjId: this.param.projId,
+        secret: this.param.secret
+      }
+      hasIdList = tools.arrayUnique(hasIdList, "spaceId")
+      param.data.criterias = hasIdList.map(item => {
+        let criteria = { infos: {} }
+        if (!!item.Pic && item.Pic.length) {
+          criteria.infos.Pic = [{
+            value: item.Pic.map(child => {
+              return {
+                key: child.key,
+                name: child.name,
+                type: child.type,
+                systemId: "dataPlatform"
+              }
+            })
+          }]
+        }
+        criteria.id = item.spaceId
+        criteria.infos.RoomLocalName = [{ value: item.pointName || "" }]
+        criteria.infos.RoomLocalID = [{ value: item.LocalId || "" }]
+        return criteria
+      })
+      updateBusiness(param).then(res => {
+        console.log(res)
+      })
+    },
+
+    //获取数据
+    getData(data) {
+      if (!data.map) {
+        this.type = 2;
+      } else {
+        this.buildMess = data;
+        this.type = 3;
+        // this.getJson(this.buildMess.map);
+      }
+    },
+
+    getJson(jsonId) {
+      axios({
+        method: 'get',
+        url: "/img/image-service/common/file_get/" + jsonId + "?systemId=revit",
+        data: {},
+        responseType: 'blob',
+        // contentType: "charset=utf-8"
+      })
+        .then(res => {
+          let data = null
+          var blob = res.data;
+          var reader = new FileReader();
+          reader.readAsBinaryString(blob)
+          let _this = this
+          reader.onload = function (readerEvt) {
+            var binaryString = readerEvt.target.result;
+            // let base64Data = btoa(binaryString)
+            let base64Data = btoa(binaryString)
+            let unGzipData = pako.unzip(base64Data)
+            data = unGzipData
+            _this.dataMax = tools.getPoint(data);
+            if (data.WallList && data.WallList.length) {
+              tools.changeMap(data.WallList, -1, "PointList");
+            }
+            if (data.SpaceList && data.SpaceList.length) {
+              tools.changeMap(data.SpaceList, -1, "Paths");
+            }
+            if (data.ColumnList && data.ColumnList.length) {
+              tools.changeMap(data.ColumnList, -1, "Path");
+            }
+            if (data.VirtualWallList && data.VirtualWallList.length) {
+              tools.changeMap(data.VirtualWallList, -1, "PointList");
+            }
+            if (data.EquipmentList && data.EquipmentList.length) {
+              tools.changeMap(data.EquipmentList, -1, "PointList");
+            }
+            let ids = [];
+            if (data.SpaceList && data.SpaceList.length) {
+              data.SpaceList.map(items => {
+                items.BimId = _this.buildMess.code + ":" + items.BimId;
+                ids.push(items.BimId);
+              });
+            } else {
+              _this.$message("没有元空间数据")
+            }
+            _this.createCanvas(ids, data);
+          };
+        });
+    },
+
+    //创建实例
+    async createCanvas(ids, data) {
+      //初始化
+      if (!!this.view && !!this.view.scene) {
+        this.view.scene.root.children = [];
+        this.view = null;
+      }
+      if (this.type != 3) {
+        return;
+      }
+      this.view = new SGraphyView("canvas", this.mainScene);
+      this.view.onDraw();
+      this.view.canvasView.addEventListener("mouseup", this.dataChange);
+      this.view.canvasView.addEventListener("contextmenu", this.contextMenu);
+      this.view.canvasView.addEventListener("mousemove", this.canvasMove);
+
+      //添加事件使右键菜单隐藏
+      window.addEventListener("click", this.menuNone);
+      //   this.bimIdToId(ids, data);
+      await this.bimIdToId(ids, data);
+      //   this.getJson(this.buildMess.map)
+    },
+
+    //事件:canvas的划过事件
+    canvasMove(e) { },
+
+    //画虚拟墙
+    addLine() {
+      this.view.canvasView.addEventListener("click", this.addLineClick);
+    },
+
+    //画点位坐标
+    doPoint(list) {
+      console.log("list", list)
+      this.list = list;
+      this.getJson(this.buildMess.map)
+    },
+
+    //排序函数
+    compare(property) {
+      return function (a, b) {
+        let value1 = a[property];
+        let value2 = b[property];
+        return value1 - value2;
+      };
+    },
+
+    //删除虚拟墙
+    detaleWall() {
+      let arr = this.view.scene.root.children;
+      let index = arr.indexOf(this.detaleLine);
+      if (index > -1) {
+        arr.splice(index, 1);
+        this.detaleLine = null;
+      }
+    },
+
+    //获取点到线的最短距离
+    getMinDistance(arr, dot) {
+      let len;
+
+      //如果arr[0].x==arr[1].x 说明是条竖着的线
+      if (arr[0].x - arr[1].x == 0) {
+        len = Math.abs(dot.X - arr[0].x);
+      } else {
+        let A = (arr[0].y - arr[1].y) / (arr[0].x - arr[1].x);
+        let B = arr[0].y - A * arr[0].x;
+
+        len = Math.abs((A * dot.X + B - dot.Y) / Math.sqrt(A * A + 1));
+      }
+
+      return {
+        min: len,
+        line: arr
+      };
+    },
+
+    //获取最近的交点
+    getIntersection(arr, point) {
+      let P = {};
+      // 斜率为:k = ( pt2.y - pt1. y ) / (pt2.x - pt1.x );
+      // 该直线方程为:y = k* ( x - pt1.x) + pt1.y。
+
+      //其垂线的斜率为 - 1 / k,垂线方程为:y = (-1/k) * (x - point.x) + point.y 。
+
+      //联立两直线方程解得:x = ( k^2 * pt1.x + k * (point.y - pt1.y ) + point.x ) / ( k^2 + 1) ,y = k * ( x - pt1.x) + pt1.y;
+      //如果arr[0].x==arr[1].x 说明是条竖着的线
+      if (arr[0].x == arr[1].x) {
+        P.x = arr[0].x;
+        P.y = point.Y;
+      } else {
+        let k = (arr[1].y - arr[0].y) / (arr[1].x - arr[0].x);
+        // let y = k * (x - arr[0].x) + arr[0].y;
+        // let y1 = (-1/k) * (x - point.X) + point.Y
+        // let x =
+        //     (k * k * arr[0].x + k * (point.Y - arr[0].y) + point.X) /
+        //     (k * k * k),
+        //   y = k * (x - arr[0].x) + arr[0].y;
+        // if(x > arr[0].x && x > arr[1].x){
+        //   if(arr[0].x > arr[1].x){
+        //     x = arr[0].x
+        //     y = arr[0].y
+        //   }else{
+        //     x = arr[1].x
+        //     y = arr[1].y
+        //   }
+        // }
+        // P.x = x
+        // P.y = y
+        let A = (arr[0].y - arr[1].y) / (arr[0].x - arr[1].x);
+        let B = arr[0].y - A * arr[0].x;
+        let m = point.X + A * point.Y;
+
+        P.x = (m - A * B) / (A * A + 1);
+        P.y = A * P.x + B;
+      }
+      return P;
+    },
+
+    //右键菜单的查看详情
+    getDatails() {
+      let arr = this.view.scene.root.children;
+      let index = arr.indexOf(this.detaleItem);
+      this.$emit("getDetails", { Id: arr[index].id });
+    },
+
+    //右键的清除该点位的坐标
+    clearXY() {
+      let param = {
+        PointId: this.detaleItem.id,
+        ProjId: this.param.ProjId,
+        UserId: this.param.UserId
+      };
+      this.changePoint(param, { x: 0, y: 0 }, false);
+    },
+
+    //右键的修改为无法定位到楼层的点位
+    noLocate() {
+      let param = {
+        PointId: this.detaleItem.id,
+        ProjId: this.param.ProjId,
+        UserId: this.param.UserId
+      };
+      this.changePoint(param, { x: 0, y: 0 }, 2);
+    },
+
+    //右键菜单隐藏
+    menuNone() {
+      this.menuShow = this.lineShow = this.pointShow = false;
+    },
+
+    async bimIdToId(ids, data) {
+      await formBIMToPri({
+        type: ["Si"],
+        ids: ids,
+        ProjId: this.param.projId,
+        secret: this.param.secret
+      })
+        .then(res => {
+          if (res.data.Result == "success") {
+            data.SpaceList.map((item, index) => {
+              res.data.Content.map((i, li) => {
+                //判断bimId是否相同
+                if (item.BimId == i.infos.BIMID) {
+                  item.id = i.id;
+                }
+              });
+            });
+            // this.createCanvas();
+            // this.initGraphy(data);
+            this.initGraphy(data);
+            return data
+          } else {
+            this.$message.error(res.data.ResultMsg);
+          }
+        })
+        .catch(() => {
+          this.$message.error("请求出错");
+        });
+    },
+
+    //实例化视图
+    initGraphy(data) {
+      this.view.pos.x = this.view.pos.y = -50;
+      let equip = data.EquipmentList,
+        wall = data.WallList,
+        virtual = data.VirtualWallList,
+        space = data.SpaceList,
+        column = data.ColumnList,
+        spaceStr;
+
+      //空间
+      if (space && space.length) {
+        for (let i = 0; i < space.length; i++) {
+          if (space[i].Paths[0] && space[i].Paths[0].length >= 2) {
+            spaceStr = new SGraphyPolygonItem(
+              space[i].Paths[0],
+              1,
+              "red",
+              colorArr[i % 10],
+              space[i].id
+            );
+            this.mainScene.addItem(spaceStr);
+          }
+          for (let j = 0; j < space[i].Paths.length; j++) {
+            if (space[i].Paths[0] && j > 1 && space[i].Paths[j].length >= 2) {
+              spaceStr = new SGraphyPolygonItem(
+                space[i].Paths[j],
+                2,
+                "#fff",
+                "#fff",
+                space[i].id
+              );
+              this.mainScene.addItem(spaceStr);
+            }
+          }
+        }
+      }
+
+      // 画柱子
+      if (column && column.length) {
+        for (let i = 0; i < column.length; i++) {
+          if (column[i].Path && column[i].Path.length >= 2) {
+            spaceStr = new SGraphyPolygonItem(
+              column[i].Path,
+              1,
+              "#000",
+              "#000"
+            );
+            this.mainScene.addItem(spaceStr);
+          }
+        }
+      }
+
+      // 画墙
+      if (wall && wall.length) {
+        for (let i = 0; i < wall.length; i++) {
+          for (let j = 0; j < wall[i].PointList.length - 1; j++) {
+            let str = "wall" + i;
+            str = new SGraphyLineItem(
+              wall[i].PointList[j].X,
+              wall[i].PointList[j].Y,
+              wall[i].PointList[j + 1].X,
+              wall[i].PointList[j + 1].Y
+            );
+            this.mainScene.addItem(str);
+          }
+        }
+        wall.map((res, index) => {
+          if (res.PointList.length > 1) {
+            res.PointList.map((list, inde) => {
+              if (res.PointList[inde + 1] != undefined) {
+                this.wallList.push([
+                  { x: list.X, y: list.Y },
+                  { x: res.PointList[inde + 1].X, y: res.PointList[inde + 1].Y }
+                ]);
+              } else {
+                return undefined;
+              }
+            });
+          }
+        });
+      }
+
+      // //画虚拟墙
+      if (virtual && virtual.length) {
+        for (let i = 0; i < virtual.length; i++) {
+          for (let j = 0; j < virtual[i].PointList.length - 1; j++) {
+            let str = "virtual" + i + j;
+            str = new SGraphyVirtualItem(
+              virtual[i].PointList[j].X,
+              virtual[i].PointList[j].Y,
+              virtual[i].PointList[j + 1].X,
+              virtual[i].PointList[j + 1].Y,
+              "green",
+              2,
+              true,
+              true
+            );
+            this.mainScene.addItem(str);
+          }
+        }
+      }
+
+      if (this.list && this.list.length) {
+        this.list = this.list.map(item => {
+          if (item.X == 0 && item.Y == 0) {
+            return undefined;
+          } else {
+            return {
+              id: item.Id,
+              X: item.X,
+              Y: item.Y,
+              Name: item.Name
+            };
+          }
+        });
+        this.list = this.list.filter(item => item);
+        for (let i = 0; i < this.list.length; i++) {
+          let space = "point" + i;
+          let url = this.imageUrl;
+          space = new SGraphyImageItem(30, 30, url, this.list[i].id);
+          space.moveTo(this.list[i].X, this.list[i].Y * -1);
+          this.mainScene.addItem(space);
+        }
+      }
+
+      //获取中心点
+      let rect = this.view.scene.worldRect();
+
+      //初始化画布缩放比例
+      this.view.scale = 1;
+
+      //计算缩放比例
+      this.view.scale = Math.min(
+        this.view.width / (rect.width * 1.2),
+        this.view.height / (rect.height * 1.2)
+      );
+      this.view.minScale = this.view.scale / 10
+      this.view.maxScale = this.view.scale * 10
+      // 移动画布
+      this.view.pos.x =
+        (-(rect.right + rect.left) / 2) * this.view.scale + this.view.width / 2;
+      this.view.pos.y =
+        (-(rect.bottom + rect.top) / 2) * this.view.scale +
+        this.view.height / 2;
+    },
+
+    // 定位
+    locationGraphy(point) {
+      // 移动画布
+      this.view.pos.x = -point.X * this.view.scale + this.view.width / 2;
+      this.view.pos.y = -point.Y * this.view.scale + this.view.height / 2;
+      this.view.scale = this.view.scale;
+    },
+
+    //点击按钮
+    addPoint(item) {
+      let bbox = this.view.canvasView.getBoundingClientRect();
+      this.id = item.Id;
+      this.view.canvasView.style.cursor =
+        "url(http://prod.dp.sagacloud.cn:28888/image-service/common/image_get?systemId=dev&key=graphy.png),auto";
+      this.view.canvasView.addEventListener("click", this.getPoint);
+    },
+
+    //获取鼠标相对canvas的位置
+    getMouseCanvas(e) {
+      let bbox = this.view.canvasView.getBoundingClientRect();
+      let x = e.clientX - bbox.left,
+        y = e.clientY - bbox.top;
+      return {
+        x: x,
+        y: y
+      };
+    },
+
+    //修改点位坐标信息
+    changePoint(getParam, pointWall, falg, createPoint) {
+      let pointList = null;
+      getPoint(getParam).then(res => {
+        if (res.data.Result == "success") {
+          let param = {
+            ProjId: this.param.ProjId,
+            UserId: this.param.UserId,
+            PointList: res.data.PointList[0]
+          };
+          param.PointList.X = pointWall.x;
+          param.PointList.Y = pointWall.y * -1;
+          if (!param.PointList.FloorId) {
+            param.PointList.FloorId = this.data.code;
+          }
+          if (falg == 2) {
+            param.PointList.FloorId = "";
+          }
+          updatePoint(param).then(res => {
+            if (res.data.Result == "success") {
+              this.id = null;
+              if (falg == 1) {
+                this.mainScene.addItem(createPoint);
+                this.$message.success("标记成功");
+              } else if (falg == 2) {
+                this.view.scene.removeItem(this.detaleItem);
+                this.detaleItem = null;
+                this.$message.success("修改成功");
+              } else if (falg == 3) {
+                this.detaleItem = null;
+                this.$message.success("修改成功");
+              } else {
+                this.view.scene.removeItem(this.detaleItem);
+                this.detaleItem = null;
+                this.$message.success("修改成功");
+              }
+              this.$emit("resetPoint");
+            } else {
+              this.$message("标记失败,请重新标记");
+            }
+          });
+        } else {
+          this.$message.error("获取点位信息失败");
+        }
+      });
+    },
+
+    /** canvas事件------------------------------------------------------------------------------------*/
+
+    //点击事件
+    getPoint(e) {
+      let pointMess = this.getMouseCanvas(e);
+      // 获取真实的point
+      let pointWall = this.view.mapToScene(pointMess);
+      let url = this.imageUrl;
+      let createPoint = new SGraphyImageItem(30, 30, url, this.id);
+      //移动新建的point
+      createPoint.moveTo(pointWall.x, pointWall.y);
+      let getParam = {
+        PointId: this.id,
+        ProjId: this.param.ProjId,
+        UserId: this.param.UserId
+      };
+      this.changePoint(getParam, pointWall, 1, createPoint);
+
+      this.view.canvasView.style.cursor = "auto";
+      this.view.canvasView.removeEventListener("click", this.getPoint);
+    },
+
+    //右键菜单
+    contextMenu(e) {
+      //取消默认的浏览器自带的右键
+      e.preventDefault();
+
+      //将canvas的坐标转换成数据坐标
+      let point = this.view.mapToScene(this.getMouseCanvas(e));
+
+      //设立falg判断是否在标签上
+      let falg = false,
+        index = 0,
+        wallIndex = 0,
+        wallFalg = false;
+      let items = this.view.scene.root.children;
+      for (let i = 0; i < items.length; i++) {
+        if (items[i].type == 1) {
+          if (items[i].contains(point.x, point.y)) {
+            index = i;
+            falg = true;
+          }
+        }
+        // if (items[i].type == 4) {
+        //   if (items[i].contains(point.x, point.y)) {
+        //     wallIndex = i;
+        //     wallFalg = true;
+        //   }
+        // }
+      }
+
+      //如果在标签上
+      if (falg || wallFalg) {
+        this.menuShow = true;
+        let el = this.$refs.graphyMain;
+        if (falg) {
+          this.detaleItem = items[index];
+          this.pointShow = true;
+        } else if (wallFalg) {
+          this.detaleLine = items[wallIndex];
+          this.lineShow = true;
+        }
+        if (el.offsetWidth < e.layerX + 200) {
+          this.$refs.menu.style.left = e.layerX - 200 + "px";
+          this.$refs.menu.style.top = e.layerY + "px";
+        } else if (el.offsetHeight < e.layerY + 150) {
+          this.$refs.menu.style.left = e.layerX + "px";
+          this.$refs.menu.style.top = e.layerY - 100 + "px";
+        } else {
+          this.$refs.menu.style.left = e.layerX + "px";
+          this.$refs.menu.style.top = e.layerY + "px";
+        }
+        // this.mainScene.removeItem(items[index]);
+      } else {
+        this.lineShow = this.pointShow = false;
+        this.menuShow = false;
+      }
+    },
+
+    //鼠标抬起事件,数据发生改变
+    dataChange(e) {
+      let item = this.mouseInElement(this.view, e);
+      let childRen = this.view.scene.root.children;
+      myData = [];
+      for (let i in childRen) {
+        if (childRen[i].type == 1) {
+          myData.push({
+            Id: childRen[i].id,
+            name: childRen[i].name,
+            PointList: {
+              X: childRen[i]._pos.x,
+              Y: childRen[i]._pos.y
+            }
+          });
+        }
+      }
+
+      myData.map(item => {
+        for (let j = 0; j < this.list.length; j++) {
+          if (item.Id == this.list[j].id && (item.PointList.X != this.list[j].X || item.PointList.Y * -1 != this.list[j].Y)) {
+            this.list[j].X = item.PointList.X
+            this.list[j].Y = item.PointList.Y
+            let param = {
+              PointId: item.Id,
+              ProjId: this.param.ProjId,
+              UserId: this.param.UserId
+            };
+            this.changePoint(param, { x: item.PointList.X, y: item.PointList.Y }, 3);
+          }
+        }
+      })
+    },
+
+    /**
+     *
+     * @param {*} view graphy class
+     * @param {*} e    mouse元素e
+     */
+    mouseInElement(view, e) {
+      let mouse = this.getMouseCanvas(e),
+        falg = false,
+        items = view.scene.root.children,
+        i = 0;
+      for (; i < items.length; i++) {
+        if (items[i].type == 1) {
+          if (items[i].contains(mouse)) {
+            falg = true;
+            break;
+          }
+        }
+      }
+      return {
+        falg,
+        item: items[i] || [],
+        index: i
+      };
+    },
+
+    //调整到合适比例
+    suitableSize() {
+      //获取中心点
+      let rect = this.view.scene.worldRect();
+      //计算缩放比例
+      this.view.scale = Math.min(
+        this.view.width / (rect.width * 1.2),
+        this.view.height / (rect.height * 1.2)
+      );
+      // 移动画布
+      this.view.pos.x =
+        (-(rect.right + rect.left) / 2) * this.view.scale + this.view.width / 2;
+      this.view.pos.y =
+        (-(rect.bottom + rect.top) / 2) * this.view.scale +
+        this.view.height / 2;
+    },
+
+    //调整到小比例
+    smallSize() {
+      //获取中心点
+      let rect = this.view.scene.worldRect();
+      //计算缩放比例
+      this.view.scale = this.view.scale * 0.9;
+      // 移动画布
+      this.view.pos.x =
+        (-(rect.right + rect.left) / 2) * this.view.scale + this.view.width / 2;
+      this.view.pos.y =
+        (-(rect.bottom + rect.top) / 2) * this.view.scale +
+        this.view.height / 2;
+    },
+
+    bigSize() {
+      //获取中心点
+      let rect = this.view.scene.worldRect();
+      //计算缩放比例
+      this.view.scale = this.view.scale * 1.1;
+      // 移动画布
+      this.view.pos.x =
+        (-(rect.right + rect.left) / 2) * this.view.scale + this.view.width / 2;
+      this.view.pos.y =
+        (-(rect.bottom + rect.top) / 2) * this.view.scale +
+        this.view.height / 2;
+    }
+
+  }
+};
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style lang="less" scoped>
+.canvasGraphy {
+  position: relative;
+  canvas {
+    border: 1px solid #ccc;
+  }
+  .saga-message {
+    height: 400px;
+    line-height: 400px;
+    color: #ccc;
+    font-size: 24px;
+    text-align: center;
+  }
+  #menu {
+    width: 200px;
+    z-index: 88;
+    overflow: hidden;
+    box-shadow: 0 1px 1px #888, 1px 0 1px #ccc;
+    position: absolute;
+    background-color: #fff;
+  }
+  #menu p {
+    width: 100%;
+    padding-left: 5px;
+    overflow: hidden;
+    height: 35px;
+    line-height: 35px;
+    font-size: 14px;
+    margin: 0;
+    text-align: left;
+    cursor: pointer;
+  }
+  #menu p:hover {
+    background-color: aqua;
+  }
+}
+</style>

+ 543 - 0
src/views/data_admin/buildGraphy/graphyTabs.vue

@@ -0,0 +1,543 @@
+<!--
+setFalg 插旗事件
+getLocation 定位
+-->
+<template>
+  <div id="graphy-tabs">
+    <el-tabs v-model="activeName2" type="card" @tab-click="handleClick">
+      <el-tab-pane label="本层的点位标签" name="point">
+        <div
+          v-if="pointData.length"
+          v-loading="isLoading"
+          style="max-height: 800px;overflow-y:auto;"
+        >
+          <div v-for="(item,index) in pointData" :key="index">
+            <div class="point">
+              <span>{{item.Name}}</span>
+              <el-button size="mini" @click="getDetails(item)">编辑点位标签</el-button>
+              <el-button
+                :disabled="!map"
+                size="mini"
+                @click="btnClick(item)"
+              >{{ item.X == 0 && item.Y == 0 ? '插旗' : '定位'}}</el-button>
+            </div>
+          </div>
+        </div>
+        <template v-if="!pointData.length">
+          <div class="saga-message">{{pointParam.FloorId ? "数据为空" : "←请选择楼层"}}</div>
+        </template>
+      </el-tab-pane>
+      <el-tab-pane label="无法定位到楼层的点位标签" name="noPoint">
+        <div v-if="pointNoData.length" v-loading="isLoading" style="max-height: 800px;">
+          <div v-for="(item,index) in pointNoData" :key="index">
+            <div class="point">
+              <span>{{item.Name}}</span>
+              <el-button size="mini" @click="getDetails(item)">编辑点位标签</el-button>
+              <el-button
+                :disabled="!(item.X == 0 && item.Y == 0)"
+                size="mini"
+                @click="btnClick(item)"
+              >{{ item.X == 0 && item.Y == 0 ? '插旗' : '定位'}}</el-button>
+            </div>
+          </div>
+        </div>
+        <template v-if="!pointNoData.length">
+          <div class="saga-message">{{pointParam.FloorId ? "数据为空" : "←请选择楼层"}}</div>
+        </template>
+      </el-tab-pane>
+    </el-tabs>
+    <el-dialog title="详情" :visible.sync="pointShow" width="40%">
+      <div class="qrcode">
+        <div class="qrcode-view">
+          <img
+            :src="'api/ScanBuilding/service/qrcode/point?projectId=' + projectId + '&pointId=' + pointDetails.PointId + '&FloorId=' + pointDetails.FloorId + '&width=200&height=200'"
+            alt="点位标签二维码"
+          >
+        </div>
+        <div class="point-edit">
+          <p>
+            点位标签的现场位置:{{activeName2 != 'point' ? '无楼层' : pointParam.fllorName}}
+            -{{pointDetails.spaceName || '未知原空间'}}
+            -({{pointDetails.X}},{{pointDetails.Y}})
+          </p>
+          <div>
+            <form-input
+              :width="100"
+              @change="changeInput"
+              :value="pointDetails.PointName"
+              :keys="'PointName'"
+              :label="'点位标签:'"
+              :isRule="false"
+            ></form-input>
+            <form-input
+              :width="100"
+              @change="changeInput"
+              :value="pointDetails.PointLocalId"
+              :keys="'PointLocalId'"
+              :label="'点位本地编码:'"
+              :isRule="false"
+            ></form-input>
+            <!-- <form-input></form-input> -->
+          </div>
+        </div>
+      </div>
+      <div class="point-coding">
+        <p>编码及关系</p>
+        <ul>
+          <li>
+            <span>点位标签ID</span>
+            <span>{{pointDetails.PointId}}</span>
+          </li>
+          <li>
+            <span>模型ID</span>
+            <span>{{pointDetails.BimId || '暂无'}}</span>
+          </li>
+        </ul>
+      </div>
+      <div class="point-coding">
+        <p>基本信息</p>
+        <ul>
+          <li>
+            <span>信标类型</span>
+            <span>二维码</span>
+          </li>
+          <li>
+            <span>备注</span>
+            <span>
+              <form-input
+                :width="0"
+                @change="changeInput"
+                :value="pointDetails.Note"
+                :keys="'Note'"
+                :label="''"
+                :isRule="false"
+              ></form-input>
+            </span>
+          </li>
+        </ul>
+      </div>
+      <div class="point-pic">
+        <p>点位安装位置效果照片</p>
+        <template v-for="(item,index) in installPic">
+          <div class="point-image" :key="index">
+            <i class="el-icon-delete" @click="delImage(index,installPic)"></i>
+            <img
+              :src="'img/image-service/common/image_get?systemId=dataPlatform&key='+ item.key +'&width=200&height=200'"
+              alt
+            >
+          </div>
+        </template>
+        <load-img keyName="安装位置" @getKey="getKey"></load-img>
+      </div>
+      <div class="point-pic">
+        <p>全景照片</p>
+        <template v-for="(item,index) in panorama">
+          <div class="point-image" :key="index">
+            <i class="el-icon-delete" @click="delImage(index,panorama)"></i>
+            <img
+              :src="'img/image-service/common/image_get?systemId=dataPlatform&key='+ item.key +'&width=200&height=200'"
+              alt
+            >
+          </div>
+        </template>
+        <load-img keyName="全景照片" @getKey="getKey"></load-img>
+      </div>
+      <div class="point-pic">
+        <p>周边照片</p>
+        <template v-for="(item,index) in rimPic">
+          <div class="point-image" :key="index">
+            <i class="el-icon-delete" @click="delImage(index,rimPic)"></i>
+            <img
+              :src="'img/image-service/common/image_get?systemId=dataPlatform&key='+ item.key +'&width=200&height=200'"
+              alt
+            >
+          </div>
+        </template>
+        <load-img keyName="周边照片" @getKey="getKey"></load-img>
+      </div>
+      <div class="point-pic">
+        <p>视频资料</p>
+        <template v-for="(item,index) in videoPic">
+          <div class="point-image" :key="index">
+            <i class="el-icon-delete" @click="delImage(index,videoPic)"></i>
+            <img
+              :src="'img/image-service/common/image_get?systemId=dataPlatform&key='+ item.key +'&width=200&height=200'"
+              alt
+            >
+          </div>
+        </template>
+        <load-img keyName="视频" @getKey="getKey"></load-img>
+      </div>
+      <div class="point-pic">
+        <p>其他照片</p>
+        <template v-for="(item,index) in elsePic">
+          <div class="point-image" :key="index">
+            <i class="el-icon-delete" @click="delImage(index,elsePic)"></i>
+            <img
+              :src="'img/image-service/common/image_get?systemId=dataPlatform&key='+ item.key +'&width=200&height=200'"
+              alt
+            >
+          </div>
+        </template>
+        <load-img keyName="其他照片" @getKey="getKey"></load-img>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  getPT, //获取点位列表
+  getPoint, //获取点位详情
+  updatePoint //修改点位
+} from "@/api/scan/request";
+
+import formInput from "./lib/formInput";
+import loadImg from "./lib/uploadImg";
+import {mapGetters, mapActions} from 'vuex';
+
+export default {
+  props: {
+    pointParam: {
+      type: Object
+    }
+  },
+  components: {
+    formInput,
+    loadImg
+  },
+  data() {
+    return {
+      activeName2: "point",
+      pointData: [], //tab为本层的点位标签
+      pointNoData: [], //tab为无法定位的点位标签
+      pointShow: false, //标签详情的弹窗
+      pointDetails: {}, //标签详情信息对象
+      // projId: this.$route.query.projId,
+      index: "",
+      installPic: [], //安装位置
+      panorama: [], //全景照片
+      rimPic: [], //周边照片
+      videoPic: [], //视频资料
+      elsePic: [], //其他照片
+      map: true
+    };
+  },
+  computed: {
+        ...mapGetters("peojMess", [
+        "projectId",
+        "userId",
+        "secret"
+    ])
+    },
+  methods: {
+    //tabs被点击
+    handleClick(tab, event) {
+      this.index = tab.index;
+      this.getPointList();
+    },
+
+    //修改input
+    changeInput(val, key) {
+      this.pointDetails[key] = val;
+      this.updatePoint();
+    },
+
+    //删除图片
+    delImage(index, arr) {
+      arr.splice(index, 1);
+      this.updatePoint();
+    },
+
+    //获取key的值
+    getKey(val, name) {
+      switch (name) {
+        case "安装位置":
+          this.installPic.push({
+            key: val,
+            name: name,
+            type: "image_wz"
+          });
+          break;
+        case "全景照片":
+          this.panorama.push({
+            key: val,
+            name: name,
+            type: "panorama"
+          });
+          break;
+        case "周边照片":
+          this.rimPic.push({
+            key: val,
+            name: name,
+            type: "image_zb"
+          });
+          break;
+        case "视频":
+          this.videoPic.push({
+            key: val,
+            name: name,
+            type: "video"
+          });
+          break;
+        default:
+          this.elsePic.push({
+            key: val,
+            name: name,
+            type: "image_else"
+          });
+      }
+      this.updatePoint();
+    },
+
+    btnClick(item) {
+      if (item.X == 0 && item.Y == 0) {
+        this.$emit("setFalg", item);
+      } else {
+        this.$emit("getLocation", item);
+      }
+    },
+
+    mapPush(detailsArr, pic) {
+      pic.map(item => {
+        detailsArr.push(item);
+      });
+    },
+
+    //修改详情
+    updatePoint() {
+      this.pointDetails.ImageList = [];
+      this.mapPush(this.pointDetails.ImageList, this.installPic);
+      this.mapPush(this.pointDetails.ImageList, this.panorama);
+      this.mapPush(this.pointDetails.ImageList, this.rimPic);
+      this.mapPush(this.pointDetails.ImageList, this.videoPic);
+      this.mapPush(this.pointDetails.ImageList, this.elsePic);
+      let param = {
+        ProjId: this.pointParam.ProjId,
+        UserId: this.pointParam.UserId,
+        PointList: this.pointDetails
+      };
+      updatePoint(param).then(res => {
+        this.$message.success("修改成功");
+      });
+    },
+
+    getDetails(item) {
+      let params = {
+        ProjId: this.projectId,
+        UserId: this.userId,
+        PointId: item.Id
+      };
+      getPoint(params).then(res => {
+        let data = res.data;
+        if (data.Result == "success") {
+          this.pointShow = true;
+          this.pointDetails = data.PointList[0];
+          this.getPic(data.PointList[0].ImageList);
+        } else {
+          this.$message.error("请求出错");
+        }
+      });
+    },
+
+    getPic(imgArr) {
+      this.installPic = [];
+      this.panorama = [];
+      this.rimPic = [];
+      this.videoPic = [];
+      this.elsePic = [];
+      imgArr.map((item, index) => {
+        switch (item.name) {
+          case "安装位置":
+            this.installPic.push(item);
+            break;
+          case "全景照片":
+            this.panorama.push(item);
+            break;
+          case "周边照片":
+            this.rimPic.push(item);
+            break;
+          case "视频":
+            this.videoPic.push(item);
+            break;
+          default:
+            this.elsePic.push(item);
+        }
+      });
+    },
+
+    //获取point
+    getPointList() {
+      this.isLoading = true;
+      if (this.pointParam.FloorId) {
+        let param = {
+          FloorId: this.pointParam.FloorId,
+          ProjId: this.pointParam.ProjId,
+          UserId: this.pointParam.UserId
+        };
+        console.log(param)
+        //当index为1时FloorId为空
+        if (this.index == "1") {
+          param.FloorId = "";
+        }
+        getPT(param).then(res => {
+          res.data.PointList.splice(0, 1);
+          if (this.index == "1") {
+            this.pointNoData = res.data.PointList;
+          } else {
+            this.$emit("getPointList", res.data.PointList);
+            this.pointData = res.data.PointList;
+          }
+          this.isLoading = false;
+        });
+      }
+    },
+
+    //初始化
+    reset(data, map) {
+      this.map = map
+      this.pointParam.FloorId = data.FloorId;
+      this.pointParam.fllorName = data.fllorName;
+      this.activeName2 = "point";
+      this.getPointList();
+    }
+  },
+  watch: {
+    pointShow: {
+      deep: true,
+      handler: function (old, val) {
+        if (old == false && val == true) {
+          this.getPointList();
+        }
+      }
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+#graphy-tabs {
+  .saga-message {
+    height: 400px;
+    line-height: 400px;
+    color: #ccc;
+    font-size: 24px;
+    text-align: center;
+  }
+  .point {
+    padding-left: 20px;
+    height: 30px;
+    span {
+      font-size: 12px;
+      width: 180px;
+      display: inline-block;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      overflow: hidden;
+    }
+    button {
+      margin-bottom: 5px;
+    }
+  }
+  .point:hover {
+    background-color: #f2f6fc;
+  }
+  .qrcode {
+    width: 100%;
+    height: 180px;
+    overflow: hidden;
+    .qrcode-view {
+      width: 180px;
+      height: 180px;
+      overflow: hidden;
+      float: left;
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+    .point-edit {
+      height: 180px;
+      display: inline-block;
+      padding-top: 10px;
+      overflow-x: hidden;
+      width: calc(100% - 200px);
+    }
+  }
+  .point-coding {
+    width: 100%;
+    height: 120px;
+    margin-top: 5px;
+    overflow: hidden;
+    p {
+      height: 30px;
+      line-height: 30px;
+      padding-left: 10px;
+      font-weight: 500;
+      font-size: 16px;
+      text-align: left;
+    }
+    ul {
+      width: 100%;
+      border: 1px solid #ccc;
+      border-bottom: none;
+      li {
+        line-height: 40px;
+        height: 40px;
+        span {
+          display: block;
+          float: left;
+          padding-left: 10px;
+          box-sizing: border-box;
+          border-right: 1px solid #ccc;
+          border-bottom: 1px solid #ccc;
+          border-left: 1px solid #ccc;
+          height: 40px;
+          overflow: hidden;
+        }
+        span:first-child {
+          width: 30%;
+        }
+        span:last-child {
+          width: 70%;
+        }
+      }
+    }
+  }
+  .point-pic {
+    width: 100%;
+    overflow: hidden;
+    p {
+      height: 25px;
+      line-height: 25px;
+      padding-left: 10px;
+      font-weight: 500;
+      font-size: 16px;
+      margin-top: 5px;
+      margin-bottom: 5px;
+    }
+  }
+  .point-image {
+    width: 180px;
+    height: 180px;
+    float: left;
+    position: relative;
+    margin-right: 10px;
+    margin-bottom: 10px;
+    border: 1px solid #ccc;
+    img {
+      width: 100%;
+      height: 100%;
+    }
+    i {
+      position: absolute;
+      bottom: 10px;
+      right: 10px;
+      background-color: #fff;
+      padding: 5px;
+      cursor: pointer;
+    }
+  }
+}
+</style>
+

+ 92 - 0
src/views/data_admin/buildGraphy/graphyTree.vue

@@ -0,0 +1,92 @@
+<template>
+    <el-tree
+    :props="treeArr"
+    :load="getNodes"
+    @node-click="floorClick"
+    :highlight-current="true"
+    lazy>
+    </el-tree>
+</template>
+
+<script>
+import {
+  getBuildSelect, //根据项目ID获得建筑列表
+  getFloor //根据建筑id获取楼层id
+} from "@/api/scan/request";
+export default {
+  props: {
+    param: {
+      type: Object
+    }
+  },
+  data() {
+    return {
+      treeArr: {
+        label: "name", //label的名字
+        children: "zones", //如果有下一级children和isLeaf存在
+        isLeaf: "isChild"
+      }
+    };
+  },
+  methods: {
+    //点击节点懒加载
+    getNodes(node, resolve) {
+      let param = {
+        ProjId: this.param.ProjId,
+        UserId: this.param.UserId
+      };
+      console.log(param)
+      console.log(node);
+      //第一级初始化数据,获取建筑信息
+      if (node.level === 0) {
+        getBuildSelect(param).then(res => {
+          let data = res.data.BuildList,
+            arr;
+            console.log(data)
+          if (data && data.length > 0) {
+            arr = data.map(item => {
+              return {
+                name: item.BuildLocalName,
+                code: item.BuildId
+              };
+            });
+          }
+          console.log(arr)
+          return resolve(arr);
+        });
+      } else {
+        //   第二级获取楼层信息
+        param.BuildId = node.data.code;
+        getFloor(param).then(res => {
+          let resData = res.data.FloorList,
+            buildData;
+          if (resData && resData.length > 0) {
+            buildData = resData.map(item => {
+              return {
+                name: item.FloorLocalName + (item.FloorMap ? '' : '(需初始化数据)'),
+                code: item.FloorId,
+                map: item.FloorMap,
+                isChild: true //没有下一级
+              };
+            });
+            return resolve(buildData);
+          }
+        });
+      }
+    },
+
+    //子节点被点击
+    floorClick(data) {
+      if (data.isChild) {
+          //派发事件
+          this.$emit("change",data)
+      } else {
+        return false;
+      }
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+</style>

+ 156 - 0
src/views/data_admin/buildGraphy/index.vue

@@ -0,0 +1,156 @@
+<!--
+  revit空间管理
+ -->
+<template>
+  <div id="graphy">
+    <div class="graphy-left">
+      <graphy-tree v-if="show" :param="param" @change="getPoint"></graphy-tree>
+    </div>
+    <div class="graphy-main">
+      <graphy-canvas v-if="show" :param="param" @getDetails="getDetails" @resetPoint="resetPoint" ref="canvas"></graphy-canvas>
+    </div>
+    <div class="graphy-right">
+      <graphy-tabs v-show="show"
+        ref="tabs"
+        :pointParam="pointParam"
+        @setFalg="setFalg"
+        @getLocation="getLocation"
+        @getPointList="sendPointList"
+      ></graphy-tabs>
+    </div>
+  </div>
+</template>
+
+<script>
+//接口
+import graphyTree from "./graphyTree";
+import graphyTabs from "./graphyTabs";
+import graphyCanvas from "./graphyCanvas";
+import {mapGetters, mapActions} from 'vuex';
+import {getPT} from "@/api/scan/request"; //获取点位坐标
+import Handsontable from "handsontable-pro"
+import 'handsontable-pro/dist/handsontable.full.css'
+import zhCN from 'handsontable-pro/languages/zh-CN';
+export default {
+  components: {
+    graphyTree,
+    graphyTabs,
+    graphyCanvas
+  },
+  data() {
+    return {
+      param: {
+        ProjId: this.projectId, //项目id
+        UserId: this.userId //用户id
+      },
+      pointParam: {
+        //point请求参数
+        ProjId: this.projectId, //项目id
+        UserId: this.userId, //用户id
+        fllorName: ""
+      },
+      map: null,
+      pointId: null,
+      show:false,
+    };
+  },
+  mounted() { 
+    this.changeValue()
+  },
+  computed: {
+    ...mapGetters("peojMess", [
+        "projectId",
+        "userId",
+        "secret"
+    ])
+  },
+  methods: {
+    changeValue(){
+      this.$set(this.param,'ProjId',this.projectId)
+      console.log(this.param)
+      this.$set(this.param,'UserId',this.userId)
+      this.$set(this.pointParam,'ProjId',this.projectId)
+      this.$set(this.pointParam,'UserId',this.userId)
+      console.log(this.pointParam)
+      this.show = true
+    },
+    getPoint(data) {
+      this.pointParam.FloorId = data.code;
+      this.pointParam.fllorName = data.name;
+      this.$refs.tabs.reset(this.pointParam, data.map);
+      if (this.map != data.map) {
+        this.map = data.map;
+        this.$refs.canvas.getData(data);
+      } else {
+        return;
+      }
+    },
+
+    //获取到点位标签坐标
+    sendPointList(list) {
+      if (list && list.length && list[0].Id == this.pointId) {
+        this.$refs.canvas.doPoint(list);
+      } else {
+        if (list.length) {
+          this.pointId = list[0].Id;
+          this.$refs.canvas.doPoint(list);
+        } else {
+          this.$refs.canvas.doPoint([]);
+        }
+      }
+    },
+
+    //插旗setFalg
+    setFalg(item) {
+      this.$refs.canvas.addPoint(item);
+    },
+
+    //定位getLocation
+    getLocation(item) {
+      this.$refs.canvas.locationGraphy({ X: item.X, Y: item.Y * -1 });
+    },
+
+    //重新获取点位信息resetPoint
+    resetPoint() {
+      this.$refs.tabs.reset(this.pointParam, true);
+    },
+
+    //查看详情
+    getDetails(item) {
+      this.$refs.tabs.getDetails(item);
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+#graphy {
+  .graphy-left {
+    width: 200px;
+    height: 100%;
+    position: absolute;
+    overflow-y: auto;
+    left: 0;
+    top: 0;
+    bottom: 0;
+    border-right: 1px solid #ccc;
+  }
+  .graphy-main {
+    position: absolute;
+    left: 200px;
+    top: 0;
+    right: 400px;
+    bottom: 0;
+    overflow: auto;
+  }
+  .graphy-right {
+    position: absolute;
+    right: 0;
+    width: 400px;
+    top: 0;
+    bottom: 0;
+    border-left: 1px solid #ccc;
+    overflow: hidden;
+  }
+}
+</style>

+ 114 - 0
src/views/data_admin/buildGraphy/lib/cascaders/assets.vue

@@ -0,0 +1,114 @@
+<template>
+  <div id="cascaderMap">
+    <span class="buildFloor">设备族:</span>
+    <el-cascader
+      placeholder="请选择"
+      :options="options"
+      v-model="value"
+      :props="props"
+      filterable
+      :style="isWidth ? '' : 'width:160px;'"
+      size="small"
+      @change="changeVal"
+      change-on-select
+    ></el-cascader>
+  </div>
+</template>
+<script>
+import { getEquipmentFamily } from "@/api/request";
+export default {
+  name: "getCode",
+  props: {
+    isWidth: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      value: [],
+      options: [],
+      props: {
+        value: "code",
+        label: "facility"
+      },
+      falg: true,
+      content: []
+    };
+  },
+  created() {
+    this.getData();
+  },
+  mounted() { },
+  methods: {
+    setValue(val) {
+      this.value = val
+    },
+    //修改val
+    changeVal(val) {
+      let value = {}
+      this.options.map(item => {
+        if (item.code == val) {
+          value = item
+        }
+      })
+      this.value = val
+      this.$emit("change", value)
+    },
+    async getData() {
+      let _this = this
+      await getEquipmentFamily(res => {
+        _this.options = _this.changeArr(res.Content)
+        if (!!this.value && this.value.length) {
+          let value = {}
+          this.options.map(item => {
+            if (item.code == this.value[0]) {
+              value = item
+            }
+          })
+          this.$emit("change", value)
+        }
+        if (!_this.falg) {
+          _this.changeList()
+        }
+      })
+    },
+    changeArr(arr) {
+      let data = [];
+      arr.map(item => {
+        data.push({ code: item.code, facility: item.name, disabled: false })
+      });
+      return data;
+    },
+    pushData(content) {
+      this.content = content
+      if (this.options.length) {
+        this.falg = true
+        this.changeList()
+      } else {
+        this.falg = false
+      }
+    },
+    changeList() {
+      this.options.map(item => {
+        item.disabled = true
+        this.content.map(child => {
+          if (item.code == child) {
+            item.disabled = false
+          }
+        })
+      })
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#cascaderMap {
+  float: left;
+  margin-left: 10px;
+  .buildFloor {
+    color: #999999;
+    font-size: 14px;
+  }
+}
+</style>

+ 120 - 0
src/views/data_admin/buildGraphy/lib/cascaders/system.vue

@@ -0,0 +1,120 @@
+<template>
+  <div id="cascaderMap">
+    <span class="buildFloor">所属专业系统类型:</span>
+    <el-cascader
+      placeholder="请选择"
+      :options="options"
+      v-model="value"
+      :props="props"
+      filterable
+      :style="isWidth ? '' : 'width:160px;'"
+      size="small"
+      @change="changeVal"
+      change-on-select
+    ></el-cascader>
+  </div>
+</template>
+<script>
+import { getEqCode } from "@/api/request";
+export default {
+  name: "getCode",
+  props: {
+    isWidth: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      value: [],
+      options: [],
+      props: {
+        value: "code",
+        label: "facility"
+      },
+      falg: true,
+      content: []
+    };
+  },
+  created() {
+    this.getData();
+  },
+  mounted() { },
+  methods: {
+    setValue(val) {
+      this.value = val
+    },
+    //修改val
+    changeVal(val) {
+      let value = {}
+      this.options.map(item => {
+        if (item.code == val) {
+          value = item
+        }
+      })
+      this.$emit("change", value)
+    },
+    getData() {
+      getEqCode().then(res => {
+        console.log(res.data)
+        this.options = this.changeArr(res.data.Content);
+        if (!!this.value && this.value.length) {
+          let value = {}
+          this.options.map(item => {
+            if (item.code == this.value[0]) {
+              value = item
+            }
+          })
+          this.$emit("change", value)
+        }
+        if (!this.falg) {
+          this.changeList()
+        }
+      });
+    },
+    changeArr(arr) {
+      let data = [];
+      arr.map(item => {
+        if (item.content && item.content.length) {
+          return item.content.map(children => {
+            data.push({ code: children.code, facility: children.system });
+          });
+        }
+      });
+      return data;
+    },
+    //上级页面传入content
+    pushData(content) {
+      this.content = content
+      if (this.options.length) {
+        this.falg = true
+        this.changeList()
+      } else {
+        this.falg = false
+      }
+    },
+
+    //修改list
+    changeList() {
+      this.options.map(item => {
+        item.disabled = true
+        this.content.map(child => {
+          if (item.code == child) {
+            item.disabled = false
+          }
+        })
+      })
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#cascaderMap {
+  float: left;
+  margin-left: 10px;
+  .buildFloor {
+    color: #999999;
+    font-size: 14px;
+  }
+}
+</style>

+ 75 - 0
src/views/data_admin/buildGraphy/lib/detailsDia.vue

@@ -0,0 +1,75 @@
+<template>
+  <el-dialog
+    :title="title"
+    append-to-body
+    class="iframe"
+    :visible.sync="dialog.details"
+    width="500px"
+  >
+    <iframe
+      id="google_ads_frame2"
+      name="google_ads_frame2"
+      frameborder="0"
+      width="100%"
+      height="600px"
+      :src="iframeSrc"
+      marginwidth="0"
+      marginheight="0"
+      vspace="0"
+      hspace="0"
+      allowtransparency="true"
+      scrolling="no"
+      allowfullscreen="true"
+    ></iframe>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  props: {
+    iframeSrc: {
+      type: String,
+      default: ""
+    },
+    title: {
+      type: String,
+      default: "详情"
+    },
+    dialog: {
+      type: Object,
+      default: function () {
+        return {
+          details: false
+        }
+      }
+    },
+    setData: {
+      type: [Array, String],
+      default: function () {
+        return []
+      }
+    }
+  },
+  methods: {
+    setMess() {
+      this.$nextTick(_ => {
+        let iframe = document.getElementById("google_ads_frame2")
+        iframe.onload = () => {
+          iframe.contentWindow.postMessage(this.setData, "*")
+        }
+      })
+    }
+  },
+  watch: {
+    dialog: {
+      deep: true,
+      handler: function () {
+        if (this.dialog.details) {
+          this.setMess()
+        }
+      }
+    }
+  }
+}
+</script>
+

+ 119 - 0
src/views/data_admin/buildGraphy/lib/floorCascader.vue

@@ -0,0 +1,119 @@
+<template>
+  <div id="buildFloor">
+    <span class="buildFloor">所属建筑楼层:</span>
+    <el-cascader
+      placeholder="请选择建筑楼层"
+      :options="options"
+      v-model="value"
+      filterable
+      size="small"
+      :style="isWidth ? '' : 'width:160px;'"
+      @change="changeCascader"
+    ></el-cascader>
+  </div>
+</template>
+<script>
+
+import { getSpaceFloor } from '@/api/request'
+
+export default {
+  props: {
+    isWidth: {
+      type: Boolean,
+      default: true
+    },
+    type: {
+      type: String,
+      default: "yes"
+    }
+  },
+  data() {
+    return {
+      options: [
+      ],
+      param: {
+        ProjId: this.$route.query.projId,
+        secret: this.$route.query.secret
+      },
+      value: ['all']
+    };
+  },
+  created() {
+    this.getData()
+  },
+  mounted() { },
+  methods: {
+    //获取数据
+    getData() {
+      getSpaceFloor(this.param).then(res => {
+        if (res.data.Result == 'success') {
+          let data = this.changeArr(res.data.Content)
+          data.unshift({
+            value: "all",
+            label: "全部"
+          }, {
+              value: "noKnow",
+              label: "未明确建筑的设备"
+            })
+          data.map(item => {
+            if (!!item.children) {
+              item.children.unshift({
+                value: 'noKnow',
+                label: "未明确楼层的设备"
+              })
+              item.children.unshift({
+                value: "all",
+                label: "全部"
+              })
+            }
+            return item
+          })
+          this.options = data
+        } else {
+          this.$message.error(res.data.ResultMsg)
+        }
+      }).catch(() => {
+        this.$message.error("请求出错")
+      })
+    },
+    //将数组转换成optiosn格式
+    changeArr(arr) {
+      return arr.map(item => {
+        if (item.floors && item.floors.length && this.type == "yes") {
+          return {
+            value: item.id,
+            label: item.infos.BuildLocalName,
+            children: item.floors.map(i => {
+              return {
+                value: i.id,
+                label: i.infos.FloorLocalName,
+              }
+            })
+          }
+        } else {
+          return {
+            value: item.id,
+            label: item.infos.BuildLocalName,
+            children: null,
+            isChilren: 1,
+          }
+        }
+      })
+    },
+
+    //改变item
+    changeCascader(value) {
+      this.$emit("change", value)
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#buildFloor {
+  float: left;
+  .buildFloor {
+    color: #999999;
+    font-size: 14px;
+  }
+}
+</style>

+ 315 - 0
src/views/data_admin/buildGraphy/lib/formInput.vue

@@ -0,0 +1,315 @@
+<!--
+A1	手工填写-单个-数字-无单位
+A2	手工填写-单个-数字-有单位
+A3	手工填写-多个-数字-无单位
+A4	手工填写-多个-数字-有单位
+A5	手工填写-单个-数字范围-无单位
+A6	手工填写-单个-数字范围-有单位
+A7	手工填写-多个-数字范围-无单位
+A8	手工填写-多个-数字范围-有单位
+B1	手工填写-单个-文本
+B2	手工填写-多个-文本
+C1	手工填写-单个-日期时间值
+C2	手工填写-单个-日期时间段
+C3	手工填写-多个-日期时间值
+C4	手工填写-多个-日期时间段
+C5	手工填写-单个-日期值
+C6	手工填写-单个-日期段
+C7	手工填写-多个-日期值
+C8	手工填写-多个-日期段
+C9	手工填写-单个-时间值
+C10	手工填写-单个-时间段
+C11	手工填写-多个-时间值
+C12	手工填写-多个-时间段
+D1	字典选择-单个-单选
+D2	字典选择-单个-多选
+D3	字典选择-多个-单选
+D4	字典选择-多个-多选
+E1	字典布尔选择-单个
+E2	字典布尔选择-多个
+F1	上传-单个文件 -->
+
+<template>
+  <el-form
+    :label-position="'right'"
+    :labelWidth="width + 'px'"
+    :model="formLabelAlign"
+    ref="form"
+    @submit.native.prevent
+  >
+    <el-form-item :label="label" :rules="isRule ? { required: true, message: '不能为空'} : {}">
+      <!-- 普通输入类型 -->
+      <el-input
+        size="small"
+        v-if="!isShow && (type == 'default' || type == 'B1')"
+        v-model="formLabelAlign.name"
+        style="width: 9rem;"
+        @change="onSubmit"
+        @keyup.enter.native="onSubmit"
+      >
+        <template slot="append" v-if="unit">{{unit}}</template>
+      </el-input>
+      <el-input
+        type="number"
+        v-if="!isShow && (type == 'A1' || type == 'A2')"
+        v-model="formLabelAlign.name"
+        style="width: 9rem;"
+        @change="onSubmit"
+        @keyup.enter.native="onSubmit"
+      >
+        <template slot="append" v-if="unit">{{unit}}</template>
+      </el-input>
+      <!-- date类型 -->
+      <el-date-picker
+        v-if="!isShow && (type == 'year' || type == 'C5')"
+        v-model="formLabelAlign.name"
+        type="date"
+        value-format="yyyy-MM-dd"
+        @change="onSubmit"
+        :clearable="false"
+        placeholder="选择日期"
+      ></el-date-picker>
+      <!-- 级联选择 -->
+      <el-cascader
+        v-if="!isShow && (type == 'cascader' || type == 'D1')"
+        :options="typeArr"
+        v-model="formLabelAlign.name"
+        @change="onSubmit"
+        :props="props"
+      ></el-cascader>
+      <!-- 日期到分 -->
+      <el-date-picker
+        v-if="!isShow && type == 'C1'"
+        v-model="formLabelAlign.name"
+        type="datetime"
+        value-format="yyyy-MM-dd HH:MM"
+        @change="onSubmit"
+        :clearable="false"
+        placeholder="选择日期"
+      ></el-date-picker>
+      <!-- 输入文本框 -->
+      <el-input
+        v-if="!isShow && type == 'B2'"
+        type="textarea"
+        :rows="2"
+        @change="onSubmit"
+        @keyup.enter.native="onSubmit"
+        placeholder="请输入内容"
+        v-model="formLabelAlign.name"
+      ></el-input>
+      <!-- 日期 -->
+      <el-date-picker
+        v-if="!isShow && type == 'C6'"
+        v-model="formLabelAlign.name"
+        type="datetimerange"
+        range-separator="至"
+        start-placeholder="开始日期"
+        end-placeholder="结束日期"
+        value-format="yyyy-MM-dd HH:MM"
+        @change="onSubmit"
+        :clearable="false"
+        placeholder="选择日期"
+      ></el-date-picker>
+      <!-- 点击确定 -->
+      <i
+        v-if="!isShow  && (type == 'default' || type == 'B1')"
+        class="el-input__icon el-icon-check hover"
+        @click="onSubmit"
+      ></i>
+      <!-- 显示基本内容 -->
+      <span v-if="isShow" @click="changeItem" class="hover">
+        {{ filterArr(formLabelAlign.name) }} {{unit}}
+        <i class="el-icon-edit" v-if="type != 'X'"></i>
+      </span>
+      <slot name="mess"></slot>
+    </el-form-item>
+  </el-form>
+</template>
+
+<script>
+export default {
+  name: "ownerInput",
+  props: {
+    type: {
+      type: String,
+      default: "default"
+    }, //类型
+    value: [String, Number, Array], //value值
+    label: String, //label值,从父级传入
+    isRule: Boolean, //是否需要规则
+    keys: [String, Number], //
+    typeArr: [Array, String], //当其为级联或者下拉时传入
+    unit: {
+      //单位
+      type: String,
+      default: ""
+    },
+    width: {
+      type: Number,
+      default: 100
+    }
+  },
+
+  data() {
+    return {
+      formLabelAlign: {
+        name: ""
+      },
+      key: "",
+      isShow: true,
+      props: {
+        label: "name",
+        value: "code",
+        children: "content"
+      } //修改默认数据格式
+    };
+  },
+
+  methods: {
+    //点击确定或者url
+    onSubmit() {
+      if (this.formLabelAlign.name == "" || this.formLabelAlign.name == []) {
+        this.$message.error("请确定值不为空");
+      } else {
+        this.isShow = true;
+        if (this.type == 'cascader' || this.type == 'D1') {
+          let data = this.formLabelAlign.name
+          this.$emit("change", data[data.length - 1], this.keys);
+        } else {
+          this.$emit("change", this.formLabelAlign.name, this.keys);
+        }
+      }
+    },
+
+    //点击文案出现输入
+    changeItem() {
+      if (this.type == "X") {
+        this.$message('该信息点不支持编辑')
+        return;
+      } else {
+        this.isShow = false;
+      }
+    },
+
+    //对数组中的空数组去除
+    toMyNeed(arr) {
+      return arr.map(res => {
+        let param = {};
+        if (res.content && res.content.length != 0) {
+          param.content = this.toMyNeed(res.content);
+        }
+        param.name = res.name;
+        param.code = res.code;
+        return param;
+      });
+    },
+
+    //获取级联选中的值
+    getCascaderObj(val, opt) {
+      let data = this.getMyVal(val, opt, 'name')
+      data.length > 1 ? data = data.join('/') : data = data.join('')
+      return data
+    },
+
+    getMyVal(val, content, code) {
+      let data = []
+      if (content && content.length) {
+        for (let i = 0; i < content.length; i++) {
+          if (content[i].code == val) {
+            data.push(content[i][code])
+            break
+          } else {
+            if (content[i].content && content.length) {
+              for (let j = 0; j < content[i].content.length; j++) {
+                if (content[i].content[j].code == val) {
+                  data.push(content[i][code])
+                  data.push(content[i].content[j][code])
+                  break
+                } else {
+                  if (content[i].content[j].content && content[i].content[j].content.length) {
+                    for (let k = 0; k < content[i].content[j].content.length; k++) {
+                      if (content[i].content[j].content[k].code == val) {
+                        data.push(content[i][code])
+                        data.push(content[i].content[j][code])
+                        data.push(content[i].content[j].content[k][code])
+                        break
+                      } else {
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      if (!data.length) {
+        data = null
+      }
+      return data
+    },
+
+    getMap(val, opt) {
+      return opt.map(function (value, index, array) {
+        for (var itm of opt) {
+          if (itm.code == value.code) {
+            opt = itm.content;
+            return itm;
+          }
+        }
+        return null;
+      });
+    },
+
+    //数组过滤
+    filterArr(val) {
+      let value = ""; //最后输出的文案
+      let isNeedType = this.type == 'cascader' || this.type == 'D1'
+      if (this.type == 'C6') {
+        value = value != "" ? val[0] + '至' + val[1] : "--"
+      } else if (this.type == 'cascader' || this.type == 'D1') {
+        if (val && val.length) {
+          value = this.getCascaderObj(val[val.length - 1], this.typeArr, 'name') || "--";
+        }
+      } else {
+        value = val || "--";
+      }
+      return value;
+    }
+  },
+
+  created() {
+    if (typeof (this.typeArr) == Object) {
+      this.typeArr = this.toMyNeed(this.typeArr)
+    }
+    if (this.type == 'cascader' || this.type == 'D1') {
+      if (this.value == '' || this.value == undefined) {
+        this.formLabelAlign.name = []
+      } else {
+        this.formLabelAlign.name = this.getMyVal(this.value, this.typeArr, 'code');
+      }
+    } else {
+      this.formLabelAlign.name = this.value;
+    }
+    this.key = this.label;
+  },
+
+  watch: {
+    label() { }
+  }
+};
+</script>
+
+<style lang="less">
+.hover:hover {
+  cursor: pointer;
+  color: #409eff;
+}
+input::-webkit-outer-spin-button,
+input::-webkit-inner-spin-button {
+  -webkit-appearance: none;
+}
+input[type="number"] {
+  -moz-appearance: textfield;
+}
+</style>

+ 180 - 0
src/views/data_admin/buildGraphy/lib/lookImages.vue

@@ -0,0 +1,180 @@
+<!--
+    上传图片的弹窗
+-->
+
+<template>
+  <el-dialog title="上传图片" :visible.sync="dialog.lookPic" v-if="dialog.lookPic" width="600px">
+    <div style="max-height:700px;overflow-y:auto;">
+      <el-tabs type="border-card">
+        <el-tab-pane>
+          <span slot="label">图片</span>
+          <div style="width:500px;max-height:500px;">
+            <div v-if="picArrs.length">
+              <iframe
+                id="google_ads_frame3"
+                name="google_ads_frame3"
+                frameborder="0"
+                width="100%"
+                height="500px"
+                :src="iframeSrc"
+                marginwidth="0"
+                marginheight="0"
+                vspace="0"
+                hspace="0"
+                allowtransparency="true"
+                scrolling="no"
+                allowfullscreen="true"
+              ></iframe>
+            </div>
+            <div v-if="!picArrs.length">暂无图片</div>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane v-if="videoArr.length">
+          <span slot="label">视频</span>
+          <div style="width:500px;">
+            <div
+              v-for=" item in videoArr "
+              style="width:200px;height:200px;float:left;margin: 5px;"
+            >
+              <video
+                width="100%"
+                height="100%"
+                :src="
+                '/img/image-service/common/image_get?systemId=dataPlatform&key='+item.key"
+                controls
+                :poster="'img/image-service/common/image_get?systemId=dataPlatform&key='+ item.key +'&width=200'"
+              ></video>
+            </div>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+  </el-dialog>
+</template>
+<script>
+import uploadImgs from "@/components/lib/uploadImgsName";
+import tools from "@/assets/js/tools"
+export default {
+  components: {
+    uploadImgs
+  },
+  props: {
+    dialog: {
+      type: Object,
+      default: function () {
+        return {
+          lookPic: true
+        };
+      }
+    },
+    keysArr: {
+      type: Array,
+      default: function () {
+        return []
+      }
+    },
+    read: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      picArrs: [],
+      panoramaArr: [],
+      videoArr: [],
+      videoPicArr: [],
+      changeKeys: [],
+      iframeSrc: ""
+    };
+  },
+  created() { },
+  mounted() { },
+  methods: {
+    imageItem(images) {
+      this.picArrs = images
+      this.change()
+    },
+
+    panoramaItem(images) {
+      this.panoramaArr = images
+      this.change()
+    },
+
+    videoItem(videos, pe, pics) {
+      this.videoArr = videos
+      this.videoPicArr = pics
+      this.change()
+    },
+
+    change() {
+      //   let picsArr = this.getArr(this.picArrs, "设备图片", "image")
+      //   let videos = this.getArr(this.videoArr, "视频", "video")
+      //   let videoPics = this.getArr(this.videoPicArr, "视频资料", "image_video")
+      //   let panoramas = this.getArr(this.panoramaArr, "全景照片", "panorama")
+      let picsArr = this.picArrs
+      let videos = this.videoArr
+      let videoPics = this.videoPicArr
+      let panoramas = this.panoramaArr
+      this.changeKeys = picsArr.concat(videos).concat(videoPics).concat(panoramas)
+      console.log(this.changeKeys)
+      this.$emit("change", this.changeKeys)
+    },
+
+    getArr(arr, name, type) {
+      return arr.map(item => {
+        return { "systemId": "dataPlatform", "name": name, "type": type, "key": item }
+      })
+    },
+
+    //将父组件传来的数据进行分组
+    fatherTochild() {
+      this.panoramaArr = []
+      this.videoArr = []
+      this.videoPicArr = []
+      this.picArrs = []
+      if (this.keysArr instanceof Array) {
+        this.keysArr.map(item => {
+          if (item.type == 'panorama') {
+            this.panoramaArr.push(item)
+          } else if (item.type == "video") {
+            this.videoArr.push(item)
+          } else if (item.type == 'image_video') {
+            this.videoPicArr.push(item)
+          } else {
+            this.picArrs.push(item)
+          }
+        })
+      } else {
+        this.panoramaArr = []
+        this.videoArr = []
+        this.videoPicArr = []
+        this.picArrs = []
+      }
+      if (this.picArrs.length) {
+        this.$nextTick(_ => {
+          this.iframeSrc = process.env.BASE_URL + ":8890/photo-View.html"
+          let iframe = document.getElementById("google_ads_frame3")
+          console.log(iframe)
+          iframe.onload = () => {
+            console.log("onload")
+            iframe.contentWindow.postMessage(this.picArrs, "*")
+          }
+        })
+      }
+    }
+  },
+  watch: {
+    dialog: {
+      deep: true,
+      handler: function () {
+        if (this.dialog.lookPic) {
+          this.fatherTochild()
+        }
+      }
+    }
+  }
+};
+</script>
+<style>
+</style>

+ 58 - 0
src/views/data_admin/buildGraphy/lib/myPagination.vue

@@ -0,0 +1,58 @@
+<!--
+    props:{
+        size: 当前页的页数,
+        sizes: 下拉的条数,
+        total: 总条数,
+        currentPage: 当前页
+    }
+    @change 发生改变
+-->
+<template>
+    <div class="block">
+        <el-pagination
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+        :current-page.sync="page.currentPage"
+        :page-sizes="page.sizes"
+        :page-size="page.size"
+        :small="true"
+        :layout=" isSmall ? 'total, sizes, prev, pager, next, jumper' : 'prev, pager, next'"
+        :total="page.total">
+        </el-pagination>
+    </div>
+</template>
+<script>
+export default {
+  name: "pagination",
+  props: {
+    page: {
+      type: Object
+    },
+    isSmall:{
+      type:Boolean,
+      default: true
+    }
+  },
+  methods: {
+    //当前条数发生改变
+    handleSizeChange(val) {
+      this.page.size = val;
+      this.change()
+    },
+    //当前页发生改变
+    handleCurrentChange(val) {
+      this.page.currentPage = val;
+      this.change()
+    },
+    //发生改变
+    change() {
+      this.$emit("change");
+    }
+  }
+};
+</script>
+<style>
+.block{
+  margin-top: 5px;
+}
+</style>

+ 57 - 0
src/views/data_admin/buildGraphy/lib/qrcode.vue

@@ -0,0 +1,57 @@
+<template>
+  <el-dialog
+    title="二维码"
+    v-if="dialog.qrcode"
+    custom-class="custom-dialog"
+    :visible.sync="dialog.qrcode"
+    width="300px"
+  >
+    <div>
+      <div id="qrcode">
+        <img
+          style="width:200px;height:200px;margin:auto;display:block;"
+          :src="'img/image-service/common/file_get/'+ qrcodeUrl +'?systemId=dataPlatform'"
+          alt="二维码"
+        >
+      </div>
+    </div>
+  </el-dialog>
+</template>
+<script>
+import { qrcanvas } from "qrcanvas";
+export default {
+  props: {
+    dialog: {
+      type: Object,
+      default: function () {
+        return {
+          qrcode: false
+        };
+      }
+    },
+    qrcodeUrl: {
+      default: ""
+    }
+  },
+  data() {
+    return {};
+  },
+  created() { },
+  mounted() {
+  },
+  methods: {
+    // getCanvas(id) {
+    //     let canvas = qrcanvas({
+    //         cellSize: 8,
+    //         data: 'http://service.sagacloud.cn/qrcode/' + 'Pea3a31168a30d4056acda3a56e557940b'
+    //     });
+    //     canvas.style.margin = "auto"
+    //     canvas.style.display = "block"
+    //     this.$nextTick(() => {
+    //         document.getElementById("qrcode").innerHTML = null;
+    //         document.getElementById("qrcode").appendChild(canvas);
+    //     });
+    // }
+  }
+};
+</script>

+ 207 - 0
src/views/data_admin/buildGraphy/lib/uploadFiles.vue

@@ -0,0 +1,207 @@
+<!--
+  上传组件
+  type: 类型,默认image
+  identify: key值,通过val获取
+  disabled: 是否可用
+  index: 父组件的下标
+  imageIndex: 图片下标
+  isShow: 图片的显示
+ -->
+<template>
+  <div id="saga-upload">
+    <div id="uploadFile">
+      <div v-if="item && filesArr.length" v-for="(item,index) in filesArr">
+        <el-button type="text" @click="download(item)">{{delFile(item)}}</el-button>
+        <i
+          v-if="!readOnly"
+          class="el-icon-close delete-icon"
+          style="margin-left:10px; cursor:pointer"
+          @click="deleteFile(index,item)"
+        ></i>
+      </div>
+      <el-upload
+        v-if="filesArr.length < max"
+        class="upload-file"
+        action
+        :http-request="uploadAndSubmit"
+        :show-file-list="false"
+        drag
+      >
+        <el-button size="small" type="primary" v-if="!readOnly">点击上传</el-button>
+        <div slot="tip" class="el-upload__tip" v-if="!readOnly">请上传文件</div>
+      </el-upload>
+    </div>
+  </div>
+</template>
+
+<script>
+import tools from "@/assets/js/tools";
+export default {
+  props: {
+    keysArr: {
+      type: [Array, String],
+      default: function () {
+        return []
+      }
+    },
+    readOnly: {
+      type: Boolean,
+      default: false
+    },
+    max: {
+      type: [Number, String],
+      default: 6
+    },
+    defined: null
+  },
+  data() {
+    return {
+      filesArr: []
+    };
+  },
+  created() {
+    let type = typeof (this.keysArr)
+    this.fileFalg()
+  },
+  methods: {
+    //判断是否为空
+    fileFalg() {
+      let type = typeof (this.keysArr)
+      console.log(this.keysArr, "keysAee")
+      if (type == 'string') {
+        this.filesArr = [this.keysArr]
+      } else {
+        this.filesArr = tools.deepCopy(this.keysArr)
+      }
+
+      if (!this.keysArr) {
+        this.filesArr = []
+      }
+    },
+    //处理地址
+    delFile(name) {
+      console.log(name, "name")
+      return name.length > 20 ? name.substring(0, 20) + "..." : ""
+    },
+
+    resetFile() {
+      this.filesArr = []
+    },
+
+
+    //点击下载
+    download(key) {
+      console.log(key)
+      window.open("/img/image-service/common/file_get/" + key + "?systemId=dataPlatform")
+    },
+
+    //删除图片
+    deleteFile(i, key) {
+      this.filesArr.splice(i, 1);
+      this.$emit("change", this.filesArr, this.defined);
+    },
+
+    //上传
+    uploadAndSubmit(item) {
+      // var form = document.forms["demoForm"];
+
+      // if (form["file"].files.length > 0) {
+      // 寻找表单域中的 <input type="file" ... /> 标签
+      // var file = form["file"].files[0];
+
+      let file = item.file;
+      // try sending
+      let reader = new FileReader();
+
+      let vm = this;
+
+      let fileType = file.name.split(".");
+      let type = fileType[fileType.length - 1];
+      let key = "&key=" + fileType[0] + file.uid + "." + type
+
+      reader.onloadstart = function () {
+        // 这个事件在读取开始时触发
+      };
+      reader.onprogress = function (p) {
+        // 这个事件在读取进行中定时触发
+      };
+
+      reader.onload = function () {
+        // 这个事件在读取成功结束后触发
+      };
+      reader.onloadend = function () {
+        // 这个事件在读取结束后,无论成功或者失败都会触发
+        if (reader.error) {
+        } else {
+          // document.getElementById("bytesRead").textContent = file.size;
+          // 构造 XMLHttpRequest 对象,发送文件 Binary 数据
+          var xhr = new XMLHttpRequest();
+          xhr.open(
+            /* method */
+            "POST",
+            /* target url */
+            "/img/image-service/common/file_upload?systemId=dataPlatform&secret=9e0891a7a8c8e885&overwrite=true" + key
+            /*, async, default to true */
+          );
+          //xhr.overrideMimeType("application/octet-stream");
+          xhr.send(reader.result);
+          xhr.onreadystatechange = function () {
+            if (xhr.readyState == 4) {
+              console.log(xhr)
+              if (xhr.status == 200) {
+                vm.filesArr.push(
+                  key.split("=")[1]
+                );
+                console.log(vm.filesArr)
+                vm.$emit("change", vm.filesArr, vm.defined);
+              } else {
+                this.$message.error(res.data.ResultMsg)
+              }
+            }
+          };
+        }
+      };
+      reader.readAsArrayBuffer(file);
+    }
+  },
+  watch: {
+    keysArr: function (val) {
+      this.fileFalg()
+    }
+  }
+};
+</script>
+
+<style lang="less">
+#saga-upload {
+  .dill-image {
+    position: absolute;
+    right: 0px;
+    top: 0px;
+    font-size: 20px;
+  }
+  .el-upload-dragger {
+    width: 180px;
+    height: 180px;
+  }
+  img {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+  }
+  #uploadFile {
+    .upload-file {
+      overflow: hidden;
+      .el-upload-dragger {
+        width: inherit;
+        height: inherit;
+        border: none;
+      }
+    }
+  }
+}
+</style>

+ 109 - 0
src/views/data_admin/buildGraphy/lib/uploadImg.vue

@@ -0,0 +1,109 @@
+<template>
+    <el-upload
+    class="avatar-uploader"
+    :http-request="uploadAndSubmit"
+    :show-file-list="false"
+    accept="image/*"
+    action=""
+    drag
+    style="position: relation"
+    >
+        <i class="el-icon-plus avatar-uploader-icon"></i>
+    </el-upload>
+</template>
+
+<script>
+export default {
+  props: {
+    keyName: {
+      type: String,
+      default: ""
+    }
+  },
+  methods: {
+    uploadAndSubmit(item) {
+      // var form = document.forms["demoForm"];
+
+      // if (form["file"].files.length > 0) {
+      // 寻找表单域中的 <input type="file" ... /> 标签
+      // var file = form["file"].files[0];
+
+      let file = item.file;
+      // try sending
+      let reader = new FileReader();
+
+      let vm = this;
+
+      let fileType = file.name.split('.')
+      let type = fileType[fileType.length -1]
+
+      reader.onloadstart = function() {
+        // 这个事件在读取开始时触发
+      };
+      reader.onprogress = function(p) {
+        // 这个事件在读取进行中定时触发
+      };
+
+      reader.onload = function() {
+        // 这个事件在读取成功结束后触发
+      };
+
+      reader.onloadend = function() {
+        // 这个事件在读取结束后,无论成功或者失败都会触发
+        if (reader.error) {
+        } else {
+          // document.getElementById("bytesRead").textContent = file.size;
+          // 构造 XMLHttpRequest 对象,发送文件 Binary 数据
+          var xhr = new XMLHttpRequest();
+          xhr.open(
+            /* method */ "POST",
+            /* target url */
+            "/img/image-service/common/image_upload?systemId=dataPlatform&secret=9e0891a7a8c8e885&overwrite=true&key=" +
+              file.uid + '.' + type
+            /*, async, default to true */
+          );
+          //xhr.overrideMimeType("application/octet-stream");
+          xhr.send(reader.result);
+          xhr.onreadystatechange = function() {
+            if (xhr.readyState == 4) {
+              if (xhr.status == 200) {
+                vm.$emit("getKey", file.uid + '.' + type, vm.keyName);
+              }
+            }
+          };
+        }
+      };
+      reader.readAsArrayBuffer(file);
+    }
+  }
+};
+</script>
+
+<style lang="less">
+.point-pic {
+  .avatar-uploader {
+    height: 180px;
+    width: 180px;
+    overflow: hidden;
+    .el-upload {
+      width: 100%;
+      height: 100%;
+      .el-upload-dragger{
+        width: 100%;
+        height: 100%;
+        .el-icon-plus{
+          display: block;
+          width: 20px;
+          height: 20px;
+          font-size: 20px;
+          margin: 80px;
+        }
+      }
+    }
+  }
+}
+.el-dialog__body{
+  max-height: 600px;
+  overflow-y: auto;
+}
+</style>

+ 321 - 0
src/views/data_admin/buildGraphy/lib/uploadImgs.vue

@@ -0,0 +1,321 @@
+<!--
+    @param keysArr 承接数组
+    @param readOnly  删除按钮是否显示,上传是否显示
+    @param max     上传最大数限制
+    @click change  承接数组发生变化时触发函数
+-->
+<template>
+  <div id="sagaUploads">
+    <div class="saga-upload-images">
+      <div v-if="type != 'video'" class="point-image" v-for="(item,index) in imagesArr">
+        <i v-if="!readOnly" class="el-icon-delete" @click="delImage(index,item)"></i>
+        <img :src="imageGetUrl + '&key=' +item" alt v-load>
+      </div>
+      <div v-if="type == 'video'" class="point-image" v-for="(item,index) in imagesArr">
+        <i v-if="!readOnly" class="el-icon-delete" @click="delImage(index,item)"></i>
+        <video
+          width="100%"
+          height="100%;"
+          :src="imageGetUrl + '&key=' +item"
+          controls="controls"
+        >您的浏览器不支持 video 标签。</video>
+      </div>
+      <div v-if="!readOnly && imagesArr.length < max" style="float:left;">
+        <el-upload
+          class="avatar-uploader"
+          :http-request="uploadAndSubmit"
+          :show-file-list="false"
+          :accept="accept"
+          action
+          drag
+          style="position: relation"
+        >
+          <i class="el-icon-plus avatar-uploader-icon"></i>
+        </el-upload>
+        <video style="display:none;" id="video" controls/>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import tools from "@/assets/js/tools";
+export default {
+  props: {
+    keysArr: {
+      type: [Array, String]
+    },
+    readOnly: {
+      type: Boolean,
+      default: false
+    },
+    max: {
+      type: [Number, String],
+      default: 6
+    },
+    accept: {
+      type: String,
+      default: "image/*"
+    },
+    type: {
+      type: String,
+      default: "image"
+    },
+    defined: null,
+    videoPicArr: {
+      type: Array,
+      default: function () {
+        return []
+      }
+    }
+  },
+  data() {
+    return {
+      baseUrl: "",
+      imageGetUrl: "/img/image-service/common/image_get?systemId=dataPlatform",
+      imageUploadUrl: "/img/image-service/common/image_upload?systemId=dataPlatform&secret=9e0891a7a8c8e885&overwrite=true",
+      imagesArr: []
+    };
+  },
+  created() {
+    this.imageFalg();
+  },
+  methods: {
+    //判断是否为空
+    imageFalg() {
+      let type = typeof this.keysArr;
+      console.log(this.keysArr)
+      if (type == "string") {
+        this.imagesArr = [this.keysArr];
+      } else {
+        this.imagesArr = tools.deepCopy(this.keysArr);
+      }
+
+      if (!this.keysArr) {
+        this.imagesArr = [];
+      }
+    },
+
+    //删除图片
+    delImage(i, key) {
+      if (this.type == "video") {
+        this.videoPicArr = this.videoPicArr.map(item => {
+          if (item.substring(0, item.length - 3) == this.imagesArr[i].substring(0, this.imagesArr[i].length - 3)) {
+            return undefined
+          } else {
+            return item
+          }
+        }).filter(p => p)
+      }
+      this.imagesArr.splice(i, 1);
+      this.$emit("change", this.imagesArr, this.defined, this.videoPicArr);
+    },
+
+    //上传
+    uploadAndSubmit(item, key) {
+      // var form = document.forms["demoForm"];
+
+      // if (form["file"].files.length > 0) {
+      // 寻找表单域中的 <input type="file" ... /> 标签
+      // var file = form["file"].files[0];
+
+      console.log("lalala", item)
+      let file = item.file;
+      // try sending
+      let reader = new FileReader();
+
+      let vm = this;
+
+      let fileType = file.name.split(".");
+      let type = fileType[fileType.length - 1];
+
+      let uploadKey = file.uid
+      if (!!key) {
+        uploadKey = key
+      }
+
+      reader.onloadstart = function () {
+        // 这个事件在读取开始时触发
+      };
+      reader.onprogress = function (p) {
+        // 这个事件在读取进行中定时触发
+      };
+
+      reader.onload = function () {
+        // 这个事件在读取成功结束后触发
+      };
+      reader.onloadend = function () {
+        // 这个事件在读取结束后,无论成功或者失败都会触发
+        if (reader.error) {
+        } else {
+          // document.getElementById("bytesRead").textContent = file.size;
+          // 构造 XMLHttpRequest 对象,发送文件 Binary 数据
+          var xhr = new XMLHttpRequest();
+          xhr.open(
+            /* method */
+            "POST",
+            /* target url */
+            vm.imageUploadUrl + "&key=" + uploadKey + "." + type
+            /*, async, default to true */
+          );
+          //xhr.overrideMimeType("application/octet-stream");
+          xhr.send(reader.result);
+          xhr.onreadystatechange = function () {
+            if (xhr.readyState == 4) {
+              if (xhr.status == 200) {
+                if (vm.type == 'image') {
+                  vm.imagesArr.push(
+                    uploadKey + "." + type
+                  );
+                }
+                if (type == 'mp4') {
+                  vm.imagesArr.push(
+                    uploadKey + "." + type
+                  );
+                  vm.creatImg(vm.imageGetUrl + "&key=" + uploadKey + "." + type, uploadKey)
+                }
+                console.log(vm.type, type)
+                if (vm.type == "video" && type == "png") {
+                  console.log("触发时评上传图片回调")
+                  vm.videoPicArr.push(uploadKey + "." + type)
+                }
+                vm.$emit("change", vm.imagesArr, vm.defined, vm.videoPicArr);
+              }
+            }
+          };
+        }
+      };
+      reader.readAsArrayBuffer(file);
+    },
+    dataURLtoBlob: function (dataURI, type) {
+      var binary = atob(dataURI.split(',')[1]);
+      var array = [];
+      for (var i = 0; i < binary.length; i++) {
+        array.push(binary.charCodeAt(i));
+      }
+      return new Blob([new Uint8Array(array)], { type: type });
+    },
+
+    creatImg(reader, key) {
+      var videoDom = document.getElementById('video');
+      videoDom.src = reader;
+      let vm = this
+      videoDom.onloadeddata = function () {
+        // 这里可以打印视频时长
+        // 这里取得视频封面
+        var canvas = document.createElement('canvas');
+        canvas.width = 300;
+        canvas.height = 300 * this.videoHeight / this.videoWidth;
+        canvas.getContext('2d').drawImage(this, 0, 0, canvas.width, canvas.height);
+        //将canvas的base64位图片转换成图片png的file
+        var blob = vm.dataURLtoBlob(canvas.toDataURL('image/png'), "image/png")
+        //将其转换成file对象
+        var file = new File([blob], "video_image.png", { type: "image/png", lastModified: Date.now() })//blob转file
+        vm.uploadAndSubmit({ file: file }, key)
+      }
+    },
+  },
+  watch: {
+    keysArr: function (val) {
+      this.imageFalg();
+    }
+  },
+  //自定义指令
+  directives: {
+    load: function (el) {
+      let imgDom = document.createElement("img");
+      imgDom.style.position = "absolute";
+      imgDom.style.top = "-999px";
+      imgDom.style.opacity = 0;
+      imgDom.src = el.src;
+      el.src = "";
+      imgDom.onload = () => {
+        let width = imgDom.width;
+        let height = imgDom.height;
+        if (width > height) {
+          el.style.height = "100%";
+          el.style.width = "auto";
+          el.style.position = "absolute";
+          el.style.left = "50%";
+          el.style.top = "0";
+          el.style.transform = "translateX(-50%)";
+          el.style.webkitTransform = "translateX(-50%) translateY(0)";
+          el.style.MozTransform = "translateX(-50%) translateY(0)";
+          el.style.msTransform = "translateX(-50%) translateY(0)";
+          el.style.OTransform = "translateX(-50%) translateY(0)";
+        } else if (width < height) {
+          el.src = imgDom.src;
+          el.style.width = "100%";
+          el.style.height = "auto";
+          el.style.position = "absolute";
+          el.style.top = "50%";
+          el.style.left = "0";
+          el.style.transform = "translateY(-50%) translateX(0)";
+          el.style.webkitTransform = "translateY(-50%) translateX(0)";
+          el.style.MozTransform = "translateY(-50%) translateX(0)";
+          el.style.msTransform = "translateY(-50%) translateX(0)";
+          el.style.OTransform = "translateY(-50%) translateX(0)";
+        } else {
+          el.style.width = "100%";
+          el.style.height = "100%";
+          el.style.position = "absolute";
+          el.style.top = "0";
+          el.style.left = "0";
+          el.style.transform = "translateY(0) translateX(0)";
+          el.style.webkitTransform = "translateY(0) translateX(0)";
+          el.style.MozTransform = "translateY(0) translateX(0)";
+          el.style.msTransform = "translateY(0) translateX(0)";
+          el.style.OTransform = "translateY(0) translateX(0)";
+        }
+        el.src = imgDom.src;
+      };
+    }
+  }
+};
+</script>
+<style lang="less">
+#sagaUploads {
+  overflow: hidden;
+  .avatar-uploader {
+    height: 180px;
+    width: 180px;
+    overflow: hidden;
+    .el-upload {
+      width: 180px;
+      height: 180px;
+      .el-upload-dragger {
+        width: 180px;
+        height: 180px;
+        .el-icon-plus {
+          display: block;
+          width: 20px;
+          height: 20px;
+          font-size: 20px;
+          margin: 80px;
+        }
+      }
+    }
+  }
+  .point-image {
+    width: 180px;
+    height: 180px;
+    float: left;
+    position: relative;
+    margin-right: 10px;
+    margin-bottom: 10px;
+    border: 1px solid #ccc;
+    overflow: hidden;
+    image {
+      z-index: 11;
+    }
+    i {
+      position: absolute;
+      bottom: 10px;
+      right: 10px;
+      background-color: #fff;
+      padding: 5px;
+      cursor: pointer;
+      z-index: 66;
+    }
+  }
+}
+</style>

+ 365 - 0
src/views/data_admin/buildGraphy/lib/uploadImgsName.vue

@@ -0,0 +1,365 @@
+<!--
+    @param keysArr 承接数组
+    @param readOnly  删除按钮是否显示,上传是否显示
+    @param max     上传最大数限制
+    @click change  承接数组发生变化时触发函数
+-->
+<template>
+  <div id="sagaUploads">
+    <div class="saga-upload-images">
+      <div v-if="type != 'video'" class="point-view" v-for="(item,index) in imagesArr">
+        <div class="point-image">
+          <i v-if="!readOnly" class="el-icon-delete" @click="delImage(index,item)"></i>
+          <img @click="lookImg" :src="imageGetUrl + '&key=' +item.key" alt v-load>
+        </div>
+        <form-input :label="''" @change="getName" :keys="index" :value="item.name" :width="10"></form-input>
+      </div>
+      <div v-if="type == 'video'" class="point-view" v-for="(item,index) in imagesArr">
+        <div class="point-image">
+          <i v-if="!readOnly" class="el-icon-delete" @click="delImage(index,item)"></i>
+          <video
+            width="100%"
+            height="100%;"
+            :src="imageGetUrl + '&key=' +item.key"
+            controls="controls"
+          >您的浏览器不支持 video 标签。</video>
+        </div>
+        <form-input :label="''" @change="getName" :keys="index" :value="item.name" :width="10"></form-input>
+      </div>
+      <div v-if="!readOnly && imagesArr.length < max" style="float:left;">
+        <el-upload
+          class="avatar-uploader"
+          :http-request="uploadAndSubmit"
+          :show-file-list="false"
+          :accept="accept"
+          action
+          drag
+          style="position: relation"
+        >
+          <i class="el-icon-plus avatar-uploader-icon"></i>
+        </el-upload>
+        <video style="display:none;" id="video" controls/>
+      </div>
+    </div>
+    <details-dialog :title="'图片'" :iframeSrc="iframeSrc" :dialog="dialog" :setData="imagesArr"></details-dialog>
+  </div>
+</template>
+<script>
+import tools from "@/assets/js/tools";
+import formInput from "@/components/lib/formInput"
+import detailsDialog from "@/components/lib/detailsDia"
+
+export default {
+  components: {
+    formInput,
+    detailsDialog
+  },
+  props: {
+    keysArr: {
+      type: [Array, String]
+    },
+    readOnly: {
+      type: Boolean,
+      default: false
+    },
+    max: {
+      type: [Number, String],
+      default: 6
+    },
+    accept: {
+      type: String,
+      default: "image/*"
+    },
+    type: {
+      type: String,
+      default: "image"
+    },
+    defined: null,
+    videoPicArr: {
+      type: Array,
+      default: function () {
+        return []
+      }
+    }
+  },
+  data() {
+    return {
+      baseUrl: "",
+      imageGetUrl: "/img/image-service/common/image_get?systemId=dataPlatform",
+      imageUploadUrl: "/img/image-service/common/image_upload?systemId=dataPlatform&secret=9e0891a7a8c8e885&overwrite=true",
+      imagesArr: [],
+      iframeSrc: "",
+      dialog: {
+        details: false
+      }
+    };
+  },
+  created() {
+    this.imageFalg();
+  },
+  methods: {
+    getName(name, index) {
+      console.log(this.imagesArr, "imagesArr")
+      this.imagesArr[index].name = name
+      this.$emit("change", this.imagesArr, this.defined, this.videoPicArr);
+    },
+    //判断是否为空
+    imageFalg() {
+      let type = typeof this.keysArr;
+      if (type == "string") {
+        this.imagesArr = [this.keysArr];
+      } else {
+        this.imagesArr = tools.copyArr(this.keysArr);
+      }
+
+      if (!this.keysArr) {
+        this.imagesArr = [];
+      }
+    },
+
+    //查看图片
+    lookImg() {
+      this.dialog.details = true
+      this.iframeSrc = process.env.BASE_URL + ":8890/photo-View.html"
+    },
+
+    //删除图片
+    delImage(i, key) {
+      if (this.type == "video") {
+        this.videoPicArr = this.videoPicArr.map(item => {
+          if (item.key.substring(0, item.length - 3) == this.imagesArr[i].key.substring(0, this.imagesArr[i].length - 3)) {
+            return undefined
+          } else {
+            return item
+          }
+        }).filter(p => p)
+      }
+      this.imagesArr.splice(i, 1);
+      this.$emit("change", this.imagesArr, this.defined, this.videoPicArr);
+    },
+
+    //上传
+    uploadAndSubmit(item, key) {
+      // var form = document.forms["demoForm"];
+
+      // if (form["file"].files.length > 0) {
+      // 寻找表单域中的 <input type="file" ... /> 标签
+      // var file = form["file"].files[0];
+
+      console.log("lalala", item)
+      let file = item.file;
+      // try sending
+      let reader = new FileReader();
+
+      let vm = this;
+
+      let fileType = file.name.split(".");
+      let type = fileType[fileType.length - 1];
+
+      let uploadKey = file.uid
+      if (!!key) {
+        uploadKey = key
+      }
+
+      reader.onloadstart = function () {
+        // 这个事件在读取开始时触发
+      };
+      reader.onprogress = function (p) {
+        // 这个事件在读取进行中定时触发
+      };
+
+      reader.onload = function () {
+        // 这个事件在读取成功结束后触发
+      };
+      reader.onloadend = function () {
+        // 这个事件在读取结束后,无论成功或者失败都会触发
+        if (reader.error) {
+        } else {
+          // document.getElementById("bytesRead").textContent = file.size;
+          // 构造 XMLHttpRequest 对象,发送文件 Binary 数据
+          var xhr = new XMLHttpRequest();
+          xhr.open(
+            /* method */
+            "POST",
+            /* target url */
+            vm.imageUploadUrl + "&key=" + uploadKey + "." + type
+            /*, async, default to true */
+          );
+          //xhr.overrideMimeType("application/octet-stream");
+          xhr.send(reader.result);
+          xhr.onreadystatechange = function () {
+            if (xhr.readyState == 4) {
+              if (xhr.status == 200) {
+                if (vm.type == 'image') {
+                  vm.imagesArr.push(
+                    {
+                      name: uploadKey,
+                      key: uploadKey + "." + type,
+                      systemId: "dataPlatform",
+                      type: "image"
+                    }
+                  );
+                }
+                if (type == 'mp4') {
+                  vm.imagesArr.push({
+                    name: uploadKey,
+                    key: uploadKey + "." + type,
+                    systemId: "dataPlatform",
+                    type: "video"
+                  }
+                  );
+                  vm.creatImg(vm.imageGetUrl + "&key=" + uploadKey + "." + type, uploadKey)
+                }
+                if (vm.type == "video" && type == "png") {
+                  vm.videoPicArr.push({
+                    name: uploadKey,
+                    key: uploadKey + "." + type,
+                    systemId: "dataPlatform",
+                    type: "image_video"
+                  })
+                }
+                vm.$emit("change", vm.imagesArr, vm.defined, vm.videoPicArr);
+              }
+            }
+          };
+        }
+      };
+      reader.readAsArrayBuffer(file);
+    },
+    dataURLtoBlob(dataURI, type) {
+      var binary = atob(dataURI.split(',')[1]);
+      var array = [];
+      for (var i = 0; i < binary.length; i++) {
+        array.push(binary.charCodeAt(i));
+      }
+      return new Blob([new Uint8Array(array)], { type: type });
+    },
+
+    creatImg(reader, key) {
+      var videoDom = document.getElementById('video');
+      videoDom.src = reader;
+      let vm = this
+      videoDom.onloadeddata = function () {
+        // 这里可以打印视频时长
+        // 这里取得视频封面
+        var canvas = document.createElement('canvas');
+        canvas.width = 300;
+        canvas.height = 300 * this.videoHeight / this.videoWidth;
+        canvas.getContext('2d').drawImage(this, 0, 0, canvas.width, canvas.height);
+        //将canvas的base64位图片转换成图片png的file
+        var blob = vm.dataURLtoBlob(canvas.toDataURL('image/png'), "image/png")
+        //将其转换成file对象
+        var file = new File([blob], "video_image.png", { type: "image/png", lastModified: Date.now() })//blob转file
+        vm.uploadAndSubmit({ file: file }, key)
+      }
+    },
+  },
+  watch: {
+    keysArr: function (val) {
+      this.imageFalg();
+    }
+  },
+  //自定义指令
+  directives: {
+    load: function (el) {
+      let imgDom = document.createElement("img");
+      imgDom.style.position = "absolute";
+      imgDom.style.top = "-999px";
+      imgDom.style.opacity = 0;
+      imgDom.src = el.src;
+      el.src = "";
+      imgDom.onload = () => {
+        let width = imgDom.width;
+        let height = imgDom.height;
+        if (width > height) {
+          el.style.height = "100%";
+          el.style.width = "auto";
+          el.style.position = "absolute";
+          el.style.left = "50%";
+          el.style.top = "0";
+          el.style.transform = "translateX(-50%)";
+          el.style.webkitTransform = "translateX(-50%) translateY(0)";
+          el.style.MozTransform = "translateX(-50%) translateY(0)";
+          el.style.msTransform = "translateX(-50%) translateY(0)";
+          el.style.OTransform = "translateX(-50%) translateY(0)";
+        } else if (width < height) {
+          el.src = imgDom.src;
+          el.style.width = "100%";
+          el.style.height = "auto";
+          el.style.position = "absolute";
+          el.style.top = "50%";
+          el.style.left = "0";
+          el.style.transform = "translateY(-50%) translateX(0)";
+          el.style.webkitTransform = "translateY(-50%) translateX(0)";
+          el.style.MozTransform = "translateY(-50%) translateX(0)";
+          el.style.msTransform = "translateY(-50%) translateX(0)";
+          el.style.OTransform = "translateY(-50%) translateX(0)";
+        } else {
+          el.style.width = "100%";
+          el.style.height = "100%";
+          el.style.position = "absolute";
+          el.style.top = "0";
+          el.style.left = "0";
+          el.style.transform = "translateY(0) translateX(0)";
+          el.style.webkitTransform = "translateY(0) translateX(0)";
+          el.style.MozTransform = "translateY(0) translateX(0)";
+          el.style.msTransform = "translateY(0) translateX(0)";
+          el.style.OTransform = "translateY(0) translateX(0)";
+        }
+        el.src = imgDom.src;
+      };
+    }
+  }
+};
+</script>
+<style lang="less">
+#sagaUploads {
+  overflow: hidden;
+  .avatar-uploader {
+    height: 180px;
+    width: 180px;
+    overflow: hidden;
+    .el-upload {
+      width: 180px;
+      height: 180px;
+      .el-upload-dragger {
+        width: 180px;
+        height: 180px;
+        .el-icon-plus {
+          display: block;
+          width: 20px;
+          height: 20px;
+          font-size: 20px;
+          margin: 80px;
+        }
+      }
+    }
+  }
+  .point-view {
+    float: left;
+    margin-right: 10px;
+    margin-bottom: 10px;
+    overflow: hidden;
+    height: 240px;
+  }
+  .point-image {
+    width: 180px;
+    height: 180px;
+    position: relative;
+    border: 1px solid #ccc;
+    overflow: hidden;
+    image {
+      z-index: 11;
+    }
+    i {
+      position: absolute;
+      bottom: 10px;
+      right: 10px;
+      background-color: #fff;
+      padding: 5px;
+      cursor: pointer;
+      z-index: 66;
+    }
+  }
+}
+</style>

+ 4 - 3
src/views/data_admin/buildLog/index.vue

@@ -88,7 +88,9 @@
 <script>
 import buildInput from '@/components/data_admin/input'
 import buildTime from '@/components/data_admin/selectTime'
-
+import Handsontable from "handsontable-pro"
+import 'handsontable-pro/dist/handsontable.full.css'
+import zhCN from 'handsontable-pro/languages/zh-CN';
 
 import {
     getBuildLog,//获取日志
@@ -447,10 +449,9 @@ export default {
     box-sizing: border-box;
   }
   .log_page {
-    position: fixed;
+    position: absolute;
     bottom: 0;
     width: 100%;
-    left: 0;
     right: 0;
     height: 3rem;
     background-color: #fff;

+ 2 - 6
src/views/data_admin/buildUser/index.vue

@@ -53,10 +53,7 @@
 <script>
 import buildInput from "@/components/data_admin/input";
 import buildTime from "@/components/data_admin/selectTime";
-import {
-    mapGetters,
-    mapActions
-} from 'vuex'
+import {mapGetters, mapActions} from 'vuex'
 import {
   getUser, //获取扫楼用户
   loadUser, //修改
@@ -493,9 +490,8 @@ export default {
     // }
   }
   .user_page {
-    position: fixed;
+    position: absolute;
     height: 3rem;
-    left: 0;
     bottom: 0;
     right: 0;
     width: 100%;