疯狂的狮子Li
2024-06-06 456620b6383611bc5982d670fca8dead60571208
!549 ♥️发布 5.2.0-BETA2 公测版本
Merge pull request !549 from 疯狂的狮子Li/dev
已修改54个文件
已添加7个文件
已重命名1个文件
已删除8个文件
1533 ■■■■■ 文件已修改
pom.xml 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/pom.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-dev.yml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-prod.yml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-bom/pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/RedisExceptionHandler.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/handler/SmsExceptionHandler.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/WebSocketConfig.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/constant/WebSocketConstants.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/handler/PlusWebSocketHandler.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/interceptor/PlusWebSocketInterceptor.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/listener/WebSocketTopicListener.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/README.md 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/pom.xml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/annotation/FlowListenerAnnotation.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java 52 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowEventStrategy.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowProcessEventHandler.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowTaskEventHandler.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomProcessHandler.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomTaskHandler.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveExecutionListener.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveTaskListener.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java 157 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java 108 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/bpmn/模型.zip 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/flowable.sql 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/oracle/flowable.sql 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/oracle/oracle_ry_vue_5.X.sql 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/postgres/flowable.sql 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/postgres/postgres_ry_vue_5.X.sql 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/ry_vue_5.X.sql 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/sqlserver/flowable.sql 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/sqlserver/sqlserver_ry_vue_5.X.sql 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/update/oracle/update_5.1.2-5.2.0.sql 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/update/postgres/update_5.1.2-5.2.0.sql 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/update/sqlserver/update_5.1.2-5.2.0.sql 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/update/update_5.1.2-5.2.0.sql 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -13,8 +13,8 @@
    <description>RuoYi-Vue-Plus多租户管理系统</description>
    <properties>
        <revision>5.2.0-BETA</revision>
        <spring-boot.version>3.2.5</spring-boot.version>
        <revision>5.2.0-BETA2</revision>
        <spring-boot.version>3.2.6</spring-boot.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>17</java.version>
@@ -34,7 +34,7 @@
        <lock4j.version>2.2.7</lock4j.version>
        <dynamic-ds.version>4.3.0</dynamic-ds.version>
        <alibaba-ttl.version>2.14.4</alibaba-ttl.version>
        <snailjob.version>1.0.0-beta1</snailjob.version>
        <snailjob.version>1.0.0-beta3</snailjob.version>
        <mapstruct-plus.version>1.3.6</mapstruct-plus.version>
        <mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
        <lombok.version>1.18.32</lombok.version>
@@ -50,6 +50,8 @@
        <sms4j.version>3.2.1</sms4j.version>
        <!-- é™åˆ¶æ¡†æž¶ä¸­çš„fastjson版本 -->
        <fastjson.version>1.2.83</fastjson.version>
        <!--工作流配置-->
        <flowable.version>7.0.0</flowable.version>
        <!-- æ’件版本 -->
        <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
@@ -57,9 +59,6 @@
        <maven-compiler-plugin.verison>3.11.0</maven-compiler-plugin.verison>
        <maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
        <flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
        <!--工作流配置-->
        <flowable.version>7.0.0</flowable.version>
    </properties>
    <profiles>
ruoyi-admin/pom.xml
@@ -97,21 +97,6 @@
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>me.zhyd.oauth</groupId>
            <artifactId>JustAuth</artifactId>
        </dependency>
        <!-- SnailJob client -->
        <dependency>
            <groupId>com.aizuda</groupId>
            <artifactId>snail-job-client-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.aizuda</groupId>
            <artifactId>snail-job-client-job-core</artifactId>
        </dependency>
        <!-- skywalking æ•´åˆ logback -->
<!--        <dependency>-->
<!--            <groupId>org.apache.skywalking</groupId>-->
ruoyi-admin/src/main/resources/application-dev.yml
@@ -12,7 +12,7 @@
snail-job:
  enabled: true
  # éœ€è¦åœ¨ SnailJob åŽå°ç»„管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
  group-name: "ruoyi_group"
  group: "ruoyi_group"
  # SnailJob æŽ¥å…¥éªŒè¯ä»¤ç‰Œ è¯¦è§ script/sql/snail_job.sql `sj_group_config` è¡¨
  token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
  server:
@@ -20,7 +20,6 @@
    port: 1788
  # è¯¦è§ script/sql/snail_job.sql `sj_namespace` è¡¨
  namespace: ${spring.profiles.active}
--- # æ•°æ®æºé…ç½®
spring:
@@ -102,6 +101,7 @@
    # æ˜¯å¦å¼€å¯ssl
    ssl.enabled: false
# redisson é…ç½®
redisson:
  # redis key前缀
  keyPrefix:
ruoyi-admin/src/main/resources/application-prod.yml
@@ -15,7 +15,7 @@
snail-job:
  enabled: false
  # éœ€è¦åœ¨ SnailJob åŽå°ç»„管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
  group-name: "ruoyi_group"
  group: "ruoyi_group"
  # SnailJob æŽ¥å…¥éªŒè¯ä»¤ç‰Œ è¯¦è§ script/sql/snail_job.sql `sj_group_config` è¡¨
  token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
  server:
@@ -104,6 +104,7 @@
    # æ˜¯å¦å¼€å¯ssl
    ssl.enabled: false
# redisson é…ç½®
redisson:
  # redis key前缀
  keyPrefix:
ruoyi-common/ruoyi-common-bom/pom.xml
@@ -14,7 +14,7 @@
    </description>
    <properties>
        <revision>5.2.0-BETA</revision>
        <revision>5.2.0-BETA2</revision>
    </properties>
    <dependencyManagement>
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package org.dromara.common.core.domain.event;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
 * æ€»ä½“流程监听
 *
 * @author may
 */
@Data
public class ProcessEvent implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * æµç¨‹å®šä¹‰key
     */
    private String key;
    /**
     * ä¸šåŠ¡id
     */
    private String businessKey;
    /**
     * çŠ¶æ€
     */
    private String status;
    /**
     * å½“为true时为申请人节点办理
     */
    private boolean submit;
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
package org.dromara.common.core.domain.event;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
 * æµç¨‹åŠžç†ç›‘å¬
 *
 * @author may
 */
@Data
public class ProcessTaskEvent implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * æµç¨‹å®šä¹‰key与流程节点标识(拼接方式:流程定义key_流程节点)
     */
    private String keyNode;
    /**
     * ä»»åŠ¡id
     */
    private String taskId;
    /**
     * ä¸šåŠ¡id
     */
    private String businessKey;
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java
ÎļþÃû´Ó ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/BusinessStatusEnum.java ÐÞ¸Ä
@@ -1,4 +1,4 @@
package org.dromara.workflow.common.enums;
package org.dromara.common.core.enums;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
package org.dromara.common.core.service;
import java.util.List;
import java.util.Map;
/**
 * é€šç”¨ å·¥ä½œæµæœåŠ¡
 *
 * @author may
 */
public interface WorkflowService {
    /**
     * è¿è¡Œä¸­çš„实例 åˆ é™¤ç¨‹å®žä¾‹ï¼Œåˆ é™¤åŽ†å²è®°å½•ï¼Œåˆ é™¤ä¸šåŠ¡ä¸Žæµç¨‹å…³è”ä¿¡æ¯
     *
     * @param businessKeys ä¸šåŠ¡id
     * @return ç»“æžœ
     */
    boolean deleteRunAndHisInstance(List<String> businessKeys);
    /**
     * èŽ·å–å½“å‰æµç¨‹çŠ¶æ€
     *
     * @param taskId ä»»åŠ¡id
     */
    String getBusinessStatusByTaskId(String taskId);
    /**
     * èŽ·å–å½“å‰æµç¨‹çŠ¶æ€
     *
     * @param businessKey ä¸šåŠ¡id
     */
    String getBusinessStatus(String businessKey);
    /**
     * è®¾ç½®æµç¨‹å˜é‡(全局变量)
     *
     * @param taskId       ä»»åŠ¡id
     * @param variableName å˜é‡åç§°
     * @param value        å˜é‡å€¼
     */
    void setVariable(String taskId, String variableName, Object value);
    /**
     * è®¾ç½®æµç¨‹å˜é‡(全局变量)
     *
     * @param taskId    ä»»åŠ¡id
     * @param variables æµç¨‹å˜é‡
     */
    void setVariables(String taskId, Map<String, Object> variables);
    /**
     * è®¾ç½®æµç¨‹å˜é‡(本地变量,非全局变量)
     *
     * @param taskId       ä»»åŠ¡id
     * @param variableName å˜é‡åç§°
     * @param value        å˜é‡å€¼
     */
    void setVariableLocal(String taskId, String variableName, Object value);
    /**
     * è®¾ç½®æµç¨‹å˜é‡(本地变量,非全局变量)
     *
     * @param taskId    ä»»åŠ¡id
     * @param variables æµç¨‹å˜é‡
     */
    void setVariablesLocal(String taskId, Map<String, Object> variables);
    /**
     * æŒ‰ç…§ä¸šåŠ¡id查询流程实例id
     *
     * @param businessKey ä¸šåŠ¡id
     * @return ç»“æžœ
     */
    String getInstanceIdByBusinessKey(String businessKey);
}
ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java
@@ -21,7 +21,7 @@
@AutoConfiguration
@ConditionalOnProperty(prefix = "snail-job", name = "enabled", havingValue = "true")
@EnableScheduling
@EnableSnailJob(group = "${snail-job.group-name}")
@EnableSnailJob
public class SnailJobConfig {
    @EventListener(SnailClientStartingEvent.class)
ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
@@ -162,13 +162,14 @@
    /**
     * ä¸Šä¼ æ–‡ä»¶åˆ° Amazon S3,并返回上传结果
     *
     * @param filePath  æœ¬åœ°æ–‡ä»¶è·¯å¾„
     * @param key       åœ¨ Amazon S3 ä¸­çš„对象键
     * @param md5Digest æœ¬åœ°æ–‡ä»¶çš„ MD5 å“ˆå¸Œå€¼ï¼ˆå¯é€‰ï¼‰
     * @param filePath    æœ¬åœ°æ–‡ä»¶è·¯å¾„
     * @param key         åœ¨ Amazon S3 ä¸­çš„对象键
     * @param md5Digest   æœ¬åœ°æ–‡ä»¶çš„ MD5 å“ˆå¸Œå€¼ï¼ˆå¯é€‰ï¼‰
     * @param contentType æ–‡ä»¶å†…容类型
     * @return UploadResult åŒ…含上传后的文件信息
     * @throws OssException å¦‚果上传失败,抛出自定义异常
     */
    public UploadResult upload(Path filePath, String key, String md5Digest) {
    public UploadResult upload(Path filePath, String key, String md5Digest, String contentType) {
        try {
            // æž„建上传请求对象
            FileUpload fileUpload = transferManager.uploadFile(
@@ -176,6 +177,7 @@
                        y -> y.bucket(properties.getBucketName())
                            .key(key)
                            .contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
                            .contentType(contentType)
                            .build())
                    .addTransferListener(LoggingTransferListener.create())
                    .source(filePath).build());
@@ -201,10 +203,11 @@
     * @param inputStream è¦ä¸Šä¼ çš„输入流
     * @param key         åœ¨ Amazon S3 ä¸­çš„对象键
     * @param length      è¾“入流的长度
     * @param contentType æ–‡ä»¶å†…容类型
     * @return UploadResult åŒ…含上传后的文件信息
     * @throws OssException å¦‚果上传失败,抛出自定义异常
     */
    public UploadResult upload(InputStream inputStream, String key, Long length) {
    public UploadResult upload(InputStream inputStream, String key, Long length, String contentType) {
        // å¦‚果输入流不是 ByteArrayInputStream,则将其读取为字节数组再创建 ByteArrayInputStream
        if (!(inputStream instanceof ByteArrayInputStream)) {
            inputStream = new ByteArrayInputStream(IoUtil.readBytes(inputStream));
@@ -219,6 +222,7 @@
                    .putObjectRequest(
                        y -> y.bucket(properties.getBucketName())
                            .key(key)
                            .contentType(contentType)
                            .build())
                    .build());
@@ -335,7 +339,7 @@
     * @throws OssException å¦‚果上传失败,抛出自定义异常
     */
    public UploadResult uploadSuffix(byte[] data, String suffix) {
        return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length));
        return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), FileUtils.getMimeType(suffix));
    }
    /**
@@ -348,7 +352,7 @@
     * @throws OssException å¦‚果上传失败,抛出自定义异常
     */
    public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length) {
        return upload(inputStream, getPath(properties.getPrefix(), suffix), length);
        return upload(inputStream, getPath(properties.getPrefix(), suffix), length, FileUtils.getMimeType(suffix));
    }
    /**
@@ -360,7 +364,7 @@
     * @throws OssException å¦‚果上传失败,抛出自定义异常
     */
    public UploadResult uploadSuffix(File file, String suffix) {
        return upload(file.toPath(), getPath(properties.getPrefix(), suffix), null);
        return upload(file.toPath(), getPath(properties.getPrefix(), suffix), null, FileUtils.getMimeType(suffix));
    }
    /**
ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java
@@ -48,7 +48,10 @@
        }
        OssProperties properties = JsonUtils.parseObject(json, OssProperties.class);
        // ä½¿ç”¨ç§Ÿæˆ·æ ‡è¯†é¿å…å¤šä¸ªç§Ÿæˆ·ç›¸åŒkey实例覆盖
        String key = properties.getTenantId() + ":" + configKey;
        String key = configKey;
        if (StringUtils.isNotBlank(properties.getTenantId())) {
            key = properties.getTenantId() + ":" + configKey;
        }
        OssClient client = CLIENT_CACHE.get(key);
        // å®¢æˆ·ç«¯ä¸å­˜åœ¨æˆ–配置不相同则重新构建
        if (client == null || !client.checkPropertiesSame(properties)) {
ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/RedisExceptionHandler.java
@@ -23,7 +23,7 @@
    @ExceptionHandler(LockFailureException.class)
    public R<Void> handleLockFailureException(LockFailureException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("获取锁失败了'{}',发生Lock4j异常." + requestURI, e.getMessage());
        log.error("获取锁失败了'{}',发生Lock4j异常.", requestURI, e);
        return R.fail(HttpStatus.HTTP_UNAVAILABLE, "业务处理中,请稍后再试...");
    }
ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java
@@ -2,7 +2,6 @@
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.hutool.core.lang.Console;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.dromara.common.redis.utils.RedisUtils;
@@ -54,7 +53,7 @@
        } else {
            RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout));
        }
        CAFFEINE.put(key, value);
        CAFFEINE.invalidate(key);
    }
    /**
@@ -64,7 +63,7 @@
    public void update(String key, String value) {
        if (RedisUtils.hasKey(key)) {
            RedisUtils.setCacheObject(key, value, true);
            CAFFEINE.put(key, value);
            CAFFEINE.invalidate(key);
        }
    }
@@ -117,7 +116,7 @@
        } else {
            RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout));
        }
        CAFFEINE.put(key, object);
        CAFFEINE.invalidate(key);
    }
    /**
@@ -127,7 +126,7 @@
    public void updateObject(String key, Object object) {
        if (RedisUtils.hasKey(key)) {
            RedisUtils.setCacheObject(key, object, true);
            CAFFEINE.put(key, object);
            CAFFEINE.invalidate(key);
        }
    }
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java
@@ -1,6 +1,7 @@
package org.dromara.common.sms.config;
import org.dromara.common.sms.core.dao.PlusSmsDao;
import org.dromara.common.sms.handler.SmsExceptionHandler;
import org.dromara.sms4j.api.dao.SmsDao;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
@@ -21,4 +22,12 @@
        return new PlusSmsDao();
    }
    /**
     * å¼‚常处理器
     */
    @Bean
    public SmsExceptionHandler smsExceptionHandler() {
        return new SmsExceptionHandler();
    }
}
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/handler/SmsExceptionHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package org.dromara.common.sms.handler;
import cn.hutool.http.HttpStatus;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.sms4j.comm.exception.SmsBlendException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
 * SMS异常处理器
 *
 * @author AprilWind
 */
