暂时去除回退功能,边界处理不够正确

This commit is contained in:
YunaiV 2022-07-08 08:54:15 +08:00
parent b37a535d20
commit 26ff753701
38 changed files with 15 additions and 1306 deletions

View File

@ -23,7 +23,7 @@
* 权限认证使用 Spring Security & Token & Redis支持多终端、多种用户的认证系统。 * 权限认证使用 Spring Security & Token & Redis支持多终端、多种用户的认证系统。
* 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能。 * 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能。
* 支持 SaaS 多租户系统,可自定义每个租户的权限,提供透明化的多租户底层封装。 * 支持 SaaS 多租户系统,可自定义每个租户的权限,提供透明化的多租户底层封装。
* 工作流使用 Activiti + Flowable支持动态表单、在线设计流程、多种任务分配方式。 * 工作流使用 Flowable支持动态表单、在线设计流程、会签 / 或签、多种任务分配方式。
* 高效率开发,使用代码生成器可以一键生成前后端代码 + 单元测试 + Swagger 接口文档 + Validator 参数校验。 * 高效率开发,使用代码生成器可以一键生成前后端代码 + 单元测试 + Swagger 接口文档 + Validator 参数校验。
* 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款。 * 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款。
* 集成阿里云、腾讯云、云片等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务。 * 集成阿里云、腾讯云、云片等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务。
@ -167,7 +167,7 @@ ps核心功能已经实现正在对接微信小程序中...
| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.16 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) | | [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.3.16 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.5.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) | | [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.5.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.2 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) | | [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.2 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
| [Activiti](https://github.com/Activiti/Activiti) | 工作流引擎 | 7.1.0.M6 | [文档](TODO) | | [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.7.0 | [文档](https://doc.iocoder.cn/bpm/) |
| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) | | [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.2 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) | | [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.2 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.0 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) | | [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.0 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |

View File

@ -25,7 +25,6 @@
<module>yudao-spring-boot-starter-excel</module> <module>yudao-spring-boot-starter-excel</module>
<module>yudao-spring-boot-starter-test</module> <module>yudao-spring-boot-starter-test</module>
<module>yudao-spring-boot-starter-extension</module>
<module>yudao-spring-boot-starter-biz-operatelog</module> <module>yudao-spring-boot-starter-biz-operatelog</module>
<module>yudao-spring-boot-starter-biz-dict</module> <module>yudao-spring-boot-starter-biz-dict</module>

View File

@ -1,68 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>yudao-framework</artifactId>
<groupId>cn.iocoder.boot</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-spring-boot-starter-extension</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>扩展点组件</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
<!-- Spring 核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<scope>provided</scope>
</dependency>
<!-- Spring 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 测试包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 测试包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,62 +0,0 @@
package cn.iocoder.yudao.framework.extension.config;
import cn.iocoder.yudao.framework.extension.core.ExtensionBootstrap;
import cn.iocoder.yudao.framework.extension.core.context.ExtensionContext;
import cn.iocoder.yudao.framework.extension.core.context.ExtensionContextHolder;
import cn.iocoder.yudao.framework.extension.core.context.ExtensionExecutor;
import cn.iocoder.yudao.framework.extension.core.factory.ExtensionFactory;
import cn.iocoder.yudao.framework.extension.core.factory.ExtensionRegisterFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @description 扩展点组件自动装配
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 21:50
* @class cn.iocoder.yudao.framework.extension.config.YudaoExtensionAutoConfiguration.java
*/
@Configuration
public class YudaoExtensionAutoConfiguration {
/**
* 组件初始化
* @return
*/
@Bean(initMethod = "init")
@ConditionalOnMissingBean(ExtensionBootstrap.class)
public ExtensionBootstrap bootstrap() {
return new ExtensionBootstrap();
}
/**
* 扩展点工厂
* @return
*/
@Bean
@ConditionalOnMissingBean({ExtensionRegisterFactory.class, ExtensionFactory.class})
public ExtensionRegisterFactory registerFactory() {
return new ExtensionRegisterFactory();
}
/**
* 扩展组件上下文对象
* @return
*/
@Bean
@ConditionalOnMissingBean({ExtensionContextHolder.class, ExtensionContext.class})
public ExtensionContextHolder context() {
return new ExtensionContextHolder();
}
/**
* 扩展组件执行器
* @return
*/
@Bean
@ConditionalOnMissingBean(ExtensionExecutor.class)
public ExtensionExecutor executor() {
return new ExtensionExecutor();
}
}

View File

@ -1,142 +0,0 @@
package cn.iocoder.yudao.framework.extension.core;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.StringJoiner;
/**
* @description 业务场景 = businessId + useCase + scenario, 用来标识系统中唯一的一个场景<br/>
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 22:19
* @class cn.iocoder.yudao.framework.extension.core.BusinessScenario.java
*/
public class BusinessScenario implements Serializable {
/**
* 默认业务id
*/
public final static String DEFAULT_BUSINESS_ID = "#defaultBusinessId#";
/**
* 默认用例
*/
public final static String DEFAULT_USECASE = "#defaultUseCase#";
/**
* 默认场景
*/
public final static String DEFAULT_SCENARIO = "#defaultScenario#";
/**
* 分隔符
*/
private final static String DOT_SEPARATOR = ".";
/**
* 业务Id
*/
private String businessId;
/**
* 用例
*/
private String useCase;
/**
* 场景
*/
private String scenario;
public BusinessScenario() {
this.businessId = DEFAULT_BUSINESS_ID;
this.useCase = DEFAULT_USECASE;
this.scenario = DEFAULT_SCENARIO;
}
public BusinessScenario(@NotNull String businessId, @NotNull String useCase, @NotNull String scenario) {
this.businessId = businessId;
this.useCase = useCase;
this.scenario = scenario;
}
public BusinessScenario(@NotNull String scenario) {
this();
this.scenario = scenario;
}
public BusinessScenario(@NotNull String useCase, @NotNull String scenario) {
this(DEFAULT_BUSINESS_ID, useCase, scenario);
}
public String getBusinessId() {
return businessId;
}
public void setBusinessId(String businessId) {
this.businessId = businessId;
}
public String getUseCase() {
return useCase;
}
public void setUseCase(String useCase) {
this.useCase = useCase;
}
public String getScenario() {
return scenario;
}
public void setScenario(String scenario) {
this.scenario = scenario;
}
/**
* 构建业务场景
* @param businessId
* @param useCase
* @param scenario
* @return
*/
public static BusinessScenario valueOf(@NotNull String businessId, @NotNull String useCase, @NotNull String scenario) {
return new BusinessScenario(businessId, useCase, scenario);
}
/**
* 构建业务场景
* @param useCase
* @param scenario
* @return
*/
public static BusinessScenario valueOf(@NotNull String useCase, @NotNull String scenario) {
return new BusinessScenario(useCase, scenario);
}
/**
* 构建业务场景
* @param scenario
* @return
*/
public static BusinessScenario valueOf(@NotNull String scenario) {
return new BusinessScenario(scenario);
}
/**
* 业务场景唯一标识
* @return
*/
public String getUniqueIdentity(){
return new StringJoiner(DOT_SEPARATOR).add(businessId).add(useCase).add(scenario).toString();
}
@Override
public String toString() {
return "BusinessScenario{" +
"businessId='" + businessId + '\'' +
", useCase='" + useCase + '\'' +
", scenario='" + scenario + '\'' +
'}';
}
}

View File

@ -1,41 +0,0 @@
package cn.iocoder.yudao.framework.extension.core;
import cn.iocoder.yudao.framework.extension.core.factory.ExtensionRegisterFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.annotation.PostConstruct;
/**
* @description
* @author Qingchen
* @version 1.0.0
* @date 2021-08-29 00:18
* @class cn.iocoder.yudao.framework.extension.core.ExtensionBootstrap.java
*/
public class ExtensionBootstrap implements ApplicationContextAware {
/**
* spring 容器
*/
private ApplicationContext applicationContext;
@Autowired
private ExtensionRegisterFactory registerFactory;
/**
* 初始化
*/
@PostConstruct
public void init() {
registerFactory.setApplicationContext(applicationContext);
registerFactory.register(null);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

View File

@ -1,131 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.context;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* @description 执行器通用方法
* @author Qingchen
* @version 1.0.0
* @date 2021-08-29 00:38
* @class cn.iocoder.yudao.framework.extension.core.context.AbstractComponentExecutor.java
*/
public abstract class AbstractComponentExecutor {
/**
* "业务" + "用例" + "场景"执行扩展组件并返回执行结果
* @param targetClazz
* @param businessId
* @param useCase
* @param scenario
* @param function
* @param <R>
* @param <T>
* @return
*/
public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, String businessId, String useCase, String scenario, Function<T, R> function) {
return execute(targetClazz, BusinessScenario.valueOf(businessId, useCase, scenario), function);
}
/**
* "用例" + "场景"执行扩展组件并返回执行结果
* @param targetClazz
* @param useCase
* @param scenario
* @param function
* @param <R>
* @param <T>
* @return
*/
public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, String useCase, String scenario, Function<T, R> function) {
return execute(targetClazz, BusinessScenario.valueOf(useCase, scenario), function);
}
/**
* "场景"执行扩展组件并返回执行结果
* @param targetClazz
* @param scenario
* @param function
* @param <R>
* @param <T>
* @return
*/
public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, String scenario, Function<T, R> function) {
return execute(targetClazz, BusinessScenario.valueOf(scenario), function);
}
/**
* 执行扩展组件并返回执行结果
* @param targetClazz
* @param businessScenario
* @param function
* @param <R> Response Type
* @param <T> Parameter Type
* @return
*/
public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, BusinessScenario businessScenario, Function<T, R> function) {
T component = locateComponent(targetClazz, businessScenario);
return function.apply(component);
}
/**
* "业务" + "用例" + "场景"执行扩展组件适用于无返回值的业务
* @param targetClazz
* @param businessId
* @param useCase
* @param scenario
* @param consumer
* @param <T>
*/
public <T extends ExtensionPoint> void accept(Class<T> targetClazz, String businessId, String useCase, String scenario, Consumer<T> consumer) {
accept(targetClazz, BusinessScenario.valueOf(businessId, useCase, scenario), consumer);
}
/**
* "场景"执行扩展组件适用于无返回值的业务
* @param targetClazz
* @param useCase
* @param scenario
* @param consumer
* @param <T>
*/
public <T extends ExtensionPoint> void accept(Class<T> targetClazz, String useCase, String scenario, Consumer<T> consumer) {
accept(targetClazz, BusinessScenario.valueOf(useCase, scenario), consumer);
}
/**
* "场景"执行扩展组件适用于无返回值的业务
* @param targetClazz
* @param scenario
* @param consumer
* @param <T>
*/
public <T extends ExtensionPoint> void accept(Class<T> targetClazz, String scenario, Consumer<T> consumer) {
accept(targetClazz, BusinessScenario.valueOf(scenario), consumer);
}
/**
* 执行扩展组件适用于无返回值的业务
* @param targetClazz
* @param businessScenario
* @param consumer
* @param <T> Parameter Type
*/
public <T extends ExtensionPoint> void accept(Class<T> targetClazz, BusinessScenario businessScenario, Consumer<T> consumer) {
T component = locateComponent(targetClazz, businessScenario);
consumer.accept(component);
}
/**
* 获取/定位扩展点组件
* @param targetClazz
* @param businessScenario
* @param <C>
* @return
*/
protected abstract <C extends ExtensionPoint> C locateComponent(Class<C> targetClazz, BusinessScenario businessScenario);
}

