Browse Source

11

pull/7/head
YaHoo94 1 year ago
parent
commit
401c82aab0
26 changed files with 595 additions and 269 deletions
  1. +1
    -1
      react-ui/config/defaultSettings.ts
  2. BIN
      react-ui/public/assets/images/compoent-icon-6.png
  3. BIN
      react-ui/public/assets/images/component-icon-1.png
  4. BIN
      react-ui/public/assets/images/component-icon-2.png
  5. BIN
      react-ui/public/assets/images/component-icon-3.png
  6. BIN
      react-ui/public/assets/images/component-icon-4.png
  7. BIN
      react-ui/public/assets/images/component-icon-5.png
  8. BIN
      react-ui/public/assets/images/component-icon-7.png
  9. BIN
      react-ui/public/assets/images/mindspore模型转换.png
  10. BIN
      react-ui/public/assets/images/pipelieEditIcon.png
  11. BIN
      react-ui/public/assets/images/pipeline-canvas-back.png
  12. BIN
      react-ui/public/assets/images/pipeline-edit-icon.png
  13. BIN
      react-ui/public/assets/images/pytorch推理.png
  14. BIN
      react-ui/public/assets/images/pytorch训练.png
  15. BIN
      react-ui/public/assets/images/tensorflow模型转换.png
  16. BIN
      react-ui/public/assets/images/发送通知.png
  17. +34
    -1
      react-ui/src/global.less
  18. +109
    -111
      react-ui/src/pages/Experiment/experimentText/index.jsx
  19. +22
    -16
      react-ui/src/pages/Experiment/index.jsx
  20. +68
    -15
      react-ui/src/pages/Experiment/index.less
  21. +2
    -0
      react-ui/src/pages/Pipeline/editPipeline/editPipeline.less
  22. +258
    -82
      react-ui/src/pages/Pipeline/editPipeline/index.jsx
  23. +3
    -1
      react-ui/src/pages/Pipeline/editPipeline/modelMenus.jsx
  24. +31
    -0
      react-ui/src/pages/Pipeline/editPipeline/modelMenus.less
  25. +13
    -27
      react-ui/src/pages/Pipeline/index.jsx
  26. +54
    -15
      react-ui/src/pages/Pipeline/index.less

+ 1
- 1
react-ui/config/defaultSettings.ts View File

@@ -18,7 +18,7 @@ const Settings: ProLayoutProps & {
colorWeak: false, colorWeak: false,
title: '复杂智能软件', title: '复杂智能软件',
pwa: true, pwa: true,
logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
logo: '/assets/images/left-top-logo.png',
iconfontUrl: '', iconfontUrl: '',
token: { token: {
// 参见ts声明,demo 见文档,通过token 修改样式 // 参见ts声明,demo 见文档,通过token 修改样式


BIN
react-ui/public/assets/images/compoent-icon-6.png View File

Before After
Width: 72  |  Height: 72  |  Size: 1.5 kB

BIN
react-ui/public/assets/images/component-icon-1.png View File

Before After
Width: 29  |  Height: 29  |  Size: 688 B Width: 72  |  Height: 72  |  Size: 1.3 kB

BIN
react-ui/public/assets/images/component-icon-2.png View File

Before After
Width: 32  |  Height: 34  |  Size: 1.1 kB Width: 72  |  Height: 72  |  Size: 2.3 kB

BIN
react-ui/public/assets/images/component-icon-3.png View File

Before After
Width: 32  |  Height: 36  |  Size: 1.6 kB Width: 72  |  Height: 72  |  Size: 3.2 kB

BIN
react-ui/public/assets/images/component-icon-4.png View File

Before After
Width: 34  |  Height: 38  |  Size: 1.4 kB Width: 72  |  Height: 72  |  Size: 2.8 kB

BIN
react-ui/public/assets/images/component-icon-5.png View File

Before After
Width: 33  |  Height: 33  |  Size: 683 B Width: 72  |  Height: 72  |  Size: 1.2 kB

BIN
react-ui/public/assets/images/component-icon-7.png View File

Before After
Width: 31  |  Height: 31  |  Size: 738 B Width: 72  |  Height: 72  |  Size: 1.4 kB

BIN
react-ui/public/assets/images/mindspore模型转换.png View File

Before After
Width: 72  |  Height: 72  |  Size: 1.9 kB

BIN
react-ui/public/assets/images/pipelieEditIcon.png View File

Before After
Width: 42  |  Height: 40  |  Size: 1.1 kB

BIN
react-ui/public/assets/images/pipeline-canvas-back.png View File

Before After
Width: 2760  |  Height: 1886  |  Size: 350 kB

BIN
react-ui/public/assets/images/pipeline-edit-icon.png View File

Before After
Width: 42  |  Height: 40  |  Size: 1.1 kB

BIN
react-ui/public/assets/images/pytorch推理.png View File

Before After
Width: 72  |  Height: 72  |  Size: 2.3 kB

BIN
react-ui/public/assets/images/pytorch训练.png View File

Before After
Width: 72  |  Height: 72  |  Size: 4.8 kB

BIN
react-ui/public/assets/images/tensorflow模型转换.png View File

Before After
Width: 72  |  Height: 72  |  Size: 4.0 kB

BIN
react-ui/public/assets/images/发送通知.png View File

Before After
Width: 72  |  Height: 72  |  Size: 1.2 kB

+ 34
- 1
react-ui/src/global.less View File

@@ -31,7 +31,38 @@ body {
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }

.ant-pro-layout .ant-pro-layout-content{
padding: 10px;
}
.ant-pro-layout .ant-pro-layout-bg-list{
background:#f9fafb;
}
.ant-table-wrapper .ant-table-thead >tr>th{
background-color: #fff;
}
.ant-table-wrapper .ant-table-thead >tr>td{
background-color: #fff;
}
.ant-menu-light .ant-menu-item-selected{
background:rgba(197, 232, 255, 0.8)!important;
}
.ant-pro-base-menu-inline{
// height: 87vh;
background:#f2f5f7;
border-radius:0px 20px 20px 0px;
}
.ant-pro-layout .ant-pro-layout-content{
background-color: #fff;
}
.ant-pro-global-header-logo img{
height: 21px;
}
.ant-pro-layout .ant-layout-sider.ant-pro-sider{
height: 87vh;
}
.ant-pro-layout .ant-pro-layout-container{
height: 98vh;
}
ul, ul,
ol { ol {
list-style: none; list-style: none;
@@ -53,3 +84,5 @@ ol {
} }
} }
} }



+ 109
- 111
react-ui/src/pages/Experiment/experimentText/index.jsx View File

