Commit 9c1ebdf0 authored by chenshouchao's avatar chenshouchao

feat: 完成表单项渲染,完成表单项和patch节点校验

parent 7fd917a1
This diff is collapsed.
......@@ -2,12 +2,17 @@ import * as React from "react";
import FormGroup from "@mui/material/FormGroup";
import FormControlLabel from "@mui/material/FormControlLabel";
import Checkbox from "@mui/material/Checkbox";
import FormControl from "@mui/material/FormControl";
import FormHelperText from '@mui/material/FormHelperText';
import _ from "lodash";
type IMyCheckBoxProps = {
value: Array<any>;
options: Array<ICheckBoxOption>;
onChange: any; // 直接返回选中项的数组
variant?: "standard" | "outlined" | "filled";
error?: boolean;
helperText?: string;
};
type ICheckBoxOption = {
......@@ -32,7 +37,7 @@ export const optionsTransform = (
};
export default function MyCheckBox(props: IMyCheckBoxProps) {
const { value, options, onChange } = props;
const { value, options, onChange, error = false, helperText, variant } = props;
const getCheckedStatus = (
checkBoxItemValue: any,
......@@ -56,6 +61,7 @@ export default function MyCheckBox(props: IMyCheckBoxProps) {
};
return (
<FormControl fullWidth variant={variant} error={error}>
<FormGroup row>
{options.map((option) => {
return (
......@@ -74,5 +80,7 @@ export default function MyCheckBox(props: IMyCheckBoxProps) {
);
})}
</FormGroup>
{helperText && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
);
}
......@@ -12,6 +12,8 @@ type MyInputProps = {
placeholder?: string;
fullWidth?: boolean; // 宽度是否和容器一致
InputProps?: any; // input加前后icon可以用这个
error?: boolean;
helperText?: string;
};
const MyInput = (props: MyInputProps) => {
......@@ -27,10 +29,14 @@ const MyInput = (props: MyInputProps) => {
placeholder = "请输入",
fullWidth = true,
InputProps,
error = false,
helperText,
} = props;
return (
<TextField
error={error}
helperText={helperText}
value={value}
sx={{ ...inputSx }}
id={id}
......
......@@ -2,11 +2,16 @@ import * as React from "react";
import Radio from "@mui/material/Radio";
import RadioGroup from "@mui/material/RadioGroup";
import FormControlLabel from "@mui/material/FormControlLabel";
import FormControl from "@mui/material/FormControl";
import FormHelperText from '@mui/material/FormHelperText';
type IMyRadioProps = {
value: any;
options: Array<ICheckBoxOption>;
onChange: any;
variant?: "standard" | "outlined" | "filled";
error?: boolean;
helperText?: string;
};
type ICheckBoxOption = {
......@@ -32,26 +37,29 @@ export const optionsTransform = (
};
export default function MyRadio(props: IMyRadioProps) {
const { value, options, onChange } = props;
const { value, options, onChange , error = false, helperText, variant} = props;
return (
<RadioGroup
row
aria-labelledby="demo-row-radio-buttons-group-label"
name="row-radio-buttons-group"
value={value}
onChange={onChange}
>
{options.map((option) => {
return (
<FormControlLabel
key={option.value}
value={option.value}
control={<Radio />}
label={option.label}
/>
);
})}
</RadioGroup>
<FormControl fullWidth variant={variant} error={error}>
<RadioGroup
row
aria-labelledby="demo-row-radio-buttons-group-label"
name="row-radio-buttons-group"
value={value}
onChange={onChange}
>
{options.map((option) => {
return (
<FormControlLabel
key={option.value}
value={option.value}
control={<Radio />}
label={option.label}
/>
);
})}
</RadioGroup>
{helperText && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
);
}
......@@ -26,12 +26,18 @@
box-sizing: border-box;
position: relative;
}
.backgroundTitleTextIcon{
visibility: hidden;
}
.backgroundTitleTextIconShow{
visibility: visible;
}
.backgroundTitleText {
font-size: 16px;
font-weight: 600;
line-height: 24px;
color: rgba(30, 38, 51, 1);
margin-left: 28px;
margin-left: 12px;
}
.formItems {
padding: 20px 44px 40px 44px;
......@@ -70,12 +76,15 @@
line-height: 22px;
margin-bottom: 12px;
}
.parameterDataType {
color: rgba(138, 144, 153, 1);
margin-left: 16px;
.parameterContent{
position: relative;
}
.parameterDesc {
position: absolute;
bottom: 12px;
top: 12px;
right: -22px;
}
.parameterDataType {
color: rgba(138, 144, 153, 1);
margin-left: 16px;
}
......@@ -10,8 +10,10 @@ import MySelect, { optionsTransform } from "../components/MySelect";
import MyCheckBox from "@/components/mui/MyCheckBox";
import MyRadio from "@/components/mui/MyRadio";
import _ from "lodash";
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";
type ConfigFormProps = {
templateConfigInfo?: ITemplateConfig;
......@@ -49,15 +51,40 @@ const ConfigForm = (props: ConfigFormProps) => {
const result: IRenderTasks = [];
templateConfigInfo?.tasks.forEach((task, taskIndex) => {
if (task.type === "BATCH") {
result.push({ ...task, flows: [] });
result.push({ ...task, flows: [], isCheck: true });
} else {
result[result.length - 1]?.flows.push({ ...task });
}
});
result.forEach((task) => {
let isCheck = true
if (task.parameters.length > 0) {
task.parameters.forEach((parameter)=>{
const { error } = getCheckResult(parameter, parameter.value)
if (error) {
isCheck = false
return
}
})
}
if(task.flows.length>0) {
task.flows.forEach((flow) => {
if (flow.parameters.length > 0) {
flow.parameters.forEach((parameter)=>{
const { error } = getCheckResult(parameter, parameter.value)
if (error) {
isCheck = false
return
}
})
}
})
}
task.isCheck = isCheck
})
return result;
}, [templateConfigInfo]);
console.log(renderTasks);
// const options = [
// {
......@@ -191,8 +218,12 @@ const ConfigForm = (props: ConfigFormProps) => {
[styles.backgroundTitlePass]: true,
})}
>
{/* <img src="" alt="" /> */}
<span>下面的子项校验是否通过</span>
<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}>
......@@ -208,8 +239,55 @@ const ConfigForm = (props: ConfigFormProps) => {
{parameter.dataType}
</span>
</div>
<div className={styles.parameterContent}>
{parameter.domType.toLowerCase() === "input" && (
<MyInput
<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(
......@@ -218,19 +296,40 @@ const ConfigForm = (props: ConfigFormProps) => {
parameter.name || ""
)
}
placeholder="请输入"
></MyInput>
)}
{/* {parameter.domType.toLowerCase()} */}
{parameter.description && (
<Tooltip title={parameter.description} placement="top">
<img
className={styles.parameterDesc}
src={questionMark}
alt=""
/>
</Tooltip>
)}
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>
);
......
......@@ -3,6 +3,7 @@ import Box from "@mui/material/Box";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import FormHelperText from '@mui/material/FormHelperText';
import Select, { SelectProps } from "@mui/material/Select";
export interface IOption {
......@@ -39,6 +40,8 @@ interface IProps
isTitle?: boolean;
size?: "small" | "medium";
multiple?: boolean; // 多选
error?: boolean;
helperText?: string;
}
export default function MySelect(props: IProps) {
const {
......@@ -50,11 +53,13 @@ export default function MySelect(props: IProps) {
variant,
size = "small",
multiple = false,
error = false,
helperText,
} = props;
return (
<Box sx={{ minWidth: 120 }}>
<FormControl fullWidth variant={variant}>
<FormControl fullWidth variant={variant} error={error}>
{isTitle ? (
<InputLabel id="demo-simple-select-label">
{title || "请选择"}
......@@ -84,6 +89,7 @@ export default function MySelect(props: IProps) {
})
: null}
</Select>
{helperText && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
</Box>
);
......
......@@ -18,12 +18,13 @@ import _ from "lodash";
import useMyRequest from "@/hooks/useMyRequest";
import { fetchTemplateConfigInfo } 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 { templateConfigJson } from "./mock";
const ProjectSubmitWork = () => {
const [templateConfigInfo, setTemplateConfigInfo] =
useState<ITemplateConfig>();
useState<ITemplateConfig>(templateConfigJson as ITemplateConfig);
const location: any = useLocation();
const navigate = useNavigate();
......@@ -31,7 +32,11 @@ const ProjectSubmitWork = () => {
const { run } = useMyRequest(fetchTemplateConfigInfo, {
onSuccess: (res: IResponse<ITemplateConfig>) => {
setTemplateConfigInfo(res.data);
// setTemplateConfigInfo(templateConfigJson as ITemplateConfig);
},
// onError: () => {
// setTemplateConfigInfo(templateConfigJson as ITemplateConfig);
// }
});
useEffect(() => {
......@@ -47,6 +52,29 @@ const ProjectSubmitWork = () => {
tack.parameters.forEach((parameter) => {
if (parameter.name === parameterName) {
parameter.value = value;
const checkResult = getCheckResult(parameter,value)
parameter.error = checkResult.error
parameter.helperText = checkResult.helperText
// 表单校验
// if (parameter.required && !value) {
// parameter.error = true
// parameter.helperText = '该选项是必填项'
// } else if (parameter.validators.length > 0) {
// parameter.validators.forEach((validator)=>{
// let error = false
// let helperText = ''
// const reg = new RegExp(validator.regex)
// if (!reg.test(value)) {
// error = true
// helperText = validator.message
// }
// parameter.error = error
// parameter.helperText = helperText
// })
// } else {
// parameter.error = false
// parameter.helperText = ''
// }
} else {
return;
}
......
......@@ -14,7 +14,7 @@ export interface IParameter {
required: boolean;
domType: IDomType;
dataType?: string;
value: string;
value: any;
description: string;
language: string;
languageVersion: string;
......@@ -24,6 +24,8 @@ export interface IParameter {
tasks: ITask[];
validators: Array<IValidator>;
choices: Array<IChoice>;
error? : boolean;
helperText? : string;
}
export interface ITask {
......@@ -99,4 +101,5 @@ export type IRenderTask = {
parameters: Array<IParameter>;
edges: Array<IEdge>;
flows: ITask[];
isCheck: boolean; // 里面的子项表单校验是否全部通过
};
......@@ -17,125 +17,166 @@ export const templateConfigJson = {
x: 0,
y: 0,
},
type: "batch",
type: "BATCH",
parameters: [
{
hidden: false,
name: "in",
required: true,
domType: "input",
// domType: "input",
// domType: "select",
// domType: "multipleselect",
// domType: "radio",
domType: "checkbox",
dataType: "stringParameter",
value: "",
// value: "",
value: [],
description: "输入一段字符串",
validators: "",
choices: [],
},
{
hidden: true,
name: "out",
required: true,
domType: "File",
dataType: "stringParameter",
value: "/home/cloudam/task_a.out",
description: "task_A的输出",
validators: "",
choices: [],
validators: [
{
regex: '^[0-9]*$',
message: '只能输入数字'
}
],
choices: [
{
key: '1',
value: 'a'
},
{
key: '2',
value: '2'
},
{
key: '3',
value: '3'
}
],
language: '1',
languageVersion: '1',
tags:['1'],
source:'1',
productId:'1',
tasks: [{
id: 'id',
title: 'title',
description: 'description',
position: {
x: 100,
y: 200
},
type: 'BATCH',
parentNode: '1',
parameters: [],
edges: []
}]
},
// {
// hidden: true,
// name: "out",
// required: true,
// domType: "File",
// dataType: "stringParameter",
// value: "/home/cloudam/task_a.out",
// description: "task_A的输出",
// validators: "",
// choices: [],
// },
],
edges: [],
},
{
id: "流式算子ID1",
title: "task_B",
description: "这是task_B",
position: {
x: 100,
y: 50,
},
type: "batch",
parameters: [
{
hidden: true,
name: "in",
required: true,
domType: "pathSelect",
// pathSelect-路径选择器 datasetSelect-数据集选择器 fileSelect-文件选择器 input-输入框 select-单选下拉框 multipleSelect-多选下拉框 radio-单选组 checkbox-多选组
dataType: "stringParameter",
value: "task_A.out",
description: "这是task_B的输入",
validators: "",
choices: [],
},
{
hidden: false,
name: "sb",
required: false,
domType: "input",
// pathSelect-路径选择器 datasetSelect-数据集选择器 fileSelect-文件选择器 input-输入框 select-单选下拉框 multipleSelect-多选下拉框 radio-单选组 checkbox-多选组
dataType: "stringParameter",
value: "",
description: "这是task_B的输入",
validators: [],
choices: [],
},
],
edges: [
{
id: "10001",
source: "流式算子ID1",
sourceHandle: "流式算子1出口A",
target: "流式算子ID2",
targetHandle: "流式算子2入口A",
lable: "",
},
],
},
{
id: "流式算子ID2",
title: "task_C",
description: "这是task_C",
position: {
x: 100,
y: 100,
},
type: "batch",
parameters: [
{
hidden: true,
name: "in",
required: true,
domType: "pathSelect",
// pathSelect-路径选择器 datasetSelect-数据集选择器 fileSelect-文件选择器 input-输入框 select-单选下拉框 multipleSelect-多选下拉框 radio-单选组 checkbox-多选组
dataType: "stringParameter",
value: "task_A.out",
description: "这是task_C的输入",
validators: "",
choices: [],
},
{
hidden: false,
name: "sc",
required: false,
domType: "input",
// pathSelect-路径选择器 datasetSelect-数据集选择器 fileSelect-文件选择器 input-输入框 select-单选下拉框 multipleSelect-多选下拉框 radio-单选组 checkbox-多选组
dataType: "stringParameter",
value: "",
description: "这是task_C的输入",
validators: [],
choices: [],
},
],
edges: [
{
id: "10002",
source: "流式算子ID2",
sourceHandle: "流式算子1出口A",
target: "流式算子ID2",
targetHandle: "流式算子2入口A",
lable: "",
},
],
},
// {
// id: "流式算子ID1",
// title: "task_B",
// description: "这是task_B",
// position: {
// x: 100,
// y: 50,
// },
// type: "batch",
// parameters: [
// {
// hidden: true,
// name: "in",
// required: true,
// domType: "pathSelect",
// // pathSelect-路径选择器 datasetSelect-数据集选择器 fileSelect-文件选择器 input-输入框 select-单选下拉框 multipleSelect-多选下拉框 radio-单选组 checkbox-多选组
// dataType: "stringParameter",
// value: "task_A.out",
// description: "这是task_B的输入",
// validators: "",
// choices: [],
// },
// {
// hidden: false,
// name: "sb",
// required: false,
// domType: "input",
// // pathSelect-路径选择器 datasetSelect-数据集选择器 fileSelect-文件选择器 input-输入框 select-单选下拉框 multipleSelect-多选下拉框 radio-单选组 checkbox-多选组
// dataType: "stringParameter",
// value: "",
// description: "这是task_B的输入",
// validators: [],
// choices: [],
// },
// ],
// edges: [
// {
// id: "10001",
// source: "流式算子ID1",
// sourceHandle: "流式算子1出口A",
// target: "流式算子ID2",
// targetHandle: "流式算子2入口A",
// lable: "",
// },
// ],
// },
// {
// id: "流式算子ID2",
// title: "task_C",
// description: "这是task_C",
// position: {
// x: 100,
// y: 100,
// },
// type: "batch",
// parameters: [
// {
// hidden: true,
// name: "in",
// required: true,
// domType: "pathSelect",
// // pathSelect-路径选择器 datasetSelect-数据集选择器 fileSelect-文件选择器 input-输入框 select-单选下拉框 multipleSelect-多选下拉框 radio-单选组 checkbox-多选组
// dataType: "stringParameter",
// value: "task_A.out",
// description: "这是task_C的输入",
// validators: "",
// choices: [],
// },
// {
// hidden: false,
// name: "sc",
// required: false,
// domType: "input",
// // pathSelect-路径选择器 datasetSelect-数据集选择器 fileSelect-文件选择器 input-输入框 select-单选下拉框 multipleSelect-多选下拉框 radio-单选组 checkbox-多选组
// dataType: "stringParameter",
// value: "",
// description: "这是task_C的输入",
// validators: [],
// choices: [],
// },
// ],
// edges: [
// {
// id: "10002",
// source: "流式算子ID2",
// sourceHandle: "流式算子1出口A",
// target: "流式算子ID2",
// targetHandle: "流式算子2入口A",
// lable: "",
// },
// ],
// },
],
};
// {
......
import { IParameter } from "./interface"
export const getCheckResult = (parameter: IParameter, value: string): {
error: boolean,
helperText: string
} => {
let error = false
let helperText = ''
// 表单校验
if (parameter.required) {
if (Array.isArray(value)) {
if (value.length === 0) {
error = true
helperText = '该选项是必填项'
}
} else if (value === '' || value === null || value === undefined) {
error = true
helperText = '该选项是必填项'
}
}
if (parameter.validators.length > 0) {
parameter.validators.forEach((validator)=>{
const reg = new RegExp(validator.regex)
if (!reg.test(value)) {
error = true
helperText = validator.message
}
})
}
return {
error,
helperText
}
}
\ No newline at end of file
This diff is collapsed.
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