feat(workflow): 新增定时任务(事件等待)管理接口与菜单

- 新增 FlwEventWaitController:/workflow/eventWait 分页列表、状态汇总、详情、
  手动补发,权限分别为 workflow:eventWait:list / query / trigger
- FlowEventWaitBo 支持按流程编码、节点编码、业务主键、事件类型、状态、
  下次触发时间区间筛选;多值条件用逗号串传递
- FlowEventWaitVo 装配流程名称、业务主键,并透出 timerEnabled,
  供前端在定时引擎未开启时给出提示
- 手动补发复用引擎 InsService#startByTimer,不读写等待记录,
  下次触发时间不受影响;业务主键留空时生成 long 型雪花 ID
- 四方言全量脚本补充「流程监控 → 定时任务」菜单与查询、手动补发按钮
- 升级脚本补充 flow_event_wait 建表(6.0.0 存量库没有该表)与定时任务菜单
This commit is contained in:
may 2026-10-21 17:06:56 +08:00
parent d0a35db6c5
commit 1ee1289c4d
11 changed files with 775 additions and 0 deletions

View File

@ -0,0 +1,95 @@
package org.dromara.workflow.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.PageResult;
import org.dromara.common.core.domain.R;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.redis.annotation.RepeatSubmit;
import org.dromara.common.web.core.BaseController;
import org.dromara.workflow.common.ConditionalOnEnable;
import org.dromara.workflow.domain.bo.FlowEventWaitBo;
import org.dromara.workflow.domain.bo.FlowTimerTriggerBo;
import org.dromara.workflow.domain.vo.FlowEventWaitVo;
import org.dromara.workflow.service.IFlwEventWaitService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* 定时任务(事件等待记录)控制器。
* <p>数据来源为引擎事件等待表,默认只查定时类事件;消息类 / 错误类等待需显式放开事件类型范围。
* 写操作只有一项:对定时启动任务手动补发一次实例——补发不读取、也不推进等待记录,
* 定时任务的下次触发时间不受影响。</p>
*
* @author may
* @since 2026/10/21
*/
@ConditionalOnEnable
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/workflow/eventWait")
public class FlwEventWaitController extends BaseController {
private final IFlwEventWaitService flwEventWaitService;
/**
* 分页查询定时任务(事件等待记录)列表。
*
* @param bo 查询条件
* @return 等待记录分页数据
*/
@SaCheckPermission("workflow:eventWait:list")
@GetMapping("/list")
public R<PageResult<FlowEventWaitVo>> list(FlowEventWaitBo bo) {
return R.ok(flwEventWaitService.queryPageList(bo));
}
/**
* 按同一组筛选条件统计各状态等待记录数量。
*
* @param bo 查询条件
* @return 各状态计数
*/
@SaCheckPermission("workflow:eventWait:list")
@GetMapping("/summary")
public R<Map<String, Long>> summary(FlowEventWaitBo bo) {
return R.ok(flwEventWaitService.summary(bo));
}
/**
* 查询定时任务详情。
*
* @param id 事件等待记录主键
* @return 等待记录详情
*/
@SaCheckPermission("workflow:eventWait:query")
@GetMapping("/{id}")
public R<FlowEventWaitVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(flwEventWaitService.queryById(id));
}
/**
* 手动补发一次定时启动任务(运维应急)。
* <p>不推进等待记录,下一次定时触发照常进行;实例发起人记为当前登录用户。</p>
*
* @param bo 补发参数
* @return 新建实例主键
*/
@SaCheckPermission("workflow:eventWait:trigger")
@Log(title = "定时任务手动补发", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/trigger")
public R<Long> trigger(@RequestBody FlowTimerTriggerBo bo) {
return R.ok(flwEventWaitService.manualTrigger(bo));
}
}

View File

