Commit 5651e90b authored by chenshouchao's avatar chenshouchao

Merge branch 'feat-20220705-customTemplate' into 'release'

cn- Feat 20220705 custom template

See merge request sunyihao/bkunyun!99
parents 0ac8a41c ed3d6226
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com * @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-13 09:56:57 * @Date: 2022-06-13 09:56:57
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com * @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-07 18:19:20 * @LastEditTime: 2022-07-10 13:47:53
* @FilePath: /bkunyun/src/api/api_manager.ts * @FilePath: /bkunyun/src/api/api_manager.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
...@@ -37,6 +37,7 @@ const RESTAPI = { ...@@ -37,6 +37,7 @@ const RESTAPI = {
API_SUBMIT_WORKFLOW: `${BACKEND_API_URI_PREFIX}/cpp/workflow/submit`, //提交工作流 API_SUBMIT_WORKFLOW: `${BACKEND_API_URI_PREFIX}/cpp/workflow/submit`, //提交工作流
API_WORKBENCH_WORKFLOW_TASKINFO: `${BACKEND_API_URI_PREFIX}/cpp/workbench/workflowjob/task-info`, //查询任务某个算子详情 API_WORKBENCH_WORKFLOW_TASKINFO: `${BACKEND_API_URI_PREFIX}/cpp/workbench/workflowjob/task-info`, //查询任务某个算子详情
API_OPERATOR_LIST:`${BACKEND_API_URI_PREFIX}/cpp/workflow/actorspecs`, // 获取算子列表 API_OPERATOR_LIST:`${BACKEND_API_URI_PREFIX}/cpp/workflow/actorspecs`, // 获取算子列表
API_VERSION_OPERATOR:`${BACKEND_API_URI_PREFIX}/cpp/workflow/actorversion`, // 获取指定版本算子
}; };
export default RESTAPI; export default RESTAPI;
export interface IGetOperatorList { /*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-08 09:26:58
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-10 13:53:26
* @FilePath: /bkunyun/src/api/workbenchInterface.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
export interface IGetOperatorListParams {
owner: string; owner: string;
productId: string; productId: string;
keyword?: string keyword?: string
}
export interface IFetchOperatorListParams {
version: string;
title: string
} }
\ No newline at end of file
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com * @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-05 14:00:37 * @Date: 2022-07-05 14:00:37
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com * @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-07 18:24:16 * @LastEditTime: 2022-07-10 13:54:04
* @FilePath: /bkunyun/src/api/workbench_api.ts * @FilePath: /bkunyun/src/api/workbench_api.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
import request from "@/utils/axios/service"; import request from "@/utils/axios/service";
import Api from "./api_manager"; import Api from "./api_manager";
import { IGetOperatorList } from "./workbenchInterface"; import { IGetOperatorListParams, IFetchOperatorListParams } from "./workbenchInterface";
function current() { function current() {
return request({ return request({
...@@ -129,7 +129,7 @@ const cancelWorkflowJob = (params: workflowJobCancelParams) => { ...@@ -129,7 +129,7 @@ const cancelWorkflowJob = (params: workflowJobCancelParams) => {
}; };
// 获取算子列表数据 // 获取算子列表数据
const fetchOperatorList = (params: IGetOperatorList) => { const fetchOperatorList = (params: IGetOperatorListParams) => {
return request({ return request({
url: Api.API_OPERATOR_LIST, url: Api.API_OPERATOR_LIST,
method: "get", method: "get",
...@@ -137,6 +137,15 @@ const fetchOperatorList = (params: IGetOperatorList) => { ...@@ -137,6 +137,15 @@ const fetchOperatorList = (params: IGetOperatorList) => {
}); });
}; };
// 获取指定版本算子
const fetchVersionOperator = (params: IFetchOperatorListParams) => {
return request({
url: Api.API_VERSION_OPERATOR,
method: "get",
params,
});
};
export { export {
current, current,
menu, menu,
...@@ -147,5 +156,6 @@ export { ...@@ -147,5 +156,6 @@ export {
getWorkflowJobList, getWorkflowJobList,
deleteWorkflowJob, deleteWorkflowJob,
cancelWorkflowJob, cancelWorkflowJob,
fetchOperatorList fetchOperatorList,
fetchVersionOperator
}; };
...@@ -84,6 +84,7 @@ export default function MyCheckBox(props: IMyCheckBoxProps) { ...@@ -84,6 +84,7 @@ export default function MyCheckBox(props: IMyCheckBoxProps) {
label={option.label} label={option.label}
name={option.value} name={option.value}
onChange={handleMyCheckBoxOnChange} onChange={handleMyCheckBoxOnChange}
disabled={option.disabled}
/> />
); );
})} })}
......
...@@ -63,7 +63,11 @@ const MyMenu = (props: IMyMenuProps) => { ...@@ -63,7 +63,11 @@ const MyMenu = (props: IMyMenuProps) => {
}; };
const handleClose = (value: string) => { const handleClose = (value: string) => {
setAnchorEl(null); setAnchorEl(null);
};
const handleMenuClick = (value: string) => {
setValue && setValue(value); setValue && setValue(value);
setAnchorEl(null);
}; };
return ( return (
...@@ -82,7 +86,7 @@ const MyMenu = (props: IMyMenuProps) => { ...@@ -82,7 +86,7 @@ const MyMenu = (props: IMyMenuProps) => {
{options.map((option, index) => { {options.map((option, index) => {
return ( return (
<MenuItem <MenuItem
onClick={() => handleClose(option.value)} onClick={() => handleMenuClick(option.value)}
selected={value === option.value} selected={value === option.value}
key={index} key={index}
> >
......
// import * as React from "react";
// import { ReactNode, useEffect } from "react";
// import Box from "@mui/material/Box";
// import ButtonComponent from "./Button";
// import tipsIcon from "@/assets/project/information-outline.svg";
// import Popper from "@mui/material/Popper";
// type IMyPopconfirmProps = {
// title: string | ReactNode;
// cancelText?: string;
// okText?: string;
// showCancel?: boolean;
// onCancel?: any;
// onConfirm?: any;
// children: ReactNode;
// };
// const MyPopconfirm = (props: IMyPopconfirmProps) => {
// const {
// title,
// cancelText = "取消",
// okText = "确认",
// showCancel = true,
// onCancel,
// onConfirm,
// } = props;
// const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
// const handleClick = (event: React.MouseEvent<HTMLElement>) => {
// event.nativeEvent.stopImmediatePropagation();
// setAnchorEl(anchorEl ? null : event.currentTarget);
// };
// const open = Boolean(anchorEl);
// const id = open ? "simple-popper" : undefined;
// const handleCancel = () => {
// setAnchorEl(null);
// onCancel && onCancel();
// };
// const handleOk = () => {
// setAnchorEl(null);
// onConfirm && onConfirm();
// };
// useEffect(() => {
// document.addEventListener("click", (e) => {
// setAnchorEl(null);
// });
// }, []);
// return (
// <div>
// <div aria-describedby={id} onClick={handleClick}>
// {props.children && props.children}
// </div>
// <Popper
// id={id}
// open={open}
// anchorEl={anchorEl}
// sx={{
// zIndex: 2000,
// bgcolor: "#fff",
// minWidth: "200px",
// borderRadius: "2px",
// padding: "20px 16px",
// boxShadow: "0px 3px 10px 0px rgba(0, 24, 57, 0.14)",
// }}
// >
// {/* "0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d", */}
// <Box sx={{ marginBottom: "16px" }}>
// <img
// style={{ marginRight: "12px", position: "relative", top: "3px" }}
// src={tipsIcon}
// alt=""
// />
// {title}
// </Box>
// <Box sx={{ display: "flex", justifyContent: "flex-end" }}>
// {showCancel && (
// <ButtonComponent
// text={cancelText}
// // variant="text"
// size="small"
// color="inherit"
// click={handleCancel}
// style={{ marginRight: "12px" }}
// ></ButtonComponent>
// )}
// <ButtonComponent
// text={okText}
// // variant="text"
// size="small"
// click={handleOk}
// ></ButtonComponent>
// </Box>
// </Popper>
// </div>
// );
// };
// export default MyPopconfirm;
// 确认提示框, 支持同一页面多个提示框
import * as React from "react"; import * as React from "react";
import { ReactNode, useEffect } from "react"; import { ReactNode, useMemo } from "react";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import ButtonComponent from "./Button"; import ButtonComponent from "./Button";
import tipsIcon from "@/assets/project/information-outline.svg"; import tipsIcon from "@/assets/project/information-outline.svg";
import Popper from "@mui/material/Popper"; import Popper from "@mui/material/Popper";
type IMyPopconfirmProps = { type IMyPopconfirmProps = {
title: string | ReactNode; title: string | ReactNode;
cancelText?: string; placement?:
okText?: string; | "auto-end"
showCancel?: boolean; | "auto-start"
onCancel?: any; | "auto"
onConfirm?: any; | "bottom-end"
children: ReactNode; | "bottom-start"
| "bottom"
| "left-end"
| "left-start"
| "left"
| "right-end"
| "right-start"
| "right"
| "top-end"
| "top-start"
| "top";
anchorEl?: null | HTMLElement;
cancelText?: string;
okText?: string;
showCancel?: boolean;
onCancel?: any;
onConfirm?: any;
}; };
const MyPopconfirm = (props: IMyPopconfirmProps) => { const MyPopconfirm = (props: IMyPopconfirmProps) => {
const { const {
title, title,
cancelText = "取消", anchorEl,
okText = "确认", placement = "bottom",
showCancel = true, cancelText = "取消",
onCancel, okText = "确认",
onConfirm, showCancel = true,
} = props; onCancel,
onConfirm,
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); } = props;
const handleClick = (event: React.MouseEvent<HTMLElement>) => { const open = useMemo(() => {
event.nativeEvent.stopImmediatePropagation(); return Boolean(anchorEl);
setAnchorEl(anchorEl ? null : event.currentTarget); }, [anchorEl]);
};
const id = open ? "simple-popper" : undefined;
const open = Boolean(anchorEl);
const id = open ? "simple-popper" : undefined; const handleCancel = () => {
onCancel && onCancel();
const handleCancel = () => { };
setAnchorEl(null);
onCancel && onCancel(); const handleOk = () => {
}; onConfirm && onConfirm();
};
const handleOk = () => {
setAnchorEl(null); return (
onConfirm && onConfirm(); <Popper
}; id={id}
open={open}
useEffect(() => { anchorEl={anchorEl}
document.addEventListener("click", (e) => { placement={placement}
setAnchorEl(null); sx={{
}); zIndex: 2000,
}, []); bgcolor: "#fff",
minWidth: "200px",
return ( borderRadius: "2px",
<div> padding: "20px 16px",
<div aria-describedby={id} onClick={handleClick}> boxShadow: "0px 3px 10px 0px rgba(0, 24, 57, 0.14)",
{props.children && props.children} }}
</div> >
<Popper <Box sx={{ marginBottom: "16px" }}>
id={id} <img
open={open} style={{ marginRight: "12px", position: "relative", top: "3px" }}
anchorEl={anchorEl} src={tipsIcon}
sx={{ alt=""
zIndex: 2000, />
bgcolor: "#fff", {title}
minWidth: "200px", </Box>
borderRadius: "2px", <Box sx={{ display: "flex", justifyContent: "flex-end" }}>
padding: "20px 16px", {showCancel && (
boxShadow: "0px 3px 10px 0px rgba(0, 24, 57, 0.14)", <ButtonComponent
}} text={cancelText}
> size="small"
{/* "0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d", */} color="inherit"
<Box sx={{ marginBottom: "16px" }}> click={handleCancel}
<img style={{ marginRight: "12px" }}
style={{ marginRight: "12px", position: "relative", top: "3px" }} ></ButtonComponent>
src={tipsIcon} )}
alt="" <ButtonComponent
/> text={okText}
{title} size="small"
</Box> click={handleOk}
<Box sx={{ display: "flex", justifyContent: "flex-end" }}> ></ButtonComponent>
{showCancel && ( </Box>
<ButtonComponent </Popper>
text={cancelText} );
// variant="text"
size="small"
color="inherit"
click={handleCancel}
style={{ marginRight: "12px" }}
></ButtonComponent>
)}
<ButtonComponent
text={okText}
// variant="text"
size="small"
click={handleOk}
></ButtonComponent>
</Box>
</Popper>
</div>
);
}; };
export default MyPopconfirm; export default MyPopconfirm;
...@@ -64,6 +64,7 @@ export default function MyRadio(props: IMyRadioProps) { ...@@ -64,6 +64,7 @@ export default function MyRadio(props: IMyRadioProps) {
value={option.value} value={option.value}
control={<Radio />} control={<Radio />}
label={option.label} label={option.label}
disabled={option.disabled}
/> />
); );
})} })}
......
import * as React from 'react';
import Switch from '@mui/material/Switch';
import { ThemeProvider, createTheme } from "@mui/material/styles";
type IMySwitchProps = {
value: boolean;
onChange?: any;
disabled?: boolean;
}
const theme = createTheme({
components: {
MuiSwitch: {
styleOverrides: {
root: {
height: '22px',
width: '40px',
boxSizing: 'border-box',
padding: '0',
},
switchBase:{
top: '4px',
left: '4px',
padding: 0,
'&.Mui-checked': {
left: '2px',
'& + .MuiSwitch-track': {
opacity: 1,
}
},
},
thumb: {
width: '14px',
height: '14px',
color: '#fff'
},
track: {
borderRadius: '11px',
backgroundColor: "#E6E8EB",
opacity: 1,
},
},
},
},
});
const MySwitch = (props: IMySwitchProps) => {
const {value, onChange, disabled= false} = props;
return (
<ThemeProvider theme={theme}>
<Switch checked={value} disabled={disabled} onChange={onChange} />
</ThemeProvider>
)
}
export default MySwitch;
\ No newline at end of file
...@@ -11,27 +11,62 @@ import { isEqual } from "lodash"; ...@@ -11,27 +11,62 @@ import { isEqual } from "lodash";
import { useState } from "react"; import { useState } from "react";
import { Box } from "@mui/system"; import { Box } from "@mui/system";
import Tab from "@mui/material/Tab"; import Tab from "@mui/material/Tab";
import { ThemeProvider, createTheme } from "@mui/material/styles";
import { TabContext, TabList, TabPanel } from "@mui/lab"; import { TabContext, TabList, TabPanel } from "@mui/lab";
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";
interface ITabList { interface ITabList {
label: string; label: string;
value: string; value: string;
component: JSX.Element; component: JSX.Element | React.ReactNode;
icon?: string; icon?: string;
iconed?: string; iconed?: string;
hide?: boolean; hide?: boolean;
disabled?: boolean;
} }
interface IProps { interface IProps {
tabList: ITabList[]; tabList: ITabList[];
defaultValue?: string; defaultValue?: string;
allowNullValue?: boolean; // 是否允许空值
} }
const theme = createTheme({
components: {
MuiTab: {
styleOverrides: {
root: {
paddingLeft: 0,
paddingRight: 0,
paddingTop: '8px',
paddingBottom: '8px',
minWidth: '20px',
marginRight: '32px',
color: '#8A9099',
selected: {
color: '#1976d2'
},
"&.Mui-disabled": {
color: '#C2C6CC',
},
},
},
},
// #C2C6CC
MuiTabs:{
styleOverrides: {
indicator: {
backgroundColor: '#1370FF',
}
}
},
},
});
const Tabs = (props: IProps) => { const Tabs = (props: IProps) => {
const { tabList, defaultValue } = props; const { tabList, defaultValue, allowNullValue = false } = props;
const [value, setValue] = useState( const [value, setValue] = useState(
defaultValue || tabList.filter((e) => !e.hide)[0].value defaultValue ? defaultValue : allowNullValue ? '' : tabList.filter((e) => !e.hide)[0].value
); );
const onChange = (val: string) => { const onChange = (val: string) => {
...@@ -58,6 +93,7 @@ const Tabs = (props: IProps) => { ...@@ -58,6 +93,7 @@ const Tabs = (props: IProps) => {
}; };
return ( return (
<ThemeProvider theme={theme}>
<TabContext value={value}> <TabContext value={value}>
<Box sx={{ borderBottom: 1, borderColor: "#F0F2F5" }}> <Box sx={{ borderBottom: 1, borderColor: "#F0F2F5" }}>
<TabList <TabList
...@@ -74,6 +110,7 @@ const Tabs = (props: IProps) => { ...@@ -74,6 +110,7 @@ const Tabs = (props: IProps) => {
label={labelRender(item, key)} label={labelRender(item, key)}
value={item.value} value={item.value}
id={item.value} id={item.value}
disabled={item.disabled}
/> />
); );
})} })}
...@@ -93,6 +130,7 @@ const Tabs = (props: IProps) => { ...@@ -93,6 +130,7 @@ const Tabs = (props: IProps) => {
); );
})} })}
</TabContext> </TabContext>
</ThemeProvider>
); );
}; };
const handleEqual = (prvProps: IProps, nextProps: IProps) => { const handleEqual = (prvProps: IProps, nextProps: IProps) => {
......
...@@ -293,6 +293,30 @@ const ProjectSubmitWork = observer(() => { ...@@ -293,6 +293,30 @@ const ProjectSubmitWork = observer(() => {
} }
}, [isPass, state]); }, [isPass, state]);
const [goToProjectDataPath, setGoToProjectDataPath] = useState("");
const [popperTitle, setPopperTitle] = useState(
"正在运行的任务终止后将无法重新运行,确认继续吗?"
);
const [anchorEl, setAnchorEl] = useState<any>(null);
const handleCancel = () => {
setAnchorEl(null);
};
const handleShowPopper = (e: any, title: string) => {
setPopperTitle(title);
setAnchorEl(anchorEl ? null : e.currentTarget);
};
const handleConfirm = () => {
if (popperTitle === "正在运行的任务终止后将无法重新运行,确认继续吗?") {
onStopJob();
} else if (popperTitle === "任务被删除后将无法恢复,确认继续吗?") {
onDeleteJob();
} else {
goToProjectData(goToProjectDataPath);
}
};
return ( return (
<div className={styles.swBox}> <div className={styles.swBox}>
{fullScreenShow ? null : ( {fullScreenShow ? null : (
...@@ -318,7 +342,7 @@ const ProjectSubmitWork = observer(() => { ...@@ -318,7 +342,7 @@ const ProjectSubmitWork = observer(() => {
</div> </div>
{returnPermission && ( {returnPermission && (
<div className={styles.swHeaderRight}> <div className={styles.swHeaderRight}>
<MyPopconfirm {/* <MyPopconfirm
title={ title={
state === "RUNNING" state === "RUNNING"
? "正在运行的任务终止后将无法重新运行,确认继续吗?" ? "正在运行的任务终止后将无法重新运行,确认继续吗?"
...@@ -327,14 +351,22 @@ const ProjectSubmitWork = observer(() => { ...@@ -327,14 +351,22 @@ const ProjectSubmitWork = observer(() => {
onConfirm={() => { onConfirm={() => {
state === "RUNNING" ? onStopJob() : onDeleteJob(); state === "RUNNING" ? onStopJob() : onDeleteJob();
}} }}
> > */}
<ButtonComponent <ButtonComponent
text={state === "RUNNING" ? "终止" : "删除"} text={state === "RUNNING" ? "终止" : "删除"}
variant="outlined" variant="outlined"
color="secondary" color="secondary"
// click={onStopJob} click={(e: any) =>
></ButtonComponent> handleShowPopper(
</MyPopconfirm> e,
state === "RUNNING"
? "正在运行的任务终止后将无法重新运行,确认继续吗?"
: "任务被删除后将无法恢复,确认继续吗?"
)
}
// click={onStopJob}
></ButtonComponent>
{/* </MyPopconfirm> */}
</div> </div>
)} )}
</div> </div>
...@@ -350,23 +382,32 @@ const ProjectSubmitWork = observer(() => { ...@@ -350,23 +382,32 @@ const ProjectSubmitWork = observer(() => {
{randerOutputs1.map((item, index) => { {randerOutputs1.map((item, index) => {
return ( return (
<div key={index} className={styles.outputLi}> <div key={index} className={styles.outputLi}>
<MyPopconfirm {/* <MyPopconfirm
title="即将跳转至项目数据内该任务的结果目录,确认继续吗?" title="即将跳转至项目数据内该任务的结果目录,确认继续吗?"
onConfirm={() => onConfirm={() =>
goToProjectData(getFolderPath(item.path)) goToProjectData(getFolderPath(item.path))
} }
> */}
<div
className={styles.outputLiLeft}
onClick={(e: any) => {
handleShowPopper(
e,
"即将跳转至项目数据内该任务的结果目录,确认继续吗?"
);
setGoToProjectDataPath(getFolderPath(item.path));
}}
> >
<div className={styles.outputLiLeft}> <img
<img className={styles.outputLiLeftImg}
className={styles.outputLiLeftImg} src={
src={ item.type === "file" ? fileIcon : dataSetIcon
item.type === "file" ? fileIcon : dataSetIcon }
} alt=""
alt="" />
/> {item.name}
{item.name} </div>
</div> {/* </MyPopconfirm> */}
</MyPopconfirm>
<span className={styles.outputLiRight}> <span className={styles.outputLiRight}>
{item.size} {item.size}
</span> </span>
...@@ -622,6 +663,12 @@ const ProjectSubmitWork = observer(() => { ...@@ -622,6 +663,12 @@ const ProjectSubmitWork = observer(() => {
onClick={() => setFullScreenShow(!fullScreenShow)} onClick={() => setFullScreenShow(!fullScreenShow)}
alt="全屏" alt="全屏"
/> />
<MyPopconfirm
title={popperTitle}
anchorEl={anchorEl}
onCancel={handleCancel}
onConfirm={handleConfirm}
/>
</div> </div>
); );
}); });
......
...@@ -202,31 +202,57 @@ const ProjectSubmitWork = observer(() => { ...@@ -202,31 +202,57 @@ const ProjectSubmitWork = observer(() => {
} }
}; };
const [popperTitle, setPopperTitle] = useState(
"提交前请先确认参数填写无误,确认提交吗?"
);
const [anchorEl, setAnchorEl] = useState<any>(null);
const handleCancel = () => {
setAnchorEl(null);
};
const handleShowPopper = (e: any, title: string) => {
setPopperTitle(title);
setAnchorEl(anchorEl ? null : e.currentTarget);
};
const handleConfirm = () => {
if (popperTitle === "提交前请先确认参数填写无误,确认提交吗?") {
handleSubmitForm();
} else {
handleGoBack();
}
};
return ( return (
<div className={styles.swBox}> <div className={styles.swBox}>
{fullScreenShow ? null : ( {fullScreenShow ? null : (
<div className={styles.swHeader}> <div className={styles.swHeader}>
<div className={styles.swHeaderLeft}> <div className={styles.swHeaderLeft}>
<MyPopconfirm {/* <MyPopconfirm
title="返回后,当前页面已填写内容将不保存,确认返回吗?" title="返回后,当前页面已填写内容将不保存,确认返回吗?"
onConfirm={handleGoBack} onConfirm={handleGoBack}
> */}
<IconButton
color="primary"
onClick={(e: any) =>
handleShowPopper(
e,
"返回后,当前页面已填写内容将不保存,确认返回吗?"
)
}
aria-label="upload picture"
component="span"
size="small"
> >
<IconButton <ArrowBackIosNewIcon
color="primary" sx={{
// onClick={() => handleGoBack()} color: "rgba(194, 198, 204, 1)",
aria-label="upload picture" width: "12px",
component="span" height: "12px",
size="small" }}
> />
<ArrowBackIosNewIcon </IconButton>
sx={{ {/* </MyPopconfirm> */}
color: "rgba(194, 198, 204, 1)",
width: "12px",
height: "12px",
}}
/>
</IconButton>
</MyPopconfirm>
<div className={styles.swTemplateTitle}> <div className={styles.swTemplateTitle}>
{templateConfigInfo?.title} {templateConfigInfo?.title}
...@@ -250,15 +276,18 @@ const ProjectSubmitWork = observer(() => { ...@@ -250,15 +276,18 @@ const ProjectSubmitWork = observer(() => {
<div className={styles.swHeaderGoback}></div> <div className={styles.swHeaderGoback}></div>
</div> </div>
<div className={styles.swHeaderRight}> <div className={styles.swHeaderRight}>
<MyPopconfirm {/* <MyPopconfirm
title="提交前请先确认参数填写无误,确认提交吗?" title="提交前请先确认参数填写无误,确认提交吗?"
onConfirm={handleSubmitForm} onConfirm={handleSubmitForm}
> > */}
<ButtonComponent <ButtonComponent
text="提交任务" text="提交任务"
// click={handleSubmitForm} // click={handleSubmitForm}
></ButtonComponent> click={(e: any) =>
</MyPopconfirm> handleShowPopper(e, "提交前请先确认参数填写无误,确认提交吗?")
}
></ButtonComponent>
{/* </MyPopconfirm> */}
</div> </div>
</div> </div>
)} )}
...@@ -290,6 +319,12 @@ const ProjectSubmitWork = observer(() => { ...@@ -290,6 +319,12 @@ const ProjectSubmitWork = observer(() => {
onClick={() => setFullScreenShow(!fullScreenShow)} onClick={() => setFullScreenShow(!fullScreenShow)}
alt="全屏" alt="全屏"
/> />
<MyPopconfirm
title={popperTitle}
anchorEl={anchorEl}
onCancel={handleCancel}
onConfirm={handleConfirm}
/>
</div> </div>
); );
}); });
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com * @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-21 20:03:56 * @Date: 2022-06-21 20:03:56
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com * @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-07 17:39:49 * @LastEditTime: 2022-07-09 15:57:24
* @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/interface.ts * @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/interface.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
...@@ -38,6 +38,7 @@ export interface ITask { ...@@ -38,6 +38,7 @@ export interface ITask {
title: string; title: string;
description: string; description: string;
version?: string; version?: string;
allVersions?: string[]
position: { position: {
x: number; x: number;
y: number; y: number;
......
...@@ -34,9 +34,14 @@ interface IProps extends ReactFlowProps { ...@@ -34,9 +34,14 @@ interface IProps extends ReactFlowProps {
tasks?: ITask[]; tasks?: ITask[];
/** 点击batch事件 */ /** 点击batch事件 */
onBatchClick?: (val: string) => void; onBatchClick?: (val: string) => void;
/** 设置选中节点id */
setSelectedNodeId?: (val: string) => void; setSelectedNodeId?: (val: string) => void;
/** 选中的节点id */
selectedNodeId?: string; selectedNodeId?: string;
/** 类型, edit为编辑类型 */
type?: "edit" | "default"; type?: "edit" | "default";
/** 设置组件数据 组件为编辑状态使用 */
setTasks?: (val: ITask[]) => void;
} }
/** 获取imgUrl */ /** 获取imgUrl */
...@@ -140,6 +145,7 @@ const Flow = (props: IProps) => { ...@@ -140,6 +145,7 @@ const Flow = (props: IProps) => {
setSelectedNodeId, setSelectedNodeId,
selectedNodeId, selectedNodeId,
type: flowType = "default", type: flowType = "default",
setTasks,
} = props; } = props;
/** 自定义的节点类型 */ /** 自定义的节点类型 */
const nodeTypes = useMemo(() => { const nodeTypes = useMemo(() => {
...@@ -148,6 +154,27 @@ const Flow = (props: IProps) => { ...@@ -148,6 +154,27 @@ const Flow = (props: IProps) => {
/** 内部维护的选择的节点Id */ /** 内部维护的选择的节点Id */
const [inSideNodeId, setInSideNodeId] = useState<string>(""); const [inSideNodeId, setInSideNodeId] = useState<string>("");
const deleteSelectBatchNode = useCallback(
(e: any) => {
if (e.keyCode === 8) {
const val =
tasks?.length &&
tasks.filter((item) => {
return item.id !== inSideNodeId && item.parentNode !== inSideNodeId;
});
setTasks && setTasks(val || []);
}
},
[inSideNodeId, setTasks, tasks]
);
useEffect(() => {
window.addEventListener("keyup", deleteSelectBatchNode);
return () => {
window.removeEventListener("keyup", deleteSelectBatchNode);
};
}, [deleteSelectBatchNode]);
/** 获取是否有输入节点或者是否有输出节点 */ /** 获取是否有输入节点或者是否有输出节点 */
const nodesInputAndOutputStatus = useCallback( const nodesInputAndOutputStatus = useCallback(
(id: string) => { (id: string) => {
...@@ -223,10 +250,10 @@ const Flow = (props: IProps) => { ...@@ -223,10 +250,10 @@ const Flow = (props: IProps) => {
const val: any = []; const val: any = [];
tasks?.length && tasks?.length &&
tasks.forEach((item) => { tasks.forEach((item) => {
console.log(item, "item");
val.push({ val.push({
id: item.id, id: item.id,
type: item.type === "BATCH" ? "batchNode" : "flowNode", type: item.type === "BATCH" ? "batchNode" : "flowNode",
/** 每一项的数据 */
data: { data: {
label: item.title || "", label: item.title || "",
...@@ -240,7 +267,9 @@ const Flow = (props: IProps) => { ...@@ -240,7 +267,9 @@ const Flow = (props: IProps) => {
: inSideNodeId === item.id, : inSideNodeId === item.id,
} }
: {}), : {}),
/** 是否选中 */
isCheck: item.isCheck, isCheck: item.isCheck,
/** 运行状态 */
executionStatus: item.executionStatus, executionStatus: item.executionStatus,
/** 输入输出圆点状态 */ /** 输入输出圆点状态 */
dotStatus: nodesInputAndOutputStatus(item.id), dotStatus: nodesInputAndOutputStatus(item.id),
...@@ -250,13 +279,20 @@ const Flow = (props: IProps) => { ...@@ -250,13 +279,20 @@ const Flow = (props: IProps) => {
padding: isFlowNode(item.id) ? "20px" : "12px 20px", padding: isFlowNode(item.id) ? "20px" : "12px 20px",
}, },
}, },
/** 坐标 */
position: { position: {
x: Number(item.position?.x) || 0, x: Number(item.position?.x) || 0,
y: Number(item.position?.y) || 0, y: Number(item.position?.y) || 0,
}, },
...(item.type === "BATCH" ? { style: { zIndex: -1 } } : {}), /**
* extent: "parent" 跟随父节点移动
* draggable: false 节点不可移动
*/
...(item.type === "BATCH"
? { style: { zIndex: -1 }, extent: "parent" }
: { draggable: false }),
/** parentNode 父节点ID */
...(item.parentNode ? { parentNode: item.parentNode } : {}), ...(item.parentNode ? { parentNode: item.parentNode } : {}),
...(item.type === "BATCH" ? { extent: "parent" } : {}),
}); });
}); });
return val; return val;
...@@ -329,9 +365,9 @@ const Flow = (props: IProps) => { ...@@ -329,9 +365,9 @@ const Flow = (props: IProps) => {
}; };
/** node节点 */ /** node节点 */
const [nodes, setNodes] = useNodesState(initialNodes); const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
/** 连线数组 */ /** 连线数组 */
const [edges, setEdges] = useEdgesState(initialEdges); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
useEffect(() => { useEffect(() => {
setEdges(initialEdges); setEdges(initialEdges);
...@@ -346,7 +382,11 @@ const Flow = (props: IProps) => { ...@@ -346,7 +382,11 @@ const Flow = (props: IProps) => {
nodes={nodes} nodes={nodes}
edges={edges} edges={edges}
fitView={flowType === "default" ? true : false} fitView={flowType === "default" ? true : false}
proOptions={{ hideAttribution: true, account: "" }} onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
deleteKeyCode={["13"]}
// onConnect={onConnect}
// proOptions={{ hideAttribution: true, account: "" }}
nodeTypes={nodeTypes} nodeTypes={nodeTypes}
onPaneClick={handlePaneClick} onPaneClick={handlePaneClick}
onNodeClick={onNodeClick} onNodeClick={onNodeClick}
......
...@@ -51,3 +51,11 @@ ...@@ -51,3 +51,11 @@
overflow-y: scroll; overflow-y: scroll;
height: calc(100% - 48px); height: calc(100% - 48px);
} }
.versionBox {
background: #e6e8eb;
color: #1e2633;
cursor: pointer;
padding: 0 8px;
border-radius: 2px;
}
import { OutlinedInput } from "@mui/material"; import { OutlinedInput } from "@mui/material";
import SearchIcon from "@mui/icons-material/Search"; import SearchIcon from "@mui/icons-material/Search";
import classNames from "classnames"; import classNames from "classnames";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { toJS } from "mobx"; import { toJS } from "mobx";
import cloneDeep from "lodash/cloneDeep"; import cloneDeep from "lodash/cloneDeep";
...@@ -10,7 +10,7 @@ import { IOperatorItemProps, IOperatorListProps } from "./interface"; ...@@ -10,7 +10,7 @@ import { IOperatorItemProps, IOperatorListProps } from "./interface";
import { ITask } from "@/views/Project/ProjectSubmitWork/interface"; import { ITask } from "@/views/Project/ProjectSubmitWork/interface";
import useMyRequest from "@/hooks/useMyRequest"; import useMyRequest from "@/hooks/useMyRequest";
import { IResponse } from "@/api/http"; import { IResponse } from "@/api/http";
import { fetchOperatorList } from "@/api/workbench_api"; import { fetchOperatorList, fetchVersionOperator } from "@/api/workbench_api";
import { useStores } from "@/store"; import { useStores } from "@/store";
import styles from "./index.module.css"; import styles from "./index.module.css";
...@@ -29,7 +29,7 @@ let count = 1; ...@@ -29,7 +29,7 @@ let count = 1;
const OperatorItem = (props: IOperatorItemProps) => { const OperatorItem = (props: IOperatorItemProps) => {
const { const {
info: { title, description, tags }, info: { title, description, tags, allVersions, version },
setTemplateConfigInfo, setTemplateConfigInfo,
templateConfigInfo, templateConfigInfo,
setOperatorListData, setOperatorListData,
...@@ -37,6 +37,7 @@ const OperatorItem = (props: IOperatorItemProps) => { ...@@ -37,6 +37,7 @@ const OperatorItem = (props: IOperatorItemProps) => {
info, info,
} = props; } = props;
const [isDragStyle, setIsDragStyle] = useState<boolean>(false); const [isDragStyle, setIsDragStyle] = useState<boolean>(false);
const [versionValue, setVersionValue] = useState<string>("");
/** 拖拽开始 */ /** 拖拽开始 */
const onDragStart = useCallback(() => { const onDragStart = useCallback(() => {
...@@ -44,6 +45,26 @@ const OperatorItem = (props: IOperatorItemProps) => { ...@@ -44,6 +45,26 @@ const OperatorItem = (props: IOperatorItemProps) => {
count++; count++;
}, []); }, []);
// 获取指定版本的算子
const { run: getVersionOperator } = useMyRequest(fetchVersionOperator, {
onSuccess: (res: IResponse<any>) => {
if (res.data) {
let index: number | undefined = undefined;
const newVal = operatorListData.filter((item, i) => {
const bol = item.id === info.id || item.parentNode === info.id;
if (bol && index === undefined) {
index = i;
}
return !bol;
});
if (index !== undefined) {
newVal.splice(index, 0, ...res.data);
}
setOperatorListData(newVal);
}
},
});
/** 通过id查找相对的批流数组 */ /** 通过id查找相对的批流数组 */
const getBatchFlowArr = useCallback( const getBatchFlowArr = useCallback(
(id: string) => { (id: string) => {
...@@ -121,6 +142,27 @@ const OperatorItem = (props: IOperatorItemProps) => { ...@@ -121,6 +142,27 @@ const OperatorItem = (props: IOperatorItemProps) => {
] ]
); );
/** 所有版本信息格式化 */
const getAllVersion = useMemo(() => {
return (
allVersions?.length &&
allVersions?.map((item) => {
return { label: item, value: item };
})
);
}, [allVersions]);
/** 切换版本 */
const changeVersion = useCallback(
(val: string) => {
if (val !== versionValue) {
setVersionValue(val);
getVersionOperator({ title: info.title, version: val });
}
},
[getVersionOperator, info.title, versionValue]
);
return ( return (
<div <div
className={classNames({ className={classNames({
...@@ -149,14 +191,15 @@ const OperatorItem = (props: IOperatorItemProps) => { ...@@ -149,14 +191,15 @@ const OperatorItem = (props: IOperatorItemProps) => {
); );
})} })}
<MyMenu <MyMenu
options={[ options={getAllVersion || []}
{ label: "1.1.0", value: "1.1.0" }, value={versionValue || version || ""}
{ label: "1.2.0", value: "1.2.0" }, setValue={(val: string) => {
{ label: "1.3.0", value: "1.3.0" }, changeVersion(val);
]} }}
value="1.1.0"
> >
<div>ddd</div> <div className={styles.versionBox}>{`版本:${
versionValue || version
}`}</div>
</MyMenu> </MyMenu>
</div> </div>
</div> </div>
......
...@@ -93,15 +93,15 @@ ...@@ -93,15 +93,15 @@
.parameterBox:last-child { .parameterBox:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
.parameterTop { .inOutParameterTop {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 8px; margin-bottom: 8px;
} }
.parameterleft { .inOutParameterleft {
} }
.parameterName { .inOutParameterName {
color: rgba(30, 38, 51, 1); color: rgba(30, 38, 51, 1);
font-size: 14px; font-size: 14px;
line-height: 22px; line-height: 22px;
...@@ -112,7 +112,7 @@ ...@@ -112,7 +112,7 @@
color: rgba(255, 78, 78, 1); color: rgba(255, 78, 78, 1);
margin-left: 4px; margin-left: 4px;
} }
.parameterdataType { .inOutParameterdataType {
color: rgba(138, 144, 153, 1); color: rgba(138, 144, 153, 1);
font-size: 12px; font-size: 12px;
line-height: 20px; line-height: 20px;
...@@ -133,3 +133,34 @@ ...@@ -133,3 +133,34 @@
line-height: 22px; line-height: 22px;
color: rgba(138, 144, 153, 1); color: rgba(138, 144, 153, 1);
} }
.paramsGroup{
padding-bottom: 24px;
}
.parameter{
padding: 16px 0 24px;
border-bottom: 1px solid #F0F2F5;
}
.parameter:last-child{
border-bottom: none;
}
.parameterTop{
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.parameterLeft{
}
.parameterName{
font-size: 14px;
color: #1E2633;
line-height: 22px;
font-weight: 600;
}
.parameterClassTypeName{
font-size: 14px;
color: #8A9099;
line-height: 22px;
}
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com * @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-21 20:03:56 * @Date: 2022-06-21 20:03:56
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com * @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-08 11:51:07 * @LastEditTime: 2022-07-09 15:11:17
* @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/index.tsx * @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
...@@ -41,40 +41,70 @@ const WorkFlowEdit = (props: IProps) => { ...@@ -41,40 +41,70 @@ const WorkFlowEdit = (props: IProps) => {
const [leftContentType, setLeftContentType] = useState("list"); const [leftContentType, setLeftContentType] = useState("list");
const [popperTitle, setPopperTitle] = useState(
"返回后,当前页面已填写内容将不保存,确认返回吗?"
);
// 返回后,当前页面已填写内容将不保存,确认返回吗?
const [anchorEl, setAnchorEl] = useState<any>(null);
const handleCancel = () => {
setAnchorEl(null);
};
const handleShowPopper = (e: any, title: string) => {
setPopperTitle(title);
setAnchorEl(anchorEl ? null : e.currentTarget);
};
const handleConfirm = () => {
if (popperTitle === "返回后,当前页面已填写内容将不保存,确认返回吗?") {
onBack && onBack();
} else {
console.log("提交");
}
};
return ( return (
<div className={styles.swBox}> <div className={styles.swBox}>
<div className={styles.swHeader}> <div className={styles.swHeader}>
<div className={styles.swHeaderLeft}> <div className={styles.swHeaderLeft}>
<MyPopconfirm {/* <MyPopconfirm
title="返回后,当前页面已填写内容将不保存,确认返回吗?" title="返回后,当前页面已填写内容将不保存,确认返回吗?"
onConfirm={onBack} onConfirm={onBack}
> */}
<IconButton
color="primary"
aria-label="upload picture"
component="span"
size="small"
onClick={(e: any) =>
handleShowPopper(
e,
"返回后,当前页面已填写内容将不保存,确认返回吗?"
)
}
> >
<IconButton <ArrowBackIosNewIcon
color="primary" sx={{
aria-label="upload picture" color: "rgba(194, 198, 204, 1)",
component="span" width: "12px",
size="small" height: "12px",
> }}
<ArrowBackIosNewIcon />
sx={{ </IconButton>
color: "rgba(194, 198, 204, 1)", {/* </MyPopconfirm> */}
width: "12px",
height: "12px",
}}
/>
</IconButton>
</MyPopconfirm>
</div> </div>
<div className={styles.swHeaderRight}> <div className={styles.swHeaderRight}>
<MyPopconfirm {/* <MyPopconfirm
title="提交前请先确认参数填写无误,确认提交吗?" title="提交前请先确认参数填写无误,确认提交吗?"
onConfirm={() => console.log(2)} onConfirm={() => console.log(2)}
> > */}
<ButtonComponent <ButtonComponent
text="保存" text="保存"
// click={handleSubmitForm} click={(e: any) =>
></ButtonComponent> handleShowPopper(e, "提交前请先确认参数填写无误,确认提交吗?")
</MyPopconfirm> }
></ButtonComponent>
{/* </MyPopconfirm> */}
</div> </div>
</div> </div>
<div className={styles.swContent}> <div className={styles.swContent}>
...@@ -108,9 +138,19 @@ const WorkFlowEdit = (props: IProps) => { ...@@ -108,9 +138,19 @@ const WorkFlowEdit = (props: IProps) => {
)} )}
</div> </div>
<div className={styles.swFlowBox} id="workFlowEditRight"> <div className={styles.swFlowBox} id="workFlowEditRight">
<Flow tasks={templateConfigInfo} type="edit" /> <Flow
tasks={templateConfigInfo}
setTasks={setTemplateConfigInfo}
type="edit"
/>
</div> </div>
</div> </div>
<MyPopconfirm
title={popperTitle}
anchorEl={anchorEl}
onCancel={handleCancel}
onConfirm={handleConfirm}
/>
</div> </div>
); );
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment