2298 lines
62 KiB
Vue
2298 lines
62 KiB
Vue
<!-- AntV G6 Graph Component -->
|
||
<script setup lang="ts">
|
||
import { ref, onMounted } from 'vue';
|
||
import { ElMessage } from "element-plus";
|
||
import {
|
||
Clipboard,
|
||
Graph,
|
||
History,
|
||
Keyboard,
|
||
Selection,
|
||
Shape,
|
||
Snapline,
|
||
Stencil,
|
||
Transform
|
||
} from '@antv/x6'
|
||
|
||
// @ts-ignore
|
||
import insertCss from 'insert-css'
|
||
import { updateProjects} from "@/api/business/project";
|
||
import Createscenario from '@/views/component/scenario/createscenario.vue'
|
||
import ScenarioModel from '@/views/component/scenario/index.vue'
|
||
import { addDevices } from "@/api/business/database/device";
|
||
import { saveOrUpdate} from "@/api/business/database/material";
|
||
|
||
import { projectsById} from "@/api/business/project";
|
||
import line1 from '@/assets/x6/line1.png'
|
||
import line2 from '@/assets/x6/line2.png'
|
||
import line3 from '@/assets/x6/line3.png'
|
||
import line4 from '@/assets/x6/line4.png'
|
||
import line5 from '@/assets/x6/line5.png'
|
||
import line6 from '@/assets/x6/line6.png'
|
||
import AdddeviceModel from './adddevice.vue';
|
||
import EditdeviceModel from './editdevice.vue';
|
||
import MaterialModels from './materialmodel.vue';
|
||
import ChangesettingsModels from './changesettings.vue';
|
||
|
||
import ConnectingwireModel from './connectingwire.vue';
|
||
import { TurnOff } from '@element-plus/icons-vue/dist/types';
|
||
const emit = defineEmits([ 'closeAntvx6']);
|
||
const props = defineProps({
|
||
projectInfo: {
|
||
required: false,
|
||
type: Object,
|
||
default: {}
|
||
},
|
||
})
|
||
const isLock = ref(false) // 是否锁定
|
||
const deviceTypetype:any = ref('') // 设备类型
|
||
const isAdddevice = ref(false) // 是否添加设备
|
||
const isEditdevice = ref(false) // 是否编辑设备
|
||
const isMaterialModel = ref(false) // 是否物料信息
|
||
const projectInfo:any = ref(props.projectInfo) // 项目信息
|
||
const isScenario = ref(false) //是否展示历史模拟场景
|
||
const isDisplay = ref(true) // 是否显示
|
||
const isExpansionandcontraction = ref(false) // 是否显示展开收起按钮
|
||
// 为了协助代码演示
|
||
let graph: Graph
|
||
onMounted(() => {
|
||
preWork()
|
||
|
||
|
||
// #region 初始化画布
|
||
graph = new Graph({
|
||
container: document.getElementById('graph-container') as HTMLElement,
|
||
grid: true,
|
||
mousewheel: {
|
||
enabled: true,
|
||
zoomAtMousePosition: true,
|
||
modifiers: 'ctrl',
|
||
minScale: 0.5,
|
||
maxScale: 3,
|
||
},
|
||
connecting: {
|
||
router: 'manhattan',
|
||
connector: {
|
||
name: 'rounded',
|
||
args: {
|
||
radius: 1,
|
||
},
|
||
},
|
||
anchor: 'center',
|
||
connectionPoint: 'anchor',
|
||
allowBlank: false,
|
||
snap: {
|
||
radius: 20,
|
||
},
|
||
createEdge() {
|
||
return new Shape.Edge({
|
||
attrs: {
|
||
line: {
|
||
stroke: '#A2B1C3',
|
||
strokeWidth: 2,
|
||
strokeDasharray: 0,
|
||
targetMarker: {
|
||
name: 'block',
|
||
width: 12,
|
||
height: 8,
|
||
},
|
||
sourceMarker: null,
|
||
},
|
||
},
|
||
zIndex: 0,
|
||
interactive: {
|
||
vertexMovable: true,
|
||
vertexAddable: true,
|
||
vertexDeletable: true,
|
||
arrowheadMovable: true,
|
||
edgeMovable: true,
|
||
},
|
||
})
|
||
},
|
||
validateConnection({ targetMagnet }) {
|
||
return !!targetMagnet
|
||
},
|
||
},
|
||
highlighting: {
|
||
magnetAdsorbed: {
|
||
name: 'stroke',
|
||
args: {
|
||
attrs: {
|
||
fill: '#5F95FF',
|
||
stroke: '#5F95FF',
|
||
},
|
||
},
|
||
},
|
||
},
|
||
|
||
interacting: function (cellView) {
|
||
// 获取当前节点的模型
|
||
const cell = cellView.cell
|
||
// 判断节点是否为 'rect' 形状
|
||
if (cell.shape === 'rect') {
|
||
// 如果是 'rect' 形状,则禁止节点移动
|
||
return { nodeMovable: false }
|
||
}
|
||
// 其他形状的节点允许所有交互
|
||
return true
|
||
}
|
||
// interacting: {
|
||
// nodeMovable: false, // 禁止所有节点移动
|
||
// },
|
||
})
|
||
// #endregion
|
||
|
||
// #region 使用插件
|
||
graph
|
||
.use(
|
||
new Transform({
|
||
resizing: false, // 通过拖拽边缘调整节点大小
|
||
rotating: false, // 允许旋转节点
|
||
// scaling 不是 Transform 插件的有效配置项,已移除
|
||
}),
|
||
)
|
||
.use(
|
||
new Selection({
|
||
rubberband: true,
|
||
showNodeSelectionBox: true,
|
||
}),
|
||
)
|
||
.use(new Snapline())
|
||
.use(new Keyboard())
|
||
.use(new Clipboard())
|
||
.use(new History())
|
||
// #endregion
|
||
|
||
// #region 初始化 stencil
|
||
const stencil = new Stencil({
|
||
title: '',
|
||
target: graph,
|
||
stencilGraphWidth: 300,
|
||
stencilGraphHeight: 180,
|
||
stencilGraphOptions: { panning: false },
|
||
collapsable: false,
|
||
groups: [
|
||
// {
|
||
// title: '基础流程图',
|
||
// name: 'group1',
|
||
// },
|
||
{
|
||
collapsable: false,
|
||
title: '设备',
|
||
name: 'group2',
|
||
graphHeight: 550,
|
||
layoutOptions: {
|
||
rowHeight: 120,
|
||
},
|
||
},
|
||
// {
|
||
// collapsable: false,
|
||
// title: '管线',
|
||
// name: 'group3',
|
||
// graphHeight: 400,
|
||
// layoutOptions: {
|
||
// rowHeight: 120,
|
||
// },
|
||
// },
|
||
],
|
||
|
||
layoutOptions: {
|
||
columns: 2,
|
||
columnWidth: 140,
|
||
rowHeight: 100,
|
||
},
|
||
getDragNode: (sourceNode:any) => {
|
||
console.log('1111')
|
||
let node:any = sourceNode
|
||
if (node.data && node.data.lineStyle) {
|
||
// 应用管线样式到连接线
|
||
const lineStyle = node.data.lineStyle
|
||
graph.options.connecting.createEdge = () => {
|
||
return new Shape.Edge({
|
||
attrs: {
|
||
line: {
|
||
stroke: '#A2B1C3',
|
||
strokeWidth: 2,
|
||
strokeDasharray: lineStyle.strokeDasharray,
|
||
targetMarker: lineStyle.targetMarker,
|
||
sourceMarker: lineStyle.sourceMarker
|
||
}
|
||
},
|
||
zIndex: 0
|
||
})
|
||
}
|
||
// 移除管线节点,因为它只是一个样式选择器
|
||
setTimeout(() => {
|
||
graph.removeNode(node)
|
||
}, 100)
|
||
return null
|
||
}
|
||
return sourceNode.clone({ deep: true })
|
||
},
|
||
// getDropNode: (draggingNode) => {
|
||
// return draggingNode.clone({ deep: true })
|
||
// },
|
||
})
|
||
|
||
graph.on('node:contextmenu', ({ e, node }) => {
|
||
selectedNode.value = node
|
||
e.preventDefault()
|
||
// 显示自定义上下文菜单,包含箭头样式选项
|
||
const pos = node.position?.() || { x: 0, y: 0 }
|
||
showContextMenu(pos.x, pos.y)
|
||
})
|
||
|
||
function showContextMenu(x: number, y: number) {
|
||
left.value = x + 260
|
||
top.value = y - 50
|
||
isMenuShow.value = true
|
||
}
|
||
graph.on('node:click', (row:any) => {
|
||
|
||
let node:any = row.node
|
||
nodeId.value = node.id
|
||
if( node.store.data.shape == 'rect'){
|
||
|
||
styleInfo.value = {
|
||
name: node.store.data.attrs.label.text,
|
||
color: node.store.data.attrs.body.stroke,
|
||
line: node.store.data.attrs.body.strokeDasharray == ''?'实线':'虚线',
|
||
width: node.store.data.attrs.body.strokeWidth,
|
||
remark: node.store.data.remark
|
||
}
|
||
}
|
||
row.e.preventDefault()
|
||
})
|
||
// 监听Stencil内部的Dnd事件
|
||
|
||
document
|
||
.getElementById('stencil')
|
||
?.appendChild(stencil.container as HTMLElement)
|
||
|
||
// 监听Graph中节点创建事件
|
||
graph.on('node:added', (args:any) => {
|
||
console.log('节点已添加到画布', args)
|
||
if(isLock.value == true){
|
||
return
|
||
}
|
||
|
||
|
||
|
||
const { node } = args
|
||
|
||
// 检查是否是管线节点
|
||
if (node.data && node.data.lineStyle) {
|
||
// 应用管线样式到连接线
|
||
const lineStyle = node.data.lineStyle
|
||
graph.options.connecting.createEdge = () => {
|
||
return new Shape.Edge({
|
||
attrs: {
|
||
line: {
|
||
stroke: '#A2B1C3',
|
||
strokeWidth: 2,
|
||
strokeDasharray: lineStyle.strokeDasharray,
|
||
targetMarker: lineStyle.targetMarker,
|
||
sourceMarker: lineStyle.sourceMarker
|
||
}
|
||
},
|
||
zIndex: 0
|
||
})
|
||
}
|
||
// 移除管线节点,因为它只是一个样式选择器
|
||
setTimeout(() => {
|
||
graph.removeNode(node)
|
||
}, 100)
|
||
} else {
|
||
if(node.store && node.store.data && node.store.data.shape === 'rect'){
|
||
nodeId.value = node.id
|
||
styleInfo.value = {
|
||
name: node.store.data.attrs.label.text,
|
||
color: '#ff0000',
|
||
line: '虚线',
|
||
width: node.store.data.attrs.body.strokeWidth,
|
||
remark: ''
|
||
|
||
}
|
||
node.store.data.remark = ''
|
||
return
|
||
}
|
||
|
||
node.size(160, 160)
|
||
// 去掉背景节点
|
||
node.attr('body/fill', 'none')
|
||
// 图片居中
|
||
node.attr('image/refX', 0)
|
||
node.attr('image/refY', 0)
|
||
// node.attr('label/refX', 40)
|
||
|
||
node.attr('image/width', 160) // 修改宽度
|
||
node.attr('image/height', 160) // 修改高度
|
||
|
||
|
||
nodeId.value = node.id
|
||
if(node.store.data.attrs.text.text == '圆柱槽'){
|
||
deviceTypetype.value = 'CylindricalTank'
|
||
node.size(110, 140)
|
||
const width = node.size().width
|
||
node.attr('image/xlink:href', '/assets/11.png')
|
||
node.attr('image/width', 105)
|
||
node.attr('image/height', 135)
|
||
node.attr('label/refY', 140)
|
||
node.attr('label/refX', width/2)
|
||
node.attr('label/textAnchor', 'middle')
|
||
}else if(node.store.data.attrs.text.text == '扁平槽'){
|
||
deviceTypetype.value = 'FlatTank'
|
||
|
||
node.size(130, 60)
|
||
const width = node.size().width
|
||
node.attr('image/xlink:href', '/assets/22.png')
|
||
node.attr('image/width', 130)
|
||
node.attr('image/height', 60)
|
||
node.attr('label/refY', 65)
|
||
node.attr('label/refX', width/2)
|
||
node.attr('label/textAnchor', 'middle')
|
||
|
||
|
||
}else if(node.store.data.attrs.text.text == '环形槽'){
|
||
deviceTypetype.value = 'AnnularTank'
|
||
|
||
node.size(90, 140)
|
||
const width = node.size().width
|
||
node.attr('image/xlink:href', '/assets/33.png')
|
||
node.attr('image/width', 90)
|
||
node.attr('image/height', 135)
|
||
node.attr('label/refY', 140)
|
||
node.attr('label/refX', width/2)
|
||
node.attr('label/textAnchor', 'middle')
|
||
|
||
|
||
}else if(node.store.data.attrs.text.text == '管束槽'){
|
||
deviceTypetype.value = 'TubeBundleTank'
|
||
node.size(80, 140)
|
||
const width = node.size().width
|
||
node.attr('image/xlink:href', '/assets/44.png')
|
||
node.attr('image/width', 80)
|
||
node.attr('image/height', 135)
|
||
node.attr('label/refY', 140)
|
||
node.attr('label/refX', width/2)
|
||
node.attr('label/textAnchor', 'middle')
|
||
}else if(node.store.data.attrs.text.text == '萃取柱'){
|
||
deviceTypetype.value = 'ExtractionColumn'
|
||
|
||
node.size(30, 140)
|
||
const width = node.size().width
|
||
node.attr('image/xlink:href', '/assets/55.png')
|
||
node.attr('image/width', 30)
|
||
node.attr('image/height', 135)
|
||
node.attr('label/refY', 140)
|
||
node.attr('label/refX', width/2)
|
||
node.attr('label/textAnchor', 'middle')
|
||
|
||
|
||
}else if(node.store.data.attrs.text.text == '流化床'){
|
||
deviceTypetype.value = 'FluidizedBed'
|
||
node.size(60, 140)
|
||
const width = node.size().width
|
||
node.attr('image/xlink:href', '/assets/66.png')
|
||
node.attr('image/width', 60)
|
||
node.attr('image/height', 135)
|
||
node.attr('label/refY', 140)
|
||
node.attr('label/refX', width/2)
|
||
node.attr('label/textAnchor', 'middle')
|
||
}else if(node.store.data.attrs.text.text == '锥底环形槽'){
|
||
deviceTypetype.value = 'ACFTank'
|
||
node.size(40, 140)
|
||
const width = node.size().width
|
||
node.attr('image/xlink:href', '/assets/77.png')
|
||
node.attr('image/width', 40)
|
||
node.attr('image/height', 135)
|
||
node.attr('label/refY', 140)
|
||
node.attr('label/refX', width/2)
|
||
node.attr('label/textAnchor', 'middle')
|
||
}
|
||
// 设置固定大小
|
||
|
||
// 删除节点上的文字
|
||
// node.attr('text/text', '')
|
||
// node.attr('label/text', '')
|
||
isAdddevice.value = true
|
||
|
||
|
||
}
|
||
|
||
})
|
||
|
||
graph.on('edge:selected', ({ edge }) => {
|
||
let edgeTemp :any = edge
|
||
edge.addTools({
|
||
name: 'button-remove',
|
||
args: {
|
||
x: 0,
|
||
y: 0,
|
||
offset: { x: 10, y: 10 },
|
||
},
|
||
})
|
||
edge.addTools({
|
||
name: 'vertices', // 指定使用 vertices 工具
|
||
args: {
|
||
// 可选配置参数
|
||
snapRadius: 20, // 移动时的吸附半径
|
||
addable: true, // 是否允许单击边添加顶点
|
||
removable: true, // 是否允许双击顶点删除
|
||
attrs: { // 自定义顶点的样式(小圆点)
|
||
r: 6,
|
||
fill: edgeTemp.store.data.attrs.line.stroke,
|
||
},
|
||
},
|
||
})
|
||
|
||
|
||
|
||
});
|
||
graph.on('edge:unselected', ({ edge }) => {
|
||
edge.removeTools()
|
||
})
|
||
|
||
|
||
|
||
// #endregion
|
||
|
||
// #region 快捷键与事件
|
||
graph.bindKey(['meta+c', 'ctrl+c'], () => {
|
||
const cells = graph.getSelectedCells()
|
||
if (cells.length) {
|
||
graph.copy(cells)
|
||
}
|
||
return false
|
||
})
|
||
graph.bindKey(['meta+x', 'ctrl+x'], () => {
|
||
const cells = graph.getSelectedCells()
|
||
if (cells.length) {
|
||
graph.cut(cells)
|
||
}
|
||
return false
|
||
})
|
||
graph.bindKey(['meta+v', 'ctrl+v'], () => {
|
||
if (!graph.isClipboardEmpty()) {
|
||
const cells = graph.paste({ offset: 32 })
|
||
graph.cleanSelection()
|
||
graph.select(cells)
|
||
}
|
||
return false
|
||
})
|
||
|
||
// undo redo
|
||
graph.bindKey(['meta+z', 'ctrl+z'], () => {
|
||
if (graph.canUndo()) {
|
||
graph.undo()
|
||
}
|
||
return false
|
||
})
|
||
graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
|
||
if (graph.canRedo()) {
|
||
graph.redo()
|
||
}
|
||
return false
|
||
})
|
||
|
||
// select all
|
||
graph.bindKey(['meta+a', 'ctrl+a'], () => {
|
||
const nodes = graph.getNodes()
|
||
if (nodes) {
|
||
graph.select(nodes)
|
||
}
|
||
})
|
||
graph.bindKey('delete', () => {
|
||
const cells = graph.getSelectedCells()
|
||
if (cells.length) {
|
||
graph.removeCells(cells)
|
||
}
|
||
})
|
||
|
||
// zoom
|
||
graph.bindKey(['ctrl+1', 'meta+1'], () => {
|
||
const zoom = graph.zoom()
|
||
if (zoom < 1.5) {
|
||
graph.zoom(0.1)
|
||
}
|
||
})
|
||
graph.bindKey(['ctrl+2', 'meta+2'], () => {
|
||
const zoom = graph.zoom()
|
||
if (zoom > 0.5) {
|
||
graph.zoom(-0.1)
|
||
}
|
||
})
|
||
|
||
|
||
|
||
|
||
let startPoint:any = null // 矩形起点
|
||
|
||
// 监听鼠标按下事件:记录起点
|
||
graph.on('blank:mousedown', (e) => {
|
||
startPoint = { x: e.x, y: e.y }
|
||
})
|
||
|
||
// 监听鼠标松开事件:绘制矩形
|
||
graph.on('blank:mouseup', (e) => {
|
||
console.log('鼠标松开事件', e)
|
||
if (!startPoint) return
|
||
|
||
if(isBoundary.value == false){
|
||
return
|
||
}
|
||
|
||
|
||
const endPoint = { x: e.x, y: e.y }
|
||
if(Math.abs(endPoint.x - startPoint.x) <20 && Math.abs(endPoint.y - startPoint.y) <20){
|
||
return
|
||
}
|
||
const width = Math.abs(endPoint.x - startPoint.x)
|
||
const height = Math.abs(endPoint.y - startPoint.y)
|
||
const x = Math.min(startPoint.x, endPoint.x)
|
||
const y = Math.min(startPoint.y, endPoint.y)
|
||
|
||
// 添加矩形节点(设置 zIndex 为 -1 确保在最底层)
|
||
graph.addNode({
|
||
shape: 'rect',
|
||
x,
|
||
y,
|
||
width,
|
||
height,
|
||
zIndex: -1, // 关键:置于底层
|
||
// interactive: false, // 禁用所有交互
|
||
// selectable: false, // 明确禁止选中
|
||
draggable: false, // 明确禁止移动
|
||
interacting: {
|
||
nodeMovable: false, // 禁止所有节点移动
|
||
},
|
||
attrs: {
|
||
body: {
|
||
fill: 'transparent',
|
||
stroke: '#ff0000',
|
||
strokeWidth: 1,
|
||
strokeDasharray: '5 5', // 设置虚线样式
|
||
},
|
||
label: {
|
||
text: '系统边界',
|
||
refX: '50%',
|
||
refY: -15,
|
||
textAnchor: 'middle',
|
||
dominantBaseline: 'middle', // 文本自身的垂直居中
|
||
fontSize: 15,
|
||
fill: '#333333'
|
||
}
|
||
},
|
||
})
|
||
|
||
startPoint = null // 重置起点
|
||
})
|
||
|
||
|
||
// 控制连接桩显示/隐藏
|
||
const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
|
||
for (let i = 0, len = ports.length; i < len; i += 1) {
|
||
ports[i].style.visibility = show ? 'visible' : 'hidden'
|
||
}
|
||
}
|
||
graph.on('node:mouseenter', () => {
|
||
const container = document.getElementById('graph-container') as HTMLElement
|
||
const ports = container.querySelectorAll(
|
||
'.x6-port-body',
|
||
) as NodeListOf<SVGElement>
|
||
showPorts(ports, true)
|
||
})
|
||
graph.on('node:mouseleave', () => {
|
||
const container = document.getElementById('graph-container') as HTMLElement
|
||
const ports = container.querySelectorAll(
|
||
'.x6-port-body',
|
||
) as NodeListOf<SVGElement>
|
||
showPorts(ports, false)
|
||
})
|
||
// #endregion
|
||
|
||
// #region 初始化图形
|
||
const ports = {
|
||
groups: {
|
||
top: {
|
||
position: 'top',
|
||
attrs: {
|
||
circle: {
|
||
r: 8,
|
||
magnet: true,
|
||
stroke: '#5F95FF',
|
||
strokeWidth: 1,
|
||
fill: '#fff',
|
||
style: {
|
||
visibility: 'hidden',
|
||
},
|
||
},
|
||
},
|
||
},
|
||
right: {
|
||
position: 'right',
|
||
attrs: {
|
||
circle: {
|
||
r: 8,
|
||
magnet: true,
|
||
stroke: '#5F95FF',
|
||
strokeWidth: 1,
|
||
fill: '#fff',
|
||
style: {
|
||
visibility: 'hidden',
|
||
},
|
||
},
|
||
},
|
||
},
|
||
bottom: {
|
||
position: 'bottom',
|
||
attrs: {
|
||
circle: {
|
||
r: 8,
|
||
magnet: true,
|
||
stroke: '#5F95FF',
|
||
strokeWidth: 1,
|
||
fill: '#fff',
|
||
style: {
|
||
visibility: 'hidden',
|
||
},
|
||
},
|
||
},
|
||
},
|
||
left: {
|
||
position: 'left',
|
||
attrs: {
|
||
circle: {
|
||
r: 8,
|
||
magnet: true,
|
||
stroke: '#5F95FF',
|
||
strokeWidth: 1,
|
||
fill: '#fff',
|
||
style: {
|
||
visibility: 'hidden',
|
||
},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
items: [
|
||
{
|
||
group: 'top',
|
||
},
|
||
{
|
||
group: 'right',
|
||
},
|
||
{
|
||
group: 'bottom',
|
||
},
|
||
{
|
||
group: 'left',
|
||
},
|
||
],
|
||
}
|
||
Graph.registerNode(
|
||
'custom-image',
|
||
{
|
||
inherit: 'rect',
|
||
width: 130,
|
||
height: 100,
|
||
markup: [
|
||
{
|
||
tagName: 'rect',
|
||
selector: 'body',
|
||
},
|
||
{
|
||
tagName: 'image',
|
||
},
|
||
{
|
||
tagName: 'text',
|
||
selector: 'label',
|
||
},
|
||
],
|
||
attrs: {
|
||
body: {
|
||
stroke: 'transparent',
|
||
fill: '#f8f8f8',
|
||
},
|
||
image: {
|
||
width: 62,
|
||
height:84,
|
||
refX: 35,
|
||
refY: 0,
|
||
},
|
||
label: {
|
||
refX: 45,
|
||
refY: 80,
|
||
textAnchor: 'start',
|
||
textVerticalAnchor: 'top',
|
||
fontSize: 14,
|
||
fill: '#000',
|
||
},
|
||
},
|
||
ports: { ...ports },
|
||
},
|
||
true,
|
||
)
|
||
Graph.registerNode(
|
||
'rect-text',
|
||
{
|
||
inherit: 'rect',
|
||
width: 120,
|
||
height: 60,
|
||
markup: [
|
||
{
|
||
tagName: 'rect',
|
||
selector: 'body',
|
||
},
|
||
{
|
||
tagName: 'image',
|
||
selector: 'img',
|
||
},
|
||
{
|
||
tagName: 'text',
|
||
selector: 'label',
|
||
},
|
||
],
|
||
attrs: {
|
||
body: {
|
||
stroke: 'transparent',
|
||
strokeWidth: 1,
|
||
fill: 'transparent',
|
||
rx: 6,
|
||
ry: 6,
|
||
},
|
||
label: {
|
||
text: '',
|
||
fill: '#333',
|
||
fontSize: 12,
|
||
refX: 0.5,
|
||
refY: 0.5,
|
||
textAnchor: 'middle',
|
||
dy: 10,
|
||
},
|
||
'.': {
|
||
class: 'custom-image-node',
|
||
},
|
||
},
|
||
},
|
||
true,
|
||
)
|
||
const imageShapes = [
|
||
{
|
||
label: '圆柱槽',
|
||
image: '/assets/1.png',
|
||
},
|
||
{
|
||
label: '扁平槽',
|
||
image: '/assets/2.png',
|
||
},
|
||
{
|
||
label: '环形槽',
|
||
image: '/assets/3.png',
|
||
},
|
||
{
|
||
label: '管束槽',
|
||
image: '/assets/4.png',
|
||
},
|
||
{
|
||
label: '萃取柱',
|
||
image: '/assets/5.png',
|
||
},
|
||
{
|
||
label: '流化床',
|
||
image: '/assets/6.png',
|
||
},{
|
||
label: '锥底环形槽',
|
||
image: '/assets/7.png',
|
||
},
|
||
]
|
||
const imageNodes = imageShapes.map((item) =>
|
||
graph.createNode({
|
||
shape: 'custom-image',
|
||
label: item.label,
|
||
attrs: {
|
||
image: {
|
||
'xlink:href': item.image,
|
||
},
|
||
},
|
||
}),
|
||
)
|
||
stencil.load(imageNodes, 'group2')
|
||
|
||
// 创建管线节点
|
||
const lineShapes = [
|
||
{
|
||
label: '实线',
|
||
image: line1,
|
||
targetMarker: null,
|
||
sourceMarker: null,
|
||
strokeDasharray: 0
|
||
},
|
||
{
|
||
label: '单箭头实线',
|
||
image: line2,
|
||
targetMarker: {
|
||
name: 'block',
|
||
width: 12,
|
||
height: 8
|
||
},
|
||
sourceMarker: null,
|
||
strokeDasharray: 0
|
||
},
|
||
{
|
||
label: '双箭头实线',
|
||
image: line3,
|
||
targetMarker: {
|
||
name: 'block',
|
||
width: 12,
|
||
height: 8
|
||
},
|
||
sourceMarker: {
|
||
name: 'block',
|
||
width: 12,
|
||
height: 8
|
||
},
|
||
strokeDasharray: 0
|
||
},
|
||
{
|
||
label: '虚线',
|
||
image: line4,
|
||
targetMarker: null,
|
||
sourceMarker: null,
|
||
strokeDasharray: 5
|
||
},
|
||
{
|
||
label: '单箭头虚线',
|
||
image: line5,
|
||
targetMarker: {
|
||
name: 'block',
|
||
width: 12,
|
||
height: 8
|
||
},
|
||
sourceMarker: null,
|
||
strokeDasharray: 5
|
||
},
|
||
{
|
||
label: '双箭头虚线',
|
||
image: line6,
|
||
targetMarker: {
|
||
name: 'block',
|
||
width: 12,
|
||
height: 8
|
||
},
|
||
sourceMarker: {
|
||
name: 'block',
|
||
width: 12,
|
||
height: 8
|
||
},
|
||
strokeDasharray: 5
|
||
}
|
||
]
|
||
|
||
const lineNodes = lineShapes.map((item) => {
|
||
// 创建一个节点来显示管线样式
|
||
const node = graph.createNode({
|
||
shape: 'custom-image',
|
||
label: item.label,
|
||
width: 130,
|
||
height: 100,
|
||
attrs: {
|
||
image: {
|
||
'xlink:href': item.image,
|
||
width: 31,
|
||
height: 31,
|
||
refX: 50,
|
||
refY: 20
|
||
},
|
||
body: {
|
||
stroke: 'transparent',
|
||
fill: '#f8f8f8'
|
||
},
|
||
label: {
|
||
text: item.label,
|
||
refX: 60,
|
||
refY: 65,
|
||
textAnchor: 'middle',
|
||
fontSize: 12,
|
||
fill: '#666'
|
||
}
|
||
},
|
||
data: {
|
||
lineStyle: {
|
||
strokeDasharray: item.strokeDasharray,
|
||
targetMarker: item.targetMarker,
|
||
sourceMarker: item.sourceMarker
|
||
}
|
||
}
|
||
})
|
||
|
||
return node
|
||
})
|
||
|
||
stencil.load(lineNodes, 'group3')
|
||
if (!graph || !projectInfo.value || !projectInfo.value.topology) return;
|
||
graph.clearCells();
|
||
projectsById({projectId:props.projectInfo.projectId}).then((res:any) => {
|
||
if(res.topology != null && res.topology != ''){
|
||
projectInfo.value = res
|
||
if (!graph || !projectInfo.value || !projectInfo.value.topology) return;
|
||
graph.clearCells();
|
||
const topology:any = JSON.parse(projectInfo.value.topology)
|
||
if(!topology.designData)return
|
||
graph.fromJSON(topology.designData);
|
||
}
|
||
|
||
})
|
||
// #endregion
|
||
})
|
||
|
||
function preWork() {
|
||
// 这里协助演示的代码,在实际项目中根据实际情况进行调整
|
||
const container = document.getElementById('container') as HTMLElement
|
||
const stencilContainer = document.createElement('div')
|
||
stencilContainer.id = 'stencil'
|
||
const graphContainer = document.createElement('div')
|
||
graphContainer.id = 'graph-container'
|
||
container.appendChild(stencilContainer)
|
||
container.appendChild(graphContainer)
|
||
|
||
insertCss(`
|
||
#container {
|
||
display: flex;
|
||
border: 1px solid #dfe3e8;
|
||
width: 100vw;
|
||
height: calc(100vh - 60px);
|
||
}
|
||
#stencil {
|
||
width: 300px;
|
||
height: 100%;
|
||
position: relative;
|
||
border-right: 1px solid #dfe3e8;
|
||
}
|
||
.x6-widget-stencil-content{
|
||
top:0px !important;
|
||
}
|
||
.x6-widget-stencil-title{
|
||
display: none;
|
||
}
|
||
.x6-container-editbox #graph-container {
|
||
width: calc(100% - 180px);
|
||
height: 100% !important;
|
||
background-color: #f1f3fe;
|
||
}
|
||
.x6-widget-stencil {
|
||
background-color: #fff;
|
||
}
|
||
.x6-widget-stencil-title {
|
||
background-color: #fff;
|
||
}
|
||
.x6-widget-stencil-group-title {
|
||
background-color: #fff !important;
|
||
}
|
||
.x6-widget-transform {
|
||
margin: -1px 0 0 -1px;
|
||
padding: 0px;
|
||
border: 1px solid #239edd;
|
||
}
|
||
.x6-widget-transform > div {
|
||
border: 1px solid #239edd;
|
||
}
|
||
.x6-widget-transform > div:hover {
|
||
background-color: #3dafe4;
|
||
}
|
||
.x6-widget-transform-active-handle {
|
||
background-color: #3dafe4;
|
||
}
|
||
.x6-widget-transform-resize {
|
||
border-radius: 0;
|
||
}
|
||
.x6-widget-selection-inner {
|
||
border: 1px solid #239edd;
|
||
}
|
||
.x6-widget-selection-box {
|
||
opacity: 0;
|
||
}
|
||
`)
|
||
}
|
||
const left = ref(0)
|
||
const top = ref(0)
|
||
const isMenuShow = ref(false) // 是否显示右键菜单
|
||
const selectedNode:any = ref(null)
|
||
function deleteNode() { // 删除节点
|
||
graph.removeNode(selectedNode.value)
|
||
isMenuShow.value = false
|
||
}
|
||
|
||
|
||
|
||
const isCopy = ref(false)
|
||
const copyNodeInfo:any = ref(null)
|
||
function copyNode() { // 复制节点
|
||
if (selectedNode.value) {
|
||
try {
|
||
// 获取当前节点的位置
|
||
const position = selectedNode.value.position()
|
||
// 创建新节点,使用节点的原始数据
|
||
copyNodeInfo.value = selectedNode.value.clone()
|
||
// 设置新位置(偏移50px)
|
||
copyNodeInfo.value.position(position.x + 50, position.y + 50)
|
||
// deviceTypetype.value = newNode.store.data.deviceInfo.type
|
||
// 添加到画布
|
||
// graph.addNode(newNode)
|
||
copyDeviceInfo.value = {
|
||
oldname: copyNodeInfo.value.store.data.deviceInfo.name,
|
||
name:''
|
||
}
|
||
|
||
isMenuShow.value = false
|
||
isCopy.value = true
|
||
} catch (error) {
|
||
console.error('节点复制失败:', error)
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
function closeAntvx6() {
|
||
// let isSaveDesign = false
|
||
// const designData:any = graph.toJSON()
|
||
// for(let i = 0;i<designData.cells.length;i++){
|
||
// if(designData.cells[i].shape == 'rect-text' || designData.cells[i].shape == 'image-node'){
|
||
// isSaveDesign = true
|
||
// }
|
||
// }
|
||
// if(isSaveDesign == true){
|
||
// saveDesign(true)
|
||
// }
|
||
emit('closeAntvx6')
|
||
}
|
||
|
||
function revokeClick(){
|
||
if (graph.canUndo()) {
|
||
isLock.value = true
|
||
graph.undo()
|
||
setTimeout(() => {
|
||
isLock.value = false
|
||
}, 500);
|
||
}
|
||
}
|
||
function removeClick(){
|
||
if (graph.canRedo()) {
|
||
isLock.value = true
|
||
graph.redo()
|
||
setTimeout(() => {
|
||
isLock.value = false
|
||
}, 500);
|
||
}
|
||
}
|
||
function bigClick(){ // 放大画布
|
||
graph.zoom(0.1)
|
||
}
|
||
function smallClick(){ // 缩小画布
|
||
graph.zoom(-0.1)
|
||
}
|
||
function ConnectingwireClick(){ // 打开连接线弹窗
|
||
isConnectingwire.value = true;
|
||
}
|
||
function dialogConnectingwire(){ // 关闭连接线弹窗
|
||
isConnectingwire.value = false;
|
||
}
|
||
const connectingwireInfo:any = ref({
|
||
label: "实线",
|
||
strokeDasharray: "0",
|
||
arrow: "1",
|
||
strokeWidth: 2,
|
||
color: "#a2b1c3",
|
||
})
|
||
const lineLine:any = ref( "#a2b1c3")
|
||
function closeConnectingwireModel(e:any){ // 关闭连接线弹窗
|
||
if(e != false){
|
||
connectingwireInfo.value = e
|
||
lineLine.value = e.color
|
||
let lineStyle:any = {
|
||
strokeDasharray: 0,
|
||
targetMarker: {},
|
||
sourceMarker: {}
|
||
}
|
||
if(e.arrow == 0){
|
||
lineStyle = {
|
||
sourceMarker: null,
|
||
strokeDasharray: e.strokeDasharray,
|
||
targetMarker: null
|
||
}
|
||
}
|
||
if(e.arrow == 1){
|
||
lineStyle = {
|
||
sourceMarker: null,
|
||
strokeDasharray:e.strokeDasharray,
|
||
targetMarker: {
|
||
height: 8,
|
||
name: "block",
|
||
width: 12
|
||
}
|
||
}
|
||
}
|
||
if(e.arrow == 2){
|
||
lineStyle = {
|
||
sourceMarker: {
|
||
height: 8,
|
||
name: "block",
|
||
width: 12
|
||
},
|
||
strokeDasharray:e.strokeDasharray,
|
||
targetMarker: {
|
||
height: 8,
|
||
name: "block",
|
||
width: 12
|
||
}
|
||
}
|
||
}
|
||
graph.options.connecting.createEdge = () => {
|
||
return new Shape.Edge({
|
||
attrs: {
|
||
line: {
|
||
stroke: lineLine.value,
|
||
strokeWidth: e.strokeWidth,
|
||
strokeDasharray: lineStyle.strokeDasharray,
|
||
targetMarker: lineStyle.targetMarker,
|
||
sourceMarker: lineStyle.sourceMarker
|
||
}
|
||
},
|
||
zIndex: 0
|
||
})
|
||
}
|
||
}
|
||
isConnectingwire.value = false;
|
||
}
|
||
const nodeId = ref("")
|
||
|
||
|
||
|
||
function analysisAdd(){
|
||
dialogVisible.value = true;
|
||
}
|
||
const dialogVisible = ref(false)
|
||
function closeCreatescenario(){ // 关闭新增模拟分析弹窗
|
||
dialogVisible.value = false;
|
||
}
|
||
function simulationClick() { // 打开模拟分析
|
||
isScenario.value = true;
|
||
}
|
||
//取消按钮
|
||
function handleClose() {
|
||
isScenario.value = false;
|
||
}
|
||
|
||
function dialogAdddevice(){ // 打开新增设备弹窗
|
||
graph.undo()
|
||
isAdddevice.value = false;
|
||
}
|
||
const selectedDevice = ref({})
|
||
function closeAdddevice(e:any){ // 关闭新增设备弹窗
|
||
selectedDevice.value = e
|
||
let retrievedNode:any = graph.getCellById(nodeId.value)
|
||
retrievedNode.attr('text/text', e.name)
|
||
retrievedNode.attr('label/text', e.name)
|
||
retrievedNode.store.data.deviceInfo = e
|
||
saveDesign(false)
|
||
isAdddevice.value = false;
|
||
}
|
||
|
||
const deviceInfo:any = ref({}) // 是否编辑设备
|
||
|
||
function EditdeviceClick(){ // 打开编辑设备弹窗
|
||
deviceInfo.value = selectedNode.value.store.data.deviceInfo
|
||
nodeId.value = selectedNode.value.id
|
||
if(deviceInfo.value != null){
|
||
deviceTypetype.value = deviceInfo.value.type
|
||
}
|
||
isEditdevice.value = true;
|
||
}
|
||
function closeEditdevice(e:any){ // 关闭编辑设备弹窗
|
||
selectedDevice.value = e
|
||
let retrievedNode:any = graph.getCellById(nodeId.value)
|
||
retrievedNode.store.data.deviceInfo = e
|
||
retrievedNode.attr('text/text', e.name)
|
||
retrievedNode.attr('label/text', e.name)
|
||
isEditdevice.value = false;
|
||
saveDesign(false)
|
||
}
|
||
|
||
function dialogEditdevice(){ // 关闭设备弹窗
|
||
isEditdevice.value = false;
|
||
}
|
||
const materialInfo:any = ref({}) // 是否物料信息
|
||
const selectedMaterial:any = ref({})
|
||
|
||
|
||
function MaterialModelClick(){ // 打开物料信息弹窗
|
||
deviceInfo.value = selectedNode.value.store.data.deviceInfo
|
||
materialInfo.value = {}
|
||
if(selectedNode.value.store.data.materialInfo != null){
|
||
materialInfo.value = selectedNode.value.store.data.materialInfo
|
||
}
|
||
|
||
nodeId.value = selectedNode.value.id
|
||
if(materialInfo.value != null){
|
||
deviceTypetype.value = materialInfo.value.type
|
||
}
|
||
isMaterialModel.value = true;
|
||
}
|
||
function dialogMaterialModel(){ // 关闭物料信息弹窗
|
||
isMaterialModel.value = false;
|
||
}
|
||
function closeMaterialModel(e:any){ // 关闭物料信息弹窗
|
||
if(e == false){
|
||
isMaterialModel.value = false;
|
||
return
|
||
}
|
||
|
||
selectedMaterial.value = e
|
||
let retrievedNode:any = graph.getCellById(nodeId.value)
|
||
retrievedNode.store.data.materialInfo = e
|
||
saveDesign(false)
|
||
isMaterialModel.value = false;
|
||
}
|
||
|
||
const isConnectingwire = ref(false) // 是否连接线
|
||
// const connectingwireData:any = ref([]) // 是否连接线数据
|
||
|
||
const isChangesettings = ref(false)
|
||
const changesettingsData:any = ref([]) // 是否变动设置
|
||
function dialogChangesettings(){ // 关闭变动设置弹窗
|
||
isChangesettings.value = false;
|
||
}
|
||
function ChangesettingsClick(){ // 打开变动设置弹窗
|
||
changesettingsData.value = []
|
||
if(selectedNode.value.store.data.deviceInfo == null){
|
||
ElMessage({
|
||
type: "error",
|
||
message: "请先添加设备信息",
|
||
});
|
||
return
|
||
}
|
||
if(selectedNode.value.store.data.materialInfo == null){
|
||
ElMessage({
|
||
type: "error",
|
||
message: "请先添加物料信息",
|
||
});
|
||
return
|
||
}
|
||
deviceInfo.value = selectedNode.value.store.data.deviceInfo
|
||
materialInfo.value = selectedNode.value.store.data.materialInfo
|
||
|
||
if(selectedNode.value.store.data.changesettings != null){
|
||
changesettingsData.value = selectedNode.value.store.data.changesettings
|
||
}
|
||
|
||
nodeId.value = selectedNode.value.id
|
||
if(materialInfo.value != null){
|
||
deviceTypetype.value = materialInfo.value.type
|
||
}
|
||
isChangesettings.value = true;
|
||
}
|
||
|
||
function closeChangesettingsModel(e:any){ // 关闭变动设置弹窗
|
||
if(e == false){
|
||
isChangesettings.value = false;
|
||
return
|
||
}
|
||
selectedMaterial.value = e
|
||
let retrievedNode:any = graph.getCellById(nodeId.value)
|
||
retrievedNode.store.data.changesettings = e
|
||
isChangesettings.value = false;
|
||
}
|
||
|
||
function setFormulaInit(formula:any) {
|
||
// const formula = "【(圆柱槽B)*0.2+(环形槽A)*1.0+0.5】";
|
||
// 匹配*号后、+或)前的数字(支持整数和小数)
|
||
const regex = /([\*\/])(\d+\.?\d*)/g;
|
||
const coefficients = [];
|
||
let match;
|
||
|
||
// 循环提取所有匹配项
|
||
while ((match = regex.exec(formula)) !== null) {
|
||
if(!isNaN(parseFloat(match[1]))){
|
||
coefficients.push(parseFloat(match[1])); // 转为数字类型
|
||
}else if(!isNaN(parseFloat(match[2]))){
|
||
coefficients.push(parseFloat(match[2])); // 转为数字类型
|
||
}
|
||
|
||
}
|
||
console.log(coefficients); // 输出: [0.2, 1.0]
|
||
return coefficients
|
||
|
||
}
|
||
|
||
function getBias(formula:any){
|
||
// 从后往前找最后一个+的位置
|
||
// 匹配最后一个+号后面的数字(支持整数、小数)
|
||
if (formula.includes(' - ')){
|
||
const parts = formula.split(' - ');
|
||
// 处理以点开头的文件(如.gitignore)
|
||
return parseFloat('-' + parts.pop().toLowerCase()) ;
|
||
};
|
||
if (formula.includes(' + ')){
|
||
const parts = formula.split(' + ');
|
||
// 处理以点开头的文件(如.gitignore)
|
||
return parseFloat('+' + parts.pop().toLowerCase()) ;
|
||
};
|
||
return 0
|
||
// 从最后一个点分割,取后面的部分
|
||
|
||
|
||
}
|
||
|
||
const styleInfo:any = ref({
|
||
name: '',
|
||
color: '#409EFF',
|
||
line: '',
|
||
width: '',
|
||
remark: ''
|
||
})
|
||
|
||
function inputChange (e:any){
|
||
let node:any = graph.getCellById(nodeId.value)
|
||
node.attr('label/text', e)
|
||
}
|
||
function lineChange(e:any){
|
||
let node:any = graph.getCellById(nodeId.value)
|
||
if(e == '实线'){
|
||
node.attr('body/strokeDasharray', '')
|
||
}else{
|
||
node.attr('body/strokeDasharray', '5 5')
|
||
}
|
||
|
||
}
|
||
function widthChange(e:any){
|
||
let node:any = graph.getCellById(nodeId.value)
|
||
node.attr('body/strokeWidth', e)
|
||
}
|
||
|
||
function colorChangs(e:any){
|
||
let node:any = graph.getCellById(nodeId.value)
|
||
node.attr('body/stroke', e)
|
||
}
|
||
|
||
function remarkChange(e:any){
|
||
let node:any = graph.getCellById(nodeId.value)
|
||
node.store.data.remark = e
|
||
}
|
||
|
||
|
||
|
||
function saveDesign(is:any) { // 保存设计
|
||
try {
|
||
// 获取画布内容并转换为JSON
|
||
const designData:any = graph.toJSON()
|
||
// if(is == true){
|
||
// isDisplay.value = true
|
||
// for(let i = 0;i<designData.cells.length;i++){
|
||
// if(designData.cells[i].shape == 'rect-text' || designData.cells[i].shape == 'image-node'){
|
||
// graph.removeCell(designData.cells[i].id)
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
|
||
let cells:any = []
|
||
if(designData !=null && designData.cells.length>0){
|
||
cells = designData.cells
|
||
}
|
||
let devices = []
|
||
for(let i=0;i<cells.length;i++){
|
||
if(cells[i].shape == 'custom-image'){
|
||
let tempData:any = {}
|
||
if(cells[i].changesettings && cells[i].changesettings.length > 0){
|
||
for(let j=0;j<cells[i].changesettings.length;j++){
|
||
if(cells[i].changesettings[j].formula != '' && cells[i].changesettings[j].formula != null){
|
||
const key = cells[i].changesettings[j].name as string
|
||
const unit = cells[i].changesettings[j].unit
|
||
const name = cells[i].changesettings[j].name
|
||
const delay= cells[i].changesettings[j].delay
|
||
let tempSources = []
|
||
|
||
for(let k=0;k<setFormulaInit(cells[i].changesettings[j].formula).length;k++){
|
||
|
||
// name: '('+getName(key).name +')',
|
||
// key: getName(key).key,
|
||
// type: getName(key).type,
|
||
// parentName : getName(key).type == 'device' ? '('+item.deviceName +')' : '('+item.materialName +')',
|
||
// parentId : getName(key).type == 'device' ? item.deviceId : item.materialId
|
||
|
||
if(cells[i].changesettings[j].deviceMaterialData[k] == null){
|
||
return
|
||
}
|
||
|
||
tempSources.push({
|
||
entityType: cells[i].changesettings[j].deviceMaterialData[k].type, //圆柱槽B
|
||
entityId: cells[i].changesettings[j].deviceMaterialData[k].parentId , //materialId : cdeeca2e-1e0c-4bdd-b946-f347c104752c
|
||
property: cells[i].changesettings[j].deviceMaterialData[k].key, // 铀浓度(g/L)
|
||
coefficient: setFormulaInit(cells[i].changesettings[j].formula)[k], //0.2
|
||
delay: { enabled: true, time: cells[i].changesettings[j].deviceMaterialData[k].delay, unit: 's' } // 5
|
||
})
|
||
}
|
||
tempData[key] = {
|
||
name: tempData[key],
|
||
type:'influence',
|
||
unit:unit,
|
||
base:0,
|
||
bias: getBias(cells[i].changesettings[j].formula) || 0,
|
||
sources:tempSources,
|
||
expression:cells[i].changesettings[j].formula
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
if(cells[i].deviceInfo != null){
|
||
devices.push({
|
||
deviceId:cells[i].id,
|
||
name:cells[i].deviceInfo.name,
|
||
type:cells[i].deviceInfo.type,
|
||
properties:{},
|
||
material: cells[i].materialInfo != null ? {
|
||
materialId:cells[i].id,
|
||
name:cells[i].materialInfo.name,
|
||
properties:tempData
|
||
}:{}
|
||
})
|
||
}
|
||
|
||
}
|
||
}
|
||
const topology = {
|
||
projectId: projectInfo.value.projectId,
|
||
name: projectInfo.value.name,
|
||
devices:devices,
|
||
pipelines:[],
|
||
systemboundaries:[],
|
||
globalDisplay:{
|
||
device:{
|
||
showProperties:[]
|
||
},
|
||
material:{
|
||
showProperties:[]
|
||
},
|
||
|
||
},
|
||
designData:cells
|
||
}
|
||
// 添加保存信息
|
||
const saveData = {
|
||
projectId: projectInfo.value.projectId,
|
||
topology: JSON.stringify(topology)
|
||
}
|
||
updateProjects(saveData).then((res:any) => {
|
||
if(res === true){
|
||
ElMessage({
|
||
type: "success",
|
||
message: "保存成功",
|
||
});
|
||
}
|
||
});
|
||
// 返回保存的数据
|
||
return saveData
|
||
} catch (error) {
|
||
console.error('保存设计失败:', error)
|
||
return null
|
||
}
|
||
}
|
||
const isBoundary = ref(false)
|
||
const boundaryClick = () => {
|
||
isBoundary.value = !isBoundary.value
|
||
}
|
||
|
||
|
||
const copyDeviceInfo:any = ref({})
|
||
function dialogCopy(){
|
||
isCopy.value = false
|
||
}
|
||
const loading = ref(false)
|
||
const confirmCopyClick = async ()=>{
|
||
|
||
if(copyDeviceInfo.value.name == ''){
|
||
ElMessage({
|
||
type: "warning",
|
||
message: "请输入新设备名称",
|
||
});
|
||
return
|
||
}
|
||
loading.value = true
|
||
copyNodeInfo.value.store.data.attrs.label.text = copyDeviceInfo.value.name
|
||
copyNodeInfo.value.store.data.deviceInfo.name = copyDeviceInfo.value.name
|
||
copyNodeInfo.value.store.data.deviceInfo.code = copyDeviceInfo.value.code + '-copy'
|
||
copyNodeInfo.value.store.data.deviceInfo.deviceId = copyNodeInfo.value.id
|
||
|
||
if(copyNodeInfo.value.store.data.materialInfo != null && copyNodeInfo.value.store.data.materialInfo.materialId != null){
|
||
copyNodeInfo.value.store.data.materialInfo.materialId = copyNodeInfo.value.id
|
||
}
|
||
if(copyNodeInfo.value.store.data.changesettings != null &&
|
||
copyNodeInfo.value.store.data.changesettings.length >0){
|
||
for(let i=0;i<copyNodeInfo.value.store.data.changesettings.length;i++){
|
||
let changeSetting = copyNodeInfo.value.store.data.changesettings[i]
|
||
if(changeSetting.delayList != null && changeSetting.delayList.length >0){
|
||
for(let j=0;j<changeSetting.delayList.length;j++){
|
||
let delayList = changeSetting.delayList[j]
|
||
if(delayList.type == 'device'){
|
||
delayList.parentId = copyNodeInfo.value.id
|
||
delayList.parentName = copyDeviceInfo.value.name
|
||
}else if(delayList.type == 'material'){
|
||
delayList.parentId = copyNodeInfo.value.id
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
if(changeSetting.deviceMaterialData != null && changeSetting.deviceMaterialData.length >0){
|
||
for(let k=0;k<changeSetting.deviceMaterialData.length;k++){
|
||
let deviceMaterialData = changeSetting.deviceMaterialData[k]
|
||
if(deviceMaterialData.type == 'device'){
|
||
deviceMaterialData.parentId = copyNodeInfo.value.id
|
||
deviceMaterialData.parentName = copyDeviceInfo.value.name
|
||
}else if(deviceMaterialData.type == 'material'){
|
||
deviceMaterialData.parentId = copyNodeInfo.value.id
|
||
}
|
||
}
|
||
}
|
||
if(changeSetting.formulaData != null && changeSetting.formulaData.length >0){
|
||
for(let l=0;l<changeSetting.formulaData.length;l++){
|
||
let formulaData = changeSetting.formulaData[l]
|
||
if(typeof formulaData === 'object') {
|
||
if(formulaData.type == 'device'){
|
||
formulaData.parentId = copyNodeInfo.value.id
|
||
formulaData.parentName = copyDeviceInfo.value.name
|
||
}else if(formulaData.type == 'material'){
|
||
formulaData.parentId = copyNodeInfo.value.id
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
const deviceInfo = copyNodeInfo.value.store.data.deviceInfo
|
||
const materialInfo = copyNodeInfo.value.store.data.materialInfo
|
||
const result:any = await addDevices(deviceInfo);
|
||
if(result == false || result == undefined){
|
||
loading.value = false
|
||
ElMessage({
|
||
type: "success",
|
||
message: "复制失败",
|
||
});
|
||
return
|
||
}
|
||
if(materialInfo !=null && materialInfo.materialId != null){
|
||
const results:any = await saveOrUpdate(materialInfo);
|
||
if(results == false || results == undefined){
|
||
loading.value = false
|
||
ElMessage({
|
||
type: "success",
|
||
message: "复制失败",
|
||
});
|
||
return
|
||
}
|
||
}
|
||
isLock.value = true
|
||
graph.addNode(copyNodeInfo.value)
|
||
isLock.value = false
|
||
loading.value = false
|
||
saveDesign(false)
|
||
isCopy.value = false
|
||
}
|
||
|
||
|
||
|
||
function isDisplayClick(){
|
||
let tempGraph:any = graph.toJSON().cells
|
||
if(isDisplay.value == false){
|
||
isDisplay.value = true
|
||
for(let i = 0;i<tempGraph.length;i++){
|
||
if(tempGraph[i].shape == 'rect-text' || tempGraph[i].shape == 'image-node'){
|
||
graph.removeCell(tempGraph[i].id)
|
||
}
|
||
}
|
||
}else{
|
||
isDisplay.value = false
|
||
isLock.value = true
|
||
tempGraph.forEach((item:any,index:any) => {
|
||
let num = -1
|
||
let tempInfo = {...item.deviceInfo}
|
||
if(tempInfo.size != null && tempInfo.size != ''){
|
||
tempInfo = {...tempInfo, ...JSON.parse(tempInfo.size)}
|
||
}
|
||
if(item.materialInfo != null && item.materialInfo.materialId != null){
|
||
tempInfo = {...tempInfo,...item.materialInfo}
|
||
|
||
|
||
}
|
||
for (const key in tempInfo) {
|
||
if (!Object.hasOwn(tempInfo, key)) continue;
|
||
|
||
const element = tempInfo[key];
|
||
if(getName(key) != '' && tempInfo[key] != null){
|
||
if(isDisplay.value == true){
|
||
return
|
||
}
|
||
num = num + 1
|
||
graph.addNode({
|
||
shape: 'rect-text',
|
||
x: item.position.x,
|
||
y: item.position.y + 153 + num * 25,
|
||
width: 260,
|
||
height: 30,
|
||
// label: data[i].name + ':' + data[i].value,
|
||
attrs: {
|
||
body: {
|
||
stroke: 'transparent',
|
||
fill: 'transparent',
|
||
strokeWidth: 1,
|
||
},
|
||
label: {
|
||
textAnchor: 'left',
|
||
refX: 0,
|
||
text: getName(key) + ':' + element,
|
||
textWrap: {
|
||
width: 250,
|
||
height: 30,
|
||
ellipsis: true,
|
||
},
|
||
},
|
||
text: {
|
||
text: '',
|
||
fill: '#363636', // 蓝色文字
|
||
fontSize: 12,
|
||
},
|
||
},
|
||
})
|
||
}
|
||
}
|
||
})
|
||
isLock.value = false
|
||
}
|
||
|
||
}
|
||
|
||
function appendAttrText(key:any,element:any){
|
||
|
||
|
||
}
|
||
function getName(code:any) {
|
||
let name = ''
|
||
switch (code) {
|
||
case 'width':
|
||
return name = "宽度cm";
|
||
break;
|
||
case 'outer_diameter':
|
||
return name = "外径cm";
|
||
break;
|
||
case 'height':
|
||
return name = "高度cm";
|
||
break;
|
||
case 'length':
|
||
return name = "长度cm";
|
||
break;
|
||
case 'diameter':
|
||
return name = "外径cm";
|
||
break;
|
||
case 'volume':
|
||
return name = "容量(单位:L)";
|
||
break;
|
||
case 'flow_rate':
|
||
return name = "流量(单位:m3/h)";
|
||
break;
|
||
case 'flowRate':
|
||
return name = "流量(单位:m3/h)";
|
||
break;
|
||
case 'pulse_velocity':
|
||
return name = "脉冲速度(单位:Hz)";
|
||
break;
|
||
case 'pulseVelocity':
|
||
return name = "脉冲速度(单位:Hz)";
|
||
break;
|
||
case 'u_concentration':
|
||
return name = "铀浓度(g/L)";
|
||
break;
|
||
case 'uConcentration':
|
||
return name = "铀浓度(g/L)";
|
||
break;
|
||
case 'uo2_density':
|
||
return name = "氧化铀密度(g/cm3)";
|
||
break;
|
||
case 'uo2Density':
|
||
return name = "氧化铀密度(g/cm3)";
|
||
break;
|
||
case 'u_enrichment':
|
||
return name = "铀富集度(%)";
|
||
break;
|
||
case 'uEnrichment':
|
||
return name = "铀富集度(%)";
|
||
break;
|
||
case 'pu_concentration':
|
||
return name = "钚浓度(g/L)";
|
||
break;
|
||
case 'puConcentration':
|
||
return name = "钚浓度(g/L)";
|
||
break;
|
||
case 'puo2_density':
|
||
return name = "氧化钚密度(g/cm3)";
|
||
break;
|
||
case 'puo2Density':
|
||
return name = "氧化钚密度(g/cm3)";
|
||
break;
|
||
case 'pu_isotope':
|
||
return name = "钚同位素比例(PU-240占比)%";
|
||
break;
|
||
case 'puIsotope':
|
||
return name = "钚同位素比例(PU-240占比)%";
|
||
break;
|
||
case 'hno3_acidity':
|
||
return name = "硝酸酸度(mol/L)";
|
||
break;
|
||
case 'hno3Acidity':
|
||
return name = "硝酸酸度(mol/L)";
|
||
break;
|
||
case 'h2c2o4_concentration':
|
||
return name = "草酸浓度(mol/L)";
|
||
break;
|
||
case 'h2c2o4Concentration':
|
||
return name = "草酸浓度(mol/L)";
|
||
break;
|
||
case 'organic_ratio':
|
||
return name = "有机相比例%";
|
||
break;
|
||
case 'organicRatio':
|
||
return name = "有机相比例%";
|
||
break;
|
||
case 'moisture_content':
|
||
return name = "含水率%";
|
||
break;
|
||
case 'moistureContent':
|
||
return name = "含水率%";
|
||
break;
|
||
default:
|
||
return name = "";
|
||
}
|
||
return name
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div class="app-layout" @click="isMenuShow = false" >
|
||
<div class="antvx6-header">
|
||
<div class="header-left-box">
|
||
<div class="return-icon-box" @click="closeAntvx6" title="返回工作台">
|
||
<img src="@/assets/x6/return.png" alt="图标" style="cursor: pointer;">
|
||
</div>
|
||
<div class="project-name">{{ projectInfo.name }}</div>
|
||
<div class="return-icon-box" @click="analysisAdd" title="新增模拟分析">
|
||
<img src="@/assets/x6/add.png" alt="图标" style="cursor: pointer;">
|
||
</div>
|
||
<div class="return-icon-box" @click="simulationClick" title="历史模拟分析">
|
||
<img src="@/assets/x6/history.png" alt="图标" style="cursor: pointer;">
|
||
</div>
|
||
</div>
|
||
<div class="header-content-box">
|
||
<div class="operation-icon-box" @click="revokeClick">
|
||
<img src="@/assets/x6/revoke.png">
|
||
<div class="operation-icon-text">撤销</div>
|
||
</div>
|
||
<div class="operation-icon-box" @click="removeClick">
|
||
<img src="@/assets/x6/redo.png">
|
||
<div class="operation-icon-text">重做</div>
|
||
</div>
|
||
<div class="operation-icon-box" @click="bigClick">
|
||
<img src="@/assets/x6/magnify.png">
|
||
<div class="operation-icon-text">放大</div>
|
||
</div>
|
||
<div class="operation-icon-box" @click="smallClick">
|
||
<img src="@/assets/x6/reduce.png">
|
||
<div class="operation-icon-text">缩小</div>
|
||
</div>
|
||
<!-- <div class="operation-icon-box" @click="isDisplay = !isDisplay">
|
||
<img v-if="isDisplay" src="@/assets/x6/display.png">
|
||
<img v-else src="@/assets/x6/hide.png">
|
||
<div class="operation-icon-text">显示</div>
|
||
</div> -->
|
||
|
||
<!-- <div class="operation-icon-box" @click="isDisplayClick">
|
||
<img v-if="isDisplay" src="@/assets/x6/display.png">
|
||
<img v-else src="@/assets/x6/hide.png">
|
||
<div class="operation-icon-text">显示</div>
|
||
</div> -->
|
||
|
||
<div class="operation-icon-box" style="width: 60px;" @click="boundaryClick">
|
||
<img v-if="!isBoundary" src="@/assets/x6/display.png">
|
||
<img v-else src="@/assets/x6/hide.png">
|
||
<div v-if="!isBoundary" class="operation-icon-text">绘制边界</div>
|
||
<div v-else class="operation-icon-text">停止绘制</div>
|
||
</div>
|
||
|
||
<div class="operation-icon-box" @click="ConnectingwireClick">
|
||
<img src="@/assets/x6/line.png" style="margin: 5px 0;">
|
||
<div class="operation-icon-text">连接线</div>
|
||
</div>
|
||
|
||
<div class="operation-icon-box" @click="saveDesign(true)">
|
||
<img src="@/assets/x6/save.png">
|
||
<div class="operation-icon-text">保存</div>
|
||
</div>
|
||
</div>
|
||
<div class="header-left-box"></div>
|
||
</div>
|
||
<div id="container" style="position: relative;">
|
||
<div class="context-menu" v-if="isMenuShow" :style="{left: left +'px', top: top+'px'}">
|
||
<img src="@/assets/x6/info.png" alt="图标" title="设备信息" style="cursor: pointer;" @click="EditdeviceClick">
|
||
<img src="@/assets/x6/material.png" alt="图标" title="物料信息" style="cursor: pointer;" @click="MaterialModelClick">
|
||
<img src="@/assets/x6/change.png" alt="图标" title="变动设置" style="cursor: pointer;" @click="ChangesettingsClick">
|
||
<img src="@/assets/x6/copy.png" alt="图标" title="复制" style="cursor: pointer;" @click="copyNode">
|
||
<img src="@/assets/x6/del.png" alt="图标" title="删除" style="cursor: pointer;"
|
||
@click="deleteNode">
|
||
</div>
|
||
|
||
<div class="line-style-box">
|
||
<!-- <div class="DisplaySettingsButton">显示设置</div> -->
|
||
<div class="expansionandcontraction-box" v-if="isExpansionandcontraction == false" @click="isExpansionandcontraction = true">
|
||
<img src="@/assets/x6/expansionandcontraction-left.png">
|
||
</div>
|
||
<div v-if="isExpansionandcontraction == true" style="display: flex;align-items: center;">
|
||
<div class="expansionandcontraction-box" @click="isExpansionandcontraction = false">
|
||
<img src="@/assets/x6/expansionandcontraction-right.png">
|
||
</div>
|
||
<div class="style-content-box">
|
||
<div class="style-content-box-title">样式</div>
|
||
<div class="style-content-box-display">
|
||
<div class="style-content-box-key">名称</div>
|
||
<el-input v-model="styleInfo.name" style="width:200px" placeholder="" @input="inputChange"></el-input>
|
||
</div>
|
||
<div class="style-content-box-display">
|
||
<div class="style-content-box-key">线形</div>
|
||
<el-select v-model="styleInfo.line" style="width:200px" @change="lineChange">
|
||
<el-option label="实线" value="实线" />
|
||
<el-option label="虚线" value="虚线" />
|
||
</el-select>
|
||
|
||
</div>
|
||
<div class="style-content-box-display">
|
||
<div class="style-content-box-key">线宽</div>
|
||
<el-select v-model="styleInfo.width" style="width:200px" @change="widthChange">
|
||
|
||
<el-option label="1" value="1" />
|
||
<el-option label="2" value="2" />
|
||
<el-option label="3" value="3" />
|
||
<el-option label="4" value="4" />
|
||
<el-option label="5" value="5" />
|
||
<el-option label="6" value="6" />
|
||
<el-option label="7" value="7" />
|
||
<el-option label="8" value="8" />
|
||
<el-option label="9" value="9" />
|
||
<el-option label="10" value="10" />
|
||
</el-select>
|
||
</div>
|
||
<div class="style-content-box-display">
|
||
<div class="style-content-box-key">边线颜色</div>
|
||
<el-color-picker v-model="styleInfo.color" @change="colorChangs"></el-color-picker>
|
||
</div>
|
||
<div class="style-content-box-display" style="align-items: self-start;">
|
||
<div class="style-content-box-key" style="padding-top: 5px;">描述信息</div>
|
||
<el-input type="textarea" :rows="4" v-model="styleInfo.remark" style="width:200px" @input="remarkChange"></el-input>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
<Createscenario v-if="dialogVisible" :projectInfo="projectInfo" @closeCreatescenario ="closeCreatescenario"/>
|
||
<el-dialog v-model="isScenario" :close-on-click-modal="false"
|
||
:modal="false" draggable :before-close="handleClose" title="历史模拟分析"
|
||
append-to-body width="1142px">
|
||
<ScenarioModel v-if="isScenario" :projectInfo="projectInfo" ref="Scenario" />
|
||
</el-dialog>
|
||
<el-dialog v-model="isAdddevice" :close-on-click-modal="false"
|
||
:modal="false" draggable :before-close="dialogAdddevice" title="添加设备"
|
||
append-to-body width="1050px">
|
||
<AdddeviceModel v-if="isAdddevice == true" :deviceId="nodeId" :projectInfo="projectInfo"
|
||
:deviceTypetype="deviceTypetype" ref="Adddevice" @closeAdddevice="closeAdddevice"/>
|
||
</el-dialog>
|
||
|
||
<el-dialog v-model="isEditdevice" :close-on-click-modal="false" :modal="false" draggable :before-close="dialogEditdevice" title="设备信息" append-to-body width="1050px">
|
||
<EditdeviceModel v-if="isEditdevice == true" :deviceId="nodeId" :deviceInfo="deviceInfo"
|
||
:deviceTypetype="deviceTypetype" ref="Editdevice" @closeEditdevice="closeEditdevice"/>
|
||
</el-dialog>
|
||
|
||
<el-dialog v-model="isMaterialModel" :close-on-click-modal="false" :modal="false" draggable :before-close="dialogMaterialModel" title="物料信息" append-to-body width="1014px">
|
||
<MaterialModels v-if="isMaterialModel == true" :materialId="nodeId" :projectInfo="projectInfo"
|
||
:materialInfo="materialInfo" :deviceInfo="deviceInfo" :deviceTypetype="deviceTypetype" ref="MaterialModel" @closeMaterialModel="closeMaterialModel"/>
|
||
</el-dialog>
|
||
|
||
|
||
<el-dialog v-model="isChangesettings" :close-on-click-modal="false" :modal="false" draggable :before-close="dialogChangesettings" title="变动设置" append-to-body width="1014px">
|
||
<ChangesettingsModels v-if="isChangesettings == true" :materialId="nodeId" :projectInfo="projectInfo" :changesettingsData="changesettingsData"
|
||
:materialInfo="materialInfo" :deviceInfo="deviceInfo" ref="ChangesettingsModel" @closeChangesettingsModel="closeChangesettingsModel"/>
|
||
</el-dialog>
|
||
|
||
|
||
<el-dialog v-model="isConnectingwire" :close-on-click-modal="false" :modal="false" draggable :before-close="dialogConnectingwire" title="连接线" append-to-body width="1014px">
|
||
<div style="height: calc(100vh - 200px); overflow: auto;">
|
||
<ConnectingwireModel v-if="isConnectingwire == true" :connectingwireInfo="connectingwireInfo"
|
||
@closeConnectingwireModel="closeConnectingwireModel"/>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-dialog v-model="isCopy" :close-on-click-modal="false"
|
||
:modal="false"
|
||
draggable
|
||
:before-close="dialogCopy"
|
||
title="复制设备"
|
||
append-to-body width="600px">
|
||
<el-form ref="infoForm" :model="copyDeviceInfo" label-width="100px"
|
||
style="width: 100%;height: 200px;margin-top: 30px;" v-loading="loading" element-loading-text="正在复制中...">
|
||
<el-form-item label="复制设备" prop="code" style="width: 100%;">
|
||
<el-input v-model="copyDeviceInfo.oldname" style="width: 100%" placeholder="" disabled></el-input>
|
||
</el-form-item>
|
||
<el-form-item label="新设备名称" prop="name" style="width: 100%;">
|
||
<el-input v-model="copyDeviceInfo.name" style="width: 100%" placeholder="请输入设备名称"></el-input>
|
||
</el-form-item>
|
||
<span class="dialog-footer"
|
||
style="display: flex;display: -webkit-flex; justify-content: flex-end;-webkit-justify-content: flex-end;">
|
||
<el-button @click="dialogCopy">取 消</el-button>
|
||
<el-button type="primary" @click="confirmCopyClick">确 定</el-button>
|
||
</span>
|
||
</el-form>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.app-layout {
|
||
position: fixed;
|
||
z-index: 10;
|
||
display: flex;
|
||
flex-direction: column;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
font-family: 'Segoe UI', sans-serif;
|
||
}
|
||
|
||
.toolbar {
|
||
padding: 10px;
|
||
background-color: #f5f5f5;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
display: flex;
|
||
gap: 20px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.style-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
margin-right: 20px;
|
||
}
|
||
|
||
.style-group h4 {
|
||
margin: 0 0 5px 0;
|
||
font-size: 14px;
|
||
color: #333;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.toolbar button {
|
||
padding: 8px 16px;
|
||
border: 1px solid #d9d9d9;
|
||
border-radius: 4px;
|
||
background-color: #fff;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
transition: all 0.3s;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.toolbar button:hover {
|
||
border-color: #1890ff;
|
||
color: #1890ff;
|
||
}
|
||
|
||
.toolbar button:active {
|
||
background-color: #f0f0f0;
|
||
}
|
||
|
||
/* Sidebar Styles */
|
||
.sidebar {
|
||
width: 200px;
|
||
background-color: #ffffff;
|
||
border-right: 1px solid #e0e0e0;
|
||
overflow-y: auto;
|
||
padding: 16px;
|
||
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.sidebar-section {
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.sidebar-section h3 {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 12px;
|
||
padding-bottom: 8px;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.device-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 10px;
|
||
margin-bottom: 8px;
|
||
background-color: #fafafa;
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 4px;
|
||
cursor: grab;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.device-item:hover {
|
||
background-color: #f0f5ff;
|
||
border-color: #1890ff;
|
||
transform: translateY(-1px);
|
||
box-shadow: 0 2px 4px rgba(24, 144, 255, 0.2);
|
||
}
|
||
|
||
.device-item:active {
|
||
cursor: grabbing;
|
||
}
|
||
|
||
.device-icon {
|
||
font-size: 24px;
|
||
margin-right: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 32px;
|
||
height: 32px;
|
||
}
|
||
|
||
.device-name {
|
||
font-size: 13px;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* Graph Container Styles */
|
||
.graph-container {
|
||
flex: 1;
|
||
position: relative;
|
||
background-color: #fafafa;
|
||
overflow: hidden;
|
||
width: 100%;
|
||
height: 100%;
|
||
|
||
}
|
||
|
||
/* Drag and drop visual feedback */
|
||
.graph-container.drag-over {
|
||
background-color: #e6f7ff;
|
||
border: 2px dashed #1890ff;
|
||
}
|
||
|
||
.context-menu {
|
||
position: absolute;
|
||
z-index: 100;
|
||
background-color: #fff;
|
||
border: 1px solid #dfe3e8;
|
||
border-radius: 4px;
|
||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.15);
|
||
width: 240px;
|
||
height: 40px;
|
||
display: flex;
|
||
justify-content: space-around;
|
||
align-items: center;
|
||
}
|
||
</style>
|
||
<style>
|
||
.antvx6-content #graph-container {
|
||
flex: 1;
|
||
position: relative;
|
||
background-color: #fafafa;
|
||
overflow: hidden;
|
||
width: 100% !important;
|
||
height: calc(100%) !important;
|
||
}
|
||
.x6-widget-stencil-content {
|
||
top: 0px !important;
|
||
}
|
||
|
||
.antvx6-header {
|
||
width: 100%;
|
||
height: 60px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 10px;
|
||
background-color: #ffffff;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
}
|
||
|
||
.header-left-box {
|
||
width: 400px;
|
||
height: 60px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.header-content-box {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.return-icon-box {
|
||
width: 30px;
|
||
height: 30px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.return-icon-box:hover {
|
||
background-color: #eeeeee;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.antvx6-header .project-name {
|
||
font-family: 'Arial Negreta', 'Arial Normal', 'Arial';
|
||
font-weight: 700;
|
||
font-style: normal;
|
||
font-size: 16px;
|
||
color: #333333;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.antvx6-header .operation-icon-box {
|
||
width: 46px;
|
||
height: 46px;
|
||
display: flex;
|
||
align-content: center;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
cursor: pointer;
|
||
margin-right: 20px;
|
||
font-family: '微软雅黑';
|
||
font-weight: 400;
|
||
font-style: normal;
|
||
font-size: 12px;
|
||
color: #4B4B4B;
|
||
padding-top: 5px;
|
||
}
|
||
|
||
.antvx6-header .operation-icon-box:hover {
|
||
background-color: #eeeeee;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.operation-icon-text {
|
||
width: 100%;
|
||
text-align: center;
|
||
padding-top: 5px;
|
||
}
|
||
.line-style-box{
|
||
position: absolute;
|
||
right: 0;
|
||
height: 100%;
|
||
/* width: 100px; */
|
||
/* background-color: #d9d9d9; */
|
||
z-index: 10;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.expansionandcontraction-box{
|
||
width:15px;
|
||
height: 64px;
|
||
background-color: #ffffff;
|
||
border: 1px solid #cfcfcf;
|
||
|
||
border-radius: 10px 0 0 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
}
|
||
.style-content-box{
|
||
width: 300px;
|
||
height: calc(100vh - 60px);
|
||
border: 1px solid #cfcfcf;
|
||
border-top: none;
|
||
border-right: none;
|
||
background: #fff;
|
||
}
|
||
.style-content-box-title{
|
||
width: 100%;
|
||
height: 40px;
|
||
line-height: 40px;
|
||
text-align: left;
|
||
font-size: 14px;
|
||
font-family: 'Arial Negreta', 'Arial Normal', 'Arial';
|
||
font-weight: 700;
|
||
font-style: normal;
|
||
font-size: 14px;
|
||
color: #282828;
|
||
background-color: rgba(255, 255, 255, 1);
|
||
box-sizing: border-box;
|
||
border-bottom:1px solid rgba(238, 238, 238, 1);
|
||
padding-left: 15px;
|
||
}
|
||
|
||
.DisplaySettingsButton{
|
||
position: absolute;
|
||
left: -100px;
|
||
top: 20px;
|
||
width: 100px;
|
||
height: 40px;
|
||
line-height: 40px;
|
||
text-align: center;
|
||
font-size: 14px;
|
||
font-family: 'Arial Negreta', 'Arial Normal', 'Arial';
|
||
font-weight: 400;
|
||
font-style: normal;
|
||
font-size: 14px;
|
||
color: #282828;
|
||
background-color: rgba(255, 255, 255, 1);
|
||
border: none;
|
||
border-radius: 4px;
|
||
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.x6-graph-grid {
|
||
background-image: none !important;
|
||
}
|
||
.style-content-box-display{
|
||
display: flex;
|
||
align-items: center;
|
||
padding-top: 20px;
|
||
|
||
}
|
||
.style-content-box-key{
|
||
width: 80px;
|
||
text-align: right;
|
||
font-family: '微软雅黑';
|
||
font-weight: 400;
|
||
font-style: normal;
|
||
font-size: 14px;
|
||
color: #808080;
|
||
padding-right: 10px;
|
||
}
|
||
|
||
.x6-widget-stencil .x6-node.x6-node-immovable{
|
||
cursor: pointer;
|
||
}
|
||
</style> |