Commit e3389589 authored by chenshouchao's avatar chenshouchao

feat: 参数设置表单校验

parent ed3d6226
......@@ -28,6 +28,7 @@ interface ITabList {
interface IProps {
tabList: ITabList[];
defaultValue?: string;
tabPanelSx?: any;
allowNullValue?: boolean; // 是否允许空值
}
......@@ -36,37 +37,46 @@ const theme = createTheme({
MuiTab: {
styleOverrides: {
root: {
paddingLeft: 0,
paddingRight: 0,
paddingTop: '8px',
paddingBottom: '8px',
minWidth: '20px',
marginRight: '32px',
color: '#8A9099',
paddingLeft: 0,
paddingRight: 0,
paddingTop: "8px",
paddingBottom: "8px",
minWidth: "20px",
marginRight: "32px",
color: "#8A9099",
selected: {
color: '#1976d2'
color: "#1976d2",
},
"&.Mui-disabled": {
color: '#C2C6CC',
color: "#C2C6CC",
},
},
},
},
// #C2C6CC
MuiTabs:{
MuiTabs: {
styleOverrides: {
indicator: {
backgroundColor: '#1370FF',
}
}
backgroundColor: "#1370FF",
},
},
},
},
});
const Tabs = (props: IProps) => {
const { tabList, defaultValue, allowNullValue = false } = props;
const {
tabList,
defaultValue,
allowNullValue = false,
tabPanelSx = { padding: "20px 0 0 0" },
} = props;
const [value, setValue] = useState(
defaultValue ? defaultValue : allowNullValue ? '' : tabList.filter((e) => !e.hide)[0].value
defaultValue
? defaultValue
: allowNullValue
? ""
: tabList.filter((e) => !e.hide)[0].value
);
const onChange = (val: string) => {
......@@ -94,42 +104,38 @@ const Tabs = (props: IProps) => {
return (
<ThemeProvider theme={theme}>
<TabContext value={value}>
<Box sx={{ borderBottom: 1, borderColor: "#F0F2F5" }}>
<TabList
onChange={(e: any, val: string) => {
onChange(val);
}}
>
{tabList
?.filter((item) => !item.hide)
.map((item, key) => {
return (
<Tab
key={key}
label={labelRender(item, key)}
value={item.value}
id={item.value}
disabled={item.disabled}
/>
);
})}
</TabList>
</Box>
{tabList
?.filter((item) => !item.hide)
.map((item) => {
return (
<TabPanel
sx={{ padding: "20px 0 0 0" }}
value={item.value}
key={item.value}
>
{item.component}
</TabPanel>
);
})}
</TabContext>
<TabContext value={value}>
<Box sx={{ borderBottom: 1, borderColor: "#F0F2F5" }}>
<TabList
onChange={(e: any, val: string) => {
onChange(val);
}}
>
{tabList
?.filter((item) => !item.hide)
.map((item, key) => {
return (
<Tab
key={key}
label={labelRender(item, key)}
value={item.value}
id={item.value}
disabled={item.disabled}
/>
);
})}
</TabList>
</Box>
{tabList
?.filter((item) => !item.hide)
.map((item) => {
return (
<TabPanel sx={tabPanelSx} value={item.value} key={item.value}>
{item.component}
</TabPanel>
);
})}
</TabContext>
</ThemeProvider>
);
};
......
......@@ -19,7 +19,7 @@ import fileSelectIcon from "@/assets/project/fileSelect.svg";
import MySwitch from "@/components/mui/MySwitch";
import Tabs from "@/components/mui/Tabs";
import classNames from "classnames";
import { Hidden } from "@mui/material";
import { getCustomTemplateParameterCheckResult } from "../../util";
type IParameterSettingProps = {
templateConfigInfo: ITask[];
......@@ -43,11 +43,11 @@ const templateConfigInfoMock = [
parameters: [
{
hidden: true,
id: "",
id: "1",
name: "smi_in",
required: true,
defaultValue: '',
domType: "select",
defaultValue: "",
domType: "input",
classType: "STRING",
classTypeName: "String",
value: "",
......@@ -69,10 +69,10 @@ const templateConfigInfoMock = [
},
{
hidden: true,
id: "",
id: "2",
name: "out",
required: true,
defaultValue: '',
defaultValue: "",
domType: "select",
classType: "STRING",
classTypeName: "String",
......@@ -95,10 +95,10 @@ const templateConfigInfoMock = [
},
{
hidden: true,
id: "999",
id: "3",
name: "basis999",
required: true,
defaultValue: '',
defaultValue: "",
domType: "select",
classType: "STRING",
classTypeName: "String",
......@@ -121,10 +121,10 @@ const templateConfigInfoMock = [
},
{
hidden: true,
id: "",
id: "4",
name: "basis",
required: true,
defaultValue: '',
defaultValue: "",
domType: "select",
classType: "STRING",
classTypeName: "String",
......@@ -147,10 +147,10 @@ const templateConfigInfoMock = [
},
{
hidden: true,
id: "",
id: "5",
name: "senior",
required: true,
defaultValue: '',
defaultValue: "",
domType: "select",
classType: "STRING",
classTypeName: "String",
......@@ -173,10 +173,10 @@ const templateConfigInfoMock = [
},
{
hidden: true,
id: "",
id: "6",
name: "hardware",
required: true,
defaultValue: '',
defaultValue: "",
domType: "select",
classType: "STRING",
classTypeName: "String",
......@@ -207,7 +207,9 @@ const taskId = "id";
const ParameterSetting = (props: IParameterSettingProps) => {
// const { templateConfigInfo, taskId } = props;
const [templateConfigInfo, setTemplateConfigInfo] = useState<ITask[]>(templateConfigInfoMock as ITask[])
const [templateConfigInfo, setTemplateConfigInfo] = useState<ITask[]>(
templateConfigInfoMock as ITask[]
);
const [descHeight, setDescHeight] = useState(0);
const [isShowAllDese, setIsShowAllDese] = useState(false);
......@@ -242,158 +244,161 @@ const ParameterSetting = (props: IParameterSettingProps) => {
}, [templateConfigInfo, taskId]);
// 设置parameter.hidden字段
const handleHiddenChange = useCallback((e: any, parameterId: string) => {
const result: ITask[] = _.cloneDeep(templateConfigInfo);
const taskIndex = result.findIndex((item) => {
return item.id === taskId
})
if (taskIndex !== -1) {
result[taskIndex].parameters.forEach((parameter) => {
if (parameter.id === parameterId) {
parameter.hidden = e.target.checked
}
})
}
setTemplateConfigInfo(result)
}, [templateConfigInfo, setTemplateConfigInfo])
const handleHiddenChange = useCallback(
(e: any, parameterId: string) => {
const result: ITask[] = _.cloneDeep(templateConfigInfo);
const taskIndex = result.findIndex((item) => {
return item.id === taskId;
});
if (taskIndex !== -1) {
result[taskIndex].parameters.forEach((parameter) => {
if (parameter.id === parameterId) {
console.log(e.target.checked);
parameter.hidden = !e.target.checked;
}
});
}
setTemplateConfigInfo(result);
},
[templateConfigInfo, setTemplateConfigInfo]
);
const renderInput = useCallback((parameter: IParameter) => {
return (
<Tooltip title={parameter.description} placement="top">
<div>
{parameter.domType.toLowerCase() === "file" && (
<MyInput
value={parameter.defaultValue || ""}
InputProps={{
endAdornment: (
<img
onClick={() => handleOpenFileSelect(taskId, parameter.name)}
src={fileSelectIcon}
alt=""
className={styles.fileSelectImg}
/>
),
}}
placeholder="请选择"
error={parameter.error || false}
helperText={parameter.helperText}
disabled={parameter.parameterGroup === 'out'}
></MyInput>
)}
{parameter.domType.toLowerCase() === "path" && (
<MyInput
value={parameter.defaultValue || ""}
InputProps={{
endAdornment: (
<img
onClick={() => handleOpenFileSelect(taskId, parameter.name)}
src={fileSelectIcon}
alt=""
className={styles.fileSelectImg}
/>
),
}}
placeholder="请选择"
error={parameter.error || false}
helperText={parameter.helperText}
disabled={parameter.parameterGroup === 'out'}
></MyInput>
)}
{parameter.domType.toLowerCase() === "dataset" && (
<MyInput
value={parameter.defaultValue || ""}
InputProps={{
endAdornment: (
<img
onClick={() => handleOpenFileSelect(taskId, parameter.name)}
src={fileSelectIcon}
alt=""
className={styles.fileSelectImg}
/>
),
}}
placeholder="请选择"
error={parameter.error || false}
helperText={parameter.helperText}
disabled={parameter.parameterGroup === 'out'}
></MyInput>
)}
{parameter.domType.toLowerCase() === "input" && (
<MyInput
value={parameter.defaultValue || ""}
onChange={(e: any) =>
handleParameterChange(e, taskId, parameter.name || "")
}
placeholder="请输入"
error={parameter.error || false}
helperText={parameter.helperText}
disabled={parameter.parameterGroup === 'out'}
></MyInput>
)}
{parameter.domType.toLowerCase() === "select" && (
<MySelect
value={parameter.defaultValue}
onChange={(e: any) =>
handleParameterChange(e, taskId, parameter.name || "")
}
error={parameter.error || false}
helpertext={parameter.helperText}
options={optionsTransform(parameter?.choices || [], "label")}
disabled={parameter.parameterGroup === 'out'}
></MySelect>
)}
{parameter.domType.toLowerCase() === "multipleselect" && (
<MySelect
value={parameter.defaultValue}
onChange={(e: any) =>
handleParameterChange(e, taskId, parameter.name || "")
}
multiple={true}
error={parameter.error || false}
helpertext={parameter.helperText}
options={optionsTransform(parameter.choices, "label")}
disabled={parameter.parameterGroup === 'out'}
></MySelect>
)}
{parameter.domType.toLowerCase() === "radio" && (
<MyRadio
value={parameter.defaultValue}
onChange={(e: any) =>
handleParameterChange(e, taskId, parameter.name || "")
}
options={optionsTransform(parameter.choices, "label")}
error={parameter.error || false}
helperText={parameter.helperText}
></MyRadio>
)}
{parameter.domType.toLowerCase() === "checkbox" && (
<MyCheckBox
value={parameter.defaultValue}
onChange={(e: any) =>
handleParameterChange(
{
target: {
value: e,
<div>
{parameter.domType.toLowerCase() === "file" && (
<MyInput
value={parameter.defaultValue || ""}
InputProps={{
endAdornment: (
<img
onClick={() => handleOpenFileSelect(taskId, parameter.name)}
src={fileSelectIcon}
alt=""
className={styles.fileSelectImg}
/>
),
}}
placeholder="请选择"
error={parameter.error || false}
helperText={parameter.helperText}
disabled={parameter.parameterGroup === "out"}
></MyInput>
)}
{parameter.domType.toLowerCase() === "path" && (
<MyInput
value={parameter.defaultValue || ""}
InputProps={{
endAdornment: (
<img
onClick={() => handleOpenFileSelect(taskId, parameter.name)}
src={fileSelectIcon}
alt=""
className={styles.fileSelectImg}
/>
),
}}
placeholder="请选择"
error={parameter.error || false}
helperText={parameter.helperText}
disabled={parameter.parameterGroup === "out"}
></MyInput>
)}
{parameter.domType.toLowerCase() === "dataset" && (
<MyInput
value={parameter.defaultValue || ""}
InputProps={{
endAdornment: (
<img
onClick={() => handleOpenFileSelect(taskId, parameter.name)}
src={fileSelectIcon}
alt=""
className={styles.fileSelectImg}
/>
),
}}
placeholder="请选择"
error={parameter.error || false}
helperText={parameter.helperText}
disabled={parameter.parameterGroup === "out"}
></MyInput>
)}
{parameter.domType.toLowerCase() === "input" && (
<MyInput
value={parameter.defaultValue || ""}
onChange={(e: any) =>
handleParameterChange(e, parameter.id || "")
}
placeholder="请输入"
error={parameter.error || false}
helperText={parameter.helperText}
disabled={parameter.parameterGroup === "out"}
></MyInput>
)}
{parameter.domType.toLowerCase() === "select" && (
<MySelect
value={parameter.defaultValue}
onChange={(e: any) =>
handleParameterChange(e, parameter.id || "")
}
error={parameter.error || false}
helpertext={parameter.helperText}
options={optionsTransform(parameter?.choices || [], "label")}
disabled={parameter.parameterGroup === "out"}
></MySelect>
)}
{parameter.domType.toLowerCase() === "multipleselect" && (
<MySelect
value={parameter.defaultValue}
onChange={(e: any) =>
handleParameterChange(e, parameter.id || "")
}
multiple={true}
error={parameter.error || false}
helpertext={parameter.helperText}
options={optionsTransform(parameter.choices, "label")}
disabled={parameter.parameterGroup === "out"}
></MySelect>
)}
{parameter.domType.toLowerCase() === "radio" && (
<MyRadio
value={parameter.defaultValue}
onChange={(e: any) =>
handleParameterChange(e, parameter.id || "")
}
options={optionsTransform(parameter.choices, "label")}
error={parameter.error || false}
helperText={parameter.helperText}
></MyRadio>
)}
{parameter.domType.toLowerCase() === "checkbox" && (
<MyCheckBox
value={parameter.defaultValue}
onChange={(e: any) =>
handleParameterChange(
{
target: {
value: e,
},
},
},
taskId,
parameter.name || ""
)
}
options={optionsTransform(parameter.choices, "label")}
error={parameter.error || false}
helperText={parameter.helperText}
></MyCheckBox>
)}
{/* {parameter.description && (
parameter.id || ""
)
}
options={optionsTransform(parameter.choices, "label")}
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>
</Tooltip>
);
},[]);
}, []);
// 输入参数
const inParameters: Array<IParameter> = useMemo(() => {
......@@ -405,7 +410,6 @@ const ParameterSetting = (props: IParameterSettingProps) => {
);
}
}, [taskInfo]);
console.log(inParameters);
// 输出参数
const outParameters: Array<IParameter> = useMemo(() => {
......@@ -451,40 +455,48 @@ const ParameterSetting = (props: IParameterSettingProps) => {
}
}, [taskInfo]);
const randerParameters = useCallback((parameters: Array<IParameter>)=>{
return (
<div className={styles.parameters}>
{parameters.map((parameter, parameterIndex) => {
return (
<div
className={styles.parameter}
key={parameter.id || "" + parameterIndex}
>
<div className={styles.parameterTop}>
<div className={styles.parameterLeft}>
<div
className={classNames({
[styles.parameterName]: true,
[styles.required]: parameter.required,
})}
>
{parameter.name}
</div>
<div className={styles.parameterClassTypeName}>
{parameter.classTypeName}
const randerParameters = useCallback(
(parameters: Array<IParameter>) => {
return (
<div className={styles.parameters}>
{parameters.map((parameter, parameterIndex) => {
return (
<div
className={styles.parameter}
key={parameter.id || "" + parameterIndex}
>
<div className={styles.parameterTop}>
<div className={styles.parameterLeft}>
<div
className={classNames({
[styles.parameterName]: true,
[styles.required]: parameter.required,
})}
>
{parameter.name}
</div>
<div className={styles.parameterClassTypeName}>
{parameter.classTypeName}
</div>
</div>
<MySwitch
value={!parameter.hidden}
onChange={(e: any) =>
handleHiddenChange(e, parameter.id || "")
}
></MySwitch>
</div>
<div className={styles.parameterContent}>
{renderInput(parameter)}
</div>
<MySwitch value={parameter.hidden} onChange={(e: any) => handleHiddenChange(e, parameter.id || '')}></MySwitch>
</div>
<div className={styles.parameterContent}>
{renderInput(parameter)}
</div>
</div>
);
})}
</div>
)
},[renderInput])
);
})}
</div>
);
},
[renderInput, handleHiddenChange]
);
const handleOpenFileSelect = (
taskId: string = "",
......@@ -497,53 +509,80 @@ const ParameterSetting = (props: IParameterSettingProps) => {
setFileSelectOpen(true);
};
const handleParameterChange = (
e: any,
taskId: string,
parameterName: string
) => {
console.log(e.target.value, taskId, parameterName);
// setParameter(e.target.value, taskId, parameterName);
};
const handleParameterChange = useCallback(
(e: any, parameterId: string) => {
console.log(e.target.value, taskId, parameterId);
const result: ITask[] = _.cloneDeep(templateConfigInfo);
console.log(result);
result.forEach((task) => {
if (task.id === taskId) {
let isCheck = true;
task.parameters.forEach((parameter) => {
if (parameter.id === parameterId) {
parameter.defaultValue = e.target.value;
const checkResult = getCustomTemplateParameterCheckResult(
parameter,
e.target.value
);
parameter.error = checkResult.error;
parameter.helperText = checkResult.helperText;
}
if (
getCustomTemplateParameterCheckResult(
parameter,
parameter.defaultValue
).error === true
) {
isCheck = false;
}
});
task.isCheck = isCheck;
} else {
return;
}
});
setTemplateConfigInfo(result);
// setParameter(e.target.value, taskId, parameterName);
},
[templateConfigInfo, setTemplateConfigInfo]
);
// 参数组tabs
const paramsTabList = useMemo(()=>{
const paramsTabList = useMemo(() => {
return [
{
label: "基础参数",
value: "basis",
component: randerParameters(basisParameters),
disabled: basisParameters.length === 0
disabled: basisParameters.length === 0,
},
{
label: "高级选项",
value: "senior",
component: randerParameters(seniorParameters),
disabled: seniorParameters.length === 0
disabled: seniorParameters.length === 0,
},
{
label: "硬件配置",
value: "hardware",
component: randerParameters(hardwareParameters),
disabled: hardwareParameters.length === 0
}
]
}, [basisParameters, seniorParameters, hardwareParameters, randerParameters])
disabled: hardwareParameters.length === 0,
},
];
}, [basisParameters, seniorParameters, hardwareParameters, randerParameters]);
// 激活的参数组tab
const activeParamsTab = useMemo(()=>{
const activeParamsTab = useMemo(() => {
if (basisParameters.length !== 0) {
return 'basis'
return "basis";
} else if (seniorParameters.length !== 0) {
return 'senior'
return "senior";
} else if (hardwareParameters.length !== 0) {
return 'hardware'
return "hardware";
} else {
return ''
return "";
}
}, [basisParameters, seniorParameters, hardwareParameters])
}, [basisParameters, seniorParameters, hardwareParameters]);
return (
<div className={styles.parameterSetting}>
......@@ -608,7 +647,12 @@ const ParameterSetting = (props: IParameterSettingProps) => {
</div>
</div>
<div className={styles.inOutParameterRight}>
<MySwitch value={parameter.hidden}></MySwitch>
<MySwitch
value={!parameter.hidden}
onChange={(e: any) =>
handleHiddenChange(e, parameter.id || "")
}
></MySwitch>
</div>
</div>
{renderInput(parameter)}
......@@ -639,9 +683,7 @@ const ParameterSetting = (props: IParameterSettingProps) => {
{parameter.classTypeName}
</div>
</div>
<div className={styles.inOutParameterRight}>
</div>
<div className={styles.inOutParameterRight}></div>
</div>
{renderInput(parameter)}
</div>
......@@ -650,30 +692,29 @@ const ParameterSetting = (props: IParameterSettingProps) => {
</div>
</div>
)}
{
taskInfo && (
<div className={styles.paramsGroup}>
<div className={styles.paramsTitle}>
参数组
<Tooltip
title="当某个参数项为启用状态时,代表该参数将由模板使用者在使用的时候填写赋值;当为关闭状态时,代表该参数不需要使用者来填写赋值。"
placement="right"
>
<img
className={styles.paramsTitleDesc}
src={questionMark}
alt=""
/>
</Tooltip>
</div>
<Tabs
tabList={paramsTabList}
defaultValue={activeParamsTab}
allowNullValue={true}
/>
{taskInfo && (
<div className={styles.paramsGroup}>
<div className={styles.paramsTitle}>
参数组
<Tooltip
title="当某个参数项为启用状态时,代表该参数将由模板使用者在使用的时候填写赋值;当为关闭状态时,代表该参数不需要使用者来填写赋值。"
placement="right"
>
<img
className={styles.paramsTitleDesc}
src={questionMark}
alt=""
/>
</Tooltip>
</div>
)
}
<Tabs
tabList={paramsTabList}
defaultValue={activeParamsTab}
allowNullValue={true}
tabPanelSx={{ padding: "7px 0" }}
/>
</div>
)}
{!taskInfo && (
<div className={styles.noData}>
<img src={noTemplate} alt="" className={styles.noDataImg} />
......
......@@ -40,7 +40,6 @@ const WorkFlowEdit = (props: IProps) => {
const [templateConfigInfo, setTemplateConfigInfo] = useState<ITask[]>([]);
const [leftContentType, setLeftContentType] = useState("list");
const [popperTitle, setPopperTitle] = useState(
"返回后,当前页面已填写内容将不保存,确认返回吗?"
);
......
import { IParameter } from "../Project/ProjectSubmitWork/interface";
export const getCustomTemplateParameterCheckResult = (
parameter: IParameter,
value: string
): {
error: boolean;
helperText: string;
} => {
let error = false;
let helperText = "";
// 表单校验
if (parameter.required) {
// 提交任务时不展示
if (parameter.hidden) {
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,
};
};
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