@@ -51,7 +51,7 @@ const ExperimentText = React.FC = () => {
return { return {
display: 'flex', display: 'flex',
backgroundColor:'#fff', backgroundColor:'#fff',
height:'81vh'
height:'98vh'
}; };
}); });
const graphStyle = useEmotionCss(() => { const graphStyle = useEmotionCss(() => {
@@ -158,98 +158,78 @@ const ExperimentText = React.FC = () => {
},[]) },[])
const initGraph=()=>{ const initGraph=()=>{
G6.registerNode( G6.registerNode(
'rect-node',
{
// draw anchor-point circles according to the anchorPoints in afterDraw
getAnchorPoints(cfg) {
return (
cfg.anchorPoints || [
// 上下各3,左右各1
[0.1, 0.05],
[0.5, 0.05],
[0.9, 0.05],
[0, 0.5],
[1, 0.5],
[0.1, 1],
[0.5, 1],
[0.9, 1],
// 四边中间
// [0.5, 0.05],
// [0, 0.5],
// [1, 0.5],
// [0.5, 1],
// 四个角落
// [0.05, 0.05],
// [0.9, 0.05],
// [0.05, 1],
// [0.9, 1],
]
);
},
afterDraw(cfg, group) {
// console.log(group, cfg, 12312);
const image = group.addShape('image', {
'rect-node',
{
// draw anchor-point circles according to the anchorPoints in afterDraw
getAnchorPoints(cfg) {
return (
cfg.anchorPoints || [
// 上下各3,左右各1
[0.5, 0],
[0.5, 1],

]
);
},
afterDraw(cfg, group) {
// console.log(group, cfg, 12312);
const image = group.addShape('image', {
attrs: {
x: -45,
y: -10,
width: 20,
height: 20,
img: cfg.img,
cursor: 'pointer',
},
draggable: true,
});
// if (cfg.label) {
// group.addShape('text', {
// attrs: {
// x: 0,
// y: cfg.height / 2 - 5,
// textAlign: 'center',
// textBaseline: 'middle',
// text: cfg.label,
// fill: '#fff',
// },
// draggable: true,
// });
// }
const bbox = group.getBBox();
const anchorPoints = this.getAnchorPoints(cfg);
// console.log(anchorPoints);
anchorPoints.forEach((anchorPos, i) => {
group.addShape('circle', {
attrs: { attrs: {
x: -25,
y: -13,
width: 23,
height: 21,
img: cfg.img,
cursor: 'pointer',
r: 3,
x: bbox.x + bbox.width * anchorPos[0],
y: bbox.y + bbox.height * anchorPos[1],
fill: '#fff',
stroke: '#a4a4a5',
}, },
draggable: true,
});
// if (cfg.label) {
// group.addShape('text', {
// attrs: {
// x: 0,
// y: cfg.height / 2 - 5,
// textAlign: 'center',
// textBaseline: 'middle',
// text: cfg.label,
// fill: '#fff',
// },
// draggable: true,
// });
// }
const bbox = group.getBBox();
const anchorPoints = this.getAnchorPoints(cfg);
// console.log(anchorPoints);
anchorPoints.forEach((anchorPos, i) => {
group.addShape('circle', {
attrs: {
r: 5,
x: bbox.x + bbox.width * anchorPos[0],
y: bbox.y + bbox.height * anchorPos[1],
fill: '#000',
stroke: '#000',
},
name: `anchor-point`, // the name, for searching by group.find(ele => ele.get('name') === 'anchor-point')
anchorPointIdx: i, // flag the idx of the anchor-point circle
links: 0, // cache the number of edges connected to this shape
visible: false, // invisible by default, shows up when links > 1 or the node is in showAnchors state
draggable: true, // allow to catch the drag events on this shape
});
name: `anchor-point`, // the name, for searching by group.find(ele => ele.get('name') === 'anchor-point')
anchorPointIdx: i, // flag the idx of the anchor-point circle
links: 0, // cache the number of edges connected to this shape
visible: false, // invisible by default, shows up when links > 1 or the node is in showAnchors state
}); });
return image;
},
// response the state changes and show/hide the link-point circles
setState(name, value, item) {
// 默认显示全部锚点,防止过宽导致锚点无法被选中
// if (name === 'showAnchors') {
});
return image;
},
// response the state changes and show/hide the link-point circles
setState(name, value, item) {
const anchorPoints = item.getContainer().findAll(ele => ele.get('name') === 'anchor-point'); const anchorPoints = item.getContainer().findAll(ele => ele.get('name') === 'anchor-point');
anchorPoints.forEach(point => { anchorPoints.forEach(point => {
// if (value) point.show();
// else point.hide();
point.show();
});
// }
},
if (value || point.get('links') > 0) point.show()
else point.hide()
})
// }
}, },
'rect'
);
},
'rect'
);
console.log(graphRef,'graphRef'); console.log(graphRef,'graphRef');
graph = new G6.Graph({ graph = new G6.Graph({
container: graphRef.current, container: graphRef.current,
@@ -258,13 +238,27 @@ const ExperimentText = React.FC = () => {
height: graphRef.current.clientHeight||760, height: graphRef.current.clientHeight||760,
animate: false, animate: false,
groupByTypes: false, groupByTypes: false,
plugins: [],
fitView:true,
enabledStack: true, enabledStack: true,
modes: { modes: {
default: [ default: [
// config the shouldBegin for drag-node to avoid node moving while dragging on the anchor-point circles
{
type: 'drag-node',
shouldBegin: e => {
if (e.target.get('name') === 'anchor-point') return false;
return true;
},
// shouldEnd: e => {
// console.log(e);
// return false;
// },
},
// config the shouldBegin and shouldEnd to make sure the create-edge is began and ended at anchor-point circles
'drag-canvas', 'drag-canvas',
'zoom-canvas', 'zoom-canvas',
// 'brush-select',
'drag-combo',
], ],
altSelect: [ altSelect: [
{ {
@@ -277,49 +271,53 @@ const ExperimentText = React.FC = () => {


defaultNode: { defaultNode: {
type: 'rect-node', type: 'rect-node',
size: 70,
size: [110,36],
labelCfg: { labelCfg: {
style: { style: {
fill: '#000', fill: '#000',
fontSize: 12,
fontSize: 10,
cursor: 'pointer', cursor: 'pointer',
x: 0,
x: -20,
y: 0, y: 0,
textAlign: 'left', textAlign: 'left',
textBaseline: 'middle', textBaseline: 'middle',
}, },
}, },
style: { style: {
fill: 'transparent',
stroke: 'transparent',
fill: '#fff',
stroke: '#fff',
radius:10,
lineWidth:0.5
},
},
nodeStateStyles: {
nodeSelected: {
fill: 'red',
shadowColor: 'red',
stroke: 'red',
'text-shape': {
fill: 'red',
stroke: 'red',
},
}, },
}, },
// nodeStateStyles: {
// nodeSelected: {
// fill: 'red',
// shadowColor: 'red',
// stroke: 'red',
// 'text-shape': {
// fill: 'red',
// stroke: 'red',
// },
// },
// },
defaultEdge: { defaultEdge: {
// type: 'quadratic', // type: 'quadratic',
type: 'polyline',
type: 'cubic-vertical',


style: { style: {
endArrow: {
path: G6.Arrow.triangle(),
endArrow: { // 设置终点箭头
path: G6.Arrow.triangle(3, 3, 3), // 使用内置箭头路径函数,参数为箭头的 宽度、长度、偏移量(默认为 0,与 d 对应)
d: 4.5,
fill:'#a2a6b5'
}, },
cursor: 'pointer', cursor: 'pointer',
endArrow: true,
lineWidth: 1, lineWidth: 1,
opacity: 1, opacity: 1,
stroke: '#a2a6b5', stroke: '#a2a6b5',
radius: 10,
radius: 1,
}, },
nodeStateStyle: { nodeStateStyle: {
hover: { hover: {
@@ -346,7 +344,7 @@ const ExperimentText = React.FC = () => {
cursor: 'pointer', cursor: 'pointer',
}, },
}, },
linkCenter: true,
// linkCenter: true,
fitView: true, fitView: true,
fitViewPadding: [60, 60, 60, 80], fitViewPadding: [60, 60, 60, 80],
}); });


+ 22
- 16
react-ui/src/pages/Experiment/index.jsx View File

@@ -1,6 +1,6 @@
import React ,{ useState,useEffect,useRef }from 'react'; import React ,{ useState,useEffect,useRef }from 'react';
import { Space, Table, Tag,Button,Modal, Form, Input ,message, Select,} from 'antd'; import { Space, Table, Tag,Button,Modal, Form, Input ,message, Select,} from 'antd';
import { PlusOutlined, EditOutlined ,PlayCircleOutlined,DeleteOutlined,FieldTimeOutlined} from '@ant-design/icons';
import { PlusOutlined,PlusCircleOutlined, EditOutlined ,PlayCircleOutlined,DeleteOutlined,FieldTimeOutlined} from '@ant-design/icons';
import {getWorkflow,} from '@/services/pipeline/index.js' import {getWorkflow,} from '@/services/pipeline/index.js'
import {getExperiment,runExperiments,getExperimentById,postExperiment,putExperiment,getQueryByExperimentId,deleteExperimentById,deleteQueryByExperimentInsId,putQueryByExperimentInsId} from '@/services/experiment/index.js' import {getExperiment,runExperiments,getExperimentById,postExperiment,putExperiment,getQueryByExperimentId,deleteExperimentById,deleteQueryByExperimentInsId,putQueryByExperimentInsId} from '@/services/experiment/index.js'
import Styles from './index.less' import Styles from './index.less'
@@ -49,6 +49,7 @@ const Experiment = React.FC = () => {
size:10000, size:10000,
name:null name:null
}); });
const [disableFlag,setDisableFlag]=useState(false)
const timers=(time)=>{ const timers=(time)=>{
let timer=new Date(time) let timer=new Date(time)
let hours = timer.getHours(); //转换成时 let hours = timer.getHours(); //转换成时
@@ -96,6 +97,7 @@ const Experiment = React.FC = () => {
} }
const showModal = () => { const showModal = () => {
setDialogTitle('新建实验') setDialogTitle('新建实验')
setDisableFlag(false)
console.log(workflowList); console.log(workflowList);
setIsModalOpen(true); setIsModalOpen(true);
}; };
@@ -103,6 +105,7 @@ const Experiment = React.FC = () => {
getExperimentById(id).then(ret=>{ getExperimentById(id).then(ret=>{
if(ret.code==200){ if(ret.code==200){
form.setFieldsValue({...ret.data}) form.setFieldsValue({...ret.data})
setDisableFlag(true)
setFormId(ret.data.id) setFormId(ret.data.id)
setDialogTitle('编辑实验') setDialogTitle('编辑实验')
getWorkflowList() getWorkflowList()
@@ -262,6 +265,7 @@ const Experiment = React.FC = () => {
{ {
title: '操作', title: '操作',
key: 'action', key: 'action',
width:300,
render: (_, record) => ( render: (_, record) => (
<Space size="small"> <Space size="small">
<Button <Button
@@ -291,6 +295,7 @@ const Experiment = React.FC = () => {
size="small" size="small"
danger danger
key="batchRemove" key="batchRemove"
style={{color:'#f98e1b'}}
icon = {< DeleteOutlined />} icon = {< DeleteOutlined />}
onClick={async () => { onClick={async () => {
Modal.confirm({ Modal.confirm({
@@ -298,6 +303,7 @@ const Experiment = React.FC = () => {
content: '确定删除该条实验吗?', content: '确定删除该条实验吗?',
okText: '确认', okText: '确认',
cancelText: '取消', cancelText: '取消',

onOk: () => { onOk: () => {
console.log(record); console.log(record);
deleteExperimentById(record.id).then(ret=>{ deleteExperimentById(record.id).then(ret=>{
@@ -326,10 +332,15 @@ const Experiment = React.FC = () => {
}, },
]; ];
return (<div> return (<div>
<div >
{/* <div >
<Button type="primary" onClick={showModal} icon = {< PlusOutlined />}> <Button type="primary" onClick={showModal} icon = {< PlusOutlined />}>
新建实验 新建实验
</Button> </Button>
</div> */}
<div className={Styles.pipelineTopBox}>
<Button type="primary" className={Styles.plusButton} onClick={showModal} icon = {<PlusCircleOutlined style={{color:'#1664ff'}} />}>
新建实验
</Button>
</div> </div>
<Table columns={columns} dataSource={experimentList} pagination={paginationProps} expandable={{ <Table columns={columns} dataSource={experimentList} pagination={paginationProps} expandable={{
expandedRowRender: (record) => ( expandedRowRender: (record) => (
@@ -340,7 +351,7 @@ const Experiment = React.FC = () => {
<div style={{width:'200px'}}>状态</div> <div style={{width:'200px'}}>状态</div>
<div style={{width:'300px'}}>运行时长</div> <div style={{width:'300px'}}>运行时长</div>
<div style={{width:'300px'}}>开始时间</div> <div style={{width:'300px'}}>开始时间</div>
<div style={{width:'300px'}}>操作</div>
<div style={{width:'200px'}}>操作</div>
</div>:''} </div>:''}
{experimentInList&&experimentInList.length>0?experimentInList.map((item,index)=>( {experimentInList&&experimentInList.length>0?experimentInList.map((item,index)=>(
@@ -349,7 +360,7 @@ const Experiment = React.FC = () => {
<div className={Styles.statusBox} style={{width:'200px'}}><img style={{width:'17px',marginRight:'7px'}} src={statusImgObj[item.status]}/> <span style={{color:statusColorObj[item.status]}} className={Styles.statusIcon}>{statusObj[item.status]}</span></div> <div className={Styles.statusBox} style={{width:'200px'}}><img style={{width:'17px',marginRight:'7px'}} src={statusImgObj[item.status]}/> <span style={{color:statusColorObj[item.status]}} className={Styles.statusIcon}>{statusObj[item.status]}</span></div>
<div style={{width:'300px'}}>{item.finish_time?timers(new Date(item.finish_time).getTime()-new Date(item.create_time).getTime()):timers(new Date().getTime()-new Date(item.create_time).getTime())}</div> <div style={{width:'300px'}}>{item.finish_time?timers(new Date(item.finish_time).getTime()-new Date(item.create_time).getTime()):timers(new Date().getTime()-new Date(item.create_time).getTime())}</div>
<div style={{width:'300px'}}>{momnet(item.create_time).format('YYYY-MM-DD HH:mm:ss')}</div> <div style={{width:'300px'}}>{momnet(item.create_time).format('YYYY-MM-DD HH:mm:ss')}</div>
<div style={{width:'300px'}}>
<div style={{width:'200px'}}>
<Button <Button
type="link" type="link"
size="small" size="small"
@@ -375,6 +386,7 @@ const Experiment = React.FC = () => {
size="small" size="small"
danger danger
key="batchRemove" key="batchRemove"
style={{color:'#f98e1b'}}
disabled={item.status=='Running'||item.status=='Pending'} disabled={item.status=='Running'||item.status=='Pending'}
icon = {< DeleteOutlined />} icon = {< DeleteOutlined />}
onClick={async () => { onClick={async () => {
@@ -409,7 +421,9 @@ const Experiment = React.FC = () => {
expandedRowKeys:[expandedRowKeys], expandedRowKeys:[expandedRowKeys],
rowExpandable: (record) =>true, rowExpandable: (record) =>true,
}}/> }}/>
<Modal title={dialogTitle} open={isModalOpen} okButtonProps={{
<Modal className={Styles.modal} title={<div style={{display:'flex',alignItems:'center',fontWeight:500}}>
<img style={{width:'20px',marginRight:'10px'}} src={`/assets/images/pipeline-edit-icon.png`} alt="" />{dialogTitle}
</div>} open={isModalOpen} okButtonProps={{
htmlType: 'submit', htmlType: 'submit',
form: 'form', form: 'form',
}} onCancel={handleCancel}> }} onCancel={handleCancel}>
@@ -417,15 +431,6 @@ const Experiment = React.FC = () => {
name="form" name="form"
form={form} form={form}
layout="vertical" layout="vertical"
labelCol={{
span: 8,
}}
wrapperCol={{
span: 16,
}}
style={{
maxWidth: 600,
}}
initialValues={{ initialValues={{
remember: true, remember: true,
}} }}
@@ -460,6 +465,7 @@ const Experiment = React.FC = () => {
<Form.Item <Form.Item
label="选择流水线" label="选择流水线"
name="workflow_id" name="workflow_id"
rules={[ rules={[
// { // {
// required: true, // required: true,
@@ -467,8 +473,8 @@ const Experiment = React.FC = () => {
// }, // },
]} ]}
> >
<Select>
{workflowList&&workflowList.length>0?workflowList.map(item=>{return <Select.Option value={item.id}>{item.name}</Select.Option>}):''}
<Select disabled={disableFlag}>
{workflowList&&workflowList.length>0?workflowList.map(item=>{return <Select.Option value={item.id}>{item.name}</Select.Option>}):''}
{/* <Select.Option value="demo">Demo</Select.Option> */} {/* <Select.Option value="demo">Demo</Select.Option> */}
</Select> </Select>
</Form.Item> </Form.Item>


+ 68
- 15
react-ui/src/pages/Experiment/index.less View File

@@ -7,22 +7,34 @@
height: 49px; height: 49px;
background-size: 100% 100%; background-size: 100% 100%;
background-image: url(/assets/images/pipeline-back.png); background-image: url(/assets/images/pipeline-back.png);
}
.pipelineTopBox{
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 30px;
width: 100%;
height: 49px;
background-size: 100% 100%;
background-image: url(/assets/images/pipeline-back.png);
margin-bottom: 10px;
}
.plusButton{
background:rgba(22, 100, 255, 0.06);
border:1px solid;
border-color:rgba(22, 100, 255, 0.11);
border-radius:4px;
color:#1d1d20;
font-size:14px;
font-family: 'Alibaba';
}
.plusButton:hover{
background:rgba(22, 100, 255, 0.06)!important;
border:1px solid!important;
border-color:rgba(22, 100, 255, 0.11)!important;
color:#1d1d20!important;
} }
// .plusButton{
// background:rgba(22, 100, 255, 0.06);
// border:1px solid;
// border-color:rgba(22, 100, 255, 0.11);
// border-radius:4px;
// color:#1d1d20;
// font-size:15px;
// font-family: 'Alibaba';
// }
// .plusButton:hover{
// background:rgba(22, 100, 255, 0.06);
// border:1px solid;
// border-color:rgba(22, 100, 255, 0.11);
// border-radius:4px;
// }
.tableExpandBox{ .tableExpandBox{
width: 100%; width: 100%;
display: flex; display: flex;
@@ -44,4 +56,45 @@
} }
.statusBox:hover .statusIcon{ .statusBox:hover .statusIcon{
visibility: visible; visibility: visible;
}
.modal {
:global {
.ant-modal-content {
background:linear-gradient(180deg,#cfdfff 0%,#d4e2ff 9.77%,#ffffff 40%,#ffffff 100%);
border-radius:21px;
padding: 20px 67px;
width: 825px;

}
.ant-modal-header{
background-color: transparent;
margin: 20px 0;
}
.ant-input{
border-color:#e6e6e6;
height: 40px;
}
.ant-select-single{
height: 40px;
}
.ant-form-item .ant-form-item-label >label{
color:rgba(29, 29, 32, 0.8);
}
.ant-modal-footer{
margin: 40px 0 30px 0;
display: flex;
justify-content: center;
}
.ant-btn{
width:123px;
height:40px;
font-size:18px;
background:rgba(22, 100, 255, 0.06);
border-radius:10px;
}
.ant-btn-primary{
background:#1664ff;
}
}
} }

+ 2
- 0
react-ui/src/pages/Pipeline/editPipeline/editPipeline.less View File

@@ -9,6 +9,7 @@
width: 100%; width: 100%;
height:43px; height:43px;
background:#f8fbff; background:#f8fbff;
color:#1d1d20; color:#1d1d20;
font-size:15px; font-size:15px;
font-family: 'Alibaba'; font-family: 'Alibaba';
@@ -22,6 +23,7 @@
.buttonList{ .buttonList{
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: end;
padding: 0 30px; padding: 0 30px;
width: 100%; width: 100%;
height:45px; height:45px;


+ 258
- 82
react-ui/src/pages/Pipeline/editPipeline/index.jsx View File

@@ -17,11 +17,12 @@ const editPipeline = React.FC = () => {
let contextMenu={} let contextMenu={}
const locationParams =useParams () //新版本获取路由参数接口 const locationParams =useParams () //新版本获取路由参数接口
let graph=null let graph=null
let sourceAnchorIdx, targetAnchorIdx;
const pipelineContainer = useEmotionCss(() => { const pipelineContainer = useEmotionCss(() => {
return { return {
display: 'flex', display: 'flex',
backgroundColor:'#fff', backgroundColor:'#fff',
height:'81vh'
height:'98vh'
}; };
}); });
const rightmenu= useEmotionCss(() => { const rightmenu= useEmotionCss(() => {
@@ -46,7 +47,8 @@ const editPipeline = React.FC = () => {
const graphStyle = useEmotionCss(() => { const graphStyle = useEmotionCss(() => {
return { return {
width:'100%', width:'100%',
backgroundColor:'#f9fafb',
backgroundSize: '100% 100%',
backgroundImage: 'url(/assets/images/pipeline-canvas-back.png)',
flex:1 flex:1
}; };
}); });
@@ -81,7 +83,7 @@ const editPipeline = React.FC = () => {
data.nodes[index] = val; data.nodes[index] = val;
graph.changeData(data) graph.changeData(data)
} }
const savePipeline=()=>{
const savePipeline=(val)=>{
const data = graph.save(); const data = graph.save();
console.log(data); console.log(data);
let params={ let params={
@@ -90,14 +92,22 @@ const editPipeline = React.FC = () => {
} }
saveWorkflow(params).then(ret=>{ saveWorkflow(params).then(ret=>{
console.log(ret); console.log(ret);
message.success('保存成功')
if(ret.code==200){
message.success('保存成功')
setTimeout(()=>{ setTimeout(()=>{
navgite({pathname:`/pipeline`,});
if(val){
navgite({pathname:`/pipeline`,});
}
},500) },500)
}
else{
message.error('保存失败')
}
}) })
console.log(params); console.log(params);
} }
const handlerClick=(e)=>{ const handlerClick=(e)=>{
e.stopPropagation()
console.log(propsRef,graph); console.log(propsRef,graph);
// let cache = []; // let cache = [];
// let json_str = JSON.stringify(graph, function(key, value) { // let json_str = JSON.stringify(graph, function(key, value) {
@@ -124,6 +134,106 @@ const editPipeline = React.FC = () => {
},500) },500)
} }
} }
const processParallelEdgesOnAnchorPoint = (
edges,
offsetDiff = 15,
multiEdgeType = 'cubic-vertical',
singleEdgeType = undefined,
loopEdgeType = undefined
) => {
const len = edges.length;
const cod = offsetDiff * 2;
const loopPosition = [
'top',
'top-right',
'right',
'bottom-right',
'bottom',
'bottom-left',
'left',
'top-left',
];
const edgeMap = {};
const tags = [];
const reverses = {};
for (let i = 0; i < len; i++) {
const edge = edges[i];
const { source, target, sourceAnchor, targetAnchor } = edge;
const sourceTarget = `${source}|${sourceAnchor}-${target}|${targetAnchor}`;
if (tags[i]) continue;
if (!edgeMap[sourceTarget]) {
edgeMap[sourceTarget] = [];
}
tags[i] = true;
edgeMap[sourceTarget].push(edge);
for (let j = 0; j < len; j++) {
if (i === j) continue;
const sedge = edges[j];
const { source: src, target: dst, sourceAnchor: srcAnchor, targetAnchor: dstAnchor } = sedge;
// 两个节点之间共同的边
// 第一条的source = 第二条的target
// 第一条的target = 第二条的source
if (!tags[j]) {
if (source === dst && sourceAnchor === dstAnchor
&& target === src && targetAnchor === srcAnchor) {
edgeMap[sourceTarget].push(sedge);
tags[j] = true;
reverses[`${src}|${srcAnchor}|${dst}|${dstAnchor}|${edgeMap[sourceTarget].length - 1}`] = true;
} else if (source === src && sourceAnchor === srcAnchor
&& target === dst && targetAnchor === dstAnchor) {
edgeMap[sourceTarget].push(sedge);
tags[j] = true;
}
}
}
}
for (const key in edgeMap) {
const arcEdges = edgeMap[key];
const { length } = arcEdges;
for (let k = 0; k < length; k++) {
const current = arcEdges[k];
if (current.source === current.target) {
if (loopEdgeType) current.type = loopEdgeType;
// 超过8条自环边,则需要重新处理
current.loopCfg = {
position: loopPosition[k % 8],
dist: Math.floor(k / 8) * 20 + 50,
};
continue;
}
if (length === 1 && singleEdgeType && (current.source !== current.target || current.sourceAnchor !== current.targetAnchor)) {
current.type = singleEdgeType;
continue;
}
current.type = multiEdgeType;
const sign =
(k % 2 === 0 ? 1 : -1) * (reverses[`${current.source}|${current.sourceAnchor}|${current.target}|${current.targetAnchor}|${k}`] ? -1 : 1);
if (length % 2 === 1) {
current.curveOffset = sign * Math.ceil(k / 2) * cod;
} else {
current.curveOffset = sign * (Math.floor(k / 2) * cod + offsetDiff);
}
}
}
return edges;
};
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',
x: item.getModel().x + 150,
y: item.getModel().y,
id: item.getModel().component_name+'-'+nodeId,
});
graph.changeData(data)
}
const getFirstWorkflow=(val)=>{ const getFirstWorkflow=(val)=>{
getWorkflowById(val).then(ret=>{ getWorkflowById(val).then(ret=>{
console.log(ret); console.log(ret);
@@ -161,22 +271,17 @@ const editPipeline = React.FC = () => {
color: #333333; color: #333333;
overflow-y: auto;"> overflow-y: auto;">
<li style="padding: 10px 20px;cursor: pointer;" code="clone">复制</li>
<li style="padding: 10px 20px;cursor: pointer;" code="delete">删除</li> <li style="padding: 10px 20px;cursor: pointer;" code="delete">删除</li>
</ul>`; </ul>`;
}, },
handleMenuClick: (target, item) => { handleMenuClick: (target, item) => {
switch (target.getAttribute('code')) { switch (target.getAttribute('code')) {
// <li style="padding: 10px 20px;cursor: pointer;" code="undo">撤回</li>
// <li style="padding: 10px 20px;cursor: pointer;" code="redo">恢复</li>
// case 'undo':
// this.$emit('handleMenuCall', { code: 'undo' });
// break;
// case 'redo':
// this.$emit('handleMenuCall', { code: 'redo' });
// break;
case 'delete': case 'delete':
graph.removeItem(item); graph.removeItem(item);
break;
case 'clone':
cloneElement(item)
break; break;
default: default:
break; break;
@@ -189,7 +294,7 @@ const editPipeline = React.FC = () => {
offsetY: 0, offsetY: 0,
// the types of items that allow the menu show up // the types of items that allow the menu show up
// 在哪些类型的元素上响应 // 在哪些类型的元素上响应
itemTypes: ['node', 'edge', 'canvas']})
itemTypes: ['node', 'edge']})
initGraph() initGraph()
}; };
@@ -197,7 +302,17 @@ const editPipeline = React.FC = () => {
getFirstWorkflow(locationParams.id) getFirstWorkflow(locationParams.id)
initMenu() initMenu()
return ()=>{
graph.off('node:mouseenter', e => {
graph.setItemState(e.item, 'showAnchors', true);
graph.setItemState(e.item, 'nodeSelected', true);
});
graph.off('node:mouseleave', e => {
// this.graph.setItemState(e.item, 'showAnchors', false);
graph.setItemState(e.item, 'nodeSelected', false);
});
graph.off('dblclick', handlerClick);
}
console.log(contextMenu); console.log(contextMenu);
},[]) },[])
const initGraph=()=>{ const initGraph=()=>{
@@ -209,25 +324,8 @@ const editPipeline = React.FC = () => {
return ( return (
cfg.anchorPoints || [ cfg.anchorPoints || [
// 上下各3,左右各1 // 上下各3,左右各1
[0.1, 0.05],
[0.5, 0.05],
[0.9, 0.05],
[0, 0.5],
[1, 0.5],
[0.1, 1],
[0.5, 0],
[0.5, 1], [0.5, 1],
[0.9, 1],
// 四边中间
// [0.5, 0.05],
// [0, 0.5],
// [1, 0.5],
// [0.5, 1],
// 四个角落
// [0.05, 0.05],
// [0.9, 0.05],
// [0.05, 1],
// [0.9, 1],
] ]
); );
}, },
@@ -235,10 +333,10 @@ const editPipeline = React.FC = () => {
// console.log(group, cfg, 12312); // console.log(group, cfg, 12312);
const image = group.addShape('image', { const image = group.addShape('image', {
attrs: { attrs: {
x: -25,
y: -13,
width: 21,
height: 21,
x: -45,
y: -10,
width: 20,
height: 20,
img: cfg.img, img: cfg.img,
cursor: 'pointer', cursor: 'pointer',
}, },
@@ -263,17 +361,16 @@ const editPipeline = React.FC = () => {
anchorPoints.forEach((anchorPos, i) => { anchorPoints.forEach((anchorPos, i) => {
group.addShape('circle', { group.addShape('circle', {
attrs: { attrs: {
r: 5,
r: 3,
x: bbox.x + bbox.width * anchorPos[0], x: bbox.x + bbox.width * anchorPos[0],
y: bbox.y + bbox.height * anchorPos[1], y: bbox.y + bbox.height * anchorPos[1],
fill: '#000',
stroke: '#000',
fill: '#fff',
stroke: '#a4a4a5',
}, },
name: `anchor-point`, // the name, for searching by group.find(ele => ele.get('name') === 'anchor-point') name: `anchor-point`, // the name, for searching by group.find(ele => ele.get('name') === 'anchor-point')
anchorPointIdx: i, // flag the idx of the anchor-point circle anchorPointIdx: i, // flag the idx of the anchor-point circle
links: 0, // cache the number of edges connected to this shape links: 0, // cache the number of edges connected to this shape
visible: false, // invisible by default, shows up when links > 1 or the node is in showAnchors state visible: false, // invisible by default, shows up when links > 1 or the node is in showAnchors state
draggable: true, // allow to catch the drag events on this shape
}); });
}); });
return image; return image;
@@ -281,14 +378,11 @@ const editPipeline = React.FC = () => {
// response the state changes and show/hide the link-point circles // response the state changes and show/hide the link-point circles
setState(name, value, item) { setState(name, value, item) {
// 默认显示全部锚点,防止过宽导致锚点无法被选中
// if (name === 'showAnchors') {
const anchorPoints = item.getContainer().findAll(ele => ele.get('name') === 'anchor-point');
anchorPoints.forEach(point => {
// if (value) point.show();
// else point.hide();
point.show();
});
const anchorPoints = item.getContainer().findAll(ele => ele.get('name') === 'anchor-point');
anchorPoints.forEach(point => {
if (value || point.get('links') > 0) point.show()
else point.hide()
})
// } // }
}, },
}, },
@@ -299,7 +393,7 @@ const editPipeline = React.FC = () => {
container: graphRef.current, container: graphRef.current,
grid: true, grid: true,
width: graphRef.current.clientWidth ||500, width: graphRef.current.clientWidth ||500,
height: graphRef.current.clientHeight||760,
height: graphRef.current.clientHeight||'100%',
animate: false, animate: false,
groupByTypes: false, groupByTypes: false,
fitView:true, fitView:true,
@@ -321,9 +415,28 @@ const editPipeline = React.FC = () => {
}, },
// config the shouldBegin and shouldEnd to make sure the create-edge is began and ended at anchor-point circles // config the shouldBegin and shouldEnd to make sure the create-edge is began and ended at anchor-point circles
{ {
type: 'create-edge',
key: 'shift', // undefined by default, options: 'shift', 'control', 'ctrl', 'meta', 'alt'
type: 'create-edge',
// trigger: 'drag',
shouldBegin: e => {
// avoid beginning at other shapes on the node
if (e.target && e.target.get('name') !== 'anchor-point') return false;
sourceAnchorIdx = e.target.get('anchorPointIdx');
e.target.set('links', e.target.get('links') + 1); // cache the number of edge connected to this anchor-point circle
return true;
}, },
shouldEnd: e => {
// avoid ending at other shapes on the node
if (e.target && e.target.get('name') !== 'anchor-point') return false;
if (e.target) {
targetAnchorIdx = e.target.get('anchorPointIdx');
e.target.set('links', e.target.get('links') + 1); // cache the number of edge connected to this anchor-point circle
return true;
}
targetAnchorIdx = undefined;
return true;
},

},
'drag-canvas', 'drag-canvas',
'zoom-canvas', 'zoom-canvas',
// 'brush-select', // 'brush-select',
@@ -340,49 +453,54 @@ const editPipeline = React.FC = () => {


defaultNode: { defaultNode: {
type: 'rect-node', type: 'rect-node',
size: 70,
size: [110,36],
labelCfg: { labelCfg: {
style: { style: {
fill: '#000', fill: '#000',
fontSize: 12,
cursor: 'pointer',
x: 0,
fontSize: 10,
boxShadow:'0px 0px 12px rgba(75, 84, 137, 0.05)',
x: -20,
y: 0, y: 0,
textAlign: 'left', textAlign: 'left',
textBaseline: 'middle', textBaseline: 'middle',
}, },
}, },
style: { style: {
fill: 'transparent',
stroke: 'transparent',
fill: '#fff',
stroke: '#fff',
cursor: 'pointer',
radius:10,
lineWidth:0.5
},
},
nodeStateStyles: {
nodeSelected: {
fill: 'red',
shadowColor: 'red',
stroke: 'red',
'text-shape': {
fill: 'red',
stroke: 'red',
},
}, },
}, },
// nodeStateStyles: {
// nodeSelected: {
// fill: 'red',
// shadowColor: 'red',
// stroke: 'red',
// 'text-shape': {
// fill: 'red',
// stroke: 'red',
// },
// },
// },
defaultEdge: { defaultEdge: {
// type: 'quadratic', // type: 'quadratic',
type: 'polyline',
type: 'cubic-vertical',


style: { style: {
endArrow: {
path: G6.Arrow.triangle(),
endArrow: { // 设置终点箭头
path: G6.Arrow.triangle(3, 3, 3), // 使用内置箭头路径函数,参数为箭头的 宽度、长度、偏移量(默认为 0,与 d 对应)
d: 4.5,
fill:'#CDD0DC'
}, },
cursor: 'pointer', cursor: 'pointer',
endArrow: true,
lineWidth: 1, lineWidth: 1,
opacity: 1, opacity: 1,
stroke: '#a2a6b5',
radius: 10,
stroke: '#CDD0DC',
radius: 1,
}, },
nodeStateStyle: { nodeStateStyle: {
hover: { hover: {
@@ -409,14 +527,29 @@ const editPipeline = React.FC = () => {
cursor: 'pointer', cursor: 'pointer',
}, },
}, },
linkCenter: true,
// linkCenter: true,
fitView: true, fitView: true,
fitViewPadding: [60, 60, 60, 80], fitViewPadding: [60, 60, 60, 80],
}); });
graph.on('dblclick', handlerClick);
graph.on('dblclick', (e)=>{
console.log(e.item);
graph.setItemState(e.item, 'nodeClicked', true);
handlerClick(e)
});
graph.on('click', (e)=>{
console.log(e.item);
});
graph.on('aftercreateedge', (e) => { graph.on('aftercreateedge', (e) => {
// update the sourceAnchor and targetAnchor for the newly added edge
graph.updateItem(e.edge, {
sourceAnchor: sourceAnchorIdx,
targetAnchor: targetAnchorIdx
})

// update the curveOffset for parallel edges
const edges = graph.save().edges; const edges = graph.save().edges;
G6.Util.processParallelEdges(edges);
processParallelEdgesOnAnchorPoint(edges);
graph.getEdges().forEach((edge, i) => { graph.getEdges().forEach((edge, i) => {
graph.updateItem(edge, { graph.updateItem(edge, {
curveOffset: edges[i].curveOffset, curveOffset: edges[i].curveOffset,
@@ -424,6 +557,50 @@ const editPipeline = React.FC = () => {
}); });
}); });
}); });
graph.on('node:mouseenter', e => {
// this.graph.setItemState(e.item, 'showAnchors', true);
graph.setItemState(e.item, 'nodeSelected', true);
graph.updateItem(e.item, {
// 节点的样式
style: {
stroke: '#1664ff',
},
});
});
graph.on('node:mouseleave', e => {
// this.graph.setItemState(e.item, 'showAnchors', false);
graph.setItemState(e.item, 'nodeSelected', false);
graph.updateItem(e.item, {
// 节点的样式
style: {
stroke: 'transparent',
},
});
});
graph.on('afterremoveitem', e => {
if (e.item && e.item.source && e.item.target) {
const sourceNode = graph.findById(e.item.source);
const targetNode = graph.findById(e.item.target);
const { sourceAnchor, targetAnchor } = e.item;
if (sourceNode && !isNaN(sourceAnchor)) {
const sourceAnchorShape = sourceNode.getContainer().find(ele => (ele.get('name') === 'anchor-point' && ele.get('anchorPointIdx') === sourceAnchor));
sourceAnchorShape.set('links', sourceAnchorShape.get('links') - 1);
}
if (targetNode && !isNaN(targetAnchor)) {
const targetAnchorShape = targetNode.getContainer().find(ele => (ele.get('name') === 'anchor-point' && ele.get('anchorPointIdx') === targetAnchor));
targetAnchorShape.set('links', targetAnchorShape.get('links') - 1);
}
}
})
// after clicking on the first node, the edge is created, update the sourceAnchor
graph.on('afteradditem', e => {
if (e.item && e.item.getType() === 'edge') {
graph.updateItem(e.item, {
sourceAnchor: sourceAnchorIdx
});
}
})
window.onresize = () => { window.onresize = () => {
if (!graph || graph.get('destroyed')) return; if (!graph || graph.get('destroyed')) return;
if (!graphRef.current || !graphRef.current.scrollWidth || !graphRef.current.scrollHeight) return; if (!graphRef.current || !graphRef.current.scrollWidth || !graphRef.current.scrollHeight) return;
@@ -434,9 +611,8 @@ const editPipeline = React.FC = () => {
<ModelMenus onParDragEnd={onDragEnd}></ModelMenus> <ModelMenus onParDragEnd={onDragEnd}></ModelMenus>
<div className={Styles.centerContainer}> <div className={Styles.centerContainer}>
<div className={Styles.buttonList}> <div className={Styles.buttonList}>
{/* <Button type="primary" shape="round" icon={<SaveOutlined />} onClick={savePipeline}>撤回</Button>
<Button type="primary" shape="round" icon={<SaveOutlined />} onClick={savePipeline}>恢复</Button> */}
<Button type="primary" shape="round" icon={<SaveOutlined />} onClick={savePipeline}>保存</Button>
<Button type="primary" shape="round" icon={<SaveOutlined />} style={{marginRight:'20px'}} onClick={()=>{savePipeline(false)}}>保存</Button>
<Button type="primary" shape="round" icon={<SaveOutlined />} onClick={()=>{savePipeline(true)}}>保存并返回</Button>
</div> </div>
<div className={graphStyle} ref={graphRef} id={Styles.graphStyle}></div> <div className={graphStyle} ref={graphRef} id={Styles.graphStyle}></div>
</div> </div>


+ 3
- 1
react-ui/src/pages/Pipeline/editPipeline/modelMenus.jsx View File

@@ -34,15 +34,17 @@ const modelMenus = ({onParDragEnd}) => {
onParDragEnd({...data,x:e.clientX,y:e.clientY,label:data.component_label,img:`/assets/images/${data.icon_path}.png`}) onParDragEnd({...data,x:e.clientX,y:e.clientY,label:data.component_label,img:`/assets/images/${data.icon_path}.png`})
} }
const { Panel } = Collapse; const { Panel } = Collapse;
return (<div style={{width:'300px',height:'100%'}}>
return (<div style={{width:'250px',height:'100%'}} className={Styles.collapse}>
<Collapse <Collapse
collapsible="header" collapsible="header"
defaultActiveKey={['1']} defaultActiveKey={['1']}
expandIconPosition="end"
> >
{modelMenusList && modelMenusList.length > 0 {modelMenusList && modelMenusList.length > 0
? modelMenusList.map(item => ( ? modelMenusList.map(item => (
<Panel <Panel
header={<div>{item.name}</div>} header={<div>{item.name}</div>}
key={item.key} key={item.key}
> >


+ 31
- 0
react-ui/src/pages/Pipeline/editPipeline/modelMenus.less View File

@@ -9,4 +9,35 @@
font-size:14px; font-size:14px;
height:40px; height:40px;
cursor: pointer; cursor: pointer;
border-radius:4px;
padding: 0 16px;
}
.collapseItem:hover{
background:rgba(22, 100, 255, 0.08);
}
.collapse{
:global {
.ant-collapse{
border-color: transparent!important;
background-color: #fff;
}
.ant-collapse>.ant-collapse-item >.ant-collapse-header{
background-color: #fff;
border-color: transparent;
margin-bottom: 5px;
}
.ant-collapse>.ant-collapse-item{
border-radius: 0px;
border-color:rgba(20, 49, 179, 0.12);
margin: 0 10px;
}
.ant-collapse .ant-collapse-content{
padding-bottom: 15px;
border-top: 1px solid transparent;
}
.ant-collapse .ant-collapse-content>.ant-collapse-content-box{
padding: 0;
}
}
} }

+ 13
- 27
react-ui/src/pages/Pipeline/index.jsx View File

@@ -1,6 +1,6 @@
import React ,{ useState,useEffect,useRef }from 'react'; import React ,{ useState,useEffect,useRef }from 'react';
import { Space, Table, Tag,Button,Modal, Form, Input ,message} from 'antd'; import { Space, Table, Tag,Button,Modal, Form, Input ,message} from 'antd';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined ,CopyOutlined} from '@ant-design/icons';
import { PlusOutlined,PlusCircleOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined ,CopyOutlined} from '@ant-design/icons';
import {getWorkflow,addWorkflow,removeWorkflow,cloneWorkflow,getWorkflowById,editWorkflow} from '@/services/pipeline/index.js' import {getWorkflow,addWorkflow,removeWorkflow,cloneWorkflow,getWorkflowById,editWorkflow} from '@/services/pipeline/index.js'
import Styles from './index.less' import Styles from './index.less'
import momnet from 'moment' import momnet from 'moment'
@@ -36,7 +36,7 @@ const Pipeline = React.FC = () => {
} }
const showModal = () => { const showModal = () => {
form.resetFields() form.resetFields()
setDialogTitle('编辑流水线')
setDialogTitle('新建流水线')
setIsModalOpen(true); setIsModalOpen(true);
}; };
const handleOk = () => { const handleOk = () => {
@@ -56,7 +56,10 @@ const Pipeline = React.FC = () => {
} }
else{ else{
addWorkflow(values).then(ret=>{ addWorkflow(values).then(ret=>{
navgite({pathname:`/pipeline/pytorchtext/${ret.id}/${ret.name}`,});
console.log(ret);
if(ret.code==200){
navgite({pathname:`/pipeline/pytorchtext/${ret.data.id}/${ret.data.name}`,});
}
} }
) )
} }
@@ -107,7 +110,7 @@ const Pipeline = React.FC = () => {
title: '序号', title: '序号',
dataIndex: 'index', dataIndex: 'index',
key: 'index', key: 'index',
width: 60,
width: 80,
render(text, record, index) { render(text, record, index) {
return ( return (
<span>{(pageOption.current.page - 1) * 10 + index + 1}</span> <span>{(pageOption.current.page - 1) * 10 + index + 1}</span>
@@ -141,6 +144,7 @@ const Pipeline = React.FC = () => {
{ {
title: '操作', title: '操作',
key: 'action', key: 'action',
render: (_, record) => ( render: (_, record) => (
<Space size="small"> <Space size="small">
<Button <Button
@@ -192,6 +196,7 @@ const Pipeline = React.FC = () => {
type="link" type="link"
size="small" size="small"
danger danger
style={{color:'#f98e1b'}}
key="batchRemove" key="batchRemove"
icon = {< DeleteOutlined />} icon = {< DeleteOutlined />}
onClick={async () => { onClick={async () => {
@@ -229,12 +234,14 @@ const Pipeline = React.FC = () => {
]; ];
return (<div> return (<div>
<div className={Styles.pipelineTopBox}> <div className={Styles.pipelineTopBox}>
<Button type="primary" className={Styles.plusButton} onClick={showModal} icon = {< PlusOutlined />}>
<Button type="primary" className={Styles.plusButton} onClick={showModal} icon = {<PlusCircleOutlined style={{color:'#1664ff'}} />}>
新建流水线 新建流水线
</Button> </Button>
</div> </div>
<Table columns={columns} dataSource={pipeList} pagination={paginationProps}/> <Table columns={columns} dataSource={pipeList} pagination={paginationProps}/>
<Modal title={dialogTitle} open={isModalOpen} okButtonProps={{
<Modal title={<div style={{display:'flex',alignItems:'center',fontWeight:500}}>
<img style={{width:'20px',marginRight:'10px'}} src={`/assets/images/pipeline-edit-icon.png`} alt="" />{dialogTitle}
</div>} open={isModalOpen} className={Styles.modal} okButtonProps={{
htmlType: 'submit', htmlType: 'submit',
form: 'form', form: 'form',
}} onCancel={handleCancel}> }} onCancel={handleCancel}>
@@ -242,15 +249,6 @@ const Pipeline = React.FC = () => {
name="form" name="form"
form={form} form={form}
layout="vertical" layout="vertical"
labelCol={{
span: 8,
}}
wrapperCol={{
span: 16,
}}
style={{
maxWidth: 600,
}}
initialValues={{ initialValues={{
remember: true, remember: true,
}} }}
@@ -282,18 +280,6 @@ const Pipeline = React.FC = () => {
> >
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item
label="备注"
name="remake"
rules={[
// {
// required: true,
// message: 'Please input your username!',
// },
]}
>
<TextArea />
</Form.Item>
</Form> </Form>
</Modal> </Modal>
</div>)}; </div>)};

+ 54
- 15
react-ui/src/pages/Pipeline/index.less View File

@@ -7,19 +7,58 @@
height: 49px; height: 49px;
background-size: 100% 100%; background-size: 100% 100%;
background-image: url(/assets/images/pipeline-back.png); background-image: url(/assets/images/pipeline-back.png);
margin-bottom: 10px;
}
.plusButton{
background:rgba(22, 100, 255, 0.06);
border:1px solid;
border-color:rgba(22, 100, 255, 0.11);
border-radius:4px;
color:#1d1d20;
font-size:14px;
font-family: 'Alibaba';
}
.plusButton:hover{
background:rgba(22, 100, 255, 0.06)!important;
border:1px solid!important;
border-color:rgba(22, 100, 255, 0.11)!important;
color:#1d1d20!important;
}
.modal {
:global {
.ant-modal-content {
background:linear-gradient(180deg,#cfdfff 0%,#d4e2ff 9.77%,#ffffff 40%,#ffffff 100%);
border-radius:21px;
padding: 20px 67px;
width: 825px;

}
.ant-modal-header{
background-color: transparent;
margin: 20px 0;
}
.ant-input{
border-color:#e6e6e6;
height: 40px;
}
.ant-form-item .ant-form-item-label >label{
color:rgba(29, 29, 32, 0.8);
}
.ant-modal-footer{
margin: 40px 0 30px 0;
display: flex;
justify-content: center;
}
.ant-btn{
width:123px;
height:40px;
font-size:18px;
background:rgba(22, 100, 255, 0.06);
border-radius:10px;
}
.ant-btn-primary{
background:#1664ff;
}
}
} }
// .plusButton{
// background:rgba(22, 100, 255, 0.06);
// border:1px solid;
// border-color:rgba(22, 100, 255, 0.11);
// border-radius:4px;
// color:#1d1d20;
// font-size:15px;
// font-family: 'Alibaba';
// }
// .plusButton:hover{
// background:rgba(22, 100, 255, 0.06);
// border:1px solid;
// border-color:rgba(22, 100, 255, 0.11);
// border-radius:4px;
// }

Loading…
Cancel
Save