| @@ -4,4 +4,7 @@ module.exports = { | |||||
| page: true, | page: true, | ||||
| REACT_APP_ENV: true, | REACT_APP_ENV: true, | ||||
| }, | }, | ||||
| rules: { | |||||
| "@typescript-eslint/no-use-before-define": "off" | |||||
| } | |||||
| }; | }; | ||||
| @@ -15,9 +15,9 @@ export default { | |||||
| // localhost:8000/api/** -> https://preview.pro.ant.design/api/** | // localhost:8000/api/** -> https://preview.pro.ant.design/api/** | ||||
| '/api/': { | '/api/': { | ||||
| // 要代理的地址 | // 要代理的地址 | ||||
| // target: 'ci4s-gateway-service.ci4s-test.svc:8082', | |||||
| // target: 'http://172.20.32.98:8082', | |||||
| target: 'http://172.20.32.150:8082', | |||||
| // target: 'http://172.20.32.181:31205', | |||||
| target: 'http://172.20.32.98:8082', | |||||
| // target: 'http://172.20.32.150:8082', | |||||
| // 配置了这个可以从 http 代理到 https | // 配置了这个可以从 http 代理到 https | ||||
| // 依赖 origin 的功能可能需要这个,比如 cookie | // 依赖 origin 的功能可能需要这个,比如 cookie | ||||
| changeOrigin: true, | changeOrigin: true, | ||||
| @@ -26,7 +26,7 @@ export default { | |||||
| '/profile/avatar/': { | '/profile/avatar/': { | ||||
| target: 'http://172.20.32.181:31205', | target: 'http://172.20.32.181:31205', | ||||
| changeOrigin: true, | changeOrigin: true, | ||||
| } | |||||
| }, | |||||
| }, | }, | ||||
| /** | /** | ||||
| @@ -46,18 +46,34 @@ export default [ | |||||
| }, | }, | ||||
| ], | ], | ||||
| }, | }, | ||||
| { | |||||
| name: 'datasetPreparation', | |||||
| path: '/datasetPreparation', | |||||
| routes: [ | |||||
| { | |||||
| name: 'datasetAnnotation', | |||||
| path: 'datasetAnnotation', | |||||
| component: './DatasetPreparation/DatasetAnnotation/index', | |||||
| }, | |||||
| { | |||||
| name: '训练', | |||||
| path: 'pytorchtext/:id/:name', | |||||
| component: './Pipeline/editPipeline/index', | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| { | { | ||||
| name: 'pipeline', | name: 'pipeline', | ||||
| path: '/pipeline', | path: '/pipeline', | ||||
| routes: [ | routes: [ | ||||
| { | { | ||||
| name: '流水线', | name: '流水线', | ||||
| path: '/pipeline', | |||||
| path: '', | |||||
| component: './Pipeline/index', | component: './Pipeline/index', | ||||
| }, | }, | ||||
| { | { | ||||
| name: '训练', | name: '训练', | ||||
| path: '/pipeline/pytorchtext/:id/:name', | |||||
| path: 'pytorchtext/:id/:name', | |||||
| component: './Pipeline/editPipeline/index', | component: './Pipeline/editPipeline/index', | ||||
| }, | }, | ||||
| ], | ], | ||||
| @@ -68,12 +84,12 @@ export default [ | |||||
| routes: [ | routes: [ | ||||
| { | { | ||||
| name: '实验', | name: '实验', | ||||
| path: '/experiment', | |||||
| path: '', | |||||
| component: './Experiment/index', | component: './Experiment/index', | ||||
| }, | }, | ||||
| { | { | ||||
| name: '实验训练', | name: '实验训练', | ||||
| path: '/experiment/pytorchtext/:workflowId/:id', | |||||
| path: 'pytorchtext/:workflowId/:id', | |||||
| component: './Experiment/experimentText/index', | component: './Experiment/experimentText/index', | ||||
| }, | }, | ||||
| ], | ], | ||||
| @@ -84,7 +100,7 @@ export default [ | |||||
| routes: [ | routes: [ | ||||
| { | { | ||||
| name: '开发环境', | name: '开发环境', | ||||
| path: '/developmentEnvironment', | |||||
| path: '', | |||||
| component: './DevelopmentEnvironment/index', | component: './DevelopmentEnvironment/index', | ||||
| }, | }, | ||||
| ], | ], | ||||
| @@ -103,7 +119,7 @@ export default [ | |||||
| path: '/system/role-auth/user/:id', | path: '/system/role-auth/user/:id', | ||||
| component: './System/Role/authUser', | component: './System/Role/authUser', | ||||
| }, | }, | ||||
| ] | |||||
| ], | |||||
| }, | }, | ||||
| { | { | ||||
| name: 'dataset', | name: 'dataset', | ||||
| @@ -123,14 +139,13 @@ export default [ | |||||
| name: '模型管理', | name: '模型管理', | ||||
| path: '/dataset/modelIndex', | path: '/dataset/modelIndex', | ||||
| component: './Model/index', | component: './Model/index', | ||||
| }, | }, | ||||
| { | { | ||||
| name: '模型简介', | name: '模型简介', | ||||
| path: '/dataset/modelIntro/:id', | path: '/dataset/modelIntro/:id', | ||||
| component: './Model/modelIntro', | component: './Model/modelIntro', | ||||
| }, | }, | ||||
| ] | |||||
| ], | |||||
| }, | }, | ||||
| { | { | ||||
| name: 'monitor', | name: 'monitor', | ||||
| @@ -141,7 +156,7 @@ export default [ | |||||
| path: '/monitor/job-log/index/:id', | path: '/monitor/job-log/index/:id', | ||||
| component: './Monitor/JobLog', | component: './Monitor/JobLog', | ||||
| }, | }, | ||||
| ] | |||||
| ], | |||||
| }, | }, | ||||
| { | { | ||||
| name: 'tool', | name: 'tool', | ||||
| @@ -157,6 +172,6 @@ export default [ | |||||
| path: '/tool/gen/edit', | path: '/tool/gen/edit', | ||||
| component: './Tool/Gen/edit', | component: './Tool/Gen/edit', | ||||
| }, | }, | ||||
| ] | |||||
| ], | |||||
| }, | }, | ||||
| ]; | ]; | ||||
| @@ -1,23 +1,25 @@ | |||||
| import RightContent from '@/components/RightContent'; | import RightContent from '@/components/RightContent'; | ||||
| import { LinkOutlined } from '@ant-design/icons'; | |||||
| import type { Settings as LayoutSettings } from '@ant-design/pro-components'; | import type { Settings as LayoutSettings } from '@ant-design/pro-components'; | ||||
| import { SettingDrawer } from '@ant-design/pro-components'; | |||||
| import type { RunTimeLayoutConfig } from '@umijs/max'; | import type { RunTimeLayoutConfig } from '@umijs/max'; | ||||
| import { history, Link } from '@umijs/max'; | |||||
| import { history } from '@umijs/max'; | |||||
| import axios from 'axios'; | |||||
| import defaultSettings from '../config/defaultSettings'; | import defaultSettings from '../config/defaultSettings'; | ||||
| import { errorConfig } from './requestErrorConfig'; | |||||
| import { clearSessionToken, getAccessToken, getRefreshToken, getTokenExpireTime } from './access'; | |||||
| import { getRemoteMenu, getRoutersInfo, getUserInfo, patchRouteWithRemoteMenus, setRemoteMenu } from './services/session'; | |||||
| import '../public/fonts/font.css'; | |||||
| import { getAccessToken } from './access'; | |||||
| import './dayjsConfig'; | |||||
| import { PageEnum } from './enums/pagesEnums'; | import { PageEnum } from './enums/pagesEnums'; | ||||
| import '../public/fonts/font.css' | |||||
| import './global.less' | |||||
| import axios from 'axios' | |||||
| axios.defaults.baseUrl='http://172.20.32.150:8082' | |||||
| import './global.less'; | |||||
| import { | |||||
| getRemoteMenu, | |||||
| getRoutersInfo, | |||||
| getUserInfo, | |||||
| patchRouteWithRemoteMenus, | |||||
| setRemoteMenu, | |||||
| } from './services/session'; | |||||
| export { requestConfig as request } from './requestConfig'; | |||||
| axios.defaults.baseUrl = 'http://172.20.32.150:8082'; | |||||
| const isDev = process.env.NODE_ENV === 'development'; | const isDev = process.env.NODE_ENV === 'development'; | ||||
| /** | /** | ||||
| * @see https://umijs.org/zh-CN/plugins/plugin-initial-state | * @see https://umijs.org/zh-CN/plugins/plugin-initial-state | ||||
| * */ | * */ | ||||
| @@ -155,9 +157,9 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) = | |||||
| export async function onRouteChange({ clientRoutes, location }) { | export async function onRouteChange({ clientRoutes, location }) { | ||||
| const menus = getRemoteMenu(); | const menus = getRemoteMenu(); | ||||
| // console.log('onRouteChange', clientRoutes, location, menus); | |||||
| if(menus === null && location.pathname !== PageEnum.LOGIN) { | |||||
| console.log('refresh') | |||||
| // console.log('onRouteChange', clientRoutes, location, menus); | |||||
| if (menus === null && location.pathname !== PageEnum.LOGIN) { | |||||
| console.log('refresh'); | |||||
| history.go(0); | history.go(0); | ||||
| } | } | ||||
| } | } | ||||
| @@ -166,7 +168,6 @@ export async function onRouteChange({ clientRoutes, location }) { | |||||
| // console.log('patchRoutes', routes, routeComponents); | // console.log('patchRoutes', routes, routeComponents); | ||||
| // } | // } | ||||
| export async function patchClientRoutes({ routes }) { | export async function patchClientRoutes({ routes }) { | ||||
| // console.log('patchClientRoutes', routes); | // console.log('patchClientRoutes', routes); | ||||
| patchRouteWithRemoteMenus(routes); | patchRouteWithRemoteMenus(routes); | ||||
| @@ -175,62 +176,12 @@ export async function patchClientRoutes({ routes }) { | |||||
| export function render(oldRender: () => void) { | export function render(oldRender: () => void) { | ||||
| // console.log('render get routers', oldRender) | // console.log('render get routers', oldRender) | ||||
| const token = getAccessToken(); | const token = getAccessToken(); | ||||
| if(!token || token?.length === 0) { | |||||
| if (!token || token?.length === 0) { | |||||
| oldRender(); | oldRender(); | ||||
| return; | return; | ||||
| } | } | ||||
| getRoutersInfo().then(res => { | |||||
| getRoutersInfo().then((res) => { | |||||
| setRemoteMenu(res); | setRemoteMenu(res); | ||||
| oldRender() | |||||
| oldRender(); | |||||
| }); | }); | ||||
| } | } | ||||
| /** | |||||
| * @name request 配置,可以配置错误处理 | |||||
| * 它基于 axios 和 ahooks 的 useRequest 提供了一套统一的网络请求和错误处理方案。 | |||||
| * @doc https://umijs.org/docs/max/request#配置 | |||||
| */ | |||||
| const checkRegion = 5 * 60 * 1000; | |||||
| export const request = { | |||||
| ...errorConfig, | |||||
| requestInterceptors: [ | |||||
| (url: any, options: { headers: any }) => { | |||||
| const headers = options.headers ? options.headers : []; | |||||
| console.log('request ====>:', url); | |||||
| const authHeader = headers['Authorization']; | |||||
| const isToken = headers['isToken']; | |||||
| if (!authHeader && isToken !== false) { | |||||
| const expireTime = getTokenExpireTime(); | |||||
| if (expireTime) { | |||||
| const left = Number(expireTime) - new Date().getTime(); | |||||
| const refreshToken = getRefreshToken(); | |||||
| if (left < checkRegion && refreshToken) { | |||||
| if (left < 0) { | |||||
| clearSessionToken(); | |||||
| } | |||||
| } else { | |||||
| const accessToken = getAccessToken(); | |||||
| if (accessToken) { | |||||
| headers['Authorization'] = `Bearer ${accessToken}`; | |||||
| } | |||||
| } | |||||
| } else { | |||||
| clearSessionToken(); | |||||
| } | |||||
| } | |||||
| return { url, options }; | |||||
| }, | |||||
| ], | |||||
| responseInterceptors: [ | |||||
| // (response) => | |||||
| // { | |||||
| // // // 不再需要异步处理读取返回体内容,可直接在data中读出,部分字段可在 config 中找到 | |||||
| // // const { data = {} as any, config } = response; | |||||
| // // // do something | |||||
| // // console.log('data: ', data) | |||||
| // // console.log('config: ', config) | |||||
| // return response | |||||
| // }, | |||||
| ], | |||||
| }; | |||||
| @@ -0,0 +1,3 @@ | |||||
| import dayjs from 'dayjs'; | |||||
| import duration from 'dayjs/plugin/duration'; | |||||
| dayjs.extend(duration); | |||||
| @@ -0,0 +1 @@ | |||||
| @@ -0,0 +1,6 @@ | |||||
| import { getDictValueEnum } from '@/services/system/dict'; | |||||
| export function useDictEnum(name: string) { | |||||
| const data = getDictValueEnum(name); | |||||
| return data; | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| import { useEffect, useRef, useState } from 'react'; | |||||
| export function useStateRef<T>(initialValue: T) { | |||||
| const [value, setValue] = useState(initialValue); | |||||
| const ref = useRef(value); | |||||
| useEffect(() => { | |||||
| ref.current = value; | |||||
| }, [value]); | |||||
| return [value, setValue, ref] as const; | |||||
| } | |||||
| @@ -1,7 +0,0 @@ | |||||
| import { getDictValueEnum } from "@/services/system/dict"; | |||||
| export function useDictEnum(name: string) | |||||
| { | |||||
| const data = getDictValueEnum(name); | |||||
| return data; | |||||
| } | |||||
| @@ -0,0 +1,10 @@ | |||||
| .container { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| .frame { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| border: none; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| import styles from './index.less'; | |||||
| function DatasetAnnotation() { | |||||
| return ( | |||||
| <div className={styles.container}> | |||||
| <iframe src="http://172.20.32.181:32102" className={styles.frame}></iframe> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default DatasetAnnotation; | |||||
| @@ -1,14 +0,0 @@ | |||||
| import React ,{ useState,useEffect,useRef }from 'react'; | |||||
| import {getJupyterUrl} from '@/services/developmentEnvironment/index.js' | |||||
| const developmentEnvironment = React.FC = () => { | |||||
| const [iframeUrl,setIframeUrl]=useState('') | |||||
| useEffect(()=>{ | |||||
| getJupyterUrl().then(ret=>{ | |||||
| console.log(ret); | |||||
| setIframeUrl(ret.msg) | |||||
| }) | |||||
| },[]) | |||||
| return ( | |||||
| <iframe style={{width:'100%',height:'81vh'}} src={iframeUrl} frameborder="0"></iframe> | |||||
| )}; | |||||
| export default developmentEnvironment; | |||||
| @@ -0,0 +1,22 @@ | |||||
| import { getJupyterUrl } from '@/services/developmentEnvironment'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| const DevelopmentEnvironment = () => { | |||||
| const [iframeUrl, setIframeUrl] = useState(''); | |||||
| useEffect(() => { | |||||
| requestJupyterUrl(); | |||||
| }, []); | |||||
| const requestJupyterUrl = async () => { | |||||
| const [res, error] = await to(getJupyterUrl()); | |||||
| if (res) { | |||||
| setIframeUrl(res.data as string); | |||||
| } else { | |||||
| console.log(error); | |||||
| } | |||||
| }; | |||||
| return <iframe style={{ width: '100%', height: '81vh', border: 0 }} src={iframeUrl}></iframe>; | |||||
| }; | |||||
| export default DevelopmentEnvironment; | |||||
| @@ -0,0 +1,18 @@ | |||||
| import LogGroup from './logGroup'; | |||||
| type LogListProps = { | |||||
| list: any[]; | |||||
| status: string; | |||||
| }; | |||||
| function LogList({ list = [], status }: LogListProps) { | |||||
| return ( | |||||
| <div> | |||||
| {list.map((v) => ( | |||||
| <LogGroup key={v.pod_name} {...v} status={status} /> | |||||
| ))} | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default LogList; | |||||
| @@ -0,0 +1,51 @@ | |||||
| .modal { | |||||
| :global { | |||||
| .ant-modal-content { | |||||
| width: 825px; | |||||
| padding: 20px 67px; | |||||
| background: linear-gradient(180deg, #cfdfff 0%, #d4e2ff 9.77%, #ffffff 40%, #ffffff 100%); | |||||
| border-radius: 21px; | |||||
| } | |||||
| .ant-modal-header { | |||||
| margin: 20px 0; | |||||
| background-color: transparent; | |||||
| } | |||||
| .ant-input { | |||||
| height: 40px; | |||||
| border-color: #e6e6e6; | |||||
| } | |||||
| .ant-select-single { | |||||
| height: 40px; | |||||
| } | |||||
| .ant-form-item .ant-form-item-label > label { | |||||
| color: rgba(29, 29, 32, 0.8); | |||||
| } | |||||
| .ant-modal-footer { | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| margin: 40px 0 30px 0; | |||||
| } | |||||
| .ant-btn { | |||||
| width: 110px; | |||||
| height: 40px; | |||||
| font-size: 18px; | |||||
| background: rgba(22, 100, 255, 0.06); | |||||
| border-color: transparent; | |||||
| border-radius: 10px; | |||||
| } | |||||
| .ant-btn-primary { | |||||
| background: #1664ff; | |||||
| } | |||||
| } | |||||
| .title { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| font-weight: 500; | |||||
| .image { | |||||
| width: 20px; | |||||
| margin-right: 10px; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,127 @@ | |||||
| import { Form, Input, Modal, Select } from 'antd'; | |||||
| import { useState } from 'react'; | |||||
| import styles from './addExperimentModal.less'; | |||||
| type FormData = { | |||||
| name?: string; | |||||
| description?: string; | |||||
| workflow_id?: string | number; | |||||
| }; | |||||
| type AddExperimentModalProps = { | |||||
| isAdd: boolean; | |||||
| open: boolean; | |||||
| onCancel: () => void; | |||||
| onFinish: () => void; | |||||
| workflowList: Workflow[]; | |||||
| initialValues: FormData; | |||||
| }; | |||||
| interface GlobalParam { | |||||
| param_name: string; | |||||
| param_value: string; | |||||
| } | |||||
| interface Workflow { | |||||
| id: string | number; | |||||
| name: string; | |||||
| global_param?: GlobalParam[] | null; | |||||
| } | |||||
| function AddExperimentModal({ | |||||
| isAdd, | |||||
| open, | |||||
| onCancel, | |||||
| onFinish, | |||||
| workflowList = [], | |||||
| initialValues = {}, | |||||
| }: AddExperimentModalProps) { | |||||
| const dialogTitle = isAdd ? '新建实验' : '编辑实验'; | |||||
| const workflowDisabled = isAdd ? false : true; | |||||
| const [globalParam, setGlobalParam] = useState<GlobalParam[]>([]); | |||||
| const [form] = Form.useForm(); | |||||
| // 除了流水线选择发生变化 | |||||
| const handleWorkflowChange = (id: string) => { | |||||
| const pipeline: Workflow | undefined = workflowList.find((v) => v.id === id); | |||||
| if (pipeline && pipeline.global_param) { | |||||
| setGlobalParam(pipeline.global_param); | |||||
| const fields = pipeline.global_param.reduce((acc, item) => { | |||||
| acc[item.param_name] = item.param_value; | |||||
| return acc; | |||||
| }, {} as Record<string, string>); | |||||
| form.setFieldsValue(fields); | |||||
| } else { | |||||
| setGlobalParam([]); | |||||
| } | |||||
| }; | |||||
| return ( | |||||
| <Modal | |||||
| className={styles.modal} | |||||
| title={ | |||||
| <div className={styles.title}> | |||||
| <img className={styles.image} src={`/assets/images/pipeline-edit-icon.png`} alt="" /> | |||||
| {dialogTitle} | |||||
| </div> | |||||
| } | |||||
| open={open} | |||||
| okButtonProps={{ | |||||
| htmlType: 'submit', | |||||
| form: 'form', | |||||
| }} | |||||
| onCancel={onCancel} | |||||
| destroyOnClose={true} | |||||
| > | |||||
| <Form | |||||
| name="form" | |||||
| layout="vertical" | |||||
| initialValues={initialValues} | |||||
| onFinish={onFinish} | |||||
| autoComplete="off" | |||||
| form={form} | |||||
| > | |||||
| <Form.Item | |||||
| label="实验名称" | |||||
| name="name" | |||||
| rules={[{ required: true, message: '请输入实验名称' }]} | |||||
| > | |||||
| <Input placeholder="请输入实验名称" maxLength={64} showCount allowClear /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="实验描述" | |||||
| name="description" | |||||
| rules={[{ required: true, message: '请输入实验描述' }]} | |||||
| > | |||||
| <Input placeholder="请输入实验描述" maxLength={128} showCount allowClear /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="选择流水线" | |||||
| name="workflow_id" | |||||
| rules={[{ required: true, message: '请选择流水线' }]} | |||||
| > | |||||
| <Select | |||||
| disabled={workflowDisabled} | |||||
| placeholder="请选择流水线" | |||||
| onChange={handleWorkflowChange} | |||||
| > | |||||
| {Array.isArray(workflowList) | |||||
| ? workflowList.map((item) => { | |||||
| return ( | |||||
| <Select.Option key={item.id} value={item.id}> | |||||
| {item.name} | |||||
| </Select.Option> | |||||
| ); | |||||
| }) | |||||
| : null} | |||||
| </Select> | |||||
| </Form.Item> | |||||
| {globalParam.map((item) => ( | |||||
| <Form.Item label={item.param_name} name={item.param_name} key={item.param_name}> | |||||
| <Input /> | |||||
| </Form.Item> | |||||
| ))} | |||||
| </Form> | |||||
| </Modal> | |||||
| ); | |||||
| } | |||||
| export default AddExperimentModal; | |||||
| @@ -1,375 +1,405 @@ | |||||
| import React ,{ useState,useEffect,useRef }from 'react'; | |||||
| import { useParams } from 'react-router-dom' | |||||
| import Props from './props'; | |||||
| import { getExperimentIns } from '@/services/experiment/index.js'; | |||||
| import { getWorkflowById } from '@/services/pipeline/index.js'; | |||||
| import { elapsedTime } from '@/utils/date'; | |||||
| import { useEmotionCss } from '@ant-design/use-emotion-css'; | import { useEmotionCss } from '@ant-design/use-emotion-css'; | ||||
| import G6 from '@antv/g6'; | import G6 from '@antv/g6'; | ||||
| import Styles from './editPipeline.less' | |||||
| import momnet from 'moment'; | |||||
| import { useEffect, useRef, useState } from 'react'; | |||||
| import { useNavigate, useParams } from 'react-router-dom'; | |||||
| import { s8 } from '../../../utils'; | 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 { 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', | |||||
| import { experimentStatusInfo } from '../status'; | |||||
| import Styles from './editPipeline.less'; | |||||
| import Props from './props'; | |||||
| function ExperimentText() { | |||||
| const [message, setMessage] = useState({}); | |||||
| const messageRef = useRef(message); | |||||
| const propsRef = useRef(); | |||||
| const navgite = useNavigate(); | |||||
| const locationParams = useParams(); //新版本获取路由参数接口 | |||||
| let graph = null; | |||||
| 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', | |||||
| backgroundColor: '#fff', | |||||
| height: '98vh', | |||||
| }; | |||||
| }); | |||||
| const graphStyle = useEmotionCss(() => { | |||||
| return { | |||||
| width: '100%', | |||||
| backgroundColor: '#f9fafb', | |||||
| flex: 1, | |||||
| }; | |||||
| }); | |||||
| const graphRef = useRef(); | |||||
| const onDragEnd = (val) => { | |||||
| console.log(val, 'eee'); | |||||
| const _x = val.x; | |||||
| const _y = val.y; | |||||
| const point = graph.getPointByClient(_x, _y); | |||||
| let model = {}; | |||||
| // 元模型 | |||||
| model = { | |||||
| ...val, | |||||
| x: point.x, | |||||
| y: point.y, | |||||
| id: val.component_name + '-' + s8(), | |||||
| isCluster: false, | |||||
| }; | |||||
| console.log(graph, model); | |||||
| graph.addItem('node', model, true); | |||||
| console.log(graph); | |||||
| }; | |||||
| const formChange = (val) => {}; | |||||
| const handlerClick = (e) => { | |||||
| console.log(propsRef, graph, messageRef.current); | |||||
| // let cache = []; | |||||
| // let json_str = JSON.stringify(graph, function(key, value) { | |||||
| // if (typeof value === 'object' && value !== null) { | |||||
| // if (cache.indexOf(value) !== -1) { | |||||
| // return; | |||||
| // } | |||||
| // cache.push(value); | |||||
| // } | |||||
| // return value; | |||||
| // }); | |||||
| // console.log(json_str); | |||||
| propsRef.current.showDrawer(e, locationParams.id, messageRef.current); | |||||
| }; | |||||
| const getGraphData = (data) => { | |||||
| if (graph) { | |||||
| console.log(graph); | |||||
| graph.data(data); | |||||
| graph.render(); | |||||
| } else { | |||||
| setTimeout(() => { | |||||
| getGraphData(data); | |||||
| }, 500); | |||||
| } | } | ||||
| 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', | |||||
| backgroundColor:'#fff', | |||||
| height:'98vh' | |||||
| }; | |||||
| }); | |||||
| const graphStyle = useEmotionCss(() => { | |||||
| return { | |||||
| width:'100%', | |||||
| backgroundColor:'#f9fafb', | |||||
| flex:1 | |||||
| }; | |||||
| }); | |||||
| const graphRef=useRef() | |||||
| const onDragEnd=(val)=>{ | |||||
| console.log(val,'eee'); | |||||
| const _x = val.x | |||||
| const _y = val.y | |||||
| const point = graph.getPointByClient(_x, _y); | |||||
| let model = {}; | |||||
| // 元模型 | |||||
| model = { | |||||
| ...val, | |||||
| x: point.x, | |||||
| y: point.y, | |||||
| id: val.component_name+'-'+s8(), | |||||
| isCluster: false, | |||||
| }; | |||||
| console.log(graph, model); | |||||
| }; | |||||
| const getFirstWorkflow = (val) => { | |||||
| getWorkflowById(val).then((ret) => { | |||||
| console.log(ret, 'retttttttttt'); | |||||
| if (ret.code == 200) { | |||||
| if (graph && ret.data && ret.data.dag) { | |||||
| console.log(JSON.parse(ret.data.dag)); | |||||
| getExperimentIns(locationParams.id).then((res) => { | |||||
| if (res.code == 200) { | |||||
| console.log(ret.data, 'data'); | |||||
| setMessage(res.data); | |||||
| const experimentStatusObjs = JSON.parse(res.data.nodes_status); | |||||
| 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 }; | |||||
| graph.addItem('node', model, true); | |||||
| console.log(graph); | |||||
| } | |||||
| const formChange=(val)=>{ | |||||
| } | |||||
| const handlerClick=(e)=>{ | |||||
| console.log(propsRef,graph); | |||||
| // let cache = []; | |||||
| // let json_str = JSON.stringify(graph, function(key, value) { | |||||
| // if (typeof value === 'object' && value !== null) { | |||||
| // if (cache.indexOf(value) !== -1) { | |||||
| // return; | |||||
| // } | |||||
| // cache.push(value); | |||||
| // } | |||||
| // return value; | |||||
| // }); | |||||
| // console.log(json_str); | |||||
| propsRef.current.showDrawer(e,locationParams.id) | |||||
| } | |||||
| const getGraphData=(data)=>{ | |||||
| if(graph){ | |||||
| console.log(graph); | |||||
| graph.data(data) | |||||
| graph.render() | |||||
| } | |||||
| else{ | |||||
| setTimeout(()=>{ | |||||
| getGraphData(data) | |||||
| },500) | |||||
| getGraphData(newData); | |||||
| // setExperimentStatusObj(JSON.parse(ret.data.nodes_status)) | |||||
| } | |||||
| }); | |||||
| } | } | ||||
| } | } | ||||
| const getFirstWorkflow=(val)=>{ | |||||
| getWorkflowById(val).then(ret=>{ | |||||
| console.log(ret,'retttttttttt'); | |||||
| if(ret.code==200){ | |||||
| if(graph&&ret.data&&ret.data.dag){ | |||||
| 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,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)) | |||||
| } | |||||
| }) | |||||
| // graph&&graph.data(JSON.parse(ret.dag)) | |||||
| // graph.render() | |||||
| }); | |||||
| }; | |||||
| // const getExperimentIn=(val)=>{ | |||||
| // getExperimentIns(val).then(ret=>{ | |||||
| // if(ret.code==200){ | |||||
| // console.log(JSON.parse(ret.data.nodes_status)); | |||||
| // setExperimentStatusObj(JSON.parse(ret.data.nodes_status)) | |||||
| // setTimeout(() => { | |||||
| // console.log(experimentStatusObj); | |||||
| } | |||||
| } | |||||
| // graph&&graph.data(JSON.parse(ret.dag)) | |||||
| // graph.render() | |||||
| }) | |||||
| } | |||||
| // const getExperimentIn=(val)=>{ | |||||
| // getExperimentIns(val).then(ret=>{ | |||||
| // if(ret.code==200){ | |||||
| // console.log(JSON.parse(ret.data.nodes_status)); | |||||
| // setExperimentStatusObj(JSON.parse(ret.data.nodes_status)) | |||||
| // setTimeout(() => { | |||||
| // console.log(experimentStatusObj); | |||||
| // }, 1000); | |||||
| // } | |||||
| // }) | |||||
| // } | |||||
| useEffect(()=>{ | |||||
| initGraph() | |||||
| getFirstWorkflow(locationParams.workflowId) | |||||
| },[]) | |||||
| const initGraph=()=>{ | |||||
| G6.registerNode( | |||||
| '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], | |||||
| // }, 1000); | |||||
| // } | |||||
| ] | |||||
| ); | |||||
| }, | |||||
| 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: { | |||||
| r: 3, | |||||
| x: bbox.x + bbox.width * anchorPos[0], | |||||
| y: bbox.y + bbox.height * anchorPos[1], | |||||
| fill: '#fff', | |||||
| stroke: '#a4a4a5', | |||||
| }, | |||||
| 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) { | |||||
| 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() | |||||
| }) | |||||
| // } | |||||
| // }) | |||||
| // } | |||||
| useEffect(() => { | |||||
| initGraph(); | |||||
| getFirstWorkflow(locationParams.workflowId); | |||||
| }, []); | |||||
| useEffect(() => { | |||||
| // Update the refs whenever the state changes | |||||
| messageRef.current = message; | |||||
| }, [message]); | |||||
| const initGraph = () => { | |||||
| G6.registerNode( | |||||
| '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', | |||||
| }, | }, | ||||
| }, | |||||
| 'rect' | |||||
| ); | |||||
| console.log(graphRef,'graphRef'); | |||||
| graph = new G6.Graph({ | |||||
| container: graphRef.current, | |||||
| grid: true, | |||||
| width: graphRef.current.clientWidth ||500, | |||||
| height: graphRef.current.clientHeight||760, | |||||
| animate: false, | |||||
| groupByTypes: false, | |||||
| enabledStack: true, | |||||
| modes: { | |||||
| 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; | |||||
| 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: 3, | |||||
| x: bbox.x + bbox.width * anchorPos[0], | |||||
| y: bbox.y + bbox.height * anchorPos[1], | |||||
| fill: '#fff', | |||||
| stroke: '#a4a4a5', | |||||
| }, | }, | ||||
| // 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', | |||||
| 'zoom-canvas', | |||||
| // 'brush-select', | |||||
| 'drag-combo', | |||||
| ], | |||||
| altSelect: [ | |||||
| { | |||||
| type: 'brush-select', | |||||
| trigger: 'drag', | |||||
| }, | |||||
| 'drag-node', | |||||
| ], | |||||
| 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; | |||||
| }, | }, | ||||
| defaultNode: { | |||||
| type: 'rect-node', | |||||
| size: [110,36], | |||||
| labelCfg: { | |||||
| style: { | |||||
| fill: '#000', | |||||
| fontSize: 10, | |||||
| cursor: 'pointer', | |||||
| x: -20, | |||||
| y: 0, | |||||
| textAlign: 'left', | |||||
| textBaseline: 'middle', | |||||
| // 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'); | |||||
| anchorPoints.forEach((point) => { | |||||
| if (value || point.get('links') > 0) point.show(); | |||||
| else point.hide(); | |||||
| }); | |||||
| // } | |||||
| }, | |||||
| }, | |||||
| 'rect', | |||||
| ); | |||||
| console.log(graphRef, 'graphRef'); | |||||
| graph = new G6.Graph({ | |||||
| container: graphRef.current, | |||||
| grid: true, | |||||
| width: graphRef.current.clientWidth || 500, | |||||
| height: graphRef.current.clientHeight || 760, | |||||
| animate: false, | |||||
| groupByTypes: false, | |||||
| enabledStack: true, | |||||
| modes: { | |||||
| 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', | |||||
| 'zoom-canvas', | |||||
| // 'brush-select', | |||||
| 'drag-combo', | |||||
| ], | |||||
| altSelect: [ | |||||
| { | |||||
| type: 'brush-select', | |||||
| trigger: 'drag', | |||||
| }, | }, | ||||
| 'drag-node', | |||||
| ], | |||||
| }, | |||||
| defaultNode: { | |||||
| type: 'rect-node', | |||||
| size: [110, 36], | |||||
| labelCfg: { | |||||
| style: { | style: { | ||||
| fill: '#fff', | |||||
| stroke: '#fff', | |||||
| radius:10, | |||||
| lineWidth:0.5 | |||||
| fill: '#000', | |||||
| fontSize: 10, | |||||
| cursor: 'pointer', | |||||
| x: -20, | |||||
| y: 0, | |||||
| textAlign: 'left', | |||||
| textBaseline: 'middle', | |||||
| }, | }, | ||||
| }, | }, | ||||
| nodeStateStyles: { | |||||
| nodeSelected: { | |||||
| style: { | |||||
| fill: '#fff', | |||||
| stroke: '#fff', | |||||
| radius: 10, | |||||
| lineWidth: 0.5, | |||||
| }, | |||||
| }, | |||||
| nodeStateStyles: { | |||||
| nodeSelected: { | |||||
| fill: 'red', | |||||
| shadowColor: 'red', | |||||
| stroke: 'red', | |||||
| 'text-shape': { | |||||
| fill: 'red', | fill: 'red', | ||||
| shadowColor: 'red', | |||||
| stroke: 'red', | stroke: 'red', | ||||
| 'text-shape': { | |||||
| fill: 'red', | |||||
| stroke: 'red', | |||||
| }, | |||||
| }, | }, | ||||
| }, | }, | ||||
| defaultEdge: { | |||||
| // type: 'quadratic', | |||||
| type: 'cubic-vertical', | |||||
| }, | |||||
| defaultEdge: { | |||||
| // type: 'quadratic', | |||||
| type: 'cubic-vertical', | |||||
| style: { | |||||
| endArrow: { // 设置终点箭头 | |||||
| path: G6.Arrow.triangle(3, 3, 3), // 使用内置箭头路径函数,参数为箭头的 宽度、长度、偏移量(默认为 0,与 d 对应) | |||||
| d: 4.5, | |||||
| fill:'#a2a6b5' | |||||
| }, | |||||
| cursor: 'pointer', | |||||
| lineWidth: 1, | |||||
| opacity: 1, | |||||
| stroke: '#a2a6b5', | |||||
| radius: 1, | |||||
| }, | |||||
| nodeStateStyle: { | |||||
| hover: { | |||||
| opacity: 1, | |||||
| stroke: '#8fe8ff', | |||||
| }, | |||||
| style: { | |||||
| endArrow: { | |||||
| // 设置终点箭头 | |||||
| path: G6.Arrow.triangle(3, 3, 3), // 使用内置箭头路径函数,参数为箭头的 宽度、长度、偏移量(默认为 0,与 d 对应) | |||||
| d: 4.5, | |||||
| fill: '#a2a6b5', | |||||
| }, | }, | ||||
| labelCfg: { | |||||
| autoRotate: true, | |||||
| // refY: 10, | |||||
| style: { | |||||
| fontSize: 10, | |||||
| fill: '#FFF', | |||||
| }, | |||||
| cursor: 'pointer', | |||||
| lineWidth: 1, | |||||
| opacity: 1, | |||||
| stroke: '#a2a6b5', | |||||
| radius: 1, | |||||
| }, | |||||
| nodeStateStyle: { | |||||
| hover: { | |||||
| opacity: 1, | |||||
| stroke: '#8fe8ff', | |||||
| }, | }, | ||||
| }, | }, | ||||
| defaultCombo: { | |||||
| type: 'rect', | |||||
| fixCollapseSize: 70, | |||||
| labelCfg: { | |||||
| autoRotate: true, | |||||
| // refY: 10, | |||||
| style: { | style: { | ||||
| fill: '#00e0ff0d', | |||||
| stroke: '#00e0ff', | |||||
| lineDash: [5, 10], | |||||
| cursor: 'pointer', | |||||
| fontSize: 10, | |||||
| fill: '#FFF', | |||||
| }, | }, | ||||
| }, | }, | ||||
| // linkCenter: true, | |||||
| fitView: false, | |||||
| fitViewPadding: [60, 60, 60, 80], | |||||
| }); | |||||
| graph.on('dblclick', handlerClick); | |||||
| window.onresize = () => { | |||||
| if (!graph || graph.get('destroyed')) return; | |||||
| if (!graphRef.current || !graphRef.current.scrollWidth || !graphRef.current.scrollHeight) return; | |||||
| graph.changeSize(graphRef.current.scrollWidth, graphRef.current.scrollHeight - 20); | |||||
| }; | |||||
| } | |||||
| return (<div className={pipelineContainer}> | |||||
| <div className={Styles.centerContainer}> | |||||
| }, | |||||
| defaultCombo: { | |||||
| type: 'rect', | |||||
| fixCollapseSize: 70, | |||||
| style: { | |||||
| fill: '#00e0ff0d', | |||||
| stroke: '#00e0ff', | |||||
| lineDash: [5, 10], | |||||
| cursor: 'pointer', | |||||
| }, | |||||
| }, | |||||
| // linkCenter: true, | |||||
| fitView: false, | |||||
| fitViewPadding: [60, 60, 60, 80], | |||||
| }); | |||||
| graph.on('dblclick', handlerClick); | |||||
| window.onresize = () => { | |||||
| if (!graph || graph.get('destroyed')) return; | |||||
| if (!graphRef.current || !graphRef.current.scrollWidth || !graphRef.current.scrollHeight) | |||||
| return; | |||||
| graph.changeSize(graphRef.current.scrollWidth, graphRef.current.scrollHeight - 20); | |||||
| }; | |||||
| }; | |||||
| return ( | |||||
| <div className={pipelineContainer}> | |||||
| <div className={Styles.centerContainer}> | |||||
| <div className={Styles.buttonList}> | <div className={Styles.buttonList}> | ||||
| <div className={Styles.allMessageItem}>启动时间:{momnet(experimentAllMessage.create_time).format('YYYY-MM-DD HH:mm:ss')}</div> | |||||
| <div className={Styles.allMessageItem}>执行时长:{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())}</div> | |||||
| <div className={Styles.allMessageItem}>状态: | |||||
| <div style={{width:'8px', | |||||
| height:'8px', | |||||
| borderRadius:'50%', | |||||
| marginRight:'6px', | |||||
| backgroundColor:statusColorObj[experimentAllMessage.status] | |||||
| }}></div> | |||||
| <span style={{color:statusColorObj[experimentAllMessage.status]}}>{statusObj[experimentAllMessage.status]}</span></div> | |||||
| <div className={Styles.allMessageItem}> | |||||
| 启动时间:{momnet(message.create_time).format('YYYY-MM-DD HH:mm:ss')} | |||||
| </div> | |||||
| <div className={Styles.allMessageItem}> | |||||
| 执行时长: | |||||
| {message.finish_time | |||||
| ? elapsedTime(new Date(message.create_time), new Date(message.finish_time)) | |||||
| : elapsedTime(new Date(message.create_time), new Date())} | |||||
| </div> | |||||
| <div className={Styles.allMessageItem}> | |||||
| 状态: | |||||
| <div | |||||
| style={{ | |||||
| width: '8px', | |||||
| height: '8px', | |||||
| borderRadius: '50%', | |||||
| marginRight: '6px', | |||||
| backgroundColor: experimentStatusInfo[message.status]?.color, | |||||
| }} | |||||
| ></div> | |||||
| <span style={{ color: experimentStatusInfo[message.status]?.color }}> | |||||
| {experimentStatusInfo[message.status]?.label} | |||||
| </span> | |||||
| </div> | |||||
| </div> | </div> | ||||
| <div className={graphStyle} ref={graphRef} id={Styles.graphStyle}></div> | <div className={graphStyle} ref={graphRef} id={Styles.graphStyle}></div> | ||||
| </div> | |||||
| <Props ref={propsRef} onParentChange={formChange}></Props> | |||||
| </div>)}; | |||||
| export default ExperimentText; | |||||
| </div> | |||||
| <Props ref={propsRef} onParentChange={formChange}></Props> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ExperimentText; | |||||
| @@ -0,0 +1,34 @@ | |||||
| .log_group { | |||||
| padding-bottom: 10px; | |||||
| } | |||||
| .log_group_pod { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: space-between; | |||||
| padding: 15px; | |||||
| background: rgba(234, 234, 234, 0.5); | |||||
| cursor: pointer; | |||||
| &_name { | |||||
| margin-right: 10px; | |||||
| color: #1d1d20; | |||||
| font-size: 14px; | |||||
| } | |||||
| } | |||||
| .log_group_detail { | |||||
| padding: 15px; | |||||
| color: white; | |||||
| font-size: 14px; | |||||
| white-space: pre-line; | |||||
| word-break: break-all; | |||||
| background: #19253b; | |||||
| } | |||||
| .log_group_more_button { | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| color: white; | |||||
| background: #19253b; | |||||
| } | |||||
| @@ -0,0 +1,127 @@ | |||||
| import { useStateRef } from '@/hooks'; | |||||
| import { getExperimentPodsLog } from '@/services/experiment/index.js'; | |||||
| import { DoubleRightOutlined, DownOutlined, UpOutlined } from '@ant-design/icons'; | |||||
| import { Button } from 'antd'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| import styles from './logGroup.less'; | |||||
| type LogGroupProps = { | |||||
| log_type?: string; | |||||
| pod_name?: string; | |||||
| log_content?: string; | |||||
| start_time?: string; | |||||
| status: string; | |||||
| }; | |||||
| type Log = { | |||||
| start_time: string; | |||||
| log_content: string; | |||||
| }; | |||||
| function LogGroup({ | |||||
| log_type = '', | |||||
| pod_name = '', | |||||
| log_content = '', | |||||
| start_time = '', | |||||
| status = '', | |||||
| }: LogGroupProps) { | |||||
| const [collapse, setCollapse] = useState(true); | |||||
| const [logList, setLogList, logListRef] = useStateRef<Log[]>([]); | |||||
| const [completed, setCompleted] = useState(false); | |||||
| useEffect(() => { | |||||
| if (status === 'Running') { | |||||
| const timerId = setInterval(() => { | |||||
| requestExperimentPodsLog(); | |||||
| }, 5000); | |||||
| return () => { | |||||
| clearInterval(timerId); | |||||
| }; | |||||
| } | |||||
| }, []); | |||||
| // 请求日志 | |||||
| const requestExperimentPodsLog = async () => { | |||||
| const list = logListRef.current; | |||||
| const startTime = list.length > 0 ? list[list.length - 1].start_time : start_time; | |||||
| const params = { | |||||
| pod_name, | |||||
| start_time: startTime, | |||||
| }; | |||||
| const res = await getExperimentPodsLog(params); | |||||
| const { log_detail } = res.data; | |||||
| if (log_detail && log_detail.log_content) { | |||||
| setLogList((oldList) => oldList.concat(log_detail)); | |||||
| } else { | |||||
| setCompleted(true); | |||||
| } | |||||
| }; | |||||
| // 请求实时日志 | |||||
| // const requestExperimentPodsRealtimeLog = async () => { | |||||
| // const params = { | |||||
| // pod_name, | |||||
| // namespace: namespace, | |||||
| // container_name: log_type === 'resource' ? '' : 'main', | |||||
| // }; | |||||
| // const res = await getExperimentPodsRealtimeLog(params); | |||||
| // const { log_detail } = res.data; | |||||
| // if (log_detail && log_detail.log_content) { | |||||
| // setLogList((list) => list.concat(log_detail)); | |||||
| // } else { | |||||
| // setCompleted(true); | |||||
| // } | |||||
| // }; | |||||
| // 处理折叠 | |||||
| const handleCollapse = async () => { | |||||
| if (!collapse) { | |||||
| setCollapse(true); | |||||
| return; | |||||
| } | |||||
| if (logList.length === 0) { | |||||
| try { | |||||
| await requestExperimentPodsLog(); | |||||
| setCollapse(false); | |||||
| } catch (error) { | |||||
| return Promise.reject(error); | |||||
| } | |||||
| } else { | |||||
| setCollapse(false); | |||||
| } | |||||
| }; | |||||
| // 加载更多 | |||||
| const loadMore = () => { | |||||
| requestExperimentPodsLog(); | |||||
| }; | |||||
| const showLog = (log_type === 'resource' && !collapse) || log_type === 'normal'; | |||||
| const logText = log_content + logList.map((v) => v.log_content).join(''); | |||||
| const showMoreBtn = status !== 'Running' && showLog && !completed && logText !== ''; | |||||
| return ( | |||||
| <div className={styles.log_group}> | |||||
| {log_type === 'resource' && ( | |||||
| <div className={styles.log_group_pod} onClick={handleCollapse}> | |||||
| <div className={styles.log_group_pod_name}>{pod_name}</div> | |||||
| {collapse ? <DownOutlined /> : <UpOutlined />} | |||||
| </div> | |||||
| )} | |||||
| {showLog && <div className={styles.log_group_detail}>{logText}</div>} | |||||
| <div className={styles.log_group_more_button}> | |||||
| {showMoreBtn && ( | |||||
| <Button | |||||
| type="text" | |||||
| style={{ color: 'white' }} | |||||
| icon={<DoubleRightOutlined rotate={90} />} | |||||
| onClick={loadMore} | |||||
| > | |||||
| 更多 | |||||
| </Button> | |||||
| )} | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default LogGroup; | |||||
| @@ -1,336 +1,424 @@ | |||||
| import React, { useState,useImperativeHandle ,forwardRef } from 'react'; | |||||
| import { Button, Drawer,Form, Input ,Tabs,message } from 'antd'; | |||||
| import Styles from './editPipeline.less' | |||||
| import{getQueryByExperimentLog,getNodeResult}from '@/services/experiment/index.js' | |||||
| import { ProfileOutlined, DatabaseOutlined} from '@ant-design/icons'; | |||||
| import {downLoadZip} from '@/utils/downloadfile' | |||||
| import momnet from 'moment' | |||||
| import { getNodeResult, getQueryByExperimentLog } from '@/services/experiment/index.js'; | |||||
| import { elapsedTime } from '@/utils/date'; | |||||
| import { downLoadZip } from '@/utils/downloadfile'; | |||||
| import { DatabaseOutlined, ProfileOutlined } from '@ant-design/icons'; | |||||
| import { Drawer, Form, Input, Tabs, message } from 'antd'; | |||||
| import moment from 'moment'; | |||||
| import { forwardRef, useImperativeHandle, useState } from 'react'; | |||||
| import LogList from './LogList'; | |||||
| import Styles from './editPipeline.less'; | |||||
| const { TextArea } = Input; | const { TextArea } = Input; | ||||
| const Props = forwardRef(({onParentChange}, ref) =>{ | |||||
| const [form] = Form.useForm(); | |||||
| const [stagingItem,setStagingItem]=useState({}) | |||||
| const [resultObj,setResultObj]=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 exportResult=(e,val)=>{ | |||||
| const Props = forwardRef(({ onParentChange }, ref) => { | |||||
| const [form] = Form.useForm(); | |||||
| const [stagingItem, setStagingItem] = useState({}); | |||||
| const [resultObj, setResultObj] = useState([]); | |||||
| const [logList, setLogList] = 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 exportResult = (e, val) => { | |||||
| const hide = message.loading('正在下载'); | const hide = message.loading('正在下载'); | ||||
| hide(); | hide(); | ||||
| downLoadZip(`/api/mmp/minioStorage/download`,{path:val}) | |||||
| } | |||||
| 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: <div style={{height:'740px', | |||||
| background:'#19253b', | |||||
| color:'#fff', | |||||
| fontSize:'14px' | |||||
| }} dangerouslySetInnerHTML={{ __html: messageItem }}></div>, | |||||
| icon:<ProfileOutlined/> | |||||
| }, | |||||
| { | |||||
| key: '2', | |||||
| label: '配置参数', | |||||
| icon:<DatabaseOutlined />, | |||||
| children: <Form | |||||
| name="form" | |||||
| form={form} | |||||
| layout="vertical" | |||||
| labelCol={{ | |||||
| span: 16, | |||||
| }} | |||||
| wrapperCol={{ | |||||
| span: 16, | |||||
| }} | |||||
| style={{ | |||||
| maxWidth: 600, | |||||
| }} | |||||
| initialValues={{ | |||||
| remember: true, | |||||
| }} | |||||
| onFinish={onFinish} | |||||
| onFinishFailed={onFinishFailed} | |||||
| autoComplete="off" | |||||
| > | |||||
| <div className={Styles.editPipelinePropsContent}> | |||||
| <img style={{width:'13px',marginRight:'10px'}} src={'/assets/images/static-message.png'} alt="" /> | |||||
| 基本信息 | |||||
| </div> | |||||
| <Form.Item | |||||
| label="任务名称" | |||||
| name="label" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入任务名称', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input disabled /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="任务ID" | |||||
| name="id" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入任务id', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input disabled/> | |||||
| </Form.Item> | |||||
| <div className={Styles.editPipelinePropsContent}> | |||||
| <img style={{width:'13px',marginRight:'10px'}} src={'/assets/images/duty-message.png'} alt="" /> | |||||
| 任务信息 | |||||
| </div> | |||||
| <Form.Item | |||||
| label="镜像" | |||||
| name="image" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入镜像', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input disabled/> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="工作目录" | |||||
| name="working_directory" | |||||
| > | |||||
| <Input disabled/> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="启动命令" | |||||
| name="command" | |||||
| > | |||||
| <Input disabled/> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="资源规格" | |||||
| name="resources_standard" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入资源规格', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input disabled/> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="挂载路径" | |||||
| name="mount_path" | |||||
| > | |||||
| <Input disabled/> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="环境变量" | |||||
| name="env_variables" | |||||
| downLoadZip(`/api/mmp/minioStorage/download`, { path: val }); | |||||
| }; | |||||
| 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: <LogList list={logList} status={stagingItem.experimentStatus}></LogList>, | |||||
| icon: <ProfileOutlined />, | |||||
| }, | |||||
| { | |||||
| key: '2', | |||||
| label: '配置参数', | |||||
| icon: <DatabaseOutlined />, | |||||
| children: ( | |||||
| <Form | |||||
| name="form" | |||||
| form={form} | |||||
| layout="vertical" | |||||
| labelCol={{ | |||||
| span: 16, | |||||
| }} | |||||
| wrapperCol={{ | |||||
| span: 16, | |||||
| }} | |||||
| style={{ | |||||
| maxWidth: 600, | |||||
| }} | |||||
| initialValues={{ | |||||
| remember: true, | |||||
| }} | |||||
| onFinish={onFinish} | |||||
| onFinishFailed={onFinishFailed} | |||||
| autoComplete="off" | |||||
| > | > | ||||
| <TextArea disabled/> | |||||
| </Form.Item> | |||||
| {stagingItem.control_strategy&&Object.keys(stagingItem.control_strategy)&&Object.keys(stagingItem.control_strategy).length>0?Object.keys(stagingItem.control_strategy).map(item=> | |||||
| <div className={Styles.editPipelinePropsContent}> | |||||
| <img | |||||
| style={{ width: '13px', marginRight: '10px' }} | |||||
| src={'/assets/images/static-message.png'} | |||||
| alt="" | |||||
| /> | |||||
| 基本信息 | |||||
| </div> | |||||
| <Form.Item | <Form.Item | ||||
| label={stagingItem.control_strategy[item].label} | |||||
| disabled | |||||
| name={item} | |||||
| > | |||||
| <Input disabled/> | |||||
| </Form.Item> | |||||
| ):''} | |||||
| <div className={Styles.editPipelinePropsContent}> | |||||
| <img style={{width:'13px',marginRight:'10px'}} src={'/assets/images/duty-message.png'} alt="" /> | |||||
| 输入参数 | |||||
| </div> | |||||
| {stagingItem.in_parameters&&Object.keys(stagingItem.in_parameters)&&Object.keys(stagingItem.in_parameters).length>0?Object.keys(stagingItem.in_parameters).map(item=> | |||||
| label="任务名称" | |||||
| name="label" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入任务名称', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input disabled /> | |||||
| </Form.Item> | |||||
| <Form.Item | <Form.Item | ||||
| label={stagingItem.in_parameters[item].label+'('+item+')'} | |||||
| name={item} | |||||
| disabled | |||||
| rules={[{ required: stagingItem.in_parameters[item].require?true:false}]} | |||||
| > | |||||
| <Input disabled/> | |||||
| </Form.Item> | |||||
| ):''} | |||||
| <div className={Styles.editPipelinePropsContent}> | |||||
| <img style={{width:'13px',marginRight:'10px'}} src={'/assets/images/duty-message.png'} alt="" /> | |||||
| 输出参数 | |||||
| </div> | |||||
| {stagingItem.out_parameters&&Object.keys(stagingItem.out_parameters)&&Object.keys(stagingItem.out_parameters).length>0?Object.keys(stagingItem.out_parameters).map(item=> | |||||
| label="任务ID" | |||||
| name="id" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入任务id', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input disabled /> | |||||
| </Form.Item> | |||||
| <div className={Styles.editPipelinePropsContent}> | |||||
| <img | |||||
| style={{ width: '13px', marginRight: '10px' }} | |||||
| src={'/assets/images/duty-message.png'} | |||||
| alt="" | |||||
| /> | |||||
| 任务信息 | |||||
| </div> | |||||
| <Form.Item | <Form.Item | ||||
| label={stagingItem.out_parameters[item].label+'('+item+')'} | |||||
| disabled | |||||
| rules={[{ required: stagingItem.out_parameters[item].require?true:false}]} | |||||
| name={item} | |||||
| > | |||||
| <Input disabled/> | |||||
| </Form.Item> | |||||
| ):''} | |||||
| </Form>, | |||||
| }, | |||||
| { | |||||
| key: '3', | |||||
| label: '输出结果', | |||||
| children: <div style={{minHeight:'740px', | |||||
| background:'#f4f4f4', | |||||
| color:'#000', | |||||
| fontSize:'14px', | |||||
| padding:'0 10px 20px 20px', | |||||
| }} > | |||||
| {resultObj&&resultObj.length>0?resultObj.map(item=><div> | |||||
| <div className={Styles.resultTop}> | |||||
| <span>{item.name}</span> | |||||
| <div style={{display:'flex'}}> | |||||
| <a onClick={(e)=>{exportResult(e,item.path)}} style={{marginRight:'10px'}}>下载</a> | |||||
| <a style={{marginRight:'10px'}}>导出到模型库</a> | |||||
| <a style={{marginRight:'10px'}}>导出到数据集</a> | |||||
| </div> | |||||
| label="镜像" | |||||
| name="image" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入镜像', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input disabled /> | |||||
| </Form.Item> | |||||
| <Form.Item label="工作目录" name="working_directory"> | |||||
| <Input disabled /> | |||||
| </Form.Item> | |||||
| <Form.Item label="启动命令" name="command"> | |||||
| <Input disabled /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="资源规格" | |||||
| name="resources_standard" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入资源规格', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input disabled /> | |||||
| </Form.Item> | |||||
| <Form.Item label="挂载路径" name="mount_path"> | |||||
| <Input disabled /> | |||||
| </Form.Item> | |||||
| <Form.Item label="环境变量" name="env_variables"> | |||||
| <TextArea disabled /> | |||||
| </Form.Item> | |||||
| {stagingItem.control_strategy && | |||||
| Object.keys(stagingItem.control_strategy) && | |||||
| Object.keys(stagingItem.control_strategy).length > 0 | |||||
| ? Object.keys(stagingItem.control_strategy).map((item) => ( | |||||
| <Form.Item label={stagingItem.control_strategy[item].label} disabled name={item}> | |||||
| <Input disabled /> | |||||
| </Form.Item> | |||||
| )) | |||||
| : ''} | |||||
| <div className={Styles.editPipelinePropsContent}> | |||||
| <img | |||||
| style={{ width: '13px', marginRight: '10px' }} | |||||
| src={'/assets/images/duty-message.png'} | |||||
| alt="" | |||||
| /> | |||||
| 输入参数 | |||||
| </div> | </div> | ||||
| <div style={{margin:'15px 0'}} className={Styles.resultContent}> | |||||
| <span>文件名称</span> | |||||
| <span>文件大小</span> | |||||
| {stagingItem.in_parameters && | |||||
| Object.keys(stagingItem.in_parameters) && | |||||
| Object.keys(stagingItem.in_parameters).length > 0 | |||||
| ? Object.keys(stagingItem.in_parameters).map((item) => ( | |||||
| <Form.Item | |||||
| label={stagingItem.in_parameters[item].label + '(' + item + ')'} | |||||
| name={item} | |||||
| disabled | |||||
| rules={[{ required: stagingItem.in_parameters[item].require ? true : false }]} | |||||
| > | |||||
| <Input disabled /> | |||||
| </Form.Item> | |||||
| )) | |||||
| : ''} | |||||
| <div className={Styles.editPipelinePropsContent}> | |||||
| <img | |||||
| style={{ width: '13px', marginRight: '10px' }} | |||||
| src={'/assets/images/duty-message.png'} | |||||
| alt="" | |||||
| /> | |||||
| 输出参数 | |||||
| </div> | </div> | ||||
| {item.value&&item.value.length>0?item.value.map(ele=> | |||||
| <div className={Styles.resultContent}> | |||||
| <span>{ele.name}</span> | |||||
| <span>{ele.size}</span> | |||||
| </div>):null} | |||||
| </div>):null} | |||||
| </div>, | |||||
| icon:<ProfileOutlined/> | |||||
| }, | |||||
| ]; | |||||
| const [open, setOpen] = useState(false); | |||||
| const afterOpenChange=()=>{ | |||||
| if(!open){ | |||||
| console.log(111,open); | |||||
| console.log(stagingItem,form.getFieldsValue()); | |||||
| for(let i in form.getFieldsValue()){ | |||||
| for(let j in stagingItem.in_parameters){ | |||||
| if(i==j){ | |||||
| console.log(j,i); | |||||
| stagingItem.in_parameters[j].value=form.getFieldsValue()[i] | |||||
| } | |||||
| {stagingItem.out_parameters && | |||||
| Object.keys(stagingItem.out_parameters) && | |||||
| Object.keys(stagingItem.out_parameters).length > 0 | |||||
| ? Object.keys(stagingItem.out_parameters).map((item) => ( | |||||
| <Form.Item | |||||
| label={stagingItem.out_parameters[item].label + '(' + item + ')'} | |||||
| disabled | |||||
| rules={[{ required: stagingItem.out_parameters[item].require ? true : false }]} | |||||
| name={item} | |||||
| > | |||||
| <Input disabled /> | |||||
| </Form.Item> | |||||
| )) | |||||
| : ''} | |||||
| </Form> | |||||
| ), | |||||
| }, | |||||
| { | |||||
| key: '3', | |||||
| label: '输出结果', | |||||
| children: ( | |||||
| <div | |||||
| style={{ | |||||
| minHeight: '740px', | |||||
| background: '#f4f4f4', | |||||
| color: '#000', | |||||
| fontSize: '14px', | |||||
| padding: '0 10px 20px 20px', | |||||
| }} | |||||
| > | |||||
| {resultObj && resultObj.length > 0 | |||||
| ? resultObj.map((item) => ( | |||||
| <div> | |||||
| <div className={Styles.resultTop}> | |||||
| <span>{item.name}</span> | |||||
| <div style={{ display: 'flex' }}> | |||||
| <a | |||||
| onClick={(e) => { | |||||
| exportResult(e, item.path); | |||||
| }} | |||||
| style={{ marginRight: '10px' }} | |||||
| > | |||||
| 下载 | |||||
| </a> | |||||
| <a style={{ marginRight: '10px' }}>导出到模型库</a> | |||||
| <a style={{ marginRight: '10px' }}>导出到数据集</a> | |||||
| </div> | |||||
| </div> | |||||
| <div style={{ margin: '15px 0' }} className={Styles.resultContent}> | |||||
| <span>文件名称</span> | |||||
| <span>文件大小</span> | |||||
| </div> | |||||
| {item.value && item.value.length > 0 | |||||
| ? item.value.map((ele) => ( | |||||
| <div className={Styles.resultContent}> | |||||
| <span>{ele.name}</span> | |||||
| <span>{ele.size}</span> | |||||
| </div> | |||||
| )) | |||||
| : null} | |||||
| </div> | |||||
| )) | |||||
| : null} | |||||
| </div> | |||||
| ), | |||||
| icon: <ProfileOutlined />, | |||||
| }, | |||||
| ]; | |||||
| const [open, setOpen] = useState(false); | |||||
| const afterOpenChange = () => { | |||||
| if (!open) { | |||||
| console.log(111, open); | |||||
| console.log(stagingItem, form.getFieldsValue()); | |||||
| for (let i in form.getFieldsValue()) { | |||||
| for (let j in stagingItem.in_parameters) { | |||||
| if (i == j) { | |||||
| console.log(j, i); | |||||
| stagingItem.in_parameters[j].value = form.getFieldsValue()[i]; | |||||
| } | } | ||||
| for(let p in stagingItem.out_parameters){ | |||||
| if(i==p){ | |||||
| stagingItem.out_parameters[p].value=form.getFieldsValue()[i] | |||||
| } | |||||
| } | |||||
| for (let p in stagingItem.out_parameters) { | |||||
| if (i == p) { | |||||
| stagingItem.out_parameters[p].value = form.getFieldsValue()[i]; | |||||
| } | } | ||||
| for(let k in stagingItem.control_strategy){ | |||||
| if(i==k){ | |||||
| stagingItem.control_strategy[k].value=form.getFieldsValue()[i] | |||||
| } | |||||
| } | |||||
| for (let k in stagingItem.control_strategy) { | |||||
| if (i == k) { | |||||
| stagingItem.control_strategy[k].value = form.getFieldsValue()[i]; | |||||
| } | } | ||||
| } | } | ||||
| // setStagingItem({...stagingItem,}) | |||||
| console.log((stagingItem.control_strategy)); | |||||
| onParentChange({...stagingItem,control_strategy:JSON.stringify(stagingItem.control_strategy),in_parameters:JSON.stringify(stagingItem.in_parameters),out_parameters:JSON.stringify(stagingItem.out_parameters),...form.getFieldsValue()}) | |||||
| // onParentChange({...stagingItem,...form.getFieldsValue()}) | |||||
| } | } | ||||
| // setStagingItem({...stagingItem,}) | |||||
| console.log(stagingItem.control_strategy); | |||||
| onParentChange({ | |||||
| ...stagingItem, | |||||
| control_strategy: JSON.stringify(stagingItem.control_strategy), | |||||
| in_parameters: JSON.stringify(stagingItem.in_parameters), | |||||
| out_parameters: JSON.stringify(stagingItem.out_parameters), | |||||
| ...form.getFieldsValue(), | |||||
| }); | |||||
| // onParentChange({...stagingItem,...form.getFieldsValue()}) | |||||
| } | } | ||||
| const onClose=()=> { | |||||
| setOpen(false); | |||||
| }; | |||||
| const onFinish = (values) => { | |||||
| console.log('Success:', values); | |||||
| }; | |||||
| const onFinishFailed = (errorInfo) => { | |||||
| console.log('Failed:', errorInfo); | |||||
| }; | |||||
| useImperativeHandle(ref, () => ({ | |||||
| showDrawer (e,id) { | |||||
| setMessageItem('') | |||||
| if(e.item&&e.item.getModel().component_id){ | |||||
| let params={ | |||||
| id:Number(id), | |||||
| component_id:e.item&&e.item.getModel().component_id | |||||
| } | |||||
| getQueryByExperimentLog(params).then(ret=>{ | |||||
| console.log(ret); | |||||
| getNodeResult({id,node_id:e.item.getModel().id}).then(res=>{ | |||||
| setResultObj(res.data) | |||||
| let msg=ret.msg.replace(/\n/g,"</br>") | |||||
| let newMsg=msg.replace(/\r/g,"</br>") | |||||
| setMessageItem(newMsg) | |||||
| 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)}) | |||||
| setOpen(true); | |||||
| }) | |||||
| }) | |||||
| }; | |||||
| const onClose = () => { | |||||
| setOpen(false); | |||||
| }; | |||||
| const onFinish = (values) => { | |||||
| console.log('Success:', values); | |||||
| }; | |||||
| const onFinishFailed = (errorInfo) => { | |||||
| console.log('Failed:', errorInfo); | |||||
| }; | |||||
| useImperativeHandle(ref, () => ({ | |||||
| showDrawer(e, id, message) { | |||||
| setLogList([]); | |||||
| if (e.item && e.item.getModel().component_id) { | |||||
| const model = e.item.getModel() || {}; | |||||
| const start_time = moment(model.experimentStartTime).valueOf() * 1.0e6; | |||||
| const params = { | |||||
| task_id: model.id, | |||||
| component_id: model.component_id, | |||||
| name: message.argo_ins_name, | |||||
| namespace: message.argo_ins_ns, | |||||
| start_time: start_time, | |||||
| }; | |||||
| getQueryByExperimentLog(params).then((ret) => { | |||||
| const { log_type, pods, log_detail } = ret.data; | |||||
| if (log_type === 'normal') { | |||||
| const list = [ | |||||
| { | |||||
| ...log_detail, | |||||
| log_type, | |||||
| }, | |||||
| ]; | |||||
| setLogList(list); | |||||
| } else if (log_type === 'resource') { | |||||
| const list = pods.map((v) => ({ | |||||
| log_type, | |||||
| pod_name: v, | |||||
| log_content: '', | |||||
| start_time, | |||||
| })); | |||||
| setLogList(list); | |||||
| } | } | ||||
| else{ | |||||
| getNodeResult({ id, node_id: e.item.getModel().id }).then((res) => { | |||||
| setResultObj(res.data); | |||||
| form.resetFields(); | 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), | |||||
| 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), | |||||
| }); | |||||
| setOpen(true); | setOpen(true); | ||||
| } | |||||
| // console.log(e.item.getModel().in_parameters); | |||||
| }, | |||||
| })); | |||||
| }); | |||||
| }); | |||||
| } else { | |||||
| 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), | |||||
| }); | |||||
| setOpen(true); | |||||
| } | |||||
| // console.log(e.item.getModel().in_parameters); | |||||
| }, | |||||
| })); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <Drawer title="任务执行详情" placement="right" closeIcon={false} onClose={onClose} afterOpenChange={afterOpenChange} open={open}> | |||||
| <div className={Styles.detailBox}>任务名称:{stagingItem.label}</div> | |||||
| <div className={Styles.detailBox} >执行状态: | |||||
| <div style={{width:'8px', | |||||
| height:'8px', | |||||
| borderRadius:'50%', | |||||
| marginRight:'6px', | |||||
| backgroundColor:statusColorObj[stagingItem.experimentStatus] | |||||
| }}></div> | |||||
| <span style={{color:statusColorObj[stagingItem.experimentStatus]}}>{statusObj[stagingItem.experimentStatus]}</span></div> | |||||
| <div className={Styles.detailBox}>启动时间:{momnet(stagingItem.experimentStartTime).format('YYYY-MM-DD HH:mm:ss')}</div> | |||||
| <div className={Styles.detailBox}>耗时:{stagingItem.experimentEndTime?timers(new Date(stagingItem.experimentEndTime).getTime()-new Date(stagingItem.experimentStartTime).getTime()):timers(new Date().getTime()-new Date(stagingItem.experimentStartTime).getTime())}</div> | |||||
| <Tabs | |||||
| defaultActiveKey="1" | |||||
| items={items}/> | |||||
| <Drawer | |||||
| title="任务执行详情" | |||||
| placement="right" | |||||
| closeIcon={false} | |||||
| onClose={onClose} | |||||
| afterOpenChange={afterOpenChange} | |||||
| open={open} | |||||
| width={600} | |||||
| destroyOnClose={true} | |||||
| > | |||||
| <div className={Styles.detailBox}>任务名称:{stagingItem.label}</div> | |||||
| <div className={Styles.detailBox}> | |||||
| 执行状态: | |||||
| <div | |||||
| style={{ | |||||
| width: '8px', | |||||
| height: '8px', | |||||
| borderRadius: '50%', | |||||
| marginRight: '6px', | |||||
| backgroundColor: statusColorObj[stagingItem.experimentStatus], | |||||
| }} | |||||
| ></div> | |||||
| <span style={{ color: statusColorObj[stagingItem.experimentStatus] }}> | |||||
| {statusObj[stagingItem.experimentStatus]} | |||||
| </span> | |||||
| </div> | |||||
| <div className={Styles.detailBox}> | |||||
| 启动时间:{moment(stagingItem.experimentStartTime).format('YYYY-MM-DD HH:mm:ss')} | |||||
| </div> | |||||
| <div className={Styles.detailBox}> | |||||
| 耗时: | |||||
| {stagingItem.experimentEndTime | |||||
| ? elapsedTime( | |||||
| new Date(stagingItem.experimentStartTime), | |||||
| new Date(stagingItem.experimentEndTime), | |||||
| ) | |||||
| : elapsedTime(new Date(stagingItem.experimentStartTime), new Date())} | |||||
| </div> | |||||
| <Tabs defaultActiveKey="1" items={items} /> | |||||
| </Drawer> | </Drawer> | ||||
| </> | </> | ||||
| ); | ); | ||||
| @@ -1,484 +1,445 @@ | |||||
| import React ,{ useState,useEffect,useRef }from 'react'; | |||||
| import { Space, Table, Tag,Button,Modal, Form, Input ,message, Select,} from 'antd'; | |||||
| import { PlusOutlined,PlusCircleOutlined, 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' | |||||
| const { TextArea } = Input; | |||||
| import { | |||||
| deleteExperimentById, | |||||
| deleteQueryByExperimentInsId, | |||||
| getExperiment, | |||||
| getExperimentById, | |||||
| getQueryByExperimentId, | |||||
| postExperiment, | |||||
| putExperiment, | |||||
| putQueryByExperimentInsId, | |||||
| runExperiments, | |||||
| } from '@/services/experiment/index.js'; | |||||
| import { getWorkflow } from '@/services/pipeline/index.js'; | |||||
| import { elapsedTime } from '@/utils/date'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { | |||||
| DeleteOutlined, | |||||
| EditOutlined, | |||||
| FieldTimeOutlined, | |||||
| PlayCircleOutlined, | |||||
| PlusCircleOutlined, | |||||
| } from '@ant-design/icons'; | |||||
| import { Button, Modal, Space, Table, message } from 'antd'; | |||||
| import momnet from 'moment'; | |||||
| import { useEffect, useRef, useState } from 'react'; | |||||
| import { useNavigate } from 'react-router-dom'; | |||||
| import AddExperimentModal from './experimentText/addExperimentModal'; | |||||
| import Styles from './index.less'; | |||||
| import { experimentStatusInfo } from './status'; | |||||
| const Experiment = React.FC = () => { | |||||
| const [form] = Form.useForm(); | |||||
| const navgite=useNavigate(); | |||||
| 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 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([]); | |||||
| const [workflowList, setWorkflowList] = useState([]); | |||||
| const [queryFlow,setQueryFlow]=useState({ | |||||
| offset:1, | |||||
| page:0, | |||||
| size:10000, | |||||
| name:null | |||||
| }); | |||||
| const [disableFlag,setDisableFlag]=useState(false) | |||||
| 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 [formId,setFormId]=useState(null) | |||||
| const [experimentInList,setExperimentInList]=useState([]) | |||||
| const [expandedRowKeys,setExpandedRowKeys]=useState(null) | |||||
| const [total, setTotal] = useState(0); | |||||
| const [dialogTitle, setDialogTitle] = useState('新建实验'); | |||||
| const [isModalOpen, setIsModalOpen] = useState(false); | |||||
| const getWorkflowList=()=>{ | |||||
| getWorkflow(queryFlow).then(ret=>{ | |||||
| console.log(ret); | |||||
| if(ret.code==200){ | |||||
| setWorkflowList(ret.data.content) | |||||
| } | |||||
| }) | |||||
| function Experiment() { | |||||
| const navgite = useNavigate(); | |||||
| const [experimentList, setExperimentList] = useState([]); | |||||
| const [workflowList, setWorkflowList] = useState([]); | |||||
| const [queryFlow, setQueryFlow] = useState({ | |||||
| offset: 1, | |||||
| page: 0, | |||||
| size: 10000, | |||||
| name: null, | |||||
| }); | |||||
| const [experimentId, setExperimentId] = useState(null); | |||||
| const [experimentInList, setExperimentInList] = useState([]); | |||||
| const [expandedRowKeys, setExpandedRowKeys] = useState(null); | |||||
| const [total, setTotal] = useState(0); | |||||
| const [isAdd, setIsAdd] = useState(true); | |||||
| const [isModalOpen, setIsModalOpen] = useState(false); | |||||
| const [addFormData, setAddFormData] = useState({}); | |||||
| useEffect(() => { | |||||
| getList(); | |||||
| getWorkflowList(); | |||||
| }, []); | |||||
| // 获取实验列表 | |||||
| const getList = async () => { | |||||
| const params = { | |||||
| offset: 0, | |||||
| page: pageOption.current.page - 1, | |||||
| size: pageOption.current.size, | |||||
| }; | |||||
| const [res, _] = await to(getExperiment(params)); | |||||
| if (res && res.data && Array.isArray(res.data.content)) { | |||||
| setExperimentList( | |||||
| res.data.content.map((item) => { | |||||
| return { ...item, key: item.id }; | |||||
| }), | |||||
| ); | |||||
| setTotal(res.data.totalElements); | |||||
| } | } | ||||
| const getQueryByExperiment=(val)=>{ | |||||
| getQueryByExperimentId(val).then(ret=>{ | |||||
| setExpandedRowKeys(val) | |||||
| if(ret.code==200&&ret.data&&ret.data.length>0){ | |||||
| setExperimentInList(ret.data) | |||||
| getList() | |||||
| } | |||||
| else{ | |||||
| setExperimentInList([]) | |||||
| getList() | |||||
| } | |||||
| }) | |||||
| }; | |||||
| // 获取流水线列表 | |||||
| const getWorkflowList = async () => { | |||||
| const [res, _] = await to(getWorkflow(queryFlow)); | |||||
| if (res && res.data && res.data.content) { | |||||
| setWorkflowList(res.data.content); | |||||
| } | } | ||||
| const expandChange=(e,record)=>{ | |||||
| if(record.id==expandedRowKeys){ | |||||
| setExpandedRowKeys(null) | |||||
| } | |||||
| else{ | |||||
| getQueryByExperiment(record.id) | |||||
| }; | |||||
| const getQueryByExperiment = (val) => { | |||||
| getQueryByExperimentId(val).then((ret) => { | |||||
| setExpandedRowKeys(val); | |||||
| if (ret.code === 200 && ret.data && ret.data.length > 0) { | |||||
| setExperimentInList(ret.data); | |||||
| getList(); | |||||
| } else { | |||||
| setExperimentInList([]); | |||||
| getList(); | |||||
| } | } | ||||
| }); | |||||
| }; | |||||
| const expandChange = (e, record) => { | |||||
| if (record.id === expandedRowKeys) { | |||||
| setExpandedRowKeys(null); | |||||
| } else { | |||||
| getQueryByExperiment(record.id); | |||||
| } | } | ||||
| const showModal = () => { | |||||
| setDialogTitle('新建实验') | |||||
| setDisableFlag(false) | |||||
| console.log(workflowList); | |||||
| }; | |||||
| // 创建实验 | |||||
| const createExperiment = () => { | |||||
| setIsAdd(true); | |||||
| setAddFormData({}); | |||||
| setExperimentId(null); | |||||
| setIsModalOpen(true); | |||||
| }; | |||||
| // 编辑实验 | |||||
| const editExperiment = (id) => { | |||||
| getExperimentById(id).then((res) => { | |||||
| setAddFormData({ | |||||
| ...res.data, | |||||
| }); | |||||
| setExperimentId(res.data.id); | |||||
| setIsAdd(false); | |||||
| setIsModalOpen(true); | setIsModalOpen(true); | ||||
| }; | |||||
| const editTable=(id)=>{ | |||||
| getExperimentById(id).then(ret=>{ | |||||
| if(ret.code==200){ | |||||
| form.setFieldsValue({...ret.data}) | |||||
| setDisableFlag(true) | |||||
| setFormId(ret.data.id) | |||||
| setDialogTitle('编辑实验') | |||||
| getWorkflowList() | |||||
| setIsModalOpen(true) | |||||
| } | |||||
| }) | |||||
| // navgite({pathname:`/pipeline/pytorchtext/${record.id}/${record.name}` }); | |||||
| }); | |||||
| }; | |||||
| // 创建或编辑实验取消 | |||||
| const handleCancel = () => { | |||||
| setIsModalOpen(false); | |||||
| }; | |||||
| const routeToEdit = (e, record) => { | |||||
| e.stopPropagation(); | |||||
| navgite({ pathname: `/pipeline/pytorchtext/${record.workflow_id}/${record.workflow_name}` }); | |||||
| }; | |||||
| // 创建或者编辑实验接口请求 | |||||
| const handleAddExperiment = async (values) => { | |||||
| const workflow_id = values['workflow_id']; | |||||
| let global_param = undefined; | |||||
| const pipeline = workflowList.find((v) => v.id === workflow_id); | |||||
| if (pipeline && pipeline.global_param) { | |||||
| const globalParamList = [...pipeline.global_param]; | |||||
| for (const item of globalParamList) { | |||||
| item.param_value = values[item.param_name]; | |||||
| values[item.param_name] = undefined; | |||||
| } | |||||
| global_param = JSON.stringify(globalParamList); | |||||
| } | } | ||||
| const handleOk = () => { | |||||
| console.log(1111); | |||||
| setIsModalOpen(false); | |||||
| }; | |||||
| const handleCancel = () => { | |||||
| setIsModalOpen(false); | |||||
| const params = { | |||||
| ...values, | |||||
| global_param, | |||||
| }; | }; | ||||
| const routeToEdit=(e,record)=>{ | |||||
| e.stopPropagation() | |||||
| navgite({pathname:`/pipeline/pytorchtext/${record.workflow_id}/${record.workflow_name}` }); | |||||
| } | |||||
| const onFinish = (values) => { | |||||
| console.log(values,formId); | |||||
| if(!formId){ | |||||
| postExperiment(values).then(ret=>{ | |||||
| if(ret.code==200){ | |||||
| message.success('新建实验成功') | |||||
| setIsModalOpen(false) | |||||
| getList() | |||||
| } | |||||
| else{ | |||||
| message.error('新建实验失败') | |||||
| } | |||||
| }) | |||||
| if (!experimentId) { | |||||
| const [res, _] = await to(postExperiment(params)); | |||||
| if (res) { | |||||
| message.success('新建实验成功'); | |||||
| setIsModalOpen(false); | |||||
| getList(); | |||||
| } | } | ||||
| else{ | |||||
| putExperiment({...values,id:formId}).then(ret=>{ | |||||
| if(ret.code==200){ | |||||
| message.success('编辑实验成功') | |||||
| setIsModalOpen(false) | |||||
| getList() | |||||
| } | |||||
| else{ | |||||
| message.error('编辑实验失败') | |||||
| } | |||||
| }) | |||||
| } else { | |||||
| const params = { ...values, id: experimentId }; | |||||
| const [res, _] = await to(putExperiment(params)); | |||||
| if (res) { | |||||
| message.success('编辑实验成功'); | |||||
| setIsModalOpen(false); | |||||
| getList(); | |||||
| } | } | ||||
| setFormId(null) | |||||
| }; | |||||
| const onFinishFailed = (errorInfo) => { | |||||
| console.log('Failed:', errorInfo); | |||||
| }; | |||||
| const pageOption = useRef({page: 1,size: 10}) | |||||
| const paginationProps = { | |||||
| showQuickJumper: true, | |||||
| showTotal: () => `共${total}条`, | |||||
| total: total, | |||||
| page: pageOption.current.page, | |||||
| size: pageOption.current.size, | |||||
| onChange: (current, size) => paginationChange(current, size) | |||||
| } | } | ||||
| // 当前页面切换 | |||||
| const paginationChange = async (current, size) => { | |||||
| console.log('page', current, size) | |||||
| pageOption.current={ | |||||
| page:current, | |||||
| size:size | |||||
| }; | |||||
| const pageOption = useRef({ page: 1, size: 10 }); | |||||
| const paginationProps = { | |||||
| showQuickJumper: true, | |||||
| showTotal: () => `共${total}条`, | |||||
| total: total, | |||||
| page: pageOption.current.page, | |||||
| size: pageOption.current.size, | |||||
| onChange: (current, size) => paginationChange(current, size), | |||||
| }; | |||||
| // 当前页面切换 | |||||
| const paginationChange = async (current, size) => { | |||||
| console.log('page', current, size); | |||||
| pageOption.current = { | |||||
| page: current, | |||||
| size: size, | |||||
| }; | |||||
| getList(); | |||||
| }; | |||||
| const runExperiment = (id) => { | |||||
| runExperiments(id).then((ret) => { | |||||
| if (ret.code === 200) { | |||||
| message.success('运行成功'); | |||||
| getQueryByExperiment(id); | |||||
| } else { | |||||
| message.error('运行失败'); | |||||
| } | } | ||||
| getList() | |||||
| } | |||||
| const runExperiment=(id)=>{ | |||||
| runExperiments(id).then(ret=>{ | |||||
| if(ret.code==200){ | |||||
| message.success('运行成功') | |||||
| getQueryByExperiment(id) | |||||
| } | |||||
| else{ | |||||
| message.error('运行失败') | |||||
| } | |||||
| }) | |||||
| } | |||||
| const routerToText=(e,item,record)=>{ | |||||
| e.stopPropagation() | |||||
| navgite({pathname:`/experiment/pytorchtext/${record.workflow_id}/${item.id}` }); | |||||
| } | |||||
| const getList=()=>{ | |||||
| let params={ | |||||
| offset:0, | |||||
| page:pageOption.current.page-1, | |||||
| size:pageOption.current.size | |||||
| } | |||||
| console.log(params,pageOption); | |||||
| getExperiment(params).then(ret=>{ | |||||
| if(ret.code==200){ | |||||
| setExperimentList(ret.data.content.map(item=>{return{...item,key:item.id}})) | |||||
| setTotal(ret.data.totalElements) | |||||
| } | |||||
| console.log(experimentList,total); | |||||
| }) | |||||
| } | |||||
| useEffect(()=>{ | |||||
| getList() | |||||
| getWorkflowList() | |||||
| // const timeOut= setInterval(() => { | |||||
| // getList() | |||||
| // }, 2000); | |||||
| return () => { | |||||
| // timeOut&&clearInterval(timeOut) | |||||
| // console.log('will unmount'); | |||||
| } | |||||
| },[]) | |||||
| const columns = [ | |||||
| // { | |||||
| // title: '序号', | |||||
| // dataIndex: 'index', | |||||
| // key: 'index', | |||||
| // width: 60, | |||||
| // render(text, record, index) { | |||||
| // return ( | |||||
| // <span>{(pageOption.current.page - 1) * 10 + index + 1}</span> | |||||
| // ) | |||||
| // } | |||||
| // // render: (text, record, index) => `${((curPage-1)*10)+(index+1)}`, | |||||
| // }, | |||||
| { | |||||
| title: '实验名称', | |||||
| dataIndex: 'name', | |||||
| key: 'name', | |||||
| render: (text) => <div >{text}</div>, | |||||
| }, | |||||
| { | |||||
| title: '关联流水线名称', | |||||
| dataIndex: 'workflow_name', | |||||
| key: 'workflow_name', | |||||
| render: (text,record) => <a onClick={(e)=>routeToEdit(e,record)}>{text}</a>, | |||||
| }, | |||||
| { | |||||
| title: '实验描述', | |||||
| dataIndex: 'description', | |||||
| key: 'description', | |||||
| }, | |||||
| { | |||||
| title: '最近五次运行状态', | |||||
| dataIndex: 'status_list', | |||||
| key: 'status_list', | |||||
| render: (text) => { | |||||
| }); | |||||
| }; | |||||
| const routerToText = (e, item, record) => { | |||||
| e.stopPropagation(); | |||||
| navgite({ pathname: `/experiment/pytorchtext/${record.workflow_id}/${item.id}` }); | |||||
| }; | |||||
| 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 <img style={{width:'17px',marginRight:'6px'}} key={index} src={statusImgObj[item]} />}):null}</> | |||||
| } | |||||
| }, | |||||
| { | |||||
| title: '操作', | |||||
| key: 'action', | |||||
| width:300, | |||||
| render: (_, record) => ( | |||||
| <Space size="small"> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="edit" | |||||
| icon = {<PlayCircleOutlined />} | |||||
| onClick={() => { | |||||
| runExperiment(record.id) | |||||
| }} | |||||
| > | |||||
| 运行 | |||||
| </Button> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="edit" | |||||
| icon = {< EditOutlined />} | |||||
| onClick={() => { | |||||
| editTable(record.id) | |||||
| }} | |||||
| > | |||||
| 编辑 | |||||
| </Button> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| danger | |||||
| key="batchRemove" | |||||
| style={{color:'#f98e1b'}} | |||||
| icon = {< DeleteOutlined />} | |||||
| onClick={async () => { | |||||
| Modal.confirm({ | |||||
| title: '删除', | |||||
| content: '确定删除该条实验吗?', | |||||
| okText: '确认', | |||||
| cancelText: '取消', | |||||
| const columns = [ | |||||
| { | |||||
| title: '实验名称', | |||||
| dataIndex: 'name', | |||||
| key: 'name', | |||||
| render: (text) => <div>{text}</div>, | |||||
| }, | |||||
| { | |||||
| title: '关联流水线名称', | |||||
| dataIndex: 'workflow_name', | |||||
| key: 'workflow_name', | |||||
| render: (text, record) => <a onClick={(e) => routeToEdit(e, record)}>{text}</a>, | |||||
| }, | |||||
| { | |||||
| title: '实验描述', | |||||
| dataIndex: 'description', | |||||
| key: 'description', | |||||
| }, | |||||
| { | |||||
| title: '最近五次运行状态', | |||||
| 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) => { | |||||
| return ( | |||||
| <img | |||||
| style={{ width: '17px', marginRight: '6px' }} | |||||
| key={index} | |||||
| src={experimentStatusInfo[item].icon} | |||||
| /> | |||||
| ); | |||||
| }) | |||||
| : null} | |||||
| </> | |||||
| ); | |||||
| }, | |||||
| }, | |||||
| 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(); | |||||
| // } | |||||
| // } | |||||
| }, | |||||
| }); | |||||
| }} | |||||
| > | |||||
| 删除 | |||||
| </Button> | |||||
| </Space> | |||||
| ), | |||||
| }, | |||||
| ]; | |||||
| return (<div> | |||||
| {/* <div > | |||||
| <Button type="primary" onClick={showModal} icon = {< PlusOutlined />}> | |||||
| { | |||||
| title: '操作', | |||||
| key: 'action', | |||||
| width: 300, | |||||
| render: (_, record) => ( | |||||
| <Space size="small"> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="run" | |||||
| icon={<PlayCircleOutlined />} | |||||
| onClick={() => { | |||||
| runExperiment(record.id); | |||||
| }} | |||||
| > | |||||
| 运行 | |||||
| </Button> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="edit" | |||||
| icon={<EditOutlined />} | |||||
| onClick={() => { | |||||
| editExperiment(record.id); | |||||
| }} | |||||
| > | |||||
| 编辑 | |||||
| </Button> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| danger | |||||
| key="batchRemove" | |||||
| style={{ color: '#f98e1b' }} | |||||
| icon={<DeleteOutlined />} | |||||
| 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(); | |||||
| // } | |||||
| // } | |||||
| }, | |||||
| }); | |||||
| }} | |||||
| > | |||||
| 删除 | |||||
| </Button> | |||||
| </Space> | |||||
| ), | |||||
| }, | |||||
| ]; | |||||
| return ( | |||||
| <div> | |||||
| {/* <div > | |||||
| <Button type="primary" onClick={createExperiment} icon = {< PlusOutlined />}> | |||||
| 新建实验 | 新建实验 | ||||
| </Button> | </Button> | ||||
| </div> */} | </div> */} | ||||
| <div className={Styles.pipelineTopBox}> | |||||
| <Button type="primary" className={Styles.plusButton} onClick={showModal} icon = {<PlusCircleOutlined style={{color:'#1664ff'}} />}> | |||||
| 新建实验 | |||||
| </Button> | |||||
| </div> | |||||
| <Table columns={columns} dataSource={experimentList} pagination={paginationProps} expandable={{ | |||||
| expandedRowRender: (record) => ( | |||||
| <div> | |||||
| {experimentInList&&experimentInList.length>0?<div className={Styles.tableExpandBox} style={{paddingBottom:'16px'}}> | |||||
| <div style={{width:'50px'}}>序号</div> | |||||
| <div style={{width:'200px'}}>状态</div> | |||||
| <div style={{width:'300px'}}>运行时长</div> | |||||
| <div style={{width:'300px'}}>开始时间</div> | |||||
| <div style={{width:'200px'}}>操作</div> | |||||
| </div>:''} | |||||
| {experimentInList&&experimentInList.length>0?experimentInList.map((item,index)=>( | |||||
| <div className={Styles.tableExpandBox} style={{border:'1px solid #eaeaea',backgroundColor:'#fff',height:'45px'}}> | |||||
| <a style={{width:'50px'}} onClick={(e)=>routerToText(e,item,record)}>{index+1}</a> | |||||
| <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'}}>{momnet(item.create_time).format('YYYY-MM-DD HH:mm:ss')}</div> | |||||
| <div style={{width:'200px'}}> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="batchRemove" | |||||
| disabled={item.status=='Succeeded'||item.status=='Failed'||item.status=='Terminated'} | |||||
| icon = {<FieldTimeOutlined />} | |||||
| onClick={async () => { | |||||
| putQueryByExperimentInsId(item.id).then(ret=>{ | |||||
| if(ret.code==200){ | |||||
| message.success('终止成功') | |||||
| getQueryByExperiment(record.id) | |||||
| } | |||||
| else{ | |||||
| message.error(ret.msg) | |||||
| } | |||||
| }) | |||||
| }} | |||||
| > | |||||
| 终止 | |||||
| </Button> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| danger | |||||
| key="batchRemove" | |||||
| style={{color:'#f98e1b'}} | |||||
| disabled={item.status=='Running'||item.status=='Pending'} | |||||
| icon = {< DeleteOutlined />} | |||||
| 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) | |||||
| } | |||||
| }); | |||||
| }, | |||||
| }); | |||||
| }} | |||||
| <div className={Styles.pipelineTopBox}> | |||||
| <Button | |||||
| type="primary" | |||||
| className={Styles.plusButton} | |||||
| onClick={createExperiment} | |||||
| icon={<PlusCircleOutlined style={{ color: '#1664ff' }} />} | |||||
| > | > | ||||
| 删除 | |||||
| 新建实验 | |||||
| </Button> | </Button> | ||||
| </div> | |||||
| </div> | |||||
| )):''} | |||||
| </div> | |||||
| </div> | |||||
| <Table | |||||
| columns={columns} | |||||
| dataSource={experimentList} | |||||
| pagination={paginationProps} | |||||
| expandable={{ | |||||
| expandedRowRender: (record) => ( | |||||
| <div> | |||||
| {experimentInList && experimentInList.length > 0 ? ( | |||||
| <div className={Styles.tableExpandBox} style={{ paddingBottom: '16px' }}> | |||||
| <div style={{ width: '50px' }}>序号</div> | |||||
| <div style={{ width: '200px' }}>状态</div> | |||||
| <div style={{ width: '300px' }}>运行时长</div> | |||||
| <div style={{ width: '300px' }}>开始时间</div> | |||||
| <div style={{ width: '200px' }}>操作</div> | |||||
| </div> | |||||
| ) : ( | |||||
| '' | |||||
| )} | |||||
| ), | |||||
| onExpand:(e,a)=>{expandChange(e,a)}, | |||||
| expandedRowKeys:[expandedRowKeys], | |||||
| rowExpandable: (record) =>true, | |||||
| }}/> | |||||
| <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', | |||||
| form: 'form', | |||||
| }} onCancel={handleCancel}> | |||||
| <Form | |||||
| name="form" | |||||
| form={form} | |||||
| layout="vertical" | |||||
| initialValues={{ | |||||
| remember: true, | |||||
| }} | |||||
| onFinish={onFinish} | |||||
| onFinishFailed={onFinishFailed} | |||||
| autoComplete="off" | |||||
| > | |||||
| <Form.Item | |||||
| label="实验名称" | |||||
| name="name" | |||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| > | |||||
| <Input /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="实验描述" | |||||
| name="description" | |||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| > | |||||
| <Input /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="选择流水线" | |||||
| name="workflow_id" | |||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| > | |||||
| <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> | |||||
| </Form.Item> | |||||
| </Form> | |||||
| </Modal> | |||||
| </div>)}; | |||||
| export default Experiment; | |||||
| {experimentInList && experimentInList.length > 0 | |||||
| ? experimentInList.map((item, index) => ( | |||||
| <div | |||||
| key={item.id} | |||||
| className={Styles.tableExpandBox} | |||||
| style={{ | |||||
| border: '1px solid #eaeaea', | |||||
| backgroundColor: '#fff', | |||||
| height: '45px', | |||||
| }} | |||||
| > | |||||
| <a style={{ width: '50px' }} onClick={(e) => routerToText(e, item, record)}> | |||||
| {index + 1} | |||||
| </a> | |||||
| <div className={Styles.statusBox} style={{ width: '200px' }}> | |||||
| <img | |||||
| style={{ width: '17px', marginRight: '7px' }} | |||||
| src={experimentStatusInfo[item.status]?.icon} | |||||
| />{' '} | |||||
| <span | |||||
| style={{ color: experimentStatusInfo[item.status]?.color }} | |||||
| className={Styles.statusIcon} | |||||
| > | |||||
| {experimentStatusInfo[item.status]?.label} | |||||
| </span> | |||||
| </div> | |||||
| <div style={{ width: '300px' }}> | |||||
| {item.finish_time | |||||
| ? elapsedTime(new Date(item.create_time), new Date(item.finish_time)) | |||||
| : elapsedTime(new Date(item.create_time), new Date())} | |||||
| </div> | |||||
| <div style={{ width: '300px' }}> | |||||
| {momnet(item.create_time).format('YYYY-MM-DD HH:mm:ss')} | |||||
| </div> | |||||
| <div style={{ width: '200px' }}> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="stop" | |||||
| disabled={ | |||||
| item.status === 'Succeeded' || | |||||
| item.status === 'Failed' || | |||||
| item.status === 'Terminated' | |||||
| } | |||||
| icon={<FieldTimeOutlined />} | |||||
| onClick={async () => { | |||||
| putQueryByExperimentInsId(item.id).then((ret) => { | |||||
| if (ret.code === 200) { | |||||
| message.success('终止成功'); | |||||
| getQueryByExperiment(record.id); | |||||
| } else { | |||||
| message.error(ret.msg); | |||||
| } | |||||
| }); | |||||
| }} | |||||
| > | |||||
| 终止 | |||||
| </Button> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| danger | |||||
| key="batchRemove" | |||||
| style={{ color: '#f98e1b' }} | |||||
| disabled={item.status === 'Running' || item.status === 'Pending'} | |||||
| icon={<DeleteOutlined />} | |||||
| 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); | |||||
| } | |||||
| }); | |||||
| }, | |||||
| }); | |||||
| }} | |||||
| > | |||||
| 删除 | |||||
| </Button> | |||||
| </div> | |||||
| </div> | |||||
| )) | |||||
| : ''} | |||||
| </div> | |||||
| ), | |||||
| onExpand: (e, a) => { | |||||
| expandChange(e, a); | |||||
| }, | |||||
| expandedRowKeys: [expandedRowKeys], | |||||
| rowExpandable: (record) => true, | |||||
| }} | |||||
| /> | |||||
| <AddExperimentModal | |||||
| isAdd={isAdd} | |||||
| open={isModalOpen} | |||||
| initialValues={addFormData} | |||||
| onCancel={handleCancel} | |||||
| onFinish={handleAddExperiment} | |||||
| workflowList={workflowList} | |||||
| /> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default Experiment; | |||||
| @@ -1,102 +1,59 @@ | |||||
| .experimentTopBox{ | |||||
| 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); | |||||
| .experimentTopBox { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: flex-end; | |||||
| width: 100%; | |||||
| height: 49px; | |||||
| padding-right: 30px; | |||||
| background-image: url(/assets/images/pipeline-back.png); | |||||
| background-size: 100% 100%; | |||||
| } | } | ||||
| .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; | |||||
| .pipelineTopBox { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: flex-end; | |||||
| width: 100%; | |||||
| height: 49px; | |||||
| margin-bottom: 10px; | |||||
| padding-right: 30px; | |||||
| background-image: url(/assets/images/pipeline-back.png); | |||||
| background-size: 100% 100%; | |||||
| } | } | ||||
| .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 { | |||||
| color: #1d1d20; | |||||
| font-size: 14px; | |||||
| font-family: 'Alibaba'; | |||||
| background: rgba(22, 100, 255, 0.06); | |||||
| border: 1px solid; | |||||
| border-color: rgba(22, 100, 255, 0.11); | |||||
| border-radius: 4px; | |||||
| } | } | ||||
| .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:hover { | |||||
| color: #1d1d20 !important; | |||||
| background: rgba(22, 100, 255, 0.06) !important; | |||||
| border: 1px solid !important; | |||||
| border-color: rgba(22, 100, 255, 0.11) !important; | |||||
| } | } | ||||
| .tableExpandBox{ | |||||
| width: 100%; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: space-between; | |||||
| color:#1d1d20; | |||||
| font-size:15px; | |||||
| padding: 0 65px 0 40px; | |||||
| .tableExpandBox { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: space-between; | |||||
| width: 100%; | |||||
| padding: 0 65px 0 40px; | |||||
| color: #1d1d20; | |||||
| font-size: 15px; | |||||
| } | } | ||||
| .statusBox{ | |||||
| display: flex; | |||||
| align-items: center; | |||||
| .statusBox { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| .statusIcon{ | |||||
| visibility: hidden; | |||||
| transition: all 0.2s; | |||||
| } | |||||
| .statusIcon { | |||||
| visibility: hidden; | |||||
| transition: all 0.2s; | |||||
| } | |||||
| } | } | ||||
| .statusBox:hover .statusIcon{ | |||||
| visibility: visible; | |||||
| .statusBox:hover .statusIcon { | |||||
| 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:110px; | |||||
| height:40px; | |||||
| font-size:18px; | |||||
| background:rgba(22, 100, 255, 0.06); | |||||
| border-radius:10px; | |||||
| border-color: transparent; | |||||
| } | |||||
| .ant-btn-primary{ | |||||
| background:#1664ff; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,59 @@ | |||||
| export interface StatusInfo { | |||||
| label: string; | |||||
| color: string; | |||||
| icon: string; | |||||
| } | |||||
| export enum ExperimentStatus { | |||||
| Running = 'Running', | |||||
| Succeeded = 'Succeeded', | |||||
| Pending = 'Pending', | |||||
| Failed = 'Failed', | |||||
| Error = 'Error', | |||||
| Terminated = 'Terminated', | |||||
| Skipped = 'Skipped', | |||||
| Omitted = 'Omitted', | |||||
| } | |||||
| export const experimentStatusInfo: Record<string, StatusInfo | undefined> = { | |||||
| Running: { | |||||
| label: '运行中', | |||||
| color: '#165bff', | |||||
| icon: '/assets/images/running-icon.png', | |||||
| }, | |||||
| Succeeded: { | |||||
| label: '成功', | |||||
| color: '#63a728', | |||||
| icon: '/assets/images/success-icon.png', | |||||
| }, | |||||
| Pending: { | |||||
| label: '等待中', | |||||
| color: '#f981eb', | |||||
| icon: '/assets/images/pending-icon.png', | |||||
| }, | |||||
| Failed: { | |||||
| label: '失败', | |||||
| color: '#c73131', | |||||
| icon: '/assets/images/fail-icon.png', | |||||
| }, | |||||
| Error: { | |||||
| label: '错误', | |||||
| color: '#c73131', | |||||
| icon: '/assets/images/fail-icon.png', | |||||
| }, | |||||
| Terminated: { | |||||
| label: '终止', | |||||
| color: '#8a8a8a', | |||||
| icon: '/assets/images/omitted-icon.png', | |||||
| }, | |||||
| Skipped: { | |||||
| label: '未执行', | |||||
| color: '#8a8a8a', | |||||
| icon: '/assets/images/omitted-icon.png', | |||||
| }, | |||||
| Omitted: { | |||||
| label: '未执行', | |||||
| color: '#8a8a8ae', | |||||
| icon: '/assets/images/omitted-icon.png', | |||||
| }, | |||||
| }; | |||||
| @@ -1,149 +1,151 @@ | |||||
| import React ,{useEffect,useState,useRef}from 'react'; | |||||
| import Styles from './index.less' | |||||
| import { Input, Space ,Button,Tabs,Pagination,Modal, Form,message, Radio,Select,Table,Upload} from 'antd'; | |||||
| import { PlusOutlined,PlusCircleOutlined, DeleteOutlined,UploadOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined ,CopyOutlined} from '@ant-design/icons'; | |||||
| import {getDatasetList,getModelById,getModelVersionsById,getModelVersionIdList,deleteModelVersion,addModelsVersionDetail} from '@/services/dataset/index.js' | |||||
| import { useParams } from 'react-router-dom' | |||||
| import {downLoadZip} from '@/utils/downloadfile' | |||||
| const { Search } = Input; | |||||
| import { getAccessToken } from '@/access'; | |||||
| import { | |||||
| addModelsVersionDetail, | |||||
| deleteModelVersion, | |||||
| getModelById, | |||||
| getModelVersionIdList, | |||||
| getModelVersionsById, | |||||
| } from '@/services/dataset/index.js'; | |||||
| import { downLoadZip } from '@/utils/downloadfile'; | |||||
| import { DeleteOutlined, PlusCircleOutlined, UploadOutlined } from '@ant-design/icons'; | |||||
| import { Button, Form, Input, Modal, Select, Table, Tabs, Upload, message } from 'antd'; | |||||
| import moment from 'moment'; | import moment from 'moment'; | ||||
| import { getAccessToken } from '@/access'; | |||||
| import { useEffect, useRef, useState } from 'react'; | |||||
| import { useParams } from 'react-router-dom'; | |||||
| import Styles from './index.less'; | |||||
| const { Search } = Input; | |||||
| const { TabPane } = Tabs; | const { TabPane } = Tabs; | ||||
| const Dataset= React.FC = () => { | |||||
| const Dataset = () => { | |||||
| const props = { | const props = { | ||||
| action: '/api/mmp/dataset/upload', | action: '/api/mmp/dataset/upload', | ||||
| // headers: { | // headers: { | ||||
| // 'X-Requested-With': null | // 'X-Requested-With': null | ||||
| // }, | // }, | ||||
| headers: { | headers: { | ||||
| Authorization:getAccessToken(), | |||||
| 'X-Requested-With': null | |||||
| Authorization: getAccessToken(), | |||||
| 'X-Requested-With': null, | |||||
| }, | }, | ||||
| onChange({ file, fileList }) { | onChange({ file, fileList }) { | ||||
| if (file.status !== 'uploading') { | if (file.status !== 'uploading') { | ||||
| console.log(file, fileList); | console.log(file, fileList); | ||||
| setFormList(fileList.map(item=>{ | |||||
| return { | |||||
| ...form.getFieldsValue(), | |||||
| models_id:locationParams.id, | |||||
| file_name:item.response.data[0].fileName, | |||||
| file_size:item.response.data[0].fileSize, | |||||
| url:item.response.data[0].url, | |||||
| } | |||||
| })) | |||||
| setFormList( | |||||
| fileList.map((item) => { | |||||
| return { | |||||
| ...form.getFieldsValue(), | |||||
| models_id: locationParams.id, | |||||
| file_name: item.response.data[0].fileName, | |||||
| file_size: item.response.data[0].fileSize, | |||||
| url: item.response.data[0].url, | |||||
| }; | |||||
| }), | |||||
| ); | |||||
| } | } | ||||
| }, | }, | ||||
| defaultFileList: [ | |||||
| ], | |||||
| defaultFileList: [], | |||||
| }; | }; | ||||
| const [form] = Form.useForm(); | const [form] = Form.useForm(); | ||||
| const [formList,setFormList]=useState([]) | |||||
| const [formList, setFormList] = useState([]); | |||||
| const [dialogTitle, setDialogTitle] = useState('新建版本'); | const [dialogTitle, setDialogTitle] = useState('新建版本'); | ||||
| const [isModalOpen,setIsModalOpen]=useState(false) | |||||
| const [datasetDetailObj,setDatasetDetailObj]=useState({ | |||||
| }); | |||||
| const [version,setVersion]=useState('') | |||||
| const [isModalOpen, setIsModalOpen] = useState(false); | |||||
| const [datasetDetailObj, setDatasetDetailObj] = useState({}); | |||||
| const [version, setVersion] = useState(''); | |||||
| const [versionList, setVersionList] = useState([]); | const [versionList, setVersionList] = useState([]); | ||||
| const locationParams =useParams () //新版本获取路由参数接口 | |||||
| const locationParams = useParams(); //新版本获取路由参数接口 | |||||
| console.log(locationParams); | console.log(locationParams); | ||||
| const [wordList, setWordList] = useState([]); | const [wordList, setWordList] = useState([]); | ||||
| const getModelByDetail=()=>{ | |||||
| getModelById(locationParams.id).then(ret=>{ | |||||
| const getModelByDetail = () => { | |||||
| getModelById(locationParams.id).then((ret) => { | |||||
| console.log(ret); | console.log(ret); | ||||
| if(ret.code==200){ | |||||
| setDatasetDetailObj(ret.data) | |||||
| if (ret.code == 200) { | |||||
| setDatasetDetailObj(ret.data); | |||||
| } | } | ||||
| }) | |||||
| } | |||||
| const getModelVersionsList=()=>{ | |||||
| getModelVersionsById(locationParams.id).then(ret=>{ | |||||
| }); | |||||
| }; | |||||
| const getModelVersionsList = () => { | |||||
| getModelVersionsById(locationParams.id).then((ret) => { | |||||
| console.log(ret); | console.log(ret); | ||||
| if(ret.code==200&&ret.data&&ret.data.length>0){ | |||||
| setVersionList(ret.data.map(item=>{ | |||||
| return { | |||||
| 'label':item, | |||||
| 'value':item | |||||
| } | |||||
| })) | |||||
| if (ret.code == 200 && ret.data && ret.data.length > 0) { | |||||
| setVersionList( | |||||
| ret.data.map((item) => { | |||||
| return { | |||||
| label: item, | |||||
| value: item, | |||||
| }; | |||||
| }), | |||||
| ); | |||||
| } | } | ||||
| }) | |||||
| } | |||||
| useEffect(()=>{ | |||||
| getModelByDetail() | |||||
| getModelVersionsList() | |||||
| return ()=>{ | |||||
| } | |||||
| },[]) | |||||
| }); | |||||
| }; | |||||
| useEffect(() => { | |||||
| getModelByDetail(); | |||||
| getModelVersionsList(); | |||||
| return () => {}; | |||||
| }, []); | |||||
| const showModal = () => { | const showModal = () => { | ||||
| form.resetFields() | |||||
| form.setFieldsValue({name:datasetDetailObj.name}) | |||||
| setDialogTitle('创建新版本') | |||||
| form.resetFields(); | |||||
| form.setFieldsValue({ name: datasetDetailObj.name }); | |||||
| setDialogTitle('创建新版本'); | |||||
| setIsModalOpen(true); | setIsModalOpen(true); | ||||
| }; | }; | ||||
| const handleCancel = () => { | const handleCancel = () => { | ||||
| setIsModalOpen(false); | setIsModalOpen(false); | ||||
| }; | }; | ||||
| const deleteDataset=()=>{ | |||||
| const deleteDataset = () => { | |||||
| Modal.confirm({ | Modal.confirm({ | ||||
| title: '删除', | title: '删除', | ||||
| content: '确定删除模型版本?', | content: '确定删除模型版本?', | ||||
| okText: '确认', | okText: '确认', | ||||
| cancelText: '取消', | cancelText: '取消', | ||||
| onOk: () => { | |||||
| deleteModelVersion({models_id:locationParams.id,version}).then(ret=>{ | |||||
| if(ret.code==200){ | |||||
| message.success('删除成功') | |||||
| getModelVersions({version,models_id:locationParams.id}) | |||||
| } | |||||
| else{ | |||||
| message.error(ret.msg) | |||||
| } | |||||
| onOk: () => { | |||||
| deleteModelVersion({ models_id: locationParams.id, version }).then((ret) => { | |||||
| if (ret.code == 200) { | |||||
| message.success('删除成功'); | |||||
| getModelVersions({ version, models_id: locationParams.id }); | |||||
| } else { | |||||
| message.error(ret.msg); | |||||
| } | |||||
| }); | }); | ||||
| }, | }, | ||||
| }); | }); | ||||
| } | |||||
| }; | |||||
| const onFinish = () => { | const onFinish = () => { | ||||
| addModelsVersionDetail(formList).then(ret=>{ | |||||
| console.log(ret); | |||||
| getModelVersionsList() | |||||
| setIsModalOpen(false); | |||||
| }) | |||||
| }; | |||||
| const getModelVersions=(params)=>{ | |||||
| getModelVersionIdList(params).then(ret=>{ | |||||
| addModelsVersionDetail(formList).then((ret) => { | |||||
| console.log(ret); | console.log(ret); | ||||
| if(ret.code==200){ | |||||
| setWordList(ret.data) | |||||
| getModelVersionsList(); | |||||
| setIsModalOpen(false); | |||||
| }); | |||||
| }; | |||||
| const getModelVersions = (params) => { | |||||
| getModelVersionIdList(params).then((ret) => { | |||||
| console.log(ret); | |||||
| if (ret.code == 200) { | |||||
| setWordList(ret.data); | |||||
| } | } | ||||
| }) | |||||
| } | |||||
| }); | |||||
| }; | |||||
| const handleExport = async () => { | const handleExport = async () => { | ||||
| const hide = message.loading('正在下载'); | const hide = message.loading('正在下载'); | ||||
| hide(); | hide(); | ||||
| downLoadZip(`/api/mmp/models/downloadAllFiles`,{models_id:locationParams.id,version}) | |||||
| downLoadZip(`/api/mmp/models/downloadAllFiles`, { models_id: locationParams.id, version }); | |||||
| }; | }; | ||||
| const downloadAlone=(e,record)=>{ | |||||
| const downloadAlone = (e, record) => { | |||||
| console.log(record); | console.log(record); | ||||
| const hide = message.loading('正在下载'); | const hide = message.loading('正在下载'); | ||||
| hide(); | hide(); | ||||
| downLoadZip(`/api/mmp/models/download_model/${record.id}`) | |||||
| } | |||||
| const handleChange=(value)=>{ | |||||
| downLoadZip(`/api/mmp/models/download_model/${record.id}`); | |||||
| }; | |||||
| const handleChange = (value) => { | |||||
| console.log(value); | console.log(value); | ||||
| if(value){ | |||||
| getModelVersions({version:value,models_id:locationParams.id}) | |||||
| setVersion(value) | |||||
| } | |||||
| else{ | |||||
| setVersion(null) | |||||
| if (value) { | |||||
| getModelVersions({ version: value, models_id: locationParams.id }); | |||||
| setVersion(value); | |||||
| } else { | |||||
| setVersion(null); | |||||
| } | } | ||||
| } | |||||
| }; | |||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', errorInfo); | console.log('Failed:', errorInfo); | ||||
| }; | }; | ||||
| @@ -164,7 +166,7 @@ const Dataset= React.FC = () => { | |||||
| title: '文件名称', | title: '文件名称', | ||||
| dataIndex: 'file_name', | dataIndex: 'file_name', | ||||
| key: 'file_name', | key: 'file_name', | ||||
| render: (text,record) => <a onClick={(e)=>downloadAlone(e,record)}>{text}</a>, | |||||
| render: (text, record) => <a onClick={(e) => downloadAlone(e, record)}>{text}</a>, | |||||
| }, | }, | ||||
| { | { | ||||
| title: '版本号', | title: '版本号', | ||||
| @@ -183,79 +185,107 @@ const Dataset= React.FC = () => { | |||||
| render: (text) => <span>{moment(text).format('YYYY-MM-DD HH:mm:ss')}</span>, | render: (text) => <span>{moment(text).format('YYYY-MM-DD HH:mm:ss')}</span>, | ||||
| }, | }, | ||||
| ]; | ]; | ||||
| const pageOption = useRef({page: 1,size: 10}) | |||||
| const pageOption = useRef({ page: 1, size: 10 }); | |||||
| // 当前页面切换 | // 当前页面切换 | ||||
| const paginationChange = async (current, size) => { | const paginationChange = async (current, size) => { | ||||
| console.log('page', current, size) | |||||
| pageOption.current={ | |||||
| page:current, | |||||
| size:size | |||||
| } | |||||
| console.log('page', current, size); | |||||
| pageOption.current = { | |||||
| page: current, | |||||
| size: size, | |||||
| }; | |||||
| // getList() | // getList() | ||||
| } | |||||
| return (<div className={Styles.datasetBox}> | |||||
| <div className={Styles.datasetIntroTopBox}> | |||||
| <span style={{color:'#1d1d20',fontSize:'20px'}}>{datasetDetailObj.name}</span> | |||||
| <div className={Styles.smallTagBox}> | |||||
| <div className={Styles.tagItem}>{datasetDetailObj.data_tag||'...'}</div> | |||||
| }; | |||||
| return ( | |||||
| <div className={Styles.datasetBox}> | |||||
| <div className={Styles.datasetIntroTopBox}> | |||||
| <span style={{ color: '#1d1d20', fontSize: '20px' }}>{datasetDetailObj.name}</span> | |||||
| <div className={Styles.smallTagBox}> | |||||
| <div className={Styles.tagItem}>{datasetDetailObj.data_tag || '...'}</div> | |||||
| <div className={Styles.tagItem}>{datasetDetailObj.data_type}</div> | <div className={Styles.tagItem}>{datasetDetailObj.data_type}</div> | ||||
| {/* <div className={Styles.tagItem}>English</div> */} | {/* <div className={Styles.tagItem}>English</div> */} | ||||
| </div> | |||||
| </div> | |||||
| <div className={Styles.datasetIntroCneterBox}> | |||||
| <Tabs | |||||
| defaultActiveKey="1" | |||||
| > | |||||
| <TabPane tab="模型简介" key="1"> | |||||
| <div className={Styles.datasetIntroTitle}>简介</div> | |||||
| <div className={Styles.datasetIntroText}>{datasetDetailObj.description}</div> | |||||
| </TabPane> | |||||
| <TabPane tab="模型文件/版本" key="2"> | |||||
| <div className={Styles.dataListBox}> | |||||
| <div>模型列表</div> | |||||
| <div className={Styles.dataButtonList}> | |||||
| <div style={{display: 'flex', | |||||
| justifyContent: 'space-between', | |||||
| alignItems: 'center'}}> | |||||
| <span style={{marginRight:'10px'}}>版本号:</span> | |||||
| <Select | |||||
| placeholder="请选择版本号" | |||||
| style={{ | |||||
| width: 160, | |||||
| }} | |||||
| allowClear | |||||
| onChange={handleChange} | |||||
| options={versionList} | |||||
| /> | |||||
| <Button type="primary" className={Styles.plusButton} onClick={showModal} icon = {<PlusCircleOutlined style={{color:'#1664ff'}} />}> | |||||
| 创建新版本 | |||||
| </Button> | |||||
| </div> | </div> | ||||
| <div style={{display: 'flex', | |||||
| justifyContent: 'space-between', | |||||
| alignItems: 'center'}}> | |||||
| <Button type="primary" className={Styles.plusButton} style={{margin:'0 20px 0 0' }} onClick={deleteDataset} icon = {<DeleteOutlined style={{color:'#1664ff', }} />}> | |||||
| 删除 | |||||
| </Button> | |||||
| <Button type="primary" className={Styles.plusButton} disabled={!version} style={{margin:'0 20px 0 0' }} onClick={handleExport} icon = {<UploadOutlined style={{color:'#1664ff'}} />}> | |||||
| 下载 | |||||
| </Button> | |||||
| </div> | |||||
| </div> | |||||
| <Table columns={columns} dataSource={wordList} pagination={false} /> | |||||
| </div> | |||||
| </TabPane> | |||||
| </Tabs> | |||||
| </div> | |||||
| <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', | |||||
| form: 'form', | |||||
| }} onCancel={handleCancel}> | |||||
| </div> | |||||
| <div className={Styles.datasetIntroCneterBox}> | |||||
| <Tabs defaultActiveKey="1"> | |||||
| <TabPane tab="模型简介" key="1"> | |||||
| <div className={Styles.datasetIntroTitle}>简介</div> | |||||
| <div className={Styles.datasetIntroText}>{datasetDetailObj.description}</div> | |||||
| </TabPane> | |||||
| <TabPane tab="模型文件/版本" key="2"> | |||||
| <div className={Styles.dataListBox}> | |||||
| <div>模型列表</div> | |||||
| <div className={Styles.dataButtonList}> | |||||
| <div | |||||
| style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }} | |||||
| > | |||||
| <span style={{ marginRight: '10px' }}>版本号:</span> | |||||
| <Select | |||||
| placeholder="请选择版本号" | |||||
| style={{ | |||||
| width: 160, | |||||
| }} | |||||
| allowClear | |||||
| onChange={handleChange} | |||||
| options={versionList} | |||||
| /> | |||||
| <Button | |||||
| type="primary" | |||||
| className={Styles.plusButton} | |||||
| onClick={showModal} | |||||
| icon={<PlusCircleOutlined style={{ color: '#1664ff' }} />} | |||||
| > | |||||
| 创建新版本 | |||||
| </Button> | |||||
| </div> | |||||
| <div | |||||
| style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }} | |||||
| > | |||||
| <Button | |||||
| type="primary" | |||||
| className={Styles.plusButton} | |||||
| style={{ margin: '0 20px 0 0' }} | |||||
| onClick={deleteDataset} | |||||
| icon={<DeleteOutlined style={{ color: '#1664ff' }} />} | |||||
| > | |||||
| 删除 | |||||
| </Button> | |||||
| <Button | |||||
| type="primary" | |||||
| className={Styles.plusButton} | |||||
| disabled={!version} | |||||
| style={{ margin: '0 20px 0 0' }} | |||||
| onClick={handleExport} | |||||
| icon={<UploadOutlined style={{ color: '#1664ff' }} />} | |||||
| > | |||||
| 下载 | |||||
| </Button> | |||||
| </div> | |||||
| </div> | |||||
| <Table columns={columns} dataSource={wordList} pagination={false} /> | |||||
| </div> | |||||
| </TabPane> | |||||
| </Tabs> | |||||
| </div> | |||||
| <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', | |||||
| form: 'form', | |||||
| }} | |||||
| onCancel={handleCancel} | |||||
| > | |||||
| <Form | <Form | ||||
| name="form" | name="form" | ||||
| form={form} | form={form} | ||||
| @@ -270,29 +300,38 @@ const Dataset= React.FC = () => { | |||||
| <Form.Item | <Form.Item | ||||
| label="模型名称" | label="模型名称" | ||||
| name="name" | name="name" | ||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| rules={ | |||||
| [ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ] | |||||
| } | |||||
| > | > | ||||
| <Input disabled placeholder="请输入数据集名称"/> | |||||
| <Input disabled placeholder="请输入数据集名称" /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | |||||
| label="模型版本" | |||||
| name="version" | |||||
| > | |||||
| <Input placeholder="请输入数据集版本"/> | |||||
| <Form.Item label="模型版本" name="version"> | |||||
| <Input placeholder="请输入数据集版本" /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item label="模型文件" name="dataset_version_vos"> | <Form.Item label="模型文件" name="dataset_version_vos"> | ||||
| <Upload {...props}> | |||||
| <Button style={{fontSize:'14px',border:'1px solid',borderColor:'#1664ff',background:'#fff'}} icon={<UploadOutlined style={{color:'#1664ff'}} />}>上传文件</Button> | |||||
| </Upload> | |||||
| </Form.Item> | |||||
| <Upload {...props}> | |||||
| <Button | |||||
| style={{ | |||||
| fontSize: '14px', | |||||
| border: '1px solid', | |||||
| borderColor: '#1664ff', | |||||
| background: '#fff', | |||||
| }} | |||||
| icon={<UploadOutlined style={{ color: '#1664ff' }} />} | |||||
| > | |||||
| 上传文件 | |||||
| </Button> | |||||
| </Upload> | |||||
| </Form.Item> | |||||
| </Form> | </Form> | ||||
| </Modal> | </Modal> | ||||
| </div>) | |||||
| </div> | |||||
| ); | |||||
| }; | }; | ||||
| export default Dataset; | |||||
| export default Dataset; | |||||
| @@ -1,234 +1,305 @@ | |||||
| import React ,{useEffect,useState}from 'react'; | |||||
| import Styles from './index.less' | |||||
| import { Input, Space ,Button,Tabs,Pagination,Modal, Form,message, Radio,Upload,Select} from 'antd'; | |||||
| import { PlusOutlined,PlusCircleOutlined, UploadOutlined,DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined ,CopyOutlined} from '@ant-design/icons'; | |||||
| import {getModelList,addModel,getAssetIcon} from '@/services/dataset/index.js' | |||||
| const { Search } = Input; | |||||
| import { useNavigate} from 'react-router-dom'; | |||||
| import { getAccessToken } from '@/access'; | |||||
| import { addModel, getAssetIcon, getModelList } from '@/services/dataset/index.js'; | |||||
| import { PlusCircleOutlined, UploadOutlined } from '@ant-design/icons'; | |||||
| import { Button, Form, Input, Modal, Pagination, Radio, Select, Upload } from 'antd'; | |||||
| import moment from 'moment'; | import moment from 'moment'; | ||||
| import { getAccessToken } from '@/access'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| import { useNavigate } from 'react-router-dom'; | |||||
| import Styles from './index.less'; | |||||
| const { Search } = Input; | |||||
| const leftdataList=[1,2,3] | |||||
| const leftdataList = [1, 2, 3]; | |||||
| const PublicData= React.FC = () => { | |||||
| const PublicData = () => { | |||||
| const props = { | const props = { | ||||
| action: '/api/mmp/dataset/upload', | action: '/api/mmp/dataset/upload', | ||||
| // headers: { | // headers: { | ||||
| // 'X-Requested-With': null | // 'X-Requested-With': null | ||||
| // }, | // }, | ||||
| headers: { | headers: { | ||||
| Authorization:getAccessToken(), | |||||
| 'X-Requested-With': null | |||||
| Authorization: getAccessToken(), | |||||
| 'X-Requested-With': null, | |||||
| }, | }, | ||||
| onChange({ file, fileList }) { | onChange({ file, fileList }) { | ||||
| if (file.status !== 'uploading') { | if (file.status !== 'uploading') { | ||||
| console.log(file, fileList); | console.log(file, fileList); | ||||
| form.setFieldsValue({dataset_version_vos:fileList.map(item=>item.response.data[0])}) | |||||
| form.setFieldsValue({ dataset_version_vos: fileList.map((item) => item.response.data[0]) }); | |||||
| } | } | ||||
| }, | }, | ||||
| defaultFileList: [ | |||||
| ], | |||||
| defaultFileList: [], | |||||
| }; | }; | ||||
| const [queryFlow,setQueryFlow]=useState({ | |||||
| page:0, | |||||
| size:10, | |||||
| name:null, | |||||
| available_range:0 | |||||
| const [queryFlow, setQueryFlow] = useState({ | |||||
| page: 0, | |||||
| size: 10, | |||||
| name: null, | |||||
| available_range: 0, | |||||
| }); | |||||
| const navgite = useNavigate(); | |||||
| const [iconParams, setIconParams] = useState({ | |||||
| name: null, | |||||
| page: 0, | |||||
| size: 10000, | |||||
| }); | }); | ||||
| const navgite=useNavigate(); | |||||
| const [iconParams,setIconParams]=useState({ | |||||
| name:null, | |||||
| page:0, | |||||
| size:10000 | |||||
| }) | |||||
| const [activeType,setActiveType]=useState(null) | |||||
| const [activeTag,setActiveTag]=useState(null) | |||||
| const [datasetTypeList,setDatasetTypeList]=useState([]) | |||||
| const [datasetDirectionList,setDatasetDirectionList]=useState([]) | |||||
| const [isModalOpen,setIsModalOpen]=useState(false) | |||||
| const [datasetList,setDatasetList]=useState([]); | |||||
| const [total,setTotal]=useState(0); | |||||
| const [activeType, setActiveType] = useState(null); | |||||
| const [activeTag, setActiveTag] = useState(null); | |||||
| const [datasetTypeList, setDatasetTypeList] = useState([]); | |||||
| const [datasetDirectionList, setDatasetDirectionList] = useState([]); | |||||
| const [isModalOpen, setIsModalOpen] = useState(false); | |||||
| const [datasetList, setDatasetList] = useState([]); | |||||
| const [total, setTotal] = useState(0); | |||||
| const [form] = Form.useForm(); | const [form] = Form.useForm(); | ||||
| const [dialogTitle, setDialogTitle] = useState('新建模型'); | const [dialogTitle, setDialogTitle] = useState('新建模型'); | ||||
| const getModelLists=(queryFlow)=>{ | |||||
| getModelList(queryFlow).then(ret=>{ | |||||
| const getModelLists = (queryFlow) => { | |||||
| getModelList(queryFlow).then((ret) => { | |||||
| console.log(ret); | console.log(ret); | ||||
| if(ret.code==200){ | |||||
| setDatasetList(ret.data.content) | |||||
| setTotal(ret.data.totalElements) | |||||
| if (ret.code == 200) { | |||||
| setDatasetList(ret.data.content); | |||||
| setTotal(ret.data.totalElements); | |||||
| } | } | ||||
| }) | |||||
| } | |||||
| }); | |||||
| }; | |||||
| const showModal = () => { | const showModal = () => { | ||||
| form.resetFields() | |||||
| setDialogTitle('新建模型') | |||||
| form.resetFields(); | |||||
| setDialogTitle('新建模型'); | |||||
| setIsModalOpen(true); | setIsModalOpen(true); | ||||
| }; | }; | ||||
| const getAssetIconList=(params)=>{ | |||||
| getAssetIcon(params).then(ret=>{ | |||||
| const getAssetIconList = (params) => { | |||||
| getAssetIcon(params).then((ret) => { | |||||
| console.log(ret); | console.log(ret); | ||||
| if(ret.code==200&&ret.data.content&&ret.data.content.length>0){ | |||||
| setDatasetTypeList(ret.data.content.filter(item=>item.category_id==3)) | |||||
| setDatasetDirectionList(ret.data.content.filter(item=>item.category_id==4)) | |||||
| } | |||||
| else{ | |||||
| setDatasetTypeList([]) | |||||
| setDatasetDirectionList([]) | |||||
| if (ret.code == 200 && ret.data.content && ret.data.content.length > 0) { | |||||
| setDatasetTypeList(ret.data.content.filter((item) => item.category_id == 3)); | |||||
| setDatasetDirectionList(ret.data.content.filter((item) => item.category_id == 4)); | |||||
| } else { | |||||
| setDatasetTypeList([]); | |||||
| setDatasetDirectionList([]); | |||||
| } | } | ||||
| }) | |||||
| } | |||||
| const onSearch=(values)=>{ | |||||
| }); | |||||
| }; | |||||
| const onSearch = (values) => { | |||||
| console.log(values); | console.log(values); | ||||
| getAssetIconList({...iconParams,name:values}) | |||||
| } | |||||
| const nameSearch=(values)=>{ | |||||
| getAssetIconList({ ...iconParams, name: values }); | |||||
| }; | |||||
| const nameSearch = (values) => { | |||||
| console.log(values); | console.log(values); | ||||
| getModelLists({...queryFlow,name:values}) | |||||
| } | |||||
| getModelLists({ ...queryFlow, name: values }); | |||||
| }; | |||||
| const handleOk = () => { | const handleOk = () => { | ||||
| console.log(1111); | |||||
| console.log(1111); | |||||
| setIsModalOpen(false); | setIsModalOpen(false); | ||||
| }; | }; | ||||
| const handleCancel = () => { | const handleCancel = () => { | ||||
| setIsModalOpen(false); | setIsModalOpen(false); | ||||
| }; | }; | ||||
| const onFinish = (values) => { | const onFinish = (values) => { | ||||
| addModel(values).then(ret=>{ | |||||
| console.log(ret); | |||||
| getModelLists(queryFlow) | |||||
| setIsModalOpen(false); | |||||
| }) | |||||
| }; | |||||
| const chooseModelType=(val,item)=>{ | |||||
| console.log(val,item); | |||||
| if(item.path==queryFlow.model_type){ | |||||
| setActiveType('') | |||||
| setQueryFlow({...queryFlow,model_type:null}) | |||||
| getModelLists({...queryFlow,model_type:null}) | |||||
| } | |||||
| else{ | |||||
| setActiveType(item.path) | |||||
| setQueryFlow({...queryFlow,model_type:item.path}) | |||||
| getModelLists({...queryFlow,model_type:item.path}) | |||||
| addModel(values).then((ret) => { | |||||
| console.log(ret); | |||||
| getModelLists(queryFlow); | |||||
| setIsModalOpen(false); | |||||
| }); | |||||
| }; | |||||
| const chooseModelType = (val, item) => { | |||||
| console.log(val, item); | |||||
| if (item.path == queryFlow.model_type) { | |||||
| setActiveType(''); | |||||
| setQueryFlow({ ...queryFlow, model_type: null }); | |||||
| getModelLists({ ...queryFlow, model_type: null }); | |||||
| } else { | |||||
| setActiveType(item.path); | |||||
| setQueryFlow({ ...queryFlow, model_type: item.path }); | |||||
| getModelLists({ ...queryFlow, model_type: item.path }); | |||||
| } | } | ||||
| // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| // getDatasetlist() | // getDatasetlist() | ||||
| // }) | // }) | ||||
| }; | }; | ||||
| const chooseModelTag=(val,item)=>{ | |||||
| if(item.path==queryFlow.model_tag){ | |||||
| setActiveTag('') | |||||
| setQueryFlow({...queryFlow,model_tag:null}) | |||||
| getModelLists({...queryFlow,model_tag:null}) | |||||
| } | |||||
| else{ | |||||
| setActiveTag(item.path) | |||||
| setQueryFlow({...queryFlow,model_tag:item.path}) | |||||
| getModelLists({...queryFlow,model_tag:item.path}) | |||||
| const chooseModelTag = (val, item) => { | |||||
| if (item.path == queryFlow.model_tag) { | |||||
| setActiveTag(''); | |||||
| setQueryFlow({ ...queryFlow, model_tag: null }); | |||||
| getModelLists({ ...queryFlow, model_tag: null }); | |||||
| } else { | |||||
| setActiveTag(item.path); | |||||
| setQueryFlow({ ...queryFlow, model_tag: item.path }); | |||||
| getModelLists({ ...queryFlow, model_tag: item.path }); | |||||
| } | } | ||||
| // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| // getDatasetlist() | // getDatasetlist() | ||||
| // }) | // }) | ||||
| }; | }; | ||||
| const routeToIntro=(e,record)=>{ | |||||
| e.stopPropagation() | |||||
| const routeToIntro = (e, record) => { | |||||
| e.stopPropagation(); | |||||
| console.log(record); | console.log(record); | ||||
| navgite({pathname:`/dataset/modelIntro/${record.id}` }); | |||||
| } | |||||
| navgite({ pathname: `/dataset/modelIntro/${record.id}` }); | |||||
| }; | |||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', errorInfo); | console.log('Failed:', errorInfo); | ||||
| }; | }; | ||||
| useEffect(()=>{ | |||||
| getAssetIconList(iconParams) | |||||
| getModelLists(queryFlow) | |||||
| return ()=>{ | |||||
| } | |||||
| },[]) | |||||
| return (<> | |||||
| <div className={Styles.datasetCneterBox}> | |||||
| <div className={Styles.datasetCneterLeftBox}> | |||||
| <div className={Styles.leftContentBox}> | |||||
| <Search | |||||
| placeholder="搜索" | |||||
| allowClear | |||||
| onSearch={onSearch} | |||||
| style={{ | |||||
| width: 300, | |||||
| marginBottom:'15px', | |||||
| }} | |||||
| /> | |||||
| <div className={Styles.itemTitle}>模型框架</div> | |||||
| <div className={Styles.itemBox}> | |||||
| {datasetTypeList&&datasetTypeList.length>0?datasetTypeList.map(item=>{return <div > | |||||
| <div className={[Styles.messageBox, item.path===activeType?Styles.active:null].join(' ')} onClick={(e)=>{chooseModelType(e, item)}}> | |||||
| <img className={Styles.ptIcon} style={{width:'22px'}} src={`/assets/images/model/${item.path}.png`} alt="" /> | |||||
| <img className={Styles.hoverIcon} style={{width:'22px'}} src={`/assets/images/model/${item.path}-hover.png`} alt="" /> | |||||
| <span className={Styles.messageText} onClick={(e)=>{chooseModelTag(e, item)}}>{item.name}</span> | |||||
| useEffect(() => { | |||||
| getAssetIconList(iconParams); | |||||
| getModelLists(queryFlow); | |||||
| return () => {}; | |||||
| }, []); | |||||
| return ( | |||||
| <> | |||||
| <div className={Styles.datasetCneterBox}> | |||||
| <div className={Styles.datasetCneterLeftBox}> | |||||
| <div className={Styles.leftContentBox}> | |||||
| <Search | |||||
| placeholder="搜索" | |||||
| allowClear | |||||
| onSearch={onSearch} | |||||
| style={{ | |||||
| width: 300, | |||||
| marginBottom: '15px', | |||||
| }} | |||||
| /> | |||||
| <div className={Styles.itemTitle}>模型框架</div> | |||||
| <div className={Styles.itemBox}> | |||||
| {datasetTypeList && datasetTypeList.length > 0 | |||||
| ? datasetTypeList.map((item) => { | |||||
| return ( | |||||
| <div> | |||||
| <div | |||||
| className={[ | |||||
| Styles.messageBox, | |||||
| item.path === activeType ? Styles.active : null, | |||||
| ].join(' ')} | |||||
| onClick={(e) => { | |||||
| chooseModelType(e, item); | |||||
| }} | |||||
| > | |||||
| <img | |||||
| className={Styles.ptIcon} | |||||
| style={{ width: '22px' }} | |||||
| src={`/assets/images/model/${item.path}.png`} | |||||
| alt="" | |||||
| /> | |||||
| <img | |||||
| className={Styles.hoverIcon} | |||||
| style={{ width: '22px' }} | |||||
| src={`/assets/images/model/${item.path}-hover.png`} | |||||
| alt="" | |||||
| /> | |||||
| <span | |||||
| className={Styles.messageText} | |||||
| onClick={(e) => { | |||||
| chooseModelTag(e, item); | |||||
| }} | |||||
| > | |||||
| {item.name} | |||||
| </span> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }) | |||||
| : ''} | |||||
| </div> | |||||
| <div className={Styles.itemTitle}>模型能力</div> | |||||
| <div className={Styles.itemBox}> | |||||
| {datasetDirectionList && datasetDirectionList.length > 0 | |||||
| ? datasetDirectionList.map((item) => { | |||||
| return ( | |||||
| <div> | |||||
| <div | |||||
| className={[ | |||||
| Styles.messageBox, | |||||
| item.path === activeTag ? Styles.active : null, | |||||
| ].join(' ')} | |||||
| onClick={(e) => { | |||||
| chooseModelTag(e, item); | |||||
| }} | |||||
| > | |||||
| <img | |||||
| className={Styles.ptIcon} | |||||
| style={{ width: '22px' }} | |||||
| src={`/assets/images/model/${item.path}.png`} | |||||
| alt="" | |||||
| /> | |||||
| <img | |||||
| className={Styles.hoverIcon} | |||||
| style={{ width: '22px' }} | |||||
| src={`/assets/images/model/${item.path}-hover.png`} | |||||
| alt="" | |||||
| /> | |||||
| <span className={Styles.messageText}>{item.name}</span> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }) | |||||
| : ''} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className={Styles.datasetCneterRightBox}> | |||||
| <div className={Styles.dataSource}> | |||||
| <span>数据总数:{total}个</span> | |||||
| <div> | |||||
| <Search | |||||
| placeholder="按模型名称筛选" | |||||
| allowClear | |||||
| onSearch={nameSearch} | |||||
| style={{ | |||||
| width: 300, | |||||
| }} | |||||
| /> | |||||
| <Button | |||||
| type="primary" | |||||
| className={Styles.plusButton} | |||||
| onClick={showModal} | |||||
| icon={<PlusCircleOutlined style={{ color: '#1664ff' }} />} | |||||
| > | |||||
| 模型注册 | |||||
| </Button> | |||||
| </div> | |||||
| </div> | </div> | ||||
| </div>}):''} | |||||
| </div> | |||||
| <div className={Styles.itemTitle}>模型能力</div> | |||||
| <div className={Styles.itemBox}> | |||||
| {datasetDirectionList&&datasetDirectionList.length>0?datasetDirectionList.map(item=>{return <div > | |||||
| <div className={[Styles.messageBox, item.path===activeTag?Styles.active:null].join(' ')} onClick={(e)=>{chooseModelTag(e, item)}}> | |||||
| <img className={Styles.ptIcon} style={{width:'22px'}} src={`/assets/images/model/${item.path}.png`} alt="" /> | |||||
| <img className={Styles.hoverIcon} style={{width:'22px'}} src={`/assets/images/model/${item.path}-hover.png`} alt="" /> | |||||
| <span className={Styles.messageText} >{item.name}</span> | |||||
| <div className={Styles.dataContent}> | |||||
| {datasetList && datasetList.length > 0 | |||||
| ? datasetList.map((item) => { | |||||
| return ( | |||||
| <div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}> | |||||
| <div className={Styles.itemText}>{item.name}</div> | |||||
| <div className={Styles.itemTime}> | |||||
| <span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span> | |||||
| </div> | |||||
| <div className={Styles.itemIcon}> | |||||
| <img | |||||
| style={{ width: '17px', marginRight: '3px' }} | |||||
| src={`/assets/images/upload-icon.png`} | |||||
| alt="" | |||||
| /> | |||||
| <span>1582</span> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }) | |||||
| : ''} | |||||
| {/* <Select.Option value="demo">Demo</Select.Option> */} | |||||
| </div> | </div> | ||||
| </div>}):''} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className={Styles.datasetCneterRightBox}> | |||||
| <div className={Styles.dataSource}> | |||||
| <span>数据总数:{total}个</span> | |||||
| <div> | |||||
| <Search | |||||
| placeholder="按模型名称筛选" | |||||
| allowClear | |||||
| onSearch={nameSearch} | |||||
| style={{ | |||||
| width: 300, | |||||
| }} | |||||
| /> | |||||
| <Button type="primary" className={Styles.plusButton} onClick={showModal} icon = {<PlusCircleOutlined style={{color:'#1664ff'}} />}> | |||||
| 模型注册 | |||||
| </Button> | |||||
| <Pagination size="small" total={total} showSizeChanger showQuickJumper /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className={Styles.dataContent}> | |||||
| {datasetList&&datasetList.length>0?datasetList.map(item=>{return <div className={Styles.dataItem} onClick={(e)=>routeToIntro(e,item)}> | |||||
| <div className={Styles.itemText}>{item.name}</div> | |||||
| <div className={Styles.itemTime}><span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span></div> | |||||
| <div className={Styles.itemIcon}><img style={{width:'17px',marginRight:'3px'}} src={`/assets/images/upload-icon.png`} alt="" /><span>1582</span></div> | |||||
| </div>}):''} | |||||
| {/* <Select.Option value="demo">Demo</Select.Option> */} | |||||
| </div> | |||||
| <Pagination | |||||
| size="small" | |||||
| total={total} | |||||
| showSizeChanger | |||||
| showQuickJumper | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| <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', | |||||
| form: 'form', | |||||
| }} onCancel={handleCancel}> | |||||
| <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', | |||||
| form: 'form', | |||||
| }} | |||||
| onCancel={handleCancel} | |||||
| > | |||||
| <Form | <Form | ||||
| name="form" | name="form" | ||||
| form={form} | form={form} | ||||
| @@ -243,73 +314,74 @@ const PublicData= React.FC = () => { | |||||
| <Form.Item | <Form.Item | ||||
| label="模型名称" | label="模型名称" | ||||
| name="name" | name="name" | ||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| rules={ | |||||
| [ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ] | |||||
| } | |||||
| > | > | ||||
| <Input placeholder="请输入模型名称"/> | |||||
| <Input placeholder="请输入模型名称" /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| label="模型描述" | label="模型描述" | ||||
| name="description" | name="description" | ||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| rules={ | |||||
| [ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ] | |||||
| } | |||||
| > | > | ||||
| <Input placeholder="请输入模型描述"/> | |||||
| <Input placeholder="请输入模型描述" /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item label="可见范围" name="available_range"> | <Form.Item label="可见范围" name="available_range"> | ||||
| <Radio.Group> | |||||
| <Radio value="0">仅自己可见</Radio> | |||||
| <Radio value="1">工作空间可见</Radio> | |||||
| </Radio.Group> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| <Radio.Group> | |||||
| <Radio value="0">仅自己可见</Radio> | |||||
| <Radio value="1">工作空间可见</Radio> | |||||
| </Radio.Group> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="模型框架" | label="模型框架" | ||||
| name="model_type" | name="model_type" | ||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| rules={ | |||||
| [ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ] | |||||
| } | |||||
| > | > | ||||
| <Select | |||||
| allowClear | |||||
| placeholder="请选择模型类型" | |||||
| options={[]} | |||||
| /> | |||||
| <Select allowClear placeholder="请选择模型类型" options={[]} /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | |||||
| <Form.Item | |||||
| label="模型能力" | label="模型能力" | ||||
| name="model_tag" | name="model_tag" | ||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| rules={ | |||||
| [ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ] | |||||
| } | |||||
| > | > | ||||
| <Select | |||||
| allowClear | |||||
| placeholder="请选择模型标签" | |||||
| options={[]} | |||||
| /> | |||||
| <Select allowClear placeholder="请选择模型标签" options={[]} /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item label="模型文件" name="dataset_version_vos"> | <Form.Item label="模型文件" name="dataset_version_vos"> | ||||
| <Upload {...props}> | |||||
| <Button icon={<UploadOutlined style={{color:'#1664ff'}} />}>上传文件</Button> | |||||
| </Upload> | |||||
| </Form.Item> | |||||
| <Upload {...props}> | |||||
| <Button icon={<UploadOutlined style={{ color: '#1664ff' }} />}>上传文件</Button> | |||||
| </Upload> | |||||
| </Form.Item> | |||||
| </Form> | </Form> | ||||
| </Modal> | </Modal> | ||||
| </>) | |||||
| </> | |||||
| ); | |||||
| }; | }; | ||||
| export default PublicData; | |||||
| export default PublicData; | |||||
| @@ -1,204 +1,263 @@ | |||||
| import React ,{useEffect,useState}from 'react'; | |||||
| import Styles from './index.less' | |||||
| import { Input, Space ,Button,Tabs,Pagination,Modal, Form,message, Radio,} from 'antd'; | |||||
| import { PlusOutlined,PlusCircleOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined ,CopyOutlined} from '@ant-design/icons'; | |||||
| import {getModelList,getAssetIcon} from '@/services/dataset/index.js' | |||||
| const { Search } = Input; | |||||
| import { useNavigate} from 'react-router-dom'; | |||||
| import { getAssetIcon, getModelList } from '@/services/dataset/index.js'; | |||||
| import { Form, Input, Modal, Pagination, Radio } from 'antd'; | |||||
| import moment from 'moment'; | import moment from 'moment'; | ||||
| const leftdataList=[1,2,3] | |||||
| import { useEffect, useState } from 'react'; | |||||
| import { useNavigate } from 'react-router-dom'; | |||||
| import Styles from './index.less'; | |||||
| const { Search } = Input; | |||||
| const leftdataList = [1, 2, 3]; | |||||
| const PublicData= React.FC = () => { | |||||
| const [queryFlow,setQueryFlow]=useState({ | |||||
| page:0, | |||||
| size:10, | |||||
| name:null, | |||||
| available_range:1 | |||||
| const PublicData = () => { | |||||
| const [queryFlow, setQueryFlow] = useState({ | |||||
| page: 0, | |||||
| size: 10, | |||||
| name: null, | |||||
| available_range: 1, | |||||
| }); | }); | ||||
| const [iconParams,setIconParams]=useState({ | |||||
| name:null, | |||||
| page:0, | |||||
| size:10000 | |||||
| }) | |||||
| const [activeType,setActiveType]=useState(null) | |||||
| const [activeTag,setActiveTag]=useState(null) | |||||
| const [datasetTypeList,setDatasetTypeList]=useState([]) | |||||
| const [datasetDirectionList,setDatasetDirectionList]=useState([]) | |||||
| const navgite=useNavigate(); | |||||
| const [isModalOpen,setIsModalOpen]=useState(false) | |||||
| const [datasetList,setDatasetList]=useState([]); | |||||
| const [total,setTotal]=useState(0); | |||||
| const [iconParams, setIconParams] = useState({ | |||||
| name: null, | |||||
| page: 0, | |||||
| size: 10000, | |||||
| }); | |||||
| const [activeType, setActiveType] = useState(null); | |||||
| const [activeTag, setActiveTag] = useState(null); | |||||
| const [datasetTypeList, setDatasetTypeList] = useState([]); | |||||
| const [datasetDirectionList, setDatasetDirectionList] = useState([]); | |||||
| const navgite = useNavigate(); | |||||
| const [isModalOpen, setIsModalOpen] = useState(false); | |||||
| const [datasetList, setDatasetList] = useState([]); | |||||
| const [total, setTotal] = useState(0); | |||||
| const [form] = Form.useForm(); | const [form] = Form.useForm(); | ||||
| const [dialogTitle, setDialogTitle] = useState('新建数据'); | const [dialogTitle, setDialogTitle] = useState('新建数据'); | ||||
| const getModelLists=(queryFlow)=>{ | |||||
| getModelList(queryFlow).then(ret=>{ | |||||
| const getModelLists = (queryFlow) => { | |||||
| getModelList(queryFlow).then((ret) => { | |||||
| console.log(ret); | console.log(ret); | ||||
| if(ret.code==200){ | |||||
| setDatasetList(ret.data.content) | |||||
| setTotal(ret.data.totalElements) | |||||
| if (ret.code == 200) { | |||||
| setDatasetList(ret.data.content); | |||||
| setTotal(ret.data.totalElements); | |||||
| } | } | ||||
| }) | |||||
| } | |||||
| }); | |||||
| }; | |||||
| const showModal = () => { | const showModal = () => { | ||||
| form.resetFields() | |||||
| setDialogTitle('新建数据集') | |||||
| form.resetFields(); | |||||
| setDialogTitle('新建数据集'); | |||||
| setIsModalOpen(true); | setIsModalOpen(true); | ||||
| }; | }; | ||||
| const nameSearch=(values)=>{ | |||||
| const nameSearch = (values) => { | |||||
| console.log(values); | console.log(values); | ||||
| getModelLists({...queryFlow,name:values}) | |||||
| } | |||||
| const getAssetIconList=(params)=>{ | |||||
| getAssetIcon(params).then(ret=>{ | |||||
| getModelLists({ ...queryFlow, name: values }); | |||||
| }; | |||||
| const getAssetIconList = (params) => { | |||||
| getAssetIcon(params).then((ret) => { | |||||
| console.log(ret); | console.log(ret); | ||||
| if(ret.code==200&&ret.data.content&&ret.data.content.length>0){ | |||||
| setDatasetTypeList(ret.data.content.filter(item=>item.category_id==3)) | |||||
| setDatasetDirectionList(ret.data.content.filter(item=>item.category_id==4)) | |||||
| if (ret.code == 200 && ret.data.content && ret.data.content.length > 0) { | |||||
| setDatasetTypeList(ret.data.content.filter((item) => item.category_id == 3)); | |||||
| setDatasetDirectionList(ret.data.content.filter((item) => item.category_id == 4)); | |||||
| } else { | |||||
| setDatasetTypeList([]); | |||||
| setDatasetDirectionList([]); | |||||
| } | } | ||||
| else{ | |||||
| setDatasetTypeList([]) | |||||
| setDatasetDirectionList([]) | |||||
| } | |||||
| }) | |||||
| } | |||||
| const onSearch=(values)=>{ | |||||
| }); | |||||
| }; | |||||
| const onSearch = (values) => { | |||||
| console.log(values); | console.log(values); | ||||
| getAssetIconList({...iconParams,name:values}) | |||||
| } | |||||
| getAssetIconList({ ...iconParams, name: values }); | |||||
| }; | |||||
| const handleOk = () => { | const handleOk = () => { | ||||
| console.log(1111); | |||||
| console.log(1111); | |||||
| setIsModalOpen(false); | setIsModalOpen(false); | ||||
| }; | }; | ||||
| const handleCancel = () => { | const handleCancel = () => { | ||||
| setIsModalOpen(false); | setIsModalOpen(false); | ||||
| }; | }; | ||||
| const chooseModelType=(val,item)=>{ | |||||
| console.log(val,item); | |||||
| if(item.path==queryFlow.model_type){ | |||||
| setActiveType('') | |||||
| setQueryFlow({...queryFlow,model_type:null}) | |||||
| getModelLists({...queryFlow,model_type:null}) | |||||
| const chooseModelType = (val, item) => { | |||||
| console.log(val, item); | |||||
| if (item.path == queryFlow.model_type) { | |||||
| setActiveType(''); | |||||
| setQueryFlow({ ...queryFlow, model_type: null }); | |||||
| getModelLists({ ...queryFlow, model_type: null }); | |||||
| } else { | |||||
| setActiveType(item.path); | |||||
| setQueryFlow({ ...queryFlow, model_type: item.path }); | |||||
| getModelLists({ ...queryFlow, model_type: item.path }); | |||||
| } | } | ||||
| else{ | |||||
| setActiveType(item.path) | |||||
| setQueryFlow({...queryFlow,model_type:item.path}) | |||||
| getModelLists({...queryFlow,model_type:item.path}) | |||||
| } | |||||
| // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| // getDatasetlist() | // getDatasetlist() | ||||
| // }) | // }) | ||||
| }; | }; | ||||
| const chooseModelTag=(val,item)=>{ | |||||
| if(item.path==queryFlow.model_tag){ | |||||
| setActiveTag('') | |||||
| setQueryFlow({...queryFlow,model_tag:null}) | |||||
| getModelLists({...queryFlow,model_tag:null}) | |||||
| } | |||||
| else{ | |||||
| setActiveTag(item.path) | |||||
| setQueryFlow({...queryFlow,model_tag:item.path}) | |||||
| getModelLists({...queryFlow,model_tag:item.path}) | |||||
| const chooseModelTag = (val, item) => { | |||||
| if (item.path == queryFlow.model_tag) { | |||||
| setActiveTag(''); | |||||
| setQueryFlow({ ...queryFlow, model_tag: null }); | |||||
| getModelLists({ ...queryFlow, model_tag: null }); | |||||
| } else { | |||||
| setActiveTag(item.path); | |||||
| setQueryFlow({ ...queryFlow, model_tag: item.path }); | |||||
| getModelLists({ ...queryFlow, model_tag: item.path }); | |||||
| } | } | ||||
| // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | // setQueryFlow({...queryFlow,data_type:item.path},()=>{ | ||||
| // getDatasetlist() | // getDatasetlist() | ||||
| // }) | // }) | ||||
| }; | }; | ||||
| const onFinish = (values) => { | |||||
| }; | |||||
| const routeToIntro=(e,record)=>{ | |||||
| e.stopPropagation() | |||||
| console.log(record); | |||||
| navgite({pathname:`/dataset/modelIntro/${record.id}` }); | |||||
| } | |||||
| const onFinish = (values) => {}; | |||||
| const routeToIntro = (e, record) => { | |||||
| e.stopPropagation(); | |||||
| console.log(record); | |||||
| navgite({ pathname: `/dataset/modelIntro/${record.id}` }); | |||||
| }; | |||||
| const onFinishFailed = (errorInfo) => { | const onFinishFailed = (errorInfo) => { | ||||
| console.log('Failed:', errorInfo); | console.log('Failed:', errorInfo); | ||||
| }; | }; | ||||
| useEffect(()=>{ | |||||
| getAssetIconList(iconParams) | |||||
| getModelLists(queryFlow) | |||||
| return ()=>{ | |||||
| } | |||||
| },[]) | |||||
| return (<> | |||||
| <div className={Styles.datasetCneterBox}> | |||||
| <div className={Styles.datasetCneterLeftBox}> | |||||
| <div className={Styles.leftContentBox}> | |||||
| <Search | |||||
| placeholder="搜索" | |||||
| allowClear | |||||
| onSearch={onSearch} | |||||
| style={{ | |||||
| width: 300, | |||||
| marginBottom:'15px', | |||||
| }} | |||||
| /> | |||||
| <div className={Styles.itemTitle}>模型框架</div> | |||||
| <div className={Styles.itemBox}> | |||||
| {datasetTypeList&&datasetTypeList.length>0?datasetTypeList.map(item=>{return <div > | |||||
| <div className={[Styles.messageBox, item.path===activeType?Styles.active:null].join(' ')} onClick={(e)=>{chooseModelType(e, item)}}> | |||||
| <img className={Styles.ptIcon} style={{width:'22px'}} src={`/assets/images/model/${item.path}.png`} alt="" /> | |||||
| <img className={Styles.hoverIcon} style={{width:'22px'}} src={`/assets/images/model/${item.path}-hover.png`} alt="" /> | |||||
| <span className={Styles.messageText} >{item.name}</span> | |||||
| useEffect(() => { | |||||
| getAssetIconList(iconParams); | |||||
| getModelLists(queryFlow); | |||||
| return () => {}; | |||||
| }, []); | |||||
| return ( | |||||
| <> | |||||
| <div className={Styles.datasetCneterBox}> | |||||
| <div className={Styles.datasetCneterLeftBox}> | |||||
| <div className={Styles.leftContentBox}> | |||||
| <Search | |||||
| placeholder="搜索" | |||||
| allowClear | |||||
| onSearch={onSearch} | |||||
| style={{ | |||||
| width: 300, | |||||
| marginBottom: '15px', | |||||
| }} | |||||
| /> | |||||
| <div className={Styles.itemTitle}>模型框架</div> | |||||
| <div className={Styles.itemBox}> | |||||
| {datasetTypeList && datasetTypeList.length > 0 | |||||
| ? datasetTypeList.map((item) => { | |||||
| return ( | |||||
| <div> | |||||
| <div | |||||
| className={[ | |||||
| Styles.messageBox, | |||||
| item.path === activeType ? Styles.active : null, | |||||
| ].join(' ')} | |||||
| onClick={(e) => { | |||||
| chooseModelType(e, item); | |||||
| }} | |||||
| > | |||||
| <img | |||||
| className={Styles.ptIcon} | |||||
| style={{ width: '22px' }} | |||||
| src={`/assets/images/model/${item.path}.png`} | |||||
| alt="" | |||||
| /> | |||||
| <img | |||||
| className={Styles.hoverIcon} | |||||
| style={{ width: '22px' }} | |||||
| src={`/assets/images/model/${item.path}-hover.png`} | |||||
| alt="" | |||||
| /> | |||||
| <span className={Styles.messageText}>{item.name}</span> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }) | |||||
| : ''} | |||||
| </div> | |||||
| <div className={Styles.itemTitle}>模型能力</div> | |||||
| <div className={Styles.itemBox}> | |||||
| {datasetDirectionList && datasetDirectionList.length > 0 | |||||
| ? datasetDirectionList.map((item) => { | |||||
| return ( | |||||
| <div> | |||||
| <div | |||||
| className={[ | |||||
| Styles.messageBox, | |||||
| item.path === activeTag ? Styles.active : null, | |||||
| ].join(' ')} | |||||
| onClick={(e) => { | |||||
| chooseModelTag(e, item); | |||||
| }} | |||||
| > | |||||
| <img | |||||
| className={Styles.ptIcon} | |||||
| style={{ width: '22px' }} | |||||
| src={`/assets/images/model/${item.path}.png`} | |||||
| alt="" | |||||
| /> | |||||
| <img | |||||
| className={Styles.hoverIcon} | |||||
| style={{ width: '22px' }} | |||||
| src={`/assets/images/model/${item.path}-hover.png`} | |||||
| alt="" | |||||
| /> | |||||
| <span className={Styles.messageText}>{item.name}</span> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }) | |||||
| : ''} | |||||
| </div> | |||||
| </div> | </div> | ||||
| </div>}):''} | |||||
| </div> | |||||
| <div className={Styles.itemTitle}>模型能力</div> | |||||
| <div className={Styles.itemBox}> | |||||
| {datasetDirectionList&&datasetDirectionList.length>0?datasetDirectionList.map(item=>{return <div > | |||||
| <div className={[Styles.messageBox, item.path===activeTag?Styles.active:null].join(' ')} onClick={(e)=>{chooseModelTag(e, item)}}> | |||||
| <img className={Styles.ptIcon} style={{width:'22px'}} src={`/assets/images/model/${item.path}.png`} alt="" /> | |||||
| <img className={Styles.hoverIcon} style={{width:'22px'}} src={`/assets/images/model/${item.path}-hover.png`} alt="" /> | |||||
| <span className={Styles.messageText} >{item.name}</span> | |||||
| </div> | |||||
| <div className={Styles.datasetCneterRightBox}> | |||||
| <div className={Styles.dataSource}> | |||||
| <span>数据总数:{total}个</span> | |||||
| <div> | |||||
| <Search | |||||
| placeholder="按数据名称筛选" | |||||
| allowClear | |||||
| onSearch={nameSearch} | |||||
| style={{ | |||||
| width: 300, | |||||
| }} | |||||
| /> | |||||
| </div> | |||||
| </div> | </div> | ||||
| </div>}):''} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className={Styles.datasetCneterRightBox}> | |||||
| <div className={Styles.dataSource}> | |||||
| <span>数据总数:{total}个</span> | |||||
| <div> | |||||
| <Search | |||||
| placeholder="按数据名称筛选" | |||||
| allowClear | |||||
| onSearch={nameSearch} | |||||
| style={{ | |||||
| width: 300, | |||||
| }} | |||||
| /> | |||||
| <div className={Styles.dataContent}> | |||||
| {datasetList && datasetList.length > 0 | |||||
| ? datasetList.map((item) => { | |||||
| return ( | |||||
| <div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}> | |||||
| <div className={Styles.itemText}>{item.name}</div> | |||||
| <div className={Styles.itemTime}> | |||||
| <span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span> | |||||
| </div> | |||||
| <div className={Styles.itemIcon}> | |||||
| <img | |||||
| style={{ width: '17px', marginRight: '3px' }} | |||||
| src={`/assets/images/upload-icon.png`} | |||||
| alt="" | |||||
| /> | |||||
| <span>1582</span> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }) | |||||
| : ''} | |||||
| {/* <Select.Option value="demo">Demo</Select.Option> */} | |||||
| </div> | |||||
| <Pagination size="small" total={total} showSizeChanger showQuickJumper /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className={Styles.dataContent}> | |||||
| {datasetList&&datasetList.length>0?datasetList.map(item=>{return <div className={Styles.dataItem} onClick={(e)=>routeToIntro(e,item)}> | |||||
| <div className={Styles.itemText}>{item.name}</div> | |||||
| <div className={Styles.itemTime}><span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span></div> | |||||
| <div className={Styles.itemIcon}><img style={{width:'17px',marginRight:'3px'}} src={`/assets/images/upload-icon.png`} alt="" /><span>1582</span></div> | |||||
| </div>}):''} | |||||
| {/* <Select.Option value="demo">Demo</Select.Option> */} | |||||
| </div> | |||||
| <Pagination | |||||
| size="small" | |||||
| total={total} | |||||
| showSizeChanger | |||||
| showQuickJumper | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| <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', | |||||
| form: 'form', | |||||
| }} onCancel={handleCancel}> | |||||
| <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', | |||||
| form: 'form', | |||||
| }} | |||||
| onCancel={handleCancel} | |||||
| > | |||||
| <Form | <Form | ||||
| name="form" | name="form" | ||||
| form={form} | form={form} | ||||
| @@ -213,59 +272,68 @@ const PublicData= React.FC = () => { | |||||
| <Form.Item | <Form.Item | ||||
| label="数据名称" | label="数据名称" | ||||
| name="name" | name="name" | ||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| rules={ | |||||
| [ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ] | |||||
| } | |||||
| > | > | ||||
| <Input placeholder="请输入数据名称"/> | |||||
| <Input placeholder="请输入数据名称" /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| label="数据集版本" | label="数据集版本" | ||||
| name="data_type" | name="data_type" | ||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| rules={ | |||||
| [ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ] | |||||
| } | |||||
| > | > | ||||
| <Input placeholder="请输入数据集版本"/> | |||||
| <Input placeholder="请输入数据集版本" /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| label="数据描述" | label="数据描述" | ||||
| name="description" | name="description" | ||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| rules={ | |||||
| [ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ] | |||||
| } | |||||
| > | > | ||||
| <Input placeholder="请输入数据描述"/> | |||||
| <Input placeholder="请输入数据描述" /> | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item label="选择流水线" name="description1"> | <Form.Item label="选择流水线" name="description1"> | ||||
| <Radio.Group> | |||||
| <Radio value="0">仅自己可见</Radio> | |||||
| <Radio value="1">工作空间可见</Radio> | |||||
| </Radio.Group> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| <Radio.Group> | |||||
| <Radio value="0">仅自己可见</Radio> | |||||
| <Radio value="1">工作空间可见</Radio> | |||||
| </Radio.Group> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| label="数据标签" | label="数据标签" | ||||
| name="description3" | name="description3" | ||||
| rules={[ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ]} | |||||
| rules={ | |||||
| [ | |||||
| // { | |||||
| // required: true, | |||||
| // message: 'Please input your username!', | |||||
| // }, | |||||
| ] | |||||
| } | |||||
| > | > | ||||
| <Input placeholder="请输入数据标签" /> | <Input placeholder="请输入数据标签" /> | ||||
| </Form.Item> | </Form.Item> | ||||
| </Form> | </Form> | ||||
| </Modal> | </Modal> | ||||
| </>) | |||||
| </> | |||||
| ); | |||||
| }; | }; | ||||
| export default PublicData; | |||||
| export default PublicData; | |||||
| @@ -1,51 +1,42 @@ | |||||
| import { getUserInfo } from '@/services/session'; | |||||
| import { | import { | ||||
| ClusterOutlined, | ClusterOutlined, | ||||
| MailOutlined, | MailOutlined, | ||||
| ManOutlined, | |||||
| MobileOutlined, | |||||
| TeamOutlined, | TeamOutlined, | ||||
| UserOutlined, | UserOutlined, | ||||
| MobileOutlined, | |||||
| ManOutlined, | |||||
| } from '@ant-design/icons'; | } from '@ant-design/icons'; | ||||
| import { PageLoading } from '@ant-design/pro-components'; | |||||
| import { useRequest } from '@umijs/max'; | |||||
| import { Card, Col, Divider, List, Row } from 'antd'; | import { Card, Col, Divider, List, Row } from 'antd'; | ||||
| import React, { useState } from 'react'; | import React, { useState } from 'react'; | ||||
| import styles from './Center.less'; | import styles from './Center.less'; | ||||
| import AvatarCropper from './components/AvatarCropper'; | |||||
| import BaseInfo from './components/BaseInfo'; | import BaseInfo from './components/BaseInfo'; | ||||
| import ResetPassword from './components/ResetPassword'; | import ResetPassword from './components/ResetPassword'; | ||||
| import AvatarCropper from './components/AvatarCropper'; | |||||
| import { useRequest } from '@umijs/max'; | |||||
| import { getUserInfo } from '@/services/session'; | |||||
| import { PageLoading } from '@ant-design/pro-components'; | |||||
| const operationTabList = [ | const operationTabList = [ | ||||
| { | { | ||||
| key: 'base', | key: 'base', | ||||
| tab: ( | |||||
| <span> | |||||
| 基本资料 | |||||
| </span> | |||||
| ), | |||||
| tab: <span>基本资料</span>, | |||||
| }, | }, | ||||
| { | { | ||||
| key: 'password', | key: 'password', | ||||
| tab: ( | |||||
| <span> | |||||
| 重置密码 | |||||
| </span> | |||||
| ), | |||||
| tab: <span>重置密码</span>, | |||||
| }, | }, | ||||
| ]; | ]; | ||||
| export type tabKeyType = 'base' | 'password'; | export type tabKeyType = 'base' | 'password'; | ||||
| const Center: React.FC = () => { | const Center: React.FC = () => { | ||||
| const [tabKey, setTabKey] = useState<tabKeyType>('base'); | const [tabKey, setTabKey] = useState<tabKeyType>('base'); | ||||
| const [cropperModalOpen, setCropperModalOpen] = useState<boolean>(false); | const [cropperModalOpen, setCropperModalOpen] = useState<boolean>(false); | ||||
| // 获取用户信息 | // 获取用户信息 | ||||
| const { data: userInfo, loading } = useRequest(async () => { | const { data: userInfo, loading } = useRequest(async () => { | ||||
| return { data: await getUserInfo()}; | |||||
| return { data: await getUserInfo() }; | |||||
| }); | }); | ||||
| if (loading) { | if (loading) { | ||||
| return <div>loading...</div>; | return <div>loading...</div>; | ||||
| @@ -141,14 +132,15 @@ const Center: React.FC = () => { | |||||
| <div> | <div> | ||||
| <Row gutter={[16, 24]}> | <Row gutter={[16, 24]}> | ||||
| <Col lg={8} md={24}> | <Col lg={8} md={24}> | ||||
| <Card | |||||
| title="个人信息" | |||||
| bordered={false} | |||||
| loading={loading} | |||||
| > | |||||
| <Card title="个人信息" bordered={false} loading={loading}> | |||||
| {!loading && ( | {!loading && ( | ||||
| <div style={{ textAlign: "center"}}> | |||||
| <div className={styles.avatarHolder} onClick={()=>{setCropperModalOpen(true)}}> | |||||
| <div style={{ textAlign: 'center' }}> | |||||
| <div | |||||
| className={styles.avatarHolder} | |||||
| onClick={() => { | |||||
| setCropperModalOpen(true); | |||||
| }} | |||||
| > | |||||
| <img alt="" src={currentUser.avatar} /> | <img alt="" src={currentUser.avatar} /> | ||||
| </div> | </div> | ||||
| {renderUserInfo(currentUser)} | {renderUserInfo(currentUser)} | ||||
| @@ -188,7 +180,7 @@ const Center: React.FC = () => { | |||||
| </Row> | </Row> | ||||
| <AvatarCropper | <AvatarCropper | ||||
| onFinished={() => { | onFinished={() => { | ||||
| setCropperModalOpen(false); | |||||
| setCropperModalOpen(false); | |||||
| }} | }} | ||||
| open={cropperModalOpen} | open={cropperModalOpen} | ||||
| data={currentUser.avatar} | data={currentUser.avatar} | ||||
| @@ -0,0 +1,57 @@ | |||||
| import type { RequestConfig } from '@umijs/max'; | |||||
| import { message } from 'antd'; | |||||
| import { clearSessionToken, getAccessToken, getRefreshToken, getTokenExpireTime } from './access'; | |||||
| const checkRegion = 5 * 60 * 1000; | |||||
| /** | |||||
| * Umi Max 网络请求配置 | |||||
| * @doc https://umijs.org/docs/max/request#配置 | |||||
| */ | |||||
| export const requestConfig: RequestConfig = { | |||||
| errorConfig: {}, | |||||
| requestInterceptors: [ | |||||
| (url: any, options: { headers: any }) => { | |||||
| const headers = options.headers ? options.headers : []; | |||||
| console.log('request ====>:', url); | |||||
| const authHeader = headers['Authorization']; | |||||
| const isToken = headers['isToken']; | |||||
| if (!authHeader && isToken !== false) { | |||||
| const expireTime = getTokenExpireTime(); | |||||
| if (expireTime) { | |||||
| const left = Number(expireTime) - new Date().getTime(); | |||||
| const refreshToken = getRefreshToken(); | |||||
| if (left < checkRegion && refreshToken) { | |||||
| if (left < 0) { | |||||
| clearSessionToken(); | |||||
| } | |||||
| } else { | |||||
| const accessToken = getAccessToken(); | |||||
| if (accessToken) { | |||||
| headers['Authorization'] = `Bearer ${accessToken}`; | |||||
| } | |||||
| } | |||||
| } else { | |||||
| clearSessionToken(); | |||||
| } | |||||
| } | |||||
| return { url, options }; | |||||
| }, | |||||
| ], | |||||
| responseInterceptors: [ | |||||
| (response: any) => | |||||
| { | |||||
| const { status, data } = response; | |||||
| if (status && status >= 200 && status < 300 && data && data.code === 200) { | |||||
| return response | |||||
| } else { | |||||
| if (data && data.msg) { | |||||
| message.error(data.msg); | |||||
| } else { | |||||
| message.error("请求失败"); | |||||
| } | |||||
| return Promise.reject(response) | |||||
| } | |||||
| }, | |||||
| ], | |||||
| }; | |||||
| @@ -1,109 +0,0 @@ | |||||
| import type { RequestOptions } from '@@/plugin-request/request'; | |||||
| import type { RequestConfig } from '@umijs/max'; | |||||
| import { message, notification } from 'antd'; | |||||
| // 错误处理方案: 错误类型 | |||||
| enum ErrorShowType { | |||||
| SILENT = 0, | |||||
| WARN_MESSAGE = 1, | |||||
| ERROR_MESSAGE = 2, | |||||
| NOTIFICATION = 3, | |||||
| REDIRECT = 9, | |||||
| } | |||||
| // 与后端约定的响应数据格式 | |||||
| interface ResponseStructure { | |||||
| success: boolean; | |||||
| data: any; | |||||
| errorCode?: number; | |||||
| errorMessage?: string; | |||||
| showType?: ErrorShowType; | |||||
| } | |||||
| /** | |||||
| * @name 错误处理 | |||||
| * pro 自带的错误处理, 可以在这里做自己的改动 | |||||
| * @doc https://umijs.org/docs/max/request#配置 | |||||
| */ | |||||
| export const errorConfig: RequestConfig = { | |||||
| // 错误处理: umi@3 的错误处理方案。 | |||||
| errorConfig: { | |||||
| // 错误抛出 | |||||
| errorThrower: (res) => { | |||||
| const { success, data, errorCode, errorMessage, showType } = | |||||
| res as unknown as ResponseStructure; | |||||
| if (!success) { | |||||
| const error: any = new Error(errorMessage); | |||||
| error.name = 'BizError'; | |||||
| error.info = { errorCode, errorMessage, showType, data }; | |||||
| throw error; // 抛出自制的错误 | |||||
| } | |||||
| }, | |||||
| // 错误接收及处理 | |||||
| errorHandler: (error: any, opts: any) => { | |||||
| if (opts?.skipErrorHandler) throw error; | |||||
| // 我们的 errorThrower 抛出的错误。 | |||||
| if (error.name === 'BizError') { | |||||
| const errorInfo: ResponseStructure | undefined = error.info; | |||||
| if (errorInfo) { | |||||
| const { errorMessage, errorCode } = errorInfo; | |||||
| switch (errorInfo.showType) { | |||||
| case ErrorShowType.SILENT: | |||||
| // do nothing | |||||
| break; | |||||
| case ErrorShowType.WARN_MESSAGE: | |||||
| message.warning(errorMessage); | |||||
| break; | |||||
| case ErrorShowType.ERROR_MESSAGE: | |||||
| message.error(errorMessage); | |||||
| break; | |||||
| case ErrorShowType.NOTIFICATION: | |||||
| notification.open({ | |||||
| description: errorMessage, | |||||
| message: errorCode, | |||||
| }); | |||||
| break; | |||||
| case ErrorShowType.REDIRECT: | |||||
| // TODO: redirect | |||||
| break; | |||||
| default: | |||||
| message.error(errorMessage); | |||||
| } | |||||
| } | |||||
| } else if (error.response) { | |||||
| // Axios 的错误 | |||||
| // 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围 | |||||
| message.error(`Response status:${error.response.status}`); | |||||
| } else if (error.request) { | |||||
| // 请求已经成功发起,但没有收到响应 | |||||
| // \`error.request\` 在浏览器中是 XMLHttpRequest 的实例, | |||||
| // 而在node.js中是 http.ClientRequest 的实例 | |||||
| message.error('None response! Please retry.'); | |||||
| } else { | |||||
| // 发送请求时出了点问题 | |||||
| message.error('Request error, please retry.'); | |||||
| } | |||||
| }, | |||||
| }, | |||||
| // 请求拦截器 | |||||
| requestInterceptors: [ | |||||
| (config: RequestOptions) => { | |||||
| // 拦截请求配置,进行个性化处理。 | |||||
| const url = config?.url?.concat('?token = 123'); | |||||
| return { ...config, url }; | |||||
| }, | |||||
| ], | |||||
| // 响应拦截器 | |||||
| responseInterceptors: [ | |||||
| (response) => { | |||||
| // 拦截响应数据,进行个性化处理 | |||||
| const { data } = response as unknown as ResponseStructure; | |||||
| if (data?.success === false) { | |||||
| message.error('请求失败!'); | |||||
| } | |||||
| return response; | |||||
| }, | |||||
| ], | |||||
| }; | |||||
| @@ -1,87 +1,102 @@ | |||||
| import { request } from '@umijs/max'; | |||||
| import { request } from '@umijs/max'; | |||||
| // 查询实验列表 | // 查询实验列表 | ||||
| export function getExperiment(params) { | export function getExperiment(params) { | ||||
| return request(`/api/mmp/experiment`, { | |||||
| method: 'GET', | |||||
| params | |||||
| }); | |||||
| } | |||||
| return request(`/api/mmp/experiment`, { | |||||
| method: 'GET', | |||||
| params, | |||||
| }); | |||||
| } | |||||
| // 运行实验 | // 运行实验 | ||||
| export function runExperiments(id) { | |||||
| return request('/api/mmp/experiment/experiments/'+id, { | |||||
| method: 'PUT', | |||||
| headers: { | |||||
| 'Content-Type': 'application/json;charset=UTF-8', | |||||
| }, | |||||
| }); | |||||
| } | |||||
| export function runExperiments(id) { | |||||
| return request('/api/mmp/experiment/experiments/' + id, { | |||||
| method: 'PUT', | |||||
| headers: { | |||||
| 'Content-Type': 'application/json;charset=UTF-8', | |||||
| }, | |||||
| }); | |||||
| } | |||||
| // 根据id查询实验 | // 根据id查询实验 | ||||
| export function getExperimentById(id) { | export function getExperimentById(id) { | ||||
| return request(`/api/mmp/experiment/${id}`, { | |||||
| method: 'GET', | |||||
| }); | |||||
| } | |||||
| return request(`/api/mmp/experiment/${id}`, { | |||||
| method: 'GET', | |||||
| }); | |||||
| } | |||||
| // 根据id删除实验 | // 根据id删除实验 | ||||
| export function deleteExperimentById(id) { | export function deleteExperimentById(id) { | ||||
| return request(`/api/mmp/experiment/${id}`, { | return request(`/api/mmp/experiment/${id}`, { | ||||
| method: 'DELETE', | |||||
| method: 'DELETE', | |||||
| }); | }); | ||||
| } | } | ||||
| // 根据id查询实验实例 | // 根据id查询实验实例 | ||||
| export function getQueryByExperimentId(id) { | export function getQueryByExperimentId(id) { | ||||
| return request(`/api/mmp/experimentIns/queryByExperimentId/${id}`, { | |||||
| method: 'GET', | |||||
| }); | |||||
| } | |||||
| return request(`/api/mmp/experimentIns/queryByExperimentId/${id}`, { | |||||
| method: 'GET', | |||||
| }); | |||||
| } | |||||
| // 根据id删除实验实例 | // 根据id删除实验实例 | ||||
| export function deleteQueryByExperimentInsId(id) { | export function deleteQueryByExperimentInsId(id) { | ||||
| return request(`/api/mmp/experimentIns/${id}`, { | return request(`/api/mmp/experimentIns/${id}`, { | ||||
| method: 'DELETE', | |||||
| method: 'DELETE', | |||||
| }); | }); | ||||
| } | } | ||||
| // 根据id终止实验实例 | // 根据id终止实验实例 | ||||
| export function putQueryByExperimentInsId(id) { | export function putQueryByExperimentInsId(id) { | ||||
| return request(`/api/mmp/experimentIns/${id}`, { | return request(`/api/mmp/experimentIns/${id}`, { | ||||
| method: 'PUT', | |||||
| method: 'PUT', | |||||
| }); | |||||
| } | |||||
| // 查询实验实例实时日志 | |||||
| export function getQueryByExperimentLog(data) { | |||||
| return request("/api/mmp/experimentIns/realTimeLog/", { | |||||
| method: 'POST', | |||||
| data, | |||||
| }); | }); | ||||
| } | } | ||||
| // 根据id查询查询日志 | |||||
| export function getQueryByExperimentLog(params) { | |||||
| return request(`/api/mmp/experimentIns/log/`, { | |||||
| method: 'GET', | |||||
| params | |||||
| }); | |||||
| } | |||||
| // 根据id查询输出结果 | |||||
| // 查询实例节点结果 | |||||
| export function getNodeResult(params) { | export function getNodeResult(params) { | ||||
| return request(`/api/mmp/experimentIns/nodeResult/`, { | return request(`/api/mmp/experimentIns/nodeResult/`, { | ||||
| method: 'GET', | |||||
| params | |||||
| method: 'GET', | |||||
| params, | |||||
| }); | |||||
| } | |||||
| // 获取pod实时日志请求,运行完成的 | |||||
| export function getExperimentPodsLog(params) { | |||||
| return request("/api/mmp/experimentIns/pods/log", { | |||||
| method: 'GET', | |||||
| params, | |||||
| }); | |||||
| } | |||||
| // 获取pod实时日志请求,运行中的 | |||||
| export function getExperimentPodsRealtimeLog(data) { | |||||
| return request("/api/mmp/experimentIns/pods/realTimeLog", { | |||||
| method: 'POST', | |||||
| data, | |||||
| }); | }); | ||||
| } | } | ||||
| // 根据实例查询详情 | // 根据实例查询详情 | ||||
| export function getExperimentIns(id) { | export function getExperimentIns(id) { | ||||
| return request(`/api/mmp/experimentIns/${id}`, { | |||||
| method: 'GET', | |||||
| }); | |||||
| } | |||||
| return request(`/api/mmp/experimentIns/${id}`, { | |||||
| method: 'GET', | |||||
| }); | |||||
| } | |||||
| // 新增实验 | // 新增实验 | ||||
| export function postExperiment(data) { | |||||
| return request(`/api/mmp/experiment`, { | |||||
| method: 'POST', | |||||
| headers: { | |||||
| 'Content-Type': 'application/json;charset=UTF-8', | |||||
| }, | |||||
| data | |||||
| }); | |||||
| } | |||||
| export function postExperiment(data) { | |||||
| return request(`/api/mmp/experiment`, { | |||||
| method: 'POST', | |||||
| headers: { | |||||
| 'Content-Type': 'application/json;charset=UTF-8', | |||||
| }, | |||||
| data, | |||||
| }); | |||||
| } | |||||
| // 编辑实验 | // 编辑实验 | ||||
| export function putExperiment(data) { | |||||
| return request(`/api/mmp/experiment`, { | |||||
| method: 'PUT', | |||||
| headers: { | |||||
| 'Content-Type': 'application/json;charset=UTF-8', | |||||
| }, | |||||
| data | |||||
| }); | |||||
| } | |||||
| export function putExperiment(data) { | |||||
| return request(`/api/mmp/experiment`, { | |||||
| method: 'PUT', | |||||
| headers: { | |||||
| 'Content-Type': 'application/json;charset=UTF-8', | |||||
| }, | |||||
| data, | |||||
| }); | |||||
| } | |||||
| @@ -3,7 +3,6 @@ import { MenuDataItem } from '@ant-design/pro-components'; | |||||
| import { request } from '@umijs/max'; | import { request } from '@umijs/max'; | ||||
| import React, { lazy } from 'react'; | import React, { lazy } from 'react'; | ||||
| let remoteMenu: any = null; | let remoteMenu: any = null; | ||||
| export function getRemoteMenu() { | export function getRemoteMenu() { | ||||
| @@ -14,7 +13,6 @@ export function setRemoteMenu(data: any) { | |||||
| remoteMenu = data; | remoteMenu = data; | ||||
| } | } | ||||
| function patchRouteItems(route: any, menu: any, parentPath: string) { | function patchRouteItems(route: any, menu: any, parentPath: string) { | ||||
| for (const menuItem of menu) { | for (const menuItem of menu) { | ||||
| if (menuItem.component === 'Layout' || menuItem.component === 'ParentView') { | if (menuItem.component === 'Layout' || menuItem.component === 'ParentView') { | ||||
| @@ -28,19 +26,19 @@ function patchRouteItems(route: any, menu: any, parentPath: string) { | |||||
| } | } | ||||
| } | } | ||||
| if (!hasItem) { | if (!hasItem) { | ||||
| newItem = { | |||||
| newItem = { | |||||
| path: menuItem.path, | path: menuItem.path, | ||||
| routes: [], | routes: [], | ||||
| children: [] | |||||
| } | |||||
| route.routes.push(newItem) | |||||
| children: [], | |||||
| }; | |||||
| route.routes.push(newItem); | |||||
| } | } | ||||
| patchRouteItems(newItem, menuItem.routes, parentPath + menuItem.path + '/'); | patchRouteItems(newItem, menuItem.routes, parentPath + menuItem.path + '/'); | ||||
| } | } | ||||
| } else { | } else { | ||||
| const names: string[] = menuItem.component.split('/'); | const names: string[] = menuItem.component.split('/'); | ||||
| let path = ''; | let path = ''; | ||||
| names.forEach(name => { | |||||
| names.forEach((name) => { | |||||
| if (path.length > 0) { | if (path.length > 0) { | ||||
| path += '/'; | path += '/'; | ||||
| } | } | ||||
| @@ -49,9 +47,9 @@ function patchRouteItems(route: any, menu: any, parentPath: string) { | |||||
| } else { | } else { | ||||
| path += name; | path += name; | ||||
| } | } | ||||
| }) | |||||
| }); | |||||
| if (!path.endsWith('.tsx')) { | if (!path.endsWith('.tsx')) { | ||||
| path += '.tsx' | |||||
| path += '.tsx'; | |||||
| } | } | ||||
| if (route.routes === undefined) { | if (route.routes === undefined) { | ||||
| route.routes = []; | route.routes = []; | ||||
| @@ -62,7 +60,7 @@ function patchRouteItems(route: any, menu: any, parentPath: string) { | |||||
| const newRoute = { | const newRoute = { | ||||
| element: React.createElement(lazy(() => import('@/pages/' + path))), | element: React.createElement(lazy(() => import('@/pages/' + path))), | ||||
| path: parentPath + menuItem.path, | path: parentPath + menuItem.path, | ||||
| } | |||||
| }; | |||||
| route.children.push(newRoute); | route.children.push(newRoute); | ||||
| route.routes.push(newRoute); | route.routes.push(newRoute); | ||||
| } | } | ||||
| @@ -70,7 +68,9 @@ function patchRouteItems(route: any, menu: any, parentPath: string) { | |||||
| } | } | ||||
| export function patchRouteWithRemoteMenus(routes: any) { | export function patchRouteWithRemoteMenus(routes: any) { | ||||
| if (remoteMenu === null) { return; } | |||||
| if (remoteMenu === null) { | |||||
| return; | |||||
| } | |||||
| let proLayout = null; | let proLayout = null; | ||||
| for (const routeItem of routes) { | for (const routeItem of routes) { | ||||
| if (routeItem.id === 'ant-design-pro-layout') { | if (routeItem.id === 'ant-design-pro-layout') { | ||||
| @@ -92,8 +92,8 @@ export async function getUserInfo(options?: Record<string, any>) { | |||||
| // 刷新方法 | // 刷新方法 | ||||
| export async function refreshToken() { | export async function refreshToken() { | ||||
| return request('/api/auth/refresh', { | return request('/api/auth/refresh', { | ||||
| method: 'post' | |||||
| }) | |||||
| method: 'post', | |||||
| }); | |||||
| } | } | ||||
| export async function getRouters(): Promise<any> { | export async function getRouters(): Promise<any> { | ||||
| @@ -0,0 +1,38 @@ | |||||
| import dayjs from 'dayjs'; | |||||
| export const elapsedTime = (beginDate: Date, endDate: Date): string => { | |||||
| if (!isValidDate(beginDate) || !isValidDate(endDate)) { | |||||
| return '--'; | |||||
| } | |||||
| const timestamp = endDate.getTime() - beginDate.getTime(); | |||||
| if (timestamp < 0) { | |||||
| return '时间有误'; | |||||
| } | |||||
| const duration = dayjs.duration(timestamp); | |||||
| const years = duration.years(); | |||||
| const months = duration.months(); | |||||
| const days = duration.days(); | |||||
| const hours = duration.hours(); | |||||
| const minutes = duration.minutes(); | |||||
| const seconds = duration.seconds(); | |||||
| if (years !== 0) { | |||||
| return `${years}年${months}个月`; | |||||
| } | |||||
| if (months !== 0) { | |||||
| return `${months}个月${days}天`; | |||||
| } | |||||
| if (days !== 0) { | |||||
| return `${days}天${hours}小时`; | |||||
| } | |||||
| if (hours !== 0) { | |||||
| return `${hours}小时${minutes}分`; | |||||
| } | |||||
| return `${minutes}分${seconds}秒`; | |||||
| }; | |||||
| // 是否是有效的日期 | |||||
| export const isValidDate = (date: Date): boolean => { | |||||
| if (date instanceof Date) { | |||||
| return !Number.isNaN(date.getTime()); // valueOf() 也可以 | |||||
| } | |||||
| return false; | |||||
| }; | |||||
| @@ -0,0 +1,20 @@ | |||||
| /** | |||||
| * @param { Promise } promise | |||||
| * @return { Promise } | |||||
| */ | |||||
| export async function to<T>(promise: Promise<T>): Promise<[T, null] | [null, Error]> { | |||||
| try { | |||||
| const data = await promise; | |||||
| return [data, null]; | |||||
| } catch (error) { | |||||
| if (error instanceof Error) { | |||||
| return [null, error]; | |||||
| } else if (typeof error === 'string') { | |||||
| return [null, new Error(error)]; | |||||
| } else { | |||||
| return [null, new Error('Error')]; | |||||
| } | |||||
| } | |||||
| } | |||||
| export default to; | |||||
| @@ -1,23 +1,31 @@ | |||||
| { | { | ||||
| "compilerOptions": { | "compilerOptions": { | ||||
| "target": "esnext", | |||||
| "module": "esnext", | |||||
| "moduleResolution": "node", | |||||
| "importHelpers": true, | |||||
| "jsx": "preserve", | |||||
| "esModuleInterop": true, | |||||
| "sourceMap": true, | |||||
| "target": "esnext", // 指定ECMAScript目标版本 | |||||
| "lib": ["dom", "dom.iterable", "esnext"], // 要包含在编译中的库文件列表 | |||||
| "allowJs": true, // 允许编译JavaScript文件 | |||||
| "skipLibCheck": true, // 跳过所有声明文件的类型检查 | |||||
| "esModuleInterop": true, // 禁用命名空间导入(import * as fs from "fs"),并启用CJS/AMD/UMD样式的导入(import fs from "fs") | |||||
| "allowSyntheticDefaultImports": true, // 允许从没有默认导出的模块进行默认导入 | |||||
| "strict": true, // 启用所有严格类型检查选项 | |||||
| "forceConsistentCasingInFileNames": true, // 不允许对同一文件的引用使用不一致的大小写 | |||||
| "module": "esnext", // 指定模块代码生成 | |||||
| "moduleResolution": "node", // 使用Node.js样式解析模块 | |||||
| "isolatedModules": true, // 无条件地为未解析的文件发出导入 | |||||
| "resolveJsonModule": true, // 包含.json扩展名的模块 | |||||
| "noEmit": true, // 不发出输出(即不编译代码,只进行类型检查) | |||||
| "jsx": "react-jsx", // 在.tsx文件中支持JSX | |||||
| "sourceMap": true, // 生成相应的.map文件 | |||||
| "declaration": true, // 生成相应的.d.ts文件 | |||||
| "noUnusedLocals": true, // 报告未使用的局部变量错误 | |||||
| "noUnusedParameters": true, // 报告未使用的参数错误 | |||||
| "incremental": true, // 通过读写磁盘上的文件来启用增量编译 | |||||
| "noFallthroughCasesInSwitch": true, // 报告switch语句中的fallthrough案例错误 | |||||
| "baseUrl": "./", | "baseUrl": "./", | ||||
| "skipLibCheck": true, | |||||
| "experimentalDecorators": true, | |||||
| "strict": true, | |||||
| "resolveJsonModule": true, | |||||
| "allowSyntheticDefaultImports": true, | |||||
| "paths": { | "paths": { | ||||
| "@/*": ["./src/*"], | |||||
| "@@/*": ["./src/.umi/*"], | |||||
| "@@test/*": ["./src/.umi-test/*"] | |||||
| "@/*": ["src/*"] | |||||
| } | } | ||||
| }, | }, | ||||
| "include": ["./**/*.d.ts", "./**/*.ts", "./**/*.tsx", "src/pages/Pipeline/index.jsx", "src/pages/Dataset/index.jsx"] | |||||
| "include": [ | |||||
| "src/**/*" // *** TypeScript应该检查的文件 *** | |||||
| ] | |||||
| } | } | ||||
| @@ -201,6 +201,12 @@ | |||||
| <version>0.1.55</version> <!-- 检查最新版本 --> | <version>0.1.55</version> <!-- 检查最新版本 --> | ||||
| </dependency> | </dependency> | ||||
| <dependency> | |||||
| <groupId>org.springframework.boot</groupId> | |||||
| <artifactId>spring-boot-starter-websocket</artifactId> | |||||
| </dependency> | |||||
| </dependencies> | </dependencies> | ||||
| <build> | <build> | ||||
| @@ -32,3 +32,4 @@ public class RuoYiManagementPlatformApplication { | |||||
| " ''-' `'-' `-..-' "); | " ''-' `'-' `-..-' "); | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,17 @@ | |||||
| package com.ruoyi.platform.config; | |||||
| import org.springframework.context.annotation.Bean; | |||||
| import org.springframework.context.annotation.Configuration; | |||||
| import org.springframework.web.socket.server.standard.ServerEndpointExporter; | |||||
| @Configuration | |||||
| public class WebSocketConfig { | |||||
| /** | |||||
| * 注入 ServerEndpointExporter, | |||||
| * 这个 bean 会自动注册使用了 @ServerEndpoint 注解声明的 WebSocket endpoint | |||||
| */ | |||||
| @Bean | |||||
| public ServerEndpointExporter serverEndpointExporter() { | |||||
| return new ServerEndpointExporter(); | |||||
| } | |||||
| } | |||||
| @@ -91,7 +91,7 @@ public class DatasetController { | |||||
| * @return 单条数据 | * @return 单条数据 | ||||
| */ | */ | ||||
| @GetMapping("{id}") | @GetMapping("{id}") | ||||
| @ApiOperation("根据id查询数据集") | |||||
| @ApiOperation("根据数据集id查询数据集") | |||||
| public AjaxResult queryById(@PathVariable("id") Integer id) { | public AjaxResult queryById(@PathVariable("id") Integer id) { | ||||
| return AjaxResult.success(this.datasetService.queryById(id)); | return AjaxResult.success(this.datasetService.queryById(id)); | ||||
| } | } | ||||
| @@ -148,7 +148,7 @@ public class DatasetController { | |||||
| * @return 删除是否成功 | * @return 删除是否成功 | ||||
| */ | */ | ||||
| @DeleteMapping({"{id}"}) | @DeleteMapping({"{id}"}) | ||||
| @ApiOperation("删除数据集") | |||||
| @ApiOperation("根据id删除数据集") | |||||
| public AjaxResult deleteById(@PathVariable("id") Integer id) { | public AjaxResult deleteById(@PathVariable("id") Integer id) { | ||||
| return AjaxResult.success(this.datasetService.removeById(id)); | return AjaxResult.success(this.datasetService.removeById(id)); | ||||
| } | } | ||||
| @@ -45,7 +45,7 @@ public class ExperimentController extends BaseController { | |||||
| return genericsSuccess(this.experimentService.queryByPage(experiment, pageRequest)); | return genericsSuccess(this.experimentService.queryByPage(experiment, pageRequest)); | ||||
| } | } | ||||
| @GetMapping(("/status")) | |||||
| @GetMapping("/status") | |||||
| @ApiOperation("查询实验状态") | @ApiOperation("查询实验状态") | ||||
| public GenericsAjaxResult<Page<Experiment>> selectStatus(@RequestBody Experiment experiment, PageRequest pageRequest) throws IOException { | public GenericsAjaxResult<Page<Experiment>> selectStatus(@RequestBody Experiment experiment, PageRequest pageRequest) throws IOException { | ||||
| return genericsSuccess(this.experimentService.selectStatus(experiment, pageRequest)); | return genericsSuccess(this.experimentService.selectStatus(experiment, pageRequest)); | ||||
| @@ -53,8 +53,8 @@ public class ExperimentController extends BaseController { | |||||
| @GetMapping(("/configuration")) | |||||
| @ApiOperation("查询实验配置") | |||||
| @GetMapping("/configuration") | |||||
| @ApiOperation("查询实验配置参数") | |||||
| public GenericsAjaxResult<ResponseEntity<Experiment>> showExperimentConfig(@RequestBody Experiment experiment){ | public GenericsAjaxResult<ResponseEntity<Experiment>> showExperimentConfig(@RequestBody Experiment experiment){ | ||||
| return genericsSuccess(this.experimentService.showExperimentConfig(experiment)); | return genericsSuccess(this.experimentService.showExperimentConfig(experiment)); | ||||
| } | } | ||||
| @@ -5,6 +5,7 @@ import com.ruoyi.common.core.web.domain.GenericsAjaxResult; | |||||
| import com.ruoyi.platform.domain.ExperimentIns; | import com.ruoyi.platform.domain.ExperimentIns; | ||||
| import com.ruoyi.platform.service.ExperimentInsService; | import com.ruoyi.platform.service.ExperimentInsService; | ||||
| import com.ruoyi.platform.vo.LogRequestVo; | import com.ruoyi.platform.vo.LogRequestVo; | ||||
| import com.ruoyi.platform.vo.PodLogVo; | |||||
| import io.swagger.annotations.Api; | import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | import io.swagger.annotations.ApiOperation; | ||||
| import org.springframework.data.domain.Page; | import org.springframework.data.domain.Page; | ||||
| @@ -138,11 +139,19 @@ public class ExperimentInsController extends BaseController { | |||||
| @GetMapping("/pods/log") | @GetMapping("/pods/log") | ||||
| @ApiOperation("获取pod实时日志请求") | @ApiOperation("获取pod实时日志请求") | ||||
| public GenericsAjaxResult<Map> getRealtimePodLog(@RequestParam("pod_name") String podName, | |||||
| public GenericsAjaxResult<Map<String, Object>> getRealtimePodLog(@RequestParam("pod_name") String podName, | |||||
| @RequestParam("start_time") String startTime){ | @RequestParam("start_time") String startTime){ | ||||
| return genericsSuccess(this.experimentInsService.getRealtimePodLog(podName,startTime)); | return genericsSuccess(this.experimentInsService.getRealtimePodLog(podName,startTime)); | ||||
| } | } | ||||
| @PostMapping("/pods/realTimeLog") | |||||
| @ApiOperation("获取pod实时日志请求") | |||||
| public GenericsAjaxResult<String> getRealtimePodLogFromPod(@RequestBody PodLogVo podLogVo){ | |||||
| return genericsSuccess(this.experimentInsService.getRealtimePodLogFromPod(podLogVo)); | |||||
| } | |||||
| /** | /** | ||||
| * 查询实验实例实时日志 | * 查询实验实例实时日志 | ||||
| * | * | ||||
| @@ -2,6 +2,7 @@ package com.ruoyi.platform.domain; | |||||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | import com.fasterxml.jackson.databind.PropertyNamingStrategy; | ||||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||||
| import io.swagger.annotations.ApiModelProperty; | |||||
| import java.util.Date; | import java.util.Date; | ||||
| import java.io.Serializable; | import java.io.Serializable; | ||||
| @@ -18,40 +19,34 @@ public class AssetIcon implements Serializable { | |||||
| /** | /** | ||||
| * 主键 | * 主键 | ||||
| */ | */ | ||||
| private Integer id; | |||||
| /** | |||||
| * 资产图标名称 | |||||
| */ | |||||
| @ApiModelProperty(value = "资产ID") | |||||
| private Integer id; | |||||
| @ApiModelProperty(value = "资产图标名称") | |||||
| private String name; | private String name; | ||||
| /** | |||||
| * 分类id | |||||
| */ | |||||
| @ApiModelProperty(value = "分类ID") | |||||
| private Integer categoryId; | private Integer categoryId; | ||||
| /** | |||||
| * 路径 | |||||
| */ | |||||
| @ApiModelProperty(value = "路径") | |||||
| private String path; | private String path; | ||||
| /** | |||||
| * 描述 | |||||
| */ | |||||
| @ApiModelProperty(value = "描述") | |||||
| private String description; | private String description; | ||||
| /** | |||||
| * 创建者 | |||||
| */ | |||||
| @ApiModelProperty(value = "创建者") | |||||
| private String createBy; | private String createBy; | ||||
| @ApiModelProperty(value = "创建时间") | |||||
| private Date createTime; | private Date createTime; | ||||
| /** | |||||
| * 更新者 | |||||
| */ | |||||
| @ApiModelProperty(value = "更新者") | |||||
| private String updateBy; | private String updateBy; | ||||
| /** | |||||
| * 更新时间 | |||||
| */ | |||||
| @ApiModelProperty(value = "更新时间") | |||||
| private Date updateTime; | private Date updateTime; | ||||
| /** | |||||
| * 0失效,1生效 | |||||
| */ | |||||
| @ApiModelProperty(value = "状态,0失效,1生效") | |||||
| private Integer state; | private Integer state; | ||||
| @@ -20,108 +20,108 @@ public class Component implements Serializable { | |||||
| /** | /** | ||||
| * 主键 | * 主键 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "id") | |||||
| @ApiModelProperty(name = "id", value = "主键") | |||||
| private Integer id; | private Integer id; | ||||
| /** | /** | ||||
| * 类别ID,数据字典配置 | * 类别ID,数据字典配置 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "category_id") | |||||
| @ApiModelProperty(name = "category_id" ,value = "类别id") | |||||
| private Integer categoryId; | private Integer categoryId; | ||||
| /** | /** | ||||
| * 组件name | * 组件name | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "category_name") | |||||
| @ApiModelProperty(name = "category_name", value = "组件名称") | |||||
| private String componentName; | private String componentName; | ||||
| /** | /** | ||||
| * 组件面板名 | * 组件面板名 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "component_label") | |||||
| @ApiModelProperty(name = "component_label" , value = "组件面板名" ) | |||||
| private String componentLabel; | private String componentLabel; | ||||
| /** | /** | ||||
| * 镜像 | * 镜像 | ||||
| */ | */ | ||||
| @JsonProperty("image") | @JsonProperty("image") | ||||
| @ApiModelProperty(name = "image") | |||||
| @ApiModelProperty(name = "image" ,value = "镜像") | |||||
| private String images; | private String images; | ||||
| /** | /** | ||||
| * 工作目录 | * 工作目录 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "working_directory") | |||||
| @ApiModelProperty(name = "working_directory" , value = "工作目录") | |||||
| private String workingDirectory; | private String workingDirectory; | ||||
| /** | /** | ||||
| * 启动命令 | * 启动命令 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "command") | |||||
| @ApiModelProperty(name = "command" , value = "启动命令") | |||||
| private String command; | private String command; | ||||
| /** | /** | ||||
| * 环境变量 | * 环境变量 | ||||
| */ | */ | ||||
| @JsonProperty("env_variables") | @JsonProperty("env_variables") | ||||
| @ApiModelProperty(name = "env_variables") | |||||
| @ApiModelProperty(name = "env_variables", value = "环境变量") | |||||
| private String envVirables; | private String envVirables; | ||||
| /** | /** | ||||
| * 资源规格 | * 资源规格 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "resources_standard") | |||||
| @ApiModelProperty(name = "resources_standard" , value = "资源规格") | |||||
| private String resourcesStandard; | private String resourcesStandard; | ||||
| /** | /** | ||||
| * 控制策略 | * 控制策略 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "control_strategy") | |||||
| @ApiModelProperty(name = "control_strategy" ,value = "控制策略") | |||||
| private String controlStrategy; | private String controlStrategy; | ||||
| /** | /** | ||||
| * 挂载路径 | * 挂载路径 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "mount_path") | |||||
| @ApiModelProperty(name = "mount_path" , value = "挂载路径") | |||||
| private String mountPath; | private String mountPath; | ||||
| /** | /** | ||||
| * 输入参数 | * 输入参数 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "in_parameters") | |||||
| @ApiModelProperty(name = "in_parameters" ,value = "输入参数") | |||||
| private String inParameters; | private String inParameters; | ||||
| /** | /** | ||||
| * 输出参数 | * 输出参数 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "out_parameters") | |||||
| @ApiModelProperty(name = "out_parameters" ,value = "输出参数") | |||||
| private String outParameters; | private String outParameters; | ||||
| /** | /** | ||||
| * 描述 | * 描述 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "description") | |||||
| @ApiModelProperty(name = "description" , value = "描述") | |||||
| private String description; | private String description; | ||||
| /** | /** | ||||
| * 图标路径 | * 图标路径 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "icon_path") | |||||
| @ApiModelProperty(name = "icon_path" ,value = "图标路径") | |||||
| private String iconPath; | private String iconPath; | ||||
| /** | /** | ||||
| * 创建者 | * 创建者 | ||||
| */ | */ | ||||
| //@JsonProperty("creater") | //@JsonProperty("creater") | ||||
| @ApiModelProperty(name = "create_by") | |||||
| @ApiModelProperty(name = "create_by" ,value = "创建者") | |||||
| private String createBy; | private String createBy; | ||||
| /** | /** | ||||
| * 创建时间 | * 创建时间 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "create_time") | |||||
| @ApiModelProperty(name = "create_time" , value = "创建时间") | |||||
| private Date createTime; | private Date createTime; | ||||
| /** | /** | ||||
| * 更新者 | * 更新者 | ||||
| */ | */ | ||||
| //@JsonProperty("modify_by") | //@JsonProperty("modify_by") | ||||
| @ApiModelProperty(name = "update_by") | |||||
| @ApiModelProperty(name = "update_by" , value = "更新者") | |||||
| private String updateBy; | private String updateBy; | ||||
| /** | /** | ||||
| * 更新时间 | * 更新时间 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "update_time") | |||||
| @ApiModelProperty(name = "update_time" , value = "更新时间") | |||||
| private Date updateTime; | private Date updateTime; | ||||
| /** | /** | ||||
| * 0,失效 1生效 | * 0,失效 1生效 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "state") | |||||
| @ApiModelProperty(name = "state" , value = "状态") | |||||
| private Integer state; | private Integer state; | ||||
| public Integer getId() { | public Integer getId() { | ||||
| @@ -22,53 +22,58 @@ public class Dataset implements Serializable { | |||||
| private Integer id; | private Integer id; | ||||
| @CheckDuplicate | @CheckDuplicate | ||||
| @ApiModelProperty(name = "name") | |||||
| @ApiModelProperty(value = "名称") | |||||
| private String name; | private String name; | ||||
| @ApiModelProperty(name = "description") | |||||
| @ApiModelProperty(value = "描述") | |||||
| private String description; | private String description; | ||||
| /** | /** | ||||
| * 是否公开: 1公开,0私有 | * 是否公开: 1公开,0私有 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "available_range") | |||||
| @ApiModelProperty(value = "是否公开:1公开,0私有") | |||||
| private int availableRange; | private int availableRange; | ||||
| /** | /** | ||||
| * 数据集类型 | * 数据集类型 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "data_type") | |||||
| @ApiModelProperty(value = "数据集类型") | |||||
| private String dataType; | private String dataType; | ||||
| /** | /** | ||||
| * 数据集tag | |||||
| * 数据集标签 | |||||
| */ | */ | ||||
| @ApiModelProperty(name = "data_tag") | |||||
| @ApiModelProperty(value = "数据集标签") | |||||
| private String dataTag; | private String dataTag; | ||||
| /** | /** | ||||
| * 创建者 | * 创建者 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "create_by") | |||||
| @ApiModelProperty(value = "创建者") | |||||
| private String createBy; | private String createBy; | ||||
| /** | /** | ||||
| * 创建时间 | * 创建时间 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "create_time") | |||||
| @ApiModelProperty(value = "创建时间") | |||||
| private Date createTime; | private Date createTime; | ||||
| /** | /** | ||||
| * 更新者 | * 更新者 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "update_by") | |||||
| @ApiModelProperty(value = "更新者") | |||||
| private String updateBy; | private String updateBy; | ||||
| /** | /** | ||||
| * 更新时间 | * 更新时间 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "update_time") | |||||
| @ApiModelProperty(value = "更新时间") | |||||
| private Date updateTime; | private Date updateTime; | ||||
| /** | |||||
| * 0,失效 1生效 | |||||
| /** | |||||
| * 状态,0失效,1生效 | |||||
| */ | */ | ||||
| @ApiModelProperty(name = "state") | |||||
| @ApiModelProperty(value = "状态:0失效,1生效") | |||||
| private Integer state; | private Integer state; | ||||
| @@ -22,66 +22,46 @@ public class DatasetVersion implements Serializable { | |||||
| */ | */ | ||||
| @ApiModelProperty(name = "id") | @ApiModelProperty(name = "id") | ||||
| private Integer id; | private Integer id; | ||||
| @ApiModelProperty(name = "dataset_id") | |||||
| @ApiModelProperty(value = "数据集ID") | |||||
| private Integer datasetId; | private Integer datasetId; | ||||
| /** | |||||
| * 版本 | |||||
| */ | |||||
| @ApiModelProperty(name = "version") | |||||
| @ApiModelProperty(value = "版本") | |||||
| private String version; | private String version; | ||||
| /** | |||||
| * 数据集存储地址 | |||||
| */ | |||||
| @ApiModelProperty(name = "url") | |||||
| @ApiModelProperty(value = "数据集存储地址") | |||||
| @CheckDuplicate | @CheckDuplicate | ||||
| private String url; | private String url; | ||||
| /** | |||||
| * 文件名 | |||||
| */ | |||||
| @ApiModelProperty(name = "file_name") | |||||
| @ApiModelProperty(value = "文件名") | |||||
| private String fileName; | private String fileName; | ||||
| /** | |||||
| * 文件大小 | |||||
| */ | |||||
| @ApiModelProperty(name = "file_size") | |||||
| @ApiModelProperty(value = "文件大小") | |||||
| private String fileSize; | private String fileSize; | ||||
| /** | |||||
| * 可用集群 | |||||
| */ | |||||
| @ApiModelProperty(name = "available_cluster") | |||||
| @ApiModelProperty(value = "可用集群") | |||||
| private String availableCluster; | private String availableCluster; | ||||
| /** | |||||
| * 状态 | |||||
| */ | |||||
| @ApiModelProperty(name = "status") | |||||
| @ApiModelProperty(value = "状态") | |||||
| private Integer status; | private Integer status; | ||||
| /** | |||||
| * 创建者 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_by") | |||||
| @ApiModelProperty(value = "创建者") | |||||
| private String createBy; | private String createBy; | ||||
| /** | |||||
| * 创建时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_time") | |||||
| @ApiModelProperty(value = "创建时间") | |||||
| private Date createTime; | private Date createTime; | ||||
| /** | |||||
| * 更新者 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_by") | |||||
| @ApiModelProperty(value = "更新者") | |||||
| private String updateBy; | private String updateBy; | ||||
| /** | |||||
| * 更新时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_time") | |||||
| @ApiModelProperty(value = "更新时间") | |||||
| private Date updateTime; | private Date updateTime; | ||||
| /** | |||||
| * 0失效,1生效 | |||||
| */ | |||||
| @ApiModelProperty(name = "state") | |||||
| @ApiModelProperty(value = "状态:0失效,1生效") | |||||
| private Integer state; | private Integer state; | ||||
| public Integer getId() { | public Integer getId() { | ||||
| return id; | return id; | ||||
| } | } | ||||
| @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.FieldFill; | |||||
| import com.baomidou.mybatisplus.annotation.TableField; | import com.baomidou.mybatisplus.annotation.TableField; | ||||
| import com.baomidou.mybatisplus.annotation.TableId; | import com.baomidou.mybatisplus.annotation.TableId; | ||||
| import com.baomidou.mybatisplus.annotation.TableLogic; | import com.baomidou.mybatisplus.annotation.TableLogic; | ||||
| import com.fasterxml.jackson.annotation.JsonRawValue; | |||||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | import com.fasterxml.jackson.databind.PropertyNamingStrategy; | ||||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||||
| import com.ruoyi.common.core.web.domain.BaseEntity; | import com.ruoyi.common.core.web.domain.BaseEntity; | ||||
| @@ -24,45 +25,43 @@ import java.util.List; | |||||
| @ApiModel("实验对象") | @ApiModel("实验对象") | ||||
| public class Experiment implements Serializable { | public class Experiment implements Serializable { | ||||
| private static final long serialVersionUID = 409135817108439880L; | private static final long serialVersionUID = 409135817108439880L; | ||||
| // @ApiModelProperty(name = "id") | |||||
| @ApiModelProperty(value = "主键") | |||||
| private Integer id; | private Integer id; | ||||
| // @ApiModelProperty(name = "name") | |||||
| @ApiModelProperty(value = "名称") | |||||
| private String name; | private String name; | ||||
| // @ApiModelProperty(name = "workflow_id") | |||||
| @ApiModelProperty(value = "工作流ID") | |||||
| private Long workflowId; | private Long workflowId; | ||||
| /** | |||||
| * 全局参数 | |||||
| */ | |||||
| @ApiModelProperty(name = "global_param") | |||||
| @ApiModelProperty(value = "全局参数,以JSON字符串格式存储") | |||||
| @JsonRawValue | |||||
| private String globalParam; | private String globalParam; | ||||
| @ApiModelProperty(value = "状态列表") | |||||
| private String statusList; | private String statusList; | ||||
| /** | |||||
| * 简介 | |||||
| */ | |||||
| @ApiModelProperty(name = "description") | |||||
| @ApiModelProperty(value = "简介") | |||||
| private String description; | private String description; | ||||
| /** | |||||
| * 创建者 | |||||
| */ | |||||
| @ApiModelProperty(value = "创建者") | |||||
| private String createBy; | private String createBy; | ||||
| /** | |||||
| * 创建时间 | |||||
| */ | |||||
| @ApiModelProperty(value = "创建时间") | |||||
| private Date createTime; | private Date createTime; | ||||
| /** | |||||
| * 更新者 | |||||
| */ | |||||
| @ApiModelProperty(value = "更新者") | |||||
| private String updateBy; | private String updateBy; | ||||
| /** | |||||
| * 更新时间 | |||||
| */ | |||||
| @ApiModelProperty(value = "更新时间") | |||||
| private Date updateTime; | private Date updateTime; | ||||
| /** | |||||
| * 0,失效 1生效 | |||||
| */ | |||||
| @ApiModelProperty(value = "状态:0失效,1生效") | |||||
| private Integer state; | private Integer state; | ||||
| @ApiModelProperty(value = "对应的实例列表") | |||||
| private List<ExperimentIns> experimentInsList; | private List<ExperimentIns> experimentInsList; | ||||
| @ApiModelProperty(value = "对应的流水线名称") | |||||
| private String workflowName; | private String workflowName; | ||||
| public String getName() { | public String getName() { | ||||
| return name; | return name; | ||||
| @@ -1,5 +1,6 @@ | |||||
| package com.ruoyi.platform.domain; | package com.ruoyi.platform.domain; | ||||
| import com.fasterxml.jackson.annotation.JsonRawValue; | |||||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | import com.fasterxml.jackson.databind.PropertyNamingStrategy; | ||||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||||
| import io.swagger.annotations.ApiModel; | import io.swagger.annotations.ApiModel; | ||||
| @@ -15,6 +16,7 @@ import java.util.Date; | |||||
| * @since 2023-11-09 09:48:36 | * @since 2023-11-09 09:48:36 | ||||
| */ | */ | ||||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | ||||
| @ApiModel("实验实例对象") | |||||
| public class ExperimentIns implements Serializable { | public class ExperimentIns implements Serializable { | ||||
| private static final long serialVersionUID = 623464560240790680L; | private static final long serialVersionUID = 623464560240790680L; | ||||
| @ApiModelProperty(name = "id") | @ApiModelProperty(name = "id") | ||||
| @@ -22,69 +24,53 @@ public class ExperimentIns implements Serializable { | |||||
| /** | /** | ||||
| * 实验ID | * 实验ID | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "experiment_id") | |||||
| @ApiModelProperty(value = "实验ID") | |||||
| private Integer experimentId; | private Integer experimentId; | ||||
| /** | |||||
| * argo返回name | |||||
| */ | |||||
| @ApiModelProperty(name = "argo_ins_name") | |||||
| @ApiModelProperty(value = "Argo实例名称") | |||||
| private String argoInsName; | private String argoInsName; | ||||
| /** | |||||
| * argo返回命名空间 | |||||
| */ | |||||
| @ApiModelProperty(name = "argo_ins_ns") | |||||
| @ApiModelProperty(value = "Argo命名空间") | |||||
| private String argoInsNs; | private String argoInsNs; | ||||
| /** | |||||
| * 实例运行状态 | |||||
| */ | |||||
| @ApiModelProperty(name = "status") | |||||
| @ApiModelProperty(value = "实例运行状态") | |||||
| private String status; | private String status; | ||||
| @ApiModelProperty(name = "nodes_status") | |||||
| @ApiModelProperty(value = "节点状态") | |||||
| private String nodesStatus; | private String nodesStatus; | ||||
| @ApiModelProperty(name = "nodes_result") | |||||
| @ApiModelProperty(value = "节点结果") | |||||
| private String nodesResult; | private String nodesResult; | ||||
| @ApiModelProperty(name = "nodes_logs") | |||||
| @ApiModelProperty(value = "节点日志") | |||||
| private String nodesLogs; | private String nodesLogs; | ||||
| /** | |||||
| * 开始时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "start_time") | |||||
| @ApiModelProperty(value = "实验实例全局参数", notes = "以JSON字符串格式存储") | |||||
| @JsonRawValue | |||||
| private String globalParam; | |||||
| @ApiModelProperty(value = "开始时间") | |||||
| private Date startTime; | private Date startTime; | ||||
| /** | |||||
| * 结束时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "finish_time") | |||||
| @ApiModelProperty(value = "结束时间") | |||||
| private Date finishTime; | private Date finishTime; | ||||
| /** | |||||
| * 创建者 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_by") | |||||
| @ApiModelProperty(value = "创建者") | |||||
| private String createBy; | private String createBy; | ||||
| /** | |||||
| * 创建时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_time") | |||||
| @ApiModelProperty(value = "创建时间") | |||||
| private Date createTime; | private Date createTime; | ||||
| /** | |||||
| * 更新者 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_by") | |||||
| @ApiModelProperty(value = "更新者") | |||||
| private String updateBy; | private String updateBy; | ||||
| /** | |||||
| * 更新时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_time") | |||||
| @ApiModelProperty(value = "更新时间") | |||||
| private Date updateTime; | private Date updateTime; | ||||
| /** | |||||
| * 0,失效 1生效 | |||||
| */ | |||||
| @ApiModelProperty(name = "state") | |||||
| @ApiModelProperty(value = "状态:0失效,1生效") | |||||
| private Integer state; | private Integer state; | ||||
| public ExperimentIns() { | public ExperimentIns() { | ||||
| } | } | ||||
| @@ -154,6 +140,14 @@ public class ExperimentIns implements Serializable { | |||||
| this.nodesLogs = nodesLogs; | this.nodesLogs = nodesLogs; | ||||
| } | } | ||||
| public String getGlobalParam() { | |||||
| return globalParam; | |||||
| } | |||||
| public void setGlobalParam(String globalParam) { | |||||
| this.globalParam = globalParam; | |||||
| } | |||||
| public void setStartTime(Date startTime) { | public void setStartTime(Date startTime) { | ||||
| this.startTime = startTime; | this.startTime = startTime; | ||||
| } | } | ||||
| @@ -19,51 +19,37 @@ public class Image implements Serializable { | |||||
| /** | /** | ||||
| * 主键 | * 主键 | ||||
| */ | */ | ||||
| @ApiModelProperty(value = "主键") | |||||
| private Integer id; | private Integer id; | ||||
| /** | /** | ||||
| * 镜像名称 | * 镜像名称 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "name") | |||||
| @ApiModelProperty(value = "名称") | |||||
| private String name; | private String name; | ||||
| /** | |||||
| * 镜像描述 | |||||
| */ | |||||
| @ApiModelProperty(name = "description") | |||||
| @ApiModelProperty(value = "镜像描述") | |||||
| private String description; | private String description; | ||||
| /** | |||||
| * 镜像类型 | |||||
| */ | |||||
| @ApiModelProperty(name = "image_type") | |||||
| @ApiModelProperty(value = "镜像类型") | |||||
| private Integer imageType; | private Integer imageType; | ||||
| /** | |||||
| * 创建者 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_by") | |||||
| @ApiModelProperty(value = "创建者") | |||||
| private String createBy; | private String createBy; | ||||
| /** | |||||
| * 创建时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_time") | |||||
| @ApiModelProperty(value = "创建时间") | |||||
| private Date createTime; | private Date createTime; | ||||
| /** | |||||
| * 更新者 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_by") | |||||
| @ApiModelProperty(value = "更新者") | |||||
| private String updateBy; | private String updateBy; | ||||
| /** | |||||
| * 更新时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_time") | |||||
| @ApiModelProperty(value = "更新时间") | |||||
| private Date updateTime; | private Date updateTime; | ||||
| /** | |||||
| * 状态,0失效,1生效 | |||||
| */ | |||||
| @ApiModelProperty(name = "state") | |||||
| @ApiModelProperty(value = "状态,0失效,1生效") | |||||
| private Integer state; | private Integer state; | ||||
| private Integer versionCount; // 版本数量统计 | |||||
| @ApiModelProperty(value = "版本数量统计") | |||||
| private Integer versionCount; | |||||
| @@ -20,63 +20,40 @@ public class ImageVersion implements Serializable { | |||||
| * 主键 | * 主键 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "id") | |||||
| @ApiModelProperty(value = "ID") | |||||
| private Integer id; | private Integer id; | ||||
| /** | |||||
| * 对应的镜像id | |||||
| */ | |||||
| @ApiModelProperty(name = "image_id") | |||||
| @ApiModelProperty(value = "对应的镜像ID") | |||||
| private Integer imageId; | private Integer imageId; | ||||
| /** | |||||
| * 镜像版本 | |||||
| */ | |||||
| @ApiModelProperty(name = "version") | |||||
| @ApiModelProperty(value = "镜像版本") | |||||
| private String version; | private String version; | ||||
| /** | |||||
| * 镜像推送地址 | |||||
| */ | |||||
| @ApiModelProperty(name = "url") | |||||
| @ApiModelProperty(value = "镜像推送地址") | |||||
| private String url; | private String url; | ||||
| /** | |||||
| * 镜像tag名称 | |||||
| */ | |||||
| @ApiModelProperty(name = "tag_name") | |||||
| @ApiModelProperty(value = "镜像tag名称") | |||||
| private String tagName; | private String tagName; | ||||
| /** | |||||
| * 镜像文件大小 | |||||
| */ | |||||
| @ApiModelProperty(name = "file_size") | |||||
| @ApiModelProperty(value = "镜像文件大小") | |||||
| private String fileSize; | private String fileSize; | ||||
| /** | |||||
| * 镜像构建状态 | |||||
| */ | |||||
| @ApiModelProperty(name = "status") | |||||
| @ApiModelProperty(value = "镜像构建状态") | |||||
| private String status; | private String status; | ||||
| /** | |||||
| * 创建者 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_by") | |||||
| @ApiModelProperty(value = "创建者") | |||||
| private String createBy; | private String createBy; | ||||
| /** | |||||
| * 创建时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_time") | |||||
| @ApiModelProperty(value = "创建时间") | |||||
| private Date createTime; | private Date createTime; | ||||
| /** | |||||
| * 更新者 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_by") | |||||
| @ApiModelProperty(value = "更新者") | |||||
| private String updateBy; | private String updateBy; | ||||
| /** | |||||
| * 更新时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_time") | |||||
| @ApiModelProperty(value = "更新时间") | |||||
| private Date updateTime; | private Date updateTime; | ||||
| /** | |||||
| * 状态,0失效,1生效 | |||||
| */ | |||||
| @ApiModelProperty(name = "state") | |||||
| @ApiModelProperty(value = "状态,0失效,1生效") | |||||
| private Integer state; | private Integer state; | ||||
| @@ -18,51 +18,37 @@ import java.io.Serializable; | |||||
| @ApiModel("模型对象") | @ApiModel("模型对象") | ||||
| public class Models implements Serializable { | public class Models implements Serializable { | ||||
| private static final long serialVersionUID = -59896385986032571L; | private static final long serialVersionUID = -59896385986032571L; | ||||
| @ApiModelProperty(name = "id") | |||||
| @ApiModelProperty(value = "ID") | |||||
| private Integer id; | private Integer id; | ||||
| @ApiModelProperty(name = "name") | |||||
| @ApiModelProperty(value = "模型名称") | |||||
| private String name; | private String name; | ||||
| // private String version; | |||||
| @ApiModelProperty(name = "description") | |||||
| @ApiModelProperty(value = "模型描述") | |||||
| private String description; | private String description; | ||||
| /** | |||||
| * 模型可见范围 | |||||
| */ | |||||
| @ApiModelProperty(name = "available_range") | |||||
| @ApiModelProperty(value = "模型可见范围,1表示公开,0表示私有") | |||||
| private int availableRange; | private int availableRange; | ||||
| @ApiModelProperty(name = "model_type") | |||||
| @ApiModelProperty(value = "模型类型") | |||||
| private String modelType; | private String modelType; | ||||
| @ApiModelProperty(name = "model_tag") | |||||
| @ApiModelProperty(value = "模型标签") | |||||
| private String modelTag; | private String modelTag; | ||||
| /** | |||||
| * 创建者 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_by") | |||||
| @ApiModelProperty(value = "创建者") | |||||
| private String createBy; | private String createBy; | ||||
| /** | |||||
| * 创建时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_time") | |||||
| @ApiModelProperty(value = "创建时间") | |||||
| private Date createTime; | private Date createTime; | ||||
| /** | |||||
| * 更新者 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_by") | |||||
| @ApiModelProperty(value = "更新者") | |||||
| private String updateBy; | private String updateBy; | ||||
| /** | |||||
| * 更新时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_time") | |||||
| @ApiModelProperty(value = "更新时间") | |||||
| private Date updateTime; | private Date updateTime; | ||||
| /** | |||||
| * 0,失效 1生效 | |||||
| */ | |||||
| @ApiModelProperty(name = "state") | |||||
| @ApiModelProperty(value = "状态,0失效,1生效") | |||||
| private Integer state; | private Integer state; | ||||
| @@ -21,59 +21,40 @@ public class ModelsVersion implements Serializable { | |||||
| /** | /** | ||||
| * 主键 | * 主键 | ||||
| */ | */ | ||||
| @ApiModelProperty(name = "id") | |||||
| private Integer id; | |||||
| @ApiModelProperty(name = "models_id") | |||||
| @ApiModelProperty(value = "ID") | |||||
| private Integer id; | |||||
| @ApiModelProperty(value = "模型ID") | |||||
| private Integer modelsId; | private Integer modelsId; | ||||
| /** | |||||
| * 版本 | |||||
| */ | |||||
| @ApiModelProperty(name = "version") | |||||
| @ApiModelProperty(value = "版本") | |||||
| private String version; | private String version; | ||||
| /** | |||||
| * 模型存储地址 | |||||
| */ | |||||
| @ApiModelProperty(name = "url") | |||||
| @ApiModelProperty(value = "模型存储地址") | |||||
| private String url; | private String url; | ||||
| /** | |||||
| * 文件名 | |||||
| */ | |||||
| @ApiModelProperty(name = "file_name") | |||||
| @ApiModelProperty(value = "文件名") | |||||
| private String fileName; | private String fileName; | ||||
| /** | |||||
| * 文件大小 | |||||
| */ | |||||
| @ApiModelProperty(name = "file_size") | |||||
| @ApiModelProperty(value = "文件大小") | |||||
| private String fileSize; | private String fileSize; | ||||
| /** | |||||
| * 状态 | |||||
| */ | |||||
| @ApiModelProperty(name = "status") | |||||
| @ApiModelProperty(value = "状态") | |||||
| private Integer status; | private Integer status; | ||||
| /** | |||||
| * 创建者 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_by") | |||||
| @ApiModelProperty(value = "创建者") | |||||
| private String createBy; | private String createBy; | ||||
| /** | |||||
| * 创建时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_time") | |||||
| @ApiModelProperty(value = "创建时间") | |||||
| private Date createTime; | private Date createTime; | ||||
| /** | |||||
| * 更新者 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_by") | |||||
| @ApiModelProperty(value = "更新者") | |||||
| private String updateBy; | private String updateBy; | ||||
| /** | |||||
| * 更新时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_time") | |||||
| @ApiModelProperty(value = "更新时间") | |||||
| private Date updateTime; | private Date updateTime; | ||||
| /** | |||||
| * 0失效,1生效 | |||||
| */ | |||||
| @ApiModelProperty(name = "state") | |||||
| @ApiModelProperty(value = "状态,0失效,1生效") | |||||
| private Integer state; | private Integer state; | ||||
| @@ -2,6 +2,7 @@ package com.ruoyi.platform.domain; | |||||
| import com.baomidou.mybatisplus.annotation.TableId; | import com.baomidou.mybatisplus.annotation.TableId; | ||||
| import com.fasterxml.jackson.annotation.JsonFormat; | import com.fasterxml.jackson.annotation.JsonFormat; | ||||
| import com.fasterxml.jackson.annotation.JsonRawValue; | |||||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | import com.fasterxml.jackson.databind.PropertyNamingStrategy; | ||||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | import com.fasterxml.jackson.databind.annotation.JsonNaming; | ||||
| import com.ruoyi.platform.handler.BaseMetaObjectHandler; | import com.ruoyi.platform.handler.BaseMetaObjectHandler; | ||||
| @@ -28,48 +29,35 @@ public class Workflow extends BaseMetaObjectHandler implements Serializable { | |||||
| /** | /** | ||||
| * id | * id | ||||
| */ | */ | ||||
| @TableId | |||||
| @ApiModelProperty(name = "id") | |||||
| @ApiModelProperty(value = "ID") | |||||
| private Long id; | private Long id; | ||||
| /** | |||||
| * 工作流名称 | |||||
| */ | |||||
| @ApiModelProperty(name = "name") | |||||
| @ApiModelProperty(value = "工作流名称") | |||||
| private String name; | private String name; | ||||
| /** | |||||
| * DAG工作流描述 | |||||
| */ | |||||
| @ApiModelProperty(name = "description") | |||||
| @ApiModelProperty(value = "流水线描述") | |||||
| private String description; | private String description; | ||||
| /** | |||||
| * DAG图 | |||||
| */ | |||||
| @ApiModelProperty(name = "dag") | |||||
| @ApiModelProperty(value = "DAG图") | |||||
| private String dag; | private String dag; | ||||
| /** | |||||
| * 创建者 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_by") | |||||
| @JsonRawValue | |||||
| @ApiModelProperty(value = "全局参数") | |||||
| private String globalParam; | |||||
| @ApiModelProperty(value = "创建者") | |||||
| private String createBy; | private String createBy; | ||||
| /** | |||||
| * 创建时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "create_time") | |||||
| @ApiModelProperty(value = "创建时间") | |||||
| private Date createTime; | private Date createTime; | ||||
| /** | |||||
| * 更新者 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_by") | |||||
| @ApiModelProperty(value = "更新者") | |||||
| private String updateBy; | private String updateBy; | ||||
| /** | |||||
| * 更新时间 | |||||
| */ | |||||
| @ApiModelProperty(name = "update_time") | |||||
| @ApiModelProperty(value = "更新时间") | |||||
| private Date updateTime; | private Date updateTime; | ||||
| /** | |||||
| * 0,失效 1生效 | |||||
| */ | |||||
| @ApiModelProperty(name = "state") | |||||
| @ApiModelProperty(value = "状态,0失效,1生效") | |||||
| private Integer state; | private Integer state; | ||||
| @@ -105,6 +93,14 @@ public class Workflow extends BaseMetaObjectHandler implements Serializable { | |||||
| this.dag = dag; | this.dag = dag; | ||||
| } | } | ||||
| public String getGlobalParam() { | |||||
| return globalParam; | |||||
| } | |||||
| public void setGlobalParam(String globalParam) { | |||||
| this.globalParam = globalParam; | |||||
| } | |||||
| public String getCreateBy() { | public String getCreateBy() { | ||||
| return createBy; | return createBy; | ||||
| } | } | ||||
| @@ -90,5 +90,7 @@ public interface ExperimentInsDao { | |||||
| List<ExperimentIns> getByExperimentId(Integer experimentId); | List<ExperimentIns> getByExperimentId(Integer experimentId); | ||||
| List<ExperimentIns> queryByExperiment(@Param("experimentIns") ExperimentIns experimentIns); | List<ExperimentIns> queryByExperiment(@Param("experimentIns") ExperimentIns experimentIns); | ||||
| List<ExperimentIns> queryByExperimentId(Integer id); | |||||
| } | } | ||||
| @@ -2,6 +2,7 @@ package com.ruoyi.platform.service; | |||||
| import com.ruoyi.platform.domain.ExperimentIns; | import com.ruoyi.platform.domain.ExperimentIns; | ||||
| import com.ruoyi.platform.vo.LogRequestVo; | import com.ruoyi.platform.vo.LogRequestVo; | ||||
| import com.ruoyi.platform.vo.PodLogVo; | |||||
| import org.springframework.data.domain.Page; | import org.springframework.data.domain.Page; | ||||
| import org.springframework.data.domain.PageRequest; | import org.springframework.data.domain.PageRequest; | ||||
| @@ -94,4 +95,7 @@ public interface ExperimentInsService { | |||||
| Map<String, Object> getRealtimeWorkflowLog(LogRequestVo logRequest); | Map<String, Object> getRealtimeWorkflowLog(LogRequestVo logRequest); | ||||
| Map<String, Object> getRealtimePodLog(String podName, String startTime); | Map<String, Object> getRealtimePodLog(String podName, String startTime); | ||||
| String getRealtimePodLogFromPod(PodLogVo podLogVo); | |||||
| } | } | ||||
| @@ -1,5 +1,6 @@ | |||||
| package com.ruoyi.platform.service; | package com.ruoyi.platform.service; | ||||
| import com.fasterxml.jackson.core.JsonProcessingException; | |||||
| import com.ruoyi.platform.domain.Workflow; | import com.ruoyi.platform.domain.Workflow; | ||||
| import org.springframework.data.domain.Page; | import org.springframework.data.domain.Page; | ||||
| import org.springframework.data.domain.PageRequest; | import org.springframework.data.domain.PageRequest; | ||||
| @@ -9,6 +9,7 @@ import com.ruoyi.platform.service.ExperimentInsService; | |||||
| import com.ruoyi.platform.service.WorkflowService; | import com.ruoyi.platform.service.WorkflowService; | ||||
| import com.ruoyi.platform.utils.*; | import com.ruoyi.platform.utils.*; | ||||
| import com.ruoyi.platform.vo.LogRequestVo; | import com.ruoyi.platform.vo.LogRequestVo; | ||||
| import com.ruoyi.platform.vo.PodLogVo; | |||||
| import com.ruoyi.system.api.model.LoginUser; | import com.ruoyi.system.api.model.LoginUser; | ||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||
| @@ -51,6 +52,9 @@ public class ExperimentInsServiceImpl implements ExperimentInsService { | |||||
| private String argoWorkflowRealTimeLog; | private String argoWorkflowRealTimeLog; | ||||
| @Value("${argo.workflowPodLog}") | @Value("${argo.workflowPodLog}") | ||||
| private String argoWorkflowPodLog; | private String argoWorkflowPodLog; | ||||
| @Value("${argo.ins.logsLines}") | |||||
| private int logsLines; | |||||
| private final MinioUtil minioUtil; | private final MinioUtil minioUtil; | ||||
| public ExperimentInsServiceImpl(MinioUtil minioUtil) { | public ExperimentInsServiceImpl(MinioUtil minioUtil) { | ||||
| @@ -91,7 +95,7 @@ public class ExperimentInsServiceImpl implements ExperimentInsService { | |||||
| //搞个标记,当状态改变才去改表 | //搞个标记,当状态改变才去改表 | ||||
| boolean flag = false; | boolean flag = false; | ||||
| List<ExperimentIns> result = new ArrayList<ExperimentIns>(); | List<ExperimentIns> result = new ArrayList<ExperimentIns>(); | ||||
| if (experimentInsList!=null&&experimentInsList.size()>0) { | |||||
| if (experimentInsList!=null && experimentInsList.size()>0) { | |||||
| for (ExperimentIns experimentIns : experimentInsList) { | for (ExperimentIns experimentIns : experimentInsList) { | ||||
| //当原本状态为null或非终止态时才调用argo接口 | //当原本状态为null或非终止态时才调用argo接口 | ||||
| if (experimentIns != null && (StringUtils.isEmpty(experimentIns.getStatus())) || !isTerminatedState(experimentIns)) { | if (experimentIns != null && (StringUtils.isEmpty(experimentIns.getStatus())) || !isTerminatedState(experimentIns)) { | ||||
| @@ -107,11 +111,9 @@ public class ExperimentInsServiceImpl implements ExperimentInsService { | |||||
| } | } | ||||
| //新增查询tensorBoard容器状态 | //新增查询tensorBoard容器状态 | ||||
| result.add(experimentIns); | result.add(experimentIns); | ||||
| } | } | ||||
| } | } | ||||
| if (flag) { | if (flag) { | ||||
| List<String> statusList = new ArrayList<String>(); | List<String> statusList = new ArrayList<String>(); | ||||
| // 更新实验状态列表 | // 更新实验状态列表 | ||||
| @@ -227,9 +229,7 @@ public class ExperimentInsServiceImpl implements ExperimentInsService { | |||||
| @Override | @Override | ||||
| public List<ExperimentIns> queryByExperimentId(Integer id) { | public List<ExperimentIns> queryByExperimentId(Integer id) { | ||||
| ExperimentIns experimentIns = new ExperimentIns(); | |||||
| experimentIns.setExperimentId(id); | |||||
| return experimentInsDao.queryByExperiment(experimentIns); | |||||
| return experimentInsDao.queryByExperimentId(id); | |||||
| } | } | ||||
| @Override | @Override | ||||
| @@ -518,6 +518,11 @@ public class ExperimentInsServiceImpl implements ExperimentInsService { | |||||
| } | } | ||||
| @Override | |||||
| public String getRealtimePodLogFromPod(PodLogVo podLogVo) { | |||||
| return K8sClientUtil.getPodLogs(podLogVo.getPodName(), podLogVo.getNamespace(),podLogVo.getContainerName(), logsLines); | |||||
| } | |||||
| private boolean isTerminatedState(ExperimentIns ins) throws IOException { | private boolean isTerminatedState(ExperimentIns ins) throws IOException { | ||||
| // 定义终止态的列表,例如 "Succeeded", "Failed" 等 | // 定义终止态的列表,例如 "Succeeded", "Failed" 等 | ||||
| String status = ins.getStatus(); | String status = ins.getStatus(); | ||||
| @@ -10,6 +10,7 @@ import com.ruoyi.platform.service.ExperimentInsService; | |||||
| import com.ruoyi.platform.service.ExperimentService; | import com.ruoyi.platform.service.ExperimentService; | ||||
| import com.ruoyi.platform.service.WorkflowService; | import com.ruoyi.platform.service.WorkflowService; | ||||
| import com.ruoyi.platform.utils.HttpUtils; | import com.ruoyi.platform.utils.HttpUtils; | ||||
| import com.ruoyi.platform.utils.JacksonUtil; | |||||
| import com.ruoyi.platform.utils.JsonUtils; | import com.ruoyi.platform.utils.JsonUtils; | ||||
| import com.ruoyi.system.api.model.LoginUser; | import com.ruoyi.system.api.model.LoginUser; | ||||
| import org.apache.commons.collections4.MapUtils; | import org.apache.commons.collections4.MapUtils; | ||||
| @@ -225,7 +226,12 @@ public class ExperimentServiceImpl implements ExperimentService { | |||||
| // 组装运行接口json | // 组装运行接口json | ||||
| Map<String, Object> runReqMap = new HashMap<>(); | Map<String, Object> runReqMap = new HashMap<>(); | ||||
| runReqMap.put("data", converMap.get("data")); | runReqMap.put("data", converMap.get("data")); | ||||
| runReqMap.put("params", JsonUtils.jsonToMap(StringUtils.isEmpty(experiment.getGlobalParam())?"{}":experiment.getGlobalParam())); | |||||
| //这里全局参数是一个json数组,需要转换成一个list<Map> | |||||
| List<Map<String, Object>> params = JacksonUtil.parseJSONStr2MapList(StringUtils.isEmpty(experiment.getGlobalParam()) ? "[]" : experiment.getGlobalParam()); | |||||
| runReqMap.put("params", params); | |||||
| runReqMap.put("experiment", new HashMap<String, Object>().put("name", "experiment-"+experiment.getId())); | |||||
| Map<String ,Object> output = (Map<String, Object>) converMap.get("output"); | Map<String ,Object> output = (Map<String, Object>) converMap.get("output"); | ||||
| // 调argo运行接口 | // 调argo运行接口 | ||||
| String runRes = HttpUtils.sendPost(argoUrl + argoWorkflowRun, JsonUtils.mapToJson(runReqMap)); | String runRes = HttpUtils.sendPost(argoUrl + argoWorkflowRun, JsonUtils.mapToJson(runReqMap)); | ||||
| @@ -243,10 +249,15 @@ public class ExperimentServiceImpl implements ExperimentService { | |||||
| Map<String, Object> metadata = (Map<String, Object>) data.get("metadata"); | Map<String, Object> metadata = (Map<String, Object>) data.get("metadata"); | ||||
| // 插入记录到实验实例表 | |||||
| ExperimentIns experimentIns = new ExperimentIns(); | ExperimentIns experimentIns = new ExperimentIns(); | ||||
| experimentIns.setExperimentId(experiment.getId()); | experimentIns.setExperimentId(experiment.getId()); | ||||
| experimentIns.setArgoInsNs((String) metadata.get("namespace")); | experimentIns.setArgoInsNs((String) metadata.get("namespace")); | ||||
| experimentIns.setArgoInsName((String) metadata.get("name")); | experimentIns.setArgoInsName((String) metadata.get("name")); | ||||
| //传入实验全局参数 | |||||
| experimentIns.setGlobalParam(experiment.getGlobalParam()); | |||||
| //替换argoInsName | //替换argoInsName | ||||
| String outputString = JsonUtils.mapToJson(output); | String outputString = JsonUtils.mapToJson(output); | ||||
| @@ -257,10 +268,9 @@ public class ExperimentServiceImpl implements ExperimentService { | |||||
| }catch (Exception e){ | }catch (Exception e){ | ||||
| throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
| } | } | ||||
| List<ExperimentIns> experimentIns = experimentInsService.queryByExperimentId(id); | |||||
| List<ExperimentIns> updatedExperimentInsList = experimentInsService.getByExperimentId(id); | |||||
| experiment.setExperimentInsList(experimentIns); | |||||
| experiment.setExperimentInsList(updatedExperimentInsList); | |||||
| return experiment; | return experiment; | ||||
| } | } | ||||
| @@ -153,6 +153,8 @@ public class WorkflowServiceImpl implements WorkflowService { | |||||
| return new PageImpl<>(this.workflowDao.queryByName(name)); | return new PageImpl<>(this.workflowDao.queryByName(name)); | ||||
| } | } | ||||
| @Override | @Override | ||||
| public Workflow duplicateWorkflow(Long id) { | public Workflow duplicateWorkflow(Long id) { | ||||
| //先去查找数据库中存在的数据 | //先去查找数据库中存在的数据 | ||||
| @@ -180,6 +182,7 @@ public class WorkflowServiceImpl implements WorkflowService { | |||||
| } | } | ||||
| duplicateWorkflow.setDag(newDag); | duplicateWorkflow.setDag(newDag); | ||||
| duplicateWorkflow.setDescription(workflow.getDescription()); | duplicateWorkflow.setDescription(workflow.getDescription()); | ||||
| duplicateWorkflow.setGlobalParam(workflow.getGlobalParam()); | |||||
| return this.insert(duplicateWorkflow); | return this.insert(duplicateWorkflow); | ||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| throw new RuntimeException("复制流水线失败: " + e.getMessage(), e); | throw new RuntimeException("复制流水线失败: " + e.getMessage(), e); | ||||
| @@ -1,13 +1,16 @@ | |||||
| package com.ruoyi.platform.utils; | package com.ruoyi.platform.utils; | ||||
| import com.alibaba.nacos.shaded.com.google.gson.reflect.TypeToken; | |||||
| import io.kubernetes.client.Exec; | import io.kubernetes.client.Exec; | ||||
| import io.kubernetes.client.custom.IntOrString; | import io.kubernetes.client.custom.IntOrString; | ||||
| import io.kubernetes.client.custom.Quantity; | import io.kubernetes.client.custom.Quantity; | ||||
| import io.kubernetes.client.openapi.ApiClient; | import io.kubernetes.client.openapi.ApiClient; | ||||
| import io.kubernetes.client.openapi.ApiException; | import io.kubernetes.client.openapi.ApiException; | ||||
| import io.kubernetes.client.openapi.ApiResponse; | |||||
| import io.kubernetes.client.openapi.apis.CoreV1Api; | import io.kubernetes.client.openapi.apis.CoreV1Api; | ||||
| import io.kubernetes.client.openapi.models.*; | import io.kubernetes.client.openapi.models.*; | ||||
| import io.kubernetes.client.util.ClientBuilder; | import io.kubernetes.client.util.ClientBuilder; | ||||
| import io.kubernetes.client.util.Watch; | |||||
| import io.kubernetes.client.util.credentials.AccessTokenAuthentication; | import io.kubernetes.client.util.credentials.AccessTokenAuthentication; | ||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||
| import org.apache.commons.lang.StringUtils; | import org.apache.commons.lang.StringUtils; | ||||
| @@ -15,7 +18,6 @@ import org.springframework.beans.factory.annotation.Value; | |||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
| import java.io.BufferedReader; | import java.io.BufferedReader; | ||||
| import java.io.IOException; | |||||
| import java.io.InputStreamReader; | import java.io.InputStreamReader; | ||||
| import java.util.HashMap; | import java.util.HashMap; | ||||
| import java.util.LinkedHashMap; | import java.util.LinkedHashMap; | ||||
| @@ -402,13 +404,14 @@ public class K8sClientUtil { | |||||
| return pod.getStatus().getPhase(); | return pod.getStatus().getPhase(); | ||||
| } | } | ||||
| public static String getPodLogs(String podName,String namespace,int line) { | |||||
| public static String getPodLogs(String podName,String namespace,String container,int line) { | |||||
| CoreV1Api api = new CoreV1Api(apiClient); | CoreV1Api api = new CoreV1Api(apiClient); | ||||
| try { | try { | ||||
| String log = api.readNamespacedPodLog(podName, namespace, null, null, null, null, null,null, null, line, null); | |||||
| String log = api.readNamespacedPodLog(podName, namespace, StringUtils.isEmpty(container)?null:container, null, null, null, null,null, null, line, null); | |||||
| return log; | return log; | ||||
| } catch (ApiException e) { | } catch (ApiException e) { | ||||
| throw new RuntimeException("获取Pod日志异常", e); | throw new RuntimeException("获取Pod日志异常", e); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,37 @@ | |||||
| package com.ruoyi.platform.vo; | |||||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |||||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | |||||
| import java.io.Serializable; | |||||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | |||||
| public class PodLogVo implements Serializable { | |||||
| private String podName; | |||||
| private String namespace; | |||||
| private String containerName; | |||||
| public String getPodName() { | |||||
| return podName; | |||||
| } | |||||
| public void setPodName(String podName) { | |||||
| this.podName = podName; | |||||
| } | |||||
| public String getNamespace() { | |||||
| return namespace; | |||||
| } | |||||
| public void setNamespace(String namespace) { | |||||
| this.namespace = namespace; | |||||
| } | |||||
| public String getContainerName() { | |||||
| return containerName; | |||||
| } | |||||
| public void setContainerName(String containerName) { | |||||
| this.containerName = containerName; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,69 @@ | |||||
| package com.ruoyi.platform.webSocket; | |||||
| import javax.annotation.Resource; | |||||
| import javax.websocket.*; | |||||
| import javax.websocket.server.PathParam; | |||||
| import javax.websocket.server.ServerEndpoint; | |||||
| import com.ruoyi.platform.service.ExperimentInsService; | |||||
| import com.ruoyi.platform.utils.K8sClientUtil; | |||||
| import org.springframework.stereotype.Component; | |||||
| import lombok.extern.slf4j.Slf4j; | |||||
| import org.springframework.web.bind.annotation.RestController; | |||||
| import java.io.IOException; | |||||
| import java.util.concurrent.CopyOnWriteArraySet; | |||||
| import java.util.concurrent.ConcurrentHashMap; | |||||
| @Component | |||||
| @Slf4j | |||||
| @ServerEndpoint("/websocket/workflowLogs") | |||||
| @RestController | |||||
| public class WebSocket { | |||||
| private Session session; | |||||
| private String userId; | |||||
| private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>(); | |||||
| private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<>(); | |||||
| @OnOpen | |||||
| public void onOpen(Session session, @PathParam("userId") String userId) { | |||||
| try { | |||||
| this.session = session; | |||||
| this.userId = "workflowLogs"; | |||||
| webSockets.add(this); | |||||
| sessionPool.put(userId, session); | |||||
| log.info("【WebSocket 消息】有新的连接,总数为:" + webSockets.size()); | |||||
| } catch (Exception e) { | |||||
| // 异常处理 | |||||
| } | |||||
| } | |||||
| @OnClose | |||||
| public void onClose() { | |||||
| try { | |||||
| webSockets.remove(this); | |||||
| sessionPool.remove(this.userId); | |||||
| log.info("【WebSocket 消息】连接断开,总数为:" + webSockets.size()); | |||||
| } catch (Exception e) { | |||||
| // 异常处理 | |||||
| } | |||||
| } | |||||
| @OnMessage | |||||
| public void onMessage(String message, Session session) { | |||||
| log.info("【WebSocket 消息】收到客户端消息:" + message); | |||||
| // 处理收到的消息,例如获取实时日志数据 | |||||
| // 推送日志数据给客户端 | |||||
| try { | |||||
| session.getBasicRemote().sendText("nihao"); | |||||
| } catch (Exception e) { | |||||
| log.error("【WebSocket 消息】推送日志数据失败:" + e.getMessage()); | |||||
| } | |||||
| } | |||||
| @OnError | |||||
| public void onError(Session session, Throwable error) { | |||||
| log.error("【WebSocket 消息】发生错误:" + error.getMessage()); | |||||
| } | |||||
| } | |||||
| @@ -84,7 +84,7 @@ | |||||
| and global_param = #{experiment.globalParam} | and global_param = #{experiment.globalParam} | ||||
| </if> | </if> | ||||
| <if test="experiment.statusList != null and experiment.statusList != ''"> | <if test="experiment.statusList != null and experiment.statusList != ''"> | ||||
| status_list = #{experiment.statusList}, | |||||
| status_list = #{experiment.statusList} | |||||
| </if> | </if> | ||||
| <if test="experiment.description != null and experiment.description != ''"> | <if test="experiment.description != null and experiment.description != ''"> | ||||
| and description = #{experiment.description} | and description = #{experiment.description} | ||||
| @@ -125,7 +125,7 @@ | |||||
| and global_param = #{experiment.globalParam} | and global_param = #{experiment.globalParam} | ||||
| </if> | </if> | ||||
| <if test="experiment.statusList != null and experiment.statusList != ''"> | <if test="experiment.statusList != null and experiment.statusList != ''"> | ||||
| status_list = #{experiment.statusList}, | |||||
| status_list = #{experiment.statusList} | |||||
| </if> | </if> | ||||
| <if test="experiment.description != null and experiment.description != ''"> | <if test="experiment.description != null and experiment.description != ''"> | ||||
| and description = #{experiment.description} | and description = #{experiment.description} | ||||
| @@ -148,7 +148,7 @@ | |||||
| <!--新增所有列--> | <!--新增所有列--> | ||||
| <insert id="insert" keyProperty="id" useGeneratedKeys="true"> | <insert id="insert" keyProperty="id" useGeneratedKeys="true"> | ||||
| insert into experiment(name,workflow_id, global_param, status_list, description, create_by, create_time, update_by, update_time, state) | insert into experiment(name,workflow_id, global_param, status_list, description, create_by, create_time, update_by, update_time, state) | ||||
| values (#{experiment.name},#{experiment.workflowId}, #{experiment.globalParam},#{experiment.statusList}, #{experiment.description}, #{experiment.createBy}, #{experiment.createTime}, #{experiment.updateBy}, #{experiment.updateTime}, #{experiment.state}) | |||||
| values (#{experiment.name},#{experiment.workflowId}, #{experiment.globalParam},#{experiment.statusList}, #{experiment.description}, #{experiment.createBy}, #{experiment.createTime}, #{experiment.updateBy}, #{experiment.updateTime}, #{experiment.state}) | |||||
| </insert> | </insert> | ||||
| <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true"> | <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true"> | ||||
| @@ -11,6 +11,7 @@ | |||||
| <result property="nodesStatus" column="nodes_status" jdbcType="VARCHAR"/> | <result property="nodesStatus" column="nodes_status" jdbcType="VARCHAR"/> | ||||
| <result property="nodesResult" column="nodes_result" jdbcType="VARCHAR"/> | <result property="nodesResult" column="nodes_result" jdbcType="VARCHAR"/> | ||||
| <result property="nodesLogs" column="nodes_logs" jdbcType="VARCHAR"/> | <result property="nodesLogs" column="nodes_logs" jdbcType="VARCHAR"/> | ||||
| <result property="globalParam" column="global_param" jdbcType="VARCHAR"/> | |||||
| <result property="startTime" column="start_time" jdbcType="TIMESTAMP"/> | <result property="startTime" column="start_time" jdbcType="TIMESTAMP"/> | ||||
| <result property="finishTime" column="finish_time" jdbcType="TIMESTAMP"/> | <result property="finishTime" column="finish_time" jdbcType="TIMESTAMP"/> | ||||
| <result property="createBy" column="create_by" jdbcType="VARCHAR"/> | <result property="createBy" column="create_by" jdbcType="VARCHAR"/> | ||||
| @@ -24,14 +25,14 @@ | |||||
| <!--查询单个--> | <!--查询单个--> | ||||
| <select id="queryById" resultMap="ExperimentInsMap"> | <select id="queryById" resultMap="ExperimentInsMap"> | ||||
| select id, experiment_id, argo_ins_name, argo_ins_ns, status, nodes_status,nodes_result, nodes_logs, start_time, finish_time, create_by, create_time, update_by, update_time, state | |||||
| select id, experiment_id, argo_ins_name, argo_ins_ns, status, nodes_status,nodes_result, nodes_logs,global_param, start_time, finish_time, create_by, create_time, update_by, update_time, state | |||||
| from experiment_ins | from experiment_ins | ||||
| where id = #{id} and state = 1 | where id = #{id} and state = 1 | ||||
| </select> | </select> | ||||
| <!--查询列表--> | <!--查询列表--> | ||||
| <select id="getByExperimentId" resultMap="ExperimentInsMap"> | <select id="getByExperimentId" resultMap="ExperimentInsMap"> | ||||
| select id, experiment_id, argo_ins_name, argo_ins_ns, status, nodes_status,nodes_result, nodes_logs, start_time, finish_time, create_by, create_time, update_by, update_time, state | |||||
| select id, experiment_id, argo_ins_name, argo_ins_ns, status, nodes_status,nodes_result, nodes_logs, global_param, start_time, finish_time, create_by, create_time, update_by, update_time, state | |||||
| from experiment_ins | from experiment_ins | ||||
| where experiment_id = #{experiment_id} and state = 1 | where experiment_id = #{experiment_id} and state = 1 | ||||
| order by create_time DESC | order by create_time DESC | ||||
| @@ -41,7 +42,7 @@ | |||||
| <select id="queryByExperiment" resultMap="ExperimentInsMap"> | <select id="queryByExperiment" resultMap="ExperimentInsMap"> | ||||
| select | select | ||||
| id, experiment_id, argo_ins_name, argo_ins_ns, status, nodes_status,nodes_result, nodes_logs, start_time, finish_time, create_by, create_time, update_by, update_time, state | |||||
| id, experiment_id, argo_ins_name, argo_ins_ns, status, nodes_status,nodes_result, nodes_logs,global_param, start_time, finish_time, create_by, create_time, update_by, update_time, state | |||||
| from experiment_ins | from experiment_ins | ||||
| <where> | <where> | ||||
| state = 1 | state = 1 | ||||
| @@ -66,6 +67,9 @@ | |||||
| <if test="experimentIns.nodesLogs != null and experimentIns.nodesLogs != ''"> | <if test="experimentIns.nodesLogs != null and experimentIns.nodesLogs != ''"> | ||||
| and nodes_logs = #{experimentIns.nodesLogs} | and nodes_logs = #{experimentIns.nodesLogs} | ||||
| </if> | </if> | ||||
| <if test="experimentIns.globalParam != null and experimentIns.globalParam != ''"> | |||||
| and global_param = #{experimentIns.globalParam} | |||||
| </if> | |||||
| <if test="experimentIns.startTime != null"> | <if test="experimentIns.startTime != null"> | ||||
| and start_time = #{experimentIns.startTime} | and start_time = #{experimentIns.startTime} | ||||
| </if> | </if> | ||||
| @@ -90,7 +94,7 @@ | |||||
| <!--查询指定行数据--> | <!--查询指定行数据--> | ||||
| <select id="queryAllByLimit" resultMap="ExperimentInsMap"> | <select id="queryAllByLimit" resultMap="ExperimentInsMap"> | ||||
| select | select | ||||
| id, experiment_id, argo_ins_name, argo_ins_ns, status, nodes_status,nodes_result, nodes_logs, start_time, finish_time, create_by, create_time, update_by, update_time, state | |||||
| id, experiment_id, argo_ins_name, argo_ins_ns, status, nodes_status,nodes_result, nodes_logs,global_param, start_time, finish_time, create_by, create_time, update_by, update_time, state | |||||
| from experiment_ins | from experiment_ins | ||||
| <where> | <where> | ||||
| state = 1 | state = 1 | ||||
| @@ -115,6 +119,9 @@ | |||||
| <if test="experimentIns.nodesLogs != null and experimentIns.nodesLogs != ''"> | <if test="experimentIns.nodesLogs != null and experimentIns.nodesLogs != ''"> | ||||
| and nodes_logs = #{experimentIns.nodesLogs} | and nodes_logs = #{experimentIns.nodesLogs} | ||||
| </if> | </if> | ||||
| <if test="experimentIns.globalParam != null and experimentIns.globalParam != ''"> | |||||
| and global_param = #{experimentIns.globalParam} | |||||
| </if> | |||||
| <if test="experimentIns.startTime != null"> | <if test="experimentIns.startTime != null"> | ||||
| and start_time = #{experimentIns.startTime} | and start_time = #{experimentIns.startTime} | ||||
| </if> | </if> | ||||
| @@ -165,6 +172,9 @@ | |||||
| <if test="experimentIns.nodesLogs != null and experimentIns.nodesLogs != ''"> | <if test="experimentIns.nodesLogs != null and experimentIns.nodesLogs != ''"> | ||||
| and nodes_logs = #{experimentIns.nodesLogs} | and nodes_logs = #{experimentIns.nodesLogs} | ||||
| </if> | </if> | ||||
| <if test="experimentIns.globalParam != null and experimentIns.globalParam != ''"> | |||||
| and global_param = #{experimentIns.globalParam} | |||||
| </if> | |||||
| <if test="experimentIns.startTime != null"> | <if test="experimentIns.startTime != null"> | ||||
| and start_time = #{experimentIns.startTime} | and start_time = #{experimentIns.startTime} | ||||
| </if> | </if> | ||||
| @@ -186,18 +196,24 @@ | |||||
| </where> | </where> | ||||
| </select> | </select> | ||||
| <select id="queryByExperimentId" resultMap="ExperimentInsMap"> | |||||
| select id, experiment_id, argo_ins_name, argo_ins_ns, status, nodes_status,nodes_result, nodes_logs, global_param, start_time, finish_time, create_by, create_time, update_by, update_time, state | |||||
| from experiment_ins | |||||
| where experiment_id = #{id} and state = 1 | |||||
| </select> | |||||
| <!--新增所有列--> | <!--新增所有列--> | ||||
| <insert id="insert" keyProperty="id" useGeneratedKeys="true"> | <insert id="insert" keyProperty="id" useGeneratedKeys="true"> | ||||
| insert into experiment_ins(experiment_id,argo_ins_name,argo_ins_ns,status,nodes_status,nodes_result,nodes_logs,start_time,finish_time,create_by,create_time,update_by,update_time,state) | |||||
| values (#{experimentIns.experimentId},#{experimentIns.argoInsName},#{experimentIns.argoInsNs},#{experimentIns.status},#{experimentIns.nodesStatus},#{experimentIns.nodesResult},#{experimentIns.nodesLogs},#{experimentIns.startTime},#{experimentIns.finishTime},#{experimentIns.createBy},#{experimentIns.createTime},#{experimentIns.updateBy},#{experimentIns.updateTime},#{experimentIns.state}) | |||||
| insert into experiment_ins(experiment_id,argo_ins_name,argo_ins_ns,status,nodes_status,nodes_result,nodes_logs,global_param,start_time,finish_time,create_by,create_time,update_by,update_time,state) | |||||
| values (#{experimentIns.experimentId},#{experimentIns.argoInsName},#{experimentIns.argoInsNs},#{experimentIns.status},#{experimentIns.nodesStatus},#{experimentIns.nodesResult},#{experimentIns.nodesLogs},#{experimentIns.globalParam},#{experimentIns.startTime},#{experimentIns.finishTime},#{experimentIns.createBy},#{experimentIns.createTime},#{experimentIns.updateBy},#{experimentIns.updateTime},#{experimentIns.state}) | |||||
| </insert> | </insert> | ||||
| <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true"> | <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true"> | ||||
| insert into | insert into | ||||
| experiment_ins(experiment_id,argo_ins_name,argo_ins_ns,status,nodes_status,nodes_result,nodes_logs,start_time,finish_time,create_by,create_time,update_by,update_time,state) | |||||
| experiment_ins(experiment_id,argo_ins_name,argo_ins_ns,status,nodes_status,nodes_result,nodes_logs,global_param,start_time,finish_time,create_by,create_time,update_by,update_time,state) | |||||
| values | values | ||||
| <foreach collection="entities" item="entity" separator=","> | <foreach collection="entities" item="entity" separator=","> | ||||
| (#{entity.experimentId},#{entity.argoInsName},#{entity.argoInsNs},#{entity.status},#{entity.nodesStatus},#{entity.nodesResult},#{entity.nodesLogs},#{entity.startTime},#{entity.finishTime},#{entity.createBy},#{entity.createTime},#{entity.updateBy},#{entity.updateTime},#{entity.state}) | |||||
| (#{entity.experimentId},#{entity.argoInsName},#{entity.argoInsNs},#{entity.status},#{entity.nodesStatus},#{entity.nodesResult},#{entity.nodesLogs},#{entity.globalParam},#{entity.startTime},#{entity.finishTime},#{entity.createBy},#{entity.createTime},#{entity.updateBy},#{entity.updateTime},#{entity.state}) | |||||
| </foreach> | </foreach> | ||||
| </insert> | </insert> | ||||
| @@ -238,6 +254,9 @@ | |||||
| <if test="experimentIns.nodesLogs != null and experimentIns.nodesLogs != ''"> | <if test="experimentIns.nodesLogs != null and experimentIns.nodesLogs != ''"> | ||||
| nodes_logs = #{experimentIns.nodesLogs}, | nodes_logs = #{experimentIns.nodesLogs}, | ||||
| </if> | </if> | ||||
| <if test="experimentIns.globalParam != null and experimentIns.globalParam != ''"> | |||||
| global_param = #{experimentIns.globalParam}, | |||||
| </if> | |||||
| <if test="experimentIns.startTime != null"> | <if test="experimentIns.startTime != null"> | ||||
| start_time = #{experimentIns.startTime}, | start_time = #{experimentIns.startTime}, | ||||
| </if> | </if> | ||||
| @@ -7,6 +7,7 @@ | |||||
| <result property="name" column="name" jdbcType="VARCHAR"/> | <result property="name" column="name" jdbcType="VARCHAR"/> | ||||
| <result property="description" column="description" jdbcType="VARCHAR"/> | <result property="description" column="description" jdbcType="VARCHAR"/> | ||||
| <result property="dag" column="dag" jdbcType="VARCHAR"/> | <result property="dag" column="dag" jdbcType="VARCHAR"/> | ||||
| <result property="globalParam" column="global_param" jdbcType="VARCHAR"/> | |||||
| <result property="createBy" column="create_by" jdbcType="VARCHAR"/> | <result property="createBy" column="create_by" jdbcType="VARCHAR"/> | ||||
| <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/> | <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/> | ||||
| <result property="updateBy" column="update_by" jdbcType="VARCHAR"/> | <result property="updateBy" column="update_by" jdbcType="VARCHAR"/> | ||||
| @@ -17,7 +18,7 @@ | |||||
| <!--查询单个--> | <!--查询单个--> | ||||
| <select id="queryById" resultMap="WorkflowMap"> | <select id="queryById" resultMap="WorkflowMap"> | ||||
| select | select | ||||
| id, name, description, dag, create_by, create_time, update_by, update_time, state | |||||
| id, name, description, dag, global_param, create_by, create_time, update_by, update_time, state | |||||
| from workflow | from workflow | ||||
| where id = #{id} and state = 1 | where id = #{id} and state = 1 | ||||
| </select> | </select> | ||||
| @@ -25,7 +26,7 @@ | |||||
| <!--查询指定行数据--> | <!--查询指定行数据--> | ||||
| <select id="queryAllByLimit" resultMap="WorkflowMap" > | <select id="queryAllByLimit" resultMap="WorkflowMap" > | ||||
| select | select | ||||
| id, name, description, dag, create_by, create_time, update_by, update_time, state | |||||
| id, name, description, dag, global_param, create_by, create_time, update_by, update_time, state | |||||
| from workflow | from workflow | ||||
| <where> | <where> | ||||
| state = 1 | state = 1 | ||||
| @@ -41,6 +42,9 @@ | |||||
| <if test="workflow.dag != null and workflow.dag != ''"> | <if test="workflow.dag != null and workflow.dag != ''"> | ||||
| and dag = #{workflow.dag} | and dag = #{workflow.dag} | ||||
| </if> | </if> | ||||
| <if test="workflow.globalParam != null and workflow.globalParam != ''"> | |||||
| and global_param = #{workflow.globalParam} | |||||
| </if> | |||||
| <if test="workflow.createBy != null and workflow.createBy != ''"> | <if test="workflow.createBy != null and workflow.createBy != ''"> | ||||
| and create_by = #{workflow.createBy} | and create_by = #{workflow.createBy} | ||||
| </if> | </if> | ||||
| @@ -76,6 +80,9 @@ | |||||
| <if test="workflow.dag != null and workflow.dag != ''"> | <if test="workflow.dag != null and workflow.dag != ''"> | ||||
| and dag = #{workflow.dag} | and dag = #{workflow.dag} | ||||
| </if> | </if> | ||||
| <if test="workflow.globalParam != null and workflow.globalParam != ''"> | |||||
| and global_param = #{workflow.globalParam} | |||||
| </if> | |||||
| <if test="workflow.createBy != null and workflow.createBy != ''"> | <if test="workflow.createBy != null and workflow.createBy != ''"> | ||||
| and create_by = #{workflow.createBy} | and create_by = #{workflow.createBy} | ||||
| </if> | </if> | ||||
| @@ -93,26 +100,26 @@ | |||||
| <!--新增所有列--> | <!--新增所有列--> | ||||
| <insert id="insert" keyProperty="id" useGeneratedKeys="true"> | <insert id="insert" keyProperty="id" useGeneratedKeys="true"> | ||||
| insert into workflow(name, description, dag, create_by, create_time, update_by, update_time,state) | |||||
| values (#{workflow.name}, #{workflow.description}, #{workflow.dag}, #{workflow.createBy}, #{workflow.createTime}, #{workflow.updateBy}, #{workflow.updateTime}, #{workflow.state}) | |||||
| insert into workflow(name, description, dag, global_param, create_by, create_time, update_by, update_time,state) | |||||
| values (#{workflow.name}, #{workflow.description}, #{workflow.dag},#{workflow.globalParam}, #{workflow.createBy}, #{workflow.createTime}, #{workflow.updateBy}, #{workflow.updateTime}, #{workflow.state}) | |||||
| </insert> | </insert> | ||||
| <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true"> | <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true"> | ||||
| insert into workflow(name, description, dag, create_by, create_time, update_by, update_time, state) | |||||
| insert into workflow(name, description, dag, global_param, create_by, create_time, update_by, update_time, state) | |||||
| values | values | ||||
| <foreach collection="entities" item="entity" separator=","> | <foreach collection="entities" item="entity" separator=","> | ||||
| (#{entity.name}, #{entity.description}, #{entity.dag}, #{entity.createBy}, #{entity.createTime}, | |||||
| (#{entity.name}, #{entity.description}, #{entity.dag}, #{entity.globalParam}, #{entity.createBy}, #{entity.createTime}, | |||||
| #{entity.updateBy}, #{entity.updateTime}, #{entity.state}) | #{entity.updateBy}, #{entity.updateTime}, #{entity.state}) | ||||
| </foreach> | </foreach> | ||||
| </insert> | </insert> | ||||
| <insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true"> | <insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true"> | ||||
| insert into workflow(name, description, dag, create_by, create_time, update_by, update_time, state) | |||||
| insert into workflow(name, description, dag, global_param, create_by, create_time, update_by, update_time, state) | |||||
| values | values | ||||
| <foreach collection="entities" item="entity" separator=","> | <foreach collection="entities" item="entity" separator=","> | ||||
| (#{entity.name}, #{entity.description}, #{entity.dag}, #{entity.createBy}, #{entity.createTime}, | |||||
| (#{entity.name}, #{entity.description}, #{entity.dag}, #{entity.globalParam},#{entity.createBy}, #{entity.createTime}, | |||||
| #{entity.updateBy}, #{entity.updateTime}, #{entity.state}) | #{entity.updateBy}, #{entity.updateTime}, #{entity.state}) | ||||
| </foreach> | </foreach> | ||||
| on duplicate key update | on duplicate key update | ||||
| @@ -139,6 +146,9 @@ | |||||
| <if test="workflow.dag != null and workflow.dag != ''"> | <if test="workflow.dag != null and workflow.dag != ''"> | ||||
| dag = #{workflow.dag}, | dag = #{workflow.dag}, | ||||
| </if> | </if> | ||||
| <if test="workflow.globalParam != null and workflow.globalParam != ''"> | |||||
| global_param = #{workflow.globalParam}, | |||||
| </if> | |||||
| <if test="workflow.createBy != null and workflow.createBy != ''"> | <if test="workflow.createBy != null and workflow.createBy != ''"> | ||||
| create_by = #{workflow.createBy}, | create_by = #{workflow.createBy}, | ||||
| </if> | </if> | ||||
| @@ -166,7 +176,7 @@ | |||||
| <!--通过流水线名字进行模糊查询--> | <!--通过流水线名字进行模糊查询--> | ||||
| <select id="queryByName" resultMap="WorkflowMap"> | <select id="queryByName" resultMap="WorkflowMap"> | ||||
| select | select | ||||
| id, name, description, dag, create_by, create_time, update_by, update_time, state | |||||
| id, name, description, dag, global_param, create_by, create_time, update_by, update_time, state | |||||
| from workflow | from workflow | ||||
| <where> | <where> | ||||
| state = 1 | state = 1 | ||||
| @@ -7,7 +7,7 @@ | |||||
| <result property="workflowId" column="workflow_id" jdbcType="INTEGER"/> | <result property="workflowId" column="workflow_id" jdbcType="INTEGER"/> | ||||
| <result property="paramName" column="param_name" jdbcType="VARCHAR"/> | <result property="paramName" column="param_name" jdbcType="VARCHAR"/> | ||||
| <result property="description" column="description" jdbcType="VARCHAR"/> | <result property="description" column="description" jdbcType="VARCHAR"/> | ||||
| <result property="paramType" column="param_type" jdbcType="INTEGER"/> | |||||
| <result property="paramType" column="param_type" jdbcType="VARCHAR"/> | |||||
| <result property="paramValue" column="param_value" jdbcType="VARCHAR"/> | <result property="paramValue" column="param_value" jdbcType="VARCHAR"/> | ||||
| <result property="isSensitive" column="is_sensitive" jdbcType="INTEGER"/> | <result property="isSensitive" column="is_sensitive" jdbcType="INTEGER"/> | ||||
| <result property="createBy" column="create_by" jdbcType="VARCHAR"/> | <result property="createBy" column="create_by" jdbcType="VARCHAR"/> | ||||