Skip to content

Commit 3bc879f

Browse files
authored
[elsa] 智能编排表单节点增强 (#105)
* [elsa] 智能编排表单节点增强 * [elsa] 渲染组件为CheckBox时,对应的type改为Array,同时去除默认值的填写
1 parent 9722528 commit 3bc879f

File tree

9 files changed

+127
-53
lines changed

9 files changed

+127
-53
lines changed

framework/elsa/fit-elsa-react/src/common/Consts.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ export const RENDER_TYPE = {
187187
RADIO: 'Radio',
188188
INPUT: 'Input',
189189
SWITCH: 'Switch',
190+
CHECK_BOX: 'CheckBox',
191+
LABEL: 'Label',
190192
};
191193

192194
export const DEFAULT_LOOP_NODE_CONTEXT = {

framework/elsa/fit-elsa-react/src/components/intelligentForm/Consts.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66

77
import {RENDER_TYPE} from '@/common/Consts.js';
88

9-
export const RENDER_OPTIONS_TYPE = new Set([RENDER_TYPE.RADIO]);
9+
export const RENDER_OPTIONS_TYPE = new Set([RENDER_TYPE.RADIO, RENDER_TYPE.SELECT, RENDER_TYPE.CHECK_BOX]);
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
3+
* This file is a part of the ModelEngine Project.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
import PropTypes from 'prop-types';
8+
import {Form} from 'antd';
9+
import {useEffect} from 'react';
10+
import {useFormContext} from '@/components/DefaultRoot.jsx';
11+
import {DATA_TYPES, RENDER_TYPE} from '@/common/Consts.js';
12+
import {JadeStopPropagationSelect} from '@/components/common/JadeStopPropagationSelect.jsx';
13+
import {useTranslation} from 'react-i18next';
14+
15+
FormItemFieldType.propTypes = {
16+
itemId: PropTypes.string.isRequired, // 确保 itemId 是一个必需的字符串
17+
propValue: PropTypes.string.isRequired, // 确保 propValue 是一个必需的字符串
18+
disableModifiable: PropTypes.bool.isRequired, // 确保 disableModifiable 是一个必需的bool值
19+
onChange: PropTypes.func.isRequired, // 确保 onChange 是一个必需的函数
20+
};
21+
22+
/**
23+
* 表单字段类型。
24+
*
25+
* @param itemId 表单字段类型所属Item的唯一标识。
26+
* @param propValue 类型的初始值。
27+
* @param disableModifiable 该字段是否禁止修改。
28+
* @param onChange 值被修改时调用的函数。
29+
* @param renderType 表单字段类型所属Item对应的渲染类型。
30+
* @returns {JSX.Element} 入参类型的Dom。
31+
*/
32+
export default function FormItemFieldType({itemId, propValue, disableModifiable, onChange, renderType}) {
33+
const { t } = useTranslation();
34+
const form = useFormContext();
35+
36+
useEffect(() => {
37+
form.setFieldsValue({ [`type-${itemId}`]: propValue });
38+
}, [propValue, form]);
39+
40+
const handleSelectClick = (event) => {
41+
event.stopPropagation(); // 阻止事件冒泡
42+
};
43+
44+
// 根据 不同组件 渲染不同的可选类型
45+
const renderOptions = () => {
46+
switch (renderType) {
47+
case RENDER_TYPE.INPUT:
48+
case RENDER_TYPE.RADIO:
49+
case RENDER_TYPE.SELECT:
50+
case RENDER_TYPE.CHECK_BOX:
51+
case RENDER_TYPE.LABEL:
52+
return [
53+
{value: DATA_TYPES.STRING, label: DATA_TYPES.STRING},
54+
{value: DATA_TYPES.INTEGER, label: DATA_TYPES.INTEGER},
55+
{value: DATA_TYPES.NUMBER, label: DATA_TYPES.NUMBER},
56+
];
57+
case RENDER_TYPE.SWITCH:
58+
return [
59+
{value: DATA_TYPES.BOOLEAN, label: DATA_TYPES.BOOLEAN},
60+
];
61+
default:
62+
return [];
63+
}
64+
};
65+
66+
return (<Form.Item
67+
className="jade-form-item"
68+
label={t('formItemType')}
69+
name={`type-${itemId}`}
70+
rules={[{required: true, message: t('formItemFieldTypeCannotBeEmpty')}]}
71+
initialValue={propValue}
72+
>
73+
<JadeStopPropagationSelect
74+
className={`jade-select intelligent-form-right-select`}
75+
value={propValue}
76+
disabled={disableModifiable}
77+
style={{width: "100%"}}
78+
onClick={handleSelectClick} // 点击下拉框时阻止事件冒泡
79+
onChange={(value) => {
80+
onChange(itemId, [{key: 'type', value: value}]); // 当选择框的值发生变化时调用父组件传递的回调函数
81+
document.activeElement.blur();// 在选择后取消焦点
82+
}}
83+
options={renderOptions()}
84+
/>
85+
</Form.Item>);
86+
}

framework/elsa/fit-elsa-react/src/components/intelligentForm/FormItemRenderType.jsx

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,12 @@ import {DATA_TYPES, RENDER_TYPE} from '@/common/Consts.js';
1919
* @param propValue 名称的初始值
2020
* @param disabled 该字段是否禁止修改
2121
* @param onChange 值被修改时调用的函数
22-
* @param type 该表单对象的类型
2322
* @returns {JSX.Element} 开始节点关于入参名称的Dom
2423
*/
25-
export const FormItemRenderType = ({itemId, propValue, disabled, onChange, type}) => {
24+
export const FormItemRenderType = ({itemId, propValue, disabled, onChange}) => {
2625
const { t } = useTranslation();
2726
const form = useFormContext();
2827

29-
// 根据 type 渲染不同的组件
30-
const renderOptions = () => {
31-
switch (type) {
32-
case DATA_TYPES.BOOLEAN:
33-
return [
34-
{value: RENDER_TYPE.SWITCH, label: RENDER_TYPE.SWITCH},
35-
];
36-
case DATA_TYPES.NUMBER:
37-
case DATA_TYPES.INTEGER:
38-
return [
39-
{value: RENDER_TYPE.INPUT, label: RENDER_TYPE.INPUT},
40-
];
41-
case DATA_TYPES.STRING:
42-
return [
43-
{value: RENDER_TYPE.INPUT, label: RENDER_TYPE.INPUT},
44-
{value: RENDER_TYPE.RADIO, label: RENDER_TYPE.RADIO},
45-
];
46-
default:
47-
return [];
48-
}
49-
};
50-
5128
useEffect(() => {
5229
form.setFieldsValue({ [`renderType-${itemId}`]: propValue });
5330
}, [propValue, form]);
@@ -62,14 +39,21 @@ export const FormItemRenderType = ({itemId, propValue, disabled, onChange, type}
6239
initialValue={propValue}
6340
>
6441
<JadeStopPropagationSelect
65-
className="jade-select intelligent-form-right-select"
42+
className="jade-select intelligent-form-left-select"
6643
disabled={disabled}
6744
style={{width: '100%'}}
6845
onChange={(value) => {
6946
onChange(itemId, [{key: 'renderType', value:value}]); // 当选择框的值发生变化时调用父组件传递的回调函数
7047
document.activeElement.blur();// 在选择后取消焦点
7148
}}
72-
options={renderOptions()}
49+
options={[
50+
{value: RENDER_TYPE.INPUT, label: RENDER_TYPE.INPUT},
51+
{value: RENDER_TYPE.SWITCH, label: RENDER_TYPE.SWITCH},
52+
{value: RENDER_TYPE.RADIO, label: RENDER_TYPE.RADIO},
53+
{value: RENDER_TYPE.SELECT, label: RENDER_TYPE.SELECT},
54+
{value: RENDER_TYPE.CHECK_BOX, label: RENDER_TYPE.CHECK_BOX},
55+
{value: RENDER_TYPE.LABEL, label: RENDER_TYPE.LABEL},
56+
]}
7357
/>
7458
</Form.Item>);
7559
};
@@ -79,5 +63,4 @@ FormItemRenderType.propTypes = {
7963
propValue: PropTypes.string.isRequired, // 确保 propValue 是一个必需的字符串
8064
disabled: PropTypes.bool.isRequired, // 确保 disabled 是一个必须的布尔值
8165
onChange: PropTypes.func.isRequired, // 确保 onChange 是一个必需的函数
82-
type: PropTypes.string.isRequired, // 确保 items 是一个必须的列表
8366
};

framework/elsa/fit-elsa-react/src/components/intelligentForm/FormItemSelectValue.jsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,20 @@ export const FormItemSelectValue = ({item, shapeStatus, onChange, label, inputRe
2929
const {t} = useTranslation();
3030

3131
/* input变化时的回调. */
32-
const onInputChange = (key, e) => {
33-
let value = e.target.value.trim() === '' ? null : e.target.value;
34-
if (value === null) {
32+
const onInputChange = (e) => {
33+
if (e === null) {
3534
form.setFieldsValue({[`value-${item.id}`]: null});
3635
}
3736
const type = item.type;
37+
let value = e
3838
if (type === 'Object' || type === 'Array') {
3939
try {
4040
value = JSON.parse(value);
4141
} catch (error) {
4242
// 不影响,报错可以继续执行.
4343
}
4444
}
45-
onChange(item.id, [{key, value}]);
45+
onChange(item.id, [{key: 'value', value}]);
4646
};
4747

4848
/**
@@ -70,7 +70,7 @@ export const FormItemSelectValue = ({item, shapeStatus, onChange, label, inputRe
7070
return <Switch
7171
disabled={shapeStatus.disabled}
7272
style={{marginLeft: '8px'}}
73-
onChange={(e) => onInputChange('value', e)}
73+
onChange={(e) => onInputChange(e)}
7474
checked={item.value}/>;
7575
case DATA_TYPES.INTEGER:
7676
return <InputNumber
@@ -79,7 +79,7 @@ export const FormItemSelectValue = ({item, shapeStatus, onChange, label, inputRe
7979
step={1}
8080
precision={0}
8181
parser={(value) => value.replace(/[^\d-]/g, '')} // 只允许输入整数部分
82-
onChange={(e) => onInputChange('value', e)}
82+
onChange={(e) => onInputChange(e)}
8383
stringMode
8484
value={item.value}
8585
/>;
@@ -88,7 +88,7 @@ export const FormItemSelectValue = ({item, shapeStatus, onChange, label, inputRe
8888
className="jade-input"
8989
disabled={shapeStatus.disabled}
9090
step={1}
91-
onChange={(e) => onInputChange('value', e)}
91+
onChange={(e) => onInputChange(e)}
9292
stringMode
9393
value={item.value}
9494
/>;
@@ -100,7 +100,7 @@ export const FormItemSelectValue = ({item, shapeStatus, onChange, label, inputRe
100100
style={{borderRadius: '0px 8px 8px 0px'}}
101101
placeholder={t('plsEnter')}
102102
value={item.type === DATA_TYPES.ARRAY || item.type === DATA_TYPES.OBJECT ? JSON.stringify(item.value) : item.value}
103-
onChange={(e) => onInputChange('value', e)}
103+
onChange={(e) => onInputChange(e.target.value.trim() === '' ? null : e.target.value)}
104104
/>;
105105
}
106106
};

framework/elsa/fit-elsa-react/src/components/intelligentForm/IntelligentInputFormItem.jsx

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import PropTypes from 'prop-types';
88
import {FormItemName} from '@/components/intelligentForm/FormItemName.jsx';
9-
import Type from '@/components/common/Type.jsx';
109
import React from 'react';
1110
import {useTranslation} from 'react-i18next';
1211
import {useDispatch, useFormContext} from '@/components/DefaultRoot.jsx';
@@ -15,7 +14,8 @@ import {FormItemSelectValue} from '@/components/intelligentForm/FormItemSelectVa
1514
import {RENDER_OPTIONS_TYPE} from '@/components/intelligentForm/Consts.js';
1615
import {FormItemDisplayName} from '@/components/intelligentForm/FormItemDisplayName.jsx';
1716
import {Col, Row} from 'antd';
18-
import {DATA_TYPES, FROM_TYPE} from '@/common/Consts.js';
17+
import {DATA_TYPES, FROM_TYPE, RENDER_TYPE} from '@/common/Consts.js';
18+
import FormItemFieldType from '@/components/intelligentForm/FormItemFieldType.jsx';
1919

2020
/**
2121
* 智能表单节点入参表单元素
@@ -40,19 +40,17 @@ const _IntelligentInputFormItem = ({item, items, shapeStatus, output}) => {
4040
const handleFormValueChange = (id, entries = []) => {
4141
const changes = new Map(entries.map(({ key, value }) => [key, value])); // 将 entries 转换为 Map
4242
// 如果 type 是 'type',清空 renderType
43-
if (changes.has('type') && changes.get('type') !== item.type) {
44-
changes.set('renderType', undefined);
43+
if (changes.has('renderType') && changes.get('renderType') !== item.renderType) {
44+
changes.set('type', undefined);
45+
if (changes.get('renderType') === RENDER_TYPE.CHECK_BOX) {
46+
changes.set('type', DATA_TYPES.ARRAY);
47+
}
4548
changes.set('value', null);
4649
form.setFieldsValue({[`value-${item.id}`]: undefined});
4750
}
4851
dispatch({ type: 'updateParam', id: id, changes });
4952
};
5053

51-
const handleChange = (value) => {
52-
handleFormValueChange(item.id, [{key: 'type', value: value}]); // 当选择框的值发生变化时调用父组件传递的回调函数
53-
document.activeElement.blur();// 在选择后取消焦点
54-
};
55-
5654
const handleOptionsChange = (id, entries = []) => {
5755
const newOptions = {...item.options};
5856
const hasInputFrom = entries.some(entry => entry.key === 'from' && entry.value === FROM_TYPE.INPUT);
@@ -76,13 +74,16 @@ const _IntelligentInputFormItem = ({item, items, shapeStatus, output}) => {
7674
</Row>
7775
<Row>
7876
<Col flex='1'>
79-
<Type itemId={item.id} propValue={item.type} disableModifiable={shapeStatus.disabled} onChange={handleChange} labelName={t('formItemType')} className={'intelligent-form-left-select'}/>
77+
<FormItemRenderType itemId={item.id} propValue={item.renderType} disabled={shapeStatus.disabled} onChange={handleFormValueChange}/>
8078
</Col>
8179
<Col flex='1'>
82-
<FormItemRenderType itemId={item.id} propValue={item.renderType} disabled={shapeStatus.disabled} onChange={handleFormValueChange} type={item.type}/>
80+
{item.renderType !== RENDER_TYPE.CHECK_BOX &&
81+
<FormItemFieldType itemId={item.id} propValue={item.type} disableModifiable={shapeStatus.disabled} onChange={handleFormValueChange}
82+
renderType={item.renderType}/>}
8383
</Col>
8484
</Row>
85-
<FormItemSelectValue item={item} onChange={handleFormValueChange} shapeStatus={shapeStatus} label={t('formItemDefaultValue')}/>
85+
{item.renderType !== RENDER_TYPE.CHECK_BOX &&
86+
<FormItemSelectValue item={item} onChange={handleFormValueChange} shapeStatus={shapeStatus} label={t('formItemDefaultValue')}/>}
8687
{RENDER_OPTIONS_TYPE.has(item.renderType) && <FormItemSelectValue item={item.options} onChange={handleOptionsChange} shapeStatus={shapeStatus} label={t('formItemOptionsValue')} inputRequired={true}/>}
8788
</>);
8889
};

framework/elsa/fit-elsa-react/src/components/intelligentForm/reducers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const AddParamReducer = () => {
2323
id: action.id,
2424
name: '',
2525
displayName: '',
26-
type: DATA_TYPES.STRING,
26+
type: undefined,
2727
from: FROM_TYPE.INPUT,
2828
value: '',
2929
renderType: '',

framework/elsa/fit-elsa-react/src/en_US.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,5 +410,6 @@
410410
"pushResultToChat": "待翻译",
411411
"appConfig": "App Configuration",
412412
"appChatStyle": "App Interface Configuration",
413-
"appChatStyleCannotBeEmpty": "App interface configuration cannot be empty"
413+
"appChatStyleCannotBeEmpty": "App interface configuration cannot be empty",
414+
"formItemFieldTypeCannotBeEmpty": "Field type is required"
414415
}

framework/elsa/fit-elsa-react/src/zh_CN.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -696,12 +696,13 @@
696696
"formItemName": "表单项名称",
697697
"formItemDisplayName": "表单项展示名称",
698698
"formItemType": "表单项类型",
699-
"formItemRenderType": "表单项渲染方式",
700-
"formItemRenderTypeCannotBeEmpty": "渲染方式不能为空",
699+
"formItemRenderType": "表单项渲染组件",
700+
"formItemRenderTypeCannotBeEmpty": "渲染组件不能为空",
701701
"formItemDefaultValue": "表单项默认值",
702702
"formItemOptionsValue": "表单选项",
703703
"pushResultToChat": "输出结果至聊天",
704704
"appConfig": "应用配置",
705705
"appChatStyle": "应用界面配置",
706-
"appChatStyleCannotBeEmpty": "应用界面配置不能为空"
706+
"appChatStyleCannotBeEmpty": "应用界面配置不能为空",
707+
"formItemFieldTypeCannotBeEmpty": "表单项类型不能为空"
707708
}

0 commit comments

Comments
 (0)