@ -0,0 +1,136 @@
package org.dromara.workflow.domain.bo;
import lombok.Data;
import org.dromara.warm.flow.core.dto.EventWaitQuery;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serial;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* 定时任务(事件等待记录)查询业务对象。
* <p>过滤维度与引擎 {@link EventWaitQuery} 一一对应:多值条件取「或」、不同条件之间取「且」;
* 事件类型留空时按 {@link #timerOnly} 决定是否只查定时类事件。数据来自引擎 flow_event_wait,
* 本对象只读,不含写操作字段。</p>
*
* @author may
* @since 2026/10/21
*/
@Data
public class FlowEventWaitBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 页码
*/
private Integer pageNum;
/**
* 每页条数
*/
private Integer pageSize;
/**
* 排序字段(引擎白名单:id / nextTriggerAt / retryAt / createTime / updateTime / status)
*/
private String orderByColumn;
/**
* 排序方向 asc / desc
*/
private String isAsc;
/**
* 等待状态多选(WAITING / RETRY / RUNNING / DEAD / CANCELLED),逗号分隔,留空表示不限
*/
private String statuses;
/**
* 事件类型多选(TIMER_START / TIMER_CATCH / TIMER_BOUNDARY / …),逗号分隔,
* 留空时按 timerOnly 取默认范围
*/
private String eventTypes;
/**
* 是否只查定时类事件,默认 true
*/
private Boolean timerOnly = true;
/**
* 流程定义编码
*/
private String flowCode;
/**
* 业务流程主键
*/
private String businessId;
/**
* 事件节点编码
*/
private String nodeCode;
/**
* 事件名称(消息名 / 错误码)
*/
private String eventName;
/**
* 下次触发时间下界
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date nextTriggerAtFrom;
/**
* 下次触发时间上界
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date nextTriggerAtTo;
/**
* 转换为引擎查询条件。
*
* @return 引擎只读查询条件
*/
public EventWaitQuery toQuery() {
EventWaitQuery query = new EventWaitQuery();
query.setPageNum(pageNum == null || pageNum < 1 ? 1 : pageNum);
query.setPageSize(pageSize == null || pageSize < 1 ? 10 : pageSize);
query.setStatuses(splitCsv(statuses));
query.setEventTypes(splitCsv(eventTypes));
query.setTimerOnly(!Boolean.FALSE.equals(timerOnly));
query.setFlowCode(flowCode);
query.setBusinessId(businessId);
query.setNodeCode(nodeCode);
query.setEventName(eventName);
query.setNextTriggerAtFrom(nextTriggerAtFrom);
query.setNextTriggerAtTo(nextTriggerAtTo);
if (orderByColumn != null && !orderByColumn.isBlank()) {
query.setOrderBy(orderByColumn);
query.setIsAsc(isAsc);
}
return query;
}
/**
* 逗号分隔串拆成引擎多值条件;空串返回 {@code null} 表示不限。
*
* @param csv 逗号分隔串
* @return 多值列表或 null
*/
private static List<String> splitCsv(String csv) {
if (csv == null || csv.isBlank()) {
return null;
}
return Arrays.stream(csv.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.toList();
}
}

View File

@ -0,0 +1,37 @@
package org.dromara.workflow.domain.bo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Map;
/**
* 定时启动任务手动补发业务对象。
* <p>只对 TIMER_START 事件的等待记录生效;补发只创建一次实例,不读取也不推进等待记录,
* 定时任务的下次触发时间不受影响。</p>
*
* @author may
* @since 2026/10/21
*/
@Data
public class FlowTimerTriggerBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 事件等待记录主键
*/
private Long waitId;
/**
* 业务主键,留空时按 M{waitId}_{时间戳} 自动生成
*/
private String businessId;
/**
* 额外流程变量,合并到节点默认变量之后
*/
private Map<String, Object> variables;
}

View File

