9 changed files with 416 additions and 24 deletions
@ -1,11 +1,386 @@ |
|||||
<template> |
<template> |
||||
<div class="app-container"> |
<div style="height: 100%;width: 100%"> |
||||
<span>你好</span> |
<el-row> |
||||
|
<el-col :span="4"> |
||||
|
<div style="text-align: center;margin-top: 10px;" > |
||||
|
<el-button icon="Plus" type="primary" @click="showAddDialog">新增节点</el-button> |
||||
|
<el-button type="primary" @click="save"> |
||||
|
<i class="ri-save-3-line"></i> 保存 |
||||
|
</el-button> |
||||
|
</div> |
||||
|
<div style="text-align: center;margin-top: 10px;" > |
||||
|
<el-button class="moduleButton" style="width: 50%;height: 100px;" :style="{background: checked ==='元数据'?'#ebf5ff':'none'}" @click="changeBackGround('元数据信息')"> |
||||
|
元数据信息模块 |
||||
|
</el-button> |
||||
|
</div> |
||||
|
<div style="text-align: center;margin-top: 10px"> |
||||
|
<el-button class="moduleButton" style="width: 50%;height: 100px" :style="{background: checked ==='其他模块'?'#ebf5ff':'none'}" @click="changeBackGround('其他模块')"> |
||||
|
其他模块----敬请期待 |
||||
|
</el-button> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="20"> |
||||
|
<div id="flow-container"></div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-dialog |
||||
|
v-model="showAdd" |
||||
|
title="新增审批节点" |
||||
|
width="500" |
||||
|
> |
||||
|
<el-form :model="addForm" class="demo-form-inline"> |
||||
|
<el-form-item label="审批角色/人员:"> |
||||
|
<el-radio-group v-model="addForm.roleOrUser"> |
||||
|
<el-radio-button label="Role" value="Role" /> |
||||
|
<el-radio-button label="User" value="User" /> |
||||
|
</el-radio-group> |
||||
|
</el-form-item> |
||||
|
<el-form-item v-if="addForm.roleOrUser === 'Role'" label="选择角色:"> |
||||
|
<el-select v-model="addForm.role"> |
||||
|
<el-option v-for="item in roleList" :value="item.roleKey+'-'+item.remark" :label="item.remark" :key="item.roleKey"></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item v-if="addForm.roleOrUser === 'User'" label="选择用户:"> |
||||
|
<el-input v-model="addForm.user" placeholder="请输入用户登录名"></el-input> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<template #footer> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button @click="showAdd = false">取消</el-button> |
||||
|
<el-button type="primary" @click="confirmAddNode"> |
||||
|
确定 |
||||
|
</el-button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-dialog> |
||||
</div> |
</div> |
||||
</template> |
</template> |
||||
<script setup> |
<script setup> |
||||
|
import { Graph, Cell, Shape } from '@antv/x6' |
||||
|
import {v4 as uuid} from 'uuid' |
||||
|
import { Stencil } from '@antv/x6-plugin-stencil' |
||||
|
import { Keyboard } from '@antv/x6-plugin-keyboard' |
||||
|
import { Selection } from '@antv/x6-plugin-selection' |
||||
|
import { Clipboard } from '@antv/x6-plugin-clipboard' |
||||
|
import { ref, nextTick, computed, watch, reactive, onMounted } from 'vue' |
||||
|
import { listRole } from "@/api/system/role"; |
||||
|
import {getflowList } from "@/api/flow/flow"; |
||||
|
|
||||
|
|
||||
|
let graph = null |
||||
|
const roleList = ref([]) |
||||
|
const data = ref([]) |
||||
|
const checked = ref('元数据') |
||||
|
const ports = ref({ |
||||
|
groups: { |
||||
|
top: { |
||||
|
position: 'top', |
||||
|
attrs: { |
||||
|
circle: { |
||||
|
r: 4, |
||||
|
magnet: true, |
||||
|
stroke: '#5F95FF', |
||||
|
strokeWidth: 1, |
||||
|
fill: '#fff', |
||||
|
style: { |
||||
|
visibility: 'hidden', |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
right: { |
||||
|
position: 'right', |
||||
|
attrs: { |
||||
|
circle: { |
||||
|
r: 4, |
||||
|
magnet: true, |
||||
|
stroke: '#5F95FF', |
||||
|
strokeWidth: 1, |
||||
|
fill: '#fff', |
||||
|
style: { |
||||
|
visibility: 'hidden', |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
bottom: { |
||||
|
position: 'bottom', |
||||
|
attrs: { |
||||
|
circle: { |
||||
|
r: 4, |
||||
|
magnet: true, |
||||
|
stroke: '#5F95FF', |
||||
|
strokeWidth: 1, |
||||
|
fill: '#fff', |
||||
|
style: { |
||||
|
visibility: 'hidden', |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
left: { |
||||
|
position: 'left', |
||||
|
attrs: { |
||||
|
circle: { |
||||
|
r: 4, |
||||
|
magnet: true, |
||||
|
stroke: '#5F95FF', |
||||
|
strokeWidth: 1, |
||||
|
fill: '#fff', |
||||
|
style: { |
||||
|
visibility: 'hidden', |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
items: [ |
||||
|
{ |
||||
|
group: 'top', |
||||
|
}, |
||||
|
{ |
||||
|
group: 'right', |
||||
|
}, |
||||
|
{ |
||||
|
group: 'bottom', |
||||
|
}, |
||||
|
{ |
||||
|
group: 'left', |
||||
|
}, |
||||
|
], |
||||
|
}) |
||||
|
const showAdd = ref(false) |
||||
|
const addForm = ref({roleOrUser:'Role',role:'',user:''}) |
||||
|
function confirmAddNode(){ |
||||
|
let node = { |
||||
|
"id": uuid(), |
||||
|
"shape": "activity", |
||||
|
"width": 100, |
||||
|
"height": 60, |
||||
|
"position": { |
||||
|
"x": 0, |
||||
|
"y": 0 |
||||
|
}, |
||||
|
} |
||||
|
if (addForm.value.roleOrUser === 'Role'){ |
||||
|
let split = addForm.value.role.split("-") |
||||
|
node.label = split[1] |
||||
|
node.code = split[0] |
||||
|
node.type = 'Role' |
||||
|
}else { |
||||
|
node.label = addForm.value.user |
||||
|
node.code = addForm.value.user |
||||
|
node.type = 'User' |
||||
|
} |
||||
|
graph.addNode(node) |
||||
|
showAdd.value = false |
||||
|
} |
||||
|
function showPorts (ports, show){ |
||||
|
for (let i = 0, len = ports.length; i < len; i += 1) { |
||||
|
ports[i].style.visibility = show ? 'visible' : 'hidden' |
||||
|
} |
||||
|
} |
||||
|
function register(){ |
||||
|
Graph.registerNode( |
||||
|
'activity', |
||||
|
{ |
||||
|
inherit: 'rect', |
||||
|
markup: [ |
||||
|
{ |
||||
|
tagName: 'rect', |
||||
|
selector: 'body', |
||||
|
}, |
||||
|
{ |
||||
|
tagName: 'image', |
||||
|
selector: 'img', |
||||
|
}, |
||||
|
{ |
||||
|
tagName: 'text', |
||||
|
selector: 'label', |
||||
|
}, |
||||
|
], |
||||
|
attrs: { |
||||
|
body: { |
||||
|
rx: 6, |
||||
|
ry: 6, |
||||
|
stroke: '#5F95FF', |
||||
|
fill: '#EFF4FF', |
||||
|
strokeWidth: 1, |
||||
|
}, |
||||
|
img: { |
||||
|
x: 6, |
||||
|
y: 6, |
||||
|
width: 16, |
||||
|
height: 16, |
||||
|
'xlink:href': |
||||
|
'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*pwLpRr7QPGwAAAAAAAAAAAAAARQnAQ', |
||||
|
}, |
||||
|
label: { |
||||
|
fontSize: 12, |
||||
|
fill: '#262626', |
||||
|
}, |
||||
|
}, |
||||
|
ports: { ...ports.value }, |
||||
|
}, |
||||
|
true, |
||||
|
) |
||||
|
Graph.registerEdge( |
||||
|
'bpmn-edge', |
||||
|
{ |
||||
|
inherit: 'edge', |
||||
|
attrs: { |
||||
|
line: { |
||||
|
stroke: '#A2B1C3', |
||||
|
strokeWidth: 2, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
true, |
||||
|
) |
||||
|
} |
||||
|
function changeBackGround(module){ |
||||
|
if (module === '元数据信息'){ |
||||
|
checked.value = '元数据' |
||||
|
} |
||||
|
if (module === '其他模块'){ |
||||
|
checked.value = '其他模块' |
||||
|
} |
||||
|
getflowList(checked.value).then(res=>{ |
||||
|
|
||||
|
}) |
||||
|
} |
||||
|
function showAddDialog(){ |
||||
|
showAdd.value = true |
||||
|
listRole({pageNum:1,pageSize:100,status:0}).then(res=>{ |
||||
|
roleList.value = res.rows; |
||||
|
}) |
||||
|
} |
||||
|
function save(){ |
||||
|
let json = graph.toJSON() |
||||
|
let array = json.cells; |
||||
|
console.log(array) |
||||
|
let flows = [] |
||||
|
if (array.length>0){ |
||||
|
for (let i = 0; i < array.length; i++) { |
||||
|
let cell = array[i] |
||||
|
if (cell.shape === "activity"){ |
||||
|
flows.push({ |
||||
|
id: cell.id, |
||||
|
code: cell.code, |
||||
|
text: cell.attrs.text.text, |
||||
|
type: cell.type, |
||||
|
x: cell.position.x, |
||||
|
y: cell.position.y, |
||||
|
parent: [], |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
for (let i = 0; i < array.length; i++) { |
||||
|
let cell = array[i] |
||||
|
if (cell.shape === "edge"){ |
||||
|
let target = cell.target.cell |
||||
|
let source = cell.source.cell |
||||
|
let sourceNode = flows.find(item => item.id === source) |
||||
|
let targetNode = flows.find(item => item.id === target) |
||||
|
if (sourceNode !== undefined && targetNode !== undefined){ |
||||
|
for (let j = 0; j < flows.length; j++) { |
||||
|
if (flows[j].id === target){ |
||||
|
flows[j].parent.push(source) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
console.log(flows) |
||||
|
} |
||||
|
function loadGraphData(){ |
||||
|
let array = [] |
||||
|
data.value.forEach((item) => { |
||||
|
let node = { |
||||
|
id: item.id, |
||||
|
code: item.code, |
||||
|
attrs: {text:{text: item.text}}, |
||||
|
position:{x:item.x,y:item.y}, |
||||
|
width: 100, |
||||
|
height: 60, |
||||
|
shape: "activity" |
||||
|
} |
||||
|
array.push(node) |
||||
|
}) |
||||
|
data.value.forEach((item) => { |
||||
|
if (item.parent && item.parent.length > 0){ |
||||
|
item.parent.forEach((parentNodeId) =>{ |
||||
|
let node = { |
||||
|
id: uuid(), |
||||
|
shape: 'edge', |
||||
|
source: {cell: parentNodeId}, |
||||
|
target: {cell: item.id} |
||||
|
} |
||||
|
array.push(node) |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
graph.fromJSON(array) |
||||
|
graph.zoomToFit({ padding:10, maxScale: 1 }) |
||||
|
} |
||||
|
onMounted(re=>{ |
||||
|
register() |
||||
|
graph = new Graph({ |
||||
|
container: document.getElementById('flow-container'), |
||||
|
width: 800, |
||||
|
height: 800, |
||||
|
grid:true, |
||||
|
autoResize: true, |
||||
|
connecting: { |
||||
|
router: 'orth', |
||||
|
}, |
||||
|
createEdge() { |
||||
|
return new Shape.Edge({ |
||||
|
"id": uuid(), |
||||
|
"shape": "bpmn-edge", |
||||
|
"source": "7", |
||||
|
"target": "13" |
||||
|
}); |
||||
|
} |
||||
|
}) |
||||
|
graph.use(new Keyboard()) |
||||
|
.use( |
||||
|
new Selection({ |
||||
|
rubberband: true, |
||||
|
showNodeSelectionBox: true, |
||||
|
}), |
||||
|
) |
||||
|
// select all |
||||
|
graph.bindKey(['meta+a', 'ctrl+a'], () => { |
||||
|
const nodes = graph.getNodes() |
||||
|
if (nodes) { |
||||
|
graph.select(nodes) |
||||
|
} |
||||
|
}) |
||||
|
// delete |
||||
|
graph.bindKey('backspace', () => { |
||||
|
const cells = graph.getSelectedCells() |
||||
|
if (cells.length) { |
||||
|
graph.removeCells(cells) |
||||
|
} |
||||
|
}) |
||||
|
graph.on('node:mouseenter', () => { |
||||
|
const container = document.getElementById('flow-container') |
||||
|
const ports = container.querySelectorAll('.x6-port-body',) |
||||
|
showPorts(ports, true) |
||||
|
}) |
||||
|
graph.on('node:mouseleave', () => { |
||||
|
const container = document.getElementById('flow-container') |
||||
|
const ports = container.querySelectorAll('.x6-port-body',) |
||||
|
showPorts(ports, false) |
||||
|
}) |
||||
|
loadGraphData() |
||||
|
}) |
||||
|
|
||||
</script> |
</script> |
||||
<style scoped lang="scss"> |
<style scoped lang="scss"> |
||||
|
.moduleButton:hover{ |
||||
|
background: #ebf5ff !important; |
||||
|
} |
||||
</style> |
</style> |
Loading…
Reference in new issue