View File

@ -1,56 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.context;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
/**
* @description 上下文包含各个扩展点的相关操作
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 22:15
* @class cn.iocoder.yudao.framework.extension.core.context.ExtensionContext.java
*/
public interface ExtensionContext {
/**
* 根据业务场景唯一标识获取扩展点组件实现类
* @param businessId
* @param useCase
* @param scenario
* @param clazz
* @param <T>
* @return
*/
<T extends ExtensionPoint> T getPoint(String businessId, String useCase, String scenario, Class<T> clazz);
/**
* 根据"实例" + "场景"获取扩展点组件实现类其中业务idbusinessId= {@linkplain cn.iocoder.yudao.framework.extension.core.BusinessScenario.DEFAULT_BUSINESS_ID}
* @param useCase
* @param scenario
* @param clazz
* @param <T>
* @return
*/
<T extends ExtensionPoint> T getPoint(String useCase, String scenario, Class<T> clazz);
/**
* 根据"场景"获取扩展点组件实现类 <br/>
* 其中
* 业务idbusinessId= {@linkplain cn.iocoder.yudao.framework.extension.core.BusinessScenario.DEFAULT_BUSINESS_ID}
* 实例useCase= {@linkplain cn.iocoder.yudao.framework.extension.core.BusinessScenario.DEFAULT_USECASE}
* @param scenario
* @param clazz
* @param <T>
* @return
*/
<T extends ExtensionPoint> T getPoint(String scenario, Class<T> clazz);
/**
* 根据业务场景唯一标识获取扩展点组件实现类
* @param businessScenario
* @param clazz
* @param <T>
* @return
*/
<T extends ExtensionPoint> T getPoint(BusinessScenario businessScenario, Class<T> clazz);
}