@ -0,0 +1,158 @@
package org.dromara.workflow.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 定时任务(事件等待记录)视图对象 flow_event_wait。
* <p>字段来自引擎 flow_event_wait;flowName / businessId 由服务层按定义与实例主键装配,
* eventTypeName / statusName 为展示文案。</p>
*
* @author may
* @since 2026/10/21
*/
@Data
public class FlowEventWaitVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
private Long id;
/**
* 流程定义id
*/
private Long definitionId;
/**
* 流程名称
*/
private String flowName;
/**
* 流程实例id(定时启动事件为空)
*/
private Long instanceId;
/**
* 业务流程主键
*/
private String businessId;
/**
* 事件节点编码
*/
private String nodeCode;
/**
* 事件类型(TIMER_START / TIMER_CATCH / TIMER_BOUNDARY / …)
*/
private String eventType;
/**
* 事件类型文案
*/
private String eventTypeName;
/**
* 事件名称(消息名 / 错误码)
*/
private String eventName;
/**
* 边界事件关联的待办任务id
*/
private Long attachedTaskId;
/**
* 定时触发策略(AFTER / FIXED / POINT_IN_TIME)
*/
private String triggerType;
/**
* 触发间隔表达式
*/
private String triggerInterval;
/**
* 下次触发时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date nextTriggerAt;
/**
* 时区
*/
private String timezone;
/**
* 已触发次数
*/
private Integer repeatCount;
/**
* 最大触发次数
*/
private Integer maxRepeatCount;
/**
* 等待状态(WAITING / RETRY / RUNNING / CANCELLED / DEAD / SUCCESS)
*/
private String status;
/**
* 等待状态文案
*/
private String statusName;
/**
* 已重试次数
*/
private Integer retryCount;
/**
* 最大重试次数
*/
private Integer maxRetryCount;
/**
* 下次重试时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date retryAt;
/**
* 载荷
*/
private String payload;
/**
* 最近一次错误
*/
private String lastError;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/**
* 定时引擎扫描开关是否开启(warm-flow.timer-enabled)。
* 关闭时等待记录仍会生成但不会被自动触发,页面据此给出提醒。
*/
private Boolean timerEnabled;
}

View File

@ -0,0 +1,53 @@
package org.dromara.workflow.service;
import org.dromara.common.core.domain.PageResult;
import org.dromara.workflow.domain.bo.FlowEventWaitBo;
import org.dromara.workflow.domain.bo.FlowTimerTriggerBo;
import org.dromara.workflow.domain.vo.FlowEventWaitVo;
import java.util.Map;
/**
* 定时任务(事件等待记录)服务接口。
* <p>数据来自引擎 flow_event_wait,页面提供查询、状态统计与定时启动任务的手动补发。
* 手动补发只创建一次实例,不读取也不推进等待记录,定时任务的下次触发时间不受影响。</p>
*
* @author may
* @since 2026/10/21
*/
public interface IFlwEventWaitService {
/**
* 分页查询事件等待记录,默认只查定时类事件、按下次触发时间升序。
*
* @param bo 查询条件
* @return 等待记录分页数据
*/
PageResult<FlowEventWaitVo> queryPageList(FlowEventWaitBo bo);
/**
* 按同一组筛选条件统计各状态等待记录数量。
*
* @param bo 查询条件(其中状态条件被逐一分组覆盖)
* @return 各状态计数,键为 waiting / retry / running / dead / cancelled
*/
Map<String, Long> summary(FlowEventWaitBo bo);
/**
* 查询单条等待记录详情。
*
* @param id 事件等待记录主键
* @return 等待记录详情,不存在时返回 {@code null}
*/
FlowEventWaitVo queryById(Long id);
/**
* 手动补发一次定时启动任务(运维应急)。
* <p>实例发起人记为当前登录用户;等待记录保持不变,「每天 9 点的任务今天提前补发一次」
* 不会吞掉当天 9 点的正常触发。</p>
*
* @param bo 补发参数(等待记录主键、可选业务主键与变量)
* @return 新建流程实例主键
*/
Long manualTrigger(FlowTimerTriggerBo bo);
}

View File

