Просмотр исходного кода

Merge branch 'master' of git.sagacloud.cn:web/wanda-adm

zhangyu 3 лет назад
Родитель
Сommit
e018684282

+ 1 - 1
package.json

@@ -15,7 +15,7 @@
   "dependencies": {
     "@babel/runtime": "^7.12.5",
     "@persagy-web/base": "2.2.1",
-    "@persagy-web/big": "2.2.50",
+    "@persagy-web/big": "2.2.51",
     "@persagy-web/draw": "2.2.13",
     "@persagy-web/graph": "2.2.45",
     "axios": "^0.21.1",

+ 273 - 86
src/utils/graph/CustomWall.ts

@@ -1,13 +1,15 @@
-import { SMouseEvent, SUndoStack } from "@persagy-web/base/lib";
+import { SKeyCode, SMouseEvent, SUndoStack } from "@persagy-web/base/lib";
 import { SItemStatus } from "@persagy-web/big/lib";
-import { SMathUtil } from "@persagy-web/big/lib/utils/SMathUtil"
+import { SMathUtil } from "@persagy-web/big/lib/utils/SMathUtil";
 import { SColor, SLine, SPainter, SPoint, SRect } from "@persagy-web/draw/lib";
-import { SGraphItem, SGraphPointListInsert, SGraphStyleItem } from "@persagy-web/graph/lib";
+import { SGraphItem, SGraphPointListDelete, SGraphPointListInsert, SGraphPointListUpdate, SGraphStyleItem, SLineStyle } from "@persagy-web/graph/lib";
 
 /**
- * 用户自定义墙
-*/
-export class CustomWall extends SGraphStyleItem {
+ * 折线编辑类
+ *
+ * @author  郝建龙
+ */
+ export class CustomWall extends SGraphStyleItem {
     /** X 坐标最小值 */
     private minX = Number.MAX_SAFE_INTEGER;
     /** X 坐标最大值 */
@@ -30,59 +32,54 @@ export class CustomWall extends SGraphStyleItem {
     }
 
     /** 鼠标移动时的点 */
-    protected lastPoint: SPoint | null = null;
+    private lastPoint: SPoint | null = null;
+
+    /** 是否垂直水平绘制 */
+    private _verAndLeve: boolean = false;
+    get verAndLeve(): boolean {
+        return this._verAndLeve;
+    }
+    set verAndLeve(bool: boolean) {
+        this._verAndLeve = bool;
+        this.update();
+    }
 
     /** 全局灵敏度 */
     dis: number = 10;
     /** 灵敏度转换为场景长度 */
-    protected sceneDis: number = 10;
+    private sceneDis: number = 10;
     /** 当前点索引 */
-    protected curIndex: number = -1;
+    private curIndex: number = -1;
     /** 当前点 */
     private curPoint: SPoint | null = null;
-    /** undo/redo 堆栈 */
+    /** undo / redo 堆栈 */
     private undoStack: SUndoStack = new SUndoStack();
 
     /**
      * 构造函数
      *
      * @param parent    父级
-     * @param list      坐标集合
-     */
-    constructor(parent: null | SGraphItem, list: SPoint[]);
-
-    /**
-     * 构造函数
-     *
-     * @param parent    父级
-     * @param list      第一个坐标
-     */
-    constructor(parent: null | SGraphItem, list: SPoint);
-
-    /**
-     * 构造函数
-     *
-     * @param parent    父级
-     * @param list      第一个坐标|坐标集合
+     * @param data      折线数据
      */
-    constructor(parent: null | SGraphItem, list: SPoint | SPoint[]) {
+    constructor(parent: null | SGraphItem, data: SPoint[] | SPoint) {
         super(parent);
-        // 数据类型为 SPoint
-        if (list instanceof SPoint) {
-            this.pointList.push(list);
+        if (data instanceof Array) {
+            this.pointList = data;
         } else {
-            this.pointList = list;
+            this.pointList.push(new SPoint(data));
+            this.lastPoint = data;
         }
-    }
-
+        this.fillColor = new SColor("#2196f3");
+        this.selectable = true;
+    } // Constructor
+    
     /**
      * 添加点至数组中
      *
-     * @param p         添加的点
-     * @param index     添加到的索引
+     * @param p       添加的点
+     * @param index   添加到的索引
      */
     private addPoint(p: SPoint, index?: number): void {
-        // 添加的索引存在且索引值有效
         if (index && this.canHandle(index)) {
             this.pointList.splice(index, 0, p);
             this.recordAction(SGraphPointListInsert, [
@@ -91,7 +88,6 @@ export class CustomWall extends SGraphStyleItem {
                 index
             ]);
         } else {
-            // 否则
             this.pointList.push(p);
             this.recordAction(SGraphPointListInsert, [this.pointList, p]);
         }
@@ -112,17 +108,16 @@ export class CustomWall extends SGraphStyleItem {
     /**
      * 根据索引删除点
      *
-     * @param index     删除点
+     * @param index   删除点
      */
     deletePoint(index: number): void {
-        // 索引值有效且折线列表有2个以上点
         if (this.canHandle(index) && this.pointList.length > 2) {
             const p = new SPoint(
                 this.pointList[this.curIndex].x,
                 this.pointList[this.curIndex].y
             );
             this.pointList.splice(index, 1);
-            this.recordAction(SGraphPointListInsert, [
+            this.recordAction(SGraphPointListDelete, [
                 this.pointList,
                 p,
                 index
@@ -134,33 +129,167 @@ export class CustomWall extends SGraphStyleItem {
     }
 
     /**
-     * 移动后处理所有坐标,并肩原点置为场景原点
+     * 鼠标按下事件
      *
-     * @param x     x 坐标
-     * @param y     y 坐标
+     * @param event   鼠标事件
+     * @return 是否处理事件
+     */
+    onMouseDown(event: SMouseEvent): boolean {
+        this.curIndex = -1;
+        this.curPoint = null;
+        if (event.shiftKey || this.verAndLeve) {
+            event = this.compare(event);
+        }
+        if (event.buttons == 1) {
+            if (this.status == SItemStatus.Create) {
+                this.addPoint(new SPoint(event.x, event.y));
+                return true;
+            } else if (this.status == SItemStatus.Edit) {
+                // 查询鼠标最近的索引
+                this.findNearestPoint(new SPoint(event.x, event.y));
+                // 增加点
+                if (this.curIndex < 0) {
+                    this.findAddPos(new SPoint(event.x, event.y));
+                }
+
+                // 删除点
+                if (event.altKey && this.canHandle(this.curIndex)) {
+                    this.deletePoint(this.curIndex);
+                }
+
+                this.update();
+                return true;
+            } else {
+                return super.onMouseDown(event);
+            }
+        }
+        return super.onMouseDown(event);
+    }
+
+    /**
+     * 鼠标移动事件
+     *
+     * @param event   鼠标事件
+     * @return 是否处理事件
      */
-    moveToOrigin(x: number, y: number): void {
-        super.moveToOrigin(x, y);
-        // 遍历点集列表
-        this.pointList = this.pointList.map(
-            (t): SPoint => {
-                t.x = t.x + x;
-                t.y = t.y + y;
-                return t;
+    onMouseMove(event: SMouseEvent): boolean {
+        if (event.shiftKey || this.verAndLeve) {
+            event = this.compare(event);
+        }
+
+        if (this.status == SItemStatus.Create) {
+            if (this.lastPoint) {
+                this.lastPoint.x = event.x;
+                this.lastPoint.y = event.y;
+            } else {
+                this.lastPoint = new SPoint(event.x, event.y);
             }
-        );
-        this.x = 0;
-        this.y = 0;
+
+            this.update();
+            return true;
+        } else if (this.status == SItemStatus.Edit) {
+            if (event.buttons == 1) {
+                if (this.canHandle(this.curIndex)) {
+                    this.pointList[this.curIndex].x = event.x;
+                    this.pointList[this.curIndex].y = event.y;
+                }
+            }
+
+            this.update();
+            return true;
+        } else {
+            return super.onMouseMove(event);
+        }
+    }
+
+    /**
+     * 鼠标移动事件
+     *
+     * @param event   鼠标事件
+     * @return 是否处理事件
+     */
+    onMouseUp(event: SMouseEvent): boolean {
+        if (this.status == SItemStatus.Edit) {
+            if (this.curIndex > -1) {
+                const p = new SPoint(
+                    this.pointList[this.curIndex].x,
+                    this.pointList[this.curIndex].y
+                );
+                this.recordAction(SGraphPointListUpdate, [
+                    this.pointList,
+                    this.curPoint,
+                    p,
+                    this.curIndex
+                ]);
+            }
+        } else if (this.status == SItemStatus.Normal) {
+            super.onMouseUp(event);
+            return true;
+        }
+        return true;
+    }
+
+    /**
+     * 鼠标双击事件
+     *
+     * @param event     事件参数
+     * @return 是否处理事件
+     */
+    onDoubleClick(event: SMouseEvent): boolean {
+        // 如果为show状态 双击改对象则需改为编辑状态
+        if (this.status == SItemStatus.Normal) {
+            this.status = SItemStatus.Edit;
+            // @ts-ignore
+            this.grabItem(this);
+        } else if (this.status == SItemStatus.Edit) {
+            // 编辑状态
+            this.status = SItemStatus.Normal;
+            this.releaseItem();
+        } else if (this.status == SItemStatus.Create) {
+            // 创建状态
+            if (this.pointList.length > 1) {
+                this.status = SItemStatus.Normal;
+                this.releaseItem();
+                this.$emit("finishCreated");
+            }
+        }
+
+        this.$emit("onDoubleClick", event);
+        return true;
+    }
+
+    /**
+     * 键盘按键弹起事件
+     *
+     * @param event     事件参数
+     */
+    onKeyUp(event: KeyboardEvent): void {
+        if (event.keyCode == SKeyCode.Enter) {
+            if (this.pointList.length > 1) {
+                if (this.status == SItemStatus.Create) {
+                    this.$emit("finishCreated");
+                }
+
+                this.status = SItemStatus.Normal;
+                this.releaseItem();
+            }
+        }
+        // delete删除点
+        if (
+            event.keyCode == SKeyCode.Delete &&
+            this.status == SItemStatus.Edit
+        ) {
+            this.deletePoint(this.curIndex);
+        }
     }
 
     /**
      * 获取点击点与点集中距离最近点
      *
-     * @param p     鼠标点击点
+     * @param p   鼠标点击点
      */
     findNearestPoint(p: SPoint): void {
         let len = this.sceneDis;
-        // 遍历点集列表
         for (let i = 0; i < this.pointList.length; i++) {
             let dis = SMathUtil.pointDistance(
                 p.x,
@@ -168,7 +297,6 @@ export class CustomWall extends SGraphStyleItem {
                 this.pointList[i].x,
                 this.pointList[i].y
             );
-            // 当前距离小于最短距离
             if (dis < len) {
                 len = dis;
                 this.curIndex = i;
@@ -183,15 +311,14 @@ export class CustomWall extends SGraphStyleItem {
     /**
      * 计算增加点的位置
      *
-     * @param p     鼠标点击点
+     * @param p   鼠标点击点
      */
     findAddPos(p: SPoint): void {
         let len = SMathUtil.pointToLine(
-            p,
-            new SLine(this.pointList[0], this.pointList[1])
-        ),
+                p,
+                new SLine(this.pointList[0], this.pointList[1])
+            ),
             index = 0;
-        // 折线点集多余2
         if (this.pointList.length > 2) {
             for (let i = 1; i < this.pointList.length - 1; i++) {
                 let dis = SMathUtil.pointToLine(
@@ -204,20 +331,21 @@ export class CustomWall extends SGraphStyleItem {
                 }
             }
         }
-        // 最短距离在可吸附范围内且吸附点存在
-        if (len.MinDis < this.sceneDis && len.Point) {
-            this.addPoint(len.Point, index + 1);
+
+        if (len.MinDis < this.sceneDis) {
+            if (len.Point) {
+                this.addPoint(len.Point, index + 1);
+            }
         }
     }
 
     /**
      * shift 垂直水平创建或编辑
      *
-     * @param event     事件
-     * @return 事件对象
+     * @param event   事件
+     * @return 处理后的鼠标事件
      */
     compare(event: SMouseEvent): SMouseEvent {
-        // 点集列表存在
         if (this.pointList.length) {
             let last = new SPoint(event.x, event.y);
             if (this.status == SItemStatus.Create) {
@@ -230,11 +358,9 @@ export class CustomWall extends SGraphStyleItem {
 
             const dx = Math.abs(event.x - last.x);
             const dy = Math.abs(event.y - last.y);
-            // 纵向变量更大
             if (dy > dx) {
                 event.x = last.x;
             } else {
-                // 否则
                 event.y = last.y;
             }
         }
@@ -257,35 +383,29 @@ export class CustomWall extends SGraphStyleItem {
     /**
      * Item 对象边界区域
      *
-     * @return 外接矩阵
+     * @return 对象边界区域
      */
     boundingRect(): SRect {
-        // 点集列表有值
         if (this.pointList.length) {
             this.minX = this.pointList[0].x;
             this.maxX = this.pointList[0].x;
             this.minY = this.pointList[0].y;
             this.maxY = this.pointList[0].y;
-            this.pointList.forEach((it): void => {
+            this.pointList.forEach(it => {
                 let x = it.x,
                     y = it.y;
-
-                // 如果数据 x 坐标小于 x 坐标最小值
                 if (x < this.minX) {
                     this.minX = x;
                 }
 
-                // 如果数据 y 坐标小于 y 坐标最小值
                 if (y < this.minY) {
                     this.minY = y;
                 }
 
-                // 如果数据 x 坐标大于 x 坐标最小值
                 if (x > this.maxX) {
                     this.maxX = x;
                 }
 
-                // 如果数据 y 坐标大于 y 坐标最小值
                 if (y > this.maxY) {
                     this.maxY = y;
                 }
@@ -309,7 +429,6 @@ export class CustomWall extends SGraphStyleItem {
      */
     contains(x: number, y: number): boolean {
         let p = new SPoint(x, y);
-        // 遍历点集列表
         for (let i = 1; i < this.pointList.length; i++) {
             let PTL = SMathUtil.pointToLine(
                 p,
@@ -320,11 +439,11 @@ export class CustomWall extends SGraphStyleItem {
                     this.pointList[i].y
                 )
             );
-            // 点在吸附范围内
             if (PTL.MinDis < this.sceneDis) {
                 return true;
             }
         }
+
         return false;
     }
 
@@ -332,7 +451,6 @@ export class CustomWall extends SGraphStyleItem {
      * 撤销操作
      */
     undo(): void {
-        // 非正常态
         if (this._status != SItemStatus.Normal) {
             this.undoStack.undo();
         }
@@ -342,7 +460,6 @@ export class CustomWall extends SGraphStyleItem {
      * 重做操作
      */
     redo(): void {
-        // 非正常态
         if (this._status != SItemStatus.Normal) {
             this.undoStack.redo();
         }
@@ -352,24 +469,94 @@ export class CustomWall extends SGraphStyleItem {
      * 取消操作执行
      */
     cancelOperate(): void {
-        // 创建态
         if (this.status == SItemStatus.Create) {
             this.parent = null;
             this.releaseItem();
         } else if (this.status == SItemStatus.Edit) {
-            // 编辑态
             this.status = SItemStatus.Normal;
             this.releaseItem();
         }
     }
 
     /**
-     * Item 绘制操作
+     * 绘制基本图形
      *
      * @param painter   绘制对象
      */
+    drawBaseLine(painter: SPainter): void {
+        // 绘制基本图形
+        painter.pen.color = this.strokeColor;
+        if (this.lineStyle == SLineStyle.Dashed) {
+            painter.pen.lineDash = [
+                painter.toPx(this.lineWidth * 3),
+                painter.toPx(this.lineWidth * 7)
+            ];
+        } else if (this.lineStyle == SLineStyle.Dotted) {
+            painter.pen.lineDash = [
+                painter.toPx(this.lineWidth),
+                painter.toPx(this.lineWidth)
+            ];
+        }
+
+        painter.drawPolyline(this.pointList);
+    }
+
+    /**
+     * 返回对象储存的相关数据
+     *
+     * @return 对象储存的相关数据
+     */
+    toData(): any {
+        return this.data;
+    }
+
+    /**
+     * Item 绘制操作
+     *
+     * @param painter 绘制对象
+     */
     onDraw(painter: SPainter): void {
         // 缓存场景长度
         this.sceneDis = painter.toPx(this.dis);
+        // 创建状态
+        painter.pen.lineWidth = painter.toPx(this.lineWidth);
+        if (this.status == SItemStatus.Create && this.lastPoint) {
+            // 绘制基本图形
+            this.drawBaseLine(painter);
+            painter.drawLine(
+                this.pointList[this.pointList.length - 1],
+                this.lastPoint
+            );
+            // 编辑状态
+            this.pointList.forEach((t, i): void => {
+                painter.brush.color = SColor.White;
+                if (i == this.curIndex) {
+                    painter.brush.color = this.fillColor;
+                }
+                painter.drawCircle(t.x, t.y, painter.toPx(5));
+            });
+        } else if (this.status == SItemStatus.Edit) {
+            // 绘制基本图形
+            this.drawBaseLine(painter);
+            // 编辑状态
+            this.pointList.forEach((t, i): void => {
+                painter.brush.color = SColor.White;
+                if (i == this.curIndex) {
+                    painter.brush.color = this.fillColor;
+                }
+                painter.drawCircle(t.x, t.y, painter.toPx(5));
+            });
+        } else {
+            // 查看状态,是否选中
+            if (this.selected) {
+                painter.pen.lineWidth = painter.toPx(this.lineWidth * 2);
+                painter.shadow.shadowBlur = 10;
+                painter.shadow.shadowColor = new SColor(`#00000033`);
+                painter.shadow.shadowOffsetX = 5;
+                painter.shadow.shadowOffsetY = 5;
+            }
+            // 绘制基本图形
+            this.drawBaseLine(painter);
+        }
     }
 }

+ 117 - 10
src/utils/graph/DivideFloorScene.ts

@@ -8,6 +8,11 @@ import { ShadeItem } from "./ShadeItem";
 import { intersect, polygon, segments, combine, selectIntersect, selectUnion, selectDifference, selectDifferenceRev, difference } from "polybooljs";
 import { DrawZoneItem } from "./DrawZoneItem";
 import { SItemStatus } from "@persagy-web/big/lib";
+import { Wall } from "@persagy-web/big/lib/types/floor/Wall";
+import { CustomWall } from "./CustomWall";
+import { SGraphItem, SGraphStyleItem } from "@persagy-web/graph/lib";
+import { remove } from "js-cookie";
+import { SWallItem } from "@persagy-web/big/lib/items/floor/SWallItem";
 
 export class DivideFloorScene extends FloorScene {
     /** 划分item  */
@@ -15,7 +20,7 @@ export class DivideFloorScene extends FloorScene {
 
     /** 绘制的分区item */
     drawItem: DrawZoneItem | null = null;
-    /** 当前绘制命令 cut-交集区域绘制 zoneDraw-绘制业务空间 */
+    /** 当前绘制命令 cut-交集区域绘制 zoneDraw-绘制业务空间 wallDraw-画墙 */
     // 2021.3.4需求不算交集,直接绘制业务空间
     drawCmd: string = '';
 
@@ -30,6 +35,10 @@ export class DivideFloorScene extends FloorScene {
 
     /** 高亮item  */
     highLight: HighlightItem | null = null;
+    /** 删除日志 */
+    deleteWallLog: Wall[] = []
+    /** 用户自己增加的墙item */
+    customWall: CustomWall[] = []
 
     /**
      * 清除划分区域
@@ -51,22 +60,57 @@ export class DivideFloorScene extends FloorScene {
     } // Function clearCut()
 
     /**
+     * 清除绘制的墙
+    */
+    clearWalls() {
+        if (this.customWall.length) {
+            this.customWall.forEach(t => {
+                this.removeItem(t)
+            })
+            this.customWall = []
+        }
+    }
+
+    /**
+     * 删除墙
+    */
+    deleteItem(item: SGraphItem) {
+        if (item instanceof CustomWall) {
+            this.removeItem(item);
+            for (let i = 0; i < this.customWall.length; i++) {
+                if (this.customWall[i] == item) {
+                    this.customWall.splice(i, 1)
+                    break
+                }
+            }
+            this.view?.update()
+        } else if (item instanceof SWallItem) {
+            this.removeItem(item);
+            this.deleteWallLog.push(item.data)
+            this.view?.update()
+        }
+    }
+
+    /**
     * 鼠标按下事件
     *
     * @param   event   保存事件参数
     * @return  boolean
     */
     onMouseDown(event: SMouseEvent): boolean {
+        // 判断是否开启吸附,并且有吸附的点
+        if (
+            this.isAbsorbing &&
+            this.highLight &&
+            this.highLight.visible
+        ) {
+            event.x = this.highLight.point.x;
+            event.y = this.highLight.point.y;
+        }
+        if (this.grabItem) {
+            return this.grabItem.onMouseDown(event);
+        }
         if (event.buttons == 1) {
-            // 判断是否开启吸附,并且有吸附的点
-            if (
-                this.isAbsorbing &&
-                this.highLight &&
-                this.highLight.visible
-            ) {
-                event.x = this.highLight.point.x;
-                event.y = this.highLight.point.y;
-            }
             if (this.drawCmd == 'cut') {
                 if (!this.cutItem) {
                     let point = new SPoint(event.x, event.y);
@@ -86,6 +130,15 @@ export class DivideFloorScene extends FloorScene {
                     this.grabItem = item;
                     return true;
                 }
+            } else if (this.drawCmd == "wallDraw") {
+                let point = new SPoint(event.x, event.y);
+                let item = new CustomWall(null, point)
+                item.status = SItemStatus.Create;
+                this.addItem(item);
+                this.customWall.push(item)
+                item.connect("finishCreated", this, this.finishCreated)
+                this.grabItem = item;
+                return true;
             }
         }
         return super.onMouseDown(event)
@@ -454,4 +507,58 @@ export class DivideFloorScene extends FloorScene {
         // poly为segments类型
         return poly;
     }
+
+    /**
+     * 读取场景中的底图对象并生成相应json
+    */
+    getMapObject(): string {
+        try {
+            if (this.json) {
+                let map = JSON.parse(this.json);
+                const tempWall = map.EntityList[0].Elements.Walls
+                console.log(map.EntityList[0].Elements.Walls.length);
+                const logArr = this.deleteWallLog.map(t => {
+                    return t.SourceId
+                })
+                if (this.deleteWallLog.length) {
+                    for (let i = 0; i < tempWall.length; i++) {
+                        if (logArr.includes(tempWall[i].SourceId)) {
+                            tempWall.splice(i, 1);
+                            i--;
+                        }
+                    }
+                }
+                if (this.customWall.length) {
+                    this.customWall.forEach(t => {
+                        tempWall.push(t.toData())
+                    })
+                }
+                console.log(map.EntityList[0].Elements.Walls.length);
+                return JSON.stringify(map);
+            }
+            return ''
+        } catch (err) {
+            console.log(err)
+            return ''
+        }
+    }
+
+    /**
+     * item绘制完成
+     */
+    finishCreated(item: SGraphStyleItem) {
+        this.grabItem = null;
+        // @ts-ignore
+        item.status = SItemStatus.Normal;
+        this.selectContainer.clear();
+        this.selectContainer.toggleItem(item);
+        this.clearCmdStatus()
+    }
+
+    /**
+     * 清除命令
+    */
+    clearCmdStatus() {
+        this.drawCmd = ''
+    }
 }

+ 3 - 3
src/utils/graph/DrawZoneItem.ts

@@ -40,7 +40,7 @@ export class DrawZoneItem extends SGraphStyleItem {
     /** 场景像素内部将灵敏像素换算为场景实际距离 */
     private scenceLen: number = 15;
     /** 场景像素 */
-    private isShift: boolean = false;
+    private isAlt: boolean = false;
     /** undo/redo 堆栈 */
     protected undoStack: SUndoStack = new SUndoStack();
 
@@ -251,8 +251,8 @@ export class DrawZoneItem extends SGraphStyleItem {
      * @param event    鼠标事件
      */
     protected editPolygonPoint(event: SMouseEvent): void {
-        //  判断是否为删除状态 isShift = true为删除状态
-        if (this.isShift) {
+        //  判断是否为删除状态 isAlt = true为删除状态
+        if (this.isAlt) {
             // 1 判断是否点击在多边形顶点
             let lenIndex = -1; // 当前点击到的点位索引;
             let curenLen = this.scenceLen; // 当前的灵敏度

+ 21 - 2
src/utils/graph/FloorScene.ts

@@ -57,6 +57,24 @@ export class FloorScene extends SGraphScene {
         );
     } // Set isSpaceSelectable
 
+    /** 空间是否可选  */
+    _isWallSelectable: boolean = false;
+    get isWallSelectable(): boolean {
+        return this._isWallSelectable;
+    } // Get isWallSelectable
+    set isWallSelectable(v: boolean) {
+        if (this._isWallSelectable === v) {
+            return;
+        }
+        this._isWallSelectable = v;
+        this.wallList.map(
+            (t: SWallItem): SWallItem => {
+                t.selectable = this._isWallSelectable;
+                return t;
+            }
+        );
+    } // Set isWallSelectable
+
     /** 业务空间是否可选  */
     _isZoneSelectable: boolean = true;
     get isZoneSelectable(): boolean {
@@ -94,8 +112,8 @@ export class FloorScene extends SGraphScene {
      *  @param  url     请求数据文件路径
      */
     loadUrl(url: string): Promise<void> {
-        return getJsonz(url).then((res: any) => {
-            this.addBaseMapItem(res)
+        return getJsonz(url, true).then((res: any) => {
+            this.addBaseMapItem(res.EntityList ? res.EntityList[0].Elements : res.entityList[0].Elements)
             this.json = JSON.stringify(res);
             return res;
         })
@@ -174,6 +192,7 @@ export class FloorScene extends SGraphScene {
     addWall(wall: Wall): void {
         let item = new SWallItem(null, wall);
         item.fillColor = ItemColor.wallColor;
+        // item.selectable = true
         this.wallList.push(item);
         this.addItem(item);
     } // Function addWall()

+ 9 - 9
src/views/maintain/relationship/components/tableHeader.ts

@@ -1,12 +1,12 @@
 const tableHeader = {
-    '设备所在建筑': ['建筑', 'BIM构件名称', '系统分类', '设备类型名称', '设备本地编码'],
-    '设备所在楼层': ['建筑', '楼层', 'BIM构件名称', '系统分类', '设备类型名称', '设备本地编码'],
-    '设备所在功能空间': ['空间本地名称', '空间本地编码', '建筑', '楼层', 'BIM构件名称', '系统分类', '设备类型名称', '设备本地编码'],
-    '设备服务功能空间': ['空间本地名称', '空间本地编码', '建筑', '楼层', 'BIM构件名称', '系统分类', '设备类型名称', '设备本地编码'],
-    '设备所在供电空间': ['空间本地名称', '空间本地编码', '建筑', '楼层', 'BIM构件名称', '系统分类', '设备类型名称', '设备本地编码'],
-    '空间所在建筑': ['建筑', '空间本地名称', '空间本地编码', '楼层'],
-    '空间所在楼层': ['建筑', '楼层', '空间本地名称', '空间本地编码'],
-    '空间服务空间': ['空间本地名称', '空间本地编码', '建筑', '楼层', '空间本地名称', '空间本地编码', '建筑', '楼层'],
-    '系统下的设备': ['系统分类', '分类名称', '系统编码', 'BIM构件名称', '系统分类', '设备类型名称', '设备本地编码'],
+    '设备所在建筑': [['建筑', 'objectInfo'], ['BIM构件名称', 'localName'], ['系统分类','systemCategory'], ['设备类型名称','codeName'], ['设备本地编码', "localId"]],
+    '设备所在楼层': [['建筑', 'objectInfo'], ['楼层','floorName'], ['BIM构件名称', 'localName'], ['系统分类','systemCategory'], ['设备类型名称','codeName'], ['设备本地编码', "localId"]],
+    '设备所在功能空间': [['空间本地名称', "localName"], ['空间本地编码', "localId"], ['建筑', 'objectInfo'], ['楼层','floorName'], ['BIM构件名称', 'localName'], ['系统分类','systemCategory'], ['设备类型名称','codeName'], ['设备本地编码', "localId"]],
+    '设备服务功能空间': [['空间本地名称', "localName"], ['空间本地编码', "localId"], ['建筑', 'objectInfo'], ['楼层','floorName'], ['BIM构件名称', 'localName'], ['系统分类','systemCategory'], ['设备类型名称','codeName'], ['设备本地编码', "localId"]],
+    '设备所在供电空间': [['空间本地名称', "localName"], ['空间本地编码', "localId"], ['建筑', 'objectInfo'], ['楼层','floorName'], ['BIM构件名称', 'localName'], ['系统分类','systemCategory'], ['设备类型名称','codeName'], ['设备本地编码', "localId"]],
+    '空间所在建筑': [['建筑', 'objectInfo'], ['空间本地名称', "localName"], ['空间本地编码', "localId"], ['楼层','floorName']],
+    '空间所在楼层': [['建筑', 'objectInfo'], ['楼层','floorName'], ['空间本地名称', "localName"], ['空间本地编码', "localId"]],
+    '空间服务空间': [['空间本地名称', "localName"], ['空间本地编码', "localId"], ['建筑', 'objectInfo'], ['楼层','floorName'], ['空间本地名称', "localName"], ['空间本地编码', "localId"], ['建筑', 'objectInfo'], ['楼层','floorName']],
+    '系统下的设备': [['系统分类','systemCategory'], ['分类名称',''], ['系统编码',''], ['BIM构件名称', 'localName'], ['系统分类','systemCategory'], ['设备类型名称','codeName'], ['设备本地编码', "localId"]],
 }
 export default tableHeader

+ 59 - 39
src/views/maintain/relationship/relation/components/table.vue

@@ -1,53 +1,73 @@
 <template>
-    <el-table
-        :data="tableData"
-        :span-method="objectSpanMethod"
-        :header-cell-style="{ background: '#e1e4e5',color: '#2b2b2b', lineHeight: '30px' }"
-        class="table"
-        style="width: 100%;"
-        height="100%"
+  <el-table
+    :data="tableData"
+    :span-method="objectSpanMethod"
+    :header-cell-style="{
+      background: '#e1e4e5',
+      color: '#2b2b2b',
+      lineHeight: '30px',
+    }"
+    v-loading="loading"
+    class="table"
+    style="width: 100%"
+    :height="height ? height : '100%'"
+  >
+    <el-table-column
+      v-for="(item, index) in tableHeader"
+      :key="index"
+      :prop="item[1]"
+      :label="item[0]"
+      align="left"
     >
-        <el-table-column
-            v-for="(item,index) in tableHeader"
-            :key="index"
-            prop="cCADID"
-            :label="item"
-            align="left"
-        >
-        </el-table-column>
-        <el-table-column
-            label="操作"
-            align="left"
-        >
-            <template slot-scope="scope">
-                <el-button slot="reference" size="mini" icon="el-icon-delete"
-                           @click="deleteObject(scope.$index, scope.row)"/>
-            </template>
-        </el-table-column>
-    </el-table>
+      <template slot-scope="scope">
+        {{ item[1] == 'objectInfo' ? scope.row.objectInfo[0].name :scope.row[item[1]] }}
+      </template>
+    </el-table-column>
+    <el-table-column label="操作" align="left">
+      <template slot-scope="scope">
+        <el-button
+          slot="reference"
+          size="mini"
+          icon="el-icon-delete"
+          @click="deleteObject(scope.$index, scope.row)"
+        />
+      </template>
+    </el-table-column>
+  </el-table>
 </template>
 
 <script lang="ts">
+import { relDel } from "@/api/datacenter";
 import { Component, Prop, Vue } from "vue-property-decorator";
-
 @Component({
-    name: 'relation-table'
+  name: "relation-table",
 })
 export default class extends Vue {
+  @Prop({ default: Array }) tableHeader?: [];
+  @Prop({ default: Array }) tableData?: [];
+  @Prop({ default: String || Number }) height?: "";
+  @Prop({ default: Boolean }) loading?: false;
 
-    @Prop({default:Array}) tableHeader?:[]
-    @Prop({default:Array}) tableData?:[]
-
-    objectSpanMethod() {
-
-    }
-
-    deleteObject() {
-
-    }
+  objectSpanMethod() {}
+  //  删除
+  deleteObject(index: number, val: any) {
+    const data = {
+      relType: this.$route.query.relationType,
+      graphicType: this.$route.query.graphicType,
+      fromId: val.id, //主对象id
+      toId: val.objectInfo.id, //主对象id
+    };
+    relDel(data).then((res) => {
+      if (res.result == "success") {
+        this.$message.success("删除成功!");
+        this.$emit("updata");
+      } else {
+        this.$message.error("删除失败!");
+      }
+    });
+  }
 }
 </script>
 
-<style scoped>
-
+<style  scoped>
 </style>

+ 116 - 14
src/views/maintain/relationship/relation/index.vue

@@ -10,9 +10,11 @@
         <p>主对象</p>
         <span v-if="relTypeStatus == 1 || relTypeStatus == 3">类型:</span>
         <el-select
+          :clearable="true"
           v-if="relTypeStatus == 1 || relTypeStatus == 3"
-          v-model="mainObject"
+          v-model="categoryFrom"
           placeholder="请选择"
+          @change="mainSelect"
           style="margin-right: 10px"
         >
           <el-option
@@ -23,14 +25,15 @@
           >
           </el-option>
         </el-select>
-        <AdmSearch />
+        <AdmSearch @SearchValue="mainSerch" />
       </el-col>
       <el-col :span="12" class="object">
         <p>从对象</p>
         <span v-if="relTypeStatus == 2 || relTypeStatus == 3">类型:</span>
         <el-select
           v-if="relTypeStatus == 2 || relTypeStatus == 3"
-          v-model="mainObject"
+          v-model="categoryTo"
+          :clearable="true"
           placeholder="请选择"
           style="margin-right: 10px"
         >
@@ -42,12 +45,33 @@
           >
           </el-option>
         </el-select>
-        <AdmSearch />
+        <AdmSearch @SearchValue="minorSearch" />
       </el-col>
     </el-row>
-    <relationTable :tableHeader="tableHeader" :tableData="tableData" />
+    <relationTable
+      v-if="tableHeight"
+      @updata="relManualQuery"
+      :tableHeader="tableHeader"
+      :tableData="tableData"
+      :height="tableHeight"
+      :loading="loading"
+    />
+    <!-- 分页 -->
+    <div class="pagination">
+      <el-pagination
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+        :current-page="page.currentPage"
+        :page-sizes="[10, 15, 20, 30]"
+        :page-size="page.pageSize"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="page.total"
+      >
+      </el-pagination>
+    </div>
     <addRelationDialog
       @closeAddRelation="addRelationValue = false"
+      @update="relManualQuery"
       :addRelationValue="addRelationValue"
       :values="values"
     />
@@ -64,7 +88,7 @@ import tableHeader from "@/views/maintain/relationship/components/tableHeader";
 import addRelationDialog from "./components/addRelationDialog.vue";
 import editRelationDialog from "./components/editRelationDialog.vue";
 import excelDialog from "./components/excelDialog.vue";
-import { relToType, relManualQuery } from "@/api/datacenter";
+import { relToType, relManualQuery, relDel } from "@/api/datacenter";
 
 @Component({
   name: "relation",
@@ -77,10 +101,12 @@ import { relToType, relManualQuery } from "@/api/datacenter";
   },
 })
 export default class extends Vue {
-  mainObject = ""; //主关系
+  categoryFrom = ""; //主关系
   mainOptions = []; //主关系选项
-  minorObject = ""; //次关系
+  categoryTo = ""; //次关系
   minorOptions = []; //次关系选项
+  vagueFrom = ""; //主关系模糊收索
+  vagueTo = ""; //次关系模糊收索
   //表头数据
   tableHeader = [];
   //表格数据
@@ -114,6 +140,13 @@ export default class extends Vue {
   };
   relTypeStatus: any = 0; //关系相关类型主从 0 None 1主 2从 3主从
 
+  page: object = {
+    total: 0, //总数
+    currentPage: 1, //当前页
+    pageSize: 15, //当前页数量
+  };
+  tableHeight: number = 0; //table高
+  loading: Boolean = false; //是否显示loadding
   /////////////////////////////////////////
   // 方法
 
@@ -131,6 +164,52 @@ export default class extends Vue {
   }
 
   /**
+   * 分页数量切换
+   */
+
+  handleSizeChange(val: any) {
+    Object.assign(this.page, {
+      pageSize: val,
+    });
+    this.relManualQuery();
+  }
+  /**
+   * 分页切换
+   */
+  handleCurrentChange(val: any) {
+    Object.assign(this.page, {
+      currentPage: val,
+    });
+    this.relManualQuery();
+  }
+
+  /**
+   * 主关系下拉框选择
+   */
+  mainSelect(val: any) {
+    this.categoryFrom = val;
+    this.relManualQuery();
+    console.log("mainSelect", val);
+  }
+  /**
+   * 从关系下拉框选择
+   */
+  minorSelect(val: any) {
+    this.categoryTo = val;
+    this.relManualQuery();
+  }
+  // 主关系模糊搜索
+  mainSerch(val: string) {
+    this.vagueFrom = val;
+    this.relManualQuery();
+  }
+  // 从关系模糊搜索
+  minorSearch(val: string) {
+    this.vagueTo = val;
+    this.relManualQuery();
+  }
+
+  /**
    * 添加关系
    */
   addRelation() {
@@ -183,20 +262,30 @@ export default class extends Vue {
    * 获取table列表
    */
   relManualQuery() {
+    this.loading = true;
     // 获取table数据
     const data = {
       projectId: this.$route.query.projectId,
+      categoryFrom: this.categoryFrom,
+      categoryTo: this.categoryTo,
+      vagueTo: this.vagueTo, //主关系
+      vagueFrom: this.vagueFrom, //从关系
       objectType: 1,
       relType: this.$route.query.relationType,
-      pageSize: 50,
-      pageNumber: 1,
+      pageSize: this.page.pageSize,
+      pageNumber: this.page.currentPage,
       graphicType: this.$route.query.graphicType,
       zoneType: this.$route.query.zoneType ? this.$route.query.zoneType : "",
     };
-    relManualQuery(data).then((res) => {
-      console.log("this.tableHeader", this.tableHeader);
-      this.tableData = res.content;
-    });
+    relManualQuery(data)
+      .then((res) => {
+        this.tableData = res.content;
+        this.page.total = res.total;
+        this.loading = false;
+      })
+      .catch((error) => {
+        this.loading = false;
+      });
   }
 
   created() {
@@ -208,6 +297,14 @@ export default class extends Vue {
     // 获取table列表
     this.relManualQuery();
   }
+  mounted() {
+    //计算table的高度
+    let allHeight =
+      document.getElementsByClassName("relation")[0].offsetHeight - 57; //57是Head的高
+    let contentHeight = document.getElementsByClassName("content")[0]
+      .offsetHeight;
+    this.tableHeight = allHeight - contentHeight - 47;
+  }
 }
 </script>
 
@@ -233,5 +330,10 @@ export default class extends Vue {
       }
     }
   }
+  .pagination {
+    margin-top: 12px;
+    margin-right: 24px;
+    float: right;
+  }
 }
 </style>

+ 19 - 1
src/views/maintain/space/components/canvasFun.vue

@@ -11,7 +11,7 @@
                 <i class="el-icon-download" style="font-size:20px;color:#fff;"></i>
                 <el-dropdown-menu slot='dropdown'>
                     <el-dropdown-item command="savePng">保存为png</el-dropdown-item>
-                    <el-dropdown-item command="saveSvg">保存为svg</el-dropdown-item>
+                    <!-- <el-dropdown-item command="saveSvg">保存为svg</el-dropdown-item> -->
                     <el-dropdown-item command="saveJson">保存为Json</el-dropdown-item>
                 </el-dropdown-menu>
             </el-dropdown>
@@ -26,6 +26,12 @@
                 </el-dropdown-menu> -->
             </el-dropdown>
         </div>
+        <div v-if="config.isEdit&&config.drawWall" @click="drawWall" :class="{ 'active': active === 'drawWall' }">
+            <i class="el-icon-share"></i>
+        </div>
+        <div v-if="config.isEdit&&config.drawWall" @click="clearWall">
+            <i class="iconfont icon-Erase"></i>
+        </div>
         <div v-if="config.isEdit&&config.divide" @click="clearDivide">
             <i class="iconfont icon-Erase"></i>
         </div>
@@ -45,6 +51,7 @@ interface configFace {
     isEdit: boolean;
     divide: boolean;
     groupSelect: boolean;
+    drawWall: boolean;
 }
 import { Vue, Component, Prop } from "vue-property-decorator";
 @Component
@@ -55,6 +62,7 @@ export default class canvasFun extends Vue {
             isEdit: false,
             divide: true,
             groupSelect: false,
+            drawWall: false,
         },
     })
     config!: configFace;
@@ -87,6 +95,11 @@ export default class canvasFun extends Vue {
         this.active = "divide";
         this.$emit("divide");
     }
+    // 画墙
+    drawWall() {
+        this.active = "drawWall";
+        this.$emit("drawWall");
+    }
     // 清除编辑
     clearDivide() {
         this.active = "";
@@ -122,6 +135,11 @@ export default class canvasFun extends Vue {
         }
         this.scale(this.sliderVal);
     }
+    // 删除墙
+    clearWall() {
+        this.active = "";
+        this.$emit("clearWall");
+    }
 }
 </script>
 <style lang="scss" scoped>

+ 84 - 7
src/views/maintain/space/components/spaceGraph.vue

@@ -46,6 +46,11 @@
                         <el-button type="primary" @click="groupCreateZone">批量创建所选业务空间</el-button>
                         <el-button plain @click="cancelGraphy">取 消</el-button>
                     </div>
+                    <!-- 保存墙 -->
+                    <div v-if="type==6">
+                        <el-button plain @click="cancelGraphy">取 消</el-button>
+                        <el-button type="primary" @click="saveMap">保存</el-button>
+                    </div>
                 </div>
             </el-row>
 
@@ -53,7 +58,8 @@
 
             <el-row class="canvas-actions-box">
                 <canvas-fun :config="config" @fit="fit" @savePng="savePng" @saveSvg="saveSvg" @divide="divide" @clearDivide="clearDivide"
-                    ref="canvasFun" @saveJson="saveJson" @changeAbsorb="changeAbsorb" @scale="scale" @groupSelect="groupSelect" />
+                    ref="canvasFun" @saveJson="saveJson" @changeAbsorb="changeAbsorb" @scale="scale" @groupSelect="groupSelect" @drawWall="drawWall"
+                    @clearWall="clearWall" />
             </el-row>
         </div>
         <div v-show="!floorKey">
@@ -83,6 +89,9 @@ import { ItemColor } from "@persagy-web/big/lib";
 import { SSpaceItem } from "@persagy-web/big/lib/items/floor/SSpaceItem";
 import { SZoneItem } from "@persagy-web/big/lib/items/floor/ZoneItem";
 import { AppModule } from "@/store/modules/app";
+import { watch } from "fs";
+import { SWallItem } from "@persagy-web/big/lib/items/floor/SWallItem";
+import { CustomWall } from "@/utils/graph/CustomWall";
 
 @Component({
     components: { canvasFun, createBSP },
@@ -98,6 +107,7 @@ export default class spaceGraph extends Vue {
         isEdit: false,
         divide: true,
         groupSelect: false,
+        drawWall: false,
     };
     search = ""; //搜索
     zoneDisable = true;
@@ -131,11 +141,10 @@ export default class spaceGraph extends Vue {
         this.canvasLoading = true;
         if (floor.infos && floor.infos.floorMap) {
             this.floor = floor;
-            const url = this.mapBaseUrl + floor.infos.floorMap;
-            if (url == this.floorKey) {
+            if (floor.infos.floorMap == this.floorKey) {
                 this.init(2);
             } else {
-                this.floorKey = this.mapBaseUrl + floor.infos.floorMap;
+                this.floorKey = floor.infos.floorMap;
                 this.init(1);
             }
         } else {
@@ -154,6 +163,7 @@ export default class spaceGraph extends Vue {
             this.scene.selectContainer.clear();
             this.scene.initSpaceColor();
             this.scene.clearCut();
+            this.scene.clearWalls()
             this.zoneDisable = true;
             this.scene.isZoneSelectable = true;
             this.scene.isSpaceSelectable = false;
@@ -176,6 +186,7 @@ export default class spaceGraph extends Vue {
             isEdit: false,
             divide: true,
             groupSelect: true,
+            drawWall: false,
         };
         if (this.$refs.canvasFun) {
             // @ts-ignore
@@ -191,7 +202,7 @@ export default class spaceGraph extends Vue {
         this.clearGraphy();
         this.scene = null;
         console.log(this.floorKey);
-        scene.loadUrl(this.floorKey).then((res) => {
+        scene.loadUrl(this.mapBaseUrl + this.floorKey).then((res) => {
             if (this.view) {
                 this.view.scene = scene;
             }
@@ -259,6 +270,7 @@ export default class spaceGraph extends Vue {
         this.config.isEdit = true;
         this.config.groupSelect = false;
         this.config.divide = true;
+        this.config.drawWall = false;
         if (this.scene) {
             this.scene.isSpaceSelectable = true;
             this.scene.isZoneSelectable = false;
@@ -291,12 +303,27 @@ export default class spaceGraph extends Vue {
             }
         }
     }
-    handleCommand() {}
+    // 下拉菜单
+    handleCommand(command: string) {
+        if (command == "createWall") {
+            // 绘制墙
+            this.config.isEdit = true;
+            this.config.groupSelect = false;
+            this.config.divide = false;
+            this.config.drawWall = true;
+            this.type = 6;
+            if (this.scene) {
+                this.scene.isSpaceSelectable = false;
+                this.scene.isZoneSelectable = false;
+            }
+        }
+    }
     // 编辑业务空间
     refactorBSP() {
         this.config.isEdit = true;
         this.config.groupSelect = false;
         this.config.divide = true;
+        this.config.drawWall = false;
         if (this.scene) {
             this.scene.isZoneSelectable = false;
             this.scene.isSpaceSelectable = true;
@@ -448,6 +475,25 @@ export default class spaceGraph extends Vue {
     }
 
     /**
+     * 生成底图json
+     */
+    saveMap() {
+        if (this.scene) {
+            const json = this.scene.getMapObject()
+            console.log(json);
+        }
+    }
+
+    /**
+     * 画墙
+     */
+    drawWall() {
+        if (this.scene) {
+            this.scene.drawCmd = "wallDraw";
+        }
+    }
+
+    /**
      * 单个计算交集
      */
     calIntersect(zoneObj: any) {
@@ -583,7 +629,14 @@ export default class spaceGraph extends Vue {
     }
     // 保存json
     saveJson() {
-        this.view?.saveFloorJson(`1.json`);
+        try {
+            this.view?.saveFloorJson(
+                `${this.floor.build}-${this.floor.localName}.json`
+            );
+        } catch (err) {
+            console.log(err);
+            this.view?.saveFloorJson(`1.json`);
+        }
     }
     // 切割划分
     divide() {
@@ -617,6 +670,20 @@ export default class spaceGraph extends Vue {
         console.log("changeAbsorb");
     }
 
+    /**
+     * 删除墙
+     */
+    clearWall() {
+        if (this.scene) {
+            if (this.scene.selectContainer.itemList.length) {
+                const item = this.scene.selectContainer.itemList[0];
+                if (item instanceof SWallItem || item instanceof CustomWall) {
+                    this.scene.deleteItem(item)
+                }
+            }
+        }
+    }
+
     @Watch("view.scale", { immediate: true, deep: true })
     onScaleChange(n: number) {
         if (this.$refs.canvasFun) {
@@ -626,6 +693,16 @@ export default class spaceGraph extends Vue {
             this.$refs.canvasFun.sliderVal = s > 1000 ? 1000 : s;
         }
     }
+
+    @Watch("scene.drawCmd", { immediate: true, deep: true })
+    onCmdChange(n: string) {
+        if (!n) {
+            if (this.$refs.canvasFun) {
+                this.$refs.canvasFun.active = "";
+                this.$refs.canvasFun.isSwitch = false;
+            }
+        }
+    }
 }
 </script>
 <style lang="scss">

+ 1 - 0
src/views/maintain/space/index.vue

@@ -209,6 +209,7 @@ export default class spaceIndex extends Vue {
             data.forEach((build) => {
                 floorData.forEach((floor) => {
                     this.floorToMap[floor.id] = floor;
+                    this.floorToMap[floor.id].build = build.label;
                     if (
                         build.value == floor.buildingId &&
                         floor.id &&