View File

@ -1,45 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.context;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.factory.ExtensionFactory;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.validation.constraints.NotNull;
/**
* @description 上下文及扩展点组件工厂的持有类
* @author Qingchen
* @version 1.0.0
* @date 2021-08-29 00:29
* @class cn.iocoder.yudao.framework.extension.core.context.ExtensionContextHolder.java
*/
@Component
@Slf4j
public class ExtensionContextHolder implements ExtensionContext{
@Autowired
private ExtensionFactory factory;
@Override
public <T extends ExtensionPoint> T getPoint(@NotNull String businessId, @NotNull String useCase, @NotNull String scenario, Class<T> clazz) {
return getPoint(BusinessScenario.valueOf(businessId, useCase, scenario), clazz);
}
@Override
public <T extends ExtensionPoint> T getPoint(@NotNull String useCase, String scenario, Class<T> clazz) {
return getPoint(BusinessScenario.valueOf(useCase, scenario), clazz);
}
@Override
public <T extends ExtensionPoint> T getPoint(@NotNull String scenario, Class<T> clazz) {
return getPoint(BusinessScenario.valueOf(scenario), clazz);
}
@Override
public <T extends ExtensionPoint> T getPoint(@NotNull BusinessScenario businessScenario, Class<T> clazz) {
return factory.get(businessScenario, clazz);
}
}

View File

@ -1,28 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.context;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @description 扩展组件执行器
* @author Qingchen
* @version 1.0.0
* @date 2021-08-29 00:32
* @class cn.iocoder.yudao.framework.extension.core.context.ExtensionExecutor.java
*/
@Component
@Slf4j
public class ExtensionExecutor extends AbstractComponentExecutor{
@Autowired
private ExtensionContextHolder contextHolder;
@Override
protected <C extends ExtensionPoint> C locateComponent(Class<C> targetClazz, BusinessScenario businessScenario) {
return contextHolder.getPoint(businessScenario, targetClazz);
}
}

View File

@ -1,96 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.factory;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Objects;
/**
* @description 扩展定义扩展坐标标识唯一一个业务场景实现
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 23:14
* @class cn.iocoder.yudao.framework.extension.core.factory.ExtensionDefinition.java
*/
@Setter
@Getter
public class ExtensionDefinition implements Serializable {
/**
* 业务场景唯一标识(id)
*/
private String uniqueIdentify;
/**
* 扩展点实现类名称
*/
private String extensionPointName;
/**
* 业务场景
*/
private BusinessScenario businessScenario;
/**
* 扩展点实现类
*/
private ExtensionPoint extensionPoint;
/**
* class
*/
private Class extensionPointClass;
public ExtensionDefinition() {
}
public ExtensionDefinition(@NotNull BusinessScenario businessScenario, @NotNull ExtensionPoint extensionPoint) {
this.businessScenario = businessScenario;
this.extensionPoint = extensionPoint;
this.uniqueIdentify = this.businessScenario.getUniqueIdentity();
this.extensionPointClass = this.extensionPoint.getClass();
}
/**
* 构建definition
* @param businessScenario
* @param point
* @return
*/
public static ExtensionDefinition valueOf(@NotNull BusinessScenario businessScenario, @NotNull ExtensionPoint point) {
return new ExtensionDefinition(businessScenario, point);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ExtensionDefinition that = (ExtensionDefinition) o;
return Objects.equals(uniqueIdentify, that.uniqueIdentify) && Objects.equals(extensionPointName, that.extensionPointName);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((uniqueIdentify == null) ? 0 : uniqueIdentify.hashCode());
result = prime * result + ((extensionPointName == null) ? 0 : extensionPointName.hashCode());
return result;
}
@Override
public String toString() {
return "ExtensionDefinition{" +
"uniqueIdentify='" + uniqueIdentify + '\'' +
", extensionPointName='" + extensionPointName + '\'' +
'}';
}
}

View File

@ -1,29 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.factory;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
/**
* @description 扩展点工厂
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 23:04
* @class cn.iocoder.yudao.framework.extension.core.factory.ExtensionFactory.java
*/
public interface ExtensionFactory {
/**
* 注册所有扩展点实现类
* @param basePackage
*/
void register(String basePackage);
/**
* 根据业务场景获取指定类型的扩展点
* @param businessScenario
* @param clazz
* @param <T>
* @return
*/
<T extends ExtensionPoint> T get(BusinessScenario businessScenario, Class<T> clazz);
}

View File

