Skip to content

Commit 99cee2e

Browse files
authored
[appbuilder] feat: use modal to add/edit custom variables on start node (#458)
* [frontend] feat: use modal to add/edit custom variables on start node * [appbuilder] feat: add validator for new param field * [app-builder] modify displayType name
1 parent a9d8551 commit 99cee2e

File tree

10 files changed

+1889
-215
lines changed

10 files changed

+1889
-215
lines changed

app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/dto/AppInputParam.java

Lines changed: 229 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,17 @@
1010
import static modelengine.fitframework.util.ObjectUtils.cast;
1111
import static modelengine.fitframework.util.StringUtils.lengthBetween;
1212

13-
import modelengine.fit.jober.aipp.common.exception.AippParamException;
14-
import modelengine.fit.jober.aipp.enums.InputParamType;
15-
1613
import lombok.AllArgsConstructor;
1714
import lombok.Builder;
1815
import lombok.Data;
16+
import lombok.Getter;
1917
import lombok.NoArgsConstructor;
20-
import modelengine.fitframework.inspection.Validation;
21-
import modelengine.fitframework.util.MapBuilder;
18+
import modelengine.fit.jober.aipp.common.exception.AippParamException;
2219
import modelengine.fitframework.util.ObjectUtils;
2320

2421
import java.math.BigDecimal;
22+
import java.util.Collection;
23+
import java.util.List;
2524
import java.util.Map;
2625
import java.util.function.Predicate;
2726

@@ -32,76 +31,257 @@
3231
* @since 2024-11-25
3332
*/
3433
@Data
34+
@Builder
3535
@NoArgsConstructor
36+
@AllArgsConstructor
3637
public class AppInputParam {
37-
private int stringMaxLength = 500;
38-
private Map<InputParamType, Predicate<Object>> paramTypePredicateMap;
38+
private static final int DEFAULT_STRING_MAX_LENGTH = 500;
39+
private static final BigDecimal DEFAULT_MIN_NUMBER = new BigDecimal("-999999999.99");
40+
private static final BigDecimal DEFAULT_MAX_NUMBER = new BigDecimal("999999999.99");
41+
private static final int MAX_DECIMAL_PLACES = 2;
42+
3943
private String name;
4044
private String type;
41-
private String description;
45+
private String displayName;
4246
private boolean isRequired;
4347
private boolean isVisible;
48+
private Integer stringMaxLength;
49+
private Predicate<Object> validator;
4450

4551
/**
46-
* 通过键值对构建一个 {@link AppInputParam} 对象.
52+
* 通过键值对构建一个 {@link AppInputParam} 对象
4753
*
48-
* @param rawParam 原始参数.
49-
* @return {@link AppInputParam} 对象.
54+
* @param rawParam 原始参数
55+
* @return {@link AppInputParam} 对象
5056
*/
5157
public static AppInputParam from(Map<String, Object> rawParam) {
52-
AppInputParam appInputParam = new AppInputParam();
53-
appInputParam.setName(ObjectUtils.cast(rawParam.get("name")));
54-
appInputParam.setType(ObjectUtils.cast(rawParam.get("type")));
55-
appInputParam.setDescription(ObjectUtils.cast(rawParam.get("description")));
56-
appInputParam.setRequired(ObjectUtils.cast(rawParam.getOrDefault("isRequired", true)));
57-
appInputParam.setVisible(ObjectUtils.cast(rawParam.getOrDefault("isVisible", true)));
58-
Integer stringMaxLength = cast(rawParam.getOrDefault("stringMaxLength", 500));
59-
appInputParam.setStringMaxLength(stringMaxLength);
60-
Map<InputParamType, Predicate<Object>> paramTypePredicateMap
61-
= MapBuilder.<InputParamType, Predicate<Object>>get()
62-
.put(InputParamType.STRING_TYPE,
63-
v -> v instanceof String && lengthBetween(cast(v), 1, stringMaxLength, true, true))
64-
.put(InputParamType.BOOLEAN_TYPE, v -> v instanceof Boolean)
65-
.put(InputParamType.INTEGER_TYPE,
66-
v -> v instanceof Integer && ObjectUtils.between((int) v, -999999999, 999999999))
67-
.put(InputParamType.NUMBER_TYPE, AppInputParam::isValidNumber)
58+
if (rawParam == null) {
59+
throw new IllegalArgumentException("rawParam cannot be null");
60+
}
61+
62+
AppearanceConfig appearance = AppearanceConfig.from(rawParam);
63+
String type = cast(rawParam.get("type"));
64+
65+
return AppInputParam.builder()
66+
.name(cast(rawParam.get("name")))
67+
.type(type)
68+
.displayName(cast(rawParam.get("displayName")))
69+
.isRequired(cast(rawParam.getOrDefault("isRequired", true)))
70+
.isVisible(cast(rawParam.getOrDefault("isVisible", true)))
71+
.stringMaxLength(appearance.getStringMaxLength())
72+
.validator(createValidator(appearance, type))
6873
.build();
69-
appInputParam.setParamTypePredicateMap(paramTypePredicateMap);
70-
return appInputParam;
7174
}
7275

73-
private static boolean isValidNumber(Object value) {
76+
/**
77+
* 校验数据
78+
*
79+
* @param dataMap 数据集合
80+
* @throws AippParamException 当参数无效时抛出
81+
*/
82+
public void validate(Map<String, Object> dataMap) {
83+
if (dataMap == null) {
84+
throw new IllegalArgumentException("dataMap cannot be null");
85+
}
86+
87+
Object value = dataMap.get(this.name);
88+
89+
// 校验必填项
90+
if (this.isRequired && value == null) {
91+
throw new AippParamException(INPUT_PARAM_IS_INVALID, this.displayName);
92+
}
93+
94+
// 如果值为null且非必填,则跳过后续校验
95+
if (value == null) {
96+
return;
97+
}
98+
99+
// 使用预构建的校验器
100+
if (this.validator != null && !this.validator.test(value)) {
101+
throw new AippParamException(INPUT_PARAM_IS_INVALID, this.displayName);
102+
}
103+
}
104+
105+
/**
106+
* 根据外观配置创建校验器
107+
*/
108+
private static Predicate<Object> createValidator(AppearanceConfig config, String type) {
109+
String displayType = config.getDisplayType();
110+
111+
if (displayType == null) {
112+
return createDefaultValidator(type);
113+
}
114+
115+
return switch (displayType) {
116+
case "textInput" -> createStringValidator(config.getStringMaxLength());
117+
case "numberInput" -> createNumberValidator(config.getMinValue(), config.getMaxValue());
118+
case "dropdown" -> createDropdownValidator(config.getOptions());
119+
case "switch" -> createBooleanValidator();
120+
case "multiselect" -> createArrayValidator(config.getOptions());
121+
default -> createDefaultValidator(type);
122+
};
123+
}
124+
125+
private static Predicate<Object> createStringValidator(Integer maxLength) {
126+
return value -> {
127+
if (!(value instanceof String str)) {
128+
return false;
129+
}
130+
// 如果没有设置 maxLength,则不限制长度
131+
return maxLength == null || lengthBetween(str, 0, maxLength, true, true);
132+
};
133+
}
134+
135+
private static Predicate<Object> createNumberValidator(BigDecimal minValue, BigDecimal maxValue) {
136+
return value -> {
137+
if (!(value instanceof Number)) {
138+
return false;
139+
}
140+
141+
try {
142+
BigDecimal numberValue = new BigDecimal(value.toString());
143+
144+
if (minValue != null && numberValue.compareTo(minValue) < 0) {
145+
return false;
146+
}
147+
148+
if (maxValue != null && numberValue.compareTo(maxValue) > 0) {
149+
return false;
150+
}
151+
152+
return true;
153+
} catch (NumberFormatException e) {
154+
return false;
155+
}
156+
};
157+
}
158+
159+
private static Predicate<Object> createDropdownValidator(List<String> options) {
160+
return value -> options != null &&
161+
!options.isEmpty() &&
162+
options.contains(String.valueOf(value));
163+
}
164+
165+
private static Predicate<Object> createArrayValidator(List<String> options) {
166+
return value -> {
167+
if (options == null || options.isEmpty()) {
168+
return false;
169+
}
170+
171+
if (!(value instanceof Collection<?> valueCollection)) {
172+
return false;
173+
}
174+
175+
return valueCollection.stream()
176+
.map(String::valueOf)
177+
.allMatch(options::contains);
178+
};
179+
}
180+
181+
private static Predicate<Object> createBooleanValidator() {
182+
return value -> value instanceof Boolean;
183+
}
184+
185+
private static Predicate<Object> createDefaultValidator(String type) {
186+
if (type == null) {
187+
return value -> false; // 如果类型未定义,则校验失败
188+
}
189+
190+
return switch (type.toLowerCase()) {
191+
case "string" -> value -> {
192+
if (!(value instanceof String str)) {
193+
return false;
194+
}
195+
return lengthBetween(str, 1, DEFAULT_STRING_MAX_LENGTH, true, true);
196+
};
197+
198+
case "integer"-> value -> {
199+
if (value instanceof Integer) {
200+
return ObjectUtils.between((int) value, -999999999, 999999999);
201+
}
202+
return false;
203+
};
204+
205+
case "number" -> value -> {
206+
if (value instanceof Number) {
207+
return isValidDecimalNumber(value);
208+
}
209+
return false;
210+
};
211+
212+
case "boolean" -> value -> value instanceof Boolean;
213+
214+
default -> value -> true;
215+
};
216+
}
217+
218+
private static boolean isValidDecimalNumber(Object value) {
74219
if (!(value instanceof Number)) {
75220
return false;
76221
}
77-
BigDecimal numberValue = new BigDecimal(value.toString());
78-
if (numberValue.compareTo(new BigDecimal("-999999999.99")) < 0
79-
|| numberValue.compareTo(new BigDecimal("999999999.99")) > 0) {
222+
223+
try {
224+
BigDecimal numberValue = new BigDecimal(value.toString());
225+
226+
// 检查数值范围
227+
if (numberValue.compareTo(DEFAULT_MIN_NUMBER) < 0 ||
228+
numberValue.compareTo(DEFAULT_MAX_NUMBER) > 0) {
229+
return false;
230+
}
231+
232+
// 检查小数位数
233+
return numberValue.scale() <= MAX_DECIMAL_PLACES;
234+
} catch (NumberFormatException e) {
80235
return false;
81236
}
82-
int scale = numberValue.scale();
83-
return scale <= 2;
84237
}
85238

86239
/**
87-
* 校验数据.
88-
*
89-
* @param dataMap 数据集合.
240+
* 外观配置内部类,用于封装外观相关参数
90241
*/
91-
public void validate(Map<String, Object> dataMap) {
92-
String paramName = this.getName();
93-
if (this.isRequired()) {
94-
Validation.notNull(cast(dataMap.get(paramName)),
95-
() -> new AippParamException(INPUT_PARAM_IS_INVALID, paramName));
242+
@Getter
243+
private static class AppearanceConfig {
244+
private final String displayType;
245+
private final Integer stringMaxLength;
246+
private final BigDecimal minValue;
247+
private final BigDecimal maxValue;
248+
private final List<String> options;
249+
250+
private AppearanceConfig(String displayType, Integer stringMaxLength,
251+
BigDecimal minValue, BigDecimal maxValue, List<String> options) {
252+
this.displayType = displayType;
253+
this.stringMaxLength = stringMaxLength;
254+
this.minValue = minValue;
255+
this.maxValue = maxValue;
256+
this.options = options;
96257
}
97-
if (dataMap.get(paramName) == null) {
98-
return;
258+
259+
public static AppearanceConfig from(Map<String, Object> rawParam) {
260+
Map<String, Object> appearance = cast(rawParam.get("appearance"));
261+
262+
if (appearance == null) {
263+
return new AppearanceConfig(null, null, null, null, null);
264+
}
265+
266+
String displayType = cast(appearance.get("displayType"));
267+
Integer stringMaxLength = cast(appearance.get("maxLength"));
268+
269+
BigDecimal minValue = parseNumber(appearance.get("minValue"));
270+
BigDecimal maxValue = parseNumber(appearance.get("maxValue"));
271+
List<String> options = cast(appearance.get("options"));
272+
273+
return new AppearanceConfig(displayType, stringMaxLength, minValue, maxValue, options);
99274
}
100275

101-
Object v = dataMap.get(this.getName());
102-
Predicate<Object> predicate = paramTypePredicateMap.get(InputParamType.getParamType(this.getType()));
103-
if (!predicate.test(v)) {
104-
throw new AippParamException(INPUT_PARAM_IS_INVALID, paramName);
276+
private static BigDecimal parseNumber(Object value) {
277+
if (value == null) {
278+
return null;
279+
}
280+
try {
281+
return new BigDecimal(value.toString());
282+
} catch (NumberFormatException e) {
283+
return null;
284+
}
105285
}
106286
}
107287
}

app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/util/FlowUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public static List<AppInputParam> getAppInputParams(FlowsService service, String
3737
AppInputParam param = new AppInputParam();
3838
param.setName(ObjectUtils.cast(rawParam.get("name")));
3939
param.setType(ObjectUtils.cast(rawParam.get("type")));
40-
param.setDescription(ObjectUtils.cast(rawParam.get("description")));
40+
param.setDisplayName(ObjectUtils.cast(rawParam.get("displayName")));
4141
param.setRequired(ObjectUtils.cast(rawParam.getOrDefault("isRequired", true)));
4242
param.setVisible(ObjectUtils.cast(rawParam.getOrDefault("isVisible", true)));
4343
return param;

0 commit comments

Comments
 (0)