vue项目用antv/g6做网络拓扑图

前言:
本人公司要求我制作网络拓扑图编辑工具,现在阶段功能研究制作完成,我发布的内容仅供互相学习参考,一切产生的后果与我无关。本人用的是vue

先上视频
vue项目用antv/g6做网络拓扑图

<template>
  <div class="sketchBox">
    <!-- 鼠标移入时展示 -->
    <div class="contextmenuBoxHover" ref="mouseHover">
      <div class="mgt-5">
        <span class="mgl-5 mgr-5">设备编号:</span>
        <span v-html="equipMentObject.relevanceEquipId"></span>
      </div>
      <div>
        <span class="mgl-5 mgr-5">设备名称:</span>
        <span v-html="equipMentObject.relevanceEquipName"></span>
      </div>
      <div>
        <span class="mgl-5 mgr-5">设备类型:</span>
        <span v-html="equipMentObject.relevanceEquipType"></span>
      </div>
    </div>
    <!-- 右键节点 -->
    <div :class="isSketchEdit?'contextmenuBoxNode':'contextmenuBoxNodeNoEdit'" ref="contextmenuBox">
      <div class="contextmenuBox_li mousehand" v-if="isSketchEdit">
        <i class="el-icon-top mgl_10 mgr_10"></i>
        <span>层级前置</span>
      </div>
      <div class="contextmenuBox_li mousehand" v-if="isSketchEdit">
        <i class="el-icon-bottom mgl_10 mgr_10"></i>
        <span>层级后置</span>
      </div>
      <div class="contextmenuBox_li mousehand">
        <i class="el-icon-search mgl_10 mgr_10"></i>
        <span>查看设备</span>
      </div>
      <div class="contextmenuBox_li mousehand" v-if="isSketchEdit">
        <i class="el-icon-edit mgl_10 mgr_10"></i>
        <span>编辑节点</span>
      </div>
      <div class="contextmenuBox_li mousehand" v-if="isSketchEdit">
        <i class="el-icon-connection mgl_10 mgr_10"></i>
        <span>关联绑定</span>
      </div>
      <div class="contextmenuBox_li mousehand" v-if="isSketchEdit">
        <i class="el-icon-delete mgl_10 mgr_10"></i>
        <span>删除节点</span>
      </div>
    </div>
    <!-- 右键线段 -->
    <div class="contextmenuBoxLine" ref="contextmenuLineBox">
      <div class="contextmenuBox_li mousehand">
        <i class="el-icon-edit mgl_10 mgr_10"></i>
        <span>编辑连线</span>
      </div>
      <div class="contextmenuBox_li mousehand">
        <i class="el-icon-delete mgl_10 mgr_10"></i>
        <span>删除线段</span>
      </div>
    </div>
    <!-- 全局右键节点 -->
    <div class="contextmenuBoxNodeAll" ref="contextmenuBoxAll">
      <div class="contextmenuBox_li" @click="goBack1" :class="undoList.length>0?'mousehand':'no_cursor'">
        <i class="el-icon-back mgl_10 mgr_10"></i>
        <span>回退</span>
      </div>
      <div class="contextmenuBox_li" @click="goBack2" :class="redoList.length>0?'mousehand':'no_cursor'">
        <i class="el-icon-right mgl_10 mgr_10"></i>
        <span>返回</span>
      </div>
      <div class="contextmenuBox_li mousehand" @click="goDelete">
        <i class="el-icon-document-delete mgl_10 mgr_10"></i>
        <span>清空</span>
      </div>
      <div class="contextmenuBox_li mousehand" @click="goDocument">
        <i class="el-icon-document mgl_10 mgr_10"></i>
        <span>查看JSON</span>
      </div>
      <div class="contextmenuBox_li mousehand" @click="goRefresh">
        <i class="el-icon-refresh mgl_10 mgr_10"></i>
        <span>居中显示</span>
      </div>
      <div class="contextmenuBox_li mousehand" @click="goDeletePage">
        <i class="el-icon-delete mgl_10 mgr_10"></i>
        <span>删除</span>
      </div>
      <div class="contextmenuBox_li mousehand" @click="goBack">
        <i class="el-icon-switch-button mgl_10 mgr_10"></i>
        <span>关闭</span>
      </div>
      <div class="contextmenuBox_li mousehand" @click="goSaveSketch">
        <i class="el-icon-success mgl_10 mgr_10"></i>
        <span>保存</span>
      </div>
    </div>
    <!-- 编辑线段描述 -->
    <div class="editorLineBox" ref="editorLineBoxRef">
      <el-input v-model="sketchObject.label" size="mini" clearable style="width:200px;">
        <el-button style="width:50px;padding:0px;" slot="append" @click="setEditorLineText">确认</el-button>
      </el-input>
    </div>
    <div id="mountNode" ref="mountNode"></div>
    <div class="sketchBoxMove" v-if="!isSketchEdit">
      <div class="df-c mgt-10">
        <div class="df-a sketchHeight">
          <div class="mgl_10 sketchBoxTitle">拓扑名称:</div>
          <el-input v-model="topologyListObject.topologyName" size="mini" disabled clearable style="width:120px;"></el-input>
        </div>
        <div class="df-a sketchHeight">
          <div class="mgl_10 sketchBoxTitle">拓扑类型:</div>
          <el-select v-model="topologyListObject.topologyType" disabled placeholder="请选择拓扑图类型" size="mini" class="mgr-10" style="width:120px;" clearable>
            <el-option v-for="item in topologyTypeList" :key="item.id" :label="item.label" :value="item.id">
            </el-option>
          </el-select>
        </div>
        <div class="df-a sketchHeight">
          <div class="mgl_10 sketchBoxTitle">显示网格:</div>
          <el-switch v-model="gridShow" @change='switchChange' active-color="#01bbd2" inactive-color="#0091a6">
          </el-switch>
        </div>
        <div class="df-a sketchHeight">
          <div class="mgl_10 sketchBoxTitle">查看JSON:</div>
          <el-button type="primary" circle size="mini" icon="el-icon-document" @click="goDocument"></el-button>
        </div>
        <div class="df-aj btnBoxMoveCss">
          <el-button type="primary" size="mini" @click="goBackNoEdit">关闭</el-button>
        </div>
      </div>
    </div>
    <!-- 左侧 -->
    <div class="monitoringLeft" v-if="isSketchEdit">
      <!-- <div class="df-c show_right2" :style="leftDrawer ? 'left:100%;' : 'left:0%;'">
        <div class="show_left df-a" @click="showLeft">
          <i :class="leftDrawer ? 'el-icon-arrow-left' : 'el-icon-arrow-right'"></i>
        </div>
      </div> -->
      <transition name="fadeleft">
        <div v-show="leftDrawer" class="monitoringRightFade addStyle">
          <sketch-collapse @setShape='setShapeCollapse'></sketch-collapse>
        </div>
      </transition>
    </div>
    <!-- 右侧 -->
    <div class="monitoringRight" v-if="rightDrawer">
      <div class="df-c show_right2" :style="rightDrawer ? 'right:105%;' : 'right:4.5%;'">
      </div>
      <transition name="faderight">
        <div v-if="rightDrawer" class="monitoringRightFade">
          <div class="show_rightClose df-aj mousehand" @click="deleteClose">
            <i class="el-icon-close sketchCloseIcon"></i>
          </div>
          <el-form aria-label="100px" class="mgl_20 mgt_30 sketchPageForm" style="position: relative;">
            <el-form-item label="节点名称:" style="width:270px;">
              <el-input v-model="sketchObject.label" @change='sketchObjectChange' clearable class="input-with-select" size="mini">
              </el-input>
            </el-form-item>
            <el-form-item label="节点长宽:" style="width:270px;">
              <el-input-number v-model.number="sketchObject.size[0]" controls-position="right" @change='sketchObjectChange("size[0]")' size="mini"></el-input-number>
              <span class="el-icon-connection connectionCss mousehand mgl-5 mgr-5" @click="connectionShow = !connectionShow" :class="connectionShow?'connectionClickTrue':''"></span>
              <el-input-number v-model.number="sketchObject.size[1]" controls-position="right" @change='sketchObjectChange("size[1]")' size="mini"></el-input-number>
            </el-form-item>
            <el-form-item label="节点类型:" style="width:270px;" class="mgb_10">
              <el-input v-model="sketchObject.equipType" disabled class="input-with-select" size="mini">
              </el-input>
            </el-form-item>
            <el-form-item label="关联状态:" style="width:270px;">
              <el-button type="primary" v-show="sketchObject.relevance.relevanceEquipName != ''" size="mini" @click="yesRelevanceClick">已关联</el-button>
              <el-button type="danger" v-show="sketchObject.relevance.relevanceEquipName == ''" size="mini" @click="noRelevanceClick">未关联</el-button>
            </el-form-item>
            <el-form-item label="关联名称:" style="width:270px;">
              <el-input v-model="sketchObject.relevance.relevanceName" disabled clearable class="input-with-select" size="mini">
              </el-input>
            </el-form-item>
          </el-form>
          <div class="df-aj btnBoxCss">
            <el-button type="primary" size="mini" @click="deleteClose">取消</el-button>
            <el-button type="danger" size="mini" @click="deleteClose">确认</el-button>
          </div>
        </div>
      </transition>
    </div>
    <div class="monitoringRight" v-if="rightDrawerLine">
      <div class="df-c show_right2" :style="rightDrawerLine ? 'right:105%;' : 'right:4.5%;'">
      </div>
      <transition name="faderight">
        <div v-if="rightDrawerLine" class="monitoringRightFade">
          <div class="show_rightClose df-aj mousehand" @click="deleteCloseLine">
            <i class="el-icon-close sketchCloseIcon"></i>
          </div>
          <el-form aria-label="100px" class="mgl_20 mgt_30">
            <el-form-item label="连线描述:" style="width:270px;">
              <el-input v-model="sketchObjectLine.label" @change='sketchObjectLineChange' clearable class="input-with-select" size="mini">
              </el-input>
            </el-form-item>
            <el-form-item label="连线类型:" style="width:270px;">
              <el-select v-model="sketchObjectLine.linkType" placeholder="请选择连线类型" size="mini" class="mgr-10" clearable>
                <el-option v-for="item in lineTypeLine" :key="item.id" :label="item.label" :value="item.id">
                </el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="连线方式:" style="width:270px;" class="mgb_10">
              <el-select v-model="sketchObjectLine.direction" @change='setLineDirection' placeholder="请选择连线方式" size="mini" class="mgr-10" clearable>
                <el-option v-for="item in lineDirectionLine" :key="item.id" :label="item.label" :value="item.id">
                </el-option>
              </el-select>
            </el-form-item>
          </el-form>
          <div class="df-aj btnBoxCss">
            <el-button type="primary" size="mini" @click="deleteCloseLine">取消</el-button>
            <el-button type="danger" size="mini" @click="deleteCloseLine">确认</el-button>
          </div>
        </div>
      </transition>
    </div>
    <!-- 中间添加 -->
    <div class="monitoringCenter df-a df-sp" v-if="isSketchEdit">
      <div class="df-a">
        <div class="mgl_20" style="color:red;margin-right:2px;">*</div>
        <div>拓扑图名称:</div>
        <el-input v-model="topologyListObject.topologyName" size="mini" clearable style="width:220px;"></el-input>
        <div class="mgl_10">拓扑图类型:</div>
        <el-select v-model="topologyListObject.topologyType" placeholder="请选择类型" size="mini" class="mgr-10" style="width:110px;" clearable>
          <el-option v-for="item in topologyTypeList" :key="item.id" :label="item.label" :value="item.id">
          </el-option>
        </el-select>
      </div>
      <div class="mgr-20 df-a">
        <span>显示网格</span>
        <el-switch class="mgl-10" v-model="gridShow" @change='switchChange' active-color="#01bbd2" inactive-color="#0091a6">
        </el-switch>
        <span class="mgr-10 mgl-10 geClss">|</span>
        <el-tooltip effect="dark" content="查看JSON" placement="bottom">
          <el-button type="primary" size="mini" icon="el-icon-document" @click="goDocument"></el-button>
        </el-tooltip>
        <el-tooltip effect="dark" content="居中显示" placement="bottom">
          <el-button type="primary" size="mini" icon="el-icon-refresh" @click="goRefresh"></el-button>
        </el-tooltip>
        <el-tooltip effect="dark" content="清空" placement="bottom">
          <el-button type="primary" size="mini" icon="el-icon-document-delete" @click="goDelete"></el-button>
        </el-tooltip>
        <el-tooltip effect="dark" content="回退" placement="bottom">
          <el-button type="primary" size="mini" :disabled='undoList.length>0?false:true' icon="el-icon-back" @click="goBack1"></el-button>
        </el-tooltip>
        <el-tooltip effect="dark" content="返回" placement="bottom">
          <el-button type="primary" size="mini" :disabled='redoList.length>0?false:true' icon="el-icon-right" @click="goBack2"></el-button>
        </el-tooltip>
        <span class="mgr-10 mgl-10 geClss">|</span>
        <el-tooltip effect="dark" content="删除" placement="bottom">
          <el-button type="primary" size="mini" icon="el-icon-delete" @click="goDeletePage"></el-button>
        </el-tooltip>
        <el-tooltip effect="dark" content="关闭" placement="bottom">
          <el-button type="primary" size="mini" icon="el-icon-close" @click="goBack"></el-button>
        </el-tooltip>
        <el-tooltip effect="dark" content="保存" placement="bottom">
          <el-button type="primary" size="mini" icon="el-icon-check" @click="goSaveSketch"></el-button>
        </el-tooltip>
      </div>
    </div>
    <!-- 设备绑定 -->
    <el-dialog title="设备绑定" width="1000px" class="workerInfo" :close-on-click-modal="false" append-to-body :visible.sync="equipmentBindingVisible" style="margin-top:6vh">
      <div class="df-aj equipmentBindingBox">
        <div class="equipmentBindingBox_text1">
          {{sketchObject.label}}
        </div>
        <i class="el-icon-connection equipmentBindingBox_text2"></i>
        <div class="equipmentBindingBox_text3">
          {{sketchObject.relevance.relevanceEquipName}}
        </div>
      </div>
      <div class="df mgb_20">
        <div class="workMaintenance_title_name">选择设备:</div>
        <el-select v-model="queryInfo.searchParams.devType" placeholder="请选择" size="mini" class="mgr-10" style="width:180px;" clearable @change="getComputerList">
          <el-option v-for="item in equipmentList" :key="item.id" :label="item.name" :value="item.id">
          </el-option>
        </el-select>
        <el-input placeholder="请输入设备编号|设备名称" style="width:300px;" v-model="queryInfo.searchParams.devName" clearable @clear="getComputerList" class="input-with-select" size="mini">
          <el-button slot="append" icon="el-icon-search" @click="getComputerList"></el-button>
        </el-input>
      </div>
      <el-table border :context="$root" height="440px" highlight-current-row @current-change="handleCurrentChangeFormBind" ref="resourceTable" row-key="id" :data="computerDataList" element-loading-text="正在拼命加载,请稍等片刻。" v-loading="showLoading" style="width:100%;">
        <el-table-column width="60" type="index" :index="indexMethod" label="序号" align="center"></el-table-column>
        <el-table-column prop="typeName" show-overflow-tooltip label="设备类型" align="center"></el-table-column>
        <el-table-column prop="devNo" show-overflow-tooltip label="设备编号" align="center"></el-table-column>
        <el-table-column prop="devName" show-overflow-tooltip label="设备名称" align="center"></el-table-column>
        <el-table-column prop="devIp" show-overflow-tooltip label="IP" align="center"></el-table-column>
      </el-table>
      <!-- </div> -->
      <div class="manageComputer_bottom mgt-20 mgb-10">
        <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="queryInfo.pageIndex" :page-sizes="[10, 20, 30, 50, 100]" :page-size="queryInfo.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total"></el-pagination>
      </div>
      <el-row slot="footer">
        <el-col align="center" :span="24">
          <el-button type="primary" @click="bindSubmitServer">确认</el-button>
          <el-button type="primary" @click="bindCancel">关闭</el-button>
        </el-col>
      </el-row>
    </el-dialog>
    <el-dialog title="查看JSON" :visible.sync="jsonDialogVisible" width="30%" style="margin-top:6vh">
      <json-viewer :value="jsonData" :expand-depth=5 copyable boxed sort></json-viewer>
      <el-row slot="footer">
        <el-col align="center" :span="24" class="mgt-10">
          <el-button type="primary" @click="jsonDialogVisible = false">关闭</el-button>
        </el-col>
      </el-row>
    </el-dialog>
    <!-- 查看设备 -->
    <view-equipment :visible.sync="addUserDialogShow" :equipId="equipmentId" :deviceTypeList='options'></view-equipment>
    <!-- 设备弹窗 -->
    <equipment-workorder :visible.sync="equipmentDialogShow" :superState='superState' :equipNewFaultObj='equipNewFaultObj' :equipListObj='equipListObj' @equipShow='setEquipShow' :workTypeList="workTypeList" :queryUnitList="queryUnitList" :workSourceList="workSourceList" :failureCauseList="failureCauseList" :repairLevelList="repairLevelList" :workState="workState"></equipment-workorder>

  </div>

