大声道撒旦

This commit is contained in:
dengqichen 2024-12-26 18:05:06 +08:00
parent 53c61ad0c8
commit bfb7c7b6da
16 changed files with 538 additions and 189 deletions

View File

@ -0,0 +1,44 @@
package com.qqchen.deploy.backend.deploy.api;
import com.qqchen.deploy.backend.deploy.dto.BuildConfigDefinedDTO;
import com.qqchen.deploy.backend.deploy.dto.DeployAppConfigDTO;
import com.qqchen.deploy.backend.deploy.entity.DeployAppConfig;
import com.qqchen.deploy.backend.deploy.query.DeployAppConfigQuery;
import com.qqchen.deploy.backend.deploy.service.IDeployAppConfigService;
import com.qqchen.deploy.backend.framework.api.Response;
import com.qqchen.deploy.backend.framework.controller.BaseController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 应用配置控制器
*/
@Slf4j
@RestController
@RequestMapping("/api/v1/deploy-app-config")
@Tag(name = "应用配置管理", description = "应用配置管理相关接口")
public class DeployAppConfigApiController extends BaseController<DeployAppConfig, DeployAppConfigDTO, Long, DeployAppConfigQuery> {
@Resource
private IDeployAppConfigService deployAppConfigService;
@Operation(summary = "获取构建类型Schema定义")
@GetMapping("/defined")
public Response<List<BuildConfigDefinedDTO>> defined() {
return Response.success(deployAppConfigService.defined());
}
@Override
protected void exportData(HttpServletResponse response, List<DeployAppConfigDTO> data) {
}
}

View File

@ -0,0 +1,13 @@
package com.qqchen.deploy.backend.deploy.converter;
import com.qqchen.deploy.backend.deploy.dto.DeployAppConfigDTO;
import com.qqchen.deploy.backend.deploy.entity.DeployAppConfig;
import com.qqchen.deploy.backend.framework.converter.BaseConverter;
import org.mapstruct.Mapper;
/**
* 应用配置转换器
*/
@Mapper(config = BaseConverter.class)
public interface DeployAppConfigConverter extends BaseConverter<DeployAppConfig, DeployAppConfigDTO> {
}

View File

@ -0,0 +1,27 @@
package com.qqchen.deploy.backend.deploy.dto;
import com.fasterxml.jackson.databind.JsonNode;
import com.qqchen.deploy.backend.deploy.enums.BuildTypeEnum;
import com.qqchen.deploy.backend.deploy.enums.DevelopmentLanguageTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "部署配置定义")
public class BuildConfigDefinedDTO {
@Schema(description = "编码")
private String code;
@Schema(description = "名称")
private String name;
@Schema(description = "部署类型类型")
private BuildTypeEnum buildType;
private DevelopmentLanguageTypeEnum languageType;
@Schema(description = "JSON SCHEMA")
private JsonNode buildVariablesSchema;
}

View File

@ -0,0 +1,29 @@
package com.qqchen.deploy.backend.deploy.dto;
import com.fasterxml.jackson.databind.JsonNode;
import com.qqchen.deploy.backend.deploy.enums.BuildTypeEnum;
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 应用配置DTO
*/
@Data
@Schema(description = "应用配置")
@EqualsAndHashCode(callSuper = true)
public class DeployAppConfigDTO extends BaseDTO {
@Schema(description = "环境ID")
private Long environmentId;
@Schema(description = "应用ID")
private Long applicationId;
@Schema(description = "构建类型")
private BuildTypeEnum buildType;
@Schema(description = "构建变量")
private JsonNode buildVariables;
}

View File

@ -0,0 +1,19 @@
package com.qqchen.deploy.backend.deploy.dto.variables;
import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty;
import lombok.Data;
/**
* Jenkins构建变量
*/
@Data
public class JenkinsBaseBuildVariables {
@SchemaProperty(
title = "分支名称",
description = "Git分支名称",
required = true
)
private String branch;
}

View File

