|
|
|
@@ -13,13 +13,12 @@ import GlobalParamsDrawer from '../components/GlobalParamsDrawer'; |
|
|
|
import ModelMenu from '../components/ModelMenu'; |
|
|
|
import styles from './index.less'; |
|
|
|
import Props from './props'; |
|
|
|
import { findAllParentNodes, findFirstDuplicate } from './utils'; |
|
|
|
import { findAllParentNodes } from './utils'; |
|
|
|
|
|
|
|
let graph = null; |
|
|
|
|
|
|
|
const EditPipeline = () => { |
|
|
|
const navgite = useNavigate(); |
|
|
|
let contextMenu = {}; |
|
|
|
const locationParams = useParams(); //新版本获取路由参数接口 |
|
|
|
const graphRef = useRef(); |
|
|
|
const paramsDrawerRef = useRef(); |
|
|
|
@@ -31,10 +30,23 @@ const EditPipeline = () => { |
|
|
|
let dragSourceNode; |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
initMenu(); |
|
|
|
initGraph(); |
|
|
|
getFirstWorkflow(locationParams.id); |
|
|
|
|
|
|
|
const changeSize = () => { |
|
|
|
if (!graph || graph.get('destroyed')) return; |
|
|
|
if (!graphRef.current) return; |
|
|
|
graph.changeSize(graphRef.current.clientWidth, graphRef.current.clientHeight); |
|
|
|
graph.fitView(); |
|
|
|
}; |
|
|
|
|
|
|
|
window.addEventListener('resize', changeSize); |
|
|
|
return () => { |
|
|
|
window.removeEventListener('resize', changeSize); |
|
|
|
}; |
|
|
|
}, []); |
|
|
|
|
|
|
|
// 拖拽结束,添加新节点 |
|
|
|
const onDragEnd = (val) => { |
|
|
|
const { x, y } = val; |
|
|
|
const point = graph.getPointByClient(x, y); |
|
|
|
@@ -45,11 +57,14 @@ const EditPipeline = () => { |
|
|
|
y: point.y, |
|
|
|
id: val.component_name + '-' + s8(), |
|
|
|
isCluster: false, |
|
|
|
formError: true, |
|
|
|
}; |
|
|
|
// console.log('model', model); |
|
|
|
graph.addItem('node', model, false); |
|
|
|
}; |
|
|
|
const formChange = (val) => { |
|
|
|
|
|
|
|
// 节点数据发生变化 |
|
|
|
const handleFormChange = (val) => { |
|
|
|
if (graph) { |
|
|
|
const data = graph.save(); |
|
|
|
const index = data.nodes.findIndex((item) => { |
|
|
|
@@ -68,6 +83,8 @@ const EditPipeline = () => { |
|
|
|
graph.translate(lastPoint.x - newPoint.x, lastPoint.y - newPoint.y); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// 保存 |
|
|
|
const savePipeline = async (val) => { |
|
|
|
const [res, error] = await to(paramsDrawerRef.current.validateFields()); |
|
|
|
if (error) { |
|
|
|
@@ -76,13 +93,6 @@ const EditPipeline = () => { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const duplicateName = findFirstDuplicate(res.global_param || []); |
|
|
|
if (duplicateName) { |
|
|
|
message.error('全局参数配置有重复的参数名称:' + duplicateName); |
|
|
|
openParamsDrawer(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// const [propsRes, propsError] = await to(propsRef.current.getFieldsValue()); |
|
|
|
// if (propsError) { |
|
|
|
// message.error('基本信息必填项需配置'); |
|
|
|
@@ -108,6 +118,8 @@ const EditPipeline = () => { |
|
|
|
}); |
|
|
|
}, 500); |
|
|
|
}; |
|
|
|
|
|
|
|
// 渲染数据 |
|
|
|
const getGraphData = (data) => { |
|
|
|
if (graph) { |
|
|
|
// 修改历史数据有蓝色边框的问题 |
|
|
|
@@ -122,6 +134,8 @@ const EditPipeline = () => { |
|
|
|
}, 500); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// 处理并行边,暂时没有用 |
|
|
|
const processParallelEdgesOnAnchorPoint = ( |
|
|
|
edges, |
|
|
|
offsetDiff = 15, |
|
|
|
@@ -242,11 +256,11 @@ const EditPipeline = () => { |
|
|
|
} |
|
|
|
return false; |
|
|
|
}; |
|
|
|
|
|
|
|
// 复制节点 |
|
|
|
const cloneElement = (item) => { |
|
|
|
console.log(item); |
|
|
|
let data = graph.save(); |
|
|
|
const nodeId = s8(); |
|
|
|
console.log(item.getModel()); |
|
|
|
data.nodes.push({ |
|
|
|
...item.getModel(), |
|
|
|
label: item.getModel().label + '-copy', |
|
|
|
@@ -256,66 +270,22 @@ const EditPipeline = () => { |
|
|
|
}); |
|
|
|
graph.changeData(data); |
|
|
|
}; |
|
|
|
const getFirstWorkflow = (val) => { |
|
|
|
getWorkflowById(val).then((ret) => { |
|
|
|
if (ret && ret.data) { |
|
|
|
setGlobalParam(ret.data.global_param || []); |
|
|
|
} |
|
|
|
if (graph && ret.data && ret.data.dag) { |
|
|
|
getGraphData(JSON.parse(ret.data.dag)); |
|
|
|
} |
|
|
|
}); |
|
|
|
}; |
|
|
|
// 上下文菜单 |
|
|
|
const initMenu = () => { |
|
|
|
// const selectedNodes = this.selectedNodes; |
|
|
|
contextMenu = new G6.Menu({ |
|
|
|
getContent(evt) { |
|
|
|
const type = evt.item.getType(); |
|
|
|
const cloneDisplay = type === 'node' ? 'block' : 'none'; |
|
|
|
return ` |
|
|
|
<ul style="position: absolute; |
|
|
|
width: 100px; |
|
|
|
padding-left:0; |
|
|
|
display:flex; |
|
|
|
flex-direction: column; |
|
|
|
align-items:center; |
|
|
|
left: 0px; |
|
|
|
top: 0px; |
|
|
|
background-color: #ffffff; |
|
|
|
font-size: 14px; |
|
|
|
color: #333333; |
|
|
|
overflow-y: auto;"> |
|
|
|
<li style="padding: 10px 20px;cursor: pointer; display: ${cloneDisplay}" code="clone">复制</li> |
|
|
|
<li style="padding: 10px 20px;cursor: pointer;" code="delete">删除</li> |
|
|
|
</ul>`; |
|
|
|
}, |
|
|
|
handleMenuClick: (target, item) => { |
|
|
|
switch (target.getAttribute('code')) { |
|
|
|
case 'delete': |
|
|
|
graph.removeItem(item); |
|
|
|
break; |
|
|
|
case 'clone': |
|
|
|
cloneElement(item); |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
}, |
|
|
|
// offsetX and offsetY include the padding of the parent container |
|
|
|
// 需要加上父级容器的 padding-left 16 与自身偏移量 10 |
|
|
|
offsetX: 16 + 10, |
|
|
|
// 需要加上父级容器的 padding-top 24 、画布兄弟元素高度、与自身偏移量 10 |
|
|
|
offsetY: 0, |
|
|
|
// the types of items that allow the menu show up |
|
|
|
// 在哪些类型的元素上响应 |
|
|
|
itemTypes: ['node', 'edge'], |
|
|
|
}); |
|
|
|
|
|
|
|
initGraph(); |
|
|
|
// 获取流水线详情 |
|
|
|
const getFirstWorkflow = async (val) => { |
|
|
|
const [res] = await to(getWorkflowById(val)); |
|
|
|
if (res && res.data) { |
|
|
|
const { global_param, dag } = res.data; |
|
|
|
setGlobalParam(global_param || []); |
|
|
|
if (dag) { |
|
|
|
getGraphData(JSON.parse(dag)); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// 初始化图 |
|
|
|
const initGraph = () => { |
|
|
|
const contextMenu = initMenu(); |
|
|
|
G6.registerNode( |
|
|
|
'rect-node', |
|
|
|
{ |
|
|
|
@@ -515,6 +485,7 @@ const EditPipeline = () => { |
|
|
|
}, |
|
|
|
cursor: 'pointer', |
|
|
|
lineWidth: 1, |
|
|
|
lineAppendWidth: 4, |
|
|
|
opacity: 1, |
|
|
|
stroke: '#CDD0DC', |
|
|
|
radius: 1, |
|
|
|
@@ -527,19 +498,13 @@ const EditPipeline = () => { |
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
defaultCombo: { |
|
|
|
type: 'rect', |
|
|
|
fixCollapseSize: 70, |
|
|
|
style: { |
|
|
|
fill: '#00e0ff0d', |
|
|
|
stroke: '#00e0ff', |
|
|
|
lineDash: [5, 10], |
|
|
|
cursor: 'pointer', |
|
|
|
}, |
|
|
|
}, |
|
|
|
}); |
|
|
|
|
|
|
|
bindEvents(); |
|
|
|
}; |
|
|
|
|
|
|
|
const bindEvents = () => { |
|
|
|
graph.on('node:click', (e) => { |
|
|
|
e.stopPropagation(); |
|
|
|
if (e.target.get('name') !== 'anchor-point' && e.item) { |
|
|
|
// 获取所有的上游节点 |
|
|
|
const parentNodes = findAllParentNodes(graph, e.item); |
|
|
|
@@ -558,16 +523,6 @@ const EditPipeline = () => { |
|
|
|
type: |
|
|
|
targetAnchorIdx === 0 || targetAnchorIdx === 1 ? 'cubic-vertical' : 'cubic-horizontal', |
|
|
|
}); |
|
|
|
|
|
|
|
// update the curveOffset for parallel edges |
|
|
|
// const edges = graph.save().edges; |
|
|
|
// processParallelEdgesOnAnchorPoint(edges); |
|
|
|
// graph.getEdges().forEach((edge, i) => { |
|
|
|
// graph.updateItem(edge, { |
|
|
|
// curveOffset: edges[i].curveOffset, |
|
|
|
// curvePosition: edges[i].curvePosition, |
|
|
|
// }); |
|
|
|
// }); |
|
|
|
}); |
|
|
|
// 删除边时,修改 anchor-point 的 links 值 |
|
|
|
graph.on('afterremoveitem', (e) => { |
|
|
|
@@ -639,13 +594,56 @@ const EditPipeline = () => { |
|
|
|
graph.setItemState(e.item, 'drop', false); |
|
|
|
dropAnchorIdx = undefined; |
|
|
|
}); |
|
|
|
window.onresize = () => { |
|
|
|
if (!graph || graph.get('destroyed')) return; |
|
|
|
if (!graphRef.current) return; |
|
|
|
graph.changeSize(graphRef.current.clientWidth, graphRef.current.clientHeight); |
|
|
|
graph.fitView(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
// 上下文菜单 |
|
|
|
const initMenu = () => { |
|
|
|
const contextMenu = new G6.Menu({ |
|
|
|
getContent(evt) { |
|
|
|
const type = evt.item.getType(); |
|
|
|
const cloneDisplay = type === 'node' ? 'block' : 'none'; |
|
|
|
return ` |
|
|
|
<ul style="position: absolute; |
|
|
|
width: 100px; |
|
|
|
padding-left:0; |
|
|
|
display:flex; |
|
|
|
flex-direction: column; |
|
|
|
align-items:center; |
|
|
|
left: 0px; |
|
|
|
top: 0px; |
|
|
|
background-color: #ffffff; |
|
|
|
font-size: 14px; |
|
|
|
color: #333333; |
|
|
|
overflow-y: auto;"> |
|
|
|
<li style="padding: 10px 20px;cursor: pointer; display: ${cloneDisplay}" code="clone">复制</li> |
|
|
|
<li style="padding: 10px 20px;cursor: pointer;" code="delete">删除</li> |
|
|
|
</ul>`; |
|
|
|
}, |
|
|
|
handleMenuClick: (target, item) => { |
|
|
|
switch (target.getAttribute('code')) { |
|
|
|
case 'delete': |
|
|
|
graph.removeItem(item); |
|
|
|
break; |
|
|
|
case 'clone': |
|
|
|
cloneElement(item); |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
}, |
|
|
|
// offsetX and offsetY include the padding of the parent container |
|
|
|
// 需要加上父级容器的 padding-left 16 与自身偏移量 10 |
|
|
|
offsetX: 16 + 10, |
|
|
|
// 需要加上父级容器的 padding-top 24 、画布兄弟元素高度、与自身偏移量 10 |
|
|
|
offsetY: 0, |
|
|
|
// the types of items that allow the menu show up |
|
|
|
// 在哪些类型的元素上响应 |
|
|
|
itemTypes: ['node', 'edge'], |
|
|
|
}); |
|
|
|
|
|
|
|
return contextMenu; |
|
|
|
}; |
|
|
|
|
|
|
|
return ( |
|
|
|
<div className={styles['pipeline-container']}> |
|
|
|
<ModelMenu onComponentDragEnd={onDragEnd}></ModelMenu> |
|
|
|
@@ -687,7 +685,7 @@ const EditPipeline = () => { |
|
|
|
</div> |
|
|
|
<div className={styles['pipeline-container__workflow__graph']} ref={graphRef}></div> |
|
|
|
</div> |
|
|
|
<Props ref={propsRef} onParentChange={formChange}></Props> |
|
|
|
<Props ref={propsRef} onParentChange={handleFormChange}></Props> |
|
|
|
<GlobalParamsDrawer |
|
|
|
ref={paramsDrawerRef} |
|
|
|
open={paramsDrawerOpen} |
|
|
|
|