增加构建通知
This commit is contained in:
parent
730bb94926
commit
e7211f8699
@ -16,6 +16,7 @@ import com.qqchen.deploy.backend.deploy.integration.IJenkinsServiceIntegration;
|
||||
import com.qqchen.deploy.backend.deploy.repository.*;
|
||||
import com.qqchen.deploy.backend.deploy.service.IJenkinsBuildService;
|
||||
import com.qqchen.deploy.backend.deploy.service.IJenkinsSyncHistoryService;
|
||||
import com.qqchen.deploy.backend.notification.dto.BaseSendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationChannel;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationTemplate;
|
||||
import com.qqchen.deploy.backend.notification.entity.config.WeworkTemplateConfig;
|
||||
@ -33,14 +34,26 @@ import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -48,8 +61,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, JenkinsBuildDTO, JenkinsBuildQuery, Long>
|
||||
implements IJenkinsBuildService {
|
||||
public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, JenkinsBuildDTO, JenkinsBuildQuery, Long> implements IJenkinsBuildService {
|
||||
|
||||
@Resource
|
||||
private IExternalSystemRepository externalSystemRepository;
|
||||
@ -96,8 +108,6 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
@Resource
|
||||
private INotificationService notificationService;
|
||||
|
||||
@Resource
|
||||
private INotificationSendService notificationSendService;
|
||||
|
||||
@Resource(name = "jenkinsTaskExecutor")
|
||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||
@ -143,7 +153,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
() -> syncView(context.getExternalSystem(), view),
|
||||
threadPoolTaskExecutor
|
||||
))
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
|
||||
// 3. 等待所有任务完成并汇总结果
|
||||
int totalSyncedBuilds = futures.stream()
|
||||
@ -236,10 +246,10 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
}
|
||||
|
||||
private List<JenkinsBuildResponse> getNewBuilds(
|
||||
ExternalSystem externalSystem,
|
||||
JenkinsJob job,
|
||||
JenkinsJobResponse jobResponse,
|
||||
Optional<JenkinsBuild> lastBuild) {
|
||||
ExternalSystem externalSystem,
|
||||
JenkinsJob job,
|
||||
JenkinsJobResponse jobResponse,
|
||||
Optional<JenkinsBuild> lastBuild) {
|
||||
|
||||
// 1. 获取最新构建号(从jobResponse中获取,避免额外的API调用)
|
||||
if (jobResponse.getLastBuild() == null) {
|
||||
@ -280,9 +290,9 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
}
|
||||
|
||||
private void saveNewBuilds(
|
||||
ExternalSystem externalSystem,
|
||||
JenkinsJob job,
|
||||
List<JenkinsBuildResponse> builds) {
|
||||
ExternalSystem externalSystem,
|
||||
JenkinsJob job,
|
||||
List<JenkinsBuildResponse> builds) {
|
||||
List<JenkinsBuild> jenkinsBuilds = builds.stream()
|
||||
.map(buildResponse -> {
|
||||
JenkinsBuild build = new JenkinsBuild();
|
||||
@ -355,7 +365,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
* 同步指定视图下的构建信息(异步执行)
|
||||
*
|
||||
* @param externalSystemId 外部系统ID
|
||||
* @param viewId 视图ID
|
||||
* @param viewId 视图ID
|
||||
*/
|
||||
@Override
|
||||
@Async
|
||||
@ -368,8 +378,8 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
* 同步指定任务的构建信息(异步执行)
|
||||
*
|
||||
* @param externalSystemId 外部系统ID
|
||||
* @param viewId 视图ID (未使用,但为了保持API一致性)
|
||||
* @param jobId 任务ID
|
||||
* @param viewId 视图ID (未使用,但为了保持API一致性)
|
||||
* @param jobId 任务ID
|
||||
*/
|
||||
@Override
|
||||
@Async
|
||||
@ -382,8 +392,8 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
* 执行构建同步的核心方法
|
||||
*
|
||||
* @param externalSystemId 外部系统ID
|
||||
* @param viewId 视图ID(可选)
|
||||
* @param jobId 任务ID(可选)
|
||||
* @param viewId 视图ID(可选)
|
||||
* @param jobId 任务ID(可选)
|
||||
*/
|
||||
private void doSyncBuilds(Long externalSystemId, Long viewId, Long jobId) {
|
||||
// 1. 创建同步上下文
|
||||
@ -456,8 +466,8 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
List<JenkinsBuild> pendingBuilds = pendingBuildIds.isEmpty()
|
||||
? Collections.emptyList()
|
||||
: jenkinsBuildRepository.findAllById(pendingBuildIds).stream()
|
||||
.filter(b -> b.getExternalSystemId().equals(externalSystemId))
|
||||
.collect(Collectors.toList());
|
||||
.filter(b -> b.getExternalSystemId().equals(externalSystemId))
|
||||
.toList();
|
||||
|
||||
// 4. 合并需要处理的构建(去重)
|
||||
Map<Long, JenkinsBuild> buildMap = new HashMap<>();
|
||||
@ -578,23 +588,11 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
/**
|
||||
* 处理单个构建的通知
|
||||
*/
|
||||
private void processBuildNotification(
|
||||
TeamEnvironmentNotificationConfig config,
|
||||
NotificationChannel channel,
|
||||
JenkinsJob job,
|
||||
JenkinsBuild build,
|
||||
ExternalSystem externalSystem,
|
||||
Application application,
|
||||
Environment environment) {
|
||||
private void processBuildNotification(TeamEnvironmentNotificationConfig config, NotificationChannel channel, JenkinsJob job, JenkinsBuild build, ExternalSystem externalSystem, Application application, Environment environment) {
|
||||
|
||||
try {
|
||||
// 1. 查询通知记录
|
||||
JenkinsBuildNotification record = jenkinsBuildNotificationRepository
|
||||
.findByBuildIdAndTeamIdAndEnvironmentId(
|
||||
build.getId(),
|
||||
config.getTeamId(),
|
||||
config.getEnvironmentId()
|
||||
)
|
||||
JenkinsBuildNotification record = jenkinsBuildNotificationRepository.findByBuildIdAndTeamIdAndEnvironmentId(build.getId(), config.getTeamId(), config.getEnvironmentId())
|
||||
.orElse(null);
|
||||
|
||||
// 2. 新构建(只处理6分钟内的新构建)
|
||||
@ -650,11 +648,9 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
|
||||
} catch (org.springframework.orm.ObjectOptimisticLockingFailureException e) {
|
||||
// 乐观锁冲突,说明记录已被其他线程更新,跳过即可
|
||||
log.warn("构建通知记录乐观锁冲突,跳过处理: teamId={}, envId={}, buildId={}",
|
||||
config.getTeamId(), config.getEnvironmentId(), build.getId());
|
||||
log.warn("构建通知记录乐观锁冲突,跳过处理: teamId={}, envId={}, buildId={}", config.getTeamId(), config.getEnvironmentId(), build.getId());
|
||||
} catch (Exception e) {
|
||||
log.error("处理构建通知失败: teamId={}, envId={}, buildId={}",
|
||||
config.getTeamId(), config.getEnvironmentId(), build.getId(), e);
|
||||
log.error("处理构建通知失败: teamId={}, envId={}, buildId={}", config.getTeamId(), config.getEnvironmentId(), build.getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -663,23 +659,13 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
*/
|
||||
private boolean isBuildFinished(JenkinsBuild build) {
|
||||
String status = build.getBuildStatus();
|
||||
return "SUCCESS".equals(status) ||
|
||||
"FAILURE".equals(status) ||
|
||||
"ABORTED".equals(status);
|
||||
return "SUCCESS".equals(status) || "FAILURE".equals(status) || "ABORTED".equals(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送通知(使用模板)
|
||||
*/
|
||||
private void sendNotification(
|
||||
TeamEnvironmentNotificationConfig config,
|
||||
NotificationChannel channel,
|
||||
JenkinsJob job,
|
||||
JenkinsBuild build,
|
||||
String status,
|
||||
ExternalSystem externalSystem,
|
||||
Application application,
|
||||
Environment environment) {
|
||||
private void sendNotification(TeamEnvironmentNotificationConfig config, NotificationChannel channel, JenkinsJob job, JenkinsBuild build, String status, ExternalSystem externalSystem, Application application, Environment environment) {
|
||||
|
||||
try {
|
||||
// 1. 检查是否配置了构建通知模板
|
||||
@ -690,9 +676,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
}
|
||||
|
||||
// 2. 查询模板
|
||||
NotificationTemplate template = notificationTemplateRepository
|
||||
.findById(config.getBuildNotificationTemplateId())
|
||||
.orElse(null);
|
||||
NotificationTemplate template = notificationTemplateRepository.findById(config.getBuildNotificationTemplateId()).orElse(null);
|
||||
if (template == null) {
|
||||
log.warn("构建通知模板不存在: templateId={}", config.getBuildNotificationTemplateId());
|
||||
return;
|
||||
@ -722,7 +706,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
templateParams.put("buildStatus", status);
|
||||
|
||||
// 时间格式化
|
||||
java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
if (build.getStarttime() != null) {
|
||||
templateParams.put("buildStartTime", build.getStarttime().format(formatter));
|
||||
}
|
||||
@ -747,9 +731,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
|
||||
// 4. 校验模板和渠道类型是否匹配
|
||||
if (!template.getChannelType().equals(channel.getChannelType())) {
|
||||
log.warn("模板渠道类型({})与通知渠道类型({})不匹配,跳过通知: templateId={}, channelId={}",
|
||||
template.getChannelType(), channel.getChannelType(),
|
||||
config.getBuildNotificationTemplateId(), channel.getId());
|
||||
log.warn("模板渠道类型({})与通知渠道类型({})不匹配,跳过通知: templateId={}, channelId={}", template.getChannelType(), channel.getChannelType(), config.getBuildNotificationTemplateId(), channel.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -759,15 +741,12 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
request.setTemplateParams(templateParams);
|
||||
request.setSendRequest(createSendRequestByChannel(channel, template));
|
||||
|
||||
log.debug("准备发送构建通知: job={}, build={}, templateId={}, channelId={}, channelType={}",
|
||||
job.getJobName(), build.getBuildNumber(), config.getBuildNotificationTemplateId(),
|
||||
channel.getId(), channel.getChannelType());
|
||||
log.debug("准备发送构建通知: job={}, build={}, templateId={}, channelId={}, channelType={}", job.getJobName(), build.getBuildNumber(), config.getBuildNotificationTemplateId(), channel.getId(), channel.getChannelType());
|
||||
|
||||
// 6. 发送通知
|
||||
notificationService.send(request);
|
||||
|
||||
log.info("已发送构建通知: job={}, build={}, status={}, templateId={}",
|
||||
job.getJobName(), build.getBuildNumber(), status, config.getBuildNotificationTemplateId());
|
||||
log.info("已发送构建通知: job={}, build={}, status={}, templateId={}", job.getJobName(), build.getBuildNumber(), status, config.getBuildNotificationTemplateId());
|
||||
|
||||
// 6. 构建失败时,发送日志文件(如果开启)
|
||||
if ("FAILURE".equals(status) && Boolean.TRUE.equals(config.getBuildFailureFileEnabled())) {
|
||||
@ -782,8 +761,8 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
/**
|
||||
* 根据渠道类型创建对应的发送请求
|
||||
*/
|
||||
private com.qqchen.deploy.backend.notification.dto.BaseSendNotificationRequest createSendRequestByChannel(
|
||||
NotificationChannel channel, NotificationTemplate template) {
|
||||
private BaseSendNotificationRequest createSendRequestByChannel(
|
||||
NotificationChannel channel, NotificationTemplate template) {
|
||||
switch (channel.getChannelType()) {
|
||||
case WEWORK:
|
||||
WeworkSendNotificationRequest weworkRequest = new WeworkSendNotificationRequest();
|
||||
@ -806,8 +785,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
private WeworkMessageTypeEnum getWeworkMessageType(NotificationTemplate template) {
|
||||
try {
|
||||
if (template.getTemplateConfig() != null) {
|
||||
WeworkTemplateConfig weworkConfig = JsonUtils.fromMap(
|
||||
template.getTemplateConfig(), WeworkTemplateConfig.class);
|
||||
WeworkTemplateConfig weworkConfig = JsonUtils.fromMap(template.getTemplateConfig(), WeworkTemplateConfig.class);
|
||||
if (weworkConfig != null && weworkConfig.getMessageType() != null) {
|
||||
return weworkConfig.getMessageType();
|
||||
}
|
||||
@ -896,8 +874,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
log.info("构建失败日志文件发送成功: job={}, buildNumber={}", jobName, buildNumber);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("发送构建失败日志文件失败: job={}, buildNumber={}",
|
||||
jobName, buildNumber, e);
|
||||
log.error("发送构建失败日志文件失败: job={}, buildNumber={}", jobName, buildNumber, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -907,12 +884,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
private String downloadBuildLogFile(ExternalSystem externalSystem, String jobName, Integer buildNumber) {
|
||||
try {
|
||||
// 获取完整的控制台输出
|
||||
var consoleOutput = jenkinsServiceIntegration.getConsoleOutput(
|
||||
externalSystem,
|
||||
jobName,
|
||||
buildNumber,
|
||||
0L
|
||||
);
|
||||
var consoleOutput = jenkinsServiceIntegration.getConsoleOutput(externalSystem, jobName, buildNumber, 0L);
|
||||
|
||||
if (consoleOutput == null || consoleOutput.getLines() == null || consoleOutput.getLines().isEmpty()) {
|
||||
return null;
|
||||
@ -921,12 +893,12 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
// 创建临时文件
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
String fileName = String.format("jenkins-build-%s-%d.log", jobName, buildNumber);
|
||||
java.nio.file.Path filePath = java.nio.file.Paths.get(tempDir, fileName);
|
||||
Path filePath = Paths.get(tempDir, fileName);
|
||||
|
||||
// 写入日志内容
|
||||
java.nio.file.Files.write(filePath, consoleOutput.getLines());
|
||||
Files.write(filePath, consoleOutput.getLines());
|
||||
|
||||
log.info("日志文件已下载: {}", filePath.toString());
|
||||
log.info("日志文件已下载: {}", filePath);
|
||||
return filePath.toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
@ -956,22 +928,18 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
String uploadUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key=" + key + "&type=file";
|
||||
|
||||
// 构建 multipart/form-data 请求
|
||||
org.springframework.core.io.FileSystemResource fileResource =
|
||||
new org.springframework.core.io.FileSystemResource(filePath);
|
||||
FileSystemResource fileResource = new FileSystemResource(filePath);
|
||||
|
||||
org.springframework.util.LinkedMultiValueMap<String, Object> map =
|
||||
new org.springframework.util.LinkedMultiValueMap<>();
|
||||
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
|
||||
map.add("media", fileResource);
|
||||
|
||||
org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders();
|
||||
HttpHeaders headers = new org.springframework.http.HttpHeaders();
|
||||
headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA);
|
||||
|
||||
org.springframework.http.HttpEntity<org.springframework.util.MultiValueMap<String, Object>> requestEntity =
|
||||
new org.springframework.http.HttpEntity<>(map, headers);
|
||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);
|
||||
|
||||
org.springframework.web.client.RestTemplate restTemplate = new org.springframework.web.client.RestTemplate();
|
||||
org.springframework.http.ResponseEntity<String> response =
|
||||
restTemplate.postForEntity(uploadUrl, requestEntity, String.class);
|
||||
RestTemplate restTemplate = new org.springframework.web.client.RestTemplate();
|
||||
ResponseEntity<String> response = restTemplate.postForEntity(uploadUrl, requestEntity, String.class);
|
||||
|
||||
if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
|
||||
// 解析响应,获取 media_id
|
||||
@ -1018,15 +986,13 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
message.put("file", file);
|
||||
|
||||
// 发送请求
|
||||
org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders();
|
||||
headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
org.springframework.http.HttpEntity<Map<String, Object>> requestEntity =
|
||||
new org.springframework.http.HttpEntity<>(message, headers);
|
||||
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(message, headers);
|
||||
|
||||
org.springframework.web.client.RestTemplate restTemplate = new org.springframework.web.client.RestTemplate();
|
||||
org.springframework.http.ResponseEntity<String> response =
|
||||
restTemplate.postForEntity(webhookUrl, requestEntity, String.class);
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
ResponseEntity<String> response = restTemplate.postForEntity(webhookUrl, requestEntity, String.class);
|
||||
|
||||
if (response.getStatusCode().is2xxSuccessful()) {
|
||||
log.info("企业微信文件消息发送成功");
|
||||
|
||||
@ -52,15 +52,15 @@ VALUES
|
||||
(99, '工作台', '/dashboard', 'Dashboard', 'DashboardOutlined', 'dashboard', 2, NULL, 0, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
|
||||
-- 工作流管理
|
||||
(100, '工作流管理', '/workflow', NULL, 'DeploymentUnitOutlined', NULL, 1, NULL, 1, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 工作流设计
|
||||
(101, '工作流设计', '/workflow/definitions', 'Workflow/Definition/List', 'EditOutlined', 'workflow:definition', 2, 100, 10, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
(100, '流程管理', '/workflow', NULL, 'DeploymentUnitOutlined', NULL, 1, NULL, 1, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 流程设计
|
||||
(101, '流程设计', '/workflow/definitions', 'Workflow/Definition/List', 'EditOutlined', 'workflow:definition', 2, 100, 10, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 工作流设计器(隐藏路由,用于编辑工作流)
|
||||
(1011, '工作流设计器', '/workflow/design/:id', 'Workflow/Design', 'EditOutlined', NULL, 2, 100, 11, TRUE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 工作流实例
|
||||
(102, '工作流实例', '/workflow/instances', 'Workflow/Instance/List', 'BranchesOutlined', 'workflow:instance', 2, 100, 20, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 动态表单菜单
|
||||
(104, '动态表单菜单', '/workflow/form', 'Form/Definition/List', 'FormOutlined', 'workflow:form', 2, 100, 30, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 流程实例
|
||||
(102, '流程实例', '/workflow/instances', 'Workflow/Instance/List', 'BranchesOutlined', 'workflow:instance', 2, 100, 20, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 动态表单
|
||||
(104, '动态表单', '/workflow/form', 'Form/Definition/List', 'FormOutlined', 'workflow:form', 2, 100, 30, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 表单设计器(隐藏路由,用于设计表单)
|
||||
(1041, '表单设计器', '/workflow/form/:id/design', 'Form/Definition/Designer', 'FormOutlined', NULL, 2, 100, 31, TRUE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 表单数据详情(隐藏路由,用于查看表单数据)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user