@ -1,4 +0,0 @@
package com.qqchen.deploy.backend.deploy.dto.variables;
public class JenkinsBuildVariables {
}

View File

@ -0,0 +1,12 @@
package com.qqchen.deploy.backend.deploy.dto.variables;
import lombok.Data;
/**
* Jenkins构建变量
*/
@Data
public class JenkinsJavaBuildVariables extends JenkinsBaseBuildVariables {
}

View File

@ -0,0 +1,11 @@
package com.qqchen.deploy.backend.deploy.dto.variables;
import lombok.Data;
/**
* Jenkins构建变量
*/
@Data
public class JenkinsNodeJsBuildVariables extends JenkinsBaseBuildVariables {
}

View File

@ -1,5 +1,7 @@
package com.qqchen.deploy.backend.deploy.enums;
import com.fasterxml.jackson.annotation.JsonValue;
import com.qqchen.deploy.backend.deploy.dto.variables.JenkinsJavaBuildVariables;
import lombok.Getter;
/**
@ -7,14 +9,71 @@ import lombok.Getter;
*/
@Getter
public enum BuildTypeEnum {
JENKINS("Jenkins构建"),
GITLAB_RUNNER("GitLab Runner构建"),
GITHUB_ACTION("GitHub Action构建");
JENKINS(
"JENKINS",
"Jenkins构建",
new DevelopmentLanguageTypeEnum[] {
DevelopmentLanguageTypeEnum.JAVA,
DevelopmentLanguageTypeEnum.NODE_JS,
DevelopmentLanguageTypeEnum.GO,
DevelopmentLanguageTypeEnum.PYTHON
},
new Class[] {
JenkinsJavaBuildVariables.class,
null,
null,
null
},
"Jenkins构建"
),
GITLAB_RUNNER(
"GITLAB_RUNNER",
"GitLab Runner构建",
null,
null,
"GitLab Runner构建"
),
GITHUB_ACTION(
"GITHUB_ACTION",
"GitHub Action构建",
null,
null,
"GitHub Action构建"
);
@JsonValue
private final String code;
private final String name;
private final DevelopmentLanguageTypeEnum[] supportedLanguages;
private final Class<?>[] buildVariables;
private final String description;
BuildTypeEnum(String description) {
BuildTypeEnum(String code, String name, DevelopmentLanguageTypeEnum[] supportedLanguages, Class<?>[] buildVariables, String description) {
this.code = code;
this.name = name;
this.supportedLanguages = supportedLanguages;
this.buildVariables = buildVariables;
this.description = description;
}
/**
* 根据编码查找对应的枚举
*
* @param code 构建类型编码
* @return 对应的枚举实例
* @throws IllegalArgumentException 当找不到对应的枚举值时抛出
*/
public static BuildTypeEnum fromValue(String code) {
for (BuildTypeEnum type : values()) {
if (type.code.equals(code)) {
return type;
}
}
throw new IllegalArgumentException("Unknown BuildType code: " + code);
}
}

View File

@ -0,0 +1,29 @@
package com.qqchen.deploy.backend.deploy.query;
import com.qqchen.deploy.backend.deploy.enums.BuildTypeEnum;
import com.qqchen.deploy.backend.framework.annotation.QueryField;
import com.qqchen.deploy.backend.framework.query.BaseQuery;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 应用配置查询对象
*/
@Data
@Schema(description = "应用配置查询")
@EqualsAndHashCode(callSuper = true)
public class DeployAppConfigQuery extends BaseQuery {
@Schema(description = "环境ID")
@QueryField(field = "environmentId")
private Long environmentId;
@Schema(description = "应用ID")
@QueryField(field = "applicationId")
private Long applicationId;
@Schema(description = "构建类型")
@QueryField(field = "buildType")
private BuildTypeEnum buildType;
}

View File

@ -0,0 +1,13 @@
package com.qqchen.deploy.backend.deploy.repository;
import com.qqchen.deploy.backend.deploy.entity.DeployAppConfig;
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
import org.springframework.stereotype.Repository;
/**
* 应用配置仓库接口
*/
@Repository
public interface IDeployAppConfigRepository extends IBaseRepository<DeployAppConfig, Long> {
}

View File

@ -0,0 +1,23 @@
package com.qqchen.deploy.backend.deploy.service;
import com.qqchen.deploy.backend.deploy.dto.BuildConfigDefinedDTO;
import com.qqchen.deploy.backend.deploy.dto.DeployAppConfigDTO;
import com.qqchen.deploy.backend.deploy.entity.DeployAppConfig;
import com.qqchen.deploy.backend.deploy.query.DeployAppConfigQuery;
import com.qqchen.deploy.backend.framework.service.IBaseService;
import com.qqchen.deploy.backend.workflow.dto.WorkflowNodeTypeDefinedDTO;
import java.util.List;
/**
* 应用配置服务接口
*/
public interface IDeployAppConfigService extends IBaseService<DeployAppConfig, DeployAppConfigDTO, DeployAppConfigQuery, Long> {
/**
* 获取构建类型Schema定义
*
* @return Schema定义列表
*/
List<BuildConfigDefinedDTO> defined();
}

View File

@ -0,0 +1,56 @@
package com.qqchen.deploy.backend.deploy.service.impl;
import com.qqchen.deploy.backend.deploy.dto.BuildConfigDefinedDTO;
import com.qqchen.deploy.backend.deploy.dto.DeployAppConfigDTO;
import com.qqchen.deploy.backend.deploy.entity.DeployAppConfig;
import com.qqchen.deploy.backend.deploy.enums.BuildTypeEnum;
import com.qqchen.deploy.backend.deploy.enums.DevelopmentLanguageTypeEnum;
import com.qqchen.deploy.backend.deploy.query.DeployAppConfigQuery;
import com.qqchen.deploy.backend.deploy.service.IDeployAppConfigService;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import static com.qqchen.deploy.backend.workflow.util.GenerateSchemaUtils.generateSchema;
/**
* 应用配置服务实现类
*/
@Slf4j
@Service
public class DeployAppConfigServiceImpl extends BaseServiceImpl<DeployAppConfig, DeployAppConfigDTO, DeployAppConfigQuery, Long> implements IDeployAppConfigService {
@Override
public List<BuildConfigDefinedDTO> defined() {
List<BuildConfigDefinedDTO> result = new ArrayList<>();
for (BuildTypeEnum buildType : BuildTypeEnum.values()) {
try {
BuildConfigDefinedDTO definedDTO = new BuildConfigDefinedDTO();
definedDTO.setCode(buildType.getCode());
definedDTO.setName(buildType.getName());
// 获取支持的语言和对应的构建变量类
DevelopmentLanguageTypeEnum[] languages = buildType.getSupportedLanguages();
Class<?>[] buildVariablesClasses = buildType.getBuildVariables();
definedDTO.setBuildType(buildType);
// 如果支持的语言不为空则处理每种语言对应的Schema
if (languages != null && buildVariablesClasses != null) {
for (int i = 0; i < languages.length; i++) {
if (buildVariablesClasses[i] != null) {
definedDTO.setLanguageType(languages[i]);
definedDTO.setBuildVariablesSchema(generateSchema(buildVariablesClasses[i]));
result.add(definedDTO);
}
}
}
} catch (Exception e) {
log.error("Error processing build type: " + buildType, e);
}
}
return result;
}
}

View File

@ -30,6 +30,8 @@ import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty;
import com.qqchen.deploy.backend.workflow.annotation.SchemaPropertyDataSource;
import com.qqchen.deploy.backend.workflow.annotation.SchemaPropertyDataSourceParam;
import static com.qqchen.deploy.backend.workflow.util.GenerateSchemaUtils.generateSchema;
/**
* 工作流节点定义服务实现
*/
@ -125,184 +127,4 @@ public class WorkflowNodeDefinitionServiceImpl extends BaseServiceImpl<WorkflowN
return result;
}
private ObjectNode generateSchema(Class<?> cls) {
ObjectMapper mapper = new ObjectMapper();
ObjectNode schema = mapper.createObjectNode();
schema.put("type", "object");
// 处理属性
ObjectNode properties = schema.putObject("properties");
List<String> required = new ArrayList<>();
// 获取所有字段包括父类的字段
List<Field> allFields = getAllFields(cls);
// 遍历所有字段
for (Field field : allFields) {
SchemaProperty annotation = field.getAnnotation(SchemaProperty.class);
if (annotation != null) {
ObjectNode property = properties.putObject(field.getName());
// 设置基本属性
String jsonType = getJsonSchemaType(field.getType());
property.put("type", jsonType);
// 从注解中获取属性
if (!annotation.title().isEmpty()) {
property.put("title", annotation.title());
}
if (!annotation.description().isEmpty()) {
property.put("description", annotation.description());
}
if (!annotation.format().isEmpty()) {
property.put("format", annotation.format());
}
if (annotation.required()) {
required.add(field.getName());
}
if (annotation.defaultValue().length() > 0) {
if (jsonType.equals("integer")) {
property.put("default", Integer.parseInt(annotation.defaultValue()));
} else if (jsonType.equals("number")) {
property.put("default", Double.parseDouble(annotation.defaultValue()));
} else {
property.put("default", annotation.defaultValue());
}
}
// 处理枚举
if (annotation.enumValues().length > 0) {
ArrayNode enumNode = property.putArray("enum");
for (String value : annotation.enumValues()) {
enumNode.add(value);
}
if (annotation.enumNames().length > 0) {
ArrayNode enumNamesNode = property.putArray("enumNames");
for (String name : annotation.enumNames()) {
enumNamesNode.add(name);
}
}
}
// 处理数组类型
if (List.class.isAssignableFrom(field.getType())) {
ObjectNode items = property.putObject("items");
items.put("type", "string");
}
// 处理Map类型
if (Map.class.isAssignableFrom(field.getType())) {
ObjectNode additionalProperties = property.putObject("additionalProperties");
additionalProperties.put("type", "string");
}
// 处理嵌套对象
if (property.get("type").asText().equals("object")
&& !Map.class.isAssignableFrom(field.getType())
&& !field.getType().getName().startsWith("java.")) {
ObjectNode nestedSchema = generateSchema(field.getType());
if (nestedSchema.has("properties")) {
property.set("properties", nestedSchema.get("properties"));
}
if (nestedSchema.has("required")) {
property.set("required", nestedSchema.get("required"));
}
}
// 处理数据源
SchemaPropertyDataSource dataSource = annotation.dataSource();
if (dataSource != null && !dataSource.type().isEmpty()) {
processDataSource(property, dataSource);
}
}
}
// 添加required字段
if (!required.isEmpty()) {
ArrayNode requiredNode = schema.putArray("required");
required.forEach(requiredNode::add);
}
return schema;
}
/**
* 处理SchemaPropertyDataSource注解生成数据源配置
*
* @param property 当前属性节点
* @param dataSource 数据源注解
*/
private void processDataSource(ObjectNode property, SchemaPropertyDataSource dataSource) {
ObjectNode dataSourceNode = property.putObject("dataSource");
// 处理基本属性
dataSourceNode.put("type", dataSource.type());
dataSourceNode.put("url", dataSource.url());
dataSourceNode.put("valueField", dataSource.valueField());
dataSourceNode.put("labelField", dataSource.labelField());
// 处理依赖字段
String[] dependsOn = dataSource.dependsOn();
if (dependsOn != null && dependsOn.length > 0) {
ArrayNode dependsOnNode = dataSourceNode.putArray("dependsOn");
for (String depend : dependsOn) {
dependsOnNode.add(depend);
}
}
// 处理请求参数
SchemaPropertyDataSourceParam[] params = dataSource.params();
if (params != null && params.length > 0) {
ObjectNode paramsNode = dataSourceNode.putObject("params");
for (SchemaPropertyDataSourceParam param : params) {
paramsNode.put(param.name(), param.value());
}
}
// // 处理其他可选属性
// if (!dataSource.method().isEmpty()) {
// dataSourceNode.put("method", dataSource.method());
// }
// if (!dataSource.searchField().isEmpty()) {
// dataSourceNode.put("searchField", dataSource.searchField());
// }
}
/**
* 获取类的所有字段包括父类的字段
*/
private List<Field> getAllFields(Class<?> clazz) {
List<Field> fields = new ArrayList<>();
Class<?> currentClass = clazz;
// 遍历类的继承层次
while (currentClass != null && !currentClass.equals(Object.class)) {
// 添加当前类的字段
fields.addAll(Arrays.asList(currentClass.getDeclaredFields()));
// 获取父类
currentClass = currentClass.getSuperclass();
}
return fields;
}
private String getJsonSchemaType(Class<?> type) {
if (String.class.equals(type)) {
return "string";
} else if (Integer.class.equals(type) || int.class.equals(type)
|| Long.class.equals(type) || long.class.equals(type)) {
return "integer";
} else if (Double.class.equals(type) || double.class.equals(type)
|| Float.class.equals(type) || float.class.equals(type)) {
return "number";
} else if (Boolean.class.equals(type) || boolean.class.equals(type)) {
return "boolean";
} else if (List.class.isAssignableFrom(type)) {
return "array";
} else if (Map.class.isAssignableFrom(type)) {
return "object";
} else {
return "object";
}
}
}

