diff --git a/react-ui/public/assets/images/component-icon-1--Omitted.png b/react-ui/public/assets/images/component-icon-1-Skipped.png
similarity index 100%
rename from react-ui/public/assets/images/component-icon-1--Omitted.png
rename to react-ui/public/assets/images/component-icon-1-Skipped.png
diff --git a/react-ui/public/assets/images/component-icon-2-Skipped.png b/react-ui/public/assets/images/component-icon-2-Skipped.png
new file mode 100644
index 00000000..6ee447f3
Binary files /dev/null and b/react-ui/public/assets/images/component-icon-2-Skipped.png differ
diff --git a/react-ui/public/assets/images/fail-icon.png b/react-ui/public/assets/images/fail-icon.png
new file mode 100644
index 00000000..da6c16cd
Binary files /dev/null and b/react-ui/public/assets/images/fail-icon.png differ
diff --git a/react-ui/public/assets/images/omitted-icon.png b/react-ui/public/assets/images/omitted-icon.png
new file mode 100644
index 00000000..1c1f2e35
Binary files /dev/null and b/react-ui/public/assets/images/omitted-icon.png differ
diff --git a/react-ui/public/assets/images/pending-icon.png b/react-ui/public/assets/images/pending-icon.png
new file mode 100644
index 00000000..7f5ea74f
Binary files /dev/null and b/react-ui/public/assets/images/pending-icon.png differ
diff --git a/react-ui/public/assets/images/running-icon.png b/react-ui/public/assets/images/running-icon.png
new file mode 100644
index 00000000..6182ada1
Binary files /dev/null and b/react-ui/public/assets/images/running-icon.png differ
diff --git a/react-ui/public/assets/images/success-icon.png b/react-ui/public/assets/images/success-icon.png
new file mode 100644
index 00000000..83ff96b7
Binary files /dev/null and b/react-ui/public/assets/images/success-icon.png differ
diff --git a/react-ui/src/pages/Experiment/experimentText/editPipeline.less b/react-ui/src/pages/Experiment/experimentText/editPipeline.less
index d0562f67..6838c151 100644
--- a/react-ui/src/pages/Experiment/experimentText/editPipeline.less
+++ b/react-ui/src/pages/Experiment/experimentText/editPipeline.less
@@ -27,4 +27,18 @@
height:45px;
background:#ffffff;
box-shadow:0px 3px 6px rgba(146, 146, 146, 0.09);
+}
+.detailBox{
+ color:#1d1d20;
+font-size:15px;
+margin-bottom: 15px;
+display: flex;
+align-items: center;
+}
+.allMessageItem{
+ display: flex;
+ align-items: center;
+ color:rgba(29, 29, 32, 0.8);
+font-size:15px;
+margin-right: 30px;
}
\ No newline at end of file
diff --git a/react-ui/src/pages/Experiment/experimentText/index.jsx b/react-ui/src/pages/Experiment/experimentText/index.jsx
index 30022345..8a961f04 100644
--- a/react-ui/src/pages/Experiment/experimentText/index.jsx
+++ b/react-ui/src/pages/Experiment/experimentText/index.jsx
@@ -8,14 +8,45 @@ import { s8 } from '../../../utils';
import { Button, message} from 'antd';
import {SaveOutlined} from '@ant-design/icons';
import {saveWorkflow,getWorkflowById,} from '@/services/pipeline/index.js'
-import {getExperimentIns} from '@/services/experiment/index.js'
+import {getExperimentIns,} from '@/services/experiment/index.js'
import { useNavigate} from 'react-router-dom';
+import momnet from 'moment'
const ExperimentText = React.FC = () => {
const propsRef=useRef()
const navgite=useNavigate();
const locationParams =useParams () //新版本获取路由参数接口
let graph=null
const [experimentStatusObj,setExperimentStatusObj]=useState({})
+ const [experimentAllMessage,setExperimentAllMessage]=useState({})
+ const statusObj={
+ "Running":'运行中',
+ "Succeeded":'成功',
+ "Pending":'等待中',
+ "Failed":'失败',
+ "Error":'错误',
+ "Terminated":'终止',
+ "Skipped":'未执行',
+ "Omitted":'未执行',
+ }
+ const statusColorObj={
+ "Running":'#165bff',
+ "Succeeded":'#63a728',
+ "Pending":'#f981eb',
+ "Failed":'#c73131',
+ "Error":'#c73131',
+ "Terminated":'#8a8a8a',
+ "Skipped":'#8a8a8a',
+ "Omitted":'#8a8a8ae',
+ }
+ const timers=(time)=>{
+ let timer=new Date(time)
+ let hours = timer.getHours(); //转换成时
+ let minutes = timer.getMinutes(); //转换成分
+ let secend = timer.getSeconds(); //转换成秒
+
+ let str = `${minutes}分${secend}秒`;
+ return str;
+ }
const pipelineContainer = useEmotionCss(() => {
return {
display: 'flex',
@@ -88,11 +119,13 @@ const ExperimentText = React.FC = () => {
console.log(JSON.parse(ret.data.dag));
getExperimentIns(locationParams.id).then(res=>{
if(res.code==200){
+ console.log(ret.data,'data');
const experimentStatusObjs=JSON.parse(res.data.nodes_status)
- const newNodeList= JSON.parse(ret.data.dag).nodes.map(item=>{console.log(experimentStatusObjs); return {...item,component_id:experimentStatusObjs&&experimentStatusObjs[item.id]&&experimentStatusObjs[item.id].id,img:experimentStatusObjs&&experimentStatusObjs[item.id]&&experimentStatusObjs[item.id].phase?item.img.slice(0,item.img.length-4)+'-'+experimentStatusObjs[item.id].phase+'.png':item.img}})
- const newData={...JSON.parse(ret.data.dag),nodes:newNodeList}
- console.log(newData);
- getGraphData(newData)
+ const newNodeList= JSON.parse(ret.data.dag).nodes.map(item=>{console.log(experimentStatusObjs); return {...item,experimentEndTime:experimentStatusObjs&&experimentStatusObjs[item.id]&&experimentStatusObjs[item.id].finishedAt,experimentStartTime:experimentStatusObjs&&experimentStatusObjs[item.id]&&experimentStatusObjs[item.id].startedAt,experimentStatus:experimentStatusObjs&&experimentStatusObjs[item.id]&&experimentStatusObjs[item.id].phase,component_id:experimentStatusObjs&&experimentStatusObjs[item.id]&&experimentStatusObjs[item.id].id,img:experimentStatusObjs&&experimentStatusObjs[item.id]&&experimentStatusObjs[item.id].phase?item.img.slice(0,item.img.length-4)+'-'+experimentStatusObjs[item.id].phase+'.png':item.img}})
+ const newData={...JSON.parse(ret.data.dag),nodes:newNodeList}
+ console.log(newData);
+ setExperimentAllMessage(res.data)
+ getGraphData(newData)
// setExperimentStatusObj(JSON.parse(ret.data.nodes_status))
}
@@ -327,6 +360,16 @@ const ExperimentText = React.FC = () => {
return (
+
启动时间:{momnet(experimentAllMessage.create_time).format('YYYY-MM-DD HH:mm:ss')}
+
执行时长:{experimentAllMessage.finish_time?timers(new Date(experimentAllMessage.finish_time).getTime()-new Date(experimentAllMessage.create_time).getTime()):timers(new Date().getTime()-new Date(experimentAllMessage.create_time).getTime())}
+
状态:
+
+
{statusObj[experimentAllMessage.status]}
diff --git a/react-ui/src/pages/Experiment/experimentText/props.jsx b/react-ui/src/pages/Experiment/experimentText/props.jsx
index 3bf1029b..2b2fec99 100644
--- a/react-ui/src/pages/Experiment/experimentText/props.jsx
+++ b/react-ui/src/pages/Experiment/experimentText/props.jsx
@@ -3,19 +3,48 @@ import { Button, Drawer,Form, Input ,Tabs } from 'antd';
import Styles from './editPipeline.less'
import{getQueryByExperimentLog}from '@/services/experiment/index.js'
import { ProfileOutlined, DatabaseOutlined} from '@ant-design/icons';
+import momnet from 'moment'
const { TextArea } = Input;
const Props = forwardRef(({onParentChange}, ref) =>{
const [form] = Form.useForm();
const [stagingItem,setStagingItem]=useState({})
const [messageItem,setMessageItem]=useState('')
-
+ const statusObj={
+ "Running":'运行中',
+ "Succeeded":'成功',
+ "Pending":'等待中',
+ "Failed":'失败',
+ "Error":'错误',
+ "Terminated":'终止',
+ "Skipped":'未执行',
+ "Omitted":'未执行',
+ }
+ const statusColorObj={
+ "Running":'#165bff',
+ "Succeeded":'#63a728',
+ "Pending":'#f981eb',
+ "Failed":'#c73131',
+ "Error":'#c73131',
+ "Terminated":'#8a8a8a',
+ "Skipped":'#8a8a8a',
+ "Omitted":'#8a8a8ae',
+ }
+ const timers=(time)=>{
+ let timer=new Date(time)
+ let hours = timer.getHours(); //转换成时
+ let minutes = timer.getMinutes(); //转换成分
+ let secend = timer.getSeconds(); //转换成秒
+
+ let str = `${minutes}分${secend}秒`;
+ return str;
+ }
const items = [
{
key: '1',
label: '日志详情',
children:
,
icon:
@@ -226,11 +255,6 @@ const Props = forwardRef(({onParentChange}, ref) =>{
form.resetFields();
form.setFieldsValue({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters),control_strategy:JSON.parse(e.item.getModel().control_strategy)})
setStagingItem({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters),control_strategy:JSON.parse(e.item.getModel().control_strategy)})
- // form.setFieldsValue({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters)})
- // setStagingItem({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters)})
- // setTimeout(() => {
- // console.log(stagingItem);
- // }, (500));
setOpen(true);
})
}
@@ -238,11 +262,6 @@ const Props = forwardRef(({onParentChange}, ref) =>{
form.resetFields();
form.setFieldsValue({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters),control_strategy:JSON.parse(e.item.getModel().control_strategy)})
setStagingItem({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters),control_strategy:JSON.parse(e.item.getModel().control_strategy)})
- // form.setFieldsValue({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters)})
- // setStagingItem({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters)})
- // setTimeout(() => {
- // console.log(stagingItem);
- // }, (500));
setOpen(true);
}
// console.log(e.item.getModel().in_parameters);
@@ -252,7 +271,18 @@ const Props = forwardRef(({onParentChange}, ref) =>{
}));
return (
<>
-
+
+ 任务名称:{stagingItem.label}
+ 执行状态:
+
+
{statusObj[stagingItem.experimentStatus]}
+ 启动时间:{momnet(stagingItem.experimentStartTime).format('YYYY-MM-DD HH:mm:ss')}
+ 耗时:{stagingItem.experimentEndTime?timers(new Date(stagingItem.experimentEndTime).getTime()-new Date(stagingItem.experimentStartTime).getTime()):timers(new Date().getTime()-new Date(stagingItem.experimentStartTime).getTime())}
diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx
index 91aa7704..2fd83114 100644
--- a/react-ui/src/pages/Experiment/index.jsx
+++ b/react-ui/src/pages/Experiment/index.jsx
@@ -1,8 +1,8 @@
import React ,{ useState,useEffect,useRef }from 'react';
import { Space, Table, Tag,Button,Modal, Form, Input ,message, Select,} from 'antd';
-import { PlusOutlined, EditOutlined ,PlayCircleOutlined} from '@ant-design/icons';
-import {getWorkflow,addWorkflow,removeWorkflow,cloneWorkflow} from '@/services/pipeline/index.js'
-import {getExperiment,runExperiments,getExperimentById,postExperiment,putExperiment,getQueryByExperimentId} from '@/services/experiment/index.js'
+import { PlusOutlined, EditOutlined ,PlayCircleOutlined,DeleteOutlined,FieldTimeOutlined} from '@ant-design/icons';
+import {getWorkflow,} from '@/services/pipeline/index.js'
+import {getExperiment,runExperiments,getExperimentById,postExperiment,putExperiment,getQueryByExperimentId,deleteExperimentById,deleteQueryByExperimentInsId,putQueryByExperimentInsId} from '@/services/experiment/index.js'
import Styles from './index.less'
import { useNavigate} from 'react-router-dom';
import momnet from 'moment'
@@ -14,9 +14,31 @@ const Experiment = React.FC = () => {
const statusObj={
"Running":'运行中',
"Succeeded":'成功',
+ "Pending":'等待中',
"Failed":'失败',
"Error":'错误',
- "Teminated":'终止'
+ "Terminated":'终止',
+ "Skipped":'未执行',
+ "Omitted":'未执行',
+ }
+ const statusColorObj={
+ "Running":'#165bff',
+ "Succeeded":'#63a728',
+ "Pending":'#f981eb',
+ "Failed":'#c73131',
+ "Error":'#c73131',
+ "Terminated":'#8a8a8a',
+ "Skipped":'#8a8a8a',
+ "Omitted":'#8a8a8ae',
+ }
+ const statusImgObj={
+ 'Running':'/assets/images/running-icon.png',
+ 'Succeeded':'/assets/images/success-icon.png',
+ 'Pending':'/assets/images/pending-icon.png',
+ 'Failed':'/assets/images/fail-icon.png',
+ 'Terminated':'/assets/images/omitted-icon.png',
+ 'Skipped':'/assets/images/omitted-icon.png',
+ 'Omitted':'/assets/images/omitted-icon.png',
}
const [experimentList, setExperimentList] = useState([]);
@@ -56,10 +78,11 @@ const Experiment = React.FC = () => {
setExpandedRowKeys(val)
if(ret.code==200&&ret.data&&ret.data.length>0){
setExperimentInList(ret.data)
-
+ getList()
}
else{
setExperimentInList([])
+ getList()
}
})
}
@@ -157,7 +180,6 @@ const Experiment = React.FC = () => {
if(ret.code==200){
message.success('运行成功')
getQueryByExperiment(id)
- getList()
}
else{
message.error('运行失败')
@@ -227,8 +249,14 @@ const Experiment = React.FC = () => {
},
{
title: '最近五次运行状态',
- dataIndex: 'state',
- key: 'state',
+ dataIndex: 'status_list',
+ key: 'status_list',
+ render: (text) => {
+
+ let newText=text&&text.replace(/\s+/g,'').split(',')
+ console.log(newText);
+ return <>{ newText&&newText.length>0?newText.map((item,index)=>{console.log(item,statusImgObj[item]); return
}):null}>
+ }
},
{
@@ -258,7 +286,41 @@ const Experiment = React.FC = () => {
>
编辑
-
+ }
+ onClick={async () => {
+ Modal.confirm({
+ title: '删除',
+ content: '确定删除该条实验吗?',
+ okText: '确认',
+ cancelText: '取消',
+ onOk: () => {
+ console.log(record);
+ deleteExperimentById(record.id).then(ret=>{
+ if(ret.code==200){
+ message.success('删除成功')
+ getList()
+ }
+ else{
+ message.error(ret.msg)
+ }
+ });
+
+ // if (success) {
+ // if (actionRef.current) {
+ // actionRef.current.reload();
+ // }
+ // }
+ },
+ });
+ }}
+ >
+ 删除
+
),
},
@@ -278,14 +340,66 @@ const Experiment = React.FC = () => {
状态
运行时长
开始时间
+ 操作
:''}
{experimentInList&&experimentInList.length>0?experimentInList.map((item,index)=>(
routerToText(e,item,record)}>{index+1}
-
{statusObj[item.status]}
-
{item.finish_time?timers(new Date(item.finish_time).getTime()-new Date(item.start_time).getTime()):timers(new Date().getTime()-new Date(item.start_time).getTime())}
-
{momnet(item.start_time).format('YYYY-MM-DD HH:mm:ss')}
+
{statusObj[item.status]}
+
{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())}
+
{momnet(item.create_time).format('YYYY-MM-DD HH:mm:ss')}
+
+ }
+ onClick={async () => {
+ putQueryByExperimentInsId(item.id).then(ret=>{
+ if(ret.code==200){
+ message.success('终止成功')
+ getQueryByExperiment(record.id)
+ }
+ else{
+ message.error(ret.msg)
+ }
+ })
+ }}
+ >
+ 终止
+
+ }
+ onClick={async () => {
+ Modal.confirm({
+ title: '删除',
+ content: '确定删除该条实例吗?',
+ okText: '确认',
+ cancelText: '取消',
+ onOk: () => {
+ deleteQueryByExperimentInsId(item.id).then(ret=>{
+ if(ret.code==200){
+ message.success('删除成功')
+ getQueryByExperiment(record.id)
+ }
+ else{
+ message.error(ret.msg)
+ }
+ });
+ },
+ });
+ }}
+ >
+ 删除
+
+
)):''}
diff --git a/react-ui/src/pages/Experiment/index.less b/react-ui/src/pages/Experiment/index.less
index 701c4cbd..b015521e 100644
--- a/react-ui/src/pages/Experiment/index.less
+++ b/react-ui/src/pages/Experiment/index.less
@@ -32,4 +32,16 @@
font-size:15px;
padding: 0 65px 0 40px;
+}
+.statusBox{
+ display: flex;
+ align-items: center;
+
+ .statusIcon{
+ visibility: hidden;
+ transition: all 0.2s;
+ }
+}
+.statusBox:hover .statusIcon{
+ visibility: visible;
}
\ No newline at end of file
diff --git a/react-ui/src/pages/Pipeline/editPipeline/index.jsx b/react-ui/src/pages/Pipeline/editPipeline/index.jsx
index 087f26af..c3f37b14 100644
--- a/react-ui/src/pages/Pipeline/editPipeline/index.jsx
+++ b/react-ui/src/pages/Pipeline/editPipeline/index.jsx
@@ -13,6 +13,7 @@ import { useNavigate} from 'react-router-dom';
const editPipeline = React.FC = () => {
const propsRef=useRef()
const navgite=useNavigate();
+ const [contextMenu,setContextMenu]=useState({})
const locationParams =useParams () //新版本获取路由参数接口
let graph=null
const pipelineContainer = useEmotionCss(() => {
@@ -30,6 +31,7 @@ const editPipeline = React.FC = () => {
};
});
const graphRef=useRef()
+
const onDragEnd=(val)=>{
console.log(val,'eee');
const _x = val.x
@@ -117,9 +119,49 @@ const editPipeline = React.FC = () => {
// graph.render()
})
}
+ const handlerContextMenu=(e)=> {
+ e.stopPropagation();
+ // this.menuType = e.item._cfg.type;
+ }
+ const initMenu=()=> {
+ // const selectedNodes = this.selectedNodes;
+ setContextMenu(new G6.Menu({
+ getContent(evt) {
+ console.log(11111, evt);
+
+ let ul = `
+
+
+
+ `;
+ },
+
+
+ handleMenuClick:(target, item) => {
+ switch (target.getAttribute('code')) {
+ // case 'undo':
+ // this.$emit('handleMenuCall', { code: 'undo' });
+ // break;
+ // case 'redo':
+ // this.$emit('handleMenuCall', { code: 'redo' });
+ // break;
+ case 'delete':
+ graph.removeItem(item);
+
+ break;
+ default:
+ break;
+ }
+ },
+ offsetX: 16 + 20,
+ offsetY: 0,
+ itemTypes: ['node', 'canvas', 'edge'],
+ }));
+ };
useEffect(()=>{
getFirstWorkflow(locationParams.id)
initGraph()
+ initMenu()
},[])
const initGraph=()=>{
G6.registerNode(
@@ -224,7 +266,7 @@ const editPipeline = React.FC = () => {
animate: false,
groupByTypes: false,
fitView:true,
- plugins: [],
+ plugins: [contextMenu],
enabledStack: true,
modes: {
default: [
@@ -345,6 +387,7 @@ const editPipeline = React.FC = () => {
});
});
});
+ graph.on('contextmenu', handlerContextMenu);
window.onresize = () => {
if (!graph || graph.get('destroyed')) return;
if (!graphRef.current || !graphRef.current.scrollWidth || !graphRef.current.scrollHeight) return;
diff --git a/react-ui/src/pages/Pipeline/editPipeline/props.jsx b/react-ui/src/pages/Pipeline/editPipeline/props.jsx
index 3f032ad1..cd243f48 100644
--- a/react-ui/src/pages/Pipeline/editPipeline/props.jsx
+++ b/react-ui/src/pages/Pipeline/editPipeline/props.jsx
@@ -49,8 +49,8 @@ const Props = forwardRef(({onParentChange}, ref) =>{
};
useImperativeHandle(ref, () => ({
showDrawer (e) {
- console.log(e.item.getModel());
- // console.log(e.item.getModel().in_parameters);
+ if(e.item&&e.item.getModel()){
+ // console.log(e.item.getModel().in_parameters);
form.resetFields();
form.setFieldsValue({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters),control_strategy:JSON.parse(e.item.getModel().control_strategy)})
setStagingItem({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters),control_strategy:JSON.parse(e.item.getModel().control_strategy)})
@@ -60,6 +60,8 @@ const Props = forwardRef(({onParentChange}, ref) =>{
// console.log(stagingItem);
// }, (500));
setOpen(true);
+ }
+
},
}));
diff --git a/react-ui/src/services/experiment/index.js b/react-ui/src/services/experiment/index.js
index af4a3264..5409d042 100644
--- a/react-ui/src/services/experiment/index.js
+++ b/react-ui/src/services/experiment/index.js
@@ -21,12 +21,30 @@ export function getExperimentById(id) {
method: 'GET',
});
}
+// 根据id删除实验
+export function deleteExperimentById(id) {
+ return request(`/api/mmp/experiment/${id}`, {
+ method: 'DELETE',
+ });
+}
// 根据id查询实验实例
export function getQueryByExperimentId(id) {
return request(`/api/mmp/experimentIns/queryByExperimentId/${id}`, {
method: 'GET',
});
}
+// 根据id删除实验实例
+export function deleteQueryByExperimentInsId(id) {
+ return request(`/api/mmp/experimentIns/${id}`, {
+ method: 'DELETE',
+ });
+}
+// 根据id终止实验实例
+export function putQueryByExperimentInsId(id) {
+ return request(`/api/mmp/experimentIns/${id}`, {
+ method: 'PUT',
+ });
+}
// 根据id查询查询日志
export function getQueryByExperimentLog(params) {
return request(`/api/mmp/experimentIns/log/`, {
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/Experiment.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/Experiment.java
index a92188f4..222e8fa5 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/Experiment.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/Experiment.java
@@ -33,6 +33,8 @@ public class Experiment implements Serializable {
*/
@ApiModelProperty(name = "global_param")
private String globalParam;
+
+ private String statusList;
/**
* 简介
*/
@@ -100,7 +102,13 @@ public class Experiment implements Serializable {
this.globalParam = globalParam;
}
+ public String getStatusList() {
+ return statusList;
+ }
+ public void setStatusList(String statusList) {
+ this.statusList = statusList;
+ }
public String getCreateBy() {
return createBy;
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentInsServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentInsServiceImpl.java
index 738f41a4..600b4353 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentInsServiceImpl.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentInsServiceImpl.java
@@ -1,6 +1,7 @@
package com.ruoyi.platform.service.impl;
import com.ruoyi.common.security.utils.SecurityUtils;
+import com.ruoyi.platform.domain.Experiment;
import com.ruoyi.platform.domain.ExperimentIns;
import com.ruoyi.platform.mapper.ExperimentDao;
import com.ruoyi.platform.mapper.ExperimentInsDao;
@@ -56,12 +57,12 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
* @return 实例对象
*/
@Override
- public ExperimentIns queryById(Integer id) {
+ public ExperimentIns queryById(Integer id) throws IOException {
ExperimentIns experimentIns = this.experimentInsDao.queryById(id);
- if (experimentIns != null && (StringUtils.isEmpty(experimentIns.getStatus())) || !isTerminatedState(experimentIns.getStatus())) {
+ if (experimentIns != null && (StringUtils.isEmpty(experimentIns.getStatus())) || !isTerminatedState(experimentIns)) {
experimentIns = this.queryStatusFromArgo(experimentIns);
//只有当新状态是终止态时才更新数据库
- if (isTerminatedState(experimentIns.getStatus())) {
+ if (isTerminatedState(experimentIns)) {
//同时更新各个节点
this.update(experimentIns);
}
@@ -78,17 +79,21 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
* @return 实验列表
*/
@Override
- public List getByExperimentId(Integer experimentId) {
+ public List getByExperimentId(Integer experimentId) throws IOException {
List experimentInsList = experimentInsDao.getByExperimentId(experimentId);
-
+ //搞个标记,当状态改变才去改表
+ boolean flag = false;
List result = new ArrayList();
if (experimentInsList!=null&&experimentInsList.size()>0) {
for (ExperimentIns experimentIns : experimentInsList) {
//当原本状态为null或非终止态时才调用argo接口
- if (experimentIns != null && (StringUtils.isEmpty(experimentIns.getStatus())) || !isTerminatedState(experimentIns.getStatus())) {
+ if (experimentIns != null && (StringUtils.isEmpty(experimentIns.getStatus())) || !isTerminatedState(experimentIns)) {
experimentIns = this.queryStatusFromArgo(experimentIns);
+ if (!flag){
+ flag = true;
+ }
//只有当新状态是终止态时才更新数据库
- if (isTerminatedState(experimentIns.getStatus())) {
+ if (isTerminatedState(experimentIns)) {
//同时更新各个节点
this.update(experimentIns);
}
@@ -97,6 +102,17 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
}
}
+ if (flag) {
+ List statusList = new ArrayList();
+ // 更新实验状态列表
+ for (int i=0;i queryByPage(ExperimentIns experimentIns, PageRequest pageRequest) {
+ public Page queryByPage(ExperimentIns experimentIns, PageRequest pageRequest) throws IOException {
long total = this.experimentInsDao.count(experimentIns);
List experimentInsList = this.experimentInsDao.queryAllByLimit(experimentIns, pageRequest);
if (experimentInsList!=null && experimentInsList.size()>0) {
@@ -152,7 +168,7 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
* @return 实例对象
*/
@Override
- public ExperimentIns update(ExperimentIns experimentIns) {
+ public ExperimentIns update(ExperimentIns experimentIns) throws IOException {
LoginUser loginUser = SecurityUtils.getLoginUser();
experimentIns.setUpdateBy(loginUser.getUsername());
experimentIns.setUpdateTime(new Date());
@@ -212,8 +228,8 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
String namespace = ins.getArgoInsNs();
String name = ins.getArgoInsName();
Integer id = ins.getId();
- ExperimentIns experimentIns = this.experimentInsDao.queryById(id);
// 创建请求数据map
+ ExperimentIns experimentIns = this.experimentInsDao.queryById(id);
Map requestData = new HashMap<>();
requestData.put("namespace", namespace);
requestData.put("name", name);
@@ -241,10 +257,6 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
if (status == null || status.isEmpty()) {
throw new RuntimeException("工作流状态为空。");
}
- //解析流水线开始时间,开始时间一定存在,所以不需要判断
- Date startTime = DateUtils.convertUTCtoShanghaiDate((String) status.get("startedAt"));
- experimentIns.setStartTime(startTime);
-
//解析流水线结束时间
String finishedAtString = (String) status.get("finishedAt");
@@ -255,21 +267,25 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
// 解析nodes字段,提取节点状态并转换为JSON字符串
Map nodes = (Map) status.get("nodes");
- if (nodes == null || nodes.isEmpty()) {
- throw new RuntimeException("工作流的节点数据为空。");
- }
-
Map modifiedNodes = new LinkedHashMap<>();
-
- for (Map.Entry nodeEntry : nodes.entrySet()) {
- Map nodeDetails = (Map) nodeEntry.getValue();
- String templateName = (String) nodeDetails.get("displayName");
- modifiedNodes.put(templateName, nodeDetails);
+ if (nodes != null ) {
+ for (Map.Entry nodeEntry : nodes.entrySet()) {
+ Map nodeDetails = (Map) nodeEntry.getValue();
+ String templateName = (String) nodeDetails.get("displayName");
+ modifiedNodes.put(templateName, nodeDetails);
+ }
}
String nodeStatusJson = JsonUtils.mapToJson(modifiedNodes);
experimentIns.setNodesStatus(nodeStatusJson);
- experimentIns.setStatus((String) status.get("phase"));
+
+ //终止态为终止不改
+ if (!StringUtils.equals(experimentIns.getStatus(),"Terminated")) {
+ experimentIns.setStatus(StringUtils.isNotEmpty((String) status.get("phase"))?(String) status.get("phase"):"Pending");
+ }
+ if (StringUtils.equals(experimentIns.getStatus(),"Error")) {
+ experimentIns.setStatus("Failed");
+ }
return experimentIns;
@@ -278,7 +294,6 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
}
-
}
/**
@@ -329,9 +344,11 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
// 从响应Map中直接获取"errCode"的值
Integer errCode = (Integer) runResMap.get("errCode");
if (errCode != null && errCode == 0) {
- experimentIns.setStatus("Terminated");
//更新experimentIns,确保状态更新被保存到数据库
- this.experimentInsDao.update(experimentIns);
+ ExperimentIns ins = queryStatusFromArgo(experimentIns);
+ ins.setStatus("Terminated");
+ ins.setFinishTime(new Date());
+ this.experimentInsDao.update(ins);
return true;
} else {
return false;
@@ -395,10 +412,27 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
}
}
- private boolean isTerminatedState(String state) {
+ private boolean isTerminatedState(ExperimentIns ins) throws IOException {
// 定义终止态的列表,例如 "Succeeded", "Failed" 等
- List terminatedStates = Arrays.asList("Succeeded", "Failed", "Terminated");
- return terminatedStates.contains(state);
+ String status = ins.getStatus();
+ boolean flag = true;
+ List terminatedStates = Arrays.asList("Succeeded", "Failed");
+ flag = terminatedStates.contains(status);
+ if (StringUtils.equals(status, "Terminated")){
+ //如果跟node_status里面不一样,就要去更新node_status的信息
+ String nodesStatus = ins.getNodesStatus();
+ Map nodeMap = JsonUtils.jsonToMap(nodesStatus);
+ String keyStartsWithWorkflow = nodeMap.keySet().stream()
+ .filter(key -> key.startsWith("workflow-"))
+ .findFirst()
+ .orElse(null);
+ Map workflowMap = (Map) nodeMap.get(keyStartsWithWorkflow);
+ if (workflowMap != null){
+ flag = StringUtils.equals("Terminated", (String) workflowMap.get("phase"));
+ }
+ }
+
+ return flag;
}
}
diff --git a/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ExperimentDaoMapper.xml b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ExperimentDaoMapper.xml
index d26be7de..d0ae5dbc 100644
--- a/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ExperimentDaoMapper.xml
+++ b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ExperimentDaoMapper.xml
@@ -7,6 +7,7 @@
+
@@ -18,7 +19,7 @@
@@ -26,7 +27,7 @@