Ver código fonte

Merge branch 'master' of http://39.106.8.246:3003/web/wanda-adm

YaolongHan 3 anos atrás
pai
commit
0f148a5138

+ 27 - 18
src/components/public/adm-multi-table.vue

@@ -12,8 +12,7 @@
         >
             <el-table-column prop="date" label="编辑" width="80" align="center" fixed>
                 <template slot-scope="scope">
-                    <span class="el-icon-edit el-input__icon" style="cursor: pointer"
-                          @click="handleEdit(scope.$index, scope.row)"> </span>
+                    <span class="el-icon-edit el-input__icon" style="cursor: pointer" @click="handleEdit(scope.$index, scope.row)"> </span>
                 </template>
             </el-table-column>
             <el-table-column v-for="item in headersStage" :key="item.name" :label="item.name" align="center">
@@ -46,6 +45,8 @@ export default class extends Vue {
     @Prop({ default: Object }) headersStage?: any;
     // 当前页头文字
     @Prop({ default: "" }) currentHeader?: string;
+    // 动态数据是否对表号-功能号做枚举转换
+    @Prop({ default: true }) isDynamicMap?: boolean;
 
     @Emit("handleCurrentEdit")
     handleEdit(index: number, row: any) {
@@ -69,26 +70,35 @@ export default class extends Vue {
      */
     private formatContent(row: any, column: any, cellValue: any) {
         const info = this.headerInfoMap[column.property];
-        if (info && cellValue) { //有值且获取到表头信息
+        // 有值且获取到表头信息
+        if (info && cellValue) {
+            // 动态类型且值不需要做转换
+            if (!this.isDynamicMap && info.category !== "STATIC") {
+                return cellValue;
+            }
             const dataSource = info?.dataSource ? info.dataSource : [];
-            if (info.dataType === "ENUM" || info.dataType === "BOOLEAN") { //内容为单选枚举和布尔类型
+            // 内容为单选枚举和布尔类型
+            if (info.dataType === "ENUM" || info.dataType === "BOOLEAN") {
                 const text = dataSource.find((item: any) => {
                     return item.code === cellValue;
                 })?.name;
-                return text;
+                return text ? text : cellValue;
             } else if (info.dataType === "MENUM" && cellValue instanceof Array && cellValue.length) { //内容为多选枚举且值为数组
-                const textList = dataSource.map((item: any) => {
-                    if (
-                        cellValue.find((value: string) => {
-                            return item?.code === value;
-                        })
-                    ) {
-                        return item?.name;
-                    }
-                }).filter((item: any) => item).join(",");
-                return textList;
-            } else if (info.dataType === "ATTACHMENT") { // 内容为附件类型
-                return cellValue.length + '个' || ''
+                const textList = dataSource
+                    .map((item: any) => {
+                        if (
+                            cellValue.find((value: string) => {
+                                return item?.code === value;
+                            })
+                        ) {
+                            return item?.name;
+                        }
+                    })
+                    .filter((item: any) => item)
+                    .join(",");
+                return textList ? textList : cellValue;
+            } else if (info.dataType === "ATTACHMENT") { //内容为附件类型
+                return cellValue.length + "个" || "";
             } else {
                 return cellValue;
             }
@@ -102,7 +112,6 @@ export default class extends Vue {
             if (this.tableDom?.doLayout) this.tableDom.doLayout();
         });
     }
-
 }
 </script>
 

+ 7 - 0
src/components/public/adm-search.vue

@@ -22,6 +22,13 @@ export default class extends Vue {
     private handleSearch() {
         return this.input
     }
+
+    /**
+     * 修改数据框内容
+     */
+    setInput(val: string) {
+        this.input = val;
+    }
 }
 </script>
 

+ 1 - 1
src/layout/components/Navbar/index.vue

@@ -76,7 +76,7 @@ export default class extends Vue {
     position: relative;
     background-color: #2b3643;
     box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
-    z-index: 1002;
+    z-index: 999;
 
     .title {
         float: left;

+ 1 - 0
src/layout/index.vue

@@ -75,6 +75,7 @@ export default class extends mixins(ResizeMixin) {
     position: relative;
     overflow-y: hidden;
     padding: 0 10px 10px;
+    margin-right: 10px;
     background: #F1F2F3;
 }
 

+ 268 - 105
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,65 +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.data = {
-            ElementType: "Wall",
-            Id: +new Date().toString(),
-            Width: 200.0,
-            SourceId: +new Date().toString()
-        }
-    }
-
+        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, [
@@ -97,7 +88,6 @@ export class CustomWall extends SGraphStyleItem {
                 index
             ]);
         } else {
-            // 否则
             this.pointList.push(p);
             this.recordAction(SGraphPointListInsert, [this.pointList, p]);
         }
@@ -118,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
@@ -140,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,
@@ -174,7 +297,6 @@ export class CustomWall extends SGraphStyleItem {
                 this.pointList[i].x,
                 this.pointList[i].y
             );
-            // 当前距离小于最短距离
             if (dis < len) {
                 len = dis;
                 this.curIndex = i;
@@ -189,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(
@@ -210,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) {
@@ -236,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;
             }
         }
@@ -263,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;
                 }
@@ -315,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,
@@ -326,11 +439,11 @@ export class CustomWall extends SGraphStyleItem {
                     this.pointList[i].y
                 )
             );
-            // 点在吸附范围内
             if (PTL.MinDis < this.sceneDis) {
                 return true;
             }
         }
+
         return false;
     }
 
