diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/dto/AppInputParam.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/dto/AppInputParam.java
index 97bb73c59..ec762f4cd 100644
--- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/dto/AppInputParam.java
+++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/dto/AppInputParam.java
@@ -10,18 +10,17 @@
import static modelengine.fitframework.util.ObjectUtils.cast;
import static modelengine.fitframework.util.StringUtils.lengthBetween;
-import modelengine.fit.jober.aipp.common.exception.AippParamException;
-import modelengine.fit.jober.aipp.enums.InputParamType;
-
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
+import lombok.Getter;
import lombok.NoArgsConstructor;
-import modelengine.fitframework.inspection.Validation;
-import modelengine.fitframework.util.MapBuilder;
+import modelengine.fit.jober.aipp.common.exception.AippParamException;
import modelengine.fitframework.util.ObjectUtils;
import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
@@ -32,76 +31,257 @@
* @since 2024-11-25
*/
@Data
+@Builder
@NoArgsConstructor
+@AllArgsConstructor
public class AppInputParam {
- private int stringMaxLength = 500;
- private Map> paramTypePredicateMap;
+ private static final int DEFAULT_STRING_MAX_LENGTH = 500;
+ private static final BigDecimal DEFAULT_MIN_NUMBER = new BigDecimal("-999999999.99");
+ private static final BigDecimal DEFAULT_MAX_NUMBER = new BigDecimal("999999999.99");
+ private static final int MAX_DECIMAL_PLACES = 2;
+
private String name;
private String type;
- private String description;
+ private String displayName;
private boolean isRequired;
private boolean isVisible;
+ private Integer stringMaxLength;
+ private Predicate
\n格式要求:只能输入英文、数字及下划线,且不能以数字开头",
"startNodeDisplayNamePopover": "用于表示入参字段在对话配置窗口中的展示名称",
@@ -1682,5 +1682,23 @@
"guestMode": "游客模式",
"guestTips": "游客模式无访问鉴权,存在数据泄露等潜在威胁,请务必谨慎使用。",
"wrongAddr": "访问地址错误",
- "wrongAddrMsg": "请访问正确的地址"
+ "wrongAddrMsg": "请访问正确的地址",
+ "inputType": "文本",
+ "numberType": "数字",
+ "dropdownType": "单选框",
+ "switchType": "开关",
+ "multiselectType": "多选框",
+ "maxLength": "最大长度",
+ "option": "选项",
+ "plsEnterOption": "请输入选项",
+ "optionShouldBeUnique": "选项不能重复",
+ "addOption": "添加选项",
+ "maxValue": "最大值",
+ "minValue": "最小值",
+ "addParamField": "添加变量",
+ "editParamField": "编辑变量",
+ "varName": "变量名称",
+ "plsEnterVarName": "请输入变量名称",
+ "attributeVarNameMustBeUnique": "名称已存在,请重新命名",
+ "noDefaultValue": "无默认值"
}
diff --git a/frontend/src/pages/addFlow/components/elsa-stage.tsx b/frontend/src/pages/addFlow/components/elsa-stage.tsx
index 56fc7ff7b..7932626df 100644
--- a/frontend/src/pages/addFlow/components/elsa-stage.tsx
+++ b/frontend/src/pages/addFlow/components/elsa-stage.tsx
@@ -29,6 +29,7 @@ import { configMap } from '../config';
import { useTranslation } from 'react-i18next';
import i18n from '../../../locale/i18n';
import { cloneDeep } from 'lodash';
+import InputParamModal from '@/pages/configForm/configUi/components/add-input-param';
/**
* elsa编排组件
@@ -56,6 +57,8 @@ const Stage = (props) => {
} = props;
const [showModal, setShowModal] = useState(false);
const [showTools, setShowTools] = useState(false);
+ const [showInputModal, setShowInputModal] = useState(false);
+ const [inputModalMode, setInputModalMode] = useState('add');
const [showDrawer, setShowDrawer] = useState(false);
const [spinning, setSpinning] = useState(false);
const [isDrawper, setIsDrawper] = useState(false);
@@ -79,6 +82,8 @@ const Stage = (props) => {
const modelCallback = useRef();
const knowledgeCallback = useRef();
const pluginCallback = useRef();
+ const inputParamCallback = useRef();
+ const inputParamRef = useRef({})
const formCallback = useRef();
const currentApp = useRef();
const currentChange = useRef(false);
@@ -251,6 +256,18 @@ const Stage = (props) => {
setShowTools(true);
setModalTypes('parallel');
});
+ agent.onAddInputParam(({onAdd, existParam}) => {
+ inputParamCallback.current = onAdd;
+ setInputModalMode('add')
+ setShowInputModal(true);
+ inputParamRef.current.existParam = existParam;
+ })
+ agent.onEditInputParam(({onEdit, id, selectedParam}) => {
+ inputParamCallback.current = onEdit;
+ setInputModalMode('edit')
+ setShowInputModal(true);
+ inputParamRef.current.selectedParam = selectedParam;
+ })
if (readOnly) {
agent.readOnly();
}
@@ -298,6 +315,10 @@ const Stage = (props) => {
searchCallback.current(value);
};
+ const addParam = (value) => {
+ inputParamCallback.current(value);
+ }
+
// 插件工具流选中
const toolsConfirm = (item) => {
let obj = {};
@@ -444,6 +465,14 @@ const Stage = (props) => {
taskName={taskName}
selectModal={selectModal}
/>
+ {/*input param添加弹窗*/}
+
{/* 添加知识库弹窗 */}
{
name={debugType.name}
label={debugType.displayName}
key={index}
- isRequired={debugType.isRequired} />
+ isRequired={debugType.isRequired}
+ appearance={debugType.appearance}
+ />
)
})}
{
diff --git a/frontend/src/pages/addFlow/components/render-form-item.tsx b/frontend/src/pages/addFlow/components/render-form-item.tsx
index 0e4b476df..305995523 100644
--- a/frontend/src/pages/addFlow/components/render-form-item.tsx
+++ b/frontend/src/pages/addFlow/components/render-form-item.tsx
@@ -5,9 +5,8 @@
*--------------------------------------------------------------------------------------------*/
import React, { useEffect } from 'react';
-import { Input, Form, InputNumber, Switch } from 'antd';
+import { Input, Form, InputNumber, Switch, Select } from 'antd';
import { useTranslation } from 'react-i18next';
-const QUESTION_NAME = 'Question';
/**
* 调试表单渲染
@@ -22,148 +21,163 @@ const QUESTION_NAME = 'Question';
*/
const RenderFormItem = (props) => {
const { t } = useTranslation();
- const { type, name, label, isRequired, form } = props;
+ const { type, name, label, isRequired, form, appearance } = props;
- useEffect(() => {
- formInit();
- }, []);
+ const displayType = appearance?.displayType;
+ const actualType = displayType || type;
- useEffect(() => {
- formInit();
- }, [type])
-
- // 初始化数据
- const formInit = () => {
- if (type === 'Boolean') {
- form.setFieldValue(name, false);
- return;
- }
- form.setFieldValue(name, null);
- }
-
- const customLabel = (
+ const getCustomLabel = (typeName) => (
{label}
- {type}
);
-
+
const validateNumber = (value, isInteger) => {
- if (value === undefined || value === null || value === '') {
- return Promise.resolve();
- }
- if (isNaN(value)) {
- return Promise.reject(new Error(t('plsEnterValidNumber')));
- }
- if (isInteger && (value < -999999999 || value > 999999999)) {
- return Promise.reject(new Error(t('integerValidateTip')));
- }
- if (!isInteger && (value < -999999999.99 || value > 999999999.99)) {
- return Promise.reject(new Error(t('numberValidateTip')));
- }
+ if (value === undefined || value === null || value === '') return Promise.resolve();
+ if (isNaN(value)) return Promise.reject(new Error(t('plsEnterValidNumber')));
+ const min = appearance?.minValue ?? (isInteger ? -999999999 : -999999999.99);
+ const max = appearance?.maxValue ?? (isInteger ? 999999999 : 999999999.99);
+ if (value < min || value > max) return Promise.reject(new Error(t(isInteger ? 'integerValidateTip' : 'numberValidateTip')));
return Promise.resolve();
};
const handleNumberItemBlur = (value, isInteger) => {
- if (isNaN(value)) {
- form.setFieldValue(name, null);
- form.validateFields([name]);
- } else if (value === '') {
+ if (isNaN(value) || value === '') {
form.setFieldValue(name, null);
} else {
- let inputNumber = isInteger ? value : Number(value).toFixed(2);
- form.setFieldValue(name, Number(inputNumber));
+ form.setFieldValue(name, isInteger ? Number(value) : Number(Number(value).toFixed(2)));
}
- }
+ };
const handleStringItemBlur = (value) => {
- if (value !== '') {
- return;
- }
- form.setFieldValue(name, null);
- }
+ if (value === '') form.setFieldValue(name, null);
+ };
- return <>
- {type === 'String' &&
-
- handleStringItemBlur(e.target.value)}
- />
-
- }
- {type === 'Integer' &&
- validateNumber(value, true) }
- ]}
- className='debug-form-item'
- >
- handleNumberItemBlur(e.target.value, true)}
- parser={(value) => value.replace(/[^\d-]/g, '')} // 仅允许数字和负号
- formatter={(value) => {
- if (value === '0') {
- return value;
- }
- return `${Math.floor(value) || ''}`;
- }
- } // 强制显示整数
- />
-
+ const isRequiredRule = { required: isRequired !== false, message: t('plsEnter') };
+
+ // 初始化表单值
+ useEffect(() => formInit(), []);
+ useEffect(() => formInit(), [actualType]);
+ const formInit = () => {
+ if (actualType === 'Boolean' || actualType === 'switch') {
+ form.setFieldValue(name, false);
}
- {type === 'Number' &&
- validateNumber(value, false) }
- ]}
- className='debug-form-item'
- >
- handleNumberItemBlur(e.target.value, false)}
- />
-
+ if (actualType === 'multiselect') {
+ form.setFieldValue(name, []);
+ } else {
+ form.setFieldValue(name, null);
}
- {type === 'Boolean' &&
-
-
-
+ };
+
+ // 如果没有 appearance,回退到原来的 type 渲染逻辑
+ if (!appearance) {
+ switch (type) {
+ case 'String':
+ return (
+
+ handleStringItemBlur(e.target.value)} />
+
+ );
+ case 'Integer':
+ case 'Number':
+ const isInteger = type === 'Integer';
+ return (
+ validateNumber(value, isInteger) }]}
+ className='debug-form-item'
+ >
+ handleNumberItemBlur(e.target.value, isInteger)}
+ />
+
+ );
+ case 'Boolean':
+ return (
+
+
+
+ );
+ default:
+ return null;
}
- >
-}
+ }
+ // 有 appearance,走新的 actualType 渲染逻辑
+ return (
+ <>
+ {actualType === 'input' && (
+
+ handleStringItemBlur(e.target.value)} />
+
+ )}
+ {actualType === 'number' && (
+ validateNumber(value, false) }]} className='debug-form-item'>
+ handleNumberItemBlur(e.target.value, false)}
+ />
+
+ )}
+ {actualType === 'Integer' && (
+ validateNumber(value, true) }]} className='debug-form-item'>
+ value.replace(/[^\d-]/g, '')}
+ formatter={(value) => (value === '0' ? value : `${Math.floor(value) || ''}`)}
+ onBlur={(e) => handleNumberItemBlur(e.target.value, true)}
+ />
+
+ )}
+ {(actualType === 'Boolean' || actualType === 'switch') && (
+
+
+
+ )}
+ {actualType === 'dropdown' && (
+
+
+
+ )}
+ {actualType === 'multiselect' && (
+
+
+
+ )}
+ >
+ );
+};
export default RenderFormItem;
diff --git a/frontend/src/pages/chatPreview/components/send-editor/components/conversation-configuration.tsx b/frontend/src/pages/chatPreview/components/send-editor/components/conversation-configuration.tsx
index d4917624f..e55818074 100644
--- a/frontend/src/pages/chatPreview/components/send-editor/components/conversation-configuration.tsx
+++ b/frontend/src/pages/chatPreview/components/send-editor/components/conversation-configuration.tsx
@@ -6,7 +6,7 @@
import React, { useEffect, useState, useContext, useRef } from 'react';
import { useTranslation } from 'react-i18next';
-import { Form, InputNumber, Input, Switch, Popover, Empty } from 'antd';
+import { Form, InputNumber, Input, Switch, Popover, Empty, Select } from 'antd';
import { isInputEmpty, getConfiguration } from '@/shared/utils/common';
import { AippContext } from '@/pages/aippIndex/context';
import { useAppSelector } from '@/store/hook';
@@ -80,44 +80,111 @@ const ConversationConfiguration = ({ appInfo, updateUserContext, chatRunning, is
}, []);
// 根据类型获取输入类型
- const getConfigurationItem = ({ name, type }) => {
+ const getConfigurationItem = ({ name, type, appearance = {}, value}) => {
+ const displayType = appearance?.displayType;
+
+ // 优先使用 displayType 分支渲染
+ switch (displayType) {
+ case 'input':
+ return (
+
+ );
+ case 'number':
+ return (
+ handleNumberChange(e, false, name)}
+ />
+ );
+ case 'switch':
+ return ;
+ case 'dropdown':
+ return (
+
+ );
+ case 'multiselect':
+ return (
+
+ );
+ }
+
+ // 如果没有 appearance.displayType,退回旧逻辑
switch (type) {
case 'String':
- return
+ return (
+
+ );
case 'Number':
- return handleNumberChange(e, false, name)}
- />
+ return (
+ handleNumberChange(e, false, name)}
+ />
+ );
case 'Integer':
- return value.replace(/[^\d-]/g, '')} // 仅允许数字和负号
- onChange={(e) => handleNumberChange(e, true, name)}
- formatter={(value) => {
- if (value === '0') {
- return '0';
- }
- return `${Math.floor(value) || ''}`;
- }
- } // 强制显示整数
- />
+ return (
+ value.replace(/[^\d-]/g, '')}
+ formatter={(value) => (value === '0' ? '0' : `${Math.floor(value) || ''}`)}
+ min={-999999999}
+ max={999999999}
+ onChange={(e) => handleNumberChange(e, true, name)}
+ />
+ );
case 'Boolean':
- return
+ return ;
+ default:
+ return ;
}
};
@@ -170,6 +237,29 @@ const ConversationConfiguration = ({ appInfo, updateUserContext, chatRunning, is
}
}, [showElsa]);
+ useEffect(() => {
+ if (configurationList?.length) {
+ configurationList.forEach(item => {
+ const preItem = preConfigurationList.current.find(it => it.name === item.name);
+ const isChangeType = preItem?.type !== item.type;
+
+ // 若已有值,保持不变,否则设置为默认值
+ const existingValue = form.getFieldValue(item.name);
+ const defaultValue = item.value ?? null;
+
+ if (item.type === 'Boolean') {
+ form.setFieldValue(item.name, isChangeType ? false : (existingValue ?? defaultValue ?? false));
+ } else {
+ const isEmpty = isInputEmpty(existingValue); // 你已有此函数
+ form.setFieldValue(item.name, isChangeType ? null : (isEmpty ? defaultValue : existingValue));
+ }
+ });
+ updateData();
+ }
+ preConfigurationList.current = configurationList;
+ }, [configurationList]);
+
+
const content = (
<>
@@ -186,7 +276,7 @@ const ConversationConfiguration = ({ appInfo, updateUserContext, chatRunning, is
name={config.name}
label={config.displayName || ' '}
className={config.isRequired ? 'is-required' : ''}>
- {getConfigurationItem(config)}
+ {getConfigurationItem({...config, value: form.getFieldValue(config.value)})}
)
}
@@ -214,4 +304,4 @@ const ConversationConfiguration = ({ appInfo, updateUserContext, chatRunning, is
>
};
-export default ConversationConfiguration;
\ No newline at end of file
+export default ConversationConfiguration;
diff --git a/frontend/src/pages/configForm/configUi/components/add-input-param.tsx b/frontend/src/pages/configForm/configUi/components/add-input-param.tsx
new file mode 100644
index 000000000..a456826d9
--- /dev/null
+++ b/frontend/src/pages/configForm/configUi/components/add-input-param.tsx
@@ -0,0 +1,520 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import React, { useEffect, useState } from 'react';
+import {
+ Modal,
+ Form,
+ Input,
+ Select,
+ InputNumber,
+ Checkbox,
+ Button,
+ Row,
+ Col,
+ Space,
+ Switch,
+} from 'antd';
+import {
+ UnorderedListOutlined,
+ FileTextOutlined,
+ NumberOutlined,
+ CheckSquareOutlined,
+ SwitcherOutlined,
+ DeleteOutlined,
+ PlusOutlined,
+} from '@ant-design/icons';
+import { v4 as uuidv4 } from 'uuid';
+import { useTranslation } from 'react-i18next';
+
+const { Option } = Select;
+
+const InputParamModal = (props) => {
+ const { t } = useTranslation();
+ const [form] = Form.useForm();
+ const { showModal, setShowModal, onSubmit, mode, modalRef } = props;
+ const [fieldType, setFieldType] = useState('input');
+
+ // 字段类型配置
+ const fieldTypes = [
+ { value: 'input', label: t('inputType'), icon:
, type: 'String' },
+ { value: 'number', label: t('numberType'), icon:
, type: 'Number' },
+ { value: 'dropdown', label: t('dropdownType'), icon:
, type: 'String' },
+ { value: 'switch', label: t('switchType'), icon:
, type: 'Boolean' },
+ { value: 'multiselect', label: t('multiselectType'), icon:
, type: 'Array[String]' },
+ ];
+
+ const requiredValue = Form.useWatch('required', form);
+ const visibleValue = Form.useWatch('visible', form);
+ const maxLength = Form.useWatch(['appearance', 'maxLength'], form);
+ const dropdownOptions = Form.useWatch(['appearance', 'options'], form);
+ const maxValue = Form.useWatch(['appearance', 'maxValue'], form);
+ const minValue = Form.useWatch(['appearance', 'minValue'], form);
+
+ useEffect(() => {
+ if (mode === 'edit' && modalRef.current) {
+ const defaultValue = modalRef.current.selectedParam;
+ form.setFieldsValue({
+ fieldType: defaultValue.appearance?.displayType,
+ tableName: defaultValue.name,
+ displayName: defaultValue.displayName,
+ defaultValue: defaultValue.value,
+ required: defaultValue.isRequired,
+ visible: defaultValue.isVisible,
+ appearance: defaultValue.appearance,
+ });
+ setFieldType(defaultValue.appearance?.displayType || 'input');
+ } else if (mode === 'add') {
+ // 添加模式:重置表单到初始值
+ form.resetFields();
+ setFieldType('input');
+ }
+ }, [showModal, mode]);
+
+ useEffect(() => {
+ if (requiredValue && !visibleValue) {
+ form.setFieldValue('visible', true);
+ }
+ }, [requiredValue, form, visibleValue]);
+
+ const handleSubmit = async () => {
+ try {
+ const values = await form.validateFields();
+
+ const fieldTypeItem = fieldTypes.find((ft) => ft.value === values.fieldType);
+ const type = fieldTypeItem?.type || 'String';
+ const finalType = type.includes('Array') ? 'Array' : type;
+
+ const transformed = {
+ id: mode === 'add' ? `input_${uuidv4()}` : modalRef.current.selectedParam.id,
+ name: values.tableName,
+ type: finalType,
+ value: getDefaultValueByType(values.defaultValue, finalType),
+ displayName: values.displayName,
+ isRequired: values.required,
+ isVisible: values.visible,
+ disableModifiable: false,
+ appearance: {
+ displayType: fieldTypeItem?.value || 'input',
+ ...values.appearance,
+ },
+ };
+
+ function getDefaultValueByType(value, type) {
+ if (value !== undefined && value !== null && value !== '') {
+ return value;
+ }
+ if (type === 'Array') {
+ return [];
+ } else {
+ return '';
+ }
+ }
+
+ setShowModal(false);
+ form.resetFields();
+ onSubmit(transformed);
+ } catch (error) {
+ console.log('验证失败:', error);
+ }
+ };
+
+ const handleCancel = () => {
+ setShowModal(false);
+ form.resetFields();
+ };
+
+ const handleFieldTypeChange = (value) => {
+ setFieldType(value);
+ form.setFieldsValue({
+ appearance: {}, // 清空所有 appearance 配置
+ defaultValue: undefined,
+ });
+ };
+
+ const getTypeByValue = (value) => {
+ const field = fieldTypes.find((item) => item.value === value);
+ return field?.type; // 如果找不到会返回 undefined
+ };
+
+ // 根据字段类型渲染不同的配置项
+ const renderFieldSpecificOptions = () => {
+ switch (fieldType) {
+ case 'input':
+ return (
+ <>
+
+
+
+
+
+
+
+ >
+ );
+
+ case 'dropdown':
+ return (
+ <>
+
+ {(fields, { add, remove }) => (
+ <>
+ {fields.map(({ key, name, ...restField }, index) => (
+ ({
+ validator(_, value) {
+ if (!value) return Promise.resolve();
+ const options = getFieldValue(['appearance', 'options']) || [];
+ const duplicates = options.filter(
+ (option, idx) => option === value && idx !== name
+ );
+ if (duplicates.length > 0) {
+ return Promise.reject(new Error(t('optionShouldBeUnique')));
+ }
+ return Promise.resolve();
+ },
+ }),
+ ]}
+ >
+ {
+ if (fields.length > 1) {
+ const options = form.getFieldValue(['appearance', 'options']);
+ const defaultValue = form.getFieldValue('defaultValue');
+ // 如果删除的是默认值,清空默认值
+ if (defaultValue === options[index]) {
+ form.setFieldValue('defaultValue', '');
+ }
+ remove(name);
+ }
+ }}
+ style={{
+ cursor: fields.length > 1 ? 'pointer' : 'not-allowed',
+ color: fields.length > 1 ? '#2d2f32' : '#8c8c8c',
+ fontSize: '14px',
+ }}
+ />
+ }
+ />
+
+ ))}
+
+
+
+ >
+ )}
+
+
+
+
+
+ >
+ );
+
+ case 'number':
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+
+ case 'switch':
+ return (
+ <>
+
+
+
+ >
+ );
+
+ case 'multiselect':
+ return (
+ <>
+
+ {(fields, { add, remove }) => (
+ <>
+ {fields.map(({ key, name, ...restField }, index) => (
+ ({
+ validator(_, value) {
+ if (!value) return Promise.resolve();
+ const options = getFieldValue(['appearance', 'options']) || [];
+ const duplicates = options.filter(
+ (option, idx) => option === value && idx !== name
+ );
+ if (duplicates.length > 0) {
+ return Promise.reject(new Error(t('optionShouldBeUnique')));
+ }
+ return Promise.resolve();
+ },
+ }),
+ ]}
+ >
+ {
+ if (fields.length > 1) {
+ const options = form.getFieldValue(['appearance', 'options']);
+ const defaultValue = form.getFieldValue('defaultValue');
+ // 如果删除的是默认值,清空默认值
+ if (defaultValue === options[index]) {
+ form.setFieldValue('defaultValue', '');
+ }
+ remove(name);
+ }
+ }}
+ style={{
+ cursor: fields.length > 1 ? 'pointer' : 'not-allowed',
+ color: fields.length > 1 ? '#2d2f32' : '#8c8c8c',
+ fontSize: '14px',
+ }}
+ />
+ }
+ />
+
+ ))}
+
+
+
+ >
+ )}
+
+
+
+
+
+ >
+ );
+
+ default:
+ return null;
+ }
+ };
+
+ return (
+
+ {t('cancel')}
+ ,
+ ,
+ ]}
+ destroyOnClose
+ >
+
+
+
+
+ {/* 变量名称 */}
+ ({
+ validator(_, value) {
+ if (!value) {
+ return Promise.resolve(); // 为空的校验由 required 处理
+ }
+
+ const existList = modalRef?.current?.existParam || [];
+
+ const isEditMode = mode === 'edit';
+ const currentId = modalRef?.current?.selectedParam?.id;
+ const currentName = modalRef?.current?.selectedParam?.name;
+
+ const nameExists = existList.some((param) => {
+ if (isEditMode && param.id === currentId) {
+ return false; // 编辑时跳过自身
+ }
+ return param.name === value;
+ });
+
+ if (nameExists) {
+ return Promise.reject(new Error(t('attributeVarNameMustBeUnique')));
+ }
+ return Promise.resolve();
+ },
+ }),
+ ]}
+ >
+
+
+
+ {/* 显示名称 */}
+ ({
+ validator(_, value) {
+ if (!value) {
+ return Promise.resolve(); // 为空的校验由 required 处理
+ }
+
+ const existList = modalRef?.current?.existParam || [];
+
+ const isEditMode = mode === 'edit';
+ const currentId = modalRef?.current?.selectedParam?.id;
+ const currentName = modalRef?.current?.selectedParam?.displayName;
+
+ const nameExists = existList.some((param) => {
+ if (isEditMode && param.id === currentId) {
+ return false; // 编辑时跳过自身
+ }
+ return param.displayName === value;
+ });
+
+ if (nameExists) {
+ return Promise.reject(new Error(t('attributeDisplayNameMustBeUnique')));
+ }
+ return Promise.resolve();
+ },
+ }),
+ ]}
+ >
+
+
+
+ {/* 字段类型特定配置 */}
+ {renderFieldSpecificOptions()}
+
+ {/* 参数展示、必填配置 */}
+
+
+
+ {t('requiredOrNot')}
+
+
+
+
+ {t('displayInDialogConfiguration')}
+
+
+
+
+
+ );
+};
+
+export default InputParamModal;