View File

@ -0,0 +1,194 @@
package com.qqchen.deploy.backend.workflow.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty;
import com.qqchen.deploy.backend.workflow.annotation.SchemaPropertyDataSource;
import com.qqchen.deploy.backend.workflow.annotation.SchemaPropertyDataSourceParam;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class GenerateSchemaUtils {
public static ObjectNode generateSchema(Class<?> cls) {
ObjectMapper mapper = new ObjectMapper();
ObjectNode schema = mapper.createObjectNode();
schema.put("type", "object");
// 处理属性
ObjectNode properties = schema.putObject("properties");
List<String> required = new ArrayList<>();
// 获取所有字段包括父类的字段
List<Field> allFields = getAllFields(cls);
// 遍历所有字段
for (Field field : allFields) {
SchemaProperty annotation = field.getAnnotation(SchemaProperty.class);
if (annotation != null) {
ObjectNode property = properties.putObject(field.getName());
// 设置基本属性
String jsonType = getJsonSchemaType(field.getType());
property.put("type", jsonType);
// 从注解中获取属性
if (!annotation.title().isEmpty()) {
property.put("title", annotation.title());
}
if (!annotation.description().isEmpty()) {
property.put("description", annotation.description());
}
if (!annotation.format().isEmpty()) {
property.put("format", annotation.format());
}
if (annotation.required()) {
required.add(field.getName());
}
if (annotation.defaultValue().length() > 0) {
if (jsonType.equals("integer")) {
property.put("default", Integer.parseInt(annotation.defaultValue()));
} else if (jsonType.equals("number")) {
property.put("default", Double.parseDouble(annotation.defaultValue()));
} else {
property.put("default", annotation.defaultValue());
}
}
// 处理枚举
if (annotation.enumValues().length > 0) {
ArrayNode enumNode = property.putArray("enum");
for (String value : annotation.enumValues()) {
enumNode.add(value);
}
if (annotation.enumNames().length > 0) {
ArrayNode enumNamesNode = property.putArray("enumNames");
for (String name : annotation.enumNames()) {
enumNamesNode.add(name);
}
}
}
// 处理数组类型
if (List.class.isAssignableFrom(field.getType())) {
ObjectNode items = property.putObject("items");
items.put("type", "string");
}
// 处理Map类型
if (Map.class.isAssignableFrom(field.getType())) {
ObjectNode additionalProperties = property.putObject("additionalProperties");
additionalProperties.put("type", "string");
}
// 处理嵌套对象
if (property.get("type").asText().equals("object") && !Map.class.isAssignableFrom(field.getType()) && !field.getType().getName().startsWith("java.")) {
ObjectNode nestedSchema = generateSchema(field.getType());
if (nestedSchema.has("properties")) {
property.set("properties", nestedSchema.get("properties"));
}
if (nestedSchema.has("required")) {
property.set("required", nestedSchema.get("required"));
}
}
// 处理数据源
SchemaPropertyDataSource dataSource = annotation.dataSource();
if (dataSource != null && !dataSource.type().isEmpty()) {
processDataSource(property, dataSource);
}
}
}
// 添加required字段
if (!required.isEmpty()) {
ArrayNode requiredNode = schema.putArray("required");
required.forEach(requiredNode::add);
}
return schema;
}
/**
* 处理SchemaPropertyDataSource注解生成数据源配置
*
* @param property 当前属性节点
* @param dataSource 数据源注解
*/
private static void processDataSource(ObjectNode property, SchemaPropertyDataSource dataSource) {
ObjectNode dataSourceNode = property.putObject("dataSource");
// 处理基本属性
dataSourceNode.put("type", dataSource.type());
dataSourceNode.put("url", dataSource.url());
dataSourceNode.put("valueField", dataSource.valueField());
dataSourceNode.put("labelField", dataSource.labelField());
// 处理依赖字段
String[] dependsOn = dataSource.dependsOn();
if (dependsOn != null && dependsOn.length > 0) {
ArrayNode dependsOnNode = dataSourceNode.putArray("dependsOn");
for (String depend : dependsOn) {
dependsOnNode.add(depend);
}
}
// 处理请求参数
SchemaPropertyDataSourceParam[] params = dataSource.params();
if (params != null && params.length > 0) {
ObjectNode paramsNode = dataSourceNode.putObject("params");
for (SchemaPropertyDataSourceParam param : params) {
paramsNode.put(param.name(), param.value());
}
}
// // 处理其他可选属性
// if (!dataSource.method().isEmpty()) {
// dataSourceNode.put("method", dataSource.method());
// }
// if (!dataSource.searchField().isEmpty()) {
// dataSourceNode.put("searchField", dataSource.searchField());
// }
}
/**
* 获取类的所有字段包括父类的字段
*/
private static List<Field> getAllFields(Class<?> clazz) {
List<Field> fields = new ArrayList<>();
Class<?> currentClass = clazz;
// 遍历类的继承层次
while (currentClass != null && !currentClass.equals(Object.class)) {
// 添加当前类的字段
fields.addAll(Arrays.asList(currentClass.getDeclaredFields()));
// 获取父类
currentClass = currentClass.getSuperclass();
}
return fields;
}
private static String getJsonSchemaType(Class<?> type) {
if (String.class.equals(type)) {
return "string";
} else if (Integer.class.equals(type) || int.class.equals(type) || Long.class.equals(type) || long.class.equals(type)) {
return "integer";
} else if (Double.class.equals(type) || double.class.equals(type) || Float.class.equals(type) || float.class.equals(type)) {
return "number";
} else if (Boolean.class.equals(type) || boolean.class.equals(type)) {
return "boolean";
} else if (List.class.isAssignableFrom(type)) {
return "array";
} else if (Map.class.isAssignableFrom(type)) {
return "object";
} else {
return "object";
}
}
}

View File

@ -78,6 +78,8 @@ VALUES
(202, '应用管理', '/deploy/applications', '/src/pages/Deploy/Application/List/index', 'AppstoreOutlined', 2, 200, 2, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
(203, '环境管理', '/deploy/environments', '/src/pages/Deploy/Environment/List/index', 'CloudOutlined', 2, 200, 3, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
(204, '部署配置管理', '/deploy/deployment', '/src/pages/Deploy/Deployment/List/index', 'CloudOutlined', 2, 200, 3, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 三方系统
(205, '三方系统管理', '/deploy/external', '/src/pages/Deploy/external/index', 'ApiOutlined', 2, 200, 70, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE);