Commit 2a7b6d6a authored by chenshouchao's avatar chenshouchao

feat: 提交任务接口联调

parent fa9375be
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -34,6 +34,7 @@ const RESTAPI = {
API_WORKBENCH_WORKFLOWJOB_LIST: `${BACKEND_API_URI_PREFIX}/cpp/workbench/project/workflowjob`, //查询工作流任务
API_WORKBENCH_DEL_WORKFLOWJOB: `${BACKEND_API_URI_PREFIX}/cpp/workflow/job/`, //删除工作流任务
API_WORKBENCH_CANCEL_WORKFLOWJOB: `${BACKEND_API_URI_PREFIX}/cpp/workflow/cancel`, //取消工作流
API_SUBMIT_WORKFLOW: `${BACKEND_API_URI_PREFIX}/cpp/workflow/submit`, //提交工作流
};
export default RESTAPI;
......@@ -202,9 +202,8 @@ const getDataFileDelPackage = (params: getDataFileDelPackageParams) => {
});
};
// 点击使用模版,获取模版数据
const fetchTemplateConfigInfo = (params: {id: string}) => {
const fetchTemplateConfigInfo = (params: { id: string }) => {
return request({
url: `${Api.API_FETCH_TEMPLATE_INFO}/${params.id}`,
method: "get",
......@@ -212,14 +211,29 @@ const fetchTemplateConfigInfo = (params: {id: string}) => {
};
// 点击工作列表,查看工作流详情
const fetchWorkFlowJob = (params: {id: string}) => {
const fetchWorkFlowJob = (params: { id: string }) => {
return request({
url: `${Api.API_WORK_FLOW_JOB}/${params.id}`,
method: "get",
});
};
type submitWorkFlowParams = {
name: string;
projectId: string;
specId: string;
outputPath: string;
promotedParameters: any;
};
// 提交工作流
const submitWorkFlow = (params: submitWorkFlowParams) => {
return request({
url: Api.API_SUBMIT_WORKFLOW,
method: "post",
data: params,
});
};
export {
current,
......@@ -238,5 +252,6 @@ export {
getDataFileDel,
getDataFileDelPackage,
fetchTemplateConfigInfo,
fetchWorkFlowJob
fetchWorkFlowJob,
submitWorkFlow,
};
......@@ -12,7 +12,7 @@ type MyInputProps = {
placeholder?: string;
fullWidth?: boolean; // 宽度是否和容器一致
InputProps?: any; // input加前后icon可以用这个
error?: boolean;
error?: boolean;
helperText?: string;
};
......
......@@ -26,10 +26,10 @@
box-sizing: border-box;
position: relative;
}
.backgroundTitleTextIcon{
.backgroundTitleTextIcon {
visibility: hidden;
}
.backgroundTitleTextIconShow{
.backgroundTitleTextIconShow {
visibility: visible;
}
.backgroundTitleText {
......@@ -65,6 +65,17 @@
.taskConfigBox {
padding: 24px 44px 40px 44px;
}
.flowTitle {
/* line-height: 22px; */
line-height: 16px;
/* margin-bottom: 24px; */
margin: 3px 0 27px;
color: rgba(30, 38, 51, 1);
font-size: 14px;
font-weight: 600;
border-left: 3px solid rgba(19, 112, 255, 1);
padding-left: 3px;
}
.parameter {
margin-bottom: 20px;
position: relative;
......@@ -76,7 +87,7 @@
line-height: 22px;
margin-bottom: 12px;
}
.parameterContent{
.parameterContent {
position: relative;
}
.parameterDesc {
......
......@@ -14,11 +14,12 @@ import { getCheckResult } from "../util";
import fileSelectIcon from "@/assets/project/fileSelect.svg";
import questionMark from "@/assets/project/questionMark.svg";
import jobSueIcon from "@/assets/project/jobSue.svg";
import { IParameter } from "../interface";
type ConfigFormProps = {
templateConfigInfo?: ITemplateConfig;
setParameter: any;
onRef?: React.Ref<any>
onRef?: React.Ref<any>;
};
const ConfigForm = (props: ConfigFormProps) => {
......@@ -30,20 +31,20 @@ const ConfigForm = (props: ConfigFormProps) => {
); // 任务名称
const [nameHelp, setNameHelp] = useState({
error: false,
helperText: ''
})
helperText: "",
});
const [outputPath, setOutputPath] = useState<string>("ProjectData"); // 输出路径
const [outputPathHelp, setOutputPathHelp] = useState({
error: false,
helperText: ''
})
helperText: "",
});
const getNameAndPath = () => {
return {
name,
outputPath,
nameAndOutputPathCheck: !(checkName(name) || checkOutputPath(outputPath)) // 任务名称、输出路径是否通过校验
}
}
nameAndOutputPathCheck: !(checkName(name) || checkOutputPath(outputPath)), // 任务名称、输出路径是否通过校验
};
};
useImperativeHandle(props.onRef, () => {
return {
......@@ -51,60 +52,80 @@ const ConfigForm = (props: ConfigFormProps) => {
};
});
const [fileSelectOpen, setFileSelectOpen] = useState(false); // 选择输出路径的弹窗显示控制
const [fileSelectObject, setFileSelectObject] = useState({
taskId: "",
parameterName: "",
});
const onFileSelectConfirm = (path: string) => {
setFileSelectOpen(false);
setOutputPath(`ProjectData${path === "/" ? "" : path}`);
checkOutputPath(`ProjectData${path === "/" ? "" : path}`)
if (fileSelectObject.taskId) {
setParameter(
`ProjectData${path === "/" ? "" : path}`,
fileSelectObject.taskId,
fileSelectObject.parameterName
);
} else {
setOutputPath(`ProjectData${path === "/" ? "" : path}`);
checkOutputPath(`ProjectData${path === "/" ? "" : path}`);
}
};
const handleFileSelectOnClose = () => {
setFileSelectOpen(false);
};
const handleOpenFileSelect = () => {
const handleOpenFileSelect = (
taskId: string = "",
parameterName: string = ""
) => {
setFileSelectObject({
taskId,
parameterName,
});
setFileSelectOpen(true);
};
const handleNameChange = (e: any) => {
setName(e.target.value);
checkName(e.target.value)
checkName(e.target.value);
};
const checkName = (name: string = '')=>{
const reg = new RegExp(/^[a-zA-Z0-9\u4e00-\u9fa5-_]{3,30}$/)
const checkName = (name: string = "") => {
const reg = new RegExp(/^[a-zA-Z0-9\u4e00-\u9fa5-_]{3,30}$/);
if (reg.test(name)) {
setNameHelp({
error: false,
helperText: ''
})
return false
helperText: "",
});
return false;
} else {
setNameHelp({
error: true,
helperText: '请输入正确任务名称(3~30字符,可包含大小写字母、数字、中文、特殊符号“-”、“_”)'
})
return true
helperText:
"请输入正确任务名称(3~30字符,可包含大小写字母、数字、中文、特殊符号“-”、“_”)",
});
return true;
}
}
};
const checkOutputPath = (outputPath: string = '')=>{
const checkOutputPath = (outputPath: string = "") => {
if (outputPath) {
setOutputPathHelp({
error: false,
helperText: ''
})
return false
helperText: "",
});
return false;
} else {
setOutputPathHelp({
error: true,
helperText: '请选择输出路径'
})
return true
helperText: "请选择输出路径",
});
return true;
}
}
};
const renderTasks: IRenderTasks = useMemo(() => {
const result: IRenderTasks = [];
......@@ -116,31 +137,31 @@ const ConfigForm = (props: ConfigFormProps) => {
}
});
result.forEach((task) => {
let isCheck = true
let isCheck = true;
if (task.parameters.length > 0) {
task.parameters.forEach((parameter)=>{
const { error } = getCheckResult(parameter, parameter.value)
task.parameters.forEach((parameter) => {
const { error } = getCheckResult(parameter, parameter.value);
if (error) {
isCheck = false
return
isCheck = false;
return;
}
})
});
}
if(task.flows.length>0) {
if (task.flows.length > 0) {
task.flows.forEach((flow) => {
if (flow.parameters.length > 0) {
flow.parameters.forEach((parameter)=>{
const { error } = getCheckResult(parameter, parameter.value)
flow.parameters.forEach((parameter) => {
const { error } = getCheckResult(parameter, parameter.value);
if (error) {
isCheck = false
return
isCheck = false;
return;
}
})
});
}
})
});
}
task.isCheck = isCheck
})
task.isCheck = isCheck;
});
return result;
}, [templateConfigInfo]);
......@@ -152,6 +173,182 @@ const ConfigForm = (props: ConfigFormProps) => {
setParameter(e.target.value, taskId, parameterName);
};
const randerParameters = (parameters: Array<IParameter>, taskId: string) => {
return parameters
.filter((parameter) => parameter.hidden === false)
.map((parameter, parameterIndex) => {
return (
<div
className={styles.parameter}
key={parameter.id || "" + parameterIndex}
>
<div
className={classnames({
[styles.parameterTitle]: true,
[styles.required]: parameter.required,
})}
>
{parameter.name}
<span className={styles.parameterDataType}>
{parameter.dataType}
</span>
</div>
<div className={styles.parameterContent}>
{parameter.domType.toLowerCase() === "file" && (
<MyInput
value={parameter.value || ""}
InputProps={{
endAdornment: (
<img
onClick={() =>
handleOpenFileSelect(taskId, parameter.name)
}
src={fileSelectIcon}
alt=""
className={styles.fileSelectImg}
/>
),
}}
error={parameter.error || false}
helperText={parameter.helperText}
></MyInput>
)}
{parameter.domType.toLowerCase() === "pathselect" && (
<MyInput
value={parameter.value || ""}
InputProps={{
endAdornment: (
<img
onClick={() =>
handleOpenFileSelect(taskId, parameter.name)
}
src={fileSelectIcon}
alt=""
className={styles.fileSelectImg}
/>
),
}}
error={parameter.error || false}
helperText={parameter.helperText}
></MyInput>
)}
{parameter.domType.toLowerCase() === "datasetselect" && (
<MyInput
value={parameter.value || ""}
InputProps={{
endAdornment: (
<img
onClick={() =>
handleOpenFileSelect(taskId, parameter.name)
}
src={fileSelectIcon}
alt=""
className={styles.fileSelectImg}
/>
),
}}
error={parameter.error || false}
helperText={parameter.helperText}
></MyInput>
)}
{parameter.domType.toLowerCase() === "fileselect" && (
<MyInput
value={parameter.value || ""}
InputProps={{
endAdornment: (
<img
onClick={() =>
handleOpenFileSelect(taskId, parameter.name)
}
src={fileSelectIcon}
alt=""
className={styles.fileSelectImg}
/>
),
}}
error={parameter.error || false}
helperText={parameter.helperText}
></MyInput>
)}
{parameter.domType.toLowerCase() === "input" && (
<MyInput
value={parameter.value}
onChange={(e: any) =>
handleParameterChange(e, taskId, parameter.name || "")
}
placeholder="请输入"
error={parameter.error || false}
helperText={parameter.helperText}
></MyInput>
)}
{parameter.domType.toLowerCase() === "select" && (
<MySelect
value={parameter.value}
onChange={(e: any) =>
handleParameterChange(e, taskId, parameter.name || "")
}
error={parameter.error || false}
helperText={parameter.helperText}
options={optionsTransform(parameter.choices, "key")}
></MySelect>
)}
{parameter.domType.toLowerCase() === "multipleselect" && (
<MySelect
value={parameter.value}
onChange={(e: any) =>
handleParameterChange(e, taskId, parameter.name || "")
}
multiple={true}
error={parameter.error || false}
helperText={parameter.helperText}
options={optionsTransform(parameter.choices, "key")}
></MySelect>
)}
{parameter.domType.toLowerCase() === "radio" && (
<MyRadio
value={parameter.value}
onChange={(e: any) =>
handleParameterChange(e, taskId, parameter.name || "")
}
options={optionsTransform(parameter.choices, "key")}
error={parameter.error || false}
helperText={parameter.helperText}
></MyRadio>
)}
{parameter.domType.toLowerCase() === "checkbox" && (
<MyCheckBox
value={parameter.value}
onChange={(e: any) =>
handleParameterChange(
{
target: {
value: e,
},
},
taskId,
parameter.name || ""
)
}
options={optionsTransform(parameter.choices, "key")}
error={parameter.error || false}
helperText={parameter.helperText}
></MyCheckBox>
)}
{parameter.description && (
<Tooltip title={parameter.description} placement="top">
<img
className={styles.parameterDesc}
src={questionMark}
alt=""
/>
</Tooltip>
)}
</div>
</div>
);
});
};
return (
<div className={styles.formBox}>
<div className={styles.templateDescBox}>
......@@ -200,11 +397,11 @@ const ConfigForm = (props: ConfigFormProps) => {
</div>
<div className={styles.formItem}>
<MyInput
value={outputPath}
value={outputPath || ""}
InputProps={{
endAdornment: (
<img
onClick={handleOpenFileSelect}
onClick={() => handleOpenFileSelect()}
src={fileSelectIcon}
alt="选择输出路径"
className={styles.fileSelectImg}
......@@ -226,122 +423,23 @@ const ConfigForm = (props: ConfigFormProps) => {
[styles.backgroundTitlePass]: true,
})}
>
<img
className={classnames({
[styles.backgroundTitleTextIcon]: true,
[styles.backgroundTitleTextIconShow]: task.isCheck,
})}
src={jobSueIcon} alt="" />
<img
className={classnames({
[styles.backgroundTitleTextIcon]: true,
[styles.backgroundTitleTextIconShow]: task.isCheck,
})}
src={jobSueIcon}
alt=""
/>
<span className={styles.backgroundTitleText}>{task.title}</span>
</div>
<div className={styles.taskConfigBox}>
{task.parameters.filter(parameter => parameter.hidden === false).map((parameter, parameterIndex) => {
{randerParameters(task.parameters, task.id)}
{task.flows.map((flow) => {
return (
<div
className={styles.parameter}
key={parameter.id || "" + parameterIndex}
>
<div className={classnames({
[styles.parameterTitle]: true,
[styles.required]: parameter.required,
})}>
{parameter.name}
<span className={styles.parameterDataType}>
{parameter.dataType}
</span>
</div>
<div className={styles.parameterContent}>
{parameter.domType.toLowerCase() === "input" && (
<MyInput
value={parameter.value}
onChange={(e: any) =>
handleParameterChange(
e,
task.id,
parameter.name || ""
)
}
placeholder="请输入"
error={parameter.error || false}
helperText={parameter.helperText}
></MyInput>
)}
{parameter.domType.toLowerCase() === "select" && (
<MySelect
value={parameter.value}
onChange={(e: any) =>
handleParameterChange(
e,
task.id,
parameter.name || ""
)
}
error={parameter.error || false}
helperText={parameter.helperText}
options={optionsTransform(parameter.choices, "key")}
></MySelect>
)}
{parameter.domType.toLowerCase() === "multipleselect" && (
<MySelect
value={parameter.value}
onChange={(e: any) =>
handleParameterChange(
e,
task.id,
parameter.name || ""
)
}
multiple={true}
error={parameter.error || false}
helperText={parameter.helperText}
options={optionsTransform(parameter.choices, "key")}
></MySelect>
)}
{parameter.domType.toLowerCase() === "radio" && (
<MyRadio
value={parameter.value}
onChange={(e: any) =>
handleParameterChange(
e,
task.id,
parameter.name || ""
)
}
options={optionsTransform(parameter.choices, "key")}
error={parameter.error || false}
helperText={parameter.helperText}
></MyRadio>
)}
{parameter.domType.toLowerCase() === "checkbox" && (
<MyCheckBox
value={parameter.value}
onChange={(e: any) =>
handleParameterChange(
{
target: {
value: e
}
},
task.id,
parameter.name || ""
)
}
options={optionsTransform(parameter.choices, "key")}
error={parameter.error || false}
helperText={parameter.helperText}
></MyCheckBox>
)}
{parameter.description && (
<Tooltip title={parameter.description} placement="top">
<img
className={styles.parameterDesc}
src={questionMark}
alt=""
/>
</Tooltip>
)}
</div>
{/* question mark */}
<div className={styles.flowConfigBox} key={flow.id}>
<div className={styles.flowTitle}>{flow.title}</div>
{randerParameters(flow.parameters, flow.id)}
</div>
);
})}
......@@ -349,27 +447,11 @@ const ConfigForm = (props: ConfigFormProps) => {
</div>
);
})}
{/* <MySelect
value={selectValue}
onChange={handleSelectChange}
multiple={true}
options={optionsTransform(options, "key")}
></MySelect> */}
{/* <MyCheckBox
value={selectValue}
onChange={handleCheckBoxChange}
options={optionsTransform(options, "key")}
></MyCheckBox> */}
{/* <MyRadio
value={selectValue}
onChange={handleRadioChange}
options={optionsTransform(options, "key")}
></MyRadio> */}
{/* <FileSelect
<FileSelect
onClose={handleFileSelectOnClose}
open={fileSelectOpen}
onConfirm={onFileSelectConfirm}
/> */}
/>
</div>
);
};
......
......@@ -16,15 +16,19 @@ import IconButton from "@mui/material/IconButton";
import { ITemplateConfig } from "./interface";
import _ from "lodash";
import useMyRequest from "@/hooks/useMyRequest";
import { fetchTemplateConfigInfo } from "@/api/project_api";
import { fetchTemplateConfigInfo, submitWorkFlow } from "@/api/project_api";
import { useLocation, useNavigate } from "react-router-dom";
import { getCheckResult } from "./util";
import { IResponse } from "@/api/http";
import { templateConfigJson } from "./mock";
import { useMessage } from "@/components/MySnackbar";
import { toJS } from "mobx";
import { useStores } from "@/store";
const ProjectSubmitWork = () => {
const Message = useMessage();
const { currentProjectStore } = useStores();
const projectId = toJS(currentProjectStore.currentProjectInfo.id);
const [templateConfigInfo, setTemplateConfigInfo] =
useState<ITemplateConfig>();
const location: any = useLocation();
......@@ -42,6 +46,12 @@ const ProjectSubmitWork = () => {
// }
});
const { run: submitWorkFlowRun } = useMyRequest(submitWorkFlow, {
onSuccess: (res) => {
console.log(res);
},
});
useEffect(() => {
run({
id: location?.state?.id,
......@@ -52,6 +62,7 @@ const ProjectSubmitWork = () => {
const result: ITemplateConfig = _.cloneDeep(templateConfigInfo);
result.tasks.forEach((tack) => {
if (tack.id === taskId) {
let isCheck = true;
tack.parameters.forEach((parameter) => {
if (parameter.name === parameterName) {
parameter.value = value;
......@@ -61,6 +72,10 @@ const ProjectSubmitWork = () => {
} else {
return;
}
if (getCheckResult(parameter, value).error === true) {
isCheck = false;
}
tack.isCheck = isCheck;
});
} else {
return;
......@@ -90,6 +105,13 @@ const ProjectSubmitWork = () => {
setTemplateConfigInfo(result);
if (check) {
console.log("提交任务");
submitWorkFlowRun({
name,
outputPath,
projectId: projectId as string,
specId: templateConfigInfo?.id as string,
promotedParameters: {},
});
} else {
Message.error("请完善左侧表单再提交");
}
......
......@@ -6,7 +6,7 @@
* @FilePath: /bkunyun/src/views/Project/ProjectSubmitWork/interface.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
type IType = 'BATCH' | 'FLOW'
type IType = "BATCH" | "FLOW";
export interface IParameter {
hidden: boolean;
id?: string;
......@@ -24,8 +24,8 @@ export interface IParameter {
tasks: ITask[];
validators: Array<IValidator>;
choices: Array<IChoice>;
error? : boolean;
helperText? : string;
error?: boolean;
helperText?: string;
}
export interface ITask {
......@@ -40,9 +40,9 @@ export interface ITask {
parentNode?: string;
parameters: Array<IParameter>;
edges: Array<IEdge>;
isCheck?: boolean;
}
export interface ITemplateConfig {
title: string;
version: string;
......@@ -54,6 +54,7 @@ export interface ITemplateConfig {
source: string;
productId: string;
tasks: ITask[];
id: string;
}
export type IDomType =
......
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