Commit 91794fa1 authored by chenshouchao's avatar chenshouchao

fix: 解决冲突

parents f1da6197 2cfbf2e2
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-21 20:03:56
* @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
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -39,39 +39,39 @@ import { storageUnitFromB } from "@/utils/util";
import styles from "./index.module.css";
const stateMap = {
RUNNING: "正在运行",
ABORTED: "运行终止",
FAILED: "运行失败",
SUCCEEDED: "运行成功",
RUNNING: "正在运行",
ABORTED: "运行终止",
FAILED: "运行失败",
SUCCEEDED: "运行成功",
};
const statusMap = {
Done: "运行完成",
Running: "正在运行",
Failed: "运行失败",
Pending: "等待运行",
Done: "运行完成",
Running: "正在运行",
Failed: "运行失败",
Pending: "等待运行",
};
type IStatus = "Done" | "Running" | "Failed" | "Pending";
let randerOutputs: Array<any> = [];
const ProjectSubmitWork = observer(() => {
const { currentProjectStore } = useStores();
const fileToken = toJS(currentProjectStore.currentProjectInfo.filetoken);
const projectId = toJS(currentProjectStore.currentProjectInfo.id);
const [workFlowJobInfo, setWorkFlowJobInfo] = useState<ITaskInfo>();
const [patchInfo, setPatchInfo] = useState<any>();
const [activePatchId, setActivePatchId] = useState<string>("");
const [overviewActive, setOverviewActive] = useState(true);
const [activeFlowIndex, setActiveFlowIndex] = useState<number>(0);
const [showOptions, setShowOptions] = useState<boolean>(false);
const [randerOutputs1, setRanderOutputs] = useState<Array<any>>([]);
const location: any = useLocation();
const navigate = useNavigate();
const message = useMessage();
const [fullScreenShow, setFullScreenShow] = useState<boolean>(false);
const { currentProjectStore } = useStores();
const fileToken = toJS(currentProjectStore.currentProjectInfo.filetoken);
const projectId = toJS(currentProjectStore.currentProjectInfo.id);
const [workFlowJobInfo, setWorkFlowJobInfo] = useState<ITaskInfo>();
const [patchInfo, setPatchInfo] = useState<any>();
const [activePatchId, setActivePatchId] = useState<string>("");
const [overviewActive, setOverviewActive] = useState(true);
const [activeFlowIndex, setActiveFlowIndex] = useState<number>(0);
const [showOptions, setShowOptions] = useState<boolean>(false);
const [randerOutputs1, setRanderOutputs] = useState<Array<any>>([]);
const location: any = useLocation();
const navigate = useNavigate();
const message = useMessage();
const [fullScreenShow, setFullScreenShow] = useState<boolean>(false);
const { name, state } = workFlowJobInfo || {};
const { name, state } = workFlowJobInfo || {};
/** 获取模版数据 */
const { run } = useMyRequest(fetchWorkFlowJob, {
......@@ -90,14 +90,13 @@ const ProjectSubmitWork = observer(() => {
});
}, [location?.state, run]);
const { run: getworkFlowTaskInfoRun } = useMyRequest(getworkFlowTaskInfo, {
onSuccess: (res) => {
setPatchInfo(res.data);
},
});
const { run: getworkFlowTaskInfoRun } = useMyRequest(getworkFlowTaskInfo, {
onSuccess: (res) => {
setPatchInfo(res.data);
},
});
const goToProjectData = (path: string) => {
console.log(path);
path = path.slice(13);
if (path) {
navigate(`/product/cadd/projectData`, {
......@@ -126,393 +125,391 @@ const ProjectSubmitWork = observer(() => {
});
}, [navigate]);
const outputPathTransform = (path: string) => {
path = path.slice(13);
return `ProjectData${path}`;
};
const outputPathTransform = (path: string) => {
path = path.slice(13);
return `ProjectData${path}`;
};
const getOutouts = (outputs: any) => {
if (outputs) {
let result = Object.keys(outputs);
let arr = result.map((item) => {
let type = "file";
if (outputs[item].indexOf("dataset") !== -1) {
type = "dataset";
}
return {
name: item,
type,
path: outputs[item],
size: 0,
};
});
arr.forEach(async (item, index) => {
if (item.type === "dataset") {
await getDataSetSize(item, index);
} else {
await getFileSize(item, index);
}
});
randerOutputs = arr;
setRanderOutputs([...randerOutputs]);
} else {
randerOutputs = [];
setRanderOutputs([]);
}
};
const getOutouts = (outputs: any) => {
if (outputs) {
let result = Object.keys(outputs);
let arr = result.map((item) => {
let type = "file";
if (outputs[item].indexOf("dataset") !== -1) {
type = "dataset";
}
return {
name: item,
type,
path: outputs[item],
size: 0,
};
});
arr.forEach(async (item, index) => {
if (item.type === "dataset") {
await getDataSetSize(item, index);
} else {
await getFileSize(item, index);
}
});
randerOutputs = arr;
setRanderOutputs([...randerOutputs]);
} else {
randerOutputs = [];
setRanderOutputs([]);
}
};
const getDataSetSize = async (item: any, index: number) => {
let path = item.path.slice(13);
const lastIndex = path.lastIndexOf("/");
if (lastIndex === -1) {
path = "/";
} else {
path = path.slice(0, lastIndex + 1);
}
const res = await getDataFind({
projectId: projectId as string,
path: path,
});
res.data.forEach((item1: any) => {
if (item1.name === item.path.slice(item.path.lastIndexOf("/") + 1)) {
randerOutputs[index].size = `${item1.size}条`;
setRanderOutputs([...randerOutputs]);
}
});
};
const getDataSetSize = async (item: any, index: number) => {
let path = item.path.slice(13);
const lastIndex = path.lastIndexOf("/");
if (lastIndex === -1) {
path = "/";
} else {
path = path.slice(0, lastIndex + 1);
}
const res = await getDataFind({
projectId: projectId as string,
path: path,
});
res.data.forEach((item1: any) => {
if (item1.name === item.path.slice(item.path.lastIndexOf("/") + 1)) {
randerOutputs[index].size = `${item1.size}条`;
setRanderOutputs([...randerOutputs]);
}
});
};
const getFileSize = (item: any, index: number) => {
let path = item.path.slice(13);
const lastIndex = path.lastIndexOf("/");
if (lastIndex === -1) {
path = "/";
} else {
path = path.slice(0, lastIndex + 1);
}
CloudEController.JobOutFileList(
path,
fileToken as string,
projectId as string,
false
)?.then((res) => {
if (Array.isArray(res.data)) {
res.data.forEach((item1) => {
if (item1.name === item.path.slice(item.path.lastIndexOf("/") + 1)) {
randerOutputs[index].size = `${
item1.size ? storageUnitFromB(Number(item1.size)) : "-"
}`;
setRanderOutputs([...randerOutputs]);
}
});
}
});
};
const getFileSize = (item: any, index: number) => {
let path = item.path.slice(13);
const lastIndex = path.lastIndexOf("/");
if (lastIndex === -1) {
path = "/";
} else {
path = path.slice(0, lastIndex + 1);
}
CloudEController.JobOutFileList(
path,
fileToken as string,
projectId as string,
false
)?.then((res) => {
if (Array.isArray(res.data)) {
res.data.forEach((item1) => {
if (item1.name === item.path.slice(item.path.lastIndexOf("/") + 1)) {
randerOutputs[index].size = `${
item1.size ? storageUnitFromB(Number(item1.size)) : "-"
}`;
setRanderOutputs([...randerOutputs]);
}
});
}
});
};
// 取消作业
const { run: cancelWorkJob } = useMyRequest(cancelWorkflowJob, {
onSuccess: (res: IResponse<boolean>) => {
const { errorCode } = res;
if (errorCode === 0) {
message.success("操作成功!");
}
onBack();
},
});
// 取消作业
const { run: cancelWorkJob } = useMyRequest(cancelWorkflowJob, {
onSuccess: (res: IResponse<boolean>) => {
const { errorCode } = res;
if (errorCode === 0) {
message.success("操作成功!");
}
onBack();
},
});
// 取消作业
const { run: deleteWorkJob } = useMyRequest(deleteWorkflowJob, {
onSuccess: (res: IResponse<boolean>) => {
const { errorCode } = res;
if (errorCode === 0) {
message.success("操作成功!");
}
onBack();
},
});
// 取消作业
const { run: deleteWorkJob } = useMyRequest(deleteWorkflowJob, {
onSuccess: (res: IResponse<boolean>) => {
const { errorCode } = res;
if (errorCode === 0) {
message.success("操作成功!");
}
onBack();
},
});
const handleBatch = (id: string) => {
setActivePatchId(id);
if (id) {
setActiveFlowIndex(0);
getworkFlowTaskInfoRun({
jobId: workFlowJobInfo?.id as string,
taskId: id,
});
}
};
const handleBatch = (id: string) => {
setActivePatchId(id);
if (id) {
setActiveFlowIndex(0);
getworkFlowTaskInfoRun({
jobId: workFlowJobInfo?.id as string,
taskId: id,
});
}
};
const randerParameters = useMemo(() => {
if (patchInfo?.children) {
if (patchInfo.children.length > 0) {
return patchInfo.children[activeFlowIndex].parameters;
} else {
return patchInfo?.parameters;
}
} else {
return patchInfo?.parameters;
}
}, [activeFlowIndex, patchInfo]);
const randerParameters = useMemo(() => {
if (patchInfo?.children) {
if (patchInfo.children.length > 0) {
return patchInfo.children[activeFlowIndex].parameters;
} else {
return patchInfo?.parameters;
}
} else {
return patchInfo?.parameters;
}
}, [activeFlowIndex, patchInfo]);
const handleParams = () => {
setOverviewActive(false);
setShowOptions(!showOptions);
};
const handleParams = () => {
setOverviewActive(false);
setShowOptions(!showOptions);
};
const handleDownLoad = (path: string) => {
if (path.indexOf("/home/cloudam") !== -1) {
path = path.slice(13);
}
CloudEController.JobFileDownload(
path,
fileToken as string,
projectId as string
);
};
const handleDownLoad = (path: string) => {
if (path.indexOf("/home/cloudam") !== -1) {
path = path.slice(13);
}
CloudEController.JobFileDownload(
path,
fileToken as string,
projectId as string
);
};
/** 终止任务 */
const onStopJob = useCallback(() => {
cancelWorkJob({
jobid: workFlowJobInfo?.id || "",
});
}, [cancelWorkJob, workFlowJobInfo?.id]);
/** 终止任务 */
const onStopJob = useCallback(() => {
cancelWorkJob({
jobid: workFlowJobInfo?.id || "",
});
}, [cancelWorkJob, workFlowJobInfo?.id]);
/** 删除任务 */
const onDeleteJob = useCallback(() => {
deleteWorkJob({
id: workFlowJobInfo?.id || "",
});
}, [deleteWorkJob, workFlowJobInfo?.id]);
/** 删除任务 */
const onDeleteJob = useCallback(() => {
deleteWorkJob({
id: workFlowJobInfo?.id || "",
});
}, [deleteWorkJob, workFlowJobInfo?.id]);
return (
<div className={styles.swBox}>
{fullScreenShow ? null : (
<div className={styles.swHeader}>
<div className={styles.swHeaderLeft}>
<IconButton
color="primary"
onClick={onBack}
aria-label="upload picture"
component="span"
size="small"
>
<ArrowBackIosNewIcon
sx={{
color: "rgba(194, 198, 204, 1)",
width: "12px",
height: "12px",
}}
/>
</IconButton>
return (
<div className={styles.swBox}>
{fullScreenShow ? null : (
<div className={styles.swHeader}>
<div className={styles.swHeaderLeft}>
<IconButton
color="primary"
onClick={onBack}
aria-label="upload picture"
component="span"
size="small"
>
<ArrowBackIosNewIcon
sx={{
color: "rgba(194, 198, 204, 1)",
width: "12px",
height: "12px",
}}
/>
</IconButton>
<div className={styles.swTemplateTitle}>{name}</div>
</div>
<div className={styles.swHeaderRight}>
<MyPopconfirm
title={
state === "RUNNING"
? "正在运行的任务终止后将无法重新运行,确认继续吗?"
: "任务被删除后将无法恢复,确认继续吗?"
}
onConfirm={() => {
state === "RUNNING" ? onStopJob() : onDeleteJob();
}}
>
<ButtonComponent
text={state === "RUNNING" ? "终止" : "删除"}
variant="outlined"
color="secondary"
// click={onStopJob}
></ButtonComponent>
</MyPopconfirm>
</div>
</div>
)}
<div className={styles.swContent}>
{fullScreenShow ? null : (
<div className={styles.swFormBox}>
{!activePatchId && (
<div className={styles.taskInfo}>
<div className={styles.title}>任务结果</div>
{workFlowJobInfo?.outputs && (
<div className={styles.taskResults}>
{randerOutputs1.map((item, index) => {
return (
<div key={index} className={styles.outputLi}>
<MyPopconfirm
title="即将跳转至项目数据内该任务的结果目录,确认继续吗?"
onConfirm={() =>
goToProjectData(getFolderPath(item.path))
}
>
<div className={styles.outputLiLeft}>
<img
className={styles.outputLiLeftImg}
src={
item.type === "file" ? fileIcon : dataSetIcon
}
alt=""
/>
{item.name}
</div>
</MyPopconfirm>
<span className={styles.outputLiRight}>
{item.size}
</span>
</div>
);
})}
</div>
)}
{!workFlowJobInfo?.outputs && (
<div className={styles.notResults}>暂无结果文件</div>
)}
<div className={styles.title}>任务信息</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>任务名称</div>
<div className={styles.taskInfoValue} title={name}>
{name || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>任务ID</div>
<div
className={styles.taskInfoValue}
title={workFlowJobInfo?.id}
>
{workFlowJobInfo?.id || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>输出路径</div>
<div
className={classNames({
[styles.taskInfoValue]: true,
[styles.taskInfoValueClick]: true,
})}
onClick={() =>
goToProjectData(workFlowJobInfo?.outputPath as string)
}
>
{workFlowJobInfo?.outputPath
? outputPathTransform(workFlowJobInfo?.outputPath)
: "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>运行状态</div>
<div className={styles.taskInfoValue}>
{state === "SUCCEEDED" && (
<img
className={styles.taskInfoValueIcon}
src={jobSue}
alt=""
/>
)}
{state === "RUNNING" && (
<img
className={styles.taskInfoValueIcon}
src={jobRun}
alt=""
/>
)}
{state === "ABORTED" && (
<img
className={styles.taskInfoValueIcon}
src={jobStop}
alt=""
/>
)}
{state === "FAILED" && (
<img
className={styles.taskInfoValueIcon}
src={jobFail}
alt=""
/>
)}
{state ? stateMap[state] : "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>源模板</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.specTitle || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>源模板版本</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.specVersion || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>花费(元)</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.jobCost || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>创建人</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.creator || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>创建时间</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.createTime || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>运行时间</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.costTime || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>日志文件</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.logPath && (
<span
className={styles.taskInfoDownload}
onClick={() => handleDownLoad(workFlowJobInfo?.logPath)}
>
下载
</span>
)}
{!workFlowJobInfo?.logPath && "-"}
</div>
</div>
</div>
)}
{activePatchId && (
<div className={styles.suanziInfo}>
<div className={styles.title}>{patchInfo?.title}</div>
<div className={styles.tabs}>
<div
className={classNames({
[styles.tabLi]: true,
[styles.tabLiAcitve]: overviewActive,
})}
onClick={() => setOverviewActive(true)}
>
概览
</div>
<div
className={classNames({
[styles.tabLi]: true,
[styles.tabLiAcitve]: !overviewActive,
})}
// onClick={() => setOverviewActive(false)}
onClick={() => handleParams()}
>
{patchInfo?.children.length > 0
? patchInfo?.children[activeFlowIndex].title
: patchInfo?.title}
{showOptions && patchInfo?.children.length > 0 && (
<div className={styles.options}>
{patchInfo?.children.map((item: any, index: number) => {
return (
<div
<div className={styles.swTemplateTitle}>{name}</div>
</div>
<div className={styles.swHeaderRight}>
<MyPopconfirm
title={
state === "RUNNING"
? "正在运行的任务终止后将无法重新运行,确认继续吗?"
: "任务被删除后将无法恢复,确认继续吗?"
}
onConfirm={() => {
state === "RUNNING" ? onStopJob() : onDeleteJob();
}}
>
<ButtonComponent
text={state === "RUNNING" ? "终止" : "删除"}
variant="outlined"
color="secondary"
// click={onStopJob}
></ButtonComponent>
</MyPopconfirm>
</div>
</div>
)}
<div className={styles.swContent}>
{fullScreenShow ? null : (
<div className={styles.swFormBox}>
{!activePatchId && (
<div className={styles.taskInfo}>
<div className={styles.title}>任务结果</div>
{workFlowJobInfo?.outputs && (
<div className={styles.taskResults}>
{randerOutputs1.map((item, index) => {
return (
<div key={index} className={styles.outputLi}>
<MyPopconfirm
title="即将跳转至项目数据内该任务的结果目录,确认继续吗?"
onConfirm={() => goToProjectData(getFolderPath(item.path))}
>
<div className={styles.outputLiLeft}>
<img
className={styles.outputLiLeftImg}
src={
item.type === "file" ? fileIcon : dataSetIcon
}
alt=""
/>
{item.name}
</div>
</MyPopconfirm>
<span className={styles.outputLiRight}>
{item.size}
</span>
</div>
);
})}
</div>
)}
{!workFlowJobInfo?.outputs && (
<div className={styles.notResults}>暂无结果文件</div>
)}
<div className={styles.title}>任务信息</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>任务名称</div>
<div className={styles.taskInfoValue} title={name}>
{name || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>任务ID</div>
<div
className={styles.taskInfoValue}
title={workFlowJobInfo?.id}
>
{workFlowJobInfo?.id || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>输出路径</div>
<div
className={classNames({
[styles.taskInfoValue]: true,
[styles.taskInfoValueClick]: true,
})}
onClick={() =>
goToProjectData(workFlowJobInfo?.outputPath as string)
}
>
{workFlowJobInfo?.outputPath
? outputPathTransform(workFlowJobInfo?.outputPath)
: "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>运行状态</div>
<div className={styles.taskInfoValue}>
{state === "SUCCEEDED" && (
<img
className={styles.taskInfoValueIcon}
src={jobSue}
alt=""
/>
)}
{state === "RUNNING" && (
<img
className={styles.taskInfoValueIcon}
src={jobRun}
alt=""
/>
)}
{state === "ABORTED" && (
<img
className={styles.taskInfoValueIcon}
src={jobStop}
alt=""
/>
)}
{state === "FAILED" && (
<img
className={styles.taskInfoValueIcon}
src={jobFail}
alt=""
/>
)}
{state ? stateMap[state] : "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>源模板</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.specTitle || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>源模板版本</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.specVersion || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>花费(元)</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.jobCost || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>创建人</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.creator || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>创建时间</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.createTime || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>运行时间</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.costTime || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>日志文件</div>
<div className={styles.taskInfoValue}>
{workFlowJobInfo?.logPath && (
<span
className={styles.taskInfoDownload}
onClick={() => handleDownLoad(workFlowJobInfo?.logPath)}
>
下载
</span>
)}
{!workFlowJobInfo?.logPath && "-"}
</div>
</div>
</div>
)}
{activePatchId && (
<div className={styles.suanziInfo}>
<div className={styles.title}>{patchInfo?.title}</div>
<div className={styles.tabs}>
<div
className={classNames({
[styles.tabLi]: true,
[styles.tabLiAcitve]: overviewActive,
})}
onClick={() => setOverviewActive(true)}
>
概览
</div>
<div
className={classNames({
[styles.tabLi]: true,
[styles.tabLiAcitve]: !overviewActive,
})}
// onClick={() => setOverviewActive(false)}
onClick={() => handleParams()}
>
{patchInfo?.children.length > 0
? patchInfo?.children[activeFlowIndex].title
: patchInfo?.title}
{showOptions && patchInfo?.children.length > 0 && (
<div className={styles.options}>
{patchInfo?.children.map((item: any, index: number) => {
return (
<div
key={index}
className={classNames({
[styles.option]: true,
......@@ -523,95 +520,95 @@ const ProjectSubmitWork = observer(() => {
>
{item.title}
</div>
);
})}
</div>
)}
</div>
</div>
{overviewActive && (
<div className={styles.overview}>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>描述</div>
<div
className={classNames({
[styles.taskInfoValue]: true,
[styles.taskInfoValueShowAll]: true,
})}
>
{patchInfo?.description}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>算子版本</div>
<div className={styles.taskInfoValue}>
{patchInfo?.creator || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>算子状态</div>
<div className={styles.taskInfoValue}>
{patchInfo?.status === "Done" && (
<img
className={styles.taskInfoValueIcon}
src={jobSue}
alt=""
/>
)}
{patchInfo?.status === "Running" && (
<img
className={styles.taskInfoValueIcon}
src={jobRun}
alt=""
/>
)}
{patchInfo?.status === "Failed" && (
<img
className={styles.taskInfoValueIcon}
src={jobFail}
alt=""
/>
)}
{statusMap[patchInfo?.status as IStatus]}
</div>
</div>
</div>
)}
{!overviewActive && (
<div className={styles.params}>
{randerParameters.map((parameter: any) => {
return (
<div className={styles.taskInfoLi} key={parameter.name}>
<div className={styles.taskInfoParams}>
{parameter.name}
</div>
<div className={styles.taskInfoValue}>
{parameter.value || "-"}
</div>
</div>
);
})}
</div>
)}
</div>
)}
</div>
)}
<div
className={styles.swFlowBox}
style={fullScreenShow ? { height: "100vh" } : undefined}
>
<Flow tasks={workFlowJobInfo?.tasks} onBatchClick={handleBatch} />
</div>
</div>
<img
className={styles.fullScreenBox}
src={fullScreenShow ? partialScreen : fullScreen}
onClick={() => setFullScreenShow(!fullScreenShow)}
alt="全屏"
/>
</div>
);
);
})}
</div>
)}
</div>
</div>
{overviewActive && (
<div className={styles.overview}>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>描述</div>
<div
className={classNames({
[styles.taskInfoValue]: true,
[styles.taskInfoValueShowAll]: true,
})}
>
{patchInfo?.description}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>算子版本</div>
<div className={styles.taskInfoValue}>
{patchInfo?.creator || "-"}
</div>
</div>
<div className={styles.taskInfoLi}>
<div className={styles.taskInfoParams}>算子状态</div>
<div className={styles.taskInfoValue}>
{patchInfo?.status === "Done" && (
<img
className={styles.taskInfoValueIcon}
src={jobSue}
alt=""
/>
)}
{patchInfo?.status === "Running" && (
<img
className={styles.taskInfoValueIcon}
src={jobRun}
alt=""
/>
)}
{patchInfo?.status === "Failed" && (
<img
className={styles.taskInfoValueIcon}
src={jobFail}
alt=""
/>
)}
{statusMap[patchInfo?.status as IStatus]}
</div>
</div>
</div>
)}
{!overviewActive && (
<div className={styles.params}>
{randerParameters.map((parameter: any) => {
return (
<div className={styles.taskInfoLi} key={parameter.name}>
<div className={styles.taskInfoParams}>
{parameter.name}
</div>
<div className={styles.taskInfoValue}>
{parameter.value || "-"}
</div>
</div>
);
})}
</div>
)}
</div>
)}
</div>
)}
<div
className={styles.swFlowBox}
style={fullScreenShow ? { height: "100vh" } : undefined}
>
<Flow tasks={workFlowJobInfo?.tasks} onBatchClick={handleBatch} />
</div>
</div>
<img
className={styles.fullScreenBox}
src={fullScreenShow ? partialScreen : fullScreen}
onClick={() => setFullScreenShow(!fullScreenShow)}
alt="全屏"
/>
</div>
);
});
export default ProjectSubmitWork;
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-05 18:06:17
* @LastEditTime: 2022-07-06 17:32:50
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -22,259 +22,265 @@ import SimpleDialog from "./components/simpleDialog";
import AddTemplate from "./components/addTemplate";
import noData from "../../../../assets/project/noTemplate.svg";
import {
getWorkbenchTemplate,
deleteWorkbenchTemplate,
getAddWorkbenchTemplate,
addWorkbenchTemplate,
getWorkbenchTemplate,
deleteWorkbenchTemplate,
getAddWorkbenchTemplate,
addWorkbenchTemplate,
} from "@/api/workbench_api";
import usePass from "@/hooks/usePass";
import ReactFlowEdit from "@/views/WorkFlowEdit";
import WorkFlowEdit from "@/views/WorkFlowEdit";
import { useStores } from "@/store";
import { ICustomTemplate } from "./interface";
import styles from "./index.module.css";
const ProjectMembers = observer(() => {
const { currentProjectStore } = useStores();
const projectIdData = toJS(currentProjectStore.currentProjectInfo.id);
const { currentProjectStore } = useStores();
const projectIdData = toJS(currentProjectStore.currentProjectInfo.id);
const isPass = usePass();
const isPass = usePass();
/** 搜索模板名称 */
const [templateName, setTemplateName] = useState("");
/** 模板列表 */
const [templateList, setTemplateList] = useState([]);
/** 选中的模板id */
const [templateId, setTemplateId] = useState("");
/** 简单弹窗(删除模板) */
const [openDialog, setOpenDialog] = useState(false);
/** 增加模板 */
const [openAddTemplate, setOpenAddTemplate] = useState(false);
/** 可增加模板列表 */
const [addTemplateList, setAddTemplateList] = useState([]);
/** 已选择增加的模板列表 */
const [selectTemplateData, setSelectTemplateData] = useState<string[]>([]);
/** 搜索模板名称 */
const [templateName, setTemplateName] = useState("");
/** 模板列表 */
const [templateList, setTemplateList] = useState([]);
/** 选中的模板id */
const [templateId, setTemplateId] = useState("");
/** 简单弹窗(删除模板) */
const [openDialog, setOpenDialog] = useState(false);
/** 增加模板 */
const [openAddTemplate, setOpenAddTemplate] = useState(false);
/** 可增加模板列表 */
const [addTemplateList, setAddTemplateList] = useState([]);
/** 已选择增加的模板列表 */
const [selectTemplateData, setSelectTemplateData] = useState<string[]>([]);
// 获取模板列表
const { run: getTemplateInfo } = useMyRequest(getWorkbenchTemplate, {
onSuccess: (result: any) => {
setTemplateList(result.data);
},
});
/** 是否显示自定义模版编辑并带有参数 */
const [customTemplateInfo, setCustomTemplateInfo] = useState<ICustomTemplate>(
{
show: false,
}
);
// 删除模板
const { run: delTemplate } = useMyRequest(deleteWorkbenchTemplate, {
onSuccess: (result: any) => {
setOpenDialog(false);
getTemplateInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
title: templateName,
});
},
});
// 获取模板列表
const { run: getTemplateInfo } = useMyRequest(getWorkbenchTemplate, {
onSuccess: (result: any) => {
setTemplateList(result.data);
},
});
// 添加工作流模板-获取模板列表
const { run: getAddTemplateList } = useMyRequest(getAddWorkbenchTemplate, {
onSuccess: (result: any) => {
setAddTemplateList(result.data);
setOpenAddTemplate(true);
},
});
// 删除模板
const { run: delTemplate } = useMyRequest(deleteWorkbenchTemplate, {
onSuccess: (result: any) => {
setOpenDialog(false);
getTemplateInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
title: templateName,
});
},
});
// 项目管理员-添加工作流模板-提交
const { run: addTemplate } = useMyRequest(addWorkbenchTemplate, {
onSuccess: (result: any) => {
setOpenAddTemplate(false);
getTemplateInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
});
setSelectTemplateData([]);
},
});
// 添加工作流模板-获取模板列表
const { run: getAddTemplateList } = useMyRequest(getAddWorkbenchTemplate, {
onSuccess: (result: any) => {
setAddTemplateList(result.data);
setOpenAddTemplate(true);
},
});
useEffect(() => {
getTemplateInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
});
}, [currentProjectStore.currentProjectInfo.id, getTemplateInfo]);
// 项目管理员-添加工作流模板-提交
const { run: addTemplate } = useMyRequest(addWorkbenchTemplate, {
onSuccess: (result: any) => {
setOpenAddTemplate(false);
getTemplateInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
});
setSelectTemplateData([]);
},
});
useEffect(() => {
console.log("projectIdData: ", projectIdData);
}, [projectIdData]);
useEffect(() => {
getTemplateInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
});
}, [currentProjectStore.currentProjectInfo.id, getTemplateInfo]);
/** 删除模板 */
const deleteTemplate = () => {
delTemplate({
projectId: currentProjectStore.currentProjectInfo.id as string,
workflowSpecId: templateId,
});
};
useEffect(() => {
console.log("projectIdData: ", projectIdData);
}, [projectIdData]);
/** 打开弹窗 */
const startDialog = (id: string) => {
setTemplateId(id);
setOpenDialog(true);
};
/** 删除模板 */
const deleteTemplate = () => {
delTemplate({
projectId: currentProjectStore.currentProjectInfo.id as string,
workflowSpecId: templateId,
});
};
/** 关闭弹窗 */
const closeDialog = () => {
setOpenDialog(false);
};
/** 打开弹窗 */
const startDialog = (id: string) => {
setTemplateId(id);
setOpenDialog(true);
};
/** 增加模板 */
const addTemplateBlock = () => {
getAddTemplateList({
projectId: currentProjectStore.currentProjectInfo.id as string,
productId: "cadd",
});
};
/** 关闭弹窗 */
const closeDialog = () => {
setOpenDialog(false);
};
/** 关闭增加模板 */
const closeAddTemplateBlock = () => {
setOpenAddTemplate(false);
setSelectTemplateData([]);
};
/** 增加模板 */
const addTemplateBlock = () => {
getAddTemplateList({
projectId: currentProjectStore.currentProjectInfo.id as string,
productId: "cadd",
});
};
/** 增加模板操作 */
const addTemplateCallback = () => {
addTemplate({
projectId: currentProjectStore.currentProjectInfo.id as string,
workflowSpecIds: selectTemplateData,
});
};
/** 关闭增加模板 */
const closeAddTemplateBlock = () => {
setOpenAddTemplate(false);
setSelectTemplateData([]);
};
/** 搜索模板 */
const searchTemplateNameCallback = (data: any) => {
getAddTemplateList({
projectId: currentProjectStore.currentProjectInfo.id as string,
productId: "cadd",
title: data,
});
};
/** 增加模板操作 */
const addTemplateCallback = () => {
addTemplate({
projectId: currentProjectStore.currentProjectInfo.id as string,
workflowSpecIds: selectTemplateData,
});
};
const templateSelectCallback = (data: string) => {
let list: string[] = [...selectTemplateData];
if (selectTemplateData.filter((e) => e === data).length > 0) {
list = list.filter((e) => e !== data);
setSelectTemplateData(list);
} else {
list.push(data);
setSelectTemplateData(list);
}
};
/** 搜索模板 */
const searchTemplateNameCallback = (data: any) => {
getAddTemplateList({
projectId: currentProjectStore.currentProjectInfo.id as string,
productId: "cadd",
title: data,
});
};
const searchChange = (data: any) => {
setTemplateName(data.length > 30 ? data.slice(0, 30) : data);
};
const templateSelectCallback = (data: string) => {
let list: string[] = [...selectTemplateData];
if (selectTemplateData.filter((e) => e === data).length > 0) {
list = list.filter((e) => e !== data);
setSelectTemplateData(list);
} else {
list.push(data);
setSelectTemplateData(list);
}
};
useEffect(() => {
setTimeout(() => {
getTemplateInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
title: templateName,
});
}, 300);
}, [templateName]);
const searchChange = (data: any) => {
setTemplateName(data.length > 30 ? data.slice(0, 30) : data);
};
return (
<Box className={styles.headerBox}>
<Box className={styles.tabBox}>
<OutlinedInput
onChange={(e: any) => {
searchChange(e.target.value);
}}
value={templateName}
placeholder="输入关键词搜索"
size="small"
sx={{ width: 340, height: 32 }}
endAdornment={<SearchIcon style={{ color: "#8A9099" }} />}
/>
useEffect(() => {
setTimeout(() => {
getTemplateInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
title: templateName,
});
}, 300);
}, [templateName]);
{templateList.length > 0 &&
isPass("PROJECT_WORKBENCH_FLOES_ADD", "MANAGER") && (
<Button
text={"添加工作流模版"}
img={<Add />}
click={addTemplateBlock}
size={"small"}
/>
)}
</Box>
return (
<Box className={styles.headerBox}>
<Box className={styles.tabBox}>
<OutlinedInput
onChange={(e: any) => {
searchChange(e.target.value);
}}
value={templateName}
placeholder="输入关键词搜索"
size="small"
sx={{ width: 340, height: 32 }}
endAdornment={<SearchIcon style={{ color: "#8A9099" }} />}
/>
{templateList.length === 0 && templateName.length > 0 && (
<Box
sx={{
display: "flex",
alignItems: "center",
flexDirection: "column",
minHeight: "calc(100vh - 376px)",
justifyContent: "center",
}}
>
<img alt="" src={noData} />
<Typography
sx={{ fontSize: "12px", fontWeight: "400", color: "#8A9099" }}
>
暂未开启模版
</Typography>
</Box>
)}
{templateList.length > 0 && (
<Box sx={{ display: "flex", flexWrap: "wrap", marginLeft: "-8px" }}>
{templateList &&
templateList.length > 0 &&
templateList.map((item, key) => {
return (
<TemplateBox data={item} startDialog={startDialog} key={key} />
);
})}
</Box>
)}
{templateList.length === 0 &&
templateName.length === 0 &&
isPass("PROJECT_WORKBENCH_FLOES_ADD", "MANAGER") && (
<Box className={styles.addNewTemplate} onClick={addTemplateBlock}>
<Add
sx={{
color: "#565C66",
fontSize: "20px",
width: "30px",
height: "30px",
}}
/>
<Typography
sx={{
fontSize: "14px",
fontWeight: "400",
color: "#8A9099",
marginTop: "15px",
}}
>
添加工作流模版
</Typography>
</Box>
)}
{templateList.length > 0 &&
isPass("PROJECT_WORKBENCH_FLOES_ADD", "MANAGER") && (
<Button
text={"添加工作流模版"}
img={<Add />}
click={addTemplateBlock}
size={"small"}
/>
)}
</Box>
<AddTemplate
openAddTemplate={openAddTemplate}
closeAddTemplateBlock={closeAddTemplateBlock}
addTemplateList={addTemplateList}
templateSelectCallback={templateSelectCallback}
selectTemplateData={selectTemplateData}
addTemplateCallback={addTemplateCallback}
searchTemplateNameCallback={searchTemplateNameCallback}
/>
{templateList.length === 0 && templateName.length > 0 && (
<Box
sx={{
display: "flex",
alignItems: "center",
flexDirection: "column",
minHeight: "calc(100vh - 376px)",
justifyContent: "center",
}}
>
<img alt="" src={noData} />
<Typography
sx={{ fontSize: "12px", fontWeight: "400", color: "#8A9099" }}
>
暂未开启模版
</Typography>
</Box>
)}
{templateList.length > 0 && (
<Box sx={{ display: "flex", flexWrap: "wrap", marginLeft: "-8px" }}>
{templateList &&
templateList.length > 0 &&
templateList.map((item, key) => {
return <TemplateBox data={item} startDialog={startDialog} />;
})}
</Box>
)}
{templateList.length === 0 &&
templateName.length === 0 &&
isPass("PROJECT_WORKBENCH_FLOES_ADD", "MANAGER") && (
<Box className={styles.addNewTemplate} onClick={addTemplateBlock}>
<Add
sx={{
color: "#565C66",
fontSize: "20px",
width: "30px",
height: "30px",
}}
/>
<Typography
sx={{
fontSize: "14px",
fontWeight: "400",
color: "#8A9099",
marginTop: "15px",
}}
>
添加工作流模版
</Typography>
</Box>
)}
{/* <ReactFlowEdit/> */}
<AddTemplate
openAddTemplate={openAddTemplate}
closeAddTemplateBlock={closeAddTemplateBlock}
addTemplateList={addTemplateList}
templateSelectCallback={templateSelectCallback}
selectTemplateData={selectTemplateData}
addTemplateCallback={addTemplateCallback}
searchTemplateNameCallback={searchTemplateNameCallback}
/>
<SimpleDialog
text={"确认移除该模板吗?"}
title={"删除模板"}
openDialog={openDialog}
closeDialog={closeDialog}
onConfirm={deleteTemplate}
/>
</Box>
);
{customTemplateInfo?.show ? <WorkFlowEdit /> : null}
<SimpleDialog
text={"确认移除该模板吗?"}
title={"删除模板"}
openDialog={openDialog}
closeDialog={closeDialog}
onConfirm={deleteTemplate}
/>
</Box>
);
});
export default memo(ProjectMembers);
/*
* @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
import ReactFlow, {
Controls,
Background,
useNodesState,
useEdgesState,
Handle,
Position,
ReactFlowProps,
Node,
Controls,
Background,
useNodesState,
useEdgesState,
Handle,
Position,
ReactFlowProps,
Node,
} from "react-flow-renderer";
import { useCallback, useEffect, useMemo, useState } from "react";
import classNames from "classnames";
......@@ -14,7 +14,11 @@ import classNames from "classnames";
import jobFail from "@/assets/project/jobFail.svg";
import jobRun from "@/assets/project/jobRun.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 styles from "./index.module.css";
......@@ -27,300 +31,317 @@ import styles from "./index.module.css";
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
interface IProps extends ReactFlowProps {
tasks?: ITask[];
/** 点击batch事件 */
onBatchClick?: (val: string) => void;
setSelectedNodeId?: (val:string) => void;
selectedNodeId?: string;
tasks?: ITask[];
/** 点击batch事件 */
onBatchClick?: (val: string) => void;
setSelectedNodeId?: (val: string) => void;
selectedNodeId?: string;
}
/** 获取imgUrl */
const getImgUrl = (type: IExecutionStatus) => {
if(type === 'Done'){
return jobSue
}
if(type === 'Failed'){
return jobFail
}
if(type === 'Running'){
return jobRun
}
return undefined
}
/** 获取imgUrl */
const getImgUrl = (type: IExecutionStatus) => {
if (type === "Done") {
return jobSue;
}
if (type === "Failed") {
return jobFail;
}
if (type === "Running") {
return jobRun;
}
return undefined;
};
/** 自定义batch节点 */
const BatchNode = (props: IBatchNode) => {
const { data } = props;
const { dotStatus, style, isFlowNode, label, selectedStatus } = data;
return (
<div
className={classNames({
[styles.batchNode]: true,
[styles.selectedBatchBox]: selectedStatus,
[styles.selectBatchNode]: selectedStatus,
})}
style={style}
>
{dotStatus?.isInput ? (
<Handle
style={{ background: "#fff ", border: "1px solid #D1D6DE", left: 20 }}
type="target"
position={Position.Top}
/>
) : null}
<div
className={classNames({
[styles.batchRotate]: isFlowNode,
})}
>
{label || ""}
{data.isCheck && <span className={styles.successDot}></span>}
</div>
{dotStatus?.isOutput ? (
<Handle
style={{ background: "#fff ", border: "1px solid #D1D6DE", left: 20 }}
type="source"
position={Position.Bottom}
/>
) : null}
</div>
);
const { data } = props;
const { dotStatus, style, isFlowNode, label, selectedStatus } = data;
return (
<div
className={classNames({
[styles.batchNode]: true,
[styles.selectedBatchBox]: selectedStatus,
[styles.selectBatchNode]: selectedStatus,
})}
style={style}
>
{dotStatus?.isInput ? (
<Handle
style={{ background: "#fff ", border: "1px solid #D1D6DE", left: 20 }}
type="target"
position={Position.Top}
/>
) : null}
<div
className={classNames({
[styles.batchRotate]: isFlowNode,
})}
>
{label || ""}
{data.isCheck && <span className={styles.successDot}></span>}
</div>
{dotStatus?.isOutput ? (
<Handle
style={{ background: "#fff ", border: "1px solid #D1D6DE", left: 20 }}
type="source"
position={Position.Bottom}
/>
) : null}
</div>
);
};
/** 自定义flow节点 */
const FlowNode = (props: any) => {
const { data } = props;
return (
<div
className={classNames({
[styles.flowNode]: true,
})}
>
{data?.dotStatus?.isInput ? (
<Handle
style={{ background: "#C2C6CC ", left: 12 }}
type="target"
position={Position.Top}
/>
) : null}
<div style={{ display: "flex", alignItems: "center" }}>
{data?.label || ""}
{data.isCheck && <span className={styles.successDot}></span>}
{getImgUrl(data.executionStatus) && <img style={{ marginLeft: "6px" }} src={getImgUrl(data.executionStatus)} alt="" />}
</div>
{data?.dotStatus?.isOutput ? (
<Handle
style={{ background: "#C2C6CC ", left: 12 }}
type="source"
position={Position.Bottom}
id="a"
/>
) : null}
</div>
);
const { data } = props;
return (
<div
className={classNames({
[styles.flowNode]: true,
})}
>
{data?.dotStatus?.isInput ? (
<Handle
style={{ background: "#C2C6CC ", left: 12 }}
type="target"
position={Position.Top}
/>
) : null}
<div style={{ display: "flex", alignItems: "center" }}>
{data?.label || ""}
{data.isCheck && <span className={styles.successDot}></span>}
{getImgUrl(data.executionStatus) && (
<img
style={{ marginLeft: "6px" }}
src={getImgUrl(data.executionStatus)}
alt=""
/>
)}
</div>
{data?.dotStatus?.isOutput ? (
<Handle
style={{ background: "#C2C6CC ", left: 12 }}
type="source"
position={Position.Bottom}
id="a"
/>
) : null}
</div>
);
};
const Flow = (props: IProps) => {
const { tasks, onBatchClick, setSelectedNodeId, selectedNodeId } = props;
/** 自定义的节点类型 */
const nodeTypes = useMemo(() => {
return { batchNode: BatchNode, flowNode: FlowNode };
}, []);
const { tasks, onBatchClick, setSelectedNodeId, selectedNodeId } = props;
/** 自定义的节点类型 */
const nodeTypes = useMemo(() => {
return { batchNode: BatchNode, flowNode: FlowNode };
}, []);
/** 内部维护的选择的节点Id */
const [inSideNodeId, setInSideNodeId] = useState<string>("");
/** 获取是否有输入节点或者是否有输出节点 */
const nodesInputAndOutputStatus = useCallback(
(id: string) => {
/** 所有的连线 */
const lineArr: IEdge[] = [];
tasks?.length &&
tasks.forEach((item) => {
lineArr.push(...item.edges);
});
/** 所有的输入节点ID */
const isInput = lineArr?.some((item) => item.target === id);
/** 所有的输出节点ID */
const isOutput = lineArr?.some((item) => item.source === id);
return {
isInput,
isOutput,
};
},
[tasks]
);
/** 获取是否有输入节点或者是否有输出节点 */
const nodesInputAndOutputStatus = useCallback(
(id: string) => {
/** 所有的连线 */
const lineArr: IEdge[] = [];
tasks?.length &&
tasks.forEach((item) => {
lineArr.push(...item.edges);
});
/** 所有的输入节点ID */
const isInput = lineArr?.some((item) => item.target === id);
/** 所有的输出节点ID */
const isOutput = lineArr?.some((item) => item.source === id);
return {
isInput,
isOutput,
};
},
[tasks]
);
/** 获取是否有流节点 */
const isFlowNode = useCallback(
(id: string) => {
return (
tasks?.length &&
tasks?.some((item) => {
return item.parentNode === id;
})
);
},
[tasks]
);
/** 获取是否有流节点 */
const isFlowNode = useCallback(
(id: string) => {
return (
tasks?.length &&
tasks?.some((item) => {
return item.parentNode === id;
})
);
},
[tasks]
);
/** 通过子flow节点计算batch节点的样式 */
const getBatchStyle = useCallback(
(value: ITask) => {
const positionXArr: number[] = [];
const positionYArr: number[] = [];
tasks?.length &&
tasks?.forEach((item) => {
if (item.parentNode === value.id) {
positionXArr.push(item.position?.x || 0);
positionYArr.push(item.position?.y || 0);
}
});
positionXArr.sort((a, b) => {
return a - b;
});
positionYArr.sort((a, b) => {
return a - b;
});
let width = 176,
height = 22;
if (positionXArr?.length) {
const val = positionXArr[positionXArr.length - 1] + 150;
width = val > 176 ? val : width;
}
if (positionYArr?.length) {
const val = positionYArr[positionYArr.length - 1];
height = val > 22 ? val : height;
}
return {
width,
height,
};
},
[tasks]
);
/** 通过子flow节点计算batch节点的样式 */
const getBatchStyle = useCallback(
(value: ITask) => {
const positionXArr: number[] = [];
const positionYArr: number[] = [];
tasks?.length &&
tasks?.forEach((item) => {
if (item.parentNode === value.id) {
positionXArr.push(item.position?.x || 0);
positionYArr.push(item.position?.y || 0);
}
});
positionXArr.sort((a, b) => {
return a - b;
});
positionYArr.sort((a, b) => {
return a - b;
});
let width = 176,
height = 22;
if (positionXArr?.length) {
const val = positionXArr[positionXArr.length - 1] + 150;
width = val > 176 ? val : width;
}
if (positionYArr?.length) {
const val = positionYArr[positionYArr.length - 1];
height = val > 22 ? val : height;
}
return {
width,
height,
};
},
[tasks]
);
/** 生成初始化node节点 */
const initialNodes = useMemo(() => {
const val: any = [];
tasks?.length &&
tasks.forEach((item) => {
val.push({
id: item.id,
type: item.type === "BATCH" ? "batchNode" : "flowNode",
data: {
label: item.title || "",
/** 生成初始化node节点 */
const initialNodes = useMemo(() => {
const val: any = [];
tasks?.length &&
tasks.forEach((item) => {
val.push({
id: item.id,
type: item.type === "BATCH" ? "batchNode" : "flowNode",
data: {
label: item.title || "",
...(item.type === "BATCH"
? {
/** 是否有流节点 */
isFlowNode: isFlowNode(item.id),
/** 选中状态 */
selectedStatus: selectedNodeId === item.id,
}
: {}),
isCheck: item.isCheck,
executionStatus: item.executionStatus,
/** 输入输出圆点状态 */
dotStatus: nodesInputAndOutputStatus(item.id),
/** 样式 */
style: {
...getBatchStyle(item),
padding: isFlowNode(item.id) ? "20px" : "12px 20px",
},
},
position: { x: Number(item.position.x), y: Number(item.position.y) },
...(item.type === "BATCH" ? { style: { zIndex: -1 } } : {}),
...(item.parentNode ? { parentNode: item.parentNode } : {}),
...(item.type === "BATCH" ? { extent: "parent" } : {}),
});
});
return val;
}, [
tasks,
isFlowNode,
selectedNodeId,
nodesInputAndOutputStatus,
getBatchStyle,
]);
...(item.type === "BATCH"
? {
/** 是否有流节点 */
isFlowNode: isFlowNode(item.id),
/** 选中状态 */
selectedStatus: selectedNodeId
? selectedNodeId === item.id
: inSideNodeId === item.id,
}
: {}),
isCheck: item.isCheck,
executionStatus: item.executionStatus,
/** 输入输出圆点状态 */
dotStatus: nodesInputAndOutputStatus(item.id),
/** 样式 */
style: {
...getBatchStyle(item),
padding: isFlowNode(item.id) ? "20px" : "12px 20px",
},
},
position: { x: Number(item.position.x), y: Number(item.position.y) },
...(item.type === "BATCH" ? { style: { zIndex: -1 } } : {}),
...(item.parentNode ? { parentNode: item.parentNode } : {}),
...(item.type === "BATCH" ? { extent: "parent" } : {}),
});
});
return val;
}, [
tasks,
isFlowNode,
selectedNodeId,
inSideNodeId,
nodesInputAndOutputStatus,
getBatchStyle,
]);
/** 生成初始化的连线节点 */
const initialEdges = useMemo(() => {
const val: ILine[] = [];
tasks?.length &&
tasks.forEach((item) => {
item.edges.forEach((every) => {
const newLine = {
...every,
batchId: item.parentNode ? item.parentNode : item.id,
};
val.push(newLine);
}, []);
});
return val.map((item: ILine) => {
return {
id: item.id,
source: item.source,
target: item.target,
type: "smoothstep",
...(item?.batchId === selectedNodeId
? { style: { stroke: "#1370FF" }, animated: true }
: {}),
labelStyle: { fill: "#8A9099" },
labelBgStyle: { fill: "#F7F8FA " },
label: item.label ? `(${item.label})` : "",
};
});
}, [selectedNodeId, tasks]);
/** 生成初始化的连线节点 */
const initialEdges = useMemo(() => {
const val: ILine[] = [];
tasks?.length &&
tasks.forEach((item) => {
item.edges.forEach((every) => {
const newLine = {
...every,
batchId: item.parentNode ? item.parentNode : item.id,
};
val.push(newLine);
}, []);
});
return val.map((item: ILine) => {
const newSelectId = selectedNodeId ? selectedNodeId : inSideNodeId;
return {
id: item.id,
source: item.source,
target: item.target,
type: "smoothstep",
...(item?.batchId === newSelectId
? { style: { stroke: "#1370FF" }, animated: true }
: {}),
labelStyle: { fill: "#8A9099" },
labelBgStyle: { fill: "#F7F8FA " },
label: item.label ? `(${item.label})` : "",
};
});
}, [inSideNodeId, selectedNodeId, tasks]);
/** flowNode点击事件 */
const onNodeClick = (e: any, node: Node) => {
tasks?.forEach((item) => {
if (item.id === node.id) {
if (item.parentNode) {
setSelectedNodeId && setSelectedNodeId(item.parentNode);
onBatchClick && onBatchClick(item.parentNode);
document.getElementById(`point${item.parentNode}`)?.scrollIntoView(true)
} else {
setSelectedNodeId && setSelectedNodeId(node.id);
onBatchClick && onBatchClick(node.id || "");
document.getElementById(`point${node.id}`)?.scrollIntoView(true)
}
}
});
};
/** flowNode点击事件 */
const onNodeClick = (e: any, node: Node) => {
tasks?.forEach((item) => {
if (item.id === node.id) {
if (item.parentNode) {
setSelectedNodeId
? setSelectedNodeId(item.parentNode)
: setInSideNodeId(item.parentNode);
onBatchClick && onBatchClick(item.parentNode);
document
.getElementById(`point${item.parentNode}`)
?.scrollIntoView(true);
} else {
setSelectedNodeId
? setSelectedNodeId(node.id)
: setInSideNodeId(node.id);
onBatchClick && onBatchClick(node.id || "");
document.getElementById(`point${node.id}`)?.scrollIntoView(true);
}
}
});
};
const handlePaneClick = () => {
setSelectedNodeId && setSelectedNodeId('');
onBatchClick && onBatchClick('');
}
const handlePaneClick = () => {
setSelectedNodeId ? setSelectedNodeId("") : setInSideNodeId("");
onBatchClick && onBatchClick("");
};
/** node节点 */
const [nodes, setNodes] = useNodesState(initialNodes);
/** 连线数组 */
const [edges, setEdges] = useEdgesState(initialEdges);
/** node节点 */
const [nodes, setNodes] = useNodesState(initialNodes);
/** 连线数组 */
const [edges, setEdges] = useEdgesState(initialEdges);
useEffect(() => {
setEdges(initialEdges);
}, [initialEdges, setEdges]);
useEffect(() => {
setEdges(initialEdges);
}, [initialEdges, setEdges]);
useEffect(() => {
setNodes(initialNodes);
}, [initialNodes, setNodes]);
useEffect(() => {
setNodes(initialNodes);
}, [initialNodes, setNodes]);
return (
<ReactFlow
nodes={nodes}
edges={edges}
fitView
proOptions={{ hideAttribution: true, account: "" }}
nodeTypes={nodeTypes}
onPaneClick={handlePaneClick}
onNodeClick={onNodeClick}
{...props}
>
<Controls />
<Background color="#aaa" gap={16} />
</ReactFlow>
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
fitView
proOptions={{ hideAttribution: true, account: "" }}
nodeTypes={nodeTypes}
onPaneClick={handlePaneClick}
onNodeClick={onNodeClick}
{...props}
>
<Controls />
<Background color="#aaa" gap={16} />
</ReactFlow>
);
};
export default Flow;
.operatorItemBox {
background-color: #fff;
border-radius: 4px;
cursor: grab;
padding: 16px 0;
border-bottom: 1px solid #f0f2f5;
}
.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;
}
.footerBx {
display: flex;
align-items: center;
}
import { IOperatorItemProps } from "./interface";
import { OutlinedInput } from "@mui/material";
import SearchIcon from "@mui/icons-material/Search";
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 16:27:16
* @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;
return (
<div className={styles.operatorItemBox}>
<h2 className={styles.operatorItemTitle}>说什么呢啊</h2>
<div className={styles.operatorItemText}>
STU utility
是一个R-packa标处理目标处理,目标处理目标处理标处理目标处理后期委屈好委屈农,博啊发布丢我被欺安度切换阿斯顿几切换,i的亲戚我好奇你eqeqeweqeqeeqeqeqeqeq。
</div>
<div className={styles.footerBx}>
<span
className={styles.labelBox}
style={{
background: true ? "#EBF3FF" : "#E3FAEC",
color: true ? "#1370FF" : "#02AB83",
}}
>
公共平台
</span>
<OutlinedInput
onChange={(e: any) => {
console.log(e.target.value);
}}
// value={templateName}
placeholder="输入关键词搜索"
size="small"
sx={{ flex: 1, height: 32 }}
endAdornment={<SearchIcon style={{ color: "#8A9099" }} />}
/>
</div>
</div>
);
};
const OperatorList = () => {
const arr = [222, 3333, 339];
return (
<>
{arr.map((item) => {
return <OperatorItem key={item} info={item} />;
})}
</>
);
};
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
......@@ -32,10 +32,10 @@
.swFormBox {
background-color: #fff;
border-right: 1xp solid rgba(235, 237, 240, 1);
width: 608px;
width: 360px;
overflow-y: scroll;
box-sizing: border-box;
padding: 36px;
padding: 24px;
}
.swFlowBox {
flex: 1;
......
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-21 20:03:56
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-07-05 16:31:28
* @LastEditTime: 2022-07-06 15:21:55
* @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -14,6 +14,7 @@ import { useLocation, useNavigate } from "react-router-dom";
import MyPopconfirm from "@/components/mui/MyPopconfirm";
import ButtonComponent from "@/components/mui/Button";
import { ITemplateConfig } from "../Project/ProjectSubmitWork/interface";
import OperatorList from "./components/OperatorList";
import styles from './index.module.css'
......@@ -64,7 +65,7 @@ const WorkFlowEdit = () => {
</div>
<div className={styles.swContent}>
<div className={styles.swFormBox}>
左侧
<OperatorList/>
</div>
<div className={styles.swFlowBox}>
右侧
......
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