@@ -338,7 +451,6 @@ export class CustomWall extends SGraphStyleItem {
      * 撤销操作
      */
     undo(): void {
-        // 非正常态
         if (this._status != SItemStatus.Normal) {
             this.undoStack.undo();
         }
@@ -348,7 +460,6 @@ export class CustomWall extends SGraphStyleItem {
      * 重做操作
      */
     redo(): void {
-        // 非正常态
         if (this._status != SItemStatus.Normal) {
             this.undoStack.redo();
         }
@@ -358,42 +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 {
-        this.data.OutLine = [];
-        const temp = this.pointList.map(t => {
-            return {
-                X: t.x,
-                Y: -t.y,
-                Z: 0.0
-            }
-        })
-        this.data.OutLine.push(temp)
         return this.data;
     }
 
     /**
      * Item 绘制操作
      *
-     * @param painter   绘制对象
+     * @param painter 绘制对象
      */
     onDraw(painter: SPainter): void {
         // 缓存场景长度
         this.sceneDis = painter.toPx(this.dis);
-
-        painter.drawPolyline(this.pointList)
+        // 创建状态
+        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);
+        }
     }
 }

+ 68 - 11
src/utils/graph/DivideFloorScene.ts

@@ -10,6 +10,9 @@ 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  */
@@ -57,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);
@@ -97,8 +135,8 @@ export class DivideFloorScene extends FloorScene {
                 let item = new CustomWall(null, point)
                 item.status = SItemStatus.Create;
                 this.addItem(item);
-                console.log(2312312);
-                
+                this.customWall.push(item)
+                item.connect("finishCreated", this, this.finishCreated)
                 this.grabItem = item;
                 return true;
             }
@@ -504,4 +542,23 @@ export class DivideFloorScene extends FloorScene {
             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; // 当前的灵敏度

+ 18 - 0
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 {

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

@@ -29,7 +29,10 @@
         <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.divide||config.drawWall)" @click="clearDivide">
+        <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>
         <div @click="reduce">
@@ -132,6 +135,11 @@ export default class canvasFun extends Vue {
         }
         this.scale(this.sliderVal);
     }
+    // 删除墙
+    clearWall() {
+        this.active = "";
+        this.$emit("clearWall");
+    }
 }
 </script>
 <style lang="scss" scoped>

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

@@ -58,8 +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"
-                    @drawWall="drawWall" />
+                    ref="canvasFun" @saveJson="saveJson" @changeAbsorb="changeAbsorb" @scale="scale" @groupSelect="groupSelect" @drawWall="drawWall"
+                    @clearWall="clearWall" />
             </el-row>
         </div>
         <div v-show="!floorKey">