@ -0,0 +1,225 @@
package org.dromara.workflow.service.impl;
import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.PageResult;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.warm.flow.core.FlowEngine;
import org.dromara.warm.flow.core.constant.EventCons;
import org.dromara.warm.flow.core.dto.EventWaitQuery;
import org.dromara.warm.flow.core.entity.EventWait;
import org.dromara.warm.flow.core.entity.Instance;
import org.dromara.warm.flow.core.enums.EventType;
import org.dromara.warm.flow.core.exception.FlowException;
import org.dromara.warm.flow.core.utils.page.Page;
import org.dromara.warm.flow.core.workflow.context.WorkflowContext;
import org.dromara.workflow.common.ConditionalOnEnable;
import org.dromara.workflow.domain.bo.FlowEventWaitBo;
import org.dromara.workflow.domain.bo.FlowTimerTriggerBo;
import org.dromara.workflow.domain.vo.FlowEventWaitVo;
import org.dromara.workflow.service.IFlwEventWaitService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 定时任务(事件等待记录)服务实现。
* <p>条件解析与合法性校验由引擎 {@link EventWaitQuery} 与门面层完成,本类只负责参数透传、
* 引擎实体到视图对象的装配(流程名 / 业务主键)与状态文案。手动补发复用引擎
* {@code InsService#startByTimer},不读写等待记录,定时任务下次触发时间不受影响。</p>
*
* @author may
* @since 2026/10/21
*/
@ConditionalOnEnable
@RequiredArgsConstructor
@Slf4j
@Service
public class FlwEventWaitServiceImpl implements IFlwEventWaitService {
/**
* 事件类型持久化值 → 页面文案。
*/
private static final Map<String, String> EVENT_TYPE_NAMES = new LinkedHashMap<>();
/**
* 等待状态持久化值 → 页面文案。
*/
private static final Map<String, String> STATUS_NAMES = new LinkedHashMap<>();
static {
EVENT_TYPE_NAMES.put(EventType.MESSAGE_START.getValue(), "消息启动");
EVENT_TYPE_NAMES.put(EventType.TIMER_START.getValue(), "定时启动");
EVENT_TYPE_NAMES.put(EventType.TIMER_CATCH.getValue(), "定时捕获");
EVENT_TYPE_NAMES.put(EventType.MESSAGE_CATCH.getValue(), "消息捕获");
EVENT_TYPE_NAMES.put(EventType.MESSAGE_THROW.getValue(), "消息抛出");
EVENT_TYPE_NAMES.put(EventType.TIMER_BOUNDARY.getValue(), "定时边界");
EVENT_TYPE_NAMES.put(EventType.MESSAGE_BOUNDARY.getValue(), "消息边界");
EVENT_TYPE_NAMES.put(EventType.TERMINATE_END.getValue(), "终止结束");
EVENT_TYPE_NAMES.put(EventType.MESSAGE_END.getValue(), "消息结束");
EVENT_TYPE_NAMES.put(EventType.ERROR_CATCH.getValue(), "错误捕获");
EVENT_TYPE_NAMES.put(EventType.ERROR_BOUNDARY.getValue(), "错误边界");
STATUS_NAMES.put(EventCons.STATUS_WAITING, "待触发");
STATUS_NAMES.put(EventCons.STATUS_RETRY, "重试中");
STATUS_NAMES.put(EventCons.STATUS_RUNNING, "执行中");
STATUS_NAMES.put(EventCons.STATUS_CANCELLED, "已取消");
STATUS_NAMES.put(EventCons.STATUS_DEAD, "已死");
STATUS_NAMES.put(EventCons.STATUS_SUCCESS, "成功");
}
/**
* 分页查询事件等待记录。
*
* @param bo 查询条件
* @return 分页等待记录
*/
@Override
public PageResult<FlowEventWaitVo> queryPageList(FlowEventWaitBo bo) {
Page<EventWait> page = FlowEngine.workflow().pageEventWaits(bo.toQuery());
List<EventWait> items = page.getList() == null ? List.of() : page.getList();
boolean timerEnabled = FlowEngine.getFlowConfig().isTimerEnabled();
List<FlowEventWaitVo> rows = new ArrayList<>(items.size());
for (EventWait wait : items) {
FlowEventWaitVo vo = toVo(wait);
vo.setTimerEnabled(timerEnabled);
rows.add(vo);
}
return PageResult.build(rows, page.getTotal());
}
/**
* 按同一组筛选条件统计各状态等待记录数量。
*
* @param bo 查询条件
* @return 各状态计数
*/
@Override
public Map<String, Long> summary(FlowEventWaitBo bo) {
Map<String, Long> summary = new LinkedHashMap<>();
summary.put("waiting", countByStatus(bo, EventCons.STATUS_WAITING));
summary.put("retry", countByStatus(bo, EventCons.STATUS_RETRY));
summary.put("running", countByStatus(bo, EventCons.STATUS_RUNNING));
summary.put("dead", countByStatus(bo, EventCons.STATUS_DEAD));
summary.put("cancelled", countByStatus(bo, EventCons.STATUS_CANCELLED));
return summary;
}
/**
* 查询单条等待记录详情。
*
* @param id 事件等待记录主键
* @return 等待记录详情,不存在时返回 null
*/
@Override
public FlowEventWaitVo queryById(Long id) {
EventWait wait = FlowEngine.eventWaitService().getById(id);
if (wait == null) {
return null;
}
FlowEventWaitVo vo = toVo(wait);
vo.setTimerEnabled(FlowEngine.getFlowConfig().isTimerEnabled());
return vo;
}
/**
* 手动补发一次定时启动任务(运维应急)。
* <p>
* 只做「按定义 + 事件节点直接发起」,<b>不读写等待记录</b>:定时任务的下次触发时间保持原样,
* 提前补发不会吞掉当天的正常触发。业务主键优先取调用方传入值,留空时用雪花 long 型 id
* (与宿主其它业务表主键同型,便于下游按 long 解析),天然不会与定时触发的
* {@code T{waitId}_{计划时间}} 撞号。加分布式锁防止同机/多机双击连发。
*
* @param bo 补发参数
* @return 新建实例主键
*/
@Override
@Lock4j(keys = {"#bo.waitId"})
public Long manualTrigger(FlowTimerTriggerBo bo) {
if (bo == null || bo.getWaitId() == null) {
throw new ServiceException("事件等待记录主键不能为空");
}
EventWait wait = FlowEngine.eventWaitService().getById(bo.getWaitId());
if (wait == null) {
throw new ServiceException("事件等待记录不存在: " + bo.getWaitId());
}
if (!EventType.TIMER_START.getValue().equals(wait.getEventType())) {
throw new ServiceException("只有定时启动任务支持手动触发,当前事件类型为 " + wait.getEventType());
}
String finalBusinessId = StringUtils.isNotBlank(bo.getBusinessId())
? bo.getBusinessId().trim()
: String.valueOf(IdWorker.getId());
WorkflowContext context = new WorkflowContext();
context.setHandler(LoginHelper.getUserIdStr());
try {
Instance instance = FlowEngine.insService().startByTimer(finalBusinessId, wait.getDefinitionId()
, wait.getNodeCode(), bo.getVariables(), context);
return instance.getId();
} catch (FlowException e) {
log.warn("定时启动任务手动补发失败 waitId={} 原因={}", bo.getWaitId(), e.getMessage());
throw new ServiceException(e.getMessage());
}
}
/**
* 统计某一状态下的等待记录数量。
*
* @param bo 查询参数(其中状态条件被覆盖)
* @param status 等待状态
* @return 记录数量
*/
private long countByStatus(FlowEventWaitBo bo, String status) {
EventWaitQuery query = bo.toQuery();
query.setStatuses(List.of(status));
return FlowEngine.workflow().countEventWaits(query);
}
/**
* 引擎等待记录 → 视图对象。
*
* @param wait 引擎等待记录
* @return 视图对象
*/
private FlowEventWaitVo toVo(EventWait wait) {
FlowEventWaitVo vo = new FlowEventWaitVo();
vo.setId(wait.getId());
vo.setDefinitionId(wait.getDefinitionId());
vo.setInstanceId(wait.getInstanceId());
vo.setNodeCode(wait.getNodeCode());
vo.setEventType(wait.getEventType());
vo.setEventName(wait.getEventName());
vo.setAttachedTaskId(wait.getAttachedTaskId());
vo.setTriggerType(wait.getTriggerType());
vo.setTriggerInterval(wait.getTriggerInterval());
vo.setNextTriggerAt(wait.getNextTriggerAt());
vo.setTimezone(wait.getTimezone());
vo.setRepeatCount(wait.getRepeatCount());
vo.setMaxRepeatCount(wait.getMaxRepeatCount());
vo.setStatus(wait.getStatus());
vo.setRetryCount(wait.getRetryCount());
vo.setMaxRetryCount(wait.getMaxRetryCount());
vo.setRetryAt(wait.getRetryAt());
vo.setPayload(wait.getPayload());
vo.setLastError(wait.getLastError());
vo.setCreateTime(wait.getCreateTime());
vo.setUpdateTime(wait.getUpdateTime());
vo.setEventTypeName(EVENT_TYPE_NAMES.getOrDefault(wait.getEventType(), wait.getEventType()));
vo.setStatusName(STATUS_NAMES.getOrDefault(wait.getStatus(), wait.getStatus()));
if (wait.getDefinitionId() != null) {
var definition = FlowEngine.defService().getById(wait.getDefinitionId());
vo.setFlowName(definition == null ? null : definition.getFlowName());
}
if (wait.getInstanceId() != null) {
var instance = FlowEngine.insService().getById(wait.getInstanceId());
vo.setBusinessId(instance == null ? null : instance.getBusinessId());
}
return vo;
}
}

View File

@ -601,6 +601,11 @@ INSERT INTO sys_menu VALUES (1761400000000011804, '流程spel表达式定义修
INSERT INTO sys_menu VALUES (1761400000000011805, '流程spel表达式定义删除', 1761400000000011801, 4, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:remove', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '');
INSERT INTO sys_menu VALUES (1761400000000011806, '流程spel表达式定义导出', 1761400000000011801, 5, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:export', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '');
-- 定时任务(事件等待记录)菜单与按钮
INSERT INTO sys_menu VALUES (1761400000000011901, '定时任务', 1761400000000011630, 3, 'timer', 'workflow/timer/index', '', 'N', 'N', 'C', '0', '0', 'workflow:eventWait:list', 'time', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '定时任务与事件等待监控菜单');
INSERT INTO sys_menu VALUES (1761400000000011902, '定时任务查询', 1761400000000011901, 1, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:eventWait:query', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '');
INSERT INTO sys_menu VALUES (1761400000000011903, '定时任务手动补发', 1761400000000011901, 2, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:eventWait:trigger', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '');
INSERT INTO sys_menu VALUES (1761400000000011638, '请假申请', 1761400000000000005, 1, 'leave', 'workflow/leave/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:leave:list', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu VALUES (1761400000000011639, '请假申请查询', 1761400000000011638, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:query', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '');
INSERT INTO sys_menu VALUES (1761400000000011640, '请假申请新增', 1761400000000011638, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:add', '#', '', '', 1761000000000000103, 1761100000000000001, SYSDATE, NULL, NULL, '');

View File

@ -569,6 +569,11 @@ INSERT INTO sys_menu VALUES (1761400000000011804, '流程spel表达式定义修
INSERT INTO sys_menu VALUES (1761400000000011805, '流程spel表达式定义删除', 1761400000000011801, 4, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:remove', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '');
INSERT INTO sys_menu VALUES (1761400000000011806, '流程spel表达式定义导出', 1761400000000011801, 5, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:export', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '');
-- 定时任务(事件等待记录)菜单与按钮
INSERT INTO sys_menu VALUES (1761400000000011901, '定时任务', 1761400000000011630, 3, 'timer', 'workflow/timer/index', '', 'N', 'N', 'C', '0', '0', 'workflow:eventWait:list', 'time', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '定时任务与事件等待监控菜单');
INSERT INTO sys_menu VALUES (1761400000000011902, '定时任务查询', 1761400000000011901, 1, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:eventWait:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '');
INSERT INTO sys_menu VALUES (1761400000000011903, '定时任务手动补发', 1761400000000011901, 2, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:eventWait:trigger', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '');
INSERT INTO sys_menu VALUES (1761400000000011638, '请假申请', 1761400000000000005, 1, 'leave', 'workflow/leave/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:leave:list', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu VALUES (1761400000000011639, '请假申请查询', 1761400000000011638, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:query', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '');
INSERT INTO sys_menu VALUES (1761400000000011640, '请假申请新增', 1761400000000011638, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:add', '#', '', '', 1761000000000000103, 1761100000000000001, now(), NULL, NULL, '');

View File

@ -349,6 +349,11 @@ INSERT INTO sys_menu VALUES (1761400000000011803, '流程达式定义新增', 17
INSERT INTO sys_menu VALUES (1761400000000011804, '流程达式定义修改', 1761400000000011801, 3, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:edit', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu VALUES (1761400000000011805, '流程达式定义删除', 1761400000000011801, 4, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:remove', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu VALUES (1761400000000011806, '流程达式定义导出', 1761400000000011801, 5, '#', '', NULL, 'N', 'Y', 'F', '0', '0', 'workflow:spel:export', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '');
-- 定时任务(事件等待记录)菜单与按钮
insert into sys_menu values (1761400000000011901, '定时任务', 1761400000000011630, 3, 'timer', 'workflow/timer/index', '', 'N', 'N', 'C', '0', '0', 'workflow:eventWait:list', 'time', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '定时任务与事件等待监控菜单');
insert into sys_menu values (1761400000000011902, '定时任务查询', 1761400000000011901, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:eventWait:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '');
insert into sys_menu values (1761400000000011903, '定时任务手动补发', 1761400000000011901, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:eventWait:trigger', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '');
-- 请假测试相关按钮
insert into sys_menu VALUES (1761400000000011638, '请假申请', 1761400000000000005, 1, 'leave', 'workflow/leave/index', '', 'N', 'Y', 'C', '0', '0', 'workflow:leave:list', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '请假申请菜单');
insert into sys_menu VALUES (1761400000000011639, '请假申请查询', 1761400000000011638, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:leave:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '');

View File

@ -1913,6 +1913,14 @@ GO
INSERT sys_menu VALUES (1761400000000011806, N'流程spel表达式定义导出', 1761400000000011801, 5, N'#', N'', NULL, N'N', N'Y', N'F', N'0', N'0', N'workflow:spel:export', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'');
GO
-- 定时任务(事件等待记录)菜单与按钮
INSERT sys_menu VALUES (1761400000000011901, N'定时任务', 1761400000000011630, 3, N'timer', N'workflow/timer/index', N'', N'N', N'N', N'C', N'0', N'0', N'workflow:eventWait:list', N'time', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'定时任务与事件等待监控菜单');
GO
INSERT sys_menu VALUES (1761400000000011902, N'定时任务查询', 1761400000000011901, 1, N'#', N'', NULL, N'N', N'Y', N'F', N'0', N'0', N'workflow:eventWait:query', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'');
GO
INSERT sys_menu VALUES (1761400000000011903, N'定时任务手动补发', 1761400000000011901, 2, N'#', N'', NULL, N'N', N'Y', N'F', N'0', N'0', N'workflow:eventWait:trigger', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'');
GO
-- 请假测试相关按钮
INSERT sys_menu VALUES (1761400000000011638, N'请假申请', 1761400000000000005, 1, N'leave', N'workflow/leave/index', N'', N'N', N'Y', N'C', N'0', N'0', N'workflow:leave:list', N'#', N'', N'', 1761000000000000103, 1761100000000000001, GETDATE(), NULL, NULL, N'请假申请菜单');
GO

View File

@ -31,3 +31,51 @@ INSERT INTO sys_dict_data VALUES (1761600000000000067, 12, '减签', 'remove_sig
-- 3. 实例状态字典补 restart(引擎 FlowStatus 有,字典缺)
INSERT INTO sys_dict_data VALUES (1761600000000000063, 8, '重启', 'restart', 'wf_business_status', '', 'info', 'N', 1761000000000000103, 1761100000000000001, sysdate(), NULL, NULL, '重启');
-- 4. 事件等待表:定时 / 消息等需要「等待」的事件统一落在此表(与全量脚本一致)。
-- 6.0.0 存量库没有这张表,不建表则定时器与定时任务页面全部不可用
-- 注意:建表后还需在 application.yml 打开 warm-flow.timer-enabled: true,引擎才会扫描本表
CREATE TABLE IF NOT EXISTS `flow_event_wait`
(
`id` bigint NOT NULL COMMENT '主键id',
`tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
`definition_id` bigint DEFAULT NULL COMMENT '流程定义id(定时启动事件必须有)',
`instance_id` bigint DEFAULT NULL COMMENT '流程实例id(实例等待事件必须有)',
`node_code` varchar(100) DEFAULT NULL COMMENT '事件节点编码(定位沿用 definition_id + node_code)',
`event_type` varchar(40) NOT NULL COMMENT '事件类型(MESSAGE_START TIMER_START TIMER_CATCH MESSAGE_CATCH MESSAGE_THROW TIMER_BOUNDARY MESSAGE_BOUNDARY ERROR_CATCH ERROR_BOUNDARY TERMINATE_END MESSAGE_END)',
`event_name` varchar(100) DEFAULT NULL COMMENT '事件名称(消息事件使用)',
`attached_task_id` bigint DEFAULT NULL COMMENT '边界事件关联的待办任务id',
`trigger_type` varchar(40) DEFAULT NULL COMMENT '触发策略类型(AFTER FIXED POINT_IN_TIME)',
`trigger_interval` varchar(100) DEFAULT NULL COMMENT '触发策略原始配置',
`next_trigger_at` datetime DEFAULT NULL COMMENT '下次触发时间',
`timezone` varchar(40) DEFAULT NULL COMMENT '定时触发使用的时区',
`repeat_count` int DEFAULT NULL COMMENT '已触发次数',
`max_repeat_count` int DEFAULT NULL COMMENT '最大触发次数',
`status` varchar(20) NOT NULL COMMENT '等待状态(WAITING RUNNING CANCELLED RETRY DEAD)',
`retry_count` int DEFAULT NULL COMMENT '已重试次数',
`max_retry_count` int DEFAULT NULL COMMENT '最大重试次数',
`retry_at` datetime DEFAULT NULL COMMENT '下次重试时间',
`lock_owner` varchar(64) DEFAULT NULL COMMENT '抢占持有者标识',
`lock_until` datetime DEFAULT NULL COMMENT '抢占租约到期时间',
`version` int DEFAULT NULL COMMENT '乐观锁版本号',
`payload` text COMMENT '消息事件接收的业务载荷',
`last_error` varchar(500) DEFAULT NULL COMMENT '最近一次失败原因摘要',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `event_wait_status_next` (`status`, `next_trigger_at`, `id`) USING BTREE,
KEY `event_wait_status_retry` (`status`, `retry_at`, `id`) USING BTREE,
KEY `event_wait_tenant_status_next` (`tenant_id`, `status`, `next_trigger_at`, `id`) USING BTREE,
KEY `event_wait_tenant_status_retry` (`tenant_id`, `status`, `retry_at`, `id`) USING BTREE,
KEY `event_wait_instance_task` (`instance_id`, `attached_task_id`) USING BTREE,
KEY `event_wait_name_instance_status` (`event_name`, `instance_id`, `status`) USING BTREE,
KEY `event_wait_def_node_status` (`definition_id`, `node_code`, `status`) USING BTREE
) ENGINE = InnoDB COMMENT ='事件等待表';
-- 5. 「流程监控」下补「定时任务」菜单 + 查询/手动补发按钮(与 script/sql/ry_workflow.sql 全量脚本一致)
-- 先删后插保证可重复执行;重新执行后记得给角色重新勾选按钮权限
DELETE FROM sys_menu WHERE menu_id IN (1761400000000011901, 1761400000000011902, 1761400000000011903);
insert into sys_menu values (1761400000000011901, '定时任务', 1761400000000011630, 3, 'timer', 'workflow/timer/index', '', 'N', 'N', 'C', '0', '0', 'workflow:eventWait:list', 'time', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '定时任务与事件等待监控菜单');
insert into sys_menu values (1761400000000011902, '定时任务查询', 1761400000000011901, 1, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:eventWait:query', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '');
insert into sys_menu values (1761400000000011903, '定时任务手动补发', 1761400000000011901, 2, '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:eventWait:trigger', '#', '', '', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '');