Commit fcf4968a authored by chenshouchao's avatar chenshouchao

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

cn-Feat 20220705 custom template

See merge request !85
parents f1d577f4 b9a6c048
.RadiosBox {
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid #e6e8eb;
border-radius: 4px;
background-color: #e6e8eb;
cursor: pointer;
height: 32px;
box-sizing: border-box;
padding: 2px;
}
.radio {
height: 28px;
box-sizing: border-box;
font-size: 14px;
color: #565c66;
border-radius: 4px;
line-height: 20px;
padding: 3px 18px;
background-color: #e6e8eb;
display: flex;
align-items: center;
}
.radioActive {
color: #1370ff;
background-color: #fff;
border: 1px solid #e6e8eb;
}
// 按钮样式的单选组
import classnames from "classnames";
import style from "./index.module.css";
type radioOption = {
value: string;
label: string;
};
type IRadioGroupOfButtonStyleProps = {
radioOptions: Array<radioOption>;
value: string;
handleRadio: any;
};
const RadioGroupOfButtonStyle = (props: IRadioGroupOfButtonStyleProps) => {
const { radioOptions, value, handleRadio } = props;
return (
<div className={style.RadiosBox}>
{radioOptions.map((options) => {
return (
<div
key={options.value}
className={classnames({
[style.radio]: true,
[style.radioActive]: value === options.value,
})}
onClick={() => handleRadio(options.value)}
>
{options.label}
</div>
);
})}
</div>
);
};
export default RadioGroupOfButtonStyle;
...@@ -34,7 +34,9 @@ const MoveFile = (props: any) => { ...@@ -34,7 +34,9 @@ const MoveFile = (props: any) => {
const [moveFileSubmitloading, setMoveFileSubmitloading] = useState(false); const [moveFileSubmitloading, setMoveFileSubmitloading] = useState(false);
const [treeData, setTreeData] = useState<any>([]); const [treeData, setTreeData] = useState<any>([]);
const [renderTreeData, setRenderTreeData] = useState<any>([]); const [renderTreeData, setRenderTreeData] = useState<any>([]);
let moveFileDialogRef: any = React.createRef(); const [moveFileDialogRef, setMoveFileDialogRef] = useState<any>(
React.createRef()
);
// 要移动的文件夹 之后用来隐藏文件夹树中同路径的文件夹 // 要移动的文件夹 之后用来隐藏文件夹树中同路径的文件夹
const [moveFolderPathArr, setMoveFolderPathArr] = useState<Array<string>>([]); const [moveFolderPathArr, setMoveFolderPathArr] = useState<Array<string>>([]);
......
...@@ -99,18 +99,20 @@ ...@@ -99,18 +99,20 @@
color: rgba(138, 144, 153, 1); color: rgba(138, 144, 153, 1);
font-size: 14px; font-size: 14px;
line-height: 22px; line-height: 22px;
width: 72px;
margin-right: 44px;
} }
.taskInfoValue { .taskInfoValue {
color: rgba(30, 38, 51, 1); color: rgba(30, 38, 51, 1);
font-size: 14px; font-size: 14px;
line-height: 22px; line-height: 22px;
max-width: 210px;
text-overflow: ellipsis;
white-space: nowrap;
display: flex; display: flex;
overflow: hidden;
position: relative; position: relative;
align-items: center; align-items: center;
text-align: left;
word-break: break-all;
flex: 1;
justify-content: flex-end;
} }
.taskInfoValueClick { .taskInfoValueClick {
cursor: pointer; cursor: pointer;
...@@ -159,6 +161,7 @@ ...@@ -159,6 +161,7 @@
background: #ffffff; background: #ffffff;
box-shadow: 0px 3px 10px 0px rgba(0, 24, 57, 0.14); box-shadow: 0px 3px 10px 0px rgba(0, 24, 57, 0.14);
border-radius: 4px; border-radius: 4px;
z-index: 1002;
} }
.option { .option {
padding: 7px 16px; padding: 7px 16px;
......
...@@ -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-06 11:01:44 * @LastEditTime: 2022-07-06 17:05:13
* @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
*/ */
...@@ -75,8 +75,8 @@ const ProjectSubmitWork = observer(() => { ...@@ -75,8 +75,8 @@ const ProjectSubmitWork = observer(() => {
/** 获取模版数据 */ /** 获取模版数据 */
const { run } = useMyRequest(fetchWorkFlowJob, { const { run } = useMyRequest(fetchWorkFlowJob, {
pollingInterval:1000 * 60, pollingInterval: 1000 * 60,
pollingWhenHidden:false, pollingWhenHidden: false,
onSuccess: (res: IResponse<ITaskInfo>) => { onSuccess: (res: IResponse<ITaskInfo>) => {
getOutouts(res.data.outputs); getOutouts(res.data.outputs);
setWorkFlowJobInfo(res.data); setWorkFlowJobInfo(res.data);
...@@ -85,7 +85,6 @@ const ProjectSubmitWork = observer(() => { ...@@ -85,7 +85,6 @@ const ProjectSubmitWork = observer(() => {
useEffect(() => { useEffect(() => {
const locationInfo: any = location?.state; const locationInfo: any = location?.state;
console.log(333)
run({ run({
id: locationInfo.taskId, id: locationInfo.taskId,
}); });
...@@ -103,15 +102,28 @@ const ProjectSubmitWork = observer(() => { ...@@ -103,15 +102,28 @@ const ProjectSubmitWork = observer(() => {
navigate(`/product/cadd/projectData`, { navigate(`/product/cadd/projectData`, {
state: { pathName: path }, state: { pathName: path },
}); });
} else {
navigate(`/product/cadd/projectData`, {
state: { pathName: "/" },
});
} }
}; };
/** 返回事件 */ // 通过文件路径获取文件所在文件夹路径 如 输入 /home/cloudam/task_a.out 输出/home/cloudam/
const getFolderPath = (path: string) => {
const lastIndex = path.lastIndexOf("/");
if (lastIndex !== -1) {
path = path.slice(0, lastIndex + 1);
}
return path;
};
/** 返回事件 */
const onBack = useCallback(() => { const onBack = useCallback(() => {
navigate('/product/cadd/projectWorkbench', { navigate("/product/cadd/projectWorkbench", {
state: {type: 'workbenchList'} state: { type: "workbenchList" },
}) });
},[navigate]) }, [navigate]);
const outputPathTransform = (path: string) => { const outputPathTransform = (path: string) => {
path = path.slice(13); path = path.slice(13);
...@@ -202,7 +214,7 @@ const ProjectSubmitWork = observer(() => { ...@@ -202,7 +214,7 @@ const ProjectSubmitWork = observer(() => {
if (errorCode === 0) { if (errorCode === 0) {
message.success("操作成功!"); message.success("操作成功!");
} }
onBack() onBack();
}, },
}); });
...@@ -213,7 +225,7 @@ const ProjectSubmitWork = observer(() => { ...@@ -213,7 +225,7 @@ const ProjectSubmitWork = observer(() => {
if (errorCode === 0) { if (errorCode === 0) {
message.success("操作成功!"); message.success("操作成功!");
} }
onBack() onBack();
}, },
}); });
...@@ -327,7 +339,7 @@ const ProjectSubmitWork = observer(() => { ...@@ -327,7 +339,7 @@ const ProjectSubmitWork = observer(() => {
<div key={index} className={styles.outputLi}> <div key={index} className={styles.outputLi}>
<MyPopconfirm <MyPopconfirm
title="即将跳转至项目数据内该任务的结果目录,确认继续吗?" title="即将跳转至项目数据内该任务的结果目录,确认继续吗?"
onConfirm={() => goToProjectData(item.path)} onConfirm={() => goToProjectData(getFolderPath(item.path))}
> >
<div className={styles.outputLiLeft}> <div className={styles.outputLiLeft}>
<img <img
...@@ -499,7 +511,11 @@ const ProjectSubmitWork = observer(() => { ...@@ -499,7 +511,11 @@ const ProjectSubmitWork = observer(() => {
return ( return (
<div <div
key={index} key={index}
className={styles.option} className={classNames({
[styles.option]: true,
[styles.optionActive]:
activeFlowIndex === index,
})}
onClick={() => setActiveFlowIndex(index)} onClick={() => setActiveFlowIndex(index)}
> >
{item.title} {item.title}
......
...@@ -30,7 +30,6 @@ import MyPopconfirm from "@/components/mui/MyPopconfirm"; ...@@ -30,7 +30,6 @@ import MyPopconfirm from "@/components/mui/MyPopconfirm";
import styles from "./index.module.css"; import styles from "./index.module.css";
const ProjectSubmitWork = () => { const ProjectSubmitWork = () => {
const Message = useMessage(); const Message = useMessage();
const { currentProjectStore } = useStores(); const { currentProjectStore } = useStores();
...@@ -68,7 +67,14 @@ const ProjectSubmitWork = () => { ...@@ -68,7 +67,14 @@ const ProjectSubmitWork = () => {
task.parameters.forEach((parameter) => { task.parameters.forEach((parameter) => {
let value: any = undefined; let value: any = undefined;
if (parameter.defaultValue) { if (parameter.defaultValue) {
if (
parameter.domType.toLowerCase() === "multipleselect" ||
parameter.domType.toLowerCase() === "checkbox"
) {
value = parameter.defaultValue.split(",");
} else {
value = parameter.defaultValue; value = parameter.defaultValue;
}
} else if ( } else if (
parameter.domType.toLowerCase() === "multipleselect" || parameter.domType.toLowerCase() === "multipleselect" ||
parameter.domType.toLowerCase() === "checkbox" parameter.domType.toLowerCase() === "checkbox"
...@@ -193,7 +199,8 @@ const ProjectSubmitWork = () => { ...@@ -193,7 +199,8 @@ const ProjectSubmitWork = () => {
return ( return (
<div className={styles.swBox}> <div className={styles.swBox}>
{ fullScreenShow ? null : <div className={styles.swHeader}> {fullScreenShow ? null : (
<div className={styles.swHeader}>
<div className={styles.swHeaderLeft}> <div className={styles.swHeaderLeft}>
<MyPopconfirm <MyPopconfirm
title="返回后,当前页面已填写内容将不保存,确认返回吗?" title="返回后,当前页面已填写内容将不保存,确认返回吗?"
...@@ -248,18 +255,28 @@ const ProjectSubmitWork = () => { ...@@ -248,18 +255,28 @@ const ProjectSubmitWork = () => {
></ButtonComponent> ></ButtonComponent>
</MyPopconfirm> </MyPopconfirm>
</div> </div>
</div>} </div>
)}
<div className={styles.swContent}> <div className={styles.swContent}>
{fullScreenShow ? null : <div className={styles.swFormBox}> {fullScreenShow ? null : (
<div className={styles.swFormBox}>
<ConfigForm <ConfigForm
onRef={configFormRef} onRef={configFormRef}
templateConfigInfo={templateConfigInfo} templateConfigInfo={templateConfigInfo}
setParameter={setParameter} setParameter={setParameter}
setSelectedNodeId={setSelectedNodeId} setSelectedNodeId={setSelectedNodeId}
/> />
</div>} </div>
<div className={styles.swFlowBox} style={fullScreenShow ? { height: "100vh" } : undefined}> )}
<WorkFlow templateConfigInfo={templateConfigInfo} setSelectedNodeId={setSelectedNodeId} selectedNodeId={selectedNodeId}/> <div
className={styles.swFlowBox}
style={fullScreenShow ? { height: "100vh" } : undefined}
>
<WorkFlow
templateConfigInfo={templateConfigInfo}
setSelectedNodeId={setSelectedNodeId}
selectedNodeId={selectedNodeId}
/>
</div> </div>
</div> </div>
<img <img
......
import { memo, useCallback, useEffect, useMemo, useState } from "react"; import { memo, useCallback, useEffect, useMemo, useState } from "react";
import styles from "../index.module.css"; import styles from "../index.module.css";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import Button from "@/components/mui/Button"; import Button from "@/components/mui/Button";
import Dialog from "@/components/mui/Dialog"; import Dialog from "@/components/mui/Dialog";
import OutlinedInput from "@mui/material/OutlinedInput"; import OutlinedInput from "@mui/material/OutlinedInput";
import RadioGroupOfButtonStyle from "@/components/CommonComponents/RadioGroupOfButtonStyle";
import SearchIcon from "@mui/icons-material/Search"; import SearchIcon from "@mui/icons-material/Search";
import Checkbox from '@mui/material/Checkbox'; import Checkbox from "@mui/material/Checkbox";
import CloseOutlinedIcon from '@mui/icons-material/CloseOutlined'; import CloseOutlinedIcon from "@mui/icons-material/CloseOutlined";
import noData from '../../../../../assets/project/noTemplate.svg' import noData from "../../../../../assets/project/noTemplate.svg";
import _ from "lodash"; import _ from "lodash";
const AddTemplate = (props: any) => { const AddTemplate = (props: any) => {
const { openAddTemplate, closeAddTemplateBlock, addTemplateList, templateSelectCallback, selectTemplateData, addTemplateCallback, searchTemplateNameCallback } = props; const {
openAddTemplate,
closeAddTemplateBlock,
addTemplateList,
templateSelectCallback,
selectTemplateData,
addTemplateCallback,
searchTemplateNameCallback,
} = props;
const [templateType, setTemplateType] = useState("public");
const radioOptions = [
{
value: "public",
label: "公共",
},
{
value: "custom",
label: "自定义",
},
];
const handleRadio = (value: string) => {
setTemplateType(value);
};
return ( return (
<Box className={styles.addTemplateMask} sx={{ display: openAddTemplate ? 'flex' : 'none' }} > <Box
<Box sx={{ height: '50px', display: 'flex', alignItems: 'center' }} > className={styles.addTemplateMask}
<CloseOutlinedIcon sx={{ color: "#ffffff", marginRight: "10px", cursor: "pointer" }} onClick={() => { sx={{ display: openAddTemplate ? "flex" : "none" }}
closeAddTemplateBlock() >
}} /> <Box sx={{ height: "50px", display: "flex", alignItems: "center" }}>
<CloseOutlinedIcon
sx={{ color: "#ffffff", marginRight: "10px", cursor: "pointer" }}
onClick={() => {
closeAddTemplateBlock();
}}
/>
</Box> </Box>
<Box className={styles.addTemplateBlock}> <Box className={styles.addTemplateBlock}>
<Box sx={{ padding: "24px 32px" }}> <Box sx={{ padding: "24px 32px" }}>
<Typography sx={{ fontSize: '18px', fontWeight: '600', color: "#1E2633" }}>添加工作流模版</Typography> <Typography
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: "20px" }}> sx={{ fontSize: "18px", fontWeight: "600", color: "#1E2633" }}
>
添加工作流模版
</Typography>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: "20px",
}}
>
<OutlinedInput <OutlinedInput
onChange={(e: any) => { onChange={(e: any) => {
_.debounce(() => { _.debounce(() => {
searchTemplateNameCallback(e.target.value) searchTemplateNameCallback(e.target.value);
}, 200)(); }, 200)();
}} }}
placeholder="输入关键词搜索" placeholder="输入关键词搜索"
...@@ -36,45 +77,128 @@ const AddTemplate = (props: any) => { ...@@ -36,45 +77,128 @@ const AddTemplate = (props: any) => {
sx={{ width: 340, height: 32, marginTop: "20px" }} sx={{ width: 340, height: 32, marginTop: "20px" }}
endAdornment={<SearchIcon style={{ color: "#8A9099" }} />} endAdornment={<SearchIcon style={{ color: "#8A9099" }} />}
/> />
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
alignItems: "center",
}}
>
<RadioGroupOfButtonStyle
value={templateType}
radioOptions={radioOptions}
handleRadio={handleRadio}
></RadioGroupOfButtonStyle>
<Button <Button
click={addTemplateCallback} click={addTemplateCallback}
size={"small"} size={"small"}
text={'添加模版' + (selectTemplateData.length === 0 ? "" : `(${selectTemplateData.length})`)} style={{
marginLeft: "12px",
}}
text={
"添加模版" +
(selectTemplateData.length === 0
? ""
: `(${selectTemplateData.length})`)
}
/> />
</Box> </Box>
</Box>
{ {addTemplateList.length === 0 && (
addTemplateList.length === 0 && <Box sx={{ <Box
display: 'flex', alignItems: 'center', flexDirection: 'column', minHeight: 'calc(100vh - 376px)', sx={{
justifyContent: 'center' display: "flex",
}}> alignItems: "center",
flexDirection: "column",
minHeight: "calc(100vh - 376px)",
justifyContent: "center",
}}
>
<img alt="" src={noData} /> <img alt="" src={noData} />
<Typography sx={{ fontSize: '12px', fontWeight: '400', color: '#8A9099' }}>暂未相关模版</Typography> <Typography
sx={{ fontSize: "12px", fontWeight: "400", color: "#8A9099" }}
>
暂未相关模版
</Typography>
</Box> </Box>
} )}
<Box sx={{ display: "flex", flexWrap: 'wrap', overflowX: 'hidden', overflowY: 'overlay', marginLeft: '-8px' }} > <Box
{ sx={{
addTemplateList.map((item: any, key: any) => { display: "flex",
flexWrap: "wrap",
overflowX: "hidden",
overflowY: "overlay",
marginLeft: "-8px",
}}
>
{addTemplateList.map((item: any, key: any) => {
return ( return (
<Box className={styles.addTemplateBox} onClick={() => { <Box
templateSelectCallback(item.id) className={styles.addTemplateBox}
onClick={() => {
templateSelectCallback(item.id);
}}
sx={{
border: selectTemplateData.includes(item.id)
? "1px solid #1370FF"
: "1px solid #EBEDF0;",
}}
key={item.id}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography
sx={{
fontSize: "14px",
fontWeight: "600",
color: "#1E2633",
marginBottom: "4px",
overflow: "hidden",
textOverflow: "ellipsis",
}} }}
sx={{ border: selectTemplateData.includes(item.id) ? '1px solid #1370FF' : "1px solid #EBEDF0;" }}
> >
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', }}> {item.title}
<Typography sx={{ fontSize: '14px', fontWeight: '600', color: '#1E2633', marginBottom: "4px", overflow: 'hidden', textOverflow: 'ellipsis' }}>{item.title}</Typography> </Typography>
<Checkbox size="small" sx={{ padding: "0px" }} checked={selectTemplateData.includes(item.id)} /> <Checkbox
size="small"
sx={{ padding: "0px" }}
checked={selectTemplateData.includes(item.id)}
/>
</Box> </Box>
<Box sx={{ display: 'flex', marginBottom: "8px" }}> <Box sx={{ display: "flex", marginBottom: "8px" }}>
<Typography sx={{ fontSize: '12px', fontWeight: '400', color: '#1370FF', marginRight: "24px" }}>版本:{item.version}</Typography> <Typography
<Typography sx={{ fontSize: '12px', fontWeight: '400', color: '#1370FF' }}>更新时间:{item.updateTime}</Typography> sx={{
fontSize: "12px",
fontWeight: "400",
color: "#1370FF",
marginRight: "24px",
}}
>
版本:{item.version}
</Typography>
<Typography
sx={{
fontSize: "12px",
fontWeight: "400",
color: "#1370FF",
}}
>
更新时间:{item.updateTime}
</Typography>
</Box> </Box>
<Typography className={styles.templateDescText} >{item.description}</Typography> <Typography className={styles.templateDescText}>
{item.description}
</Typography>
</Box> </Box>
) );
}) })}
}
</Box> </Box>
</Box> </Box>
</Box> </Box>
......
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-06 14:44:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-06 14:47:28
* @FilePath: /bkunyun/src/views/Project/ProjectWorkbench/workbenchTemplate/interface.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
export interface ICustomTemplate{
show?: boolean;
id?: string;
}
\ No newline at end of file
...@@ -14,7 +14,11 @@ import classNames from "classnames"; ...@@ -14,7 +14,11 @@ import classNames from "classnames";
import jobFail from "@/assets/project/jobFail.svg"; import jobFail from "@/assets/project/jobFail.svg";
import jobRun from "@/assets/project/jobRun.svg"; import jobRun from "@/assets/project/jobRun.svg";
import jobSue from "@/assets/project/jobSue.svg"; import jobSue from "@/assets/project/jobSue.svg";
import { IEdge, IExecutionStatus, ITask } from "../../ProjectSubmitWork/interface"; import {
IEdge,
IExecutionStatus,
ITask,
} from "../../ProjectSubmitWork/interface";
import { IBatchNode, ILine } from "./interface"; import { IBatchNode, ILine } from "./interface";
import styles from "./index.module.css"; import styles from "./index.module.css";
...@@ -30,23 +34,23 @@ interface IProps extends ReactFlowProps { ...@@ -30,23 +34,23 @@ interface IProps extends ReactFlowProps {
tasks?: ITask[]; tasks?: ITask[];
/** 点击batch事件 */ /** 点击batch事件 */
onBatchClick?: (val: string) => void; onBatchClick?: (val: string) => void;
setSelectedNodeId?: (val:string) => void; setSelectedNodeId?: (val: string) => void;
selectedNodeId?: string; selectedNodeId?: string;
} }
/** 获取imgUrl */ /** 获取imgUrl */
const getImgUrl = (type: IExecutionStatus) => { const getImgUrl = (type: IExecutionStatus) => {
if(type === 'Done'){ if (type === "Done") {
return jobSue return jobSue;
} }
if(type === 'Failed'){ if (type === "Failed") {
return jobFail return jobFail;
} }
if(type === 'Running'){ if (type === "Running") {
return jobRun return jobRun;
}
return undefined
} }
return undefined;
};
/** 自定义batch节点 */ /** 自定义batch节点 */
const BatchNode = (props: IBatchNode) => { const BatchNode = (props: IBatchNode) => {
...@@ -106,7 +110,13 @@ const FlowNode = (props: any) => { ...@@ -106,7 +110,13 @@ const FlowNode = (props: any) => {
<div style={{ display: "flex", alignItems: "center" }}> <div style={{ display: "flex", alignItems: "center" }}>
{data?.label || ""} {data?.label || ""}
{data.isCheck && <span className={styles.successDot}></span>} {data.isCheck && <span className={styles.successDot}></span>}
{getImgUrl(data.executionStatus) && <img style={{ marginLeft: "6px" }} src={getImgUrl(data.executionStatus)} alt="" />} {getImgUrl(data.executionStatus) && (
<img
style={{ marginLeft: "6px" }}
src={getImgUrl(data.executionStatus)}
alt=""
/>
)}
</div> </div>
{data?.dotStatus?.isOutput ? ( {data?.dotStatus?.isOutput ? (
<Handle <Handle
...@@ -126,6 +136,8 @@ const Flow = (props: IProps) => { ...@@ -126,6 +136,8 @@ const Flow = (props: IProps) => {
const nodeTypes = useMemo(() => { const nodeTypes = useMemo(() => {
return { batchNode: BatchNode, flowNode: FlowNode }; return { batchNode: BatchNode, flowNode: FlowNode };
}, []); }, []);
/** 内部维护的选择的节点Id */
const [inSideNodeId, setInSideNodeId] = useState<string>("");
/** 获取是否有输入节点或者是否有输出节点 */ /** 获取是否有输入节点或者是否有输出节点 */
const nodesInputAndOutputStatus = useCallback( const nodesInputAndOutputStatus = useCallback(
...@@ -213,7 +225,9 @@ const Flow = (props: IProps) => { ...@@ -213,7 +225,9 @@ const Flow = (props: IProps) => {
/** 是否有流节点 */ /** 是否有流节点 */
isFlowNode: isFlowNode(item.id), isFlowNode: isFlowNode(item.id),
/** 选中状态 */ /** 选中状态 */
selectedStatus: selectedNodeId === item.id, selectedStatus: selectedNodeId
? selectedNodeId === item.id
: inSideNodeId === item.id,
} }
: {}), : {}),
isCheck: item.isCheck, isCheck: item.isCheck,
...@@ -237,6 +251,7 @@ const Flow = (props: IProps) => { ...@@ -237,6 +251,7 @@ const Flow = (props: IProps) => {
tasks, tasks,
isFlowNode, isFlowNode,
selectedNodeId, selectedNodeId,
inSideNodeId,
nodesInputAndOutputStatus, nodesInputAndOutputStatus,
getBatchStyle, getBatchStyle,
]); ]);
...@@ -255,12 +270,13 @@ const Flow = (props: IProps) => { ...@@ -255,12 +270,13 @@ const Flow = (props: IProps) => {
}, []); }, []);
}); });
return val.map((item: ILine) => { return val.map((item: ILine) => {
const newSelectId = selectedNodeId ? selectedNodeId : inSideNodeId;
return { return {
id: item.id, id: item.id,
source: item.source, source: item.source,
target: item.target, target: item.target,
type: "smoothstep", type: "smoothstep",
...(item?.batchId === selectedNodeId ...(item?.batchId === newSelectId
? { style: { stroke: "#1370FF" }, animated: true } ? { style: { stroke: "#1370FF" }, animated: true }
: {}), : {}),
labelStyle: { fill: "#8A9099" }, labelStyle: { fill: "#8A9099" },
...@@ -268,30 +284,35 @@ const Flow = (props: IProps) => { ...@@ -268,30 +284,35 @@ const Flow = (props: IProps) => {
label: item.label ? `(${item.label})` : "", label: item.label ? `(${item.label})` : "",
}; };
}); });
}, [selectedNodeId, tasks]); }, [inSideNodeId, selectedNodeId, tasks]);
/** flowNode点击事件 */ /** flowNode点击事件 */
const onNodeClick = (e: any, node: Node) => { const onNodeClick = (e: any, node: Node) => {
tasks?.forEach((item) => { tasks?.forEach((item) => {
if (item.id === node.id) { if (item.id === node.id) {
if (item.parentNode) { if (item.parentNode) {
setSelectedNodeId && setSelectedNodeId(item.parentNode); setSelectedNodeId
? setSelectedNodeId(item.parentNode)
: setInSideNodeId(item.parentNode);
onBatchClick && onBatchClick(item.parentNode); onBatchClick && onBatchClick(item.parentNode);
document.getElementById(`point${item.parentNode}`)?.scrollIntoView(true) document
.getElementById(`point${item.parentNode}`)
?.scrollIntoView(true);
} else { } else {
setSelectedNodeId && setSelectedNodeId(node.id); setSelectedNodeId
? setSelectedNodeId(node.id)
: setInSideNodeId(node.id);
onBatchClick && onBatchClick(node.id || ""); onBatchClick && onBatchClick(node.id || "");
document.getElementById(`point${node.id}`)?.scrollIntoView(true) document.getElementById(`point${node.id}`)?.scrollIntoView(true);
} }
} }
}); });
}; };
const handlePaneClick = () => { const handlePaneClick = () => {
setSelectedNodeId && setSelectedNodeId(''); setSelectedNodeId ? setSelectedNodeId("") : setInSideNodeId("");
onBatchClick && onBatchClick(''); onBatchClick && onBatchClick("");
} };
/** node节点 */ /** node节点 */
const [nodes, setNodes] = useNodesState(initialNodes); const [nodes, setNodes] = useNodesState(initialNodes);
......
.operatorItemBox {
background-color: #fff;
border-radius: 4px;
cursor: grab;
padding: 16px 16px 0 24px;
}
.dragBox {
background-color: #f5f6f7;
}
.operatorItemTitle {
user-select: none;
font-size: 14px;
color: #1e2633;
}
.operatorItemText {
color: #8a9099;
margin: 8px 0;
font-size: 12px;
user-select: none;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.labelBox {
user-select: none;
display: inline-block;
border-radius: 2px;
font-size: 12px;
padding: 2px 8px;
}
.searchBox {
padding: 0 24px 16px 24px;
}
.footerBox {
display: flex;
align-items: center;
padding-bottom: 16px;
border-bottom: 1px solid #f0f2f5;
}
.operatorListBox {
height: 100%;
}
.listBox {
overflow-y: scroll;
height: calc(100% - 48px);
}
import { OutlinedInput } from "@mui/material";
import SearchIcon from "@mui/icons-material/Search";
import classNames from "classnames";
import { useCallback, useState } from "react";
import { mockData } from "./mock";
import { IOperatorItemProps } from "./interface";
import styles from "./index.module.css";
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-06 15:16:01
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-06 21:23:19
* @FilePath: /bkunyun/src/views/WorkFlowEdit/components/OperatorList/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
const OperatorItem = (props: IOperatorItemProps) => {
const { info } = props;
const [isDragStyle, setIsDragStyle] = useState<boolean>(false);
/** 拖拽开始 */
const onDragStart = useCallback(() => {
setIsDragStyle(true);
}, []);
/** 拖拽结束 */
const onDragEnd = useCallback((e: React.DragEvent<HTMLDivElement>) => {
console.log(e);
setIsDragStyle(false);
}, []);
return (
<div
className={classNames({
[styles.operatorItemBox]: true,
[styles.dragBox]: isDragStyle,
})}
draggable={true}
onDragStart={onDragStart}
onDragEnd={onDragEnd}
>
<h2 className={styles.operatorItemTitle}>说什么呢啊</h2>
<div className={styles.operatorItemText}>
STU utility
是一个R-packa标处理目标处理,目标处理目标处理标处理目标处理后期委屈好委屈农,博啊发布丢我被欺安度切换阿斯顿几切换,i的亲戚我好奇你eqeqeweqeqeeqeqeqeqeq。
</div>
<div className={styles.footerBox}>
<span
className={styles.labelBox}
style={{
background: true ? "#EBF3FF" : "#E3FAEC",
color: true ? "#1370FF" : "#02AB83",
}}
>
公共平台
</span>
</div>
</div>
);
};
const OperatorList = () => {
return (
<div className={styles.operatorListBox}>
<div className={styles.searchBox}>
<OutlinedInput
onChange={(e: any) => {
console.log(e.target.value);
}}
// value={templateName}
placeholder="输入关键词搜索"
size="small"
sx={{ height: 32, width: "100%" }}
endAdornment={<SearchIcon style={{ color: "#8A9099" }} />}
/>
</div>
<div className={styles.listBox}>
{mockData.map((item) => {
return <OperatorItem key={item.id} info={item} />;
})}
</div>
</div>
);
};
export default OperatorList;
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-07-06 15:32:11
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-06 15:32:42
* @FilePath: /bkunyun/src/views/WorkFlowEdit/components/OperatorList/interface.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
export interface IOperatorItemProps {
info: any
}
\ No newline at end of file
This diff is collapsed.
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
height: 100vh; height: 100vh;
background-color: RGBA(247, 248, 250, 1); background-color: RGBA(247, 248, 250, 1);
overflow-y: scroll; overflow-y: scroll;
} }
.swHeader { .swHeader {
z-index: 1001; z-index: 1001;
position: sticky; position: sticky;
top: 0; top: 0;
...@@ -19,26 +19,24 @@ ...@@ -19,26 +19,24 @@
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 0 24px; padding: 0 24px;
} }
.swHeaderLeft { .swHeaderLeft {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
} }
.swContent { .swContent {
display: flex; display: flex;
height: calc(100vh - 56px); height: calc(100vh - 56px);
} }
.swFormBox { .swFormBox {
background-color: #fff; background-color: #fff;
border-right: 1xp solid rgba(235, 237, 240, 1); border-right: 1xp solid rgba(235, 237, 240, 1);
width: 608px; width: 360px;
overflow-y: scroll; /* overflow-y: scroll; */
box-sizing: border-box; box-sizing: border-box;
padding: 36px; }
} .swFlowBox {
.swFlowBox {
flex: 1; flex: 1;
height: calc(100vh - 56px); height: calc(100vh - 56px);
} }
\ 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-05 16:31:28 * @LastEditTime: 2022-07-06 18:35:24
* @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
*/ */
...@@ -14,9 +14,9 @@ import { useLocation, useNavigate } from "react-router-dom"; ...@@ -14,9 +14,9 @@ import { useLocation, useNavigate } from "react-router-dom";
import MyPopconfirm from "@/components/mui/MyPopconfirm"; import MyPopconfirm from "@/components/mui/MyPopconfirm";
import ButtonComponent from "@/components/mui/Button"; import ButtonComponent from "@/components/mui/Button";
import { ITemplateConfig } from "../Project/ProjectSubmitWork/interface"; import { ITemplateConfig } from "../Project/ProjectSubmitWork/interface";
import OperatorList from "./components/OperatorList";
import styles from './index.module.css' import styles from "./index.module.css";
const WorkFlowEdit = () => { const WorkFlowEdit = () => {
const [templateConfigInfo, setTemplateConfigInfo] = const [templateConfigInfo, setTemplateConfigInfo] =
...@@ -24,14 +24,13 @@ const WorkFlowEdit = () => { ...@@ -24,14 +24,13 @@ const WorkFlowEdit = () => {
const location: any = useLocation(); const location: any = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
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={()=>console.log(11)} onConfirm={() => console.log(11)}
> >
<IconButton <IconButton
color="primary" color="primary"
...@@ -53,7 +52,7 @@ const WorkFlowEdit = () => { ...@@ -53,7 +52,7 @@ const WorkFlowEdit = () => {
<div className={styles.swHeaderRight}> <div className={styles.swHeaderRight}>
<MyPopconfirm <MyPopconfirm
title="提交前请先确认参数填写无误,确认提交吗?" title="提交前请先确认参数填写无误,确认提交吗?"
onConfirm={()=>console.log(2)} onConfirm={() => console.log(2)}
> >
<ButtonComponent <ButtonComponent
text="保存" text="保存"
...@@ -64,11 +63,9 @@ const WorkFlowEdit = () => { ...@@ -64,11 +63,9 @@ const WorkFlowEdit = () => {
</div> </div>
<div className={styles.swContent}> <div className={styles.swContent}>
<div className={styles.swFormBox}> <div className={styles.swFormBox}>
左侧 <OperatorList />
</div>
<div className={styles.swFlowBox}>
右侧
</div> </div>
<div className={styles.swFlowBox}>右侧</div>
</div> </div>
</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