增加formily json schema生成

This commit is contained in:
dengqichen 2025-01-15 16:52:36 +08:00
parent 5cd9f4c4d3
commit 9d1f77c069
4 changed files with 212 additions and 17 deletions

View File

@ -11,7 +11,7 @@ public @interface FormilyField {
// 基础属性 // 基础属性
String title(); // 字段标题 String title(); // 字段标题
String description() default ""; // 字段描述 String description() default ""; // 字段描述
String type() default "string"; // 字段类型(string/number/boolean/array/object) String type() default "string"; // 字段类型(string/number/boolean/array/object/map)
// 组件属性 // 组件属性
String component() default "Input"; // 组件类型 String component() default "Input"; // 组件类型
@ -29,4 +29,7 @@ public @interface FormilyField {
String pattern() default "editable"; // 展示模式(editable/disabled/readOnly) String pattern() default "editable"; // 展示模式(editable/disabled/readOnly)
String display() default "visible"; // 显示模式(visible/hidden/none) String display() default "visible"; // 显示模式(visible/hidden/none)
boolean hidden() default false; // 是否隐藏 boolean hidden() default false; // 是否隐藏
// Map类型配置
FormilyMapConfig mapConfig() default @FormilyMapConfig; // Map配置
} }

View File

@ -0,0 +1,65 @@
package com.qqchen.deploy.backend.framework.annotation.formily;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface FormilyMapConfig {
/**
* 键的标题
*/
String keyTitle() default "";
/**
* 值的标题
*/
String valueTitle() default "";
/**
* 键的组件类型
*/
String keyComponent() default "Input";
/**
* 值的组件类型
*/
String valueComponent() default "Input";
/**
* 键的组件属性
*/
FormilyComponentProps keyProps() default @FormilyComponentProps;
/**
* 值的组件属性
*/
FormilyComponentProps valueProps() default @FormilyComponentProps;
/**
* 是否允许添加
*/
boolean allowAdd() default true;
/**
* 是否允许删除
*/
boolean allowRemove() default true;
/**
* 是否允许自定义键
*/
boolean allowCustomKey() default true;
/**
* 添加按钮文本
*/
String addText() default "添加";
/**
* 删除按钮文本
*/
String removeText() default "删除";
}

View File