</template>
<script>
import G6 from '@antv/g6'
import sketchCollapse from './sketchCollapse'
import viewEquipment from '../nowWarning/viewEquipment'
import { addTopology, getTopologyDetail, delTopology, getTopologyAlarm } from '@/api/sketchManagement'
import { getDeviceByCate } from '@/api/manageComputer'
import { getDevInfoPage, getDeviceTypeList } from '@/api/workMaintenance'
import { mapGetters, mapActions } from 'vuex'
import command from './command.js'
import Editor from './Editor.js'
import eventBus from '@/utils/eventBus'
import { getAlarmByDevId } from '@/api/integratedSupervision'

import equipmentWorkorder from '../integratedSupervision/equipmentWorkorder.vue'
import { getDeviceDictListByType, queryUnitList } from '@/api/workMaintenance'
import { getDeviceByIds } from '@/api/workHistory'

export default {
  components: { sketchCollapse, viewEquipment, equipmentWorkorder },
  data() {
    return {
      graph: null,
      newEquip: {},
      leftDrawer: true,
      rightDrawer: false,
      rightDrawerLine: false,
      equipmentBindingVisible: false,
      jsonDialogVisible: false,
      addUserDialogShow: false,
      activeNames: ['1'],
      sketchObjectLine: {},
      // 点击节点后的数据
      sketchObject: {
        relevance: {},
        size: [],
      },
      editorLineText: '',
      mode: 'default',
      dragging: false,
      queryInfo: {
        pageIndex: 1,
        pageSize: 10,
        searchParams: {
          devName: '',
          devType: '',
          devState: '',
          devNo: '',
          chargeUser: '',
          unitId: '',
          contact: '',
          devTypeInner: '',
        },
      },
      computerDataList: [],
      options: [],
      total: 0,
      equipmentList: [],
      showLoading: false,
      topologyListObject: {
        id: '', //	Long	主键
        topologyName: '', //	String	拓扑图名字
        deviceNum: '', //	Integer	设备数
        width: '', //	Integer	宽度
        height: '', //	Integer	高度
        translateX: '', //	Double	平移x
        translateY: '', //	Double	平移y
        scaleX: '', //	Double	缩放x
        scaleY: '', //	Double	缩放y
        isDelete: '', //	String	是否删除
        createTime: '', // 	Date	创建时间
        createUser: '', //	String	创建人
        updateTime: '', //	Date	修改时间
        updateUser: '', //	String	修改人
        description: '', //	String	备注
        roomId: '', //	String	机房id
        topologyType: '', //	String	拓扑图类型(1系统拓扑、2业务拓扑、3逻辑拓扑)
        nodes: [],
        edges: [],
      },
      topologyTypeList: [
        { id: '1', label: '系统拓扑' },
        { id: '2', label: '业务拓扑' },
        { id: '3', label: '逻辑拓扑' },
      ],
      lineTypeLine: [
        { id: '1', label: '数据连接' },
        { id: '2', label: '通信连接' },
        { id: '3', label: '逻辑连接' },
      ],
      lineDirectionLine: [
        { id: '1', label: '单向' },
        { id: '2', label: '双向' },
        { id: '3', label: '无向' },
      ],
      equipMentObject: {
        //    <!-- 设备编号 -->
        // <!-- 设备名称 -->
        // <!-- 设备类型 -->
        relevanceEquipmentId: '', //设备id
        relevanceEquipId: '', // 设备编号
        relevanceEquipName: '', // 设备名称
        relevanceEquipType: '', // 设备类型
        relevanceName: '', // 资产名称
      },
      mouseHoverShow: false,
      jsonData: {},
      equipmentId: '',
      editor: {},
      command: null,
      redoList: [],
      undoList: [],
      updateItemData: {
        item: {},
        oldModel: {},
        newModel: {},
      },
      oncontextmenu: true,
      gridShow: true,
      grid: null,
      connectionShow: true,
      // 查看报警设备开始
      equipmentDialogShow: false,
      superState: '',
      equipNewFaultObj: {},
      equipListObj: {},
      workTypeList: [],
      queryUnitList: [],
      workSourceList: [],
      failureCauseList: [],
      repairLevelList: [],
      workState: '',
      // 查看报警设备结束
    }
  },
  computed: {
    ...mapGetters(['sketchId', 'isSketchEdit', 'equipId']),
  },
  created() {
    this.getDeviceTypeLists()
    this.initCreated()
    this.bindEvent()
    // 查看报警设备开始
    this.getAlarmEquip()
  },
  mounted() {
    console.log('isSketchEdit', this.isSketchEdit)
    if (this.isSketchEdit) {
      this.$nextTick(() => {
        this.isEditInit()
        if (this.sketchId != '-1') {
          this.getTopologyDetail(this.sketchId)
        }
      })
    } else {
      this.$nextTick(() => {
        this.noEditInit()
        if (this.sketchId != '-1') {
          this.getTopologyDetail(this.sketchId)
        }
      })
    }
  },
  methods: {
    ...mapActions(['get_sketchId']),
    initCreated() {
      this.editor = new Editor()
      this.command = new command(this.editor)
    },
    noEditInit() {
      let that = this
      this.$refs.contextmenuBoxAll.style.display = 'none'
      const contextMenu = new G6.Menu({
        getContent(evt) {
          return that.$refs.contextmenuBox
        },
        handleMenuClick: (target, item) => {
          if (target.innerText == '层级前置') {
            this.graph.findById(item._cfg.id).toFront()
            this.graph.refreshPositions()
          }
          if (target.innerText == '层级后置') {
            this.graph.findById(item._cfg.id).toBack()
            this.graph.refreshPositions()
          }
          if (target.innerText == '查看设备') {
            this.graph.save().nodes.forEach((item1) => {
              if (item1.id == item._cfg.id) {
                if (item1.relevance.relevanceEquipmentId) {
                  this.equipmentId = item1.relevance.relevanceEquipmentId + ''
                  this.addUserDialogShow = true
                } else {
                  this.$message({
                    type: 'error',
                    message: '暂未关联设备',
                    showClose: true,
                  })
                }
              }
            })
          }
          if (target.innerText == '编辑节点') {
            that.editNode(item)
          }
          if (target.innerText == '关联绑定') {
            this.graph.save().nodes.forEach((item1) => {
              if (item1.id == item._cfg.id) {
                this.sketchObject = item1
              }
            })
            this.getComputerList()
            this.equipmentBindingVisible = true
          }
          if (target.innerText == '删除节点') {
            this.rightDrawer = false
            this.deleteItem(item)
          }
        },
        offsetX: 16,
        offsetY: 0,
        itemTypes: ['node'],
      })
      const tooltip = new G6.Tooltip({
        offsetX: 20,
        offsetY: 20,
        getContent(e) {
          if (e.item.getModel().relevance.relevanceEquipmentId == '') {
            that.$refs.mouseHover.style.display = 'none'
          } else {
            that.$refs.mouseHover.style.display = 'block'
          }
          that.equipMentObject = e.item.getModel().relevance
          return that.$refs.mouseHover
        },
        itemTypes: ['node'],
      })
      G6.registerNode(
        'background-animate',
        {
          afterDraw(cfg, group) {
            const r = cfg.size[0] / 2
            const back1 = group.addShape('circle', {
              zIndex: -3,
              attrs: {
                x: 0,
                y: 0,
                r,
                fill: '#01e8ff',
                opacity: 0.6,
              },
              name: 'back1-shape',
            })
            const back2 = group.addShape('circle', {
              zIndex: -2,
              attrs: {
                x: 0,
                y: 0,
                r,
                fill: '#01e8ff',
                opacity: 0.6,
              },
              name: 'back2-shape',
            })
            const back3 = group.addShape('circle', {
              zIndex: -1,
              attrs: {
                x: 0,
                y: 0,
                r,
                fill: '#01e8ff',
                opacity: 0.6,
              },
              name: 'back3-shape',
            })
            group.sort() // Sort according to the zIndex
            back1.animate(
              {
                // Magnifying and disappearing
                r: r + cfg.size[0] / 3,
                opacity: 0.1,
              },
              {
                duration: 2000,
                easing: 'easeCubic',
                delay: 0,
                repeat: true, // repeat
              }
            ) // no delay
            back2.animate(
              {
                // Magnifying and disappearing
                r: r + cfg.size[0] / 3,
                opacity: 0.1,
              },
              {
                duration: 2000,
                easing: 'easeCubic',
                delay: 1000,
                repeat: true, // repeat
              }
            ) // 1s delay
            back3.animate(
              {
                // Magnifying and disappearing
                r: r + cfg.size[0] / 3,
                opacity: 0.1,
              },
              {
                duration: 2000,
                easing: 'easeCubic',
                delay: 2000,
                repeat: true, // repeat
              }
            ) // 3s delay
          },
        },
        'image'
      )

      this.grid = new G6.Grid()
      const width = this.$refs.mountNode.scrollWidth
      const height = this.$refs.mountNode.scrollHeight
      this.graph = new G6.Graph({
        container: 'mountNode', // String | HTMLElement,必须,在创建的容器 id 或容器本身
        width: width, // Number,必须,图的宽度
        height: height, // Number,必须,图的高度
        // fitView: true,
        plugins: [this.grid, contextMenu, tooltip],
        modes: {
          // Defualt mode
          default: ['click-select', 'drag-canvas', 'zoom-canvas'],
        },
      })
      // this.graph.data(data) // 读取数据源到图上
      this.graph.render() // 渲染图
      this.graph.on('node:click', (e) => {
        if (e.shape.cfg.name == 'warning-point') {
          this.graph.save().nodes.forEach((item1) => {
            if (item1.id == e.item._cfg.id) {
              that.getDeviceByIds(item1.relevance.relevanceEquipmentId)
              that.superState = '1'
              that.equipmentDialogShow = true
            }
          })
        } else {
          this.graph.fitCenter()
        }
      })
    },
    isEditInit() {
      let that = this
      this.$refs.contextmenuBoxAll.style.display = 'none'
      this.$refs.mountNode.oncontextmenu = (e) => {
        if (this.oncontextmenu) {
          this.$refs.contextmenuBoxAll.style.display = 'block'
          this.$refs.contextmenuBoxAll.style.left = e.layerX + 20 + 'px'
          this.$refs.contextmenuBoxAll.style.top = e.layerY + 20 + 'px'
        }
      }
      this.$refs.mountNode.onclick = (e) => {
        this.$refs.contextmenuBoxAll.style.display = 'none'
      }
      const contextMenu = new G6.Menu({
        getContent(evt) {
          return that.$refs.contextmenuBox
        },
        handleMenuClick: (target, item) => {
          if (target.innerText == '层级前置') {
            this.graph.findById(item._cfg.id).toFront()
            this.graph.refreshPositions()
          }
          if (target.innerText == '层级后置') {
            this.graph.findById(item._cfg.id).toBack()
            this.graph.refreshPositions()
          }
          if (target.innerText == '查看设备') {
            this.graph.save().nodes.forEach((item1) => {
              if (item1.id == item._cfg.id) {
                if (item1.relevance.relevanceEquipmentId) {
                  this.equipmentId = item1.relevance.relevanceEquipmentId + ''
                  this.addUserDialogShow = true
                } else {
                  this.$message({
                    type: 'error',
                    message: '暂未关联设备',
                    showClose: true,
                  })
                }
              }
            })
          }
          if (target.innerText == '编辑节点') {
            that.editNode(item)
          }
          if (target.innerText == '关联绑定') {
            this.graph.save().nodes.forEach((item1) => {
              if (item1.id == item._cfg.id) {
                this.sketchObject = item1
              }
            })
            this.getComputerList()
            this.equipmentBindingVisible = true
          }
          if (target.innerText == '删除节点') {
            this.rightDrawer = false
            this.deleteItem(item)
          }
        },
        offsetX: 16,
        offsetY: 0,
        itemTypes: ['node'],
      })
      const contextmenuLineBox = new G6.Menu({
        getContent(evt) {
          return that.$refs.contextmenuLineBox
        },
        handleMenuClick: (target, item) => {
          if (target.innerText == '编辑连线') {
            that.editLine(item)
          }
          if (target.innerText == '删除线段') {
            this.graph.save().edges.forEach((item2) => {
              if (item._cfg) {
                if (item2.id == item._cfg.id) {
                  this.deleteItem(item2)
                }
              }
            })
          }
        },
        offsetX: 16,
        offsetY: 0,
        itemTypes: ['edge'],
      })
      const tooltip = new G6.Tooltip({
        offsetX: 20,
        offsetY: 20,
        getContent(e) {
          if (e.item.getModel().relevance.relevanceEquipmentId == '') {
            that.$refs.mouseHover.style.display = 'none'
          } else {
            that.$refs.mouseHover.style.display = 'block'
          }
          that.equipMentObject = e.item.getModel().relevance
          return that.$refs.mouseHover
        },
        itemTypes: ['node'],
      })
      this.grid = new G6.Grid()
      const width = this.$refs.mountNode.scrollWidth
      const height = this.$refs.mountNode.scrollHeight
      this.graph = new G6.Graph({
        container: 'mountNode', // String | HTMLElement,必须,在创建的容器 id 或容器本身
        width: width, // Number,必须,图的宽度
        height: height, // Number,必须,图的高度
        // fitView: true,
        plugins: [this.grid, contextMenu, contextmenuLineBox, tooltip],
        modes: {
          // Defualt mode
          default: ['drag-node', 'click-select', 'drag-canvas', 'zoom-canvas'],
          // Adding node mode
          addNode: ['click-add-node', 'drag-node', 'click-select', 'drag-canvas', 'zoom-canvas'],
          // Adding edge mode
          addEdge: ['click-add-edge', 'drag-node', 'click-select', 'drag-canvas', 'zoom-canvas'],
        },
      })
      // this.graph.data(data) // 读取数据源到图上
      this.graph.render() // 渲染图
      G6.registerEdge('polyline', {
        options: {
          style: {
            stroke: '#ccc',
          },
        },
        draw: function draw(cfg, group) {
          const startPoint = cfg.startPoint
          const endPoint = cfg.endPoint
          const stroke = (cfg.style && cfg.style.stroke) || this.options.style.stroke
          const startArrow = (cfg.style && cfg.style.startArrow) || undefined
          const endArrow = (cfg.style && cfg.style.endArrow) || undefined

          const keyShape = group.addShape('path', {
            attrs: {
              path: [
                ['M', startPoint.x, startPoint.y],
                ['L', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y],
                ['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y],
                ['L', endPoint.x, endPoint.y],
              ],
              stroke,
              lineWidth: 1,
              lineAppendWidth: 20,
              startArrow,
              endArrow,
            },
            className: 'edge-shape',
            name: 'edge-shape',
            label: '',
          })
          group.addShape('text', {
            attrs: {
              text: cfg.label,
              fill: '#01e8ff',
              // textAlign: 'start',
              textBaseline: 'middle',
              x: endPoint.x / 3 + (2 / 3) * startPoint.x,
              y: startPoint.y - (startPoint.y - endPoint.y) / 2,
            },
            name: 'left-text-shape',
          })
          return keyShape
        },
      })
      G6.registerBehavior('click-add-node', {
        getEvents() {
          return {
            'canvas:click': 'onClick',
          }
        },
        onClick(ev) {
          let equipId = new Date().getTime() + ''
          const model = {
            x: ev.x,
            y: ev.y,
            size: [that.newEquip.width, that.newEquip.height],
            type: 'image',
            img: that.newEquip.image,
            id: equipId,
            equipType: that.newEquip.type,
            label: that.newEquip.label,
            zIndex: 1,
            echoType: 'node',
            labelCfg: {
              // 标签配置属性
              positions: 'center', // 标签的属性,标签在元素中的位置
              style: {
                // 包裹标签样式属性的字段 style 与标签其他属性在数据结构上并行
                fontSize: 12, // 标签的样式属性,文字字体大小
                fill: '#01e8ff', // 节点标签文字颜色
                // ...            // 标签的其他样式属性
              },
            },
            relevance: {
              relevanceState: false,
              relevanceEquipId: '',
              relevanceEquipmentId: '',
              relevanceEquipName: '',
              relevanceEquipType: '',
              relevanceName: '',
            },
          }
          this.graph.addItem('node', model)
          const group = this.graph.findById(equipId).getContainer()
          that.addControlPoint(group, that.newEquip)
          that.command.executeCommand('add', [model])
        },
      })
      G6.registerBehavior('click-add-edge', {
        getEvents() {
          return {
            'node:click': 'onClick', // The event is canvas:click, the responsing function is onClick
            mousemove: 'onMousemove', // The event is mousemove, the responsing function is onm ousemove
            'edge:click': 'onEdgeClick', // The event is edge:click, the responsing function is onEdgeClick
            // 'edge:click': 'onEdgeClick', // The event is edge:click, the responsing function is onEdgeClick
          }
        },
        onClick(ev) {
          const self = this
          const node = ev.item
          const graph = self.graph
          // The position where the mouse clicks
          const point = { x: ev.x, y: ev.y }
          const model = node.getModel()
          if (self.addingEdge && self.edge) {
            graph.updateItem(self.edge, {
              target: model.id,
            })

            self.edge = null
            self.addingEdge = false
          } else {
            // Add anew edge, the end node is the current node user clicks
            const degeLine = {
              id: new Date().getTime() + '',
              source: model.id,
              target: model.id,
              type: that.newEquip.lineType,

              label: '',
              autoRotate: true,
              echoType: 'edge',
              labelCfg: {
                // 标签配置属性
                style: {
                  // 包裹标签样式属性的字段 style 与标签其他属性在数据结构上并行
                  fontSize: 12, // 标签的样式属性,文字字体大小
                  fill: '#01e8ff', // 节点标签文字颜色
                  // ...            // 标签的其他样式属性
                },
              },
              style: {
                endArrow: true,
                startArrow: false,
                lineAppendWidth: 20,
                // lineWidth: 8,
              },
              // 连线类型:
              direction: '1',
              // 连线方式:
              linkType: '',
            }
            self.edge = graph.addItem('edge', degeLine)
            that.command.executeCommand('add', [degeLine])
            self.addingEdge = true
          }
        },
        onm ousemove(ev) {
          const self = this
          const point = { x: ev.x, y: ev.y }
          if (self.addingEdge && self.edge) {
            self.graph.updateItem(self.edge, {
              target: point,
            })
          }
        },
        onEdgeClick(ev) {
          const self = this
          const currentEdge = ev.item
          if (self.addingEdge && self.edge === currentEdge) {
            self.graph.removeItem(self.edge)
            self.edge = null
            self.addingEdge = false
          }
        },
      })

      this.bindEvents()
      this.graph.on('node:mouseenter', (evt) => {
        this.oncontextmenu = false
        this.$refs.contextmenuBoxAll.style.display = 'none'
      })
      this.graph.on('node:mouseleave', (evt) => {
        this.oncontextmenu = true
      })
      this.graph.on('edge:mouseenter', (evt) => {
        this.oncontextmenu = false
        this.$refs.contextmenuBoxAll.style.display = 'none'
      })

      this.graph.on('edge:mouseleave', (evt) => {
        this.oncontextmenu = true
      })

      this.graph.on('node:dragstart', (e) => {
        this.updateItemData = {
          item: {},
          oldModel: {},
          newModel: {},
        }
        this.updateItemData.item = e
        this.graph.save().nodes.forEach((item) => {
          if (item.id == e.item._cfg.id) {
            this.updateItemData.oldModel = JSON.parse(JSON.stringify(item))
          }
        })
      })

      this.graph.on('node:dblclick', (e) => {
        that.editNode(e.item)
      })
      this.graph.on('edge:dblclick', (e) => {
        that.editLine(e.item)
      })
      this.graph.on('keydown', (e) => {
        console.log('键盘', e)
        if (this.sketchObject.id) {
          if (e.key == 'ArrowDown') {
            this.sketchObject.y += 1
          }
          if (e.key == 'ArrowRight') {
            this.sketchObject.x += 1
          }
          if (e.key == 'ArrowUp') {
            this.sketchObject.y -= 1
          }
          if (e.key == 'ArrowLeft') {
            this.sketchObject.x -= 1
          }
          this.sketchObjectChange()
        }
        if (e.key == 'ß') {
          that.goSaveSketch()
        }
      })
      this.graph.on('node:dragend', (e) => {
        this.graph.save().nodes.forEach((item) => {
          if (item.id == e.item._cfg.id) {
            item.x = e.x
            item.y = e.y
            this.updateItemData.newModel = JSON.parse(JSON.stringify(item))
            this.command.executeCommand('update', [this.updateItemData])
          }
        })
        this.graph.refreshPositions()
      })
      const { editor, command } = this
      editor.emit('afterAddPage', { graph: this.graph, command })
    },
    bindEvent() {
      eventBus.$on('afterAddPage', (page) => {
        this.page = page
        this.command = page.command
      })
      eventBus.$on('add', (data) => {
        this.redoList = data.redoList
        this.undoList = data.undoList
      })
      eventBus.$on('update', (data) => {
        this.redoList = data.redoList
        this.undoList = data.undoList
      })
      eventBus.$on('delete', (data) => {
        this.redoList = data.redoList
        this.undoList = data.undoList
      })
    },
    deleteItem(item) {
      this.command.executeCommand('delete', [item])
    },
    bindEvents() {
      const p = {
        x: 0,
        y: 0,
      }
      this.graph.on('node:click', (e) => {
        console.log('e节点', e.item._cfg.id)
        console.log('e节点', e)
        console.log('graph.getNodes()', this.graph.getNodes())
        console.log('graph.save()', this.graph.save().nodes)

        this.graph.save().nodes.forEach((item1) => {
          if (item1.id == e.item._cfg.id) {
            this.sketchObject = item1
          }
        })
        // if (e.shape.cfg.name == 'warning-point') {
        //   const group = this.graph.findById(e.item._cfg.id).getContainer()
        //   const children = group.getChildren()

        //   children.forEach((child) => {
        //     if (child.cfg.className === 'control-point' || child.cfg.className === 'rect-node-shadow') {
        //       child.hide()
        //     }
        //   })
        // }
        // this.graph.refreshPositions()
      })
      this.graph.on('mousedown', (e) => {
        if (this.mode === 'edit' && !this.dragging) {
          this.dragging = true
          p.x = e.x
          p.y = e.y
        }
      })
      this.graph.on('node:mousemove', (e) => {
        if (this.mode === 'edit' && this.dragging && e.shape.cfg.name == 'left-top-point') {
          this.dragging = true
          this.updateNodeSize(e, p.y - e.y, p.y - e.y)
          p.x = e.x
          p.y = e.y
        }
        if (this.mode === 'edit' && this.dragging && e.shape.cfg.name == 'right-top-point') {
          this.dragging = true
          this.updateNodeSize(e, e.x - p.x, e.x - p.x)
          p.x = e.x
          p.y = e.y
        }
        if (this.mode === 'edit' && this.dragging && e.shape.cfg.name == 'right-bottom-point') {
          this.dragging = true
          this.updateNodeSize(e, e.x - p.x, e.x - p.x)
          p.x = e.x
          p.y = e.y
        }
        if (this.mode === 'edit' && this.dragging && e.shape.cfg.name == 'left-bottom-point') {
          this.dragging = true
          this.updateNodeSize(e, p.x - e.x, p.x - e.x)
          p.x = e.x
          p.y = e.y
        }
        ///
        if (this.mode === 'edit' && this.dragging && e.shape.cfg.name == 'top-point') {
          this.dragging = true
          this.updateNodeSize(e, 0, p.y - e.y)
          p.x = e.x
          p.y = e.y
        }
        if (this.mode === 'edit' && this.dragging && e.shape.cfg.name == 'bottom-point') {
          this.dragging = true
          this.updateNodeSize(e, 0, e.y - p.y)
          p.x = e.x
          p.y = e.y
        }
        if (this.mode === 'edit' && this.dragging && e.shape.cfg.name == 'right-point') {
          this.dragging = true
          this.updateNodeSize(e, e.x - p.x, 0)
          p.x = e.x
          p.y = e.y
        }
        if (this.mode === 'edit' && this.dragging && e.shape.cfg.name == 'left-point') {
          this.dragging = true
          this.updateNodeSize(e, p.x - e.x, 0)
          p.x = e.x
          p.y = e.y
        }
      })
      this.graph.on('mouseup', (e) => {
        if (this.mode === 'edit' && this.dragging) {
          this.dragging = false
        }
      })
      this.graph.on('node:mouseup', (e) => {
        if (this.mode === 'edit' && this.dragging) {
          this.dragging = false
        }
      })
      this.graph.on('node:dragend', (e) => {
        if (this.mode === 'edit' && this.dragging) {
          this.dragging = false
        }
      })
      this.graph.on('node:mouseleave', (e) => {
        if (this.mode === 'edit' && this.dragging) {
          this.dragging = false
        }
      })
    },
    editLine(item) {
      this.graph.save().edges.forEach((item1) => {
        if (item1.id == item._cfg.id) {
          this.sketchObjectLine = item1
        }
      })
      if (this.sketchObject.id) {
        this.deleteClose()
      }
      this.rightDrawerLine = true
    },
    editNode(item) {
      this.mode = 'edit'
      const group = this.graph.findById(item._cfg.id).getContainer()
      const children = group.getChildren()
      children.forEach((child) => {
        if (child.cfg.className === 'control-point' || child.cfg.className === 'rect-node-shadow') {
          child.show()
        }
      })

      this.graph.save().nodes.forEach((item1) => {
        if (item1.id == item._cfg.id) {
          this.sketchObject = item1
        }
      })
      this.rightDrawerLine = false
      this.rightDrawer = true
    },
    updateNodeSize(e, dx, dy) {
      this.graph.save().nodes.forEach((item) => {
        if (item.id == e.item._cfg.id) {
          this.sketchObject = item
        }
      })
      this.sketchObject.size[0] += dx * 2
      this.sketchObject.size[1] += dy * 2
      this.graph.updateItem(this.graph.findById(this.sketchObject.id), this.sketchObject)

      const group = e.item.getContainer()
      group.getChildren().forEach((child) => {
        this.updateChild(child)
      })
    },
    updateChild(child) {
      switch (child.cfg.name) {
        case 'left-top-point':
          child.attr({
            x: -this.sketchObject.size[0] / 2,
            y: -this.sketchObject.size[1] / 2,
          })
          break
        case 'right-top-point':
          child.attr({
            x: this.sketchObject.size[0] / 2,
            y: -this.sketchObject.size[1] / 2,
          })
          break
        case 'right-bottom-point':
          child.attr({
            x: this.sketchObject.size[0] / 2,
            y: this.sketchObject.size[1] / 2,
          })
          break
        case 'left-bottom-point':
          child.attr({
            x: -this.sketchObject.size[0] / 2,
            y: this.sketchObject.size[1] / 2,
          })
          break
        ///
        case 'top-point':
          child.attr({
            y: -this.sketchObject.size[1] / 2,
          })
          break
        case 'right-point':
          child.attr({
            x: this.sketchObject.size[0] / 2,
          })
          break
        case 'bottom-point':
          child.attr({
            y: this.sketchObject.size[1] / 2,
          })
          break
        case 'left-point':
          child.attr({
            x: -this.sketchObject.size[0] / 2,
          })
          break
        case 'warning-point':
          child.attr({
            y: -this.sketchObject.size[1] / 2 - 60,
          })
          break
      }
    },
    changeMode() {
      if (this.mode === 'default') {
        this.mode = 'edit'
      } else {
        this.mode = 'default'
      }

      const item = this.graph.findById('0')

      this.graph.setItemState(item, 'graphMode', this.mode)
    },
    sketchObjectLineChange() {
      this.graph.updateItem(this.graph.findById(this.sketchObjectLine.id), this.sketchObjectLine)
    },
    setLineDirection() {
      if (this.sketchObjectLine.direction == '1') {
        this.sketchObjectLine.style.endArrow = true
        this.sketchObjectLine.style.startArrow = false
      }
      if (this.sketchObjectLine.direction == '2') {
        this.sketchObjectLine.style.endArrow = true
        this.sketchObjectLine.style.startArrow = true
      }
      if (this.sketchObjectLine.direction == '3') {
        this.sketchObjectLine.style.endArrow = false
        this.sketchObjectLine.style.startArrow = false
      }
      this.graph.updateItem(this.graph.findById(this.sketchObjectLine.id), this.sketchObjectLine)
    },
    sketchObjectChange(type) {
      if (this.connectionShow && type == 'size[0]') {
        this.sketchObject.size = [this.sketchObject.size[0], this.sketchObject.size[0]]
      } else if (this.connectionShow && type == 'size[1]') {
        this.sketchObject.size = [this.sketchObject.size[1], this.sketchObject.size[1]]
      }
      const group = this.graph.findById(this.sketchObject.id).getContainer()
      this.graph.updateItem(this.graph.findById(this.sketchObject.id), this.sketchObject)
      const children = group.getChildren()
      children.forEach((child) => {
        this.updateChild(child)
      })
      this.graph.refreshPositions()
    },
    showLeft() {
      this.leftDrawer = !this.leftDrawer
    },
    showRight() {
      this.rightDrawer = !this.rightDrawer
    },
    addControlPoint(group, newEquip) {
      group.addShape('image', {
        attrs: {
          x: -27,
          y: -newEquip.height / 2 - 50,
          width: 54,
          height: 60,
          img: require('@/assets/newTopo/gaojing.jpg'),
          // img: require('@/assets/newTopo/fuwujiguiShu.svg'),
          cursor: 'pointer',
        },
        visible: false,
        className: 'warning-point',
        name: 'warning-point',
      })
      group.addShape('circle', {
        attrs: {
          r: 4,
          fill: '#1890ff',
          stroke: '#fff',
          strokeOpacity: 0,
          lineWidth: 20,
          x: -newEquip.height / 2,
          y: -newEquip.height / 2,
          cursor: 'nwse-resize',
        },
        visible: false,
        className: 'control-point',
        name: 'left-top-point',
      })
      group.addShape('circle', {
        attrs: {
          r: 4,
          fill: '#1890ff',
          stroke: '#fff',
          strokeOpacity: 0,
          lineWidth: 20,
          x: newEquip.height / 2,
          y: -newEquip.height / 2,
          cursor: 'nesw-resize',
        },
        visible: false,
        className: 'control-point',
        name: 'right-top-point',
      })
      group.addShape('circle', {
        attrs: {
          r: 4,
          fill: '#1890ff',
          stroke: '#fff',
          strokeOpacity: 0,
          lineWidth: 20,
          x: newEquip.height / 2,
          y: newEquip.height / 2,
          cursor: 'nwse-resize',
        },
        visible: false,
        className: 'control-point',
        name: 'right-bottom-point',
      })
      group.addShape('circle', {
        attrs: {
          r: 4,
          fill: '#1890ff',
          stroke: '#fff',
          strokeOpacity: 0,
          lineWidth: 20,
          x: -newEquip.height / 2,
          y: newEquip.height / 2,
          cursor: 'nesw-resize',
        },
        visible: false,
        className: 'control-point',
        name: 'left-bottom-point',
      })
      group.addShape('circle', {
        attrs: {
          r: 4,
          fill: '#1890ff',
          stroke: '#fff',
          strokeOpacity: 0,
          lineWidth: 20,
          x: 0,
          y: -newEquip.height / 2,
          cursor: 'ns-resize',
        },
        visible: false,
        className: 'control-point',
        name: 'top-point',
      })
      group.addShape('circle', {
        attrs: {
          r: 4,
          fill: '#1890ff',
          stroke: '#fff',
          strokeOpacity: 0,
          lineWidth: 20,
          x: newEquip.width / 2,
          y: 0,
          cursor: 'ew-resize',
        },
        visible: false,
        className: 'control-point',
        name: 'right-point',
      })
      group.addShape('circle', {
        attrs: {
          r: 4,
          fill: '#1890ff',
          stroke: '#fff',
          strokeOpacity: 0,
          lineWidth: 20,
          x: 0,
          y: newEquip.height / 2,
          cursor: 'ns-resize',
        },
        visible: false,
        className: 'control-point',
        name: 'bottom-point',
      })
      group.addShape('circle', {
        attrs: {
          r: 4,
          fill: '#1890ff',
          stroke: '#fff',
          strokeOpacity: 0,
          lineWidth: 20,
          x: -newEquip.width / 2,
          y: 0,
          cursor: 'ew-resize',
        },
        visible: false,
        className: 'control-point',
        name: 'left-point',
      })
    },
    setShapeCollapse(val) {
      this.newEquip = {}
      if (val.boolean == true) {
        // 选择线的样式
        if (val.addType == 'addEdge') {
          this.newEquip = {
            lineType: val.type,
          }
          this.graph.setMode(val.addType)
        }
        if (val.type == 'exchange') {
          this.newEquip = {
            image: require('@/assets/sketchImg/tpIcon_5.png'),
            height: 40,
            width: 40,
            type: val.type,
            label: val.label,
          }
          this.graph.setMode(val.addType)
        }
        if (val.type == 'server') {
          this.newEquip = {
            image: require('@/assets/sketchImg/mypc.png'),
            height: 40,
            width: 40,
            type: val.type,
            label: val.label,
          }
          this.graph.setMode(val.addType)
        }
      } else {
        this.graph.setMode('default')
      }
    },
    async getAlarmByDevId(devId, id) {
      const res = await getAlarmByDevId({ devId: devId })
      if (res.success) {
        const group = this.graph.findById(id).getContainer()
        const children = group.getChildren()
        children.forEach((child) => {
          if (child.cfg.className == 'warning-point') {
            if (res.result.length > 0) {
              child.show()
            } else {
              child.hide()
            }
          }
        })
      }
    },
    handleCurrentChangeFormBind(val) {
      if (val) {
        this.sketchObject.relevance = {
          relevanceEquipmentId: val.id,
          relevanceEquipId: val.devNo,
          relevanceEquipName: val.devName,
          relevanceEquipType: val.typeName,
          relevanceName: val.devName,
        }
        this.sketchObject.label = val.devName
        this.sketchObjectChange()
      }
    },
    // 每页显示件数修改
    handleSizeChange(pageSize) {
      this.queryInfo.pageSize = pageSize
      this.queryInfo.pageIndex = 1
      this.getComputerList()
    },
    // 翻页
    handleCurrentChange(pageIndex) {
      this.queryInfo.pageIndex = pageIndex
      this.getComputerList()
    },
    selectAll() {},
    // 配置分页序号
    indexMethod(index) {
      return (this.queryInfo.pageIndex - 1) * this.queryInfo.pageSize + index + 1
    },
    bindSubmitServer() {
      this.equipmentBindingVisible = false
    },
    bindCancel() {
      this.equipmentBindingVisible = false
    },
    noRelevanceClick() {
      this.getComputerList()
      this.equipmentBindingVisible = true
    },
    yesRelevanceClick() {
      this.getComputerList()
      this.equipmentBindingVisible = true
    },
    deleteClose() {
      const group = this.graph.findById(this.sketchObject.id).getContainer()
      const children = group.getChildren()
      children.forEach((child) => {
        if (child.cfg.className === 'control-point' || child.cfg.className === 'rect-node-shadow') {
          child.hide()
        }
      })
      this.graph.refreshPositions()
      this.rightDrawer = false
    },
    deleteCloseLine() {
      this.rightDrawerLine = false
    },
    setEditorLineText() {
      this.$refs.editorLineBoxRef.style.display = 'none'
      this.graph.updateItem(this.graph.findById(this.sketchObject.id), this.sketchObject)
    },
    goBack2() {
      this.$refs.contextmenuBoxAll.style.display = 'none'
      if (this.redoList.length > 0) this.command.redo()
    },
    goBack1() {
      this.$refs.contextmenuBoxAll.style.display = 'none'
      if (this.undoList.length > 0) this.command.undo()
    },
    goBackNoEdit() {
      this.$store.dispatch('function/get_routerPathURL', 'sketchManagement')
    },
    goBack() {
      this.$refs.contextmenuBoxAll.style.display = 'none'
      this.$confirm('<p>未保存的操作将会丢失,</p><p>您是否确定返回?</p>', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        dangerouslyUseHTMLString: true,
        type: 'warning',
      }).then(() => {
        this.$store.dispatch('function/get_routerPathURL', 'sketchManagement')
      })
    },
    goDelete() {
      this.$refs.contextmenuBoxAll.style.display = 'none'
      this.$confirm('<p >您确定要清空画布吗?</p><p style="color: red">清空画布后不能进行恢复。</p>', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        dangerouslyUseHTMLString: true,
        type: 'warning',
      }).then(() => {
        this.graph.clear()
      })
    },
    async goDeletePage() {
      let resConfirm = await this.$confirm('<p >您确定要删除此拓扑图吗?</p><p style="color: red">删除后不能进行恢复。</p>', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        dangerouslyUseHTMLString: true,
        type: 'warning',
      })
      if (resConfirm) {
        const res = await delTopology({ ids: this.sketchId })
        if (res.success) {
          this.$message({
            message: '删除成功',
            type: 'success',
            showClose: true,
          })
          this.$store.dispatch('function/get_routerPathURL', 'sketchManagement')
        }
      }
    },
    goRefresh() {
      this.$refs.contextmenuBoxAll.style.display = 'none'
      this.graph.fitCenter()
    },
    goDocument() {
      this.$refs.contextmenuBoxAll.style.display = 'none'
      this.jsonData = this.graph.save()
      this.jsonDialogVisible = true
    },
    async goSaveSketch() {
      this.$refs.contextmenuBoxAll.style.display = 'none'
      this.topologyListObject.deviceNum = this.graph.save().nodes.length
      this.topologyListObject.nodes = []
      this.graph.save().nodes.forEach((item) => {
        this.topologyListObject.nodes.push({
          id: item.id, //	Long	主键
          x: item.x, //	Double	平移x
          y: item.y, //	Double	平移y
          width: item.size[0], //	Integer	宽度
          height: item.size[1], //	Integer	高度
          rotate: '', //	Double	旋转
          topologyId: '', //	Long	拓扑图id
          deviceType: item.equipType, //	String	设备类型
          label: item.label, //	String	显示名称
          textPosition: '', //	String	名称位置
          visible: '', //	Boolean	是否显示
          type: '', //	String	类型
          zIndex: item.zIndex, //	Integer	层级
          floatText: JSON.stringify(item.relevance), //	String	悬浮显示内容
          isDelete: '', //	String	是否删除
          deviceId: item.relevance.relevanceEquipmentId,
        })
      })
      this.topologyListObject.edges = []
      this.graph.save().edges.forEach((item) => {
        this.topologyListObject.edges.push({
          id: item.id, //	Long	主键(时间戳)
          startPointX: item.startPoint.x, //	Double	起点x
          startPointY: item.startPoint.y, //	Double	起点y
          endPointX: item.endPoint.x, //	Double	终点x
          endPointY: item.endPoint.y, //	Double	终点y
          autoRotate: item.autoRotate, //	Boolean	旋转
          rotate: '', //	Double	旋转
          topologyId: '', //	Long	拓扑图id
          label: item.label, //	String	显示名称
          textPosition: '', //	String	名称位置
          visible: '', //	Boolean	是否显示
          source: item.source, //	Long	设备id起点
          target: item.target, //	Long	设备id终点
          sourcePort: '', //	String	起点端口
          targetPort: '', //	String	终点端口
          width: '', //	Integer	宽度
          zindex: '', //	Integer	层级
          direction: item.direction, //	String	方向(1单向、2双向、3无向)
          linkType: item.linkType, //	String	关联类型(1数据连接、2通信连接、3逻辑连接)
          type: item.type, //	String	类型
          isDelete: '', //	String	是否删除
        })
      })
      if (this.topologyListObject.topologyName == '') {
        this.$message({
          message: '拓扑图名称不能为空!',
          type: 'error',
          showClose: true,
        })
        return
      }
      const res = await addTopology(this.topologyListObject)
      if (res.success) {
        this.$message({
          message: '保存成功',
          type: 'success',
          showClose: true,
        })
        this.$store.dispatch('function/get_routerPathURL', 'sketchManagement')
      }
    },
    async getTopologyAlarm(id) {
      const res = await getTopologyAlarm({ id: id })
      if (res.success) {
        let list = res.result
        list.forEach((item) => {
          if (item.self) {
            const group = this.graph.findById(item.id).getContainer()
            const children = group.getChildren()
            children.forEach((child) => {
              if (child.cfg.className == 'warning-point') {
                if (res.result.length > 0) {
                  child.show()
                } else {
                  child.hide()
                }
              }
            })
          }
        })
      }
      console.log('报错', res)
    },
    async getTopologyDetail(id) {
      const res = await getTopologyDetail({ id: id })
      if (res.success) {
        this.topologyListObject = res.result
        let sketchData = {
          nodes: [],
          edges: [],
        }
        this.topologyListObject.nodes.forEach((item) => {
          let imgStr = ''
          if (item.deviceType == 'exchange') {
            imgStr = require('@/assets/sketchImg/tpIcon_5.png')
          }
          if (item.deviceType == 'server') {
            imgStr = require('@/assets/sketchImg/mypc.png')
          }
          let sketchType = ''
          if (this.equipId == item.deviceId && !this.isSketchEdit) {
            sketchType = 'background-animate'
          } else {
            sketchType = 'image'
          }
          sketchData.nodes.push({
            equipType: item.deviceType,
            id: item.id + '',
            img: imgStr,
            label: item.label,
            echoType: 'node',
            labelCfg: {
              positions: 'center',
              style: {
                fill: '#01e8ff',
                fontSize: 12,
              },
            },
            relevance: JSON.parse(item.floatText),
            size: [item.width, item.height],
            style: {},
            type: sketchType,
            x: item.x,
            y: item.y,
            zIndex: 1,
          })
        })
        this.topologyListObject.edges.forEach((item) => {
          let startLine = true
          let endLine = true
          if (item.direction == '1') {
            startLine = false
            endLine = true
          }
          if (item.direction == '2') {
            startLine = true
            endLine = true
          }
          if (item.direction == '3') {
            startLine = false
            endLine = false
          }
          sketchData.edges.push({
            autoRotate: true,
            direction: item.direction,
            endPoint: { x: item.endPointX, y: item.endPointY },
            id: item.id,
            echoType: 'edge',
            label: item.label,
            labelCfg: {
              style: {
                fontSize: 12, // 标签的样式属性,文字字体大小
                fill: '#01e8ff', // 节点标签文字颜色
              },
            },
            linkType: item.linkType,
            source: item.source + '',
            startPoint: { x: item.startPointX, y: item.startPointY },
            style: {
              endArrow: endLine,
              startArrow: startLine,
              lineAppendWidth: 20,
            },
            target: item.target + '',
            type: item.type,
          })
        })
        this.graph.read(sketchData)
        this.$nextTick(() => {
          this.topologyListObject.nodes.forEach((item) => {
            const group = this.graph.findById(item.id + '').getContainer()
            this.addControlPoint(group, item)
          })
          this.graph.fitCenter()
          // 详情是显示错误
          if (!this.isSketchEdit) {
            this.getTopologyAlarm(this.sketchId)
          }
        })
      }
    },
    async getComputerList() {
      this.showLoading = true
      this.queryInfo.searchParams.devTypeInner = this.equipTypeId
      const res = await getDevInfoPage(this.queryInfo)
      if (res.success) {
        this.computerDataList = res.result
        this.total = res.totalCount
      }
      this.getEquipmentList()
      this.showLoading = false
    },
    async getEquipmentList() {
      const res = await getDeviceByCate({ parentId: '24' })
      if (res.success) {
        this.equipTypeId = res.result.id
        this.equipmentList = res.result.childList
      }
    },
    getDeviceTypeLists() {
      let searchParams = {
        name: '',
        parentId: '0',
        available: 1,
        isUse: 1,
      }
      getDeviceTypeList(searchParams).then((res) => {
        if (res.success) {
          this.options = res.result
          this.options.forEach((item) => {
            if (item.childList.length > 0) {
              item.children = item.childList
              this.formessage(item)
            }
          })
        }
      })
    },
    formessage(item) {
      if (item.childList.length > 0) {
        item.children.forEach((item1) => {
          if (item1.childList.length > 0) {
            item1.children = item1.childList
            this.formessage(item1)
          }
        })
      }
    },
    switchChange() {
      if (this.gridShow) {
        this.grid = new G6.Grid()
        this.graph.addPlugin(this.grid)
      } else {
        this.graph.removePlugin(this.grid)
      }
    },
    setEquipShow(val) {
      this.equipNewFaultObj = {}
      this.equipListObj = {}
      this.equipmentDialogShow = val
    },
    getAlarmEquip() {
      this.getWorkTypeList()
      this.getQueryUnitList()
      this.getSorkSourceList()
      this.getFailureCauseList()
      this.getRepairLevelList()
    },
    async getWorkTypeList() {
      const res = await getDeviceDictListByType({ type: 'work_type' })
      if (res.success) {
        this.workTypeList = res.result
      }
    },
    // 获取所有的养护单位
    async getQueryUnitList() {
      const res = await queryUnitList()
      if (res.success) {
        this.queryUnitList = res.result
        this.queryUnitList.forEach((item) => {
          item.id = item.id + ''
        })
      }
    },
    // 获取工单来源
    async getSorkSourceList() {
      const res = await getDeviceDictListByType({ type: 'work_source' })
      if (res.success) {
        this.workSourceList = res.result
      }
    },
    async getFailureCauseList() {
      const res = await getDeviceDictListByType({ type: 'EVENT_REASON' })
      if (res.success) {
        this.failureCauseList = res.result
      }
    },
    async getRepairLevelList() {
      const res = await getDeviceDictListByType({ type: 'REPAIR_LEVEL' })
      if (res.success) {
        this.repairLevelList = res.result
      }
    },
    async getDeviceByIds(id) {
      const res = await getDeviceByIds({ ids: id })
      if (res.success) {
        console.log('res', res)
        this.equipListObj = res.result[0]
      }
    },
  },
}
</script>
<style>
.no_cursor {
  cursor: not-allowed;
}
.g6-component-contextmenu {
  padding: 0px;
  border: none;
}
.g6-grid-container {
  opacity: 0.4;
}
.g6-component-tooltip {
  padding: 0px !important;
  border: none !important;
}
.addStyle .el-collapse-item__content {
  height: 58.7vh !important;
  overflow: hidden;
  overflow-y: auto;
  border-left: 1px solid var(--buttonBorder) !important;
  border-right: 1px solid var(--buttonBorder) !important;
}
.addStyle .el-collapse-item__header {
  height: 25px;
  line-height: 25px;
  font-size: 0.3rem !important;
  background-color: var(--formHead) !important;
  color: var(--formHeadfontColor) !important;
  text-indent: 0.3rem;
}
.addStyle .el-collapse-item__arrow.is-active {
  transform: translateY(-6px) rotate(90deg);
}
.jv-container .jv-code.boxed {
  max-height: none;
}
</style>
<style scoped>
#mountNode {
  width: 100%;
  height: 100%;
  position: absolute;
  z-index: 0;
}
.sketchBox {
  width: 100%;
  height: calc(100vh - 120px);
  position: relative;
  overflow: hidden;
  border: 1px solid var(--chartBox);
  border-radius: 4px;
}
.selectBox {
  position: absolute;
  top: 10px;
  left: 400px;
}
/* left */
.fadeleft-enter-active,
.fadeleft-leave-active {
  transition: all 0.3s;
  opacity: 1;
}
.fadeleft-enter,
.fadeleft-leave-to {
  transform: translateX(-100%);
}
/* right */
.faderight-enter-active,
.faderight-leave-active {
  transition: all 0.3s;
  opacity: 1;
}
.faderight-enter,
.faderight-leave-to {
  transform: translateX(100%);
}
.monitoringLeft {
  position: absolute;
  top: 0;
  left: 0;
  width: 20vh;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.sketchBoxMove {
  position: absolute;
  top: 0;
  left: 0;
  width: 200px;
  height: 250px;
  background-color: var(--bgColor1);
  border: 1px solid var(--fontColorshadow);
  border-radius: 4px;
  z-index: 99999999;
  font-size: 11px;
  color: var(--fontColorshadow) !important;
}
.sketchBoxTitle {
  width: 70px;
}
.sketchHeight {
  height: 40px;
  line-height: 40px;
}
.show_right2 {
  position: absolute;
  top: 10px;
  z-index: 5;
  transition: all 0.36s;
  cursor: pointer;
}
.show_rightClose {
  position: absolute;
  top: 0px;
  right: 0px;
  background-color: var(--bgColor1);
  border-bottom: 1px solid var(--fontColorshadow);
  border-left: 1px solid var(--fontColorshadow);
  border-radius: 4px;
  height: 20px;
  width: 20px;
}
.sketchCloseIcon {
  font-size: 14px;
  color: var(--fontColorshadow) !important;
}
.show_right {
  position: absolute;
  top: 4.1vh;
  right: -14px;
  z-index: 5;
  transition: all 0.36s;
  background-color: var(--bgColor1);
  box-shadow: inset 0px 0px 0.13333rem 1px var(--fontColorshadow);
  border: 1px solid var(--fontColorshadow);
  color: var(--fontColorshadow) !important;
  height: 30px;
  border-top-left-radius: 4px;
  border-bottom-left-radius: 4px;
  cursor: pointer;
}
.show_left {
  position: absolute;
  top: 4.1vh;
  right: -14px;
  z-index: 5;
  transition: all 0.36s;
  background-color: var(--bgColor1);
  box-shadow: inset 0px 0px 0.13333rem 1px var(--fontColorshadow);
  border: 1px solid var(--fontColorshadow);
  color: var(--fontColorshadow) !important;
  height: 30px;
  border-top-right-radius: 4px;
  border-bottom-right-radius: 4px;
  cursor: pointer;
}
.monitoringRight {
  position: absolute;
  top: 0;
  right: 2px;
  width: 36vh;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.monitoringRightFade {
  height: 100%;
  background-color: var(--bgColor1);
  border: 1px solid var(--fontColorshadow);
  border-radius: 4px;
  position: relative;
  /* overflow-y: auto; */
}
.contextmenuBoxHover {
  position: absolute;
  width: 140px;
  height: 70px;
  background-color: var(--bgColor1);
  border: 1px solid var(--fontColorshadow);
  border-radius: 4px;
}
.contextmenuBoxHover > div {
  height: 20px;
  line-height: 20px;
  color: var(--fontColorshadow);
}
.contextmenuBoxNode {
  position: absolute;
  width: 100px;
  height: 180px;
  background-color: var(--bgColor1);
  border: 1px solid var(--fontColorshadow);
  border-radius: 4px;
  font-size: 11px;
}
.contextmenuBoxNodeNoEdit {
  position: absolute;
  width: 100px;
  height: 30px;
  background-color: var(--bgColor1);
  border: 1px solid var(--fontColorshadow);
  border-radius: 4px;
  font-size: 11px;
}
.contextmenuBoxNodeAll {
  position: absolute;
  width: 100px;
  height: 240px;
  background-color: var(--bgColor1);
  border: 1px solid var(--fontColorshadow);
  border-radius: 4px;
  z-index: 99999999;
  font-size: 11px;
}
.contextmenuBoxLine {
  position: absolute;
  width: 100px;
  height: 60px;
  background-color: var(--bgColor1);
  border: 1px solid var(--fontColorshadow);
  border-radius: 4px;
  font-size: 11px;
}
.editorLineBox {
  position: absolute;
  display: none;
}
.contextmenuBox_li {
  height: 30px;
  line-height: 30px;
  color: var(--fontColorshadow);
}
.contextmenuBox_li:hover {
  box-shadow: inset 0px 0px 5px 1px var(--fontColorshadow);
  /* border: 3px solid var(--fontColorshadow); */
  color: var(--fontColorshadow);
  /* font-weight: 700; */
}
.equipmentBindingBox {
  border: 1px solid var(--borderColor2);
  margin-bottom: 20px;
  border-radius: 4px;
  height: 50px;
  line-height: 50px;
}
.equipmentBindingBox_text1 {
  font-size: 16px;
  font-weight: 700;
  color: var(--fontColor3);
}
.equipmentBindingBox_text2 {
  margin: 0 20px;
  font-size: 16px;
  font-weight: 700;
  color: var(--buttonCZColor);
}
.equipmentBindingBox_text3 {
  font-size: 16px;
  font-weight: 700;
  color: var(--fontColor3);
}
.manageComputer_bottom {
  width: 100%;
  text-align: right;
}
.btnBoxCss {
  border-top: 1px dotted var(--borderColor2);
  margin: 20px;
  padding-top: 20px;
}
.btnBoxMoveCss {
  border-top: 1px dotted var(--borderColor2);
  margin: 10px;
  padding-top: 20px;
}
.sketchBtn {
  position: absolute;
  z-index: 999999;
  right: 100px;
  top: 100px;
}

.connectionClickTrue {
  background-color: var(--bgColor1);
  box-shadow: inset 0px 0px 0.13333rem 1px var(--fontColorshadow);
  border: 1px solid var(--fontColorshadow);
  color: var(--fontColorshadow) !important;
}
.connectionClickFalse {
  color: var(--buttonCZColor);
  background-color: var(--imgBGColor);
}
.geClss {
  font-size: 18px;
}
</style>
上一篇:nginx基于域名的虚拟主机配置(本地分布式项目域名配置及测试方法)


下一篇:关键路径(AOE)