@ -1,86 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.factory;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import cn.iocoder.yudao.framework.extension.core.stereotype.Extension;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import javax.validation.constraints.NotNull;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @description 注册工厂
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 23:07
* @class cn.iocoder.yudao.framework.extension.core.factory.ExtensionRegisterFactory.java
*/
@Component
@Slf4j
public class ExtensionRegisterFactory implements ExtensionFactory {
/**
* spring ApplicationContext
*/
private ApplicationContext applicationContext;
/**
* 扩展点实现类集合
*/
private Map<String, ExtensionDefinition> registerExtensionBeans = new ConcurrentHashMap<>();
@Override
public void register(String basePackage) {
final Map<String, Object> beans = applicationContext.getBeansWithAnnotation(Extension.class);
if(beans == null || beans.isEmpty()) {
return;
}
beans.values().forEach(point -> doRegister((ExtensionPoint) point));
log.info("业务场景相关扩展点注册完成,注册数量: {}", registerExtensionBeans.size());
}
@Override
public <T extends ExtensionPoint> T get(BusinessScenario businessScenario, Class<T> clazz) {
final ExtensionDefinition definition = registerExtensionBeans.get(businessScenario.getUniqueIdentity());
if(definition == null) {
log.error("获取业务场景扩展点实现失败,失败原因:尚未定义该业务场景相关扩展点。{}", businessScenario);
throw new RuntimeException("尚未定义该业务场景相关扩展点 [" + businessScenario + "]");
}
return (T) definition.getExtensionPoint();
}
/**
* 注册扩展点
* @param point
*/
private void doRegister(@NotNull ExtensionPoint point) {
Class<?> extensionClazz = point.getClass();
if (AopUtils.isAopProxy(point)) {
extensionClazz = ClassUtils.getUserClass(point);
}
Extension extension = AnnotationUtils.findAnnotation(extensionClazz, Extension.class);
final BusinessScenario businessScenario = BusinessScenario.valueOf(extension.businessId(), extension.useCase(), extension.scenario());
final ExtensionDefinition definition = ExtensionDefinition.valueOf(businessScenario, point);
final ExtensionDefinition exist = registerExtensionBeans.get(businessScenario.getUniqueIdentity());
if(exist != null && !exist.equals(definition)) {
throw new RuntimeException("相同的业务场景重复注册了不同类型的扩展点实现 :【" + definition + "】【" + exist + "");
}
registerExtensionBeans.put(businessScenario.getUniqueIdentity(), definition);
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}

View File

@ -1,8 +0,0 @@
/**
* @description core 核心
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 21:54
* @class cn.iocoder.yudao.framework.extension.core.package-info.java
*/
package cn.iocoder.yudao.framework.extension.core;

View File

@ -1,11 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.point;
/**
* @description 扩展点 <br/>
* 表示一块逻辑在不同的业务有不同的实现使用扩展点做接口申明然后用{@linkplain cn.iocoder.yudao.framework.extension.core.stereotype.Extension}扩展去实现扩展点
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 22:06
* @class cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint.java
*/
public interface ExtensionPoint {
}

View File

@ -1,41 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.stereotype;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
/**
* @description 表示带注释的类是扩展组件
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 21:59
* @class cn.iocoder.yudao.framework.extension.core.stereotype.Extension.java
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Component
public @interface Extension {
/**
* 业务 <br/>
* 一个自负盈亏的财务主体比如tmall淘宝和零售通就是三个不同的业务
* @return
*/
String businessId() default BusinessScenario.DEFAULT_BUSINESS_ID;
/**
* 用例 <br/>
* 描述了用户和系统之间的互动每个用例提供了一个或多个场景比如支付订单就是一个典型的用例
* @return
*/
String useCase() default BusinessScenario.DEFAULT_USECASE;
/**
* 场景 <br/>
* 场景也被称为用例的实例Instance包括用例所有的可能情况正常的和异常的比如对于"订单支付"这个用例就有支付宝支付银行卡支付"微信支付"等多个场景
* @return
*/
String scenario() default BusinessScenario.DEFAULT_SCENARIO;
}

View File

@ -1,8 +0,0 @@
/**
* @description 扩展点组件
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 14:35
* @class cn.iocoder.yudao.framework.extension.package-info.java
*/
package cn.iocoder.yudao.framework.extension;

View File

@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.iocoder.yudao.framework.extension.config.YudaoExtensionAutoConfiguration

View File

@ -1,19 +0,0 @@
package cn.iocoder.yudao.framework.extension;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @description Application
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:32
* @class cn.iocoder.yudao.framework.extension.Application.java
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -1,43 +0,0 @@
package cn.iocoder.yudao.framework.extension;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.context.ExtensionExecutor;
import cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint;
import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.math.BigDecimal;
/**
* @description
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:30
* @class cn.iocoder.yudao.framework.extension.ExtensionTest.java
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
@Slf4j
public class ExtensionTest {
@Autowired
private ExtensionExecutor extensionExecutor;
@Test
public void unifiedOrder() {
final BusinessScenario scenario = BusinessScenario.valueOf("pay", "jsapi", "wechat");
final TransactionsCommand command = new TransactionsCommand(IdUtil.objectId(), new BigDecimal(105), "Image形象店-深圳腾大-QQ公仔", "https://www.weixin.qq.com/wxpay/pay.php");
final TransactionsResult result = extensionExecutor.execute(PayExtensionPoint.class, scenario, extension -> extension.unifiedOrder(command));
log.info("result is: {}", JSONUtil.toJsonStr(result));
Assert.assertSame("wechat", result.getChannel());
}
}

View File

@ -1,8 +0,0 @@
/**
* @description
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:25
* @class cn.iocoder.yudao.framework.extension.package-info.java
*/
package cn.iocoder.yudao.framework.extension;

View File

