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