@Slf4j
@RestControllerAdvice
public class SmsExceptionHandler {
    /**
     * sms异常
     */
    @ExceptionHandler(SmsBlendException.class)
    public R<Void> handleSmsBlendException(SmsBlendException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生sms短信异常.", requestURI, e);
        return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, "短信发送失败,请稍后再试...");
    }
}
ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java
@@ -35,7 +35,7 @@
    @ConditionalOnBean(MybatisPlusConfig.class)
    @AutoConfiguration(after = {MybatisPlusConfig.class})
    static class MybatisPlusConfigation {
    static class MybatisPlusConfiguration {
        /**
         * å¤šç§Ÿæˆ·æ’ä»¶
ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java
@@ -1,6 +1,5 @@
package org.dromara.common.tenant.helper;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert;
import com.alibaba.ttl.TransmittableThreadLocal;
@@ -79,22 +78,28 @@
        }
    }
    public static void setDynamic(String tenantId) {
        setDynamic(tenantId, false);
    }
    /**
     * è®¾ç½®åŠ¨æ€ç§Ÿæˆ·(一直有效 éœ€è¦æ‰‹åŠ¨æ¸…ç†)
     * <p>
     * å¦‚果为未登录状态下 é‚£ä¹ˆåªåœ¨å½“前线程内生效
     *
     * @param tenantId ç§Ÿæˆ·id
     * @param global   æ˜¯å¦å…¨å±€ç”Ÿæ•ˆ
     */
    public static void setDynamic(String tenantId) {
    public static void setDynamic(String tenantId, boolean global) {
        if (!isEnable()) {
            return;
        }
        if (!isLogin()) {
        if (!isLogin() || !global) {
            TEMP_DYNAMIC_TENANT.set(tenantId);
            return;
        }
        String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
        RedisUtils.setCacheObject(cacheKey, tenantId);
        SaHolder.getStorage().set(cacheKey, tenantId);
    }
    /**
@@ -109,13 +114,13 @@
        if (!isLogin()) {
            return TEMP_DYNAMIC_TENANT.get();
        }
        String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
        String tenantId = (String) SaHolder.getStorage().get(cacheKey);
        // å¦‚果线程内有值 ä¼˜å…ˆè¿”回
        String tenantId = TEMP_DYNAMIC_TENANT.get();
        if (StringUtils.isNotBlank(tenantId)) {
            return tenantId;
        }
        String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
        tenantId = RedisUtils.getCacheObject(cacheKey);
        SaHolder.getStorage().set(cacheKey, tenantId);
        return tenantId;
    }
@@ -130,9 +135,9 @@
            TEMP_DYNAMIC_TENANT.remove();
            return;
        }
        TEMP_DYNAMIC_TENANT.remove();
        String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
        RedisUtils.deleteObject(cacheKey);
        SaHolder.getStorage().delete(cacheKey);
    }
    /**
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/WebSocketConfig.java
@@ -27,17 +27,20 @@
    @Bean
    public WebSocketConfigurer webSocketConfigurer(HandshakeInterceptor handshakeInterceptor,
                                                   WebSocketHandler webSocketHandler,
                                                   WebSocketProperties webSocketProperties) {
                                                   WebSocketHandler webSocketHandler, WebSocketProperties webSocketProperties) {
        // å¦‚æžœWebSocket的路径为空,则设置默认路径为 "/websocket"
        if (StrUtil.isBlank(webSocketProperties.getPath())) {
            webSocketProperties.setPath("/websocket");
        }
        // å¦‚果允许跨域访问的地址为空,则设置为 "*",表示允许所有来源的跨域请求
        if (StrUtil.isBlank(webSocketProperties.getAllowedOrigins())) {
            webSocketProperties.setAllowedOrigins("*");
        }
        // è¿”回一个WebSocketConfigurer对象,用于配置WebSocket
        return registry -> registry
            // æ·»åŠ WebSocket处理程序和拦截器到指定路径,设置允许的跨域来源
            .addHandler(webSocketHandler, webSocketProperties.getPath())
            .addInterceptors(handshakeInterceptor)
            .setAllowedOrigins(webSocketProperties.getAllowedOrigins());
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/constant/WebSocketConstants.java
@@ -6,6 +6,7 @@
 * @author zendwang
 */
public interface WebSocketConstants {
    /**
     * websocketSession中的参数的key
     */
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/handler/PlusWebSocketHandler.java
@@ -31,33 +31,42 @@
    }
    /**
     * å¤„理发送来的文本消息
     * å¤„理接收到的文本消息
     *
     * @param session
     * @param message
     * @throws Exception
     * @param session WebSocket会话
     * @param message æŽ¥æ”¶åˆ°çš„æ–‡æœ¬æ¶ˆæ¯
     * @throws Exception å¤„理消息过程中可能抛出的异常
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // ä»ŽWebSocket会话中获取登录用户信息
        LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
        List<Long> userIds = List.of(loginUser.getUserId());
        // åˆ›å»ºWebSocket消息DTO对象
        WebSocketMessageDto webSocketMessageDto = new WebSocketMessageDto();
        webSocketMessageDto.setSessionKeys(userIds);
        webSocketMessageDto.setSessionKeys(List.of(loginUser.getUserId()));
        webSocketMessageDto.setMessage(message.getPayload());
        WebSocketUtils.publishMessage(webSocketMessageDto);
    }
    /**
     * å¤„理接收到的二进制消息
     *
     * @param session WebSocket会话
     * @param message æŽ¥æ”¶åˆ°çš„二进制消息
     * @throws Exception å¤„理消息过程中可能抛出的异常
     */
    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
        super.handleBinaryMessage(session, message);
    }
    /**
     * å¿ƒè·³ç›‘测的回复
     * å¤„理接收到的Pong消息(心跳监测)
     *
     * @param session
     * @param message
     * @throws Exception
     * @param session WebSocket会话
     * @param message æŽ¥æ”¶åˆ°çš„Pong消息
     * @throws Exception å¤„理消息过程中可能抛出的异常
     */
    @Override
    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
@@ -65,11 +74,11 @@
    }
    /**
     * è¿žæŽ¥å‡ºé”™æ—¶
     * å¤„理WebSocket传输错误
     *
     * @param session
     * @param exception
     * @throws Exception
     * @param session   WebSocket会话
     * @param exception å‘生的异常
     * @throws Exception å¤„理过程中可能抛出的异常
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
@@ -77,10 +86,10 @@
    }
    /**
     * è¿žæŽ¥å…³é—­åŽ
     * åœ¨WebSocket连接关闭后执行清理操作
     *
     * @param session
     * @param status
     * @param session WebSocket会话
     * @param status  å…³é—­çŠ¶æ€ä¿¡æ¯
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
@@ -90,9 +99,9 @@
    }
    /**
     * æ˜¯å¦æ”¯æŒåˆ†ç‰‡æ¶ˆæ¯
     * æŒ‡ç¤ºå¤„理程序是否支持接收部分消息
     *
     * @return
     * @return å¦‚果支持接收部分消息,则返回true;否则返回false
     */
    @Override
    public boolean supportsPartialMessages() {
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java
@@ -18,24 +18,52 @@
    private static final Map<Long, WebSocketSession> USER_SESSION_MAP = new ConcurrentHashMap<>();
    /**
     * å°†WebSocket会话添加到用户会话Map中
     *
     * @param sessionKey ä¼šè¯é”®ï¼Œç”¨äºŽæ£€ç´¢ä¼šè¯
     * @param session    è¦æ·»åŠ çš„WebSocket会话
     */
    public static void addSession(Long sessionKey, WebSocketSession session) {
        USER_SESSION_MAP.put(sessionKey, session);
    }
    /**
     * ä»Žç”¨æˆ·ä¼šè¯Map中移除指定会话键对应的WebSocket会话
     *
     * @param sessionKey è¦ç§»é™¤çš„会话键
     */
    public static void removeSession(Long sessionKey) {
        if (USER_SESSION_MAP.containsKey(sessionKey)) {
            USER_SESSION_MAP.remove(sessionKey);
        }
    }
    /**
     * æ ¹æ®ä¼šè¯é”®ä»Žç”¨æˆ·ä¼šè¯Map中获取WebSocket会话
     *
     * @param sessionKey è¦èŽ·å–çš„ä¼šè¯é”®
     * @return ä¸Žç»™å®šä¼šè¯é”®å¯¹åº”çš„WebSocket会话,如果不存在则返回null
     */
    public static WebSocketSession getSessions(Long sessionKey) {
        return USER_SESSION_MAP.get(sessionKey);
    }
    /**
     * èŽ·å–å­˜å‚¨åœ¨ç”¨æˆ·ä¼šè¯Map中所有WebSocket会话的会话键集合
     *
     * @return æ‰€æœ‰WebSocket会话的会话键集合
     */
    public static Set<Long> getSessionsAll() {
        return USER_SESSION_MAP.keySet();
    }
    /**
     * æ£€æŸ¥ç»™å®šçš„会话键是否存在于用户会话Map中
     *
     * @param sessionKey è¦æ£€æŸ¥çš„会话键
     * @return å¦‚果存在对应的会话键,则返回true;否则返回false
     */
    public static Boolean existSession(Long sessionKey) {
        return USER_SESSION_MAP.containsKey(sessionKey);
    }
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/interceptor/PlusWebSocketInterceptor.java
@@ -1,8 +1,8 @@
package org.dromara.common.websocket.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.satoken.utils.LoginHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
@@ -21,13 +21,13 @@
public class PlusWebSocketInterceptor implements HandshakeInterceptor {
    /**
     * æ¡æ‰‹å‰
     * WebSocket握手之前执行的前置处理方法
     *
     * @param request    request
     * @param response   response
     * @param wsHandler  wsHandler
     * @param attributes attributes
     * @return æ˜¯å¦æ¡æ‰‹æˆåŠŸ
     * @param request    WebSocket握手请求
     * @param response   WebSocket握手响应
     * @param wsHandler  WebSocket处理程序
     * @param attributes ä¸ŽWebSocket会话关联的属性
     * @return å¦‚果允许握手继续进行,则返回true;否则返回false
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) {
@@ -37,15 +37,16 @@
    }
    /**
     * æ¡æ‰‹åŽ
     * WebSocket握手成功后执行的后置处理方法
     *
     * @param request   request
     * @param response  response
     * @param wsHandler wsHandler
     * @param exception å¼‚常
     * @param request   WebSocket握手请求
     * @param response  WebSocket握手响应
     * @param wsHandler WebSocket处理程序
     * @param exception æ¡æ‰‹è¿‡ç¨‹ä¸­å¯èƒ½å‡ºçŽ°çš„å¼‚å¸¸
     */
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        // åœ¨è¿™ä¸ªæ–¹æ³•中可以执行一些握手成功后的后续处理逻辑,比如记录日志或者其他操作
    }
}
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/listener/WebSocketTopicListener.java
@@ -1,9 +1,9 @@
package org.dromara.common.websocket.listener;
import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.websocket.holder.WebSocketSessionHolder;
import org.dromara.common.websocket.utils.WebSocketUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;
@@ -16,8 +16,15 @@
@Slf4j
public class WebSocketTopicListener implements ApplicationRunner, Ordered {
    /**
     * åœ¨Spring Boot应用程序启动时初始化WebSocket主题订阅监听器
     *
     * @param args åº”用程序参数
     * @throws Exception åˆå§‹åŒ–过程中可能抛出的异常
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // è®¢é˜…WebSocket消息
        WebSocketUtils.subscribeMessage((message) -> {
            log.info("WebSocket主题订阅收到消息session keys={} message={}", message.getSessionKeys(), message.getMessage());
            // å¦‚æžœkey不为空就按照key发消息 å¦‚果为空就群发
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java
@@ -29,10 +29,10 @@
public class WebSocketUtils {
    /**
     * å‘送消息
     * å‘指定的WebSocket会话发送消息
     *
     * @param sessionKey session主键 ä¸€èˆ¬ä¸ºç”¨æˆ·id
     * @param message    æ¶ˆæ¯æ–‡æœ¬
     * @param sessionKey è¦å‘送消息的用户id
     * @param message    è¦å‘送的消息内容
     */
    public static void sendMessage(Long sessionKey, String message) {
        WebSocketSession session = WebSocketSessionHolder.getSessions(sessionKey);
@@ -40,18 +40,18 @@
    }
    /**
     * è®¢é˜…消息
     * è®¢é˜…WebSocket消息主题,并提供一个消费者函数来处理接收到的消息
     *
     * @param consumer è‡ªå®šä¹‰å¤„理
     * @param consumer å¤„理WebSocket消息的消费者函数
     */
    public static void subscribeMessage(Consumer<WebSocketMessageDto> consumer) {
        RedisUtils.subscribe(WEB_SOCKET_TOPIC, WebSocketMessageDto.class, consumer);
    }
    /**
     * å‘布订阅的消息
     * å‘布WebSocket订阅消息
     *
     * @param webSocketMessage æ¶ˆæ¯å¯¹è±¡
     * @param webSocketMessage è¦å‘布的WebSocket消息对象
     */
    public static void publishMessage(WebSocketMessageDto webSocketMessage) {
        List<Long> unsentSessionKeys = new ArrayList<>();
@@ -76,9 +76,9 @@
    }
    /**
     * å‘布订阅的消息(群发)
     * å‘所有的WebSocket会话发布订阅的消息(群发)
     *
     * @param message æ¶ˆæ¯å†…容
     * @param message è¦å‘布的消息内容
     */
    public static void publishAll(String message) {
        WebSocketMessageDto broadcastMessage = new WebSocketMessageDto();
@@ -88,14 +88,31 @@
        });
    }
    /**
     * å‘指定的WebSocket会话发送Pong消息
     *
     * @param session è¦å‘送Pong消息的WebSocket会话
     */
    public static void sendPongMessage(WebSocketSession session) {
        sendMessage(session, new PongMessage());
    }
    /**
     * å‘指定的WebSocket会话发送文本消息
     *
     * @param session WebSocket会话
     * @param message è¦å‘送的文本消息内容
     */
    public static void sendMessage(WebSocketSession session, String message) {
        sendMessage(session, new TextMessage(message));
    }
    /**
     * å‘指定的WebSocket会话发送WebSocket消息对象
     *
     * @param session WebSocket会话
     * @param message è¦å‘送的WebSocket消息对象
     */
    private static void sendMessage(WebSocketSession session, WebSocketMessage<?> message) {
        if (session == null || !session.isOpen()) {
            log.warn("[send] session会话已经关闭");
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
@@ -3,10 +3,12 @@
import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.MimeTypeUtils;
import org.dromara.common.encrypt.annotation.ApiEncrypt;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.satoken.utils.LoginHelper;
@@ -19,9 +21,7 @@
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysRoleService;
import org.dromara.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -57,12 +57,14 @@
    }
    /**
     * ä¿®æ”¹ç”¨æˆ·
     * ä¿®æ”¹ç”¨æˆ·ä¿¡æ¯
     */
    @RepeatSubmit
    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<Void> updateProfile(@RequestBody SysUserProfileBo profile) {
    public R<Void> updateProfile(@Validated @RequestBody SysUserProfileBo profile) {
        SysUserBo user = BeanUtil.toBean(profile, SysUserBo.class);
        user.setUserId(LoginHelper.getUserId());
        String username = LoginHelper.getUsername();
        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
            return R.fail("修改用户'" + username + "'失败,手机号码已存在");
@@ -70,7 +72,6 @@
        if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
            return R.fail("修改用户'" + username + "'失败,邮箱账号已存在");
        }
        user.setUserId(LoginHelper.getUserId());
        if (userService.updateUserProfile(user) > 0) {
            return R.ok();
        }
@@ -82,6 +83,7 @@
     *
     * @param bo æ–°æ—§å¯†ç 
     */
    @RepeatSubmit
    @ApiEncrypt
    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping("/updatePwd")
@@ -106,6 +108,7 @@
     *
     * @param avatarfile ç”¨æˆ·å¤´åƒ
     */
    @RepeatSubmit
    @Log(title = "用户头像", businessType = BusinessType.UPDATE)
    @PostMapping(value = "/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public R<AvatarVo> avatar(@RequestPart("avatarfile") MultipartFile avatarfile) {
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
@@ -144,7 +144,7 @@
    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
    @GetMapping("/dynamic/{tenantId}")
    public R<Void> dynamicTenant(@NotBlank(message = "租户ID不能为空") @PathVariable String tenantId) {
        TenantHelper.setDynamic(tenantId);
        TenantHelper.setDynamic(tenantId, true);
        return R.ok();
    }
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java
@@ -1,14 +1,16 @@
package org.dromara.system.domain.bo;
import org.dromara.common.core.xss.Xss;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.sensitive.annotation.Sensitive;
import org.dromara.common.sensitive.core.SensitiveStrategy;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.dromara.common.core.constant.RegexConstants;
import org.dromara.common.core.xss.Xss;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.sensitive.annotation.Sensitive;
import org.dromara.common.sensitive.core.SensitiveStrategy;
/**
 * ä¸ªäººä¿¡æ¯ä¸šåŠ¡å¤„ç†
@@ -20,11 +22,6 @@
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class SysUserProfileBo extends BaseEntity {
    /**
     * ç”¨æˆ·ID
     */
    private Long userId;
    /**
     * ç”¨æˆ·æ˜µç§°
@@ -44,6 +41,7 @@
    /**
     * æ‰‹æœºå·ç 
     */
    @Pattern(regexp = RegexConstants.MOBILE, message = "手机号格式不正确")
    @Sensitive(strategy = SensitiveStrategy.PHONE)
    private String phonenumber;
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
@@ -37,6 +37,7 @@
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.*;
import org.dromara.system.service.ISysUserService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -338,6 +339,7 @@
     * @return ç»“æžœ
     */
    @Override
    @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId")
    @Transactional(rollbackFor = Exception.class)
    public int updateUser(SysUserBo user) {
        // æ–°å¢žç”¨æˆ·ä¸Žè§’色管理
@@ -386,6 +388,7 @@
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç»“æžœ
     */
    @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId")
    @Override
    public int updateUserProfile(SysUserBo user) {
        return baseMapper.update(null,
@@ -636,7 +639,10 @@
        if (CollUtil.isEmpty(userIds)) {
            return List.of();
        }
        List<SysUserVo> list = this.selectUserByIds(userIds, null);
        List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
            .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName)
            .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
            .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
        return BeanUtil.copyToList(list, UserDTO.class);
    }
ruoyi-modules/ruoyi-workflow/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3 @@
# å·¥ä½œæµè¯´æ˜Ž
工作流目前在未成熟阶段 åŽç»­ä»ä¼šç»åŽ†é‡æž„ ç”šè‡³é‡å†™(生产使用前请慎重考虑后续是否要更新维护)
ruoyi-modules/ruoyi-workflow/pom.xml
@@ -109,7 +109,10 @@
            <groupId>org.dromara</groupId>
            <artifactId>ruoyi-common-tenant</artifactId>
        </dependency>
        <dependency>
            <groupId>org.dromara</groupId>
            <artifactId>ruoyi-common-security</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/annotation/FlowListenerAnnotation.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java
@@ -71,9 +71,9 @@
    String ZIP = "ZIP";
    /**
     * æµç¨‹å®žä¾‹å¯¹è±¡
     * ä¸šåŠ¡ä¸Žæµç¨‹å®žä¾‹å…³è”å¯¹è±¡
     */
    String PROCESS_INSTANCE_VO = "processInstanceVo";
    String BUSINESS_INSTANCE_DTO = "businessInstanceDTO";
    /**
     * æµç¨‹å®šä¹‰é…ç½®
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java
@@ -58,33 +58,33 @@
    }
    /**
     * é€šè¿‡æµç¨‹å®žä¾‹id获取历史流程图
     * é€šè¿‡ä¸šåŠ¡id获取历史流程图
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey ä¸šåŠ¡id
     */
    @GetMapping("/getHistoryImage/{processInstanceId}")
    public R<String> getHistoryImage(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) {
        return R.ok("操作成功", actProcessInstanceService.getHistoryImage(processInstanceId));
    @GetMapping("/getHistoryImage/{businessKey}")
    public R<String> getHistoryImage(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
        return R.ok("操作成功", actProcessInstanceService.getHistoryImage(businessKey));
    }
    /**
     * é€šè¿‡æµç¨‹å®žä¾‹id获取历史流程图运行中,历史等节点
     * é€šè¿‡ä¸šåŠ¡id获取历史流程图运行中,历史等节点
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey ä¸šåŠ¡id
     */
    @GetMapping("/getHistoryList/{processInstanceId}")
    public R<Map<String, Object>> getHistoryList(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) {
        return R.ok("操作成功", actProcessInstanceService.getHistoryList(processInstanceId));
    @GetMapping("/getHistoryList/{businessKey}")
    public R<Map<String, Object>> getHistoryList(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
        return R.ok("操作成功", actProcessInstanceService.getHistoryList(businessKey));
    }
    /**
     * èŽ·å–å®¡æ‰¹è®°å½•
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey ä¸šåŠ¡id
     */
    @GetMapping("/getHistoryRecord/{processInstanceId}")
    public R<List<ActHistoryInfoVo>> getHistoryRecord(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) {
        return R.ok(actProcessInstanceService.getHistoryRecord(processInstanceId));
    @GetMapping("/getHistoryRecord/{businessKey}")
    public R<List<ActHistoryInfoVo>> getHistoryRecord(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
        return R.ok(actProcessInstanceService.getHistoryRecord(businessKey));
    }
    /**
@@ -102,37 +102,37 @@
    /**
     * è¿è¡Œä¸­çš„实例 åˆ é™¤ç¨‹å®žä¾‹ï¼Œåˆ é™¤åŽ†å²è®°å½•ï¼Œåˆ é™¤ä¸šåŠ¡ä¸Žæµç¨‹å…³è”ä¿¡æ¯
     *
     * @param processInstanceIds æµç¨‹å®žä¾‹id
     * @param businessKeys ä¸šåŠ¡id
     */
    @Log(title = "流程实例管理", businessType = BusinessType.DELETE)
    @RepeatSubmit()
    @DeleteMapping("/deleteRunAndHisInstance/{processInstanceIds}")
    public R<Void> deleteRunAndHisInstance(@NotNull(message = "流程实例id不能为空") @PathVariable String[] processInstanceIds) {
        return toAjax(actProcessInstanceService.deleteRunAndHisInstance(Arrays.asList(processInstanceIds)));
    @DeleteMapping("/deleteRunAndHisInstance/{businessKeys}")
    public R<Void> deleteRunAndHisInstance(@NotNull(message = "业务id不能为空") @PathVariable String[] businessKeys) {
        return toAjax(actProcessInstanceService.deleteRunAndHisInstance(Arrays.asList(businessKeys)));
    }
    /**
     * å·²å®Œæˆçš„实例 åˆ é™¤ç¨‹å®žä¾‹ï¼Œåˆ é™¤åŽ†å²è®°å½•ï¼Œåˆ é™¤ä¸šåŠ¡ä¸Žæµç¨‹å…³è”ä¿¡æ¯
     *
     * @param processInstanceIds æµç¨‹å®žä¾‹id
     * @param businessKeys ä¸šåŠ¡id
     */
    @Log(title = "流程实例管理", businessType = BusinessType.DELETE)
    @RepeatSubmit()
    @DeleteMapping("/deleteFinishAndHisInstance/{processInstanceIds}")
    public R<Void> deleteFinishAndHisInstance(@NotNull(message = "流程实例id不能为空") @PathVariable String[] processInstanceIds) {
        return toAjax(actProcessInstanceService.deleteFinishAndHisInstance(Arrays.asList(processInstanceIds)));
    @DeleteMapping("/deleteFinishAndHisInstance/{businessKeys}")
    public R<Void> deleteFinishAndHisInstance(@NotNull(message = "业务id不能为空") @PathVariable String[] businessKeys) {
        return toAjax(actProcessInstanceService.deleteFinishAndHisInstance(Arrays.asList(businessKeys)));
    }
    /**
     * æ’¤é”€æµç¨‹ç”³è¯·
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey ä¸šåŠ¡id
     */
    @Log(title = "流程实例管理", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping("/cancelProcessApply/{processInstanceId}")
    public R<Void> cancelProcessApply(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) {
        return toAjax(actProcessInstanceService.cancelProcessApply(processInstanceId));
    @PostMapping("/cancelProcessApply/{businessKey}")
    public R<Void> cancelProcessApply(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
        return toAjax(actProcessInstanceService.cancelProcessApply(businessKey));
    }
    /**
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java
@@ -225,7 +225,7 @@
    @RepeatSubmit()
    @PostMapping("/backProcess")
    public R<String> backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo backProcessBo) {
        return R.ok(actTaskService.backProcess(backProcessBo));
        return R.ok("操作成功", actTaskService.backProcess(backProcessBo));
    }
    /**
@@ -279,7 +279,7 @@
     */
    @GetMapping("/getTaskUserIdsByAddMultiInstance/{taskId}")
    public R<String> getTaskUserIdsByAddMultiInstance(@PathVariable String taskId) {
        return R.ok(actTaskService.getTaskUserIdsByAddMultiInstance(taskId));
        return R.ok("操作成功", actTaskService.getTaskUserIdsByAddMultiInstance(taskId));
    }
    /**
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java
@@ -32,7 +32,7 @@
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/leave")
@RequestMapping("/workflow/leave")
public class TestLeaveController extends BaseController {
    private final ITestLeaveService testLeaveService;
@@ -40,7 +40,7 @@
    /**
     * æŸ¥è¯¢è¯·å‡åˆ—表
     */
    @SaCheckPermission("demo:leave:list")
    @SaCheckPermission("workflow:leave:list")
    @GetMapping("/list")
    public TableDataInfo<TestLeaveVo> list(TestLeaveBo bo, PageQuery pageQuery) {
        return testLeaveService.queryPageList(bo, pageQuery);
@@ -49,7 +49,7 @@
    /**
     * å¯¼å‡ºè¯·å‡åˆ—表
     */
    @SaCheckPermission("demo:leave:export")
    @SaCheckPermission("workflow:leave:export")
    @Log(title = "请假", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(TestLeaveBo bo, HttpServletResponse response) {
@@ -62,7 +62,7 @@
     *
     * @param id ä¸»é”®
     */
    @SaCheckPermission("demo:leave:query")
    @SaCheckPermission("workflow:leave:query")
    @GetMapping("/{id}")
    public R<TestLeaveVo> getInfo(@NotNull(message = "主键不能为空")
                                  @PathVariable Long id) {
@@ -72,7 +72,7 @@
    /**
     * æ–°å¢žè¯·å‡
     */
    @SaCheckPermission("demo:leave:add")
    @SaCheckPermission("workflow:leave:add")
    @Log(title = "请假", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
@@ -83,7 +83,7 @@
    /**
     * ä¿®æ”¹è¯·å‡
     */
    @SaCheckPermission("demo:leave:edit")
    @SaCheckPermission("workflow:leave:edit")
    @Log(title = "请假", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
@@ -96,7 +96,7 @@
     *
     * @param ids ä¸»é”®ä¸²
     */
    @SaCheckPermission("demo:leave:remove")
    @SaCheckPermission("workflow:leave:remove")
    @Log(title = "请假", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java
@@ -54,5 +54,10 @@
     */
    private String remark;
    /**
     * çŠ¶æ€
     */
    private String status;
}
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java
@@ -19,10 +19,10 @@
    private static final long serialVersionUID = 1L;
    /**
     * æµç¨‹å®žä¾‹id
     * ä¸šåŠ¡id
     */
    @NotBlank(message = "流程实例id不能为空", groups = {AddGroup.class})
    private String processInstanceId;
    @NotBlank(message = "业务id不能为空", groups = {AddGroup.class})
    private String businessKey;
    /**
     * ä½œåºŸåŽŸå› 
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java
@@ -71,5 +71,10 @@
     */
    private String remark;
    /**
     * çŠ¶æ€
     */
    private String status;
}
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java
@@ -37,6 +37,10 @@
     */
    private String processInstanceId;
    /**
     * ç‰ˆæœ¬
     */
    private Integer version;
    /**
     * å¼€å§‹æ—¶é—´
     */
    private Date startTime;
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java
@@ -62,9 +62,9 @@
    private String remark;
    /**
     * æµç¨‹å®žä¾‹å¯¹è±¡
     * çŠ¶æ€
     */
    private ProcessInstanceVo processInstanceVo;
    @ExcelProperty(value = "状态")
    private String status;
}
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
package org.dromara.workflow.flowable.handler;
import org.dromara.common.core.domain.event.ProcessEvent;
import org.dromara.common.core.domain.event.ProcessTaskEvent;
import org.dromara.common.core.utils.SpringUtils;
import org.springframework.stereotype.Component;
/**
 * æµç¨‹ç›‘听服务
 *
 * @author may
 * @date 2024-06-02
 */
@Component
public class FlowProcessEventHandler {
    /**
     * æ€»ä½“流程监听(例如: æäº¤ é€€å›ž æ’¤é”€ ç»ˆæ­¢ ä½œåºŸç­‰)
     *
     * @param key         æµç¨‹key
     * @param businessKey ä¸šåŠ¡id
     * @param status      çŠ¶æ€
     * @param submit      å½“为true时为申请人节点办理
     */
    public void processHandler(String key, String businessKey, String status, boolean submit) {
        ProcessEvent processEvent = new ProcessEvent();
        processEvent.setKey(key);
        processEvent.setBusinessKey(businessKey);
        processEvent.setStatus(status);
        processEvent.setSubmit(submit);
        SpringUtils.context().publishEvent(processEvent);
    }
    /**
     * æ‰§è¡ŒåŠžç†ä»»åŠ¡ç›‘å¬
     *
     * @param keyNode     æµç¨‹å®šä¹‰key与流程节点标识(拼接方式:流程定义key_流程节点)
     * @param taskId      ä»»åŠ¡id
     * @param businessKey ä¸šåŠ¡id
     */
    public void processTaskHandler(String keyNode, String taskId, String businessKey) {
        ProcessTaskEvent processTaskEvent = new ProcessTaskEvent();
        processTaskEvent.setKeyNode(keyNode);
        processTaskEvent.setTaskId(taskId);
        processTaskEvent.setBusinessKey(businessKey);
        SpringUtils.context().publishEvent(processTaskEvent);
    }
}
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java
@@ -8,7 +8,6 @@
import org.flowable.job.service.JobHandler;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.variable.api.delegate.VariableScope;
/**
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowEventStrategy.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowProcessEventHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowTaskEventHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomProcessHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomTaskHandler.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveExecutionListener.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveTaskListener.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java
@@ -20,18 +20,18 @@
    /**
     * é€šè¿‡æµç¨‹å®žä¾‹id获取历史流程图
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey æµç¨‹å®žä¾‹id
     * @return ç»“æžœ
     */
    String getHistoryImage(String processInstanceId);
    String getHistoryImage(String businessKey);
    /**
     * é€šè¿‡æµç¨‹å®žä¾‹id获取历史流程图运行中,历史等节点
     * é€šè¿‡ä¸šåŠ¡id获取历史流程图运行中,历史等节点
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey ä¸šåŠ¡id
     * @return ç»“æžœ
     */
    Map<String, Object> getHistoryList(String processInstanceId);
    Map<String, Object> getHistoryList(String businessKey);
    /**
     * åˆ†é¡µæŸ¥è¯¢æ­£åœ¨è¿è¡Œçš„æµç¨‹å®žä¾‹
@@ -54,10 +54,10 @@
    /**
     * èŽ·å–å®¡æ‰¹è®°å½•
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey ä¸šåŠ¡id
     * @return ç»“æžœ
     */
    List<ActHistoryInfoVo> getHistoryRecord(String processInstanceId);
    List<ActHistoryInfoVo> getHistoryRecord(String businessKey);
    /**
     * ä½œåºŸæµç¨‹å®žä¾‹ï¼Œä¸ä¼šåˆ é™¤åŽ†å²è®°å½•(删除运行中的实例)
@@ -70,34 +70,26 @@
    /**
     * è¿è¡Œä¸­çš„实例 åˆ é™¤ç¨‹å®žä¾‹ï¼Œåˆ é™¤åŽ†å²è®°å½•ï¼Œåˆ é™¤ä¸šåŠ¡ä¸Žæµç¨‹å…³è”ä¿¡æ¯
     *
     * @param processInstanceIds æµç¨‹å®žä¾‹id
     * @return ç»“æžœ
     */
    boolean deleteRunAndHisInstance(List<String> processInstanceIds);
    /**
     * æŒ‰ç…§ä¸šåŠ¡id删除 è¿è¡Œä¸­çš„实例 åˆ é™¤ç¨‹å®žä¾‹ï¼Œåˆ é™¤åŽ†å²è®°å½•ï¼Œåˆ é™¤ä¸šåŠ¡ä¸Žæµç¨‹å…³è”ä¿¡æ¯
     *
     * @param businessKeys ä¸šåŠ¡id
     * @return ç»“æžœ
     */
    boolean deleteRunAndHisInstanceByBusinessKeys(List<String> businessKeys);
    boolean deleteRunAndHisInstance(List<String> businessKeys);
    /**
     * å·²å®Œæˆçš„实例 åˆ é™¤ç¨‹å®žä¾‹ï¼Œåˆ é™¤åŽ†å²è®°å½•ï¼Œåˆ é™¤ä¸šåŠ¡ä¸Žæµç¨‹å…³è”ä¿¡æ¯
     *
     * @param processInstanceIds æµç¨‹å®žä¾‹id
     * @param businessKeys ä¸šåŠ¡id
     * @return ç»“æžœ
     */
    boolean deleteFinishAndHisInstance(List<String> processInstanceIds);
    boolean deleteFinishAndHisInstance(List<String> businessKeys);
    /**
     * æ’¤é”€æµç¨‹ç”³è¯·
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey ä¸šåŠ¡id
     * @return ç»“æžœ
     */
    boolean cancelProcessApply(String processInstanceId);
    boolean cancelProcessApply(String businessKey);
    /**
     * åˆ†é¡µæŸ¥è¯¢å½“前登录人单据
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java
@@ -16,7 +16,7 @@
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.workflow.common.constant.FlowConstant;
import org.dromara.workflow.common.enums.BusinessStatusEnum;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.workflow.common.enums.TaskStatusEnum;
import org.dromara.workflow.domain.ActHiProcinst;
import org.dromara.workflow.domain.bo.ProcessInstanceBo;
@@ -26,8 +26,7 @@
import org.dromara.workflow.flowable.CustomDefaultProcessDiagramGenerator;
import org.dromara.workflow.flowable.cmd.DeleteExecutionCmd;
import org.dromara.workflow.flowable.cmd.ExecutionChildByExecutionIdCmd;
import org.dromara.workflow.flowable.strategy.FlowEventStrategy;
import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler;
import org.dromara.workflow.flowable.handler.FlowProcessEventHandler;
import org.dromara.workflow.service.IActHiProcinstService;
import org.dromara.workflow.service.IActProcessInstanceService;
import org.dromara.workflow.service.IWfNodeConfigService;
@@ -75,9 +74,9 @@
    private final TaskService taskService;
    private final IActHiProcinstService actHiProcinstService;
    private final ManagementService managementService;
    private final FlowEventStrategy flowEventStrategy;
    private final IWfTaskBackNodeService wfTaskBackNodeService;
    private final IWfNodeConfigService wfNodeConfigService;
    private final FlowProcessEventHandler flowProcessEventHandler;
    @Value("${flowable.activity-font-name}")
    private String activityFontName;
@@ -184,28 +183,28 @@
    }
    /**
     * é€šè¿‡æµç¨‹å®žä¾‹id获取历史流程图
     * é€šè¿‡ä¸šåŠ¡id获取历史流程图
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey ä¸šåŠ¡id
     */
    @SneakyThrows
    @Override
    public String getHistoryImage(String processInstanceId) {
    public String getHistoryImage(String businessKey) {
        String processDefinitionId;
        // èŽ·å–å½“å‰çš„æµç¨‹å®žä¾‹
        ProcessInstance processInstance = QueryUtils.instanceQuery(processInstanceId).singleResult();
        ProcessInstance processInstance = QueryUtils.businessKeyQuery(businessKey).singleResult();
        // å¦‚果流程已经结束,则得到结束节点
        if (Objects.isNull(processInstance)) {
            HistoricProcessInstance pi = QueryUtils.hisInstanceQuery(processInstanceId).singleResult();
            HistoricProcessInstance pi = QueryUtils.hisInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        } else {
            // æ ¹æ®æµç¨‹å®žä¾‹ID获得当前处于活动状态的ActivityId合集
            ProcessInstance pi = QueryUtils.instanceQuery(processInstanceId).singleResult();
            ProcessInstance pi = QueryUtils.instanceQuery(processInstance.getProcessInstanceId()).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        }
        // èŽ·å¾—æ´»åŠ¨çš„èŠ‚ç‚¹
        List<HistoricActivityInstance> highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
        List<HistoricActivityInstance> highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstance.getProcessInstanceId()).orderByHistoricActivityInstanceStartTime().asc().list();
        List<String> highLightedFlows = new ArrayList<>();
        List<String> highLightedNodes = new ArrayList<>();
@@ -240,15 +239,16 @@
    }
    /**
     * é€šè¿‡æµç¨‹å®žä¾‹id获取历史流程图运行中,历史等节点
     * é€šè¿‡ä¸šåŠ¡id获取历史流程图运行中,历史等节点
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey ä¸šåŠ¡id
     */
    @Override
    public Map<String, Object> getHistoryList(String processInstanceId) {
    public Map<String, Object> getHistoryList(String businessKey) {
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> taskList = new ArrayList<>();
        HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult();
        HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
        String processInstanceId = historicProcessInstance.getId();
        StringBuilder xml = new StringBuilder();
        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
        // èŽ·å–èŠ‚ç‚¹
@@ -280,7 +280,7 @@
            }
        }
        map.put("taskList", taskList);
        List<ActHistoryInfoVo> historyTaskList = getHistoryTaskList(processInstanceId);
        List<ActHistoryInfoVo> historyTaskList = getHistoryTaskList(processInstanceId, processDefinition.getVersion());
        map.put("historyList", historyTaskList);
        InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
        xml.append(IoUtil.read(inputStream, StandardCharsets.UTF_8));
@@ -292,8 +292,9 @@
     * èŽ·å–åŽ†å²ä»»åŠ¡èŠ‚ç‚¹ä¿¡æ¯
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param version           ç‰ˆæœ¬
     */
    private List<ActHistoryInfoVo> getHistoryTaskList(String processInstanceId) {
    private List<ActHistoryInfoVo> getHistoryTaskList(String processInstanceId, Integer version) {
        //查询任务办理记录
        List<HistoricTaskInstance> list = QueryUtils.hisTaskInstanceQuery(processInstanceId).orderByHistoricTaskInstanceEndTime().desc().list();
        list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed());
@@ -305,27 +306,48 @@
            if (ObjectUtil.isNotEmpty(historicTaskInstance.getDurationInMillis())) {
                actHistoryInfoVo.setRunDuration(getDuration(historicTaskInstance.getDurationInMillis()));
            }
            actHistoryInfoVo.setVersion(version);
            actHistoryInfoVoList.add(actHistoryInfoVo);
        }
        List<ActHistoryInfoVo> historyInfoVoList = new ArrayList<>();
        Map<String, List<ActHistoryInfoVo>> groupByKey = StreamUtils.groupByKey(actHistoryInfoVoList, ActHistoryInfoVo::getTaskDefinitionKey);
        for (Map.Entry<String, List<ActHistoryInfoVo>> entry : groupByKey.entrySet()) {
            ActHistoryInfoVo historyInfoVo = new ActHistoryInfoVo();
            BeanUtils.copyProperties(entry.getValue().get(0), historyInfoVo);
            actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey()) && e.getEndTime() == null).findFirst()
                .ifPresent(e -> {
                    historyInfoVo.setStatus("待处理");
                    historyInfoVo.setStartTime(e.getStartTime());
                    historyInfoVo.setEndTime(null);
                    historyInfoVo.setRunDuration(null);
                    if (ObjectUtil.isEmpty(e.getAssignee())) {
                        ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(e.getId());
            if (entry.getValue().size() > 1) {
                List<ActHistoryInfoVo> historyInfoVos = StreamUtils.filter(entry.getValue(), e -> StringUtils.isNotBlank(e.getAssignee()));
                if (CollUtil.isNotEmpty(historyInfoVos)) {
                    ActHistoryInfoVo infoVo = historyInfoVos.get(0);
                    BeanUtils.copyProperties(infoVo, historyInfoVo);
                    historyInfoVo.setStatus(infoVo.getEndTime() == null ? "待处理" : "已处理");
                    historyInfoVo.setStartTime(infoVo.getStartTime());
                    historyInfoVo.setEndTime(infoVo.getEndTime() == null ? null : infoVo.getEndTime());
                    historyInfoVo.setRunDuration(infoVo.getEndTime() == null ? null : infoVo.getRunDuration());
                    if (ObjectUtil.isEmpty(infoVo.getAssignee())) {
                        ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(infoVo.getId());
                        if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) {
                            historyInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr));
                        }
                    }
                });
                }
            } else {
                actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey())).findFirst()
                    .ifPresent(e -> {
                        BeanUtils.copyProperties(e, historyInfoVo);
                        historyInfoVo.setStatus(e.getEndTime() == null ? "待处理" : "已处理");
                        historyInfoVo.setStartTime(e.getStartTime());
                        historyInfoVo.setEndTime(e.getEndTime() == null ? null : e.getEndTime());
                        historyInfoVo.setRunDuration(e.getEndTime() == null ? null : e.getRunDuration());
                        if (ObjectUtil.isEmpty(e.getAssignee())) {
                            ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(e.getId());
                            if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) {
                                historyInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr));
                            }
                        }
                    });
            }
            historyInfoVoList.add(historyInfoVo);
        }
        return historyInfoVoList;
    }
@@ -333,13 +355,15 @@
    /**
     * èŽ·å–å®¡æ‰¹è®°å½•
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey ä¸šåŠ¡id
     */
    @Override
    public List<ActHistoryInfoVo> getHistoryRecord(String processInstanceId) {
    public List<ActHistoryInfoVo> getHistoryRecord(String businessKey) {
        // æŸ¥è¯¢ä»»åŠ¡åŠžç†è®°å½•
        List<HistoricTaskInstance> list = QueryUtils.hisTaskInstanceQuery(processInstanceId).orderByHistoricTaskInstanceEndTime().desc().list();
        List<HistoricTaskInstance> list = QueryUtils.hisTaskBusinessKeyQuery(businessKey).orderByHistoricTaskInstanceEndTime().desc().list();
        list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed());
        HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
        String processInstanceId = historicProcessInstance.getId();
        List<ActHistoryInfoVo> actHistoryInfoVoList = new ArrayList<>();
        List<Comment> processInstanceComments = taskService.getProcessInstanceComments(processInstanceId);
        //附件
@@ -440,7 +464,8 @@
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteRunInstance(ProcessInvalidBo processInvalidBo) {
        try {
            List<Task> list = QueryUtils.taskQuery(processInvalidBo.getProcessInstanceId()).list();
            List<Task> list = QueryUtils.taskQuery().processInstanceBusinessKey(processInvalidBo.getBusinessKey()).list();
            String processInstanceId = list.get(0).getProcessInstanceId();
            List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
            if (CollUtil.isNotEmpty(subTasks)) {
                subTasks.forEach(e -> taskService.deleteTask(e.getId()));
@@ -452,14 +477,13 @@
            for (Task task : StreamUtils.filter(list, e -> StringUtils.isBlank(e.getParentTaskId()))) {
                taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.INVALID.getStatus(), deleteReason);
            }
            HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInvalidBo.getProcessInstanceId()).singleResult();
            HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult();
            BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus());
            runtimeService.updateBusinessStatus(processInvalidBo.getProcessInstanceId(), BusinessStatusEnum.INVALID.getStatus());
            runtimeService.deleteProcessInstance(processInvalidBo.getProcessInstanceId(), deleteReason);
            FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(historicProcessInstance.getProcessDefinitionKey());
            if (processHandler != null) {
                processHandler.handleProcess(historicProcessInstance.getBusinessKey(), BusinessStatusEnum.INVALID.getStatus(), false);
            }
            runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.INVALID.getStatus());
            runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
            //流程作废监听
            flowProcessEventHandler.processHandler(historicProcessInstance.getProcessDefinitionKey(),
                historicProcessInstance.getBusinessKey(), BusinessStatusEnum.INVALID.getStatus(), false);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
@@ -470,40 +494,11 @@
    /**
     * è¿è¡Œä¸­çš„实例 åˆ é™¤ç¨‹å®žä¾‹ï¼Œåˆ é™¤åŽ†å²è®°å½•ï¼Œåˆ é™¤ä¸šåŠ¡ä¸Žæµç¨‹å…³è”ä¿¡æ¯
     *
     * @param processInstanceIds æµç¨‹å®žä¾‹id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteRunAndHisInstance(List<String> processInstanceIds) {
        try {
            // 1.删除运行中流程实例
            List<Task> list = QueryUtils.taskQuery(processInstanceIds).list();
            List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
            if (CollUtil.isNotEmpty(subTasks)) {
                subTasks.forEach(e -> taskService.deleteTask(e.getId()));
            }
            runtimeService.bulkDeleteProcessInstances(processInstanceIds, LoginHelper.getUserId() + "删除了当前流程申请");
            // 2.删除历史记录
            List<HistoricProcessInstance> historicProcessInstanceList = QueryUtils.hisInstanceQuery(new HashSet<>(processInstanceIds)).list();
            if (ObjectUtil.isNotEmpty(historicProcessInstanceList)) {
                historyService.bulkDeleteHistoricProcessInstances(processInstanceIds);
            }
            wfTaskBackNodeService.deleteByInstanceIds(processInstanceIds);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
    }
    /**
     * æŒ‰ç…§ä¸šåŠ¡id删除 è¿è¡Œä¸­çš„实例 åˆ é™¤ç¨‹å®žä¾‹ï¼Œåˆ é™¤åŽ†å²è®°å½•ï¼Œåˆ é™¤ä¸šåŠ¡ä¸Žæµç¨‹å…³è”ä¿¡æ¯
     *
     * @param businessKeys ä¸šåŠ¡id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteRunAndHisInstanceByBusinessKeys(List<String> businessKeys) {
    public boolean deleteRunAndHisInstance(List<String> businessKeys) {
        try {
            // 1.删除运行中流程实例
            List<ActHiProcinst> actHiProcinsts = actHiProcinstService.selectByBusinessKeyIn(businessKeys);
@@ -534,12 +529,18 @@
    /**
     * å·²å®Œæˆçš„实例 åˆ é™¤ç¨‹å®žä¾‹ï¼Œåˆ é™¤åŽ†å²è®°å½•ï¼Œåˆ é™¤ä¸šåŠ¡ä¸Žæµç¨‹å…³è”ä¿¡æ¯
     *
     * @param processInstanceIds æµç¨‹å®žä¾‹id
     * @param businessKeys ä¸šåŠ¡id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteFinishAndHisInstance(List<String> processInstanceIds) {
    public boolean deleteFinishAndHisInstance(List<String> businessKeys) {
        try {
            List<ActHiProcinst> actHiProcinsts = actHiProcinstService.selectByBusinessKeyIn(businessKeys);
            if (CollUtil.isEmpty(actHiProcinsts)) {
                log.warn("当前业务ID:{}查询到流程实例为空!", businessKeys);
                return false;
            }
            List<String> processInstanceIds = StreamUtils.toList(actHiProcinsts, ActHiProcinst::getId);
            historyService.bulkDeleteHistoricProcessInstances(processInstanceIds);
            wfTaskBackNodeService.deleteByInstanceIds(processInstanceIds);
            return true;
@@ -552,13 +553,13 @@
    /**
     * æ’¤é”€æµç¨‹ç”³è¯·
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     * @param businessKey ä¸šåŠ¡id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelProcessApply(String processInstanceId) {
    public boolean cancelProcessApply(String businessKey) {
        try {
            ProcessInstance processInstance = QueryUtils.instanceQuery(processInstanceId)
            ProcessInstance processInstance = QueryUtils.businessKeyQuery(businessKey)
                .startedBy(String.valueOf(LoginHelper.getUserId())).singleResult();
            if (ObjectUtil.isNull(processInstance)) {
                throw new ServiceException("您不是流程发起人,撤销失败!");
@@ -566,13 +567,14 @@
            if (processInstance.isSuspended()) {
                throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
            }
            String processInstanceId = processInstance.getId();
            BusinessStatusEnum.checkCancelStatus(processInstance.getBusinessStatus());
            List<Task> taskList = QueryUtils.taskQuery(processInstanceId).list();
            for (Task task : taskList) {
                taskService.setAssignee(task.getId(), null);
                taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.CANCEL.getStatus(), LoginHelper.getLoginUser().getNickname() + ":撤销申请");
            }
            HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery().finished().orderByHistoricTaskInstanceEndTime().asc().list().get(0);
            HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().asc().list().get(0);
            List<String> nodeIds = StreamUtils.toList(taskList, Task::getTaskDefinitionKey);
            runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(processInstanceId)
@@ -588,10 +590,9 @@
                managementService.executeCommand(deleteExecutionCmd);
            }
            runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.CANCEL.getStatus());
            FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey());
            if (processHandler != null) {
                processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.CANCEL.getStatus(), false);
            }
            //流程作废监听
            flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(),
                processInstance.getBusinessKey(), BusinessStatusEnum.CANCEL.getStatus(), false);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
@@ -18,16 +18,14 @@
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.workflow.common.constant.FlowConstant;
import org.dromara.workflow.common.enums.BusinessStatusEnum;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.workflow.common.enums.TaskStatusEnum;
import org.dromara.workflow.domain.ActHiTaskinst;
import org.dromara.workflow.domain.WfTaskBackNode;
import org.dromara.workflow.domain.bo.*;
import org.dromara.workflow.domain.vo.*;
import org.dromara.workflow.flowable.cmd.*;
import org.dromara.workflow.flowable.strategy.FlowEventStrategy;
import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler;
import org.dromara.workflow.flowable.strategy.FlowTaskEventHandler;
import org.dromara.workflow.flowable.handler.FlowProcessEventHandler;
import org.dromara.workflow.mapper.ActHiTaskinstMapper;
import org.dromara.workflow.mapper.ActTaskMapper;
import org.dromara.workflow.service.IActTaskService;
@@ -75,13 +73,13 @@
    private final HistoryService historyService;
    private final IdentityService identityService;
    private final ManagementService managementService;
    private final FlowEventStrategy flowEventStrategy;
    private final ActTaskMapper actTaskMapper;
    private final IWfTaskBackNodeService wfTaskBackNodeService;
    private final ActHiTaskinstMapper actHiTaskinstMapper;
    private final IWfNodeConfigService wfNodeConfigService;
    private final IWfDefinitionConfigService wfDefinitionConfigService;
    private final UserService userService;
    private final FlowProcessEventHandler flowProcessEventHandler;
    /**
     * å¯åŠ¨ä»»åŠ¡
@@ -159,15 +157,8 @@
    @Transactional(rollbackFor = Exception.class)
    public boolean completeTask(CompleteTaskBo completeTaskBo) {
        try {
            List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
            String userId = String.valueOf(LoginHelper.getUserId());
            TaskQuery taskQuery = QueryUtils.taskQuery();
            taskQuery.taskId(completeTaskBo.getTaskId()).taskCandidateOrAssigned(userId);
            if (CollUtil.isNotEmpty(roles)) {
                List<String> groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
                taskQuery.taskCandidateGroupIn(groupIds);
            }
            Task task = taskQuery.singleResult();
            Task task = WorkflowUtils.getTaskByCurrentUser(completeTaskBo.getTaskId());
            if (task == null) {
                throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
            }
@@ -186,19 +177,15 @@
            //附件上传
            AttachmentCmd attachmentCmd = new AttachmentCmd(completeTaskBo.getFileId(), task.getId(), task.getProcessInstanceId());
            managementService.executeCommand(attachmentCmd);
            FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey());
            String businessStatus = WorkflowUtils.getBusinessStatus(task.getProcessInstanceId());
            String businessStatus = WorkflowUtils.getBusinessStatus(processInstance.getBusinessKey());
            //流程提交监听
            if (BusinessStatusEnum.DRAFT.getStatus().equals(businessStatus) || BusinessStatusEnum.BACK.getStatus().equals(businessStatus) || BusinessStatusEnum.CANCEL.getStatus().equals(businessStatus)) {
                if (processHandler != null) {
                    processHandler.handleProcess(processInstance.getBusinessKey(), businessStatus, true);
                }
                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(), businessStatus, true);
            }
            runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.WAITING.getStatus());
            String key = processInstance.getProcessDefinitionKey() + "_" + task.getTaskDefinitionKey();
            FlowTaskEventHandler taskHandler = flowEventStrategy.getTaskHandler(key);
            if (taskHandler != null) {
                taskHandler.handleTask(task.getId(), processInstance.getBusinessKey());
            }
            //办理监听
            String keyNode = processInstance.getProcessDefinitionKey() + "_" + task.getTaskDefinitionKey();
            flowProcessEventHandler.processTaskHandler(keyNode, task.getId(), processInstance.getBusinessKey());
            //办理意见
            taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "同意" : completeTaskBo.getMessage());
            //办理任务
@@ -214,9 +201,8 @@
            if (pi == null) {
                UpdateBusinessStatusCmd updateBusinessStatusCmd = new UpdateBusinessStatusCmd(task.getProcessInstanceId(), BusinessStatusEnum.FINISH.getStatus());
                managementService.executeCommand(updateBusinessStatusCmd);
                if (processHandler != null) {
                    processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.FINISH.getStatus(), false);
                }
                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(),
                    BusinessStatusEnum.FINISH.getStatus(), false);
            } else {
                List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
                for (Task t : list) {
@@ -470,8 +456,8 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delegateTask(DelegateBo delegateBo) {
        TaskQuery query = QueryUtils.taskQuery();
        TaskEntity task = (TaskEntity) query.taskId(delegateBo.getTaskId()).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult();
        Task task = WorkflowUtils.getTaskByCurrentUser(delegateBo.getTaskId());
        if (ObjectUtil.isEmpty(task)) {
            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
        }
@@ -527,10 +513,9 @@
                runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.TERMINATION.getStatus());
                runtimeService.deleteProcessInstance(task.getProcessInstanceId(), StrUtil.EMPTY);
            }
            FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(historicProcessInstance.getProcessDefinitionKey());
            if (processHandler != null) {
                processHandler.handleProcess(historicProcessInstance.getBusinessKey(), BusinessStatusEnum.TERMINATION.getStatus(), false);
            }
            //流程终止监听
            flowProcessEventHandler.processHandler(historicProcessInstance.getProcessDefinitionKey(),
                historicProcessInstance.getBusinessKey(), BusinessStatusEnum.TERMINATION.getStatus(), false);
            return true;
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
@@ -544,7 +529,7 @@
     */
    @Override
    public boolean transferTask(TransmitBo transmitBo) {
        Task task = QueryUtils.taskQuery().taskId(transmitBo.getTaskId()).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult();
        Task task = WorkflowUtils.getTaskByCurrentUser(transmitBo.getTaskId());
        if (ObjectUtil.isEmpty(task)) {
            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
        }
@@ -669,9 +654,9 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String backProcess(BackProcessBo backProcessBo) {
        TaskQuery query = QueryUtils.taskQuery();
        String userId = String.valueOf(LoginHelper.getUserId());
        Task task = query.taskId(backProcessBo.getTaskId()).taskCandidateOrAssigned(userId).singleResult();
        Task task = WorkflowUtils.getTaskByCurrentUser(backProcessBo.getTaskId());
        if (ObjectUtil.isEmpty(task)) {
            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
        }
@@ -705,7 +690,9 @@
            MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
            if (multiInstance == null && taskList.size() > 1) {
                List<Task> tasks = StreamUtils.filter(taskList, e -> !e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));
                actHiTaskinstMapper.deleteBatchIds(StreamUtils.toList(tasks, Task::getId));
                if (CollUtil.isNotEmpty(tasks)) {
                    actHiTaskinstMapper.deleteBatchIds(StreamUtils.toList(tasks, Task::getId));
                }
            }
@@ -728,10 +715,8 @@
            WfTaskBackNode wfTaskBackNode = wfTaskBackNodeService.getListByInstanceIdAndNodeId(task.getProcessInstanceId(), backProcessBo.getTargetActivityId());
            if (ObjectUtil.isNotNull(wfTaskBackNode) && wfTaskBackNode.getOrderNo() == 0) {
                runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.BACK.getStatus());
                FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey());
                if (processHandler != null) {
                    processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false);
                }
                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(),
                    processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false);
            }
            //删除驳回后的流程节点
            wfTaskBackNodeService.deleteBackTaskNode(processInstanceId, backProcessBo.getTargetActivityId());
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java
@@ -1,10 +1,14 @@
package org.dromara.workflow.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.event.ProcessEvent;
import org.dromara.common.core.domain.event.ProcessTaskEvent;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.service.WorkflowService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
@@ -15,9 +19,8 @@
import org.dromara.workflow.domain.bo.TestLeaveBo;
import org.dromara.workflow.domain.vo.TestLeaveVo;
import org.dromara.workflow.mapper.TestLeaveMapper;
import org.dromara.workflow.service.IActProcessInstanceService;
import org.dromara.workflow.service.ITestLeaveService;
import org.dromara.workflow.utils.WorkflowUtils;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -32,19 +35,18 @@
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class TestLeaveServiceImpl implements ITestLeaveService {
    private final TestLeaveMapper baseMapper;
    private final IActProcessInstanceService actProcessInstanceService;
    private final WorkflowService workflowService;
    /**
     * æŸ¥è¯¢è¯·å‡
     */
    @Override
    public TestLeaveVo queryById(Long id) {
        TestLeaveVo testLeaveVo = baseMapper.selectVoById(id);
        WorkflowUtils.setProcessInstanceVo(testLeaveVo, String.valueOf(id));
        return testLeaveVo;
        return baseMapper.selectVoById(id);
    }
    /**
@@ -54,13 +56,7 @@
    public TableDataInfo<TestLeaveVo> queryPageList(TestLeaveBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TestLeave> lqw = buildQueryWrapper(bo);
        Page<TestLeaveVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        TableDataInfo<TestLeaveVo> build = TableDataInfo.build(result);
        List<TestLeaveVo> rows = build.getRows();
        if (CollUtil.isNotEmpty(rows)) {
            List<String> ids = StreamUtils.toList(rows, e -> String.valueOf(e.getId()));
            WorkflowUtils.setProcessInstanceListVo(rows, ids, "id");
        }
        return build;
        return TableDataInfo.build(result);
    }
    /**
@@ -87,13 +83,14 @@
    @Override
    public TestLeaveVo insertByBo(TestLeaveBo bo) {
        TestLeave add = MapstructUtils.convert(bo, TestLeave.class);
        if (StringUtils.isBlank(add.getStatus())) {
            add.setStatus(BusinessStatusEnum.DRAFT.getStatus());
        }
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        TestLeaveVo testLeaveVo = MapstructUtils.convert(add, TestLeaveVo.class);
        WorkflowUtils.setProcessInstanceVo(testLeaveVo, String.valueOf(add.getId()));
        return testLeaveVo;
        return MapstructUtils.convert(add, TestLeaveVo.class);
    }
    /**
@@ -103,9 +100,7 @@
    public TestLeaveVo updateByBo(TestLeaveBo bo) {
        TestLeave update = MapstructUtils.convert(bo, TestLeave.class);
        baseMapper.updateById(update);
        TestLeaveVo testLeaveVo = MapstructUtils.convert(update, TestLeaveVo.class);
        WorkflowUtils.setProcessInstanceVo(testLeaveVo, String.valueOf(update.getId()));
        return testLeaveVo;
        return MapstructUtils.convert(update, TestLeaveVo.class);
    }
    /**
@@ -115,7 +110,38 @@
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids) {
        List<String> idList = StreamUtils.toList(ids, String::valueOf);
        actProcessInstanceService.deleteRunAndHisInstanceByBusinessKeys(idList);
        workflowService.deleteRunAndHisInstance(idList);
        return baseMapper.deleteBatchIds(ids) > 0;
    }
    /**
     * æ€»ä½“流程监听(例如: æäº¤ é€€å›ž æ’¤é”€ ç»ˆæ­¢ ä½œåºŸç­‰)
     *
     * @param processEvent å‚æ•°
     */
    @EventListener(condition = "#processEvent.key=='leave1'")
    public void processHandler(ProcessEvent processEvent) {
        log.info("当前任务执行了{}", processEvent.toString());
        TestLeave testLeave = baseMapper.selectById(Long.valueOf(processEvent.getBusinessKey()));
        testLeave.setStatus(processEvent.getStatus());
        if (processEvent.isSubmit()) {
            testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
        }
        baseMapper.updateById(testLeave);
    }
    /**
     * æ‰§è¡ŒåŠžç†ä»»åŠ¡ç›‘å¬
     *
     * @param processTaskEvent å‚æ•°
     */
    @EventListener(condition = "#processTaskEvent.keyNode=='leave1_Activity_14633hx'")
    public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
        log.info("当前任务执行了{}", processTaskEvent.toString());
        TestLeave testLeave = baseMapper.selectById(Long.valueOf(processTaskEvent.getBusinessKey()));
        testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
        baseMapper.updateById(testLeave);
    }
}
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,119 @@
package org.dromara.workflow.service.impl;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.service.WorkflowService;
import org.dromara.workflow.domain.ActHiProcinst;
import org.dromara.workflow.service.IActHiProcinstService;
import org.dromara.workflow.service.IActProcessInstanceService;
import org.dromara.workflow.utils.WorkflowUtils;
import org.flowable.engine.RuntimeService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
 * é€šç”¨ å·¥ä½œæµæœåŠ¡å®žçŽ°
 *
 * @author may
 */
@RequiredArgsConstructor
@Service
public class WorkflowServiceImpl implements WorkflowService {
    private final IActProcessInstanceService iActProcessInstanceService;
    private final RuntimeService runtimeService;
    private final IActHiProcinstService iActHiProcinstService;
    /**
     * è¿è¡Œä¸­çš„实例 åˆ é™¤ç¨‹å®žä¾‹ï¼Œåˆ é™¤åŽ†å²è®°å½•ï¼Œåˆ é™¤ä¸šåŠ¡ä¸Žæµç¨‹å…³è”ä¿¡æ¯
     *
     * @param businessKeys ä¸šåŠ¡id
     * @return ç»“æžœ
     */
    @Override
    public boolean deleteRunAndHisInstance(List<String> businessKeys) {
        return iActProcessInstanceService.deleteRunAndHisInstance(businessKeys);
    }
    /**
     * èŽ·å–å½“å‰æµç¨‹çŠ¶æ€
     *
     * @param taskId ä»»åŠ¡id
     */
    @Override
    public String getBusinessStatusByTaskId(String taskId) {
        return WorkflowUtils.getBusinessStatusByTaskId(taskId);
    }
    /**
     * èŽ·å–å½“å‰æµç¨‹çŠ¶æ€
     *
     * @param businessKey ä¸šåŠ¡id
     */
    @Override
    public String getBusinessStatus(String businessKey) {
        return WorkflowUtils.getBusinessStatus(businessKey);
    }
    /**
     * è®¾ç½®æµç¨‹å˜é‡(全局变量)
     *
     * @param taskId       ä»»åŠ¡id
     * @param variableName å˜é‡åç§°
     * @param value        å˜é‡å€¼
     */
    @Override
    public void setVariable(String taskId, String variableName, Object value) {
        runtimeService.setVariable(taskId, variableName, value);
    }
    /**
     * è®¾ç½®æµç¨‹å˜é‡(全局变量)
     *
     * @param taskId    ä»»åŠ¡id
     * @param variables æµç¨‹å˜é‡
     */
    @Override
    public void setVariables(String taskId, Map<String, Object> variables) {
        runtimeService.setVariables(taskId, variables);
    }
    /**
     * è®¾ç½®æµç¨‹å˜é‡(本地变量,非全局变量)
     *
     * @param taskId       ä»»åŠ¡id
     * @param variableName å˜é‡åç§°
     * @param value        å˜é‡å€¼
     */
    @Override
    public void setVariableLocal(String taskId, String variableName, Object value) {
        runtimeService.setVariableLocal(taskId, variableName, value);
    }
    /**
     * è®¾ç½®æµç¨‹å˜é‡(本地变量,非全局变量)
     *
     * @param taskId    ä»»åŠ¡id
     * @param variables æµç¨‹å˜é‡
     */
    @Override
    public void setVariablesLocal(String taskId, Map<String, Object> variables) {
        runtimeService.setVariablesLocal(taskId, variables);
    }
    /**
     * æŒ‰ç…§ä¸šåŠ¡id查询流程实例id
     *
     * @param businessKey ä¸šåŠ¡id
     * @return ç»“æžœ
     */
    @Override
    public String getInstanceIdByBusinessKey(String businessKey) {
        ActHiProcinst actHiProcinst = iActHiProcinstService.selectByBusinessKey(businessKey);
        if (actHiProcinst == null) {
            return StrUtil.EMPTY;
        }
        return actHiProcinst.getId();
    }
}
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java
@@ -12,6 +12,7 @@
import org.flowable.engine.repository.DeploymentQuery;
import org.flowable.engine.repository.ModelQuery;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceQuery;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
@@ -75,6 +76,10 @@
        return hisTaskInstanceQuery().processInstanceId(processInstanceId);
    }
    public static HistoricTaskInstanceQuery hisTaskBusinessKeyQuery(String businessKey) {
        return hisTaskInstanceQuery().processInstanceBusinessKey(businessKey);
    }
    public static ProcessInstanceQuery instanceQuery() {
        ProcessInstanceQuery query = PROCESS_ENGINE.getRuntimeService().createProcessInstanceQuery();
        if (TenantHelper.isEnable()) {
@@ -85,6 +90,10 @@
    public static ProcessInstanceQuery instanceQuery(String processInstanceId) {
        return instanceQuery().processInstanceId(processInstanceId);
    }
    public static ProcessInstanceQuery businessKeyQuery(String businessKey) {
        return instanceQuery().processInstanceBusinessKey(businessKey);
    }
    public static ProcessInstanceQuery instanceQuery(Set<String> processInstanceIds) {
@@ -101,6 +110,10 @@
    public static HistoricProcessInstanceQuery hisInstanceQuery(String processInstanceId) {
        return hisInstanceQuery().processInstanceId(processInstanceId);
    }
    public static HistoricProcessInstanceQuery hisBusinessKeyQuery(String businessKey) {
        return hisInstanceQuery().processInstanceBusinessKey(businessKey);
    }
    public static HistoricProcessInstanceQuery hisInstanceQuery(Set<String> processInstanceIds) {
@@ -145,9 +158,11 @@
        if (task == null) {
            return null;
        }
        ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
        TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class);
        taskVo.setBusinessKey(processInstance.getBusinessKey());
        taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
        String businessStatus = WorkflowUtils.getBusinessStatus(taskVo.getProcessInstanceId());
        String businessStatus = WorkflowUtils.getBusinessStatus(taskVo.getBusinessKey());
        taskVo.setBusinessStatus(businessStatus);
        return taskVo;
    }
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java
@@ -1,34 +1,30 @@
package org.dromara.workflow.utils;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.dto.UserDTO;
import org.dromara.common.core.service.UserService;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.reflect.ReflectUtils;
import org.dromara.common.mail.utils.MailUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.websocket.dto.WebSocketMessageDto;
import org.dromara.common.websocket.utils.WebSocketUtils;
import org.dromara.workflow.common.constant.FlowConstant;
import org.dromara.workflow.common.enums.BusinessStatusEnum;
import org.dromara.workflow.common.enums.MessageTypeEnum;
import org.dromara.workflow.common.enums.TaskStatusEnum;
import org.dromara.workflow.domain.ActHiProcinst;
import org.dromara.workflow.domain.ActHiTaskinst;
import org.dromara.workflow.domain.vo.MultiInstanceVo;
import org.dromara.workflow.domain.vo.ParticipantVo;
import org.dromara.workflow.domain.vo.ProcessInstanceVo;
import org.dromara.workflow.flowable.cmd.UpdateHiTaskInstCmd;
import org.dromara.workflow.mapper.ActHiTaskinstMapper;
import org.dromara.workflow.service.IActHiProcinstService;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.common.engine.api.delegate.Expression;
@@ -38,12 +34,11 @@
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.flowable.identitylink.api.history.HistoricIdentityLink;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import java.util.*;
import static org.dromara.workflow.common.constant.FlowConstant.PROCESS_INSTANCE_VO;
/**
 * å·¥ä½œæµå·¥å…·
@@ -54,8 +49,6 @@
public class WorkflowUtils {
    private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class);
    private static final UserService USER_SERVICE = SpringUtils.getBean(UserService.class);
    private static final IActHiProcinstService ACT_HI_PROCINST_SERVICE = SpringUtils.getBean(IActHiProcinstService.class);
    private static final ActHiTaskinstMapper ACT_HI_TASKINST_MAPPER = SpringUtils.getBean(ActHiTaskinstMapper.class);
    /**
@@ -133,6 +126,7 @@
     * @param taskId ä»»åŠ¡id
     */
    public static ParticipantVo getCurrentTaskParticipant(String taskId) {
        UserService userService = SpringUtils.getBean(UserService.class);
        ParticipantVo participantVo = new ParticipantVo();
        List<HistoricIdentityLink> linksForTask = PROCESS_ENGINE.getHistoryService().getHistoricIdentityLinksForTask(taskId);
        Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
@@ -140,10 +134,10 @@
            List<HistoricIdentityLink> groupList = StreamUtils.filter(linksForTask, e -> StringUtils.isNotBlank(e.getGroupId()));
            if (CollUtil.isNotEmpty(groupList)) {
                List<Long> groupIds = StreamUtils.toList(groupList, e -> Long.valueOf(e.getGroupId()));
                List<Long> userIds = USER_SERVICE.selectUserIdsByRoleIds(groupIds);
                List<Long> userIds = userService.selectUserIdsByRoleIds(groupIds);
                if (CollUtil.isNotEmpty(userIds)) {
                    participantVo.setGroupIds(groupIds);
                    List<UserDTO> userList = USER_SERVICE.selectListByIds(userIds);
                    List<UserDTO> userList = userService.selectListByIds(userIds);
                    if (CollUtil.isNotEmpty(userList)) {
                        List<Long> userIdList = StreamUtils.toList(userList, UserDTO::getUserId);
                        List<String> nickNames = StreamUtils.toList(userList, UserDTO::getNickName);
@@ -162,7 +156,7 @@
                    }
                }
                List<UserDTO> userList = USER_SERVICE.selectListByIds(userIdList);
                List<UserDTO> userList = userService.selectListByIds(userIdList);
                if (CollUtil.isNotEmpty(userList)) {
                    List<Long> userIds = StreamUtils.toList(userList, UserDTO::getUserId);
                    List<String> nickNames = StreamUtils.toList(userList, UserDTO::getNickName);
@@ -225,70 +219,11 @@
    /**
     * èŽ·å–å½“å‰æµç¨‹çŠ¶æ€
     *
     * @param processInstanceId æµç¨‹å®žä¾‹id
     */
    public static String getBusinessStatus(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult();
        return historicProcessInstance.getBusinessStatus();
    }
    /**
     * è®¾ç½®æµç¨‹å®žä¾‹å¯¹è±¡
     *
     * @param obj         ä¸šåŠ¡å¯¹è±¡
     * @param businessKey ä¸šåŠ¡id
     */
    public static void setProcessInstanceVo(Object obj, String businessKey) {
        if (StringUtils.isBlank(businessKey) || obj == null) {
            return;
        }
        ActHiProcinst actHiProcinst = ACT_HI_PROCINST_SERVICE.selectByBusinessKey(businessKey);
        if (actHiProcinst == null) {
            ProcessInstanceVo processInstanceVo = new ProcessInstanceVo();
            processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus());
            ReflectUtils.invokeSetter(obj, PROCESS_INSTANCE_VO, processInstanceVo);
            return;
        }
        ProcessInstanceVo processInstanceVo = BeanUtil.toBean(actHiProcinst, ProcessInstanceVo.class);
        processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus()));
        ReflectUtils.invokeSetter(obj, PROCESS_INSTANCE_VO, processInstanceVo);
    }
    /**
     * è®¾ç½®æµç¨‹å®žä¾‹å¯¹è±¡
     *
     * @param obj       ä¸šåŠ¡å¯¹è±¡
     * @param idList    ä¸šåŠ¡id
     * @param fieldName ä¸»é”®å±žæ€§åç§°
     */
    public static void setProcessInstanceListVo(Object obj, List<String> idList, String fieldName) {
        if (CollUtil.isEmpty(idList) || obj == null) {
            return;
        }
        List<ActHiProcinst> actHiProcinstList = ACT_HI_PROCINST_SERVICE.selectByBusinessKeyIn(idList);
        if (obj instanceof Collection<?> collection) {
            for (Object o : collection) {
                String fieldValue = ReflectUtils.invokeGetter(o, fieldName).toString();
                if (CollUtil.isEmpty(actHiProcinstList)) {
                    ProcessInstanceVo processInstanceVo = new ProcessInstanceVo();
                    processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus());
                    processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus()));
                    ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo);
                } else {
                    ActHiProcinst actHiProcinst = actHiProcinstList.stream().filter(e -> e.getBusinessKey().equals(fieldValue)).findFirst().orElse(null);
                    if (ObjectUtil.isNotEmpty(actHiProcinst)) {
                        ProcessInstanceVo processInstanceVo = BeanUtil.toBean(actHiProcinst, ProcessInstanceVo.class);
                        processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus()));
                        ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo);
                    } else {
                        ProcessInstanceVo processInstanceVo = new ProcessInstanceVo();
                        processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus());
                        processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus()));
                        ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo);
                    }
                }
            }
        }
    public static String getBusinessStatus(String businessKey) {
        HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
        return historicProcessInstance.getBusinessStatus();
    }
    /**
@@ -300,6 +235,7 @@
     * @param message     æ¶ˆæ¯å†…容,为空则发送默认配置的消息内容
     */
    public static void sendMessage(List<Task> list, String name, List<String> messageType, String message) {
        UserService userService = SpringUtils.getBean(UserService.class);
        Set<Long> userIds = new HashSet<>();
        if (StringUtils.isBlank(message)) {
            message = "有新的【" + name + "】单据已经提交至您的待办,请您及时处理。";
@@ -307,7 +243,7 @@
        for (Task t : list) {
            ParticipantVo taskParticipant = WorkflowUtils.getCurrentTaskParticipant(t.getId());
            if (CollUtil.isNotEmpty(taskParticipant.getGroupIds())) {
                List<Long> userIdList = USER_SERVICE.selectUserIdsByRoleIds(taskParticipant.getGroupIds());
                List<Long> userIdList = userService.selectUserIdsByRoleIds(taskParticipant.getGroupIds());
                if (CollUtil.isNotEmpty(userIdList)) {
                    userIds.addAll(userIdList);
                }
@@ -318,7 +254,7 @@
            }
        }
        if (CollUtil.isNotEmpty(userIds)) {
            List<UserDTO> userList = USER_SERVICE.selectListByIds(new ArrayList<>(userIds));
            List<UserDTO> userList = userService.selectListByIds(new ArrayList<>(userIds));
            for (String code : messageType) {
                MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code);
                if (ObjectUtil.isNotEmpty(messageTypeEnum)) {
@@ -340,4 +276,22 @@
            }
        }
    }
    /**
     * æ ¹æ®ä»»åŠ¡id查询 å½“前用户的任务,检查 å½“前人员 æ˜¯å¦æ˜¯è¯¥ taskId çš„办理人
     *
     * @param taskId ä»»åŠ¡id
     * @return ç»“æžœ
     */
    public static Task getTaskByCurrentUser(String taskId) {
        TaskQuery taskQuery = QueryUtils.taskQuery();
        taskQuery.taskId(taskId).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId()));
        List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
        if (CollUtil.isNotEmpty(roles)) {
            List<String> groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
            taskQuery.taskCandidateGroupIn(groupIds);
        }
        return taskQuery.singleResult();
    }
}
script/bpmn/Ä£ÐÍ.zip
Binary files differ
script/sql/flowable.sql
@@ -27,6 +27,7 @@
    end_date     datetime                     not null comment '结束时间',
    leave_days  int(10)                      not null comment '请假天数',
    remark      varchar(255)                 null comment '请假原因',
    status      varchar(255)                 null comment '状态',
    create_dept bigint                       null comment '创建部门',
    create_by   bigint                       null comment '创建者',
    create_time datetime                     null comment '创建时间',
@@ -112,7 +113,7 @@
)
    comment '表单管理';
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, sysdate(), 1, sysdate());
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, sysdate(), 1, sysdate());
create table wf_node_config
(
@@ -134,12 +135,12 @@
    comment '节点配置';
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, sysdate(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, sysdate(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, sysdate(), NULL, NULL, '业务状态列表');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, sysdate(), NULL, NULL, '表单类型列表');
script/sql/oracle/flowable.sql
@@ -30,6 +30,7 @@
    END_DATE    DATE,
    LEAVE_DAYS  NUMBER(10),
    REMARK      VARCHAR2(255),
    STATUS      VARCHAR2(255),
    CREATE_DEPT NUMBER(20),
    CREATE_BY   NUMBER(20),
    CREATE_TIME DATE,
@@ -45,6 +46,7 @@
comment on column TEST_LEAVE.END_DATE is '结束时间';
comment on column TEST_LEAVE.LEAVE_DAYS is '请假天数';
comment on column TEST_LEAVE.REMARK is '请假原因';
comment on column TEST_LEAVE.STATUS is '状态';
comment on column TEST_LEAVE.CREATE_DEPT is '创建部门';
comment on column TEST_LEAVE.CREATE_BY is '创建者';
comment on column TEST_LEAVE.CREATE_TIME is '创建时间';
@@ -182,7 +184,7 @@
comment on column WF_FORM_MANAGE.UPDATE_BY is '更新者';
comment on column WF_FORM_MANAGE.UPDATE_TIME is '更新时间';
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, sysdate, 1, sysdate);
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, sysdate, 1, sysdate);
create table WF_NODE_CONFIG
(
@@ -218,12 +220,12 @@
comment on column WF_NODE_CONFIG.UPDATE_BY is '更新者';
comment on column WF_NODE_CONFIG.UPDATE_TIME is '更新时间';
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, sysdate, NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, sysdate, NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, sysdate, NULL, NULL, '业务状态列表');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, sysdate, NULL, NULL, '表单类型列表');
script/sql/oracle/oracle_ry_vue_5.X.sql
@@ -443,7 +443,6 @@
insert into sys_menu values('108',  '日志管理',     '1',   '9', 'log',              '',                             '', 1, 0, 'M', '0', '0', '',                            'log',           103, 1, sysdate, null, null, '日志管理菜单');
insert into sys_menu values('109',  '在线用户',     '2',   '1', 'online',           'monitor/online/index',         '', 1, 0, 'C', '0', '0', 'monitor:online:list',         'online',        103, 1, sysdate, null, null, '在线用户菜单');
insert into sys_menu values('113',  '缓存监控',     '2',   '5', 'cache',            'monitor/cache/index',          '', 1, 0, 'C', '0', '0', 'monitor:cache:list',          'redis',         103, 1, sysdate, null, null, '缓存监控菜单');
insert into sys_menu values('114',  '表单构建',     '3',   '1', 'build',            'tool/build/index',             '', 1, 0, 'C', '0', '0', 'tool:build:list',             'build',         103, 1, sysdate, null, null, '表单构建菜单');
insert into sys_menu values('115',  '代码生成',     '3',   '2', 'gen',              'tool/gen/index',               '', 1, 0, 'C', '0', '0', 'tool:gen:list',               'code',          103, 1, sysdate, null, null, '代码生成菜单');
insert into sys_menu values('121',  '租户管理',     '6',   '1', 'tenant',           'system/tenant/index',          '', 1, 0, 'C', '0', '0', 'system:tenant:list',          'list',          103, 1, sysdate, null, null, '租户管理菜单');
insert into sys_menu values('122',  '租户套餐管理', '6',   '2', 'tenantPackage',    'system/tenantPackage/index',   '', 1, 0, 'C', '0', '0', 'system:tenantPackage:list',   'form',          103, 1, sysdate, null, null, '租户套餐管理菜单');
script/sql/postgres/flowable.sql
@@ -29,6 +29,7 @@
    end_date    timestamp,
    leave_days  bigint,
    remark      varchar(255),
    status      varchar(255),
    create_dept bigint,
    create_by   bigint,
    create_time timestamp,