@@ -89,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 },
@@ -160,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;
@@ -473,7 +477,12 @@ export default class spaceGraph extends Vue {
     /**
      * 生成底图json
      */
-    saveMap() {}
+    saveMap() {
+        if (this.scene) {
+            const json = this.scene.getMapObject()
+            console.log(json);
+        }
+    }
 
     /**
      * 画墙
@@ -620,10 +629,6 @@ export default class spaceGraph extends Vue {
     }
     // 保存json
     saveJson() {
-        console.log(this.scene);
-
-        this.scene?.getMapObject();
-        return;
         try {
             this.view?.saveFloorJson(
                 `${this.floor.build}-${this.floor.localName}.json`
@@ -665,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) {
@@ -674,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">

+ 11 - 1
src/views/maintain/system/index.vue

@@ -84,7 +84,7 @@ export default class extends Vue {
     list = [];
     // 信息点集合(表头)
     all = [];
-    codeToDataSource = {};
+    codeToDataSource: any = {};
     // 系统类值
     systemType = "";
     // 系统名称 label值
@@ -282,6 +282,16 @@ export default class extends Vue {
         this.all = arr;
         arr.forEach((item: any) => {
             let i = ["localName", "localId"];
+            if (item.dataSource) {
+                try {
+                    this.codeToDataSource[item.code] = {}
+                    item.dataSource.forEach((dic: any) => {
+                        this.codeToDataSource[item.code][dic.code] = dic.name;
+                    })
+                } catch (e) {
+                    console.log(e);
+                }
+            }
             if (i.includes(item.path)) {
                 basicInfos.push(item);
             } else {

+ 283 - 0
src/views/scene/tiepoint/components/equipTab/index.vue

@@ -0,0 +1,283 @@
+<template>
+    <div class="tab-content">
+        <div class="search">
+            <el-cascader
+                :options="deviceOptions"
+                clearable
+                v-model="deviceList"
+                :props="optionProps"
+                @change="handleChangeDevice"
+                class="item"
+            ></el-cascader>
+            <admSearch @SearchValue="searchValue" class="item" />
+        </div>
+        <div v-loading="loading" style="height: calc(100% - 100px); padding: 0 12px; position: relative">
+            <template style="height: 100%" v-if="tableData.length">
+                <admMultiTable
+                    @handleCurrentEdit="handleCurrentEdit"
+                    :isDynamicMap="false"
+                    :currentHeader="currentHeader"
+                    :headersStage="headersStage"
+                    :tableData="tableData"
+                />
+                <Pagination
+                    v-if="tableData.length"
+                    :paginationList="paginationList"
+                    @handleCurrentChange="handleCurrentChange"
+                    @handleSizeChange="handleSizeChange"
+                />
+            </template>
+            <div v-else class="void align">
+                <svg-icon name="void" :width="String(120)" :height="String(123)" />
+                <p class="void-title">暂无内容</p>
+                <p class="void-tips">可点击左上角筛选</p>
+            </div>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import { Vue, Component } from "vue-property-decorator";
+import { allDevice, dictInfo } from "@/api/equipComponent";
+import { queryEquip, updateEquip } from "@/api/datacenter";
+import { AdmMultiTable, AdmSearch, Pagination } from "@/views/maintain/components/index";
+import { UserModule } from "@/store/modules/user";
+
+@Component({
+    name: "EquipTab",
+    components: {
+        AdmMultiTable,
+        AdmSearch,
+        Pagination,
+    },
+})
+export default class EquipTab extends Vue {
+    // 项目id
+    private get projectId(): string {
+        return UserModule.projectId;
+    }
+
+    // 设备类型
+    private get deviceType(): string {
+        const length = this.deviceList.length;
+        return length ? this.deviceList[length - 1] : "";
+    }
+
+    // 设备关键字
+    private keyWord = "";
+    // 设备类下拉绑定值
+    private deviceList: any = [];
+    // 设备筛选
+    private deviceOptions: any[] = [];
+    // 下拉框映射
+    private optionProps: any = {
+        value: "code",
+        label: "name",
+        children: "children",
+    };
+    // 表格数据加载loading
+    private loading = false;
+    // 表格数据
+    private tableData: any[] = [];
+    // 阶段信息
+    private currentHeader = "运维阶段维护";
+    // 表头阶段信息结合
+    private headersStage: any = {};
+    // 信息点集合(表头)
+    private all: any = [];
+    // 输入类型选项
+    private codeToDataSource: any = {};
+    // 分页
+    private paginationList = {
+        page: 1,
+        size: 50,
+        sizes: [10, 30, 50, 100, 150, 200],
+        total: 0,
+    };
+
+    // created钩子
+    created() {
+        this.getDeviceOptions();
+    }
+
+    /**
+     * 设备类数据
+     */
+    private async getDeviceOptions() {
+        const res = await allDevice({});
+        if (res.result === "success") {
+            this.deviceOptions = res.content;
+        }
+    }
+
+    /**
+     * 获取设备数据(信息点和实例数据)
+     */
+    private getEquipData() {
+        if (this.deviceType) {
+            this.loading = true;
+            let param = {
+                category: this.deviceType,
+            };
+            let param2 = {
+                filters: `classCode='${this.deviceType}'`,
+                pageNumber: this.paginationList.page,
+                pageSize: this.paginationList.size,
+                orders: "createTime desc, id asc",
+                projectId: this.projectId,
+            };
+            if (this.keyWord != "") {
+                param2.filters += `;codeName contain '${this.keyWord}' or systemCategory contain '${this.keyWord}' or bimTypeId contain '${this.keyWord}' or localId contain '${this.keyWord}'`;
+            }
+            let promise = new Promise((resolve) => {
+                dictInfo(param).then((res: any) => {
+                    resolve(res);
+                });
+            });
+            let promise2 = new Promise((resolve) => {
+                queryEquip(param2).then((res: any) => {
+                    resolve(res);
+                });
+            });
+            Promise.all([promise, promise2]).then((res: any[]) => {
+                this.loading = false;
+                // 获取运维阶段名称
+                this.currentHeader = res[0]?.dictStages.find((item: any) => {
+                    return item.code === "moms";
+                })?.name;
+                this.headersStage = this.informationArrangement(res[0]); // 重组表头数据
+                this.tableData = res[1]?.content ? res[1].content : []; // 主体数据
+                this.paginationList.total = res[1]?.total ? res[1].total : 0;
+            });
+        } else {
+            this.tableData = [];
+        }
+    }
+
+    /**
+     * 获取系统实例数据
+     */
+    private async getExampleData() {
+        if (this.deviceType) {
+            this.loading = true;
+            let params = {
+                filters: `classCode='${this.deviceType}'`,
+                pageNumber: this.paginationList.page,
+                pageSize: this.paginationList.size,
+                orders: "createTime desc, id asc",
+                projectId: this.projectId,
+            };
+            if (this.keyWord != "") {
+                params.filters += `;codeName contain '${this.keyWord}' or systemCategory contain '${this.keyWord}' or bimTypeId contain '${this.keyWord}' or localId contain '${this.keyWord}'`;
+            }
+            const res = await queryEquip(params);
+            if (res.result === "success") {
+                this.tableData = res?.content ? res.content : []; // 主体数据
+                this.paginationList.total = res?.total ? res.total : 0;
+                this.loading = false;
+            }
+        } else {
+            this.tableData = [];
+        }
+    }
+
+    /**
+     * 信息点重组
+     */
+    private informationArrangement(data: any): any {
+        if (data?.basicInfos && data?.dictStages) {
+            const base: any[] = [];
+            data.dictStages.forEach((item: any) => {
+                if (this.currentHeader === item.name) {
+                    item?.infos.forEach((val: any) => {
+                        base.push(val);
+                    });
+                }
+            });
+            // 信息点集合
+            this.all = [...data.basicInfos, ...base];
+            this.codeToDataSource = {};
+            this.all.forEach((item: any) => {
+                if (item.dataSource) {
+                    try {
+                        this.codeToDataSource[item.code] = {};
+                        item.dataSource.forEach((dic: any) => {
+                            this.codeToDataSource[item.code][dic.code] = dic.name;
+                        });
+                    } catch (e) {
+                        console.log(e);
+                    }
+                }
+            });
+            return {
+                basicInfos: {
+                    name: "基础信息台账",
+                    data: data.basicInfos,
+                },
+                dictStages: {
+                    name: this.currentHeader,
+                    data: base,
+                },
+            };
+        } else {
+            return {};
+        }
+    }
+
+    /**
+     * 切换设备类型
+     */
+    private handleChangeDevice() {
+        this.getEquipData();
+    }
+
+    /**
+     * 检索设备关键字
+     */
+    private searchValue(val: string) {
+        this.keyWord = val;
+        this.getExampleData();
+    }
+
+    /**
+     * 切换页码
+     */
+    private handleCurrentChange(val: number) {
+        this.paginationList.page = val;
+        this.getExampleData();
+    }
+
+    /**
+     * 切换每页显示数量
+     */
+    private handleSizeChange(val: number) {
+        this.paginationList.size = val;
+        this.getExampleData();
+    }
+}
+</script>
+<style lang="scss" scoped>
+.tab-content {
+    height: 100%;
+    border: 1px solid #e1e7ea;
+    border-top: none;
+    padding-bottom: 12px;
+
+    .search {
+        padding: 12px;
+        & > .item {
+            margin-right: 12px;
+        }
+    }
+}
+// 数据暂未
+.void {
+    margin-top: 200px;
+}
+.align {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    flex-wrap: wrap;
+}
+</style>