@ -108,12 +108,64 @@ public class FormilySchemaFactory {
// 组件属性 // 组件属性
fieldSchema.put("x-decorator", field.decorator()); fieldSchema.put("x-decorator", field.decorator());
fieldSchema.put("x-component", field.component()); if ("map".equals(field.type())) {
// 对于Map类型使用ArrayItems组件
fieldSchema.put("x-component", "ArrayItems");
// 生成Map配置
ObjectNode componentProps = generateMapComponentProps(field.mapConfig());
if (componentProps.size() > 0) {
fieldSchema.set("x-component-props", componentProps);
}
// 组件属性配置 // 生成Map项的Schema
ObjectNode componentProps = generateComponentProps(field.props(), field.component()); ObjectNode items = fieldSchema.putObject("items");
if (componentProps.size() > 0) { items.put("type", "object");
fieldSchema.set("x-component-props", componentProps); items.put("x-component", "ArrayItems.Item");
// 生成Map项的属性Schema
ObjectNode properties = items.putObject("properties");
// 键的Schema
ObjectNode keySchema = properties.putObject("key");
keySchema.put("type", "string");
keySchema.put("title", field.mapConfig().keyTitle());
keySchema.put("x-decorator", "FormItem");
keySchema.put("x-component", field.mapConfig().keyComponent());
ObjectNode keyProps = generateComponentProps(field.mapConfig().keyProps(), field.mapConfig().keyComponent());
if (keyProps.size() > 0) {
keySchema.set("x-component-props", keyProps);
}
// 值的Schema
ObjectNode valueSchema = properties.putObject("value");
valueSchema.put("type", "string");
valueSchema.put("title", field.mapConfig().valueTitle());
valueSchema.put("x-decorator", "FormItem");
valueSchema.put("x-component", field.mapConfig().valueComponent());
ObjectNode valueProps = generateComponentProps(field.mapConfig().valueProps(), field.mapConfig().valueComponent());
if (valueProps.size() > 0) {
valueSchema.set("x-component-props", valueProps);
}
// 操作按钮
ObjectNode operationSchema = properties.putObject("operations");
operationSchema.put("type", "void");
operationSchema.put("x-component", "ArrayItems.Remove");
operationSchema.put("x-component-props", field.mapConfig().removeText());
// 添加按钮
ObjectNode addition = fieldSchema.putObject("properties").putObject("addition");
addition.put("type", "void");
addition.put("title", field.mapConfig().addText());
addition.put("x-component", "ArrayItems.Addition");
} else {
fieldSchema.put("x-component", field.component());
// 组件属性配置
ObjectNode componentProps = generateComponentProps(field.props(), field.component());
if (componentProps.size() > 0) {
fieldSchema.set("x-component-props", componentProps);
}
} }
// 装饰器属性配置 // 装饰器属性配置
@ -146,6 +198,16 @@ public class FormilySchemaFactory {
return fieldSchema; return fieldSchema;
} }
private static ObjectNode generateMapComponentProps(FormilyMapConfig config) {
ObjectNode props = objectMapper.createObjectNode();
props.put("allowAdd", config.allowAdd());
props.put("allowRemove", config.allowRemove());
props.put("allowCustomKey", config.allowCustomKey());
return props;
}
private static ObjectNode generateComponentProps(FormilyComponentProps props, String componentType) { private static ObjectNode generateComponentProps(FormilyComponentProps props, String componentType) {
ObjectNode node = objectMapper.createObjectNode(); ObjectNode node = objectMapper.createObjectNode();

View File

@ -2,6 +2,9 @@ package com.qqchen.deploy.backend.framework.annotation.formily;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
public class FormilySchemaFactoryTest { public class FormilySchemaFactoryTest {
@ -9,12 +12,12 @@ public class FormilySchemaFactoryTest {
@Test @Test
public void testGenerateSchema() { public void testGenerateSchema() {
JsonNode schema = FormilySchemaFactory.generateSchema(TestForm.class); JsonNode schema = FormilySchemaFactory.generateSchema(TestForm.class);
// 验证基本结构 // 验证基本结构
assertEquals("object", schema.get("type").asText()); assertEquals("object", schema.get("type").asText());
assertEquals("测试表单", schema.get("name").asText()); assertEquals("测试表单", schema.get("name").asText());
assertTrue(schema.has("properties")); assertTrue(schema.has("properties"));
// 验证字段A // 验证字段A
JsonNode fieldA = schema.get("properties").get("a"); JsonNode fieldA = schema.get("properties").get("a");
assertEquals("string", fieldA.get("type").asText()); assertEquals("string", fieldA.get("type").asText());
@ -24,14 +27,14 @@ public class FormilySchemaFactoryTest {
assertEquals("editable", fieldA.get("x-pattern").asText()); assertEquals("editable", fieldA.get("x-pattern").asText());
assertEquals("visible", fieldA.get("x-display").asText()); assertEquals("visible", fieldA.get("x-display").asText());
assertFalse(fieldA.get("x-hidden").asBoolean()); assertFalse(fieldA.get("x-hidden").asBoolean());
// 验证组件属性 // 验证组件属性
JsonNode propsA = fieldA.get("x-component-props"); JsonNode propsA = fieldA.get("x-component-props");
assertEquals("/api/options/A", propsA.get("api").asText()); assertEquals("/api/options/A", propsA.get("api").asText());
assertEquals("name", propsA.get("labelField").asText()); assertEquals("name", propsA.get("labelField").asText());
assertEquals("id", propsA.get("valueField").asText()); assertEquals("id", propsA.get("valueField").asText());
assertTrue(propsA.get("allowClear").asBoolean()); assertTrue(propsA.get("allowClear").asBoolean());
// 验证字段B的联动 // 验证字段B的联动
JsonNode fieldB = schema.get("properties").get("b"); JsonNode fieldB = schema.get("properties").get("b");
JsonNode reactionsB = fieldB.get("x-reactions"); JsonNode reactionsB = fieldB.get("x-reactions");
@ -39,12 +42,12 @@ public class FormilySchemaFactoryTest {
JsonNode reactionB = reactionsB.get(0); JsonNode reactionB = reactionsB.get(0);
assertTrue(reactionB.get("dependencies").isArray()); assertTrue(reactionB.get("dependencies").isArray());
assertEquals("a", reactionB.get("dependencies").get(0).asText()); assertEquals("a", reactionB.get("dependencies").get(0).asText());
JsonNode fulfillB = reactionB.get("fulfill"); JsonNode fulfillB = reactionB.get("fulfill");
JsonNode stateB = fulfillB.get("state"); JsonNode stateB = fulfillB.get("state");
assertEquals("{{$fetch('/api/v1/jenkins-view/list?externalSystemId=' + $deps.a).then(data => data.data)}}", assertEquals("{{$fetch('/api/v1/jenkins-view/list?externalSystemId=' + $deps.a).then(data => data.data)}}",
stateB.get("dataSource").asText()); stateB.get("dataSource").asText());
// 验证字段C的联动 // 验证字段C的联动
JsonNode fieldC = schema.get("properties").get("c"); JsonNode fieldC = schema.get("properties").get("c");
JsonNode reactionsC = fieldC.get("x-reactions"); JsonNode reactionsC = fieldC.get("x-reactions");
@ -54,10 +57,10 @@ public class FormilySchemaFactoryTest {
assertEquals(2, reactionC.get("dependencies").size()); assertEquals(2, reactionC.get("dependencies").size());
assertEquals("a", reactionC.get("dependencies").get(0).asText()); assertEquals("a", reactionC.get("dependencies").get(0).asText());
assertEquals("b", reactionC.get("dependencies").get(1).asText()); assertEquals("b", reactionC.get("dependencies").get(1).asText());
JsonNode fulfillC = reactionC.get("fulfill"); JsonNode fulfillC = reactionC.get("fulfill");
JsonNode stateC = fulfillC.get("state"); JsonNode stateC = fulfillC.get("state");
assertEquals("{{$fetch('/api/v1/jenkins-job/list?externalSystemId=' + $deps.a + '&viewId=' + $deps.b).then(data => data.data)}}", assertEquals("{{$fetch('/api/v1/jenkins-job/list?externalSystemId=' + $deps.a + '&viewId=' + $deps.b).then(data => data.data)}}",
stateC.get("dataSource").asText()); stateC.get("dataSource").asText());
// 验证编辑器字段 // 验证编辑器字段
@ -65,7 +68,7 @@ public class FormilySchemaFactoryTest {
assertEquals("string", fieldScript.get("type").asText()); assertEquals("string", fieldScript.get("type").asText());
assertEquals("Pipeline script", fieldScript.get("title").asText()); assertEquals("Pipeline script", fieldScript.get("title").asText());
assertEquals("MonacoEditor", fieldScript.get("x-component").asText()); assertEquals("MonacoEditor", fieldScript.get("x-component").asText());
// 验证编辑器属性 // 验证编辑器属性
JsonNode scriptProps = fieldScript.get("x-component-props"); JsonNode scriptProps = fieldScript.get("x-component-props");
JsonNode options = scriptProps.get("options"); JsonNode options = scriptProps.get("options");
@ -79,7 +82,50 @@ public class FormilySchemaFactoryTest {
assertTrue(options.get("automaticLayout").asBoolean()); assertTrue(options.get("automaticLayout").asBoolean());
assertTrue(options.get("folding").asBoolean()); assertTrue(options.get("folding").asBoolean());
assertEquals("请输入Pipeline脚本", scriptProps.get("placeholder").asText()); assertEquals("请输入Pipeline脚本", scriptProps.get("placeholder").asText());
// 验证Map字段
JsonNode mapField = schema.get("properties").get("envVars");
assertEquals("map", mapField.get("type").asText());
assertEquals("环境变量", mapField.get("title").asText());
assertEquals("ArrayItems", mapField.get("x-component").asText());
// 验证Map项配置
JsonNode items = mapField.get("items");
assertEquals("object", items.get("type").asText());
assertEquals("ArrayItems.Item", items.get("x-component").asText());
// 验证键值配置
JsonNode properties = items.get("properties");
// 验证键配置
JsonNode keySchema = properties.get("key");
assertEquals("string", keySchema.get("type").asText());
assertEquals("变量名", keySchema.get("title").asText());
assertEquals("Select", keySchema.get("x-component").asText());
// 验证键的组件属性
JsonNode keyProps = keySchema.get("x-component-props");
assertEquals("/api/v1/env-vars/keys", keyProps.get("api").asText());
assertTrue(keyProps.get("showSearch").asBoolean());
assertTrue(keyProps.get("allowClear").asBoolean());
// 验证值配置
JsonNode valueSchema = properties.get("value");
assertEquals("string", valueSchema.get("type").asText());
assertEquals("变量值", valueSchema.get("title").asText());
assertEquals("Input", valueSchema.get("x-component").asText());
// 验证操作按钮
JsonNode operations = properties.get("operations");
assertEquals("void", operations.get("type").asText());
assertEquals("ArrayItems.Remove", operations.get("x-component").asText());
// 验证添加按钮
JsonNode addition = mapField.get("properties").get("addition");
assertEquals("void", addition.get("type").asText());
assertEquals("添加环境变量", addition.get("title").asText());
assertEquals("ArrayItems.Addition", addition.get("x-component").asText());
// 打印生成的Schema以便查看 // 打印生成的Schema以便查看
System.out.println(schema.toPrettyString()); System.out.println(schema.toPrettyString());
} }
@ -177,4 +223,23 @@ class TestForm {
} }
) )
private String script; private String script;
@FormilyField(
title = "环境变量",
type = "map",
mapConfig = @FormilyMapConfig(
keyTitle = "变量名",
valueTitle = "变量值",
keyComponent = "Select",
valueComponent = "Input",
keyProps = @FormilyComponentProps(
api = "/api/v1/env-vars/keys",
showSearch = true,
allowClear = true
),
addText = "添加环境变量",
allowCustomKey = true
)
)
private Map<String, String> envVars;
} }