@ -1,22 +0,0 @@
package cn.iocoder.yudao.framework.extension.pay;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
/**
* @description 支付操作接口
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:35
* @class cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint.java
*/
public interface PayExtensionPoint extends ExtensionPoint {
/**
* 统一下单获取"预支付交易会话标识"
* @param command
* @return
*/
TransactionsResult unifiedOrder(TransactionsCommand command);
}

View File

@ -1,40 +0,0 @@
package cn.iocoder.yudao.framework.extension.pay.command;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @description 下单请求
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:48
* @class cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand.java
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TransactionsCommand implements Serializable {
/**
* 订单编号
*/
private String orderNo;
/**
* 支付金额
*/
private BigDecimal amount;
/**
* 商品描述
*/
private String productDescription;
/**
* 通知地址
*/
private String notifyUrl;
}

View File

@ -1,39 +0,0 @@
package cn.iocoder.yudao.framework.extension.pay.domain;
import lombok.*;
import java.io.Serializable;
/**
* @description 下单: 预支付交易单返回结果
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:43
* @class cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult.java
*/
@Data
@AllArgsConstructor
public class TransactionsResult implements Serializable {
/**
* 预支付交易会话标识
*/
private String prepayId;
/**
* 订单编号
*/
private String orderNo;
/**
* 系统内部支付单号
*/
private String paymentNo;
/**
* 支付渠道微信 or 支付宝
*/
private String channel;
}

View File

@ -1,26 +0,0 @@
package cn.iocoder.yudao.framework.extension.pay.impl;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.extension.core.stereotype.Extension;
import cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint;
import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
import lombok.extern.slf4j.Slf4j;
/**
* @description 微信 JSAPI 支付
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:38
* @class cn.iocoder.yudao.framework.extension.pay.impl.AlipayService.java
*/
@Extension(businessId = "pay", useCase = "jsapi", scenario = "alipay")
@Slf4j
public class AlipayService implements PayExtensionPoint {
@Override
public TransactionsResult unifiedOrder(TransactionsCommand command) {
log.info("微信 JSAPI 支付:{}", JSONUtil.toJsonStr(command));
return new TransactionsResult("alipay26112221580621e9b071c00d9e093b0000", command.getOrderNo(), IdUtil.objectId(), "alipay");
}
}

View File

@ -1,26 +0,0 @@
package cn.iocoder.yudao.framework.extension.pay.impl;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.extension.core.stereotype.Extension;
import cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint;
import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
import lombok.extern.slf4j.Slf4j;
/**
* @description 微信 JSAPI 支付
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:37
* @class cn.iocoder.yudao.framework.extension.pay.impl.WechatPayService.java
*/
@Extension(businessId = "pay", useCase = "jsapi", scenario = "wechat")
@Slf4j
public class WechatPayService implements PayExtensionPoint {
@Override
public TransactionsResult unifiedOrder(TransactionsCommand command) {
log.info("微信 JSAPI 支付:{}", JSONUtil.toJsonStr(command));
return new TransactionsResult("wx26112221580621e9b071c00d9e093b0000", command.getOrderNo(), IdUtil.objectId(), "wechat");
}
}

View File

@ -1,19 +0,0 @@
### 作用
为了解决同一个流程不同业务有不同处理逻辑而产生,减少代码中 if else 逻辑,降低代码的耦合性,通过统一的扩展形式来支撑业务的变化。
### 原理
https://blog.csdn.net/significantfrank/article/details/100074716
### 使用介绍
参考测试代码 `cn.iocoder.yudao.framework.extension.ExtensionTest`

View File

@ -75,13 +75,4 @@ public class BpmTaskController {
return success(true); return success(true);
} }
@PutMapping("/back")
@ApiOperation(value = "回退")
// @PreAuthorize("@ss.hasPermission('bpm:task:back')")
public CommonResult<Boolean> backTask(@Valid @RequestBody BpmTaskBackReqVO reqVO) {
//先硬编码到 回退到第一个审批节点
// String destinationTaskDefKey = "task01";
return taskService.backTask(reqVO);
}
} }

View File

@ -1,45 +0,0 @@
package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* @author kemengkai
* @create 2022-05-07 08:05 TODO kevo 使用 swagger 注解即可
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BpmTaskBackReqVO {
// TODO keuserId 应该使用后端的不能前端传递不然就越权了
@ApiModelProperty(value = "用户id", required = true, example = "1")
@NotEmpty(message = "用户id不能为空")
private String userId;
// TODO keprocInstIdtaskIdoldTaskDefKey 三个是不是只要传递一个 taskId字段不要存在推导关系
@ApiModelProperty(value = "流程编号id", required = true, example = "730da750-cc4f-11ec-b58e-1e429355e4a0")
@NotEmpty(message = "流程编号id不能为空")
private String procInstId;
@ApiModelProperty(value = "当前任务id", required = true, example = "730da750-cc4f-11ec-b58e-1e429355e4a0")
@NotEmpty(message = "当前任务id不能为空")
private String taskId;
@ApiModelProperty(value = "当前流程任务id", required = true, example = "Activity_1jlembv")
@NotNull(message = "当前流程任务id不能为空")
private String oldTaskDefKey;
@ApiModelProperty(value = "准备回退的流程任务id", required = true, example = "task01")
@NotNull(message = "准备回退流程任务id不能为空")
private String newTaskDefKey;
@ApiModelProperty(value = "审批结果", required = true, example = "任务驳回")
@NotNull(message = "审批结果")
private String reason;
}