@@ -48,6 +49,8 @@
comment on column test_leave.end_date is '结束时间';
comment on column test_leave.remark is '请假原因';
comment on column test_leave.status is '状态';
comment on column test_leave.create_dept is '创建部门';
@@ -251,7 +254,7 @@
comment on column wf_form_manage.update_time is '修改时间';
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, now(), 1, now());
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, now(), 1, now());
create table wf_node_config
(
@@ -300,12 +303,12 @@
comment on column wf_node_config.update_time is '修改时间';
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, now(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, now(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, now(), NULL, NULL, '业务状态列表');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, now(), NULL, NULL, '表单类型列表');
script/sql/postgres/postgres_ry_vue_5.X.sql
@@ -444,7 +444,6 @@
insert into sys_menu values('108',  '日志管理',     '1',   '9', 'log',              '',                             '', '1', '0', 'M', '0', '0', '',                            'log',           103, 1, now(), null, null, '日志管理菜单');
insert into sys_menu values('109',  '在线用户',     '2',   '1', 'online',           'monitor/online/index',         '', '1', '0', 'C', '0', '0', 'monitor:online:list',         'online',        103, 1, now(), null, null, '在线用户菜单');
insert into sys_menu values('113',  '缓存监控',     '2',   '5', 'cache',            'monitor/cache/index',          '', '1', '0', 'C', '0', '0', 'monitor:cache:list',          'redis',         103, 1, now(), null, null, '缓存监控菜单');
insert into sys_menu values('114',  '表单构建',     '3',   '1', 'build',            'tool/build/index',             '', '1', '0', 'C', '0', '0', 'tool:build:list',             'build',         103, 1, now(), null, null, '表单构建菜单');
insert into sys_menu values('115',  '代码生成',     '3',   '2', 'gen',              'tool/gen/index',               '', '1', '0', 'C', '0', '0', 'tool:gen:list',               'code',          103, 1, now(), null, null, '代码生成菜单');
insert into sys_menu values('121',  '租户管理',     '6',   '1', 'tenant',           'system/tenant/index',          '', '1', '0', 'C', '0', '0', 'system:tenant:list',          'list',          103, 1, now(), null, null, '租户管理菜单');
insert into sys_menu values('122',  '租户套餐管理', '6',   '2', 'tenantPackage',    'system/tenantPackage/index',   '', '1', '0', 'C', '0', '0', 'system:tenantPackage:list',   'form',          103, 1, now(), null, null, '租户套餐管理菜单');
script/sql/ry_vue_5.X.sql
@@ -278,7 +278,6 @@
insert into sys_menu values('108',  '日志管理',     '1',   '9', 'log',              '',                             '', 1, 0, 'M', '0', '0', '',                            'log',           103, 1, sysdate(), null, null, '日志管理菜单');
insert into sys_menu values('109',  '在线用户',     '2',   '1', 'online',           'monitor/online/index',         '', 1, 0, 'C', '0', '0', 'monitor:online:list',         'online',        103, 1, sysdate(), null, null, '在线用户菜单');
insert into sys_menu values('113',  '缓存监控',     '2',   '5', 'cache',            'monitor/cache/index',          '', 1, 0, 'C', '0', '0', 'monitor:cache:list',          'redis',         103, 1, sysdate(), null, null, '缓存监控菜单');
insert into sys_menu values('114',  '表单构建',     '3',   '1', 'build',            'tool/build/index',             '', 1, 0, 'C', '0', '0', 'tool:build:list',             'build',         103, 1, sysdate(), null, null, '表单构建菜单');
insert into sys_menu values('115',  '代码生成',     '3',   '2', 'gen',              'tool/gen/index',               '', 1, 0, 'C', '0', '0', 'tool:gen:list',               'code',          103, 1, sysdate(), null, null, '代码生成菜单');
insert into sys_menu values('121',  '租户管理',     '6',   '1', 'tenant',           'system/tenant/index',          '', 1, 0, 'C', '0', '0', 'system:tenant:list',          'list',          103, 1, sysdate(), null, null, '租户管理菜单');
insert into sys_menu values('122',  '租户套餐管理',  '6',   '2', 'tenantPackage',    'system/tenantPackage/index',   '', 1, 0, 'C', '0', '0', 'system:tenantPackage:list',   'form',          103, 1, sysdate(), null, null, '租户套餐管理菜单');
script/sql/sqlserver/flowable.sql
@@ -28,6 +28,7 @@
    end_date    datetime2     not null,
    leave_days  int           not null,
    remark      nvarchar(255),
    status      nvarchar(255),
    create_dept bigint,
    create_by   bigint,
    create_time datetime2,
@@ -59,6 +60,9 @@
go
exec sp_addextendedproperty 'MS_Description', N'请假原因', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'remark'
go
exec sp_addextendedproperty 'MS_Description', N'状态', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'status'
go
exec sp_addextendedproperty 'MS_Description', N'创建部门', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
@@ -221,6 +225,7 @@
        unique,
    process_key   nvarchar(255)  not null,
    version       bigint         not null,
    remark        nvarchar(500) DEFAULT ('') null,
    tenant_id     nvarchar(20),
    create_dept   bigint,
    create_by     bigint,
@@ -250,6 +255,10 @@
exec sp_addextendedproperty 'MS_Description', N'流程版本', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
     'version'
go
exec sp_addextendedproperty 'MS_Description', N'备注', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
     'remark'
go
exec sp_addextendedproperty 'MS_Description', N'租户编号', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
@@ -334,7 +343,7 @@
     'update_time'
go
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, getdate(), 1, getdate());
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, getdate(), 1, getdate());
create table wf_node_config
(
@@ -406,12 +415,12 @@
     'update_time'
go
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, getdate(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, getdate(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, getdate(), NULL, NULL, '业务状态列表');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, getdate(), NULL, NULL, '表单类型列表');
script/sql/sqlserver/sqlserver_ry_vue_5.X.sql
@@ -1678,8 +1678,6 @@
GO
INSERT sys_menu VALUES (113, N'缓存监控', 2, 5, N'cache', N'monitor/cache/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:cache:list', N'redis', 103, 1, getdate(), NULL, NULL, N'缓存监控菜单')
GO
INSERT sys_menu VALUES (114, N'表单构建', 3, 1, N'build', N'tool/build/index', N'', 1, 0, N'C', N'0', N'0', N'tool:build:list', N'build', 103, 1, getdate(), NULL, NULL, N'表单构建菜单')
GO
INSERT sys_menu VALUES (115, N'代码生成', 3, 2, N'gen', N'tool/gen/index', N'', 1, 0, N'C', N'0', N'0', N'tool:gen:list', N'code', 103, 1, getdate(), NULL, NULL, N'代码生成菜单')
GO
INSERT sys_menu VALUES (121, N'租户管理', 6, 1, N'tenant', N'system/tenant/index', N'', 1, 0, N'C', N'0', N'0', N'system:tenant:list', N'code', 103, 1, getdate(), NULL, NULL, N'租户管理菜单')
script/sql/update/oracle/update_5.1.2-5.2.0.sql
@@ -6,4 +6,4 @@
COMMENT ON COLUMN sys_post.post_category IS '岗位类别编码';
UPDATE sys_post SET dept_id = 100;
UPDATE sys_post SET dept_id = 103 where post_id = 1;
UPDATE sys_menu SET path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;
UPDATE sys_menu SET menu_name = 'SnailJob控制台', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;
script/sql/update/postgres/update_5.1.2-5.2.0.sql
@@ -6,4 +6,4 @@
COMMENT ON COLUMN sys_post.post_category IS '岗位类别编码';
UPDATE sys_post SET dept_id = 100;
UPDATE sys_post SET dept_id = 103 where post_id = 1;
UPDATE sys_menu SET path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;
UPDATE sys_menu SET menu_name = 'SnailJob控制台', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;
script/sql/update/sqlserver/update_5.1.2-5.2.0.sql
@@ -25,5 +25,5 @@
GO
UPDATE sys_post SET dept_id = 103 where post_id = 1
GO
UPDATE sys_menu SET path = N'snailjob', component = N'monitor/snailjob/index', perms = N'monitor:snailjob:list', remark = N'SnailJob控制台菜单' WHERE menu_id = 120
GO
UPDATE sys_menu SET menu_name = N'SnailJob控制台', path = N'snailjob', component = N'monitor/snailjob/index', perms = N'monitor:snailjob:list', remark = N'SnailJob控制台菜单' WHERE menu_id = 120
GO
script/sql/update/update_5.1.2-5.2.0.sql
@@ -2,4 +2,4 @@
ALTER TABLE sys_post ADD dept_id BIGINT(20) NOT NULL COMMENT '部门id', ADD post_category VARCHAR(100) DEFAULT NULL COMMENT '岗位类别编码';
UPDATE sys_post SET dept_id = 100;
UPDATE sys_post SET dept_id = 103 where post_id = 1;
UPDATE sys_menu SET path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;
UPDATE sys_menu SET menu_name = 'SnailJob控制台', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;