+ 307 - 0
src/views/scene/tiepoint/components/systemTab/index.vue

@@ -0,0 +1,307 @@
+<template>
+    <div class="tab-content">
+        <div class="search">
+            <el-cascader
+                :options="systemOptions"
+                ref="systemCascader"
+                clearable
+                v-model="systemList"
+                :props="optionProps"
+                @change="handleChangeSystem"
+                class="item"
+            ></el-cascader>
+            <admSearch @SearchValue="searchValue" class="item" />
+        </div>
+        <div v-loading="loading" style="height: calc(100% - 100px); padding: 0 12px; position: relative;">
+            <template style="height: 100%" v-if="tableData.length">
+                <admMultiTable
+                    @handleCurrentEdit="handleCurrentEdit"
+                    :isDynamicMap="false"
+                    :currentHeader="currentHeader"
+                    :headersStage="headersStage"
+                    :tableData="tableData"
+                />
+                <Pagination
+                    v-if="tableData.length"
+                    :paginationList="paginationList"
+                    @handleCurrentChange="handleCurrentChange"
+                    @handleSizeChange="handleSizeChange"
+                />
+            </template>
+            <div v-else class="void align">
+                <svg-icon name="void" :width="String(120)" :height="String(123)" />
+                <p class="void-title">暂无内容</p>
+                <p class="void-tips">可点击左上角筛选</p>
+            </div>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import { Vue, Component, Ref } from "vue-property-decorator";
+import { allSystem } from "@/api/equipComponent";
+import { dictQuery, querySystem } from "@/api/datacenter";
+import { AdmMultiTable, AdmSearch, Pagination } from "@/views/maintain/components/index";
+import { UserModule } from "@/store/modules/user";
+import { ElCascader } from "element-ui/types/cascader";
+
+@Component({
+    name: "SystemTab",
+    components: {
+        AdmMultiTable,
+        AdmSearch,
+        Pagination,
+    },
+})
+export default class SystemTab extends Vue {
+    // 系统类筛选框
+    @Ref("systemCascader") readonly systemCascader!: ElCascader;
+
+    // 项目id
+    private get projectId(): string {
+        return UserModule.projectId;
+    }
+
+    // 系统类型
+    private get systemType(): string {
+        const length = this.systemList.length;
+        return length ? this.systemList[length - 1] : "";
+    }
+
+    // 系统关键字
+    private keyWord = "";
+    // 系统类下拉绑定值
+    private systemList: any = [];
+    // 系统类名称
+    private systemLabel = "";
+    // 系统筛选
+    private systemOptions: any[] = [];
+    // 下拉框映射
+    private optionProps: any = {
+        value: "code",
+        label: "name",
+        children: "children",
+    };
+    // 表格数据加载loading
+    private loading = false;
+    // 表格数据
+    private tableData: any[] = [];
+    // 阶段信息
+    private currentHeader = "运维阶段";
+    // 表头阶段信息结合
+    private headersStage: any = {};
+    // 信息点集合(表头)
+    private all: any = [];
+    // 输入类型选项
+    private codeToDataSource: any = {};
+
+    // 分页
+    private paginationList = {
+        page: 1,
+        size: 50,
+        sizes: [10, 30, 50, 100, 150, 200],
+        total: 0,
+    };
+
+    // created钩子
+    created() {
+        this.getSystemOptions();
+    }
+
+    /**
+     * 系统类数据
+     */
+    private async getSystemOptions() {
+        const res = await allSystem({});
+        if (res.result === "success") {
+            this.systemOptions = res.content;
+        }
+    }
+
+    /**
+     * 获取系统数据(信息点和系统实例)
+     */
+    private getSystemData() {
+        if (this.systemType) {
+            //系统类型不为空
+            // @ts-ignore
+            const systemLabel = this.systemCascader.getCheckedNodes()[0].pathLabels;
+            this.systemLabel = systemLabel[1];
+            this.loading = true;
+            let param = {
+                type: this.systemType,
+                orders: "sort asc, name desc",
+            };
+            let param2 = {
+                filters: `classCode='${this.systemType}'`,
+                pageNumber: this.paginationList.page,
+                pageSize: this.paginationList.size,
+                orders: "createTime asc, id asc",
+                projectId: this.projectId,
+            };
+            if (this.keyWord != "") {
+                param2.filters += `;localName contain '${this.keyWord}' or localId contain '${this.keyWord}'`;
+            }
+            let promise = new Promise((resolve) => {
+                dictQuery(param).then((res: any) => {
+                    resolve(res);
+                });
+            });
+            let promise2 = new Promise((resolve) => {
+                querySystem(param2).then((res: any) => {
+                    resolve(res);
+                });
+            });
+            Promise.all([promise, promise2]).then((res: any[]) => {
+                let tableData = [];
+                this.loading = false;
+                // 类型下信息点,重组数据
+                const { basicInfos, dictStages } = this.informationArrangement(res[0].content);
+                this.headersStage = {
+                    basicInfos: {
+                        name: "基础信息台账",
+                        data: basicInfos,
+                    },
+                    dictStages: {
+                        name: "运维阶段",
+                        data: dictStages,
+                    },
+                };
+                this.paginationList.total = res[1]?.total ? res[1].total : 0;
+                tableData = res[1]?.content ? res[1].content : []; // 主体数据
+                // 添加系统分类
+                this.tableData = tableData.map((item: any) => {
+                    item = { ...item, classification: this.systemLabel };
+                    return item;
+                });
+            });
+        } else {
+            //系统类型为空
+            this.tableData = [];
+        }
+    }
+
+    /**
+     * 获取系统实例数据
+     */
+    private async getExampleData() {
+        if (this.systemType) {
+            //系统类型不为空
+            this.loading = true;
+            let params = {
+                filters: `classCode='${this.systemType}'`,
+                pageNumber: this.paginationList.page,
+                pageSize: this.paginationList.size,
+                orders: "createTime asc, id asc",
+                projectId: this.projectId,
+            };
+            if (this.keyWord != "") {
+                params.filters = `${params.filters};localName contain '${this.keyWord}' or localId contain '${this.keyWord}'`;
+            }
+
+            const res = await querySystem(params);
+            if (res.result === "success") {
+                let tableData: any[] = [];
+                this.loading = false;
+                this.paginationList.total = res?.total ? res.total : 0;
+                tableData = res?.content ? res.content : []; // 主体数据
+                // 添加系统分类
+                this.tableData = tableData.map((item: any) => {
+                    item = { ...item, classification: this.systemLabel };
+                    return item;
+                });
+            }
+        } else {
+            //系统类型为空
+            this.tableData = [];
+        }
+    }
+
+    /**
+     * 信息点重组
+     */
+    private informationArrangement(arr: []): any {
+        let basicInfos = [{ path: "classification", name: "系统分类" }],
+            dictStages: any[] = [];
+        this.all = arr;
+        arr.forEach((item: any) => {
+            let i = ["localName", "localId"];
+            if (item?.dataSource) {
+                try {
+                    this.codeToDataSource[item.code] = {};
+                    item.dataSource.forEach((dic: any) => {
+                        this.codeToDataSource[item.code][dic.code] = dic.name;
+                    });
+                } catch (e) {
+                    console.log(e);
+                }
+            }
+            if (i.includes(item.path)) {
+                basicInfos.push(item);
+            } else {
+                dictStages.push(item);
+            }
+        });
+        return {
+            basicInfos,
+            dictStages,
+        };
+    }
+
+    /**
+     * 切换系统类型
+     */
+    private handleChangeSystem() {
+        this.getSystemData();
+    }
+
+    /**
+     * 检索系统关键字
+     */
+    private searchValue(val: string) {
+        this.keyWord = val;
+        this.getExampleData();
+    }
+
+    /**
+     * 切换页码
+     */
+    private handleCurrentChange(val: number) {
+        this.paginationList.page = val;
+        this.getExampleData();
+    }
+
+    /**
+     * 切换每页显示数量
+     */
+    private handleSizeChange(val: number) {
+        this.paginationList.size = val;
+        this.getExampleData();
+    }
+}
+</script>
+<style lang="scss" scoped>
+.tab-content {
+    height: 100%;
+    border: 1px solid #e1e7ea;
+    border-top: none;
+    padding-bottom: 12px;
+
+    .search {
+        padding: 12px;
+        & > .item {
+            margin-right: 12px;
+        }
+    }
+}
+// 数据暂未
+.void {
+    margin-top: 200px;
+}
+.align {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    flex-wrap: wrap;
+}
+</style>

+ 66 - 6
src/views/scene/tiepoint/index.vue

@@ -1,12 +1,72 @@
 <template>
-    <div>绑点</div>
+    <div class="adm-tiepoint">
+        <div class="tabs">
+            <el-tabs v-model="activeName" type="card" @tab-click="tabChange">
+                <el-tab-pane label="设备" name="equip">
+                    <equip-tab></equip-tab>
+                </el-tab-pane>
+                <el-tab-pane label="系统" name="system">
+                    <system-tab></system-tab>
+                </el-tab-pane>
+            </el-tabs>
+        </div>
+    </div>
 </template>
+<script lang="ts">
+import { Vue, Component } from "vue-property-decorator";
+import EquipTab from "./components/equipTab/index.vue";
+import SystemTab from "./components/systemTab/index.vue";
+import { UserModule } from "@/store/modules/user";
 
-<script>
-export default {
-    name: "index"
+@Component({
+    name: "TiePoint",
+    components: {
+        EquipTab,
+        SystemTab,
+    },
+})
+export default class tiePoint extends Vue {
+    // 项目id
+    private get projectId(): string {
+        return UserModule.projectId;
+    }
+
+    // 当前选中的tab
+    private activeName = "equip";
+
+    /**
+     * 切换Tab(设备/系统),初始化数据
+     */
+    private tabChange() {
+        console.log(this.activeName);
+    }
 }
 </script>
-
-<style scoped>
+<style lang="scss" scoped>
+.adm-tiepoint {
+    background: #fff;
+    padding: 12px;
+    height: 100%;
+    .tabs {
+        position: relative;
+        height: 100%;
+        ::v-deep .el-tabs {
+            height: 100%;
+        }
+        ::v-deep .el-tabs__header {
+            margin: 0;
+        }
+        ::v-deep .el-tabs__content {
+            height: calc(100% - 41px);
+        }
+        ::v-deep .el-tab-pane {
+            height: 100%;
+        }
+    }
+    ::v-deep .adm-pagination {
+        right: 10px;
+        position: absolute;
+        bottom: -45px;
+    }
+}
 </style>