View File

@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -24,28 +23,4 @@ public interface BpmTaskExtMapper extends BaseMapperX<BpmTaskExtDO> {
return selectOne(BpmTaskExtDO::getTaskId, taskId); return selectOne(BpmTaskExtDO::getTaskId, taskId);
} }
default List<BpmTaskExtDO> selectListByProcessInstanceId(String processInstanceId) {
return selectList(BpmTaskExtDO::getProcessInstanceId, processInstanceId);
}
// TODO @ke可以使用类上上面的 default 方法实现然后方法的命名上要保持和 db 一样因为 mapper 是数据层不关注业务例如说这里其实复用 updateByTaskId 方法即可
/**
* 任务驳回
*
* @param taskId 任务列表
* @param reason 驳回理由
*
* @return 返回驳回结果是否成功
*/
Boolean backByTaskId(@Param("taskId") String taskId, @Param("reason") String reason);
// TODO @ketong上哈
/**
* 逻辑删除任务
*
* @param taskIdList 任务id列表
*
* @return 返回是否成功
*/
Boolean delByTaskIds(@Param("taskIdList") List<String> taskIdList);
} }

View File

@ -5,7 +5,6 @@ import org.flowable.engine.delegate.DelegateExecution;
import java.util.Set; import java.util.Set;
// TODO @芋艿迁移到 bpm core
/** /**
* Bpm 任务分配的自定义 Script 脚本 * Bpm 任务分配的自定义 Script 脚本
* 使用场景 * 使用场景

View File

@ -84,13 +84,6 @@ public interface BpmTaskService {
*/ */
void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO); void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO);
/**
* 回退任务
*
* @param reqVO 回退任务信息
*/
CommonResult<Boolean> backTask(BpmTaskBackReqVO reqVO);
/** /**
* 将流程任务分配给指定用户 * 将流程任务分配给指定用户
* *

View File

@ -2,15 +2,12 @@ package cn.iocoder.yudao.module.bpm.service.task;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmActivityDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmActivityMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmActivityMapper;
@ -24,7 +21,6 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService; import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService; import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstance;
@ -40,7 +36,6 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
@ -60,8 +55,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
@Resource @Resource
private TaskService taskService; private TaskService taskService;
@Resource @Resource
private RuntimeService runtimeService;
@Resource
private HistoryService historyService; private HistoryService historyService;
@Resource @Resource
@ -226,44 +219,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
.setReason(reqVO.getReason())); .setReason(reqVO.getReason()));
} }
@Override
@Transactional(rollbackFor = Exception.class)
@TenantIgnore
public CommonResult<Boolean> backTask(BpmTaskBackReqVO reqVO) {
Long userId = Long.valueOf(reqVO.getUserId());
// 校验任务存在
Task task = checkTask(userId, reqVO.getTaskId());
ArrayList<String> oldTaskDefKeyList = CollUtil.newArrayList(reqVO.getOldTaskDefKey());
// List<HistoricActivityInstance> hisActInstList =
// historyService.createHistoricActivityInstanceQuery().processInstanceId(reqVO.getProcInstId()).list();
// TODO @ke使用 historyService.createHistoricActivityInstanceQuery().processInstanceId(reqVO.getProcInstId()).list() 读取会存在啥问题呀
List<BpmActivityDO> bpmActivityDOList = bpmActivityMapper.listAllByProcInstIdAndDelete(reqVO.getProcInstId());
// List<BpmActivityDO> bpmActivityDOList = BpmTaskConvert.INSTANCE.copyList(hisActInstList, BpmActivityDO.class);
// bpmActivityDOList.forEach(bpmActivityDO -> log.info("bpmActivityDO = " + bpmActivityDO));
// TODO @ke如果 开始->a->b->c->d->结束 d 驳回到 b 的话这样会不会导致 a 也被删除呀http://blog.wya1.com/article/636697030/details/7296 可以看看这篇文章哈
List<String> taskIdList = bpmActivityDOList.stream().filter(
bpmActivityDO -> bpmActivityDO.getActivityId().equals(reqVO.getOldTaskDefKey())
&& !bpmActivityDO.getTaskId().equals(reqVO.getTaskId())).map(BpmActivityDO::getTaskId)
.collect(Collectors.toList());
// 使用flowable更改任务节点
runtimeService.createChangeActivityStateBuilder().processInstanceId(reqVO.getProcInstId())
.moveActivityIdsToSingleActivityId(oldTaskDefKeyList, reqVO.getNewTaskDefKey()).changeState();
// 逻辑删除hiActInst表任务
Boolean delHiActInstResult = bpmActivityMapper.delHiActInstByTaskId(taskIdList);
// 逻辑删除hiTaskInst表任务
Boolean delHiTaskInstResult = bpmActivityMapper.delHiTaskInstByTaskId(taskIdList);
// 更新任务拓展表
Boolean backResult = taskExtMapper.backByTaskId(reqVO.getTaskId(), reqVO.getReason());
Boolean delTaskResult = taskExtMapper.delByTaskIds(taskIdList);
if (!delHiActInstResult && !delHiTaskInstResult && !backResult && !delTaskResult) {
throw new RuntimeException("任务驳回失败!!!");
}
return CommonResult.success(true);
}
@Override @Override
public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) { public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) {
// 校验任务存在 // 校验任务存在

View File

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmActivityMapper">
<update id="delHiActInstByTaskId">
UPDATE act_hi_actinst
SET delete_reason_ = 'delete task' WHERE task_id_ IN
<foreach collection="taskIdList" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</update>
<delete id="delHiTaskInstByTaskId">
UPDATE act_hi_taskinst
SET delete_reason_ = 'delete task' WHERE id_ IN
<foreach collection="taskIdList" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
<select id="listAllByProcInstIdAndDelete"
resultType="cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmActivityDO">
SELECT id_ AS `id`,
rev_ AS `rev`,
proc_def_id_ AS `proc_def_id`,
proc_inst_id_ AS `process_instance_id`,
execution_id_ AS `execution_id`,
act_id_ AS `activity_id`,
task_id_ AS `task_id`,
call_proc_inst_id_ AS `call_proc_inst_id`,
act_name_ AS `activity_name`,
act_type_ AS `activity_type`,
assignee_ AS `assignee`,
start_time_ AS `start_time`,
end_time_ AS `end_time`,
transaction_order_ AS `transaction_order`,
duration_ AS `duration`,
delete_reason_ AS `delete_reason`,
tenant_id_ AS `tenant_id`
FROM act_hi_actinst aha
WHERE aha.proc_inst_id_ = #{procInstId}
AND aha.act_type_ != 'sequenceFlow'
LIMIT 500;
</select>
</mapper>

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper">
<update id="backByTaskId">
UPDATE bpm_task_ext
SET result=2,
`reason`=#{reason}
WHERE task_id = #{taskId}
</update>
<update id="delByTaskIds">
UPDATE bpm_task_ext
SET result=1,
`deleted`= true
WHERE `task_id` IN
<foreach collection="taskIdList" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</update>
</mapper>

View File

@ -2,6 +2,8 @@
<div class="panel-tab__content"> <div class="panel-tab__content">
<el-form size="mini" label-width="90px" :model="model" :rules="rules" @submit.native.prevent> <el-form size="mini" label-width="90px" :model="model" :rules="rules" @submit.native.prevent>
<div v-if="elementBaseInfo.$type === 'bpmn:Process'"> <!-- 如果是 Process 信息的时候使用自定义表单 --> <div v-if="elementBaseInfo.$type === 'bpmn:Process'"> <!-- 如果是 Process 信息的时候使用自定义表单 -->
<el-link href="https://doc.iocoder.cn/bpm/#_3-%E4%BC%9A%E7%AD%BE-%E6%88%96%E7%AD%BE"
type="danger" target="_blank">如何实现实现会签或签</el-link>
<el-form-item label="流程标识" prop="key"> <el-form-item label="流程标识" prop="key">
<el-input v-model="model.key" placeholder="请输入流标标识" <el-input v-model="model.key" placeholder="请输入流标标识"
:disabled="model.id !== undefined && model.id.length > 0" @change="handleKeyUpdate" /> :disabled="model.id !== undefined && model.id.length > 0" @change="handleKeyUpdate" />

View File

@ -412,15 +412,16 @@ export default {
}, },
/** 处理审批退回的操作 */ /** 处理审批退回的操作 */
handleBack(task) { handleBack(task) {
const data = { this.$modal.msgError("暂不支持【退回】功能!");
id: task.id, // http://blog.wya1.com/article/636697030/details/7296
assigneeUserId: 1 // const data = {
} // id: task.id,
// this.$modal.msgError("--退"); // assigneeUserId: 1
backTask(data).then(response => { // }
this.$modal.msgSuccess("回退成功!"); // backTask(data).then(response => {
this.getDetail(); // // this.$modal.msgSuccess("退");
}); // this.getDetail(); //
// });
} }
} }
}; };