diff --git a/README_bak.md b/README_bak.md new file mode 100644 index 000000000..f72d46699 --- /dev/null +++ b/README_bak.md @@ -0,0 +1,218 @@ +以 [ruoyi-vue-pro](https://github.com/YunaiV/ruoyi-vue-pro) 为基础,实现的 Spring Cloud Alibaba 微服务架构。进度如下: + +* [x] `gateway` 网关服务 +* [x] `system` 系统服务 +* [x] `infra` 基础设施 +* [ ] `bpm` 工作流服务 +* [ ] `pay` 支付服务 +* [ ] `member` 会员服务 +* [ ] `product` 商品服务 +* [ ] `market` 营销服务 +* [ ] `trade` 交易服务 + +启动文档,可见 地址。 + +---- + +# 前言 + +基于微服务的思想,构建在 B2C 电商场景下的项目实战。 + +* 「Talk is cheap. Show me the code」(屁话少说,放码过来) + > 我们看过很多技术文章,却依然不知道微服务该咋整。 + +* 这会是一个认真做的业务开源项目,目前 Java 代码 2w+ 行,不包括注释的情况下。 + +* 整体的功能如下图:![功能图](http://static.iocoder.cn/mall%20%E5%8A%9F%E8%83%BD%E5%9B%BE-min.png) + > 功能图,和实际后端模块拆分,并不是绝对对应。 + * [功能列表 - H5 商城](https://gitee.com/zhijiantianya/onemall/blob/master/docs/guides/%E5%8A%9F%E8%83%BD%E5%88%97%E8%A1%A8/%E5%8A%9F%E8%83%BD%E5%88%97%E8%A1%A8-H5%20%E5%95%86%E5%9F%8E.md) + * [功能列表 - 管理后台](https://gitee.com/zhijiantianya/onemall/blob/master/docs/guides/%E5%8A%9F%E8%83%BD%E5%88%97%E8%A1%A8/%E5%8A%9F%E8%83%BD%E5%88%97%E8%A1%A8-%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0.md) + +* 交流群:[传送门](http://www.iocoder.cn/mall-user-group/?vip&gitee) + > 一起交流,Get 知识。 + +* 我们迫切希望更多的参与进来,可以加入「交流群」,一起骚聊。 + * [《Onemall 电商开源项目 —— 应用分层》](http://www.iocoder.cn/Onemall/Application-layer/?onemall) + * [《Onemall 电商开源项目 —— 搭建调试环境》](http://www.iocoder.cn/Onemall/build-debugger-environment/?onemall) + +* 前端项目地址: + +# 演示 + +> 艿艿:目前的开发者,都是后端出身。所以,一帮没有审美自觉的人,撸出来的前端界面,可能是东半球倒数第二难看。 +> +> 迫切希望,有前端能力不错的小伙伴,加入我们,一起来完善「芋道商城」。 + +## 管理后台 + +体验传送门: + +![GIF 图-耐心等待](https://raw.githubusercontent.com/YunaiV/Blog/master/Mall/onemall-admin-min.gif) + +## H5 商城 + +体验传送门: + +*2M 带宽小水管,访问略微有点慢* + +![GIF 图-耐心等待](https://raw.githubusercontent.com/YunaiV/Blog/master/Mall/onemall-h5-min.gif) + +## 其它演示 + +下面,我们会提供目前用到的中间件的管理平台。 + +> 艿艿:考虑到大家可以看到更全的功能,所以一般提供 admin 账号。所以,大家素质使用哟。 + +**SkyWalking UI** + +* 地址: + +> 教程:[《芋道 SkyWalking 安装部署》](http://www.iocoder.cn/SkyWalking/install/?onemall) + +**Grafana UI** + +* 地址:http://grafana.shop.iocoder.cn:18099 +* 演示账号:yudaoyuanma / yudaoyuanma +* 用于展示 Prometheus 收集的 Metrics 指标数据。 + +**Dubbo Admin** + +* 地址:http://dubbo-admin.shop.iocoder.cn:18099 +* 管理员账号:无需登陆 + +**RocketMQ Console** + +* 地址: + +> 教程:[《芋道 RocketMQ 安装部署》](http://www.iocoder.cn/RocketMQ/install/?onemall) + +**XXL-Job Console** + +* 地址: +* 管理员账号:admin / 123456 + +> 教程:[《芋道 XXL-Job 安装部署》](http://www.iocoder.cn/XXL-JOB/install/?onemall) + +**Sentinel Console** + +* 地址: +* 账号:sentinel / sentinel + +> 教程:[《芋道 Sentinel 安装部署》](http://www.iocoder.cn/Sentinel/install/?onemall) + +# 技术 + +## 搭建环境 + +[搭建调试环境](http://www.iocoder.cn/Onemall/build-debugger-environment/) + +## 架构图 + +TODO 此处应有一个架构图的装逼 JPG 图。 + +## 项目结构 + +| 模块 | 名称 | 端口 | | +| --- | --- | --- | --- | +| [`admin-dashboard-vue`](https://github.com/YunaiV/onemall-web/tree/master/admin-dashboard-vue) | 【前端】管理后台 | HTTP 9527 | | +| [`user-dashboard-vue`](https://github.com/YunaiV/onemall-web/tree/master/user-h5-vue) | 【前端】商城平台 | HTTP 8080 | | +| | | | +| | | | +| `management-web-app` | 【后端】管理平台 HTTP 服务 | HTTP 18083 | [接口文档](http://api-dashboard.shop.iocoder.cn/management-api/doc.html) | +| `shop-web-app` | 【后端】商城平台 HTTP 服务 | HTTP 18084 | [接口文档](http://api-h5.shop.iocoder.cn/shop-api/doc.html) | +| | | | +| | | | +| `system-service-project` | 系统 RPC 服务 | 随机 | +| `user-service-project` | 用户 RPC 服务 | 随机 | | +| `promotion-service-project` | 营销 RPC 服务 | 随机 | | +| `pay-service-project` | 支付 RPC 服务 | 随机 | | +| `trade-service-project` | 交易 RPC 服务 | 随机 | | +| `product-service-project` | 商品 RPC 服务 | 随机 | | +| `search-service-project` | 搜索 RPC 服务 | 随机 | | + +------- + +后端项目,目前的项目结构如下: + +```Java +[-] xxx-web-app // 提供对外 HTTP API。 + +[-] xxx-service-project + ├──[-] xxx-service-api // 提供对内 RPC API 。 + ├──[-] xxx-service-app // 提供对内 RPC 实现。 + ├──[-] xxx-service-integration-test // 集成测试。 +``` + + +## 技术栈 + +### 后端 + +| 框架 | 说明 | 版本 | +| --- | --- | --- | +| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.1.4 | +| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.6 | +| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.1.16 | +| [MyBatis](http://www.mybatis.org/mybatis-3/zh/index.html) | 数据持久层框架 | 3.5.1 | +| [MyBatis-Plus](https://mp.baomidou.com/) | Mybatis 增强工具包 | 3.1.1 | +| [Redis](https://redis.io/) | key-value 数据库 | 暂未引入,等压测后,部分模块 | +| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 暂未引入,等压测后,部分模块 | +| [Elasticsearch](https://www.elastic.co/cn/) | 分布式搜索引擎 | 6.7.1 | +| [Dubbo](http://dubbo.apache.org/) | 分布式 RPC 服务框架 | 2.7.1 | +| [RocketMQ](http://dubbo.apache.org/) | 消息中间件 | 4.3.2 | +| [Seata](https://github.com/seata/seata) | 分布式事务中间件 | 0.5.1 | +| [Zookeeper](http://zookeeper.apache.org/) | 分布式系统协调 | 3.4.9 作为注册中心 | +| [XXL-Job](http://www.xuxueli.com/xxl-job/) | 分布式任务调度平台 | 2.0.1 | +| [springfox-swagger2](https://github.com/springfox/springfox/tree/master/springfox-swagger2) | API 文档 | 2.9.2 | +| [swagger-bootstrap-ui](https://gitee.com/xiaoym/swagger-bootstrap-ui) | Swagger 增强 UI 实现 | 1.9.3 | + +未来考虑引入 + +* [ ] 配置中心 Apollo +* [ ] 服务保障 Sentinel +* [ ] 网关 Soul + +### 前端 + +**商城 H5** + +| 框架 | 说明 | 版本 | +| --- | --- | --- | +| [Vue](https://cn.vuejs.org/index.html) | JavaScript 框架 | 2.5.17 | +| [Vant](https://youzan.github.io/vant/#/zh-CN/intro) | Vue UI 组件库 | 3.13.0 | + +**管理后台** + +| 框架 | 说明 | 版本 | +| --- | --- | --- | +| [Vue](https://cn.vuejs.org/index.html) | JavaScript 框架 | 2.5.17 | +| [Vue Element Admin](https://ant.design/docs/react/introduce-cn) | 后台前端解决方案 | - | + +### 监控 + +一般来说,监控会有三种方式: + +* 1、Tracing ,我们采用 Apache SkyWalking +* 2、Logging ,我们采用 ELK +* 3、Metrics ,我们采用 Prometheus + +| 框架 | 说明 | 版本 | +| --- | --- | --- | +| [SkyWalking](http://skywalking.apache.org/) | 分布式应用追踪系统 | 6.0.0 | +| [Prometheus](https://prometheus.io/) | 服务监控体系 | 2.9.2 | +| [Alertmanager](https://prometheus.io/docs/alerting/alertmanager/) | 告警管理器 | 0.17.0 | +| [Grafana](https://grafana.com/) | 仪表盘和图形编辑器 | 0.17.0 | + +### 其它 + +* Jenkins 持续集成 +* Nginx 服务器 +* [ ] Docker 容器 +* [ ] Nginx + +# 某种结尾 + +目前成员 + +* 小范 +* 芋艿 diff --git a/pom.xml b/pom.xml index 5f3320a22..e5986837e 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ yudao-framework - + yudao-module-bpm yudao-module-system yudao-module-infra diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index ed1484fdb..45c45937e 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -16,7 +16,7 @@ 1.6.2-snapshot - 2.6.8 + 2.6.9 2021.0.1 2021.0.1.0 @@ -24,7 +24,7 @@ 1.6.6 2.5 - 1.2.8 + 1.2.11 3.4.3.4 3.5.2 3.5.0 @@ -53,7 +53,7 @@ 3.0.4 1.18.20 1.4.1.Final - 5.6.1 + 5.7.22 2.2.7 2.2 1.0.5 @@ -63,6 +63,7 @@ 2.12.2 3.8.0 0.1.55 + 2.4.1 8.2.2 4.5.25 @@ -523,6 +524,12 @@ ${easyexcel.verion} + + org.apache.tika + tika-core + ${tika-core.version} + + org.apache.velocity velocity-engine-core @@ -629,6 +636,12 @@ com.xkcoding.justauth justauth-spring-boot-starter ${justauth.version} + + + cn.hutool + hutool-core + + diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java index 947d3e815..dd3640d13 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.common.enums; /** * Web 过滤器顺序的枚举类,保证过滤器按照符合我们的预期 * - * 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 util 包下 + * 考虑到每个 starter 都需要用到该工具类,所以放到 common 模块下的 enum 包下 * * @author 芋道源码 */ diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java index 6a4c28e72..80029703b 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java @@ -23,8 +23,8 @@ public class PageParam implements Serializable { @ApiModelProperty(value = "每页条数,最大值为 100", required = true, example = "10") @NotNull(message = "每页条数不能为空") - @Min(value = 1, message = "页码最小值为 1") - @Max(value = 100, message = "页码最大值为 100") + @Min(value = 1, message = "每页条数最小值为 1") + @Max(value = 100, message = "每页条数最大值为 100") private Integer pageSize = PAGE_SIZE; } diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/ArrayUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/ArrayUtils.java index 899acbfc7..366f96008 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/ArrayUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/ArrayUtils.java @@ -2,14 +2,8 @@ package cn.iocoder.yudao.framework.common.util.collection; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.TypeUtil; -import org.springframework.cglib.core.TypeUtils; -import java.lang.reflect.Array; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; import java.util.Collection; -import java.util.List; import java.util.function.Consumer; import java.util.function.Function; @@ -53,4 +47,11 @@ public class ArrayUtils { return ArrayUtil.toArray(from, (Class) CollectionUtil.getElementType(from.iterator())); } + public static T get(T[] array, int index) { + if (null == array || index >= array.length) { + return null; + } + return array[index]; + } + } diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/FileUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/FileUtils.java index 63732f1b3..2f870d738 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/FileUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/FileUtils.java @@ -1,9 +1,14 @@ package cn.iocoder.yudao.framework.common.util.io; +import cn.hutool.core.io.FileTypeUtil; import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.file.FileNameUtil; import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; import lombok.SneakyThrows; +import java.io.ByteArrayInputStream; import java.io.File; /** @@ -58,4 +63,22 @@ public class FileUtils { return file; } + /** + * 生成文件路径 + * + * @param content 文件内容 + * @param originalName 原始文件名 + * @return path,唯一不可重复 + */ + public static String generatePath(byte[] content, String originalName) { + String sha256Hex = DigestUtil.sha256Hex(content); + // 情况一:如果存在 name,则优先使用 name 的后缀 + if (StrUtil.isNotBlank(originalName)) { + String extName = FileNameUtil.extName(originalName); + return StrUtil.isBlank(extName) ? sha256Hex : sha256Hex + "." + extName; + } + // 情况二:基于 content 计算 + return sha256Hex + '.' + FileTypeUtil.getType(new ByteArrayInputStream(content)); + } + } diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java index f41234736..0be190942 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java @@ -41,11 +41,6 @@ public class JsonUtils { JsonUtils.objectMapper = objectMapper; } - @SneakyThrows - public static String toJsonPrettyString(Object object) { - return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object); - } - @SneakyThrows public static String toJsonString(Object object) { return objectMapper.writeValueAsString(object); @@ -56,6 +51,10 @@ public class JsonUtils { return objectMapper.writeValueAsBytes(object); } + @SneakyThrows + public static String toJsonPrettyString(Object object) { + return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object); + } public static T parseObject(String text, Class clazz) { if (StrUtil.isEmpty(text)) { @@ -137,7 +136,7 @@ public class JsonUtils { } public static boolean isJson(String text) { - return JSONUtil.isJson(text); + return JSONUtil.isTypeJSON(text); } } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/aop/OperateLogAspect.java b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/aop/OperateLogAspect.java index a63208373..d3b94d25a 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/aop/OperateLogAspect.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/aop/OperateLogAspect.java @@ -44,7 +44,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC * 满足如下任一条件,则会进行记录: * 1. 使用 @ApiOperation + 非 @GetMapping * 2. 使用 @OperateLog 注解 - * + *

* 但是,如果声明 @OperateLog 注解时,将 enable 属性设置为 false 时,强制不记录。 * * @author 芋道源码 @@ -77,7 +77,8 @@ public class OperateLogAspect { return around0(joinPoint, operateLog, apiOperation); } - @Around("!@annotation(io.swagger.annotations.ApiOperation) && @annotation(operateLog)") // 兼容处理,只添加 @OperateLog 注解的情况 + @Around("!@annotation(io.swagger.annotations.ApiOperation) && @annotation(operateLog)") + // 兼容处理,只添加 @OperateLog 注解的情况 public Object around(ProceedingJoinPoint joinPoint, cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog) throws Throwable { return around0(joinPoint, operateLog, null); @@ -236,14 +237,12 @@ public class OperateLogAspect { } operateLogObj.setDuration((int) (System.currentTimeMillis() - startTime.getTime())); // (正常)处理 resultCode 和 resultMsg 字段 - if (result != null) { - if (result instanceof CommonResult) { - CommonResult commonResult = (CommonResult) result; - operateLogObj.setResultCode(commonResult.getCode()); - operateLogObj.setResultMsg(commonResult.getMsg()); - } else { - operateLogObj.setResultCode(SUCCESS.getCode()); - } + if (result instanceof CommonResult) { + CommonResult commonResult = (CommonResult) result; + operateLogObj.setResultCode(commonResult.getCode()); + operateLogObj.setResultMsg(commonResult.getMsg()); + } else { + operateLogObj.setResultCode(SUCCESS.getCode()); } // (异常)处理 resultCode 和 resultMsg 字段 if (exception != null) { @@ -267,7 +266,7 @@ public class OperateLogAspect { return null; } return Arrays.stream(requestMethods).filter(requestMethod -> - requestMethod == RequestMethod.POST + requestMethod == RequestMethod.POST || requestMethod == RequestMethod.PUT || requestMethod == RequestMethod.DELETE) .findFirst().orElse(null); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java index a23ccd341..7cb813ca9 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.tenant.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; +import java.util.Collections; import java.util.Set; /** @@ -29,13 +30,13 @@ public class TenantProperties { * * 默认情况下,每个请求需要带上 tenant-id 的请求头。但是,部分请求是无需带上的,例如说短信回调、支付回调等 Open API! */ - private Set ignoreUrls; + private Set ignoreUrls = Collections.emptySet(); /** * 需要忽略多租户的表 * * 即默认所有表都开启多租户的功能,所以记得添加对应的 tenant_id 字段哟 */ - private Set ignoreTables; + private Set ignoreTables = Collections.emptySet(); } diff --git a/yudao-framework/yudao-spring-boot-starter-file/pom.xml b/yudao-framework/yudao-spring-boot-starter-file/pom.xml index 67b05223b..905e0f7c1 100644 --- a/yudao-framework/yudao-spring-boot-starter-file/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-file/pom.xml @@ -61,6 +61,11 @@ jsch + + org.apache.tika + tika-core + + io.minio diff --git a/yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/utils/FileTypeUtils.java b/yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/utils/FileTypeUtils.java new file mode 100644 index 000000000..b623d364a --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/utils/FileTypeUtils.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.framework.file.core.utils; + +import com.alibaba.ttl.TransmittableThreadLocal; +import lombok.SneakyThrows; +import org.apache.tika.Tika; + +/** + * 文件类型 Utils + * + * @author 芋道源码 + */ +public class FileTypeUtils { + + private static final ThreadLocal TIKA = TransmittableThreadLocal.withInitial(Tika::new); + + /** + * 获得文件的 mineType,对于doc,jar等文件会有误差 + * + * @param data 包含文件开头几千个字节的字节数组 + * @return mineType 无法识别时会返回“application/octet-stream” + */ + @SneakyThrows + public static String getMineType(byte[] data) { + return TIKA.get().detect(data); + } + + /** + * 已知文件名,获取文件类型,在某些情况下比通过字节数组准确,例如使用jar文件时,通过名字更为准确 + * + * @param name 文件名 + * @return mineType 无法识别时会返回“application/octet-stream” + */ + public static String getMineType(String name) { + return TIKA.get().detect(name); + } + + /** + * 在拥有文件和数据的情况下,最好使用此方法,最为准确 + * + * @param data 包含文件开头几千个字节的字节数组 + * @param name 文件名 + * @return mineType 无法识别时会返回“application/octet-stream” + */ + public static String getMineType(byte[] data, String name) { + return TIKA.get().detect(data, name); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java b/yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java index 3621d9d99..b41f678d6 100644 --- a/yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java @@ -59,4 +59,15 @@ public class FlowableUtils { BpmnXMLConverter converter = new BpmnXMLConverter(); return converter.convertToXML(model); } + + // ========== Execution 相关的工具方法 ========== + + public static String formatCollectionVariable(String activityId) { + return activityId + "_assignees"; + } + + public static String formatCollectionElementVariable(String activityId) { + return activityId + "_assignee"; + } + } diff --git a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java index 7300352de..3c3b9f3bb 100644 --- a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java +++ b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java @@ -38,7 +38,7 @@ public class BizTraceAspect { String operationName = getOperationName(joinPoint, trace); Span span = tracer.buildSpan(operationName) .withTag(Tags.COMPONENT.getKey(), "biz") - .startManual(); + .start(); try { // 执行原有方法 return joinPoint.proceed(); diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java index 463db3038..9fd1d16f8 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.framework.mybatis.core.query; +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.ArrayUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.support.SFunction; import org.springframework.util.StringUtils; @@ -33,7 +33,7 @@ public class LambdaQueryWrapperX extends LambdaQueryWrapper { } public LambdaQueryWrapperX inIfPresent(SFunction column, Object... values) { - if (!ArrayUtils.isEmpty(values)) { + if (!ArrayUtil.isEmpty(values)) { return (LambdaQueryWrapperX) super.in(column, values); } return this; @@ -94,6 +94,12 @@ public class LambdaQueryWrapperX extends LambdaQueryWrapper { return this; } + public LambdaQueryWrapperX betweenIfPresent(SFunction column, Object[] values) { + Object val1 = ArrayUtils.get(values, 0); + Object val2 = ArrayUtils.get(values, 1); + return betweenIfPresent(column, val1, val2); + } + // ========== 重写父类方法,方便链式调用 ========== @Override diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java index 9d5f64597..7454b5ff6 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/SecurityProperties.java @@ -6,6 +6,8 @@ import org.springframework.validation.annotation.Validated; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; +import java.util.Collections; +import java.util.List; @ConfigurationProperties(prefix = "yudao.security") @Validated @@ -30,4 +32,9 @@ public class SecurityProperties { @NotEmpty(message = "mock 模式的密钥不能为空") // 这里设置了一个默认值,因为实际上只有 mockEnable 为 true 时才需要配置。 private String mockSecret = "test"; + /** + * 免登录的 URL 列表 + */ + private List permitAllUrls = Collections.emptyList(); + } diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java index 61edba6e8..7c50bbafa 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java @@ -2,7 +2,10 @@ package cn.iocoder.yudao.framework.security.config; import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter; import cn.iocoder.yudao.framework.web.config.WebProperties; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; @@ -14,9 +17,15 @@ import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import java.util.List; +import java.util.Map; +import java.util.Set; /** * 自定义的 Spring Security 配置适配器实现 @@ -29,6 +38,8 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap @Resource private WebProperties webProperties; + @Resource + private SecurityProperties securityProperties; /** * 认证失败处理类 Bean @@ -54,6 +65,9 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap @Resource private List authorizeRequestsCustomizers; + @Resource + private ApplicationContext applicationContext; + /** * 由于 Spring Security 创建 AuthenticationManager 对象时,没声明 @Bean 注解,导致无法被注入 * 通过覆写父类的该方法,添加 @Bean 注解,解决该问题 @@ -95,32 +109,77 @@ public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdap .headers().frameOptions().disable().and() // 一堆自定义的 Spring Security 处理器 .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint) - .accessDeniedHandler(accessDeniedHandler); - // 登录、登录暂时不使用 Spring Security 的拓展点,主要考虑一方面拓展多用户、多种登录方式相对复杂,一方面用户的学习成本较高 + .accessDeniedHandler(accessDeniedHandler); + // 登录、登录暂时不使用 Spring Security 的拓展点,主要考虑一方面拓展多用户、多种登录方式相对复杂,一方面用户的学习成本较高 + // 获得 @PermitAll 带来的 URL 列表,免登录 + Multimap permitAllUrls = getPermitAllUrlsFromAnnotations(); // 设置每个请求的权限 httpSecurity // ①:全局共享规则 .authorizeRequests() - // 静态资源,可匿名访问 - .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() - .antMatchers(HttpMethod.GET, "/admin-ui/**").permitAll() - // 设置 App API 无需认证 - .antMatchers(buildAppApi("/**")).permitAll() + // 静态资源,可匿名访问 + .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() + // 设置 @PermitAll 无需认证 + .antMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll() + .antMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll() + .antMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll() + .antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll() + // 基于 yudao.security.permit-all-urls 无需认证 + .antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll() + // 设置 App API 无需认证 + .antMatchers(buildAppApi("/**")).permitAll() // ②:每个项目的自定义规则 .and().authorizeRequests(registry -> // 下面,循环设置自定义规则 authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry))) // ③:兜底规则,必须认证 .authorizeRequests() - .anyRequest().authenticated() + .anyRequest().authenticated() ; // 添加 JWT Filter httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); } - + private String buildAppApi(String url) { return webProperties.getAppApi().getPrefix() + url; } + private Multimap getPermitAllUrlsFromAnnotations() { + Multimap result = HashMultimap.create(); + // 获得接口对应的 HandlerMethod 集合 + RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) + applicationContext.getBean("requestMappingHandlerMapping"); + Map handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods(); + // 获得有 @PermitAll 注解的接口 + for (Map.Entry entry : handlerMethodMap.entrySet()) { + HandlerMethod handlerMethod = entry.getValue(); + if (!handlerMethod.hasMethodAnnotation(PermitAll.class)) { + continue; + } + if (entry.getKey().getPatternsCondition() == null) { + continue; + } + Set urls = entry.getKey().getPatternsCondition().getPatterns(); + // 根据请求方法,添加到 result 结果 + entry.getKey().getMethodsCondition().getMethods().forEach(requestMethod -> { + switch (requestMethod) { + case GET: + result.putAll(HttpMethod.GET, urls); + break; + case POST: + result.putAll(HttpMethod.POST, urls); + break; + case PUT: + result.putAll(HttpMethod.PUT, urls); + break; + case DELETE: + result.putAll(HttpMethod.DELETE, urls); + break; + } + }); + } + return result; + } + } diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java index d2703a0e7..d41c3951e 100644 --- a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java @@ -40,7 +40,7 @@ public class RandomUtils { // Integer PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Integer.class, (dataProviderStrategy, attributeMetadata, map) -> { // 如果是 status 的字段,返回 0 或 1 - if (attributeMetadata.getAttributeName().equals("status")) { + if ("status".equals(attributeMetadata.getAttributeName())) { return RandomUtil.randomEle(CommonStatusEnum.values()).getStatus(); } // 如果是 type、status 结尾的字段,返回 tinyint 范围 @@ -53,7 +53,7 @@ public class RandomUtils { // Boolean PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> { // 如果是 deleted 的字段,返回非删除 - if (attributeMetadata.getAttributeName().equals("deleted")) { + if ("deleted".equals(attributeMetadata.getAttributeName())) { return false; } return RandomUtil.randomBoolean(); diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java index 8b0815b73..dbd490888 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.swagger.config; import cn.iocoder.yudao.framework.swagger.core.SpringFoxHandlerProviderBeanPostProcessor; import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -22,6 +21,7 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.Collections; import java.util.List; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; import static springfox.documentation.builders.RequestHandlerSelectors.basePackage; /** @@ -44,27 +44,22 @@ public class YudaoSwaggerAutoConfiguration { } @Bean - @ConditionalOnMissingBean - public SwaggerProperties swaggerProperties() { - return new SwaggerProperties(); - } - - @Bean - public Docket createRestApi() { - SwaggerProperties properties = swaggerProperties(); + public Docket createRestApi(SwaggerProperties properties) { // 创建 Docket 对象 return new Docket(DocumentationType.SWAGGER_2) - // 用来创建该 API 的基本信息,展示在文档的页面中(自定义展示的信息) + // ① 用来创建该 API 的基本信息,展示在文档的页面中(自定义展示的信息) .apiInfo(apiInfo(properties)) - // 设置扫描指定 package 包下的 + // ② 设置扫描指定 package 包下的 .select() .apis(basePackage(properties.getBasePackage())) // .apis(basePackage("cn.iocoder.yudao.module.system")) // 可用于 swagger 无法展示时使用 .paths(PathSelectors.any()) .build() + // ③ 安全上下文(认证) .securitySchemes(securitySchemes()) - .globalRequestParameters(globalRequestParameters()) - .securityContexts(securityContexts()); + .securityContexts(securityContexts()) + // ④ 全局参数(多租户 header) + .globalRequestParameters(globalRequestParameters()); } // ========== apiInfo ========== @@ -99,7 +94,8 @@ public class YudaoSwaggerAutoConfiguration { private static List securityContexts() { return Collections.singletonList(SecurityContext.builder() .securityReferences(securityReferences()) - .forPaths(PathSelectors.regex("^(?!auth).*$")) + // 通过 PathSelectors.regex("^(?!auth).*$"),排除包含 "auth" 的接口不需要使用securitySchemes + .operationSelector(o -> o.requestMappingPattern().matches("^(?!auth).*$")) .build()); } @@ -114,7 +110,8 @@ public class YudaoSwaggerAutoConfiguration { // ========== globalRequestParameters ========== private static List globalRequestParameters() { - RequestParameterBuilder tenantParameter = new RequestParameterBuilder().name("tenant-id").description("租户编号") + RequestParameterBuilder tenantParameter = new RequestParameterBuilder() + .name(HEADER_TENANT_ID).description("租户编号") .in(ParameterType.HEADER).example(new ExampleBuilder().value(1L).build()); return Collections.singletonList(tenantParameter.build()); } diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/logging/AccessLogFilter.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/logging/AccessLogFilter.java index d55d2149a..f753ef5f1 100644 --- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/logging/AccessLogFilter.java +++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/logging/AccessLogFilter.java @@ -86,7 +86,8 @@ public class AccessLogFilter implements GlobalFilter, Ordered { values.put("userIp", gatewayLog.getUserIp()); values.put("responseBody", JsonUtils.isJson(gatewayLog.getResponseBody()) ? // 保证 body 的展示好看 JSONUtil.parse(gatewayLog.getResponseBody()) : gatewayLog.getResponseBody()); - values.put("responseHeaders", JsonUtils.toJsonString(gatewayLog.getResponseHeaders().toSingleValueMap())); + values.put("responseHeaders", gatewayLog.getResponseHeaders() != null ? + JsonUtils.toJsonString(gatewayLog.getResponseHeaders().toSingleValueMap()) : null); values.put("httpStatus", gatewayLog.getHttpStatus()); values.put("startTime", DateUtil.format(gatewayLog.getStartTime(), NORM_DATETIME_MS_FORMAT)); values.put("endTime", DateUtil.format(gatewayLog.getEndTime(), NORM_DATETIME_MS_FORMAT)); diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/security/TokenAuthenticationFilter.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/security/TokenAuthenticationFilter.java index 954ad55a3..7d366becf 100644 --- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/security/TokenAuthenticationFilter.java +++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/security/TokenAuthenticationFilter.java @@ -34,9 +34,19 @@ import java.util.function.Function; @Component public class TokenAuthenticationFilter implements GlobalFilter, Ordered { + /** + * CommonResult 对应的 TypeReference 结果,用于解析 checkToken 的结果 + */ private static final TypeReference> CHECK_RESULT_TYPE_REFERENCE = new TypeReference>() {}; + /** + * 空的 LoginUser 的结果 + * + * TODO 芋艿:用于解决 getLoginUser 返回 Mono.empty() 的时候,会导致后续的 flatMap 无法进行处理的问题。先暂时这么解决,寻找更优解 ing + */ + private static final LoginUser LOGIN_USER_EMPTY = new LoginUser(); + private final WebClient webClient; /** @@ -76,14 +86,18 @@ public class TokenAuthenticationFilter implements GlobalFilter, Ordered { } // 情况二,如果有 Token 令牌,则解析对应 userId、userType、tenantId 等字段,并通过 通过 Header 转发给服务 - return getLoginUser(exchange, token).flatMap(user -> { - if (user == null) { + // 重要说明:defaultIfEmpty 作用,保证 Mono.empty() 情况,可以继续执行 `flatMap 的 chain.filter(exchange)` 逻辑,避免返回给前端空的 Response!! + return getLoginUser(exchange, token).defaultIfEmpty(LOGIN_USER_EMPTY).flatMap(user -> { + // 1. 无用户,直接 filter 继续请求 + if (user == LOGIN_USER_EMPTY) { return chain.filter(exchange); } - // 设置登录用户 + + // 2.1 有用户,则设置登录用户 SecurityFrameworkUtils.setLoginUser(exchange, user); - // 将 user 并设置到 login-user 的请求头,使用 json 存储值 - ServerWebExchange newExchange = exchange.mutate().request(builder -> SecurityFrameworkUtils.setLoginUserHeader(builder, user)).build(); + // 2.2 将 user 并设置到 login-user 的请求头,使用 json 存储值 + ServerWebExchange newExchange = exchange.mutate() + .request(builder -> SecurityFrameworkUtils.setLoginUserHeader(builder, user)).build(); return chain.filter(newExchange); }); } diff --git a/yudao-gateway/src/main/resources/application.yaml b/yudao-gateway/src/main/resources/application.yaml index 6d4439553..29d9576a6 100644 --- a/yudao-gateway/src/main/resources/application.yaml +++ b/yudao-gateway/src/main/resources/application.yaml @@ -23,3 +23,7 @@ spring: uri: grayLb://infra-server predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 - Path=/app-api/infra/** + - id: bpm-admin-api # 路由的编号 + uri: grayLb://bpm-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/bpm/** diff --git a/yudao-module-bpm/pom.xml b/yudao-module-bpm/pom.xml new file mode 100644 index 000000000..432b97ae4 --- /dev/null +++ b/yudao-module-bpm/pom.xml @@ -0,0 +1,27 @@ + + + + cn.iocoder.cloud + yudao + ${revision} + + 4.0.0 + + yudao-module-bpm-api + yudao-module-bpm-biz + + yudao-module-bpm + pom + + ${project.artifactId} + + bpm 包下,业务流程管理(Business Process Management),我们放工作流的功能。 + 例如说:流程定义、表单配置、审核中心(我的申请、我的待办、我的已办)等等 + bpm 解释:https://baike.baidu.com/item/BPM/1933 + + 工作流基于 Flowable 6 实现,分成流程定义、流程表单、流程实例、流程任务等功能模块。 + + + diff --git a/yudao-module-bpm/yudao-module-bpm-api/pom.xml b/yudao-module-bpm/yudao-module-bpm-api/pom.xml new file mode 100644 index 000000000..ba89fc7f6 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/pom.xml @@ -0,0 +1,33 @@ + + + + cn.iocoder.cloud + yudao-module-bpm + ${revision} + + 4.0.0 + yudao-module-bpm-api + jar + + ${project.artifactId} + + bpm 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.cloud + yudao-common + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java new file mode 100644 index 000000000..37a92219f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java @@ -0,0 +1,4 @@ +/** + * bpm API 包,定义暴露给其它模块的 API + */ +package cn.iocoder.yudao.module.bpm.api; diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApi.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApi.java new file mode 100644 index 000000000..e94a2c84f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApi.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.bpm.api.task; + +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; + +import javax.validation.Valid; + +/** + * 流程实例 Api 接口 + * + * @author 芋道源码 + */ +public interface BpmProcessInstanceApi { + + /** + * 创建流程实例(提供给内部) + * + * @param userId 用户编号 + * @param reqDTO 创建信息 + * @return 实例的编号 + */ + String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java new file mode 100644 index 000000000..5d7edbe80 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/task/dto/BpmProcessInstanceCreateReqDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.api.task.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.Map; + +/** + * 流程实例的创建 Request DTO + * + * @author 芋道源码 + */ +@Data +public class BpmProcessInstanceCreateReqDTO { + + /** + * 流程定义的标识 + */ + @NotEmpty(message = "流程定义的标识不能为空") + private String processDefinitionKey; + /** + * 变量实例 + */ + private Map variables; + + /** + * 业务的唯一标识 + * + * 例如说,请假申请的编号。通过它,可以查询到对应的实例 + */ + @NotEmpty(message = "业务的唯一标识") + private String businessKey; +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/DictTypeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/DictTypeConstants.java new file mode 100644 index 000000000..7abb3e1db --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/DictTypeConstants.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.bpm.enums; + +/** + * BPM 字典类型的枚举类 + * + * @author 芋道源码 + */ +public interface DictTypeConstants { + + String TASK_ASSIGN_RULE_TYPE = "bpm_task_assign_rule_type"; // 任务分配规则类型 + String TASK_ASSIGN_SCRIPT = "bpm_task_assign_script"; // 任务分配自定义脚本 + +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java new file mode 100644 index 000000000..9451f6d49 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.bpm.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * 工作流 错误码枚举类 + * + * 工作流系统,使用 1-009-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== 通用流程处理 模块 1-009-000-000 ========== + ErrorCode HIGHLIGHT_IMG_ERROR = new ErrorCode(1009000002, "获取高亮流程图异常"); + + // ========== OA 流程模块 1-009-001-000 ========== + ErrorCode OA_LEAVE_NOT_EXISTS = new ErrorCode(1009001001, "请假申请不存在"); + ErrorCode OA_PM_POST_NOT_EXISTS = new ErrorCode(1009001002, "项目经理岗位未设置"); + ErrorCode OA_DEPART_PM_POST_NOT_EXISTS = new ErrorCode(1009001009, "部门的项目经理不存在"); + ErrorCode OA_BM_POST_NOT_EXISTS = new ErrorCode(1009001004, "部门经理岗位未设置"); + ErrorCode OA_DEPART_BM_POST_NOT_EXISTS = new ErrorCode(1009001005, "部门的部门经理不存在"); + ErrorCode OA_HR_POST_NOT_EXISTS = new ErrorCode(1009001006, "HR岗位未设置"); + ErrorCode OA_DAY_LEAVE_ERROR = new ErrorCode(1009001007, "请假天数必须>=1"); + + // ========== 流程模型 1-009-002-000 ========== + ErrorCode MODEL_KEY_EXISTS = new ErrorCode(1009002000, "已经存在流程标识为【{}】的流程"); + ErrorCode MODEL_NOT_EXISTS = new ErrorCode(1009002001, "流程模型不存在"); + ErrorCode MODEL_KEY_VALID = new ErrorCode(1009002002, "流程标识格式不正确,需要以字母或下划线开头,后接任意字母、数字、中划线、下划线、句点!"); + ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1009002003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置"); + ErrorCode MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG = new ErrorCode(1009002004, "部署流程失败," + + "原因:用户任务({})未配置分配规则,请点击【修改流程】按钮进行配置"); + ErrorCode MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS = new ErrorCode(1009003005, "流程定义部署失败,原因:信息未发生变化"); + + // ========== 流程定义 1-009-003-000 ========== + ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1009003000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图"); + ErrorCode PROCESS_DEFINITION_NAME_NOT_MATCH = new ErrorCode(1009003001, "流程定义的名字期望是({}),当前是({}),请修改 BPMN 流程图"); + ErrorCode PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1009003002, "流程定义不存在"); + ErrorCode PROCESS_DEFINITION_IS_SUSPENDED = new ErrorCode(1009003003, "流程定义处于挂起状态"); + ErrorCode PROCESS_DEFINITION_BPMN_MODEL_NOT_EXISTS = new ErrorCode(1009003004, "流程定义的模型不存在"); + + // ========== 流程实例 1-009-004-000 ========== + ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1009004000, "流程实例不存在"); + ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS = new ErrorCode(1009004001, "流程取消失败,流程不处于运行中"); + ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF = new ErrorCode(1009004002, "流程取消失败,该流程不是你发起的"); + + // ========== 流程任务 1-009-005-000 ========== + ErrorCode TASK_COMPLETE_FAIL_NOT_EXISTS = new ErrorCode(1009005000, "审批任务失败,原因:该任务不处于未审批"); + ErrorCode TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF = new ErrorCode(1009005001, "审批任务失败,原因:该任务的审批人不是你"); + + // ========== 流程任务分配规则 1-009-006-000 ========== + ErrorCode TASK_ASSIGN_RULE_EXISTS = new ErrorCode(1009006000, "流程({}) 的任务({}) 已经存在分配规则"); + ErrorCode TASK_ASSIGN_RULE_NOT_EXISTS = new ErrorCode(1009006001, "流程任务分配规则不存在"); + ErrorCode TASK_UPDATE_FAIL_NOT_MODEL = new ErrorCode(1009006002, "只有流程模型的任务分配规则,才允许被修改"); + ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1009006003, "操作失败,原因:找不到任务的审批人!"); + ErrorCode TASK_ASSIGN_SCRIPT_NOT_EXISTS = new ErrorCode(1009006004, "操作失败,原因:任务分配脚本({}) 不存在"); + + // ========== 动态表单模块 1-009-010-000 ========== + ErrorCode FORM_NOT_EXISTS = new ErrorCode(1009010000, "动态表单不存在"); + ErrorCode FORM_FIELD_REPEAT = new ErrorCode(1009010001, "表单项({}) 和 ({}) 使用了相同的字段名({})"); + + // ========== 用户组模块 1-009-011-000 ========== + ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1009011000, "用户组不存在"); + ErrorCode USER_GROUP_IS_DISABLE = new ErrorCode(1009011001, "名字为【{}】的用户组已被禁用"); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelFormTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelFormTypeEnum.java new file mode 100644 index 000000000..c21d6f999 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmModelFormTypeEnum.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.enums.definition; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * BPM 模型的表单类型的枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmModelFormTypeEnum { + + NORMAL(10, "流程表单"), // 对应 BpmFormDO + CUSTOM(20, "业务表单") // 业务自己定义的表单,自己进行数据的存储 + ; + + private final Integer type; + private final String desc; +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java new file mode 100644 index 000000000..b7ccc7ae8 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.enums.definition; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * BPM 任务分配规则的类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmTaskAssignRuleTypeEnum { + + ROLE(10, "角色"), + DEPT_MEMBER(20, "部门的成员"), // 包括负责人 + DEPT_LEADER(21, "部门的负责人"), + POST(22, "岗位"), + USER(30, "用户"), + USER_GROUP(40, "用户组"), + SCRIPT(50, "自定义脚本"), // 例如说,发起人所在部门的领导、发起人所在部门的领导的领导 + ; + + /** + * 类型 + */ + private final Integer type; + /** + * 描述 + */ + private final String desc; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java new file mode 100644 index 000000000..7fc0e3b8b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.bpm.enums.definition; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * BPM 任务规则的脚本枚举 + * 目前暂时通过 TODO 芋艿:硬编码,未来可以考虑 Groovy 动态脚本的方式 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmTaskRuleScriptEnum { + + START_USER(10L, "流程发起人"), + + LEADER_X1(20L, "流程发起人的一级领导"), + LEADER_X2(21L, "流程发起人的二级领导"); + + /** + * 脚本编号 + */ + private final Long id; + /** + * 脚本描述 + */ + private final String desc; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java new file mode 100644 index 000000000..79001fccd --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.enums.message; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Bpm 消息的枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum BpmMessageEnum { + + PROCESS_INSTANCE_APPROVE("bpm_process_instance_approve"), // 流程任务被审批通过时,发送给申请人 + PROCESS_INSTANCE_REJECT("bpm_process_instance_reject"), // 流程任务被审批不通过时,发送给申请人 + TASK_ASSIGNED("bpm_task_assigned"); // 任务被分配时,发送给审批人 + + /** + * 短信模板的标识 + * + * 关联 SmsTemplateDO 的 code 属性 + */ + private final String smsTemplateCode; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceDeleteReasonEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceDeleteReasonEnum.java new file mode 100644 index 000000000..4f99d0a3d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceDeleteReasonEnum.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.bpm.enums.task; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 流程实例的删除原因 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmProcessInstanceDeleteReasonEnum { + + REJECT_TASK("不通过任务,原因:{}"), // 修改文案时,需要注意 isRejectReason 方法 + CANCEL_TASK("主动取消任务,原因:{}"), + + // ========== 流程任务的独有原因 ========== + MULTI_TASK_END("系统自动取消,原因:多任务审批已经满足条件,无需审批该任务"), // 多实例满足 condition 而结束时,其它任务实例任务会被取消,对应的删除原因是 MI_END + + ; + + private final String reason; + + /** + * 格式化理由 + * + * @param args 参数 + * @return 理由 + */ + public String format(Object... args) { + return StrUtil.format(reason, args); + } + + // ========== 逻辑 ========== + + public static boolean isRejectReason(String reason) { + return StrUtil.startWith(reason, "不通过任务,原因:"); + } + + /** + * 将 Flowable 的删除原因,翻译成对应的中文原因 + * + * @param reason 原始原因 + * @return 原因 + */ + public static String translateReason(String reason) { + if (StrUtil.isEmpty(reason)) { + return reason; + } + switch (reason) { + case "MI_END": return MULTI_TASK_END.getReason(); + default: return reason; + } + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java new file mode 100644 index 000000000..3b57554cf --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.bpm.enums.task; + +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 流程实例的结果 + * + * @author jason + */ +@Getter +@AllArgsConstructor +public enum BpmProcessInstanceResultEnum { + + PROCESS(1, "处理中"), + APPROVE(2, "通过"), + REJECT(3, "不通过"), + CANCEL(4, "已取消"), + + // ========== 流程任务独有的状态 ========== + + BACK(5, "退回/驳回"); + + /** + * 结果 + * + * 如果新增时,注意 {@link #isEndResult(Integer)} 是否需要变更 + */ + private final Integer result; + /** + * 描述 + */ + private final String desc; + + /** + * 判断该结果是否已经处于 End 最终结果 + * + * 主要用于一些结果更新的逻辑,如果已经是最终结果,就不再进行更新 + * + * @param result 结果 + * @return 是否 + */ + public static boolean isEndResult(Integer result) { + return ObjectUtils.equalsAny(result, APPROVE.getResult(), REJECT.getResult(), CANCEL.getResult(), BACK.getResult()); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java new file mode 100644 index 000000000..70a31dd34 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceStatusEnum.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.bpm.enums.task; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 流程实例的状态 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmProcessInstanceStatusEnum { + + RUNNING(1, "进行中"), + FINISH(2, "已完成"); + + /** + * 状态 + */ + private final Integer status; + /** + * 描述 + */ + private final String desc; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/pom.xml b/yudao-module-bpm/yudao-module-bpm-biz/pom.xml new file mode 100644 index 000000000..b168de28e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/pom.xml @@ -0,0 +1,125 @@ + + + + cn.iocoder.cloud + yudao-module-bpm + ${revision} + + 4.0.0 + yudao-module-bpm-biz + + ${project.artifactId} + + bpm-base 模块,实现公用的工作流的逻辑,提供给 bpm-activiti 和 bpm-flowable 复用 + + + + + + org.springframework.cloud + spring-cloud-starter-bootstrap + + + + cn.iocoder.cloud + yudao-module-bpm-api + ${revision} + + + cn.iocoder.cloud + yudao-module-system-api + ${revision} + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-biz-operatelog + + + cn.iocoder.cloud + yudao-spring-boot-starter-biz-data-permission + + + cn.iocoder.cloud + yudao-spring-boot-starter-biz-tenant + + + cn.iocoder.cloud + yudao-spring-boot-starter-biz-error-code + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-security + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-mybatis + + + + cn.iocoder.cloud + yudao-spring-boot-starter-redis + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-rpc + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-job + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-mq + + + + + + + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-test + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-monitor + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-flowable + + + diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/BpmServerApplication.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/BpmServerApplication.java new file mode 100644 index 000000000..d86a045a2 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/BpmServerApplication.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.bpm; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 项目的启动类 + * + * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + * + * @author 芋道源码 + */ +@SpringBootApplication +public class BpmServerApplication { + + public static void main(String[] args) { + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + + SpringApplication.run(BpmServerApplication.class, args); + + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章 + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java new file mode 100644 index 000000000..2137e2203 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/package-info.java @@ -0,0 +1,4 @@ +/** + * bpm API 实现类,定义暴露给其它模块的 API + */ +package cn.iocoder.yudao.module.bpm.api; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApiImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApiImpl.java new file mode 100644 index 000000000..596c9981a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApiImpl.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.bpm.api.task; + +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Valid; + +/** + * Flowable 流程实例 Api 实现类 + * + * @author 芋道源码 + * @author jason + */ +@Service +@Validated +public class BpmProcessInstanceApiImpl implements BpmProcessInstanceApi { + + @Resource + private BpmProcessInstanceService processInstanceService; + + @Override + public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO) { + return processInstanceService.createProcessInstance(userId, reqDTO); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmFormController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmFormController.java new file mode 100644 index 000000000..217067f31 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmFormController.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.*; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmFormConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - 动态表单") +@RestController +@RequestMapping("/bpm/form") +@Validated +public class BpmFormController { + + @Resource + private BpmFormService formService; + + @PostMapping("/create") + @ApiOperation("创建动态表单") + @PreAuthorize("@ss.hasPermission('bpm:form:create')") + public CommonResult createForm(@Valid @RequestBody BpmFormCreateReqVO createReqVO) { + return success(formService.createForm(createReqVO)); + } + + @PutMapping("/update") + @ApiOperation("更新动态表单") + @PreAuthorize("@ss.hasPermission('bpm:form:update')") + public CommonResult updateForm(@Valid @RequestBody BpmFormUpdateReqVO updateReqVO) { + formService.updateForm(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除动态表单") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('bpm:form:delete')") + public CommonResult deleteForm(@RequestParam("id") Long id) { + formService.deleteForm(id); + return success(true); + } + + @GetMapping("/get") + @ApiOperation("获得动态表单") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('bpm:form:query')") + public CommonResult getForm(@RequestParam("id") Long id) { + BpmFormDO form = formService.getForm(id); + return success(BpmFormConvert.INSTANCE.convert(form)); + } + + @GetMapping("/list-all-simple") + @ApiOperation(value = "获得动态表单的精简列表", notes = "用于表单下拉框") + public CommonResult> getSimpleForms() { + List list = formService.getFormList(); + return success(BpmFormConvert.INSTANCE.convertList2(list)); + } + + @GetMapping("/page") + @ApiOperation("获得动态表单分页") + @PreAuthorize("@ss.hasPermission('bpm:form:query')") + public CommonResult> getFormPage(@Valid BpmFormPageReqVO pageVO) { + PageResult pageResult = formService.getFormPage(pageVO); + return success(BpmFormConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java new file mode 100644 index 000000000..3dd0a0a4d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.io.IoUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; +import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import java.io.IOException; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - 流程模型") +@RestController +@RequestMapping("/bpm/model") +@Validated +public class BpmModelController { + + @Resource + private BpmModelService modelService; + + @GetMapping("/page") + @ApiOperation(value = "获得模型分页") + public CommonResult> getModelPage(BpmModelPageReqVO pageVO) { + return success(modelService.getModelPage(pageVO)); + } + + @GetMapping("/get") + @ApiOperation("获得模型") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class) + @PreAuthorize("@ss.hasPermission('bpm:model:query')") + public CommonResult getModel(@RequestParam("id") String id) { + BpmModelRespVO model = modelService.getModel(id); + return success(model); + } + + @PostMapping("/create") + @ApiOperation(value = "新建模型") + @PreAuthorize("@ss.hasPermission('bpm:model:create')") + public CommonResult createModel(@Valid @RequestBody BpmModelCreateReqVO createRetVO) { + return success(modelService.createModel(createRetVO, null)); + } + + @PutMapping("/update") + @ApiOperation(value = "修改模型") + @PreAuthorize("@ss.hasPermission('bpm:model:update')") + public CommonResult updateModel(@Valid @RequestBody BpmModelUpdateReqVO modelVO) { + modelService.updateModel(modelVO); + return success(true); + } + + @PostMapping("/import") + @ApiOperation(value = "导入模型") + @PreAuthorize("@ss.hasPermission('bpm:model:import')") + public CommonResult importModel(@Valid BpmModeImportReqVO importReqVO) throws IOException { + BpmModelCreateReqVO createReqVO = BpmModelConvert.INSTANCE.convert(importReqVO); + // 读取文件 + String bpmnXml = IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false); + return success(modelService.createModel(createReqVO, bpmnXml)); + } + + @PostMapping("/deploy") + @ApiOperation(value = "部署模型") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class) + @PreAuthorize("@ss.hasPermission('bpm:model:deploy')") + public CommonResult deployModel(@RequestParam("id") String id) { + modelService.deployModel(id); + return success(true); + } + + @PutMapping("/update-state") + @ApiOperation(value = "修改模型的状态", notes = "实际更新的部署的流程定义的状态") + @PreAuthorize("@ss.hasPermission('bpm:model:update')") + public CommonResult updateModelState(@Valid @RequestBody BpmModelUpdateStateReqVO reqVO) { + modelService.updateModelState(reqVO.getId(), reqVO.getState()); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除模型") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class) + @PreAuthorize("@ss.hasPermission('bpm:model:delete')") + public CommonResult deleteModel(@RequestParam("id") String id) { + modelService.deleteModel(id); + return success(true); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java new file mode 100644 index 000000000..ebcaad05b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmProcessDefinitionController.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - 流程定义") +@RestController +@RequestMapping("/bpm/process-definition") +@Validated +public class BpmProcessDefinitionController { + + @Resource + private BpmProcessDefinitionService bpmDefinitionService; + + @GetMapping("/page") + @ApiOperation(value = "获得流程定义分页") + @PreAuthorize("@ss.hasPermission('bpm:process-definition:query')") + public CommonResult> getProcessDefinitionPage( + BpmProcessDefinitionPageReqVO pageReqVO) { + return success(bpmDefinitionService.getProcessDefinitionPage(pageReqVO)); + } + + @GetMapping ("/list") + @ApiOperation(value = "获得流程定义列表") + @PreAuthorize("@ss.hasPermission('bpm:process-definition:query')") + public CommonResult> getProcessDefinitionList( + BpmProcessDefinitionListReqVO listReqVO) { + return success(bpmDefinitionService.getProcessDefinitionList(listReqVO)); + } + + @GetMapping ("/get-bpmn-xml") + @ApiOperation(value = "获得流程定义的 BPMN XML") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class) + @PreAuthorize("@ss.hasPermission('bpm:process-definition:query')") + public CommonResult getProcessDefinitionBpmnXML(@RequestParam("id") String id) { + String bpmnXML = bpmDefinitionService.getProcessDefinitionBpmnXML(id); + return success(bpmnXML); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmTaskAssignRuleController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmTaskAssignRuleController.java new file mode 100644 index 000000000..3e946707a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmTaskAssignRuleController.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - 任务分配规则") +@RestController +@RequestMapping("/bpm/task-assign-rule") +@Validated +public class BpmTaskAssignRuleController { + + @Resource + private BpmTaskAssignRuleService taskAssignRuleService; + + @GetMapping("/list") + @ApiOperation(value = "获得任务分配规则列表") + @ApiImplicitParams({ + @ApiImplicitParam(name = "modelId", value = "模型编号", example = "1024", dataTypeClass = String.class), + @ApiImplicitParam(name = "processDefinitionId", value = "流程定义的编号", example = "2048", dataTypeClass = String.class) + }) + @PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:query')") + public CommonResult> getTaskAssignRuleList( + @RequestParam(value = "modelId", required = false) String modelId, + @RequestParam(value = "processDefinitionId", required = false) String processDefinitionId) { + return success(taskAssignRuleService.getTaskAssignRuleList(modelId, processDefinitionId)); + } + + @PostMapping("/create") + @ApiOperation(value = "创建任务分配规则") + @PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:create')") + public CommonResult createTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleCreateReqVO reqVO) { + return success(taskAssignRuleService.createTaskAssignRule(reqVO)); + } + + @PutMapping("/update") + @ApiOperation(value = "更新任务分配规则") + @PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:update')") + public CommonResult updateTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleUpdateReqVO reqVO) { + taskAssignRuleService.updateTaskAssignRule(reqVO); + return success(true); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmUserGroupController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmUserGroupController.java new file mode 100644 index 000000000..4267f0902 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmUserGroupController.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmUserGroupConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - 用户组") +@RestController +@RequestMapping("/bpm/user-group") +@Validated +public class BpmUserGroupController { + + @Resource + private BpmUserGroupService userGroupService; + + @PostMapping("/create") + @ApiOperation("创建用户组") + @PreAuthorize("@ss.hasPermission('bpm:user-group:create')") + public CommonResult createUserGroup(@Valid @RequestBody BpmUserGroupCreateReqVO createReqVO) { + return success(userGroupService.createUserGroup(createReqVO)); + } + + @PutMapping("/update") + @ApiOperation("更新用户组") + @PreAuthorize("@ss.hasPermission('bpm:user-group:update')") + public CommonResult updateUserGroup(@Valid @RequestBody BpmUserGroupUpdateReqVO updateReqVO) { + userGroupService.updateUserGroup(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除用户组") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('bpm:user-group:delete')") + public CommonResult deleteUserGroup(@RequestParam("id") Long id) { + userGroupService.deleteUserGroup(id); + return success(true); + } + + @GetMapping("/get") + @ApiOperation("获得用户组") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('bpm:user-group:query')") + public CommonResult getUserGroup(@RequestParam("id") Long id) { + BpmUserGroupDO userGroup = userGroupService.getUserGroup(id); + return success(BpmUserGroupConvert.INSTANCE.convert(userGroup)); + } + + @GetMapping("/page") + @ApiOperation("获得用户组分页") + @PreAuthorize("@ss.hasPermission('bpm:user-group:query')") + public CommonResult> getUserGroupPage(@Valid BpmUserGroupPageReqVO pageVO) { + PageResult pageResult = userGroupService.getUserGroupPage(pageVO); + return success(BpmUserGroupConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/list-all-simple") + @ApiOperation(value = "获取用户组精简信息列表", notes = "只包含被开启的用户组,主要用于前端的下拉选项") + public CommonResult> getSimpleUserGroups() { + // 获用户门列表,只要开启状态的 + List list = userGroupService.getUserGroupListByStatus(CommonStatusEnum.ENABLE.getStatus()); + // 排序后,返回给前端 + return success(BpmUserGroupConvert.INSTANCE.convertList2(list)); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormBaseVO.java new file mode 100644 index 000000000..11fee5c00 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormBaseVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; + +import lombok.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; + +/** +* 动态表单 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class BpmFormBaseVO { + + @ApiModelProperty(value = "表单名称", required = true, example = "芋道") + @NotNull(message = "表单名称不能为空") + private String name; + + @ApiModelProperty(value = "表单状态", required = true, notes = "参见 CommonStatusEnum 枚举", example = "1") + @NotNull(message = "表单状态不能为空") + private Integer status; + + @ApiModelProperty(value = "备注", example = "我是备注") + private String remark; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormCreateReqVO.java new file mode 100644 index 000000000..d9a628125 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormCreateReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; + +import lombok.*; +import io.swagger.annotations.*; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@ApiModel("管理后台 - 动态表单创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmFormCreateReqVO extends BpmFormBaseVO { + + @ApiModelProperty(value = "表单的配置", required = true, notes = "JSON 字符串") + @NotNull(message = "表单的配置不能为空") + private String conf; + + @ApiModelProperty(value = "表单项的数组", required = true, notes = "JSON 字符串的数组") + @NotNull(message = "表单项的数组不能为空") + private List fields; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormPageReqVO.java new file mode 100644 index 000000000..a8097c437 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormPageReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ApiModel("管理后台 - 动态表单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmFormPageReqVO extends PageParam { + + @ApiModelProperty(value = "表单名称", example = "芋道") + private String name; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormRespVO.java new file mode 100644 index 000000000..76cf62046 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormRespVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; +import java.util.Date; +import java.util.List; + +@ApiModel("管理后台 - 动态表单 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmFormRespVO extends BpmFormBaseVO { + + @ApiModelProperty(value = "表单编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "表单的配置", required = true, notes = "JSON 字符串") + @NotNull(message = "表单的配置不能为空") + private String conf; + + @ApiModelProperty(value = "表单项的数组", required = true, notes = "JSON 字符串的数组") + @NotNull(message = "表单项的数组不能为空") + private List fields; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSimpleRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSimpleRespVO.java new file mode 100644 index 000000000..3a6b3c093 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormSimpleRespVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel("管理后台 - 流程表单精简 Response VO") +@Data +public class BpmFormSimpleRespVO { + + @ApiModelProperty(value = "表单编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "表单名称", required = true, example = "芋道") + private String name; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormUpdateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormUpdateReqVO.java new file mode 100644 index 000000000..55b997679 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/form/BpmFormUpdateReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form; + +import lombok.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; +import java.util.List; + +@ApiModel("管理后台 - 动态表单更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmFormUpdateReqVO extends BpmFormBaseVO { + + @ApiModelProperty(value = "表单编号", required = true, example = "1024") + @NotNull(message = "表单编号不能为空") + private Long id; + + @ApiModelProperty(value = "表单的配置", required = true, notes = "JSON 字符串") + @NotNull(message = "表单的配置不能为空") + private String conf; + + @ApiModelProperty(value = "表单项的数组", required = true, notes = "JSON 字符串的数组") + @NotNull(message = "表单项的数组不能为空") + private List fields; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupBaseVO.java new file mode 100644 index 000000000..e0dfe568e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupBaseVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; + +/** +* 用户组 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class BpmUserGroupBaseVO { + + @ApiModelProperty(value = "组名", required = true, example = "芋道") + @NotNull(message = "组名不能为空") + private String name; + + @ApiModelProperty(value = "描述", required = true, example = "芋道源码") + @NotNull(message = "描述不能为空") + private String description; + + @ApiModelProperty(value = "成员编号数组", required = true, example = "1,2,3") + @NotNull(message = "成员编号数组不能为空") + private Set memberUserIds; + + @ApiModelProperty(value = "状态", required = true, example = "1") + @NotNull(message = "状态不能为空") + private Integer status; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupCreateReqVO.java new file mode 100644 index 000000000..48b44d38b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupCreateReqVO.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; + +import lombok.*; +import io.swagger.annotations.*; + +@ApiModel("管理后台 - 用户组创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmUserGroupCreateReqVO extends BpmUserGroupBaseVO { + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java new file mode 100644 index 000000000..2bbe95192 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupPageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +@ApiModel("管理后台 - 用户组分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmUserGroupPageReqVO extends PageParam { + + @ApiModelProperty(value = "组名", example = "芋道") + private String name; + + @ApiModelProperty(value = "状态", example = "1") + private Integer status; + + @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "创建时间") + private Date[] createTime; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupRespVO.java new file mode 100644 index 000000000..55018d502 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; + +@ApiModel("管理后台 - 用户组 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmUserGroupRespVO extends BpmUserGroupBaseVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSimpleRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSimpleRespVO.java new file mode 100644 index 000000000..0b47f447e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupSimpleRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@ApiModel("管理后台 - 用户组精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BpmUserGroupSimpleRespVO { + + @ApiModelProperty(value = "用户组编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "用户组名字", required = true, example = "芋道") + private String name; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupUpdateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupUpdateReqVO.java new file mode 100644 index 000000000..14aa25c5b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/group/BpmUserGroupUpdateReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group; + +import lombok.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; + +@ApiModel("管理后台 - 用户组更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmUserGroupUpdateReqVO extends BpmUserGroupBaseVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java new file mode 100644 index 000000000..7240ba15c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.NotNull; + +@ApiModel(value = "管理后台 - 流程模型的导入 Request VO", description = "相比流程模型的新建来说,只是多了一个 bpmnFile 文件") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmModeImportReqVO extends BpmModelCreateReqVO { + + @ApiModelProperty(value = "BPMN 文件", required = true) + @NotNull(message = "BPMN 文件不能为空") + private MultipartFile bpmnFile; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelBaseVO.java new file mode 100644 index 000000000..542a177e4 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelBaseVO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +/** +* 流程模型 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class BpmModelBaseVO { + + @ApiModelProperty(value = "流程标识", required = true, example = "process_yudao") + @NotEmpty(message = "流程标识不能为空") + private String key; + + @ApiModelProperty(value = "流程名称", required = true, example = "芋道") + @NotEmpty(message = "流程名称不能为空") + private String name; + + @ApiModelProperty(value = "流程描述", example = "我是描述") + private String description; + + @ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1") + @NotEmpty(message = "流程分类不能为空") + private String category; + + @ApiModelProperty(value = "表单类型", notes = "参见 bpm_model_form_type 数据字典", example = "1") + private Integer formType; + @ApiModelProperty(value = "表单编号", example = "1024", notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private Long formId; + @ApiModelProperty(value = "自定义表单的提交路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/create", + notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private String formCustomCreatePath; + @ApiModelProperty(value = "自定义表单的查看路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/view", + notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private String formCustomViewPath; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelCreateReqVO.java new file mode 100644 index 000000000..c85ef3ae4 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelCreateReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotEmpty; + +@ApiModel("管理后台 - 流程模型的创建 Request VO") +@Data +public class BpmModelCreateReqVO { + + @ApiModelProperty(value = "流程标识", required = true, example = "process_yudao") + @NotEmpty(message = "流程标识不能为空") + private String key; + + @ApiModelProperty(value = "流程名称", required = true, example = "芋道") + @NotEmpty(message = "流程名称不能为空") + private String name; + + @ApiModelProperty(value = "流程描述", example = "我是描述") + private String description; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageItemRespVO.java new file mode 100644 index 000000000..7442b5ab0 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageItemRespVO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; + +@ApiModel("管理后台 - 流程模型的分页的每一项 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmModelPageItemRespVO extends BpmModelBaseVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + private String id; + + @ApiModelProperty(value = "表单名字", example = "请假表单") + private String formName; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + + /** + * 最新部署的流程定义 + */ + private ProcessDefinition processDefinition; + + @ApiModel("流程定义") + @Data + public static class ProcessDefinition { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + private String id; + + @ApiModelProperty(value = "版本", required = true, example = "1") + private Integer version; + + @ApiModelProperty(value = "部署时间", required = true) + private Date deploymentTime; + + @ApiModelProperty(value = "中断状态", required = true, example = "1", notes = "参见 SuspensionState 枚举") + private Integer suspensionState; + + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java new file mode 100644 index 000000000..945da139c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelPageReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + + +@ApiModel("管理后台 - 流程模型分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmModelPageReqVO extends PageParam { + + @ApiModelProperty(value = "标识", example = "process1641042089407", notes = "精准匹配") + private String key; + + @ApiModelProperty(value = "名字", example = "芋道", notes = "模糊匹配") + private String name; + + @ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1") + private String category; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java new file mode 100644 index 000000000..bce0f9100 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; + +@ApiModel("管理后台 - 流程模型的创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmModelRespVO extends BpmModelBaseVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + private String id; + + @ApiModelProperty(value = "BPMN XML", required = true) + private String bpmnXml; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java new file mode 100644 index 000000000..972aa31bb --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@ApiModel("管理后台 - 流程模型的更新 Request VO") +@Data +public class BpmModelUpdateReqVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + @NotEmpty(message = "编号不能为空") + private String id; + + @ApiModelProperty(value = "流程名称", example = "芋道") + private String name; + + @ApiModelProperty(value = "流程描述", example = "我是描述") + private String description; + + @ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1") + private String category; + + @ApiModelProperty(value = "BPMN XML", required = true) + private String bpmnXml; + + @ApiModelProperty(value = "表单类型", notes = "参见 bpm_model_form_type 数据字典", example = "1") + private Integer formType; + @ApiModelProperty(value = "表单编号", example = "1024", notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private Long formId; + @ApiModelProperty(value = "自定义表单的提交路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/create", + notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private String formCustomCreatePath; + @ApiModelProperty(value = "自定义表单的查看路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/view", + notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private String formCustomViewPath; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateStateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateStateReqVO.java new file mode 100644 index 000000000..9cfcebbdc --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateStateReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@ApiModel("管理后台 - 流程模型更新状态 Request VO") +@Data +public class BpmModelUpdateStateReqVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + @NotNull(message = "编号不能为空") + private String id; + + @ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 SuspensionState 枚举") + @NotNull(message = "状态不能为空") + private Integer state; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionListReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionListReqVO.java new file mode 100644 index 000000000..5e45b8bde --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionListReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ApiModel("管理后台 - 流程定义列表 Request VO") +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class BpmProcessDefinitionListReqVO extends PageParam { + + @ApiModelProperty(value = "中断状态", example = "1", notes = "参见 SuspensionState 枚举") + private Integer suspensionState; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageItemRespVO.java new file mode 100644 index 000000000..75990f08a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageItemRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; + +@ApiModel("管理后台 - 流程定义的分页的每一项 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmProcessDefinitionPageItemRespVO extends BpmProcessDefinitionRespVO { + + @ApiModelProperty(value = "表单名字", example = "请假表单") + private String formName; + + @ApiModelProperty(value = "部署时间", required = true) + private Date deploymentTime; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageReqVO.java new file mode 100644 index 000000000..a9657e9a2 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionPageReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ApiModel("管理后台 - 流程定义分页 Request VO") +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class BpmProcessDefinitionPageReqVO extends PageParam { + + @ApiModelProperty(value = "标识", example = "process1641042089407", notes = "精准匹配") + private String key; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java new file mode 100644 index 000000000..6f8fd4e5b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@ApiModel("管理后台 - 流程定义 Response VO") +@Data +public class BpmProcessDefinitionRespVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + private String id; + + @ApiModelProperty(value = "版本", required = true, example = "1") + private Integer version; + + @ApiModelProperty(value = "流程名称", required = true, example = "芋道") + @NotEmpty(message = "流程名称不能为空") + private String name; + + @ApiModelProperty(value = "流程描述", example = "我是描述") + private String description; + + @ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1") + @NotEmpty(message = "流程分类不能为空") + private String category; + + @ApiModelProperty(value = "表单类型", notes = "参见 bpm_model_form_type 数据字典", example = "1") + private Integer formType; + @ApiModelProperty(value = "表单编号", example = "1024", notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private Long formId; + @ApiModelProperty(value = "表单的配置", required = true, + notes = "JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private String formConf; + @ApiModelProperty(value = "表单项的数组", required = true, + notes = "JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private List formFields; + @ApiModelProperty(value = "自定义表单的提交路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/create", + notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private String formCustomCreatePath; + @ApiModelProperty(value = "自定义表单的查看路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/view", + notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private String formCustomViewPath; + + @ApiModelProperty(value = "中断状态", required = true, example = "1", notes = "参见 SuspensionState 枚举") + private Integer suspensionState; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleBaseVO.java new file mode 100644 index 000000000..bcb9fc0f0 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleBaseVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Set; + +/** + * 流程任务分配规则 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class BpmTaskAssignRuleBaseVO { + + @ApiModelProperty(value = "规则类型", required = true, example = "bpm_task_assign_rule_type") + @NotNull(message = "规则类型不能为空") + private Integer type; + + @ApiModelProperty(value = "规则值数组", required = true, example = "1,2,3") + @NotNull(message = "规则值数组不能为空") + private Set options; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleCreateReqVO.java new file mode 100644 index 000000000..cbbc108c0 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleCreateReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotEmpty; + +@ApiModel("管理后台 - 流程任务分配规则的创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmTaskAssignRuleCreateReqVO extends BpmTaskAssignRuleBaseVO { + + @ApiModelProperty(value = "流程模型的编号", required = true, example = "1024") + @NotEmpty(message = "流程模型的编号不能为空") + private String modelId; + + @ApiModelProperty(value = "流程任务定义的编号", required = true, example = "2048") + @NotEmpty(message = "流程任务定义的编号不能为空") + private String taskDefinitionKey; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleRespVO.java new file mode 100644 index 000000000..c0786e52b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleRespVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ApiModel("管理后台 - 流程任务分配规则的 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmTaskAssignRuleRespVO extends BpmTaskAssignRuleBaseVO { + + @ApiModelProperty(value = "任务分配规则的编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "流程模型的编号", required = true, example = "2048") + private String modelId; + + @ApiModelProperty(value = "流程定义的编号", required = true, example = "4096") + private String processDefinitionId; + + @ApiModelProperty(value = "流程任务定义的编号", required = true, example = "2048") + private String taskDefinitionKey; + @ApiModelProperty(value = "流程任务定义的名字", required = true, example = "关注芋道") + private String taskDefinitionName; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleUpdateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleUpdateReqVO.java new file mode 100644 index 000000000..8f1c12701 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/rule/BpmTaskAssignRuleUpdateReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@ApiModel("管理后台 - 流程任务分配规则的更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmTaskAssignRuleUpdateReqVO extends BpmTaskAssignRuleBaseVO { + + @ApiModelProperty(value = "任务分配规则的编号", required = true, example = "1024") + @NotNull(message = "任务分配规则的编号不能为空") + private Long id; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.http b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.http new file mode 100644 index 000000000..96bbf964d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.http @@ -0,0 +1,12 @@ +### 请求 /bpm/oa/leave/create 接口 => 成功 +POST {{baseUrl}}/bpm/oa/leave/create +Content-Type: application/json +tenant-id: 1 +Authorization: Bearer {{token}} + +{ + "startTime": "2022-03-01", + "endTime": "2022-03-05", + "type": 1, + "reason": "我要请假啦啦啦!" +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.java new file mode 100644 index 000000000..dd66580d3 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOALeaveController.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa; + +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveRespVO; +import cn.iocoder.yudao.module.bpm.convert.oa.BpmOALeaveConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +/** + * OA 请假申请 Controller,用于演示自己存储数据,接入工作流的例子 + * + * @author jason + * @author 芋道源码 + */ +@Api(tags = "管理后台 - OA 请假申请") +@RestController +@RequestMapping("/bpm/oa/leave") +@Validated +public class BpmOALeaveController { + + @Resource + private BpmOALeaveService leaveService; + + @PostMapping("/create") + @PreAuthorize("@ss.hasPermission('bpm:oa-leave:create')") + @ApiOperation("创建请求申请") + public CommonResult createLeave(@Valid @RequestBody BpmOALeaveCreateReqVO createReqVO) { + return success(leaveService.createLeave(getLoginUserId(), createReqVO)); + } + + @GetMapping("/get") + @PreAuthorize("@ss.hasPermission('bpm:oa-leave:query')") + @ApiOperation("获得请假申请") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + public CommonResult getLeave(@RequestParam("id") Long id) { + BpmOALeaveDO leave = leaveService.getLeave(id); + return success(BpmOALeaveConvert.INSTANCE.convert(leave)); + } + + @GetMapping("/page") + @PreAuthorize("@ss.hasPermission('bpm:oa-leave:query')") + @ApiOperation("获得请假申请分页") + public CommonResult> getLeavePage(@Valid BpmOALeavePageReqVO pageVO) { + PageResult pageResult = leaveService.getLeavePage(getLoginUserId(), pageVO); + return success(BpmOALeaveConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/package-info.java new file mode 100644 index 000000000..7028708b1 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/package-info.java @@ -0,0 +1,5 @@ +/** + * OA 示例,用于演示外部业务接入 BPM 工作流的示例 + * 一般的接入方式,只需要调用 接口,后续 Admin 用户在管理后台的【待办事务】进行审批 + */ +package cn.iocoder.yudao.module.bpm.controller.admin.oa; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveBaseVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveBaseVO.java new file mode 100644 index 000000000..cbc568a11 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveBaseVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; +import org.springframework.format.annotation.DateTimeFormat; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** +* 请假申请 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class BpmOALeaveBaseVO { + + @ApiModelProperty(value = "请假的开始时间", required = true) + @NotNull(message = "开始时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date startTime; + @ApiModelProperty(value = "请假的结束时间", required = true) + @NotNull(message = "结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date endTime; + + @ApiModelProperty(value = "请假类型", required = true, example = "1", notes = "参见 bpm_oa_type 枚举") + private Integer type; + + @ApiModelProperty(value = "原因", required = true, example = "阅读芋道源码") + private String reason; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java new file mode 100644 index 000000000..2ebab63e9 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveCreateReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.AssertTrue; + +@ApiModel("管理后台 - 请假申请创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmOALeaveCreateReqVO extends BpmOALeaveBaseVO { + + @AssertTrue(message = "结束时间,需要在开始时间之后") + public boolean isEndTimeValid() { + return !getEndTime().before(getStartTime()); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java new file mode 100644 index 000000000..2e49efaa1 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeavePageReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("管理后台 - 请假申请分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmOALeavePageReqVO extends PageParam { + + @ApiModelProperty(value = "状态", example = "1", notes = "参见 bpm_process_instance_result 枚举") + private Integer result; + + @ApiModelProperty(value = "请假类型", example = "1", notes = "参见 bpm_oa_type") + private Integer type; + + @ApiModelProperty(value = "原因", example = "阅读芋道源码", notes = "模糊匹配") + private String reason; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "申请时间") + private Date[] createTime; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveRespVO.java new file mode 100644 index 000000000..908c48e06 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/BpmOALeaveRespVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo; + +import lombok.*; +import io.swagger.annotations.*; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("管理后台 - 请假申请 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmOALeaveRespVO extends BpmOALeaveBaseVO { + + @ApiModelProperty(value = "请假表单主键", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 bpm_process_instance_result 枚举") + private Integer result; + + @ApiModelProperty(value = "申请时间", required = true) + @NotNull(message = "申请时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date createTime; + + @ApiModelProperty(value = "流程id") + private String processInstanceId; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmActivityController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmActivityController.java new file mode 100644 index 000000000..24d89cd36 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmActivityController.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO; +import cn.iocoder.yudao.module.bpm.service.task.BpmActivityService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - 流程活动实例") +@RestController +@RequestMapping("/bpm/activity") +@Validated +public class BpmActivityController { + + @Resource + private BpmActivityService activityService; + + @GetMapping("/list") + @ApiOperation(value = "生成指定流程实例的高亮流程图", + notes = "只高亮进行中的任务。不过要注意,该接口暂时没用,通过前端的 ProcessViewer.vue 界面的 highlightDiagram 方法生成") + @ApiImplicitParam(name = "processInstanceId", value = "流程实例的编号", required = true, dataTypeClass = String.class) + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getActivityList( + @RequestParam("processInstanceId") String processInstanceId) { + return success(activityService.getActivityListByProcessInstanceId(processInstanceId)); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java new file mode 100644 index 000000000..31abf7de1 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Api(tags = "管理后台 - 流程实例") // 流程实例,通过流程定义创建的一次“申请” +@RestController +@RequestMapping("/bpm/process-instance") +@Validated +public class BpmProcessInstanceController { + + @Resource + private BpmProcessInstanceService processInstanceService; + + @GetMapping("/my-page") + @ApiOperation(value = "获得我的实例分页列表", notes = "在【我的流程】菜单中,进行调用") + @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") + public CommonResult> getMyProcessInstancePage( + @Valid BpmProcessInstanceMyPageReqVO pageReqVO) { + return success(processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO)); + } + + @PostMapping("/create") + @ApiOperation("新建流程实例") + @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") + public CommonResult createProcessInstance(@Valid @RequestBody BpmProcessInstanceCreateReqVO createReqVO) { + return success(processInstanceService.createProcessInstance(getLoginUserId(), createReqVO)); + } + + @GetMapping("/get") + @ApiOperation(value = "获得指定流程实例", notes = "在【流程详细】界面中,进行调用") + @ApiImplicitParam(name = "id", value = "流程实例的编号", required = true, dataTypeClass = String.class) + @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") + public CommonResult getProcessInstance(@RequestParam("id") String id) { + return success(processInstanceService.getProcessInstanceVO(id)); + } + + @DeleteMapping("/cancel") + @ApiOperation(value = "取消流程实例", notes = "撤回发起的流程") + @PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel')") + public CommonResult cancelProcessInstance(@Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) { + processInstanceService.cancelProcessInstance(getLoginUserId(), cancelReqVO); + return success(true); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java new file mode 100644 index 000000000..eaa991f55 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; + +@Api(tags = "管理后台 - 流程任务实例") +@RestController +@RequestMapping("/bpm/task") +@Validated +public class BpmTaskController { + + @Resource + private BpmTaskService taskService; + + @GetMapping("todo-page") + @ApiOperation("获取 Todo 待办任务分页") + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getTodoTaskPage(@Valid BpmTaskTodoPageReqVO pageVO) { + return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO)); + } + + @GetMapping("done-page") + @ApiOperation("获取 Done 已办任务分页") + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getDoneTaskPage(@Valid BpmTaskDonePageReqVO pageVO) { + return success(taskService.getDoneTaskPage(getLoginUserId(), pageVO)); + } + + @GetMapping("/list-by-process-instance-id") + @ApiOperation(value = "获得指定流程实例的任务列表", notes = "包括完成的、未完成的") + @ApiImplicitParam(name = "processInstanceId", value = "流程实例的编号", required = true, dataTypeClass = String.class) + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getTaskListByProcessInstanceId( + @RequestParam("processInstanceId") String processInstanceId) { + return success(taskService.getTaskListByProcessInstanceId(processInstanceId)); + } + + @PutMapping("/approve") + @ApiOperation("通过任务") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult approveTask(@Valid @RequestBody BpmTaskApproveReqVO reqVO) { + taskService.approveTask(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/reject") + @ApiOperation("不通过任务") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult rejectTask(@Valid @RequestBody BpmTaskRejectReqVO reqVO) { + taskService.rejectTask(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/update-assignee") + @ApiOperation(value = "更新任务的负责人", notes = "用于【流程详情】的【转派】按钮") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult updateTaskAssignee(@Valid @RequestBody BpmTaskUpdateAssigneeReqVO reqVO) { + taskService.updateTaskAssignee(getLoginUserId(), reqVO); + return success(true); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/activity/BpmActivityRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/activity/BpmActivityRespVO.java new file mode 100644 index 000000000..ef9d11ac1 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/activity/BpmActivityRespVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +@ApiModel("管理后台 - 流程活动的 Response VO") +@Data +public class BpmActivityRespVO { + + @ApiModelProperty(value = "流程活动的标识", required = true, example = "1024") + private String key; + @ApiModelProperty(value = "流程活动的类型", required = true, example = "StartEvent") + private String type; + + @ApiModelProperty(value = "流程活动的开始时间", required = true) + private Date startTime; + @ApiModelProperty(value = "流程活动的结束时间", required = true) + private Date endTime; + + @ApiModelProperty(value = "关联的流程任务的编号", example = "2048", notes = "关联的流程任务,只有 UserTask 等类型才有") + private String taskId; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCancelReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCancelReqVO.java new file mode 100644 index 000000000..928f187e7 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCancelReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Map; + +@ApiModel("管理后台 - 流程实例的取消 Request VO") +@Data +public class BpmProcessInstanceCancelReqVO { + + @ApiModelProperty(value = "流程实例的编号", required = true, example = "1024") + @NotEmpty(message = "流程实例的编号不能为空") + private String id; + + @ApiModelProperty(value = "取消原因", required = true, example = "不请假了!") + @NotEmpty(message = "取消原因不能为空") + private String reason; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java new file mode 100644 index 000000000..2085253d3 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCreateReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.util.Map; + +@ApiModel("管理后台 - 流程实例的创建 Request VO") +@Data +public class BpmProcessInstanceCreateReqVO { + + @ApiModelProperty(value = "流程定义的编号", required = true, example = "1024") + @NotEmpty(message = "流程定义编号不能为空") + private String processDefinitionId; + + @ApiModelProperty(value = "变量实例") + private Map variables; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceMyPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceMyPageReqVO.java new file mode 100644 index 000000000..db297e268 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceMyPageReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("管理后台 - 流程实例的分页 Item Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmProcessInstanceMyPageReqVO extends PageParam { + + @ApiModelProperty(value = "流程名称", example = "芋道") + private String name; + + @ApiModelProperty(value = "流程定义的编号", example = "2048") + private String processDefinitionId; + + @ApiModelProperty(value = "流程实例的状态", notes = "参见 bpm_process_instance_status", example = "1") + private Integer status; + + @ApiModelProperty(value = "流程实例的结果", notes = "参见 bpm_process_instance_result", example = "2") + private Integer result; + + @ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1") + private String category; + + @ApiModelProperty(value = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date[] createTime; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java new file mode 100644 index 000000000..5b5d5797a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageItemRespVO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +@ApiModel("管理后台 - 流程实例的分页 Item Response VO") +@Data +public class BpmProcessInstancePageItemRespVO { + + @ApiModelProperty(value = "流程实例的编号", required = true, example = "1024") + private String id; + + @ApiModelProperty(value = "流程名称", required = true, example = "芋道") + private String name; + + @ApiModelProperty(value = "流程定义的编号", required = true, example = "2048") + private String processDefinitionId; + + @ApiModelProperty(value = "流程分类", required = true, notes = "参见 bpm_model_category 数据字典", example = "1") + private String category; + + @ApiModelProperty(value = "流程实例的状态", required = true, notes = "参见 bpm_process_instance_status", example = "1") + private Integer status; + + @ApiModelProperty(value = "流程实例的结果", required = true, notes = "参见 bpm_process_instance_result", example = "2") + private Integer result; + + @ApiModelProperty(value = "提交时间", required = true) + private Date createTime; + + @ApiModelProperty(value = "结束时间", required = true) + private Date endTime; + + /** + * 当前任务 + */ + private List tasks; + + @ApiModel("流程任务") + @Data + public static class Task { + + @ApiModelProperty(value = "流程任务的编号", required = true, example = "1024") + private String id; + + @ApiModelProperty(value = "任务名称", required = true, example = "芋道") + private String name; + + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java new file mode 100644 index 000000000..a1547b175 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +@ApiModel("管理后台 - 流程实例的 Response VO") +@Data +public class BpmProcessInstanceRespVO { + + @ApiModelProperty(value = "流程实例的编号", required = true, example = "1024") + private String id; + + @ApiModelProperty(value = "流程名称", required = true, example = "芋道") + private String name; + + @ApiModelProperty(value = "流程分类", required = true, notes = "参见 bpm_model_category 数据字典", example = "1") + private String category; + + @ApiModelProperty(value = "流程实例的状态", required = true, notes = "参见 bpm_process_instance_status", example = "1") + private Integer status; + + @ApiModelProperty(value = "流程实例的结果", required = true, notes = "参见 bpm_process_instance_result", example = "2") + private Integer result; + + @ApiModelProperty(value = "提交时间", required = true) + private Date createTime; + + @ApiModelProperty(value = "结束时间", required = true) + private Date endTime; + + @ApiModelProperty(value = "提交的表单值", required = true) + private Map formVariables; + + @ApiModelProperty(value = "业务的唯一标识", example = "1", notes = "例如说,请假申请的编号") + private String businessKey; + + /** + * 发起流程的用户 + */ + private User startUser; + + /** + * 流程定义 + */ + private ProcessDefinition processDefinition; + + @ApiModel("用户信息") + @Data + public static class User { + + @ApiModelProperty(value = "用户编号", required = true, example = "1") + private Long id; + @ApiModelProperty(value = "用户昵称", required = true, example = "芋艿") + private String nickname; + + @ApiModelProperty(value = "部门编号", required = true, example = "1") + private Long deptId; + @ApiModelProperty(value = "部门名称", required = true, example = "研发部") + private String deptName; + + } + + @ApiModel("流程定义信息") + @Data + public static class ProcessDefinition { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + private String id; + + @ApiModelProperty(value = "表单类型", notes = "参见 bpm_model_form_type 数据字典", example = "1") + private Integer formType; + @ApiModelProperty(value = "表单编号", example = "1024", notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private Long formId; + @ApiModelProperty(value = "表单的配置", required = true, + notes = "JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private String formConf; + @ApiModelProperty(value = "表单项的数组", required = true, + notes = "JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private List formFields; + @ApiModelProperty(value = "自定义表单的提交路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/create", + notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private String formCustomCreatePath; + @ApiModelProperty(value = "自定义表单的查看路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/view", + notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空") + private String formCustomViewPath; + + @ApiModelProperty(value = "BPMN XML", required = true) + private String bpmnXml; + + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java new file mode 100644 index 000000000..1b6a69066 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@ApiModel("管理后台 - 通过流程任务的 Request VO") +@Data +public class BpmTaskApproveReqVO { + + @ApiModelProperty(value = "任务编号", required = true, example = "1024") + @NotEmpty(message = "任务编号不能为空") + private String id; + + @ApiModelProperty(value = "审批意见", required = true, example = "不错不错!") + @NotEmpty(message = "审批意见不能为空") + private String reason; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageItemRespVO.java new file mode 100644 index 000000000..c5e2c23ae --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageItemRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; + +@ApiModel("管理后台 - 流程任务的 Done 已完成的分页项 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmTaskDonePageItemRespVO extends BpmTaskTodoPageItemRespVO { + + @ApiModelProperty(value = "结束时间", required = true) + private Date endTime; + @ApiModelProperty(value = "持续时间", required = true, example = "1000") + private Long durationInMillis; + + @ApiModelProperty(value = "任务结果", required = true, notes = "参见 bpm_process_instance_result", example = "2") + private Integer result; + @ApiModelProperty(value = "审批建议", required = true, example = "不请假了!") + private String reason; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageReqVO.java new file mode 100644 index 000000000..99145b434 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskDonePageReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("管理后台 - 流程任务的 Done 已办的分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmTaskDonePageReqVO extends PageParam { + + @ApiModelProperty(value = "流程任务名", example = "芋道") + private String name; + + @ApiModelProperty(value = "开始的创建收间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date beginCreateTime; + + @ApiModelProperty(value = "结束的创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date endCreateTime; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java new file mode 100644 index 000000000..596a82f77 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@ApiModel("管理后台 - 不通过流程任务的 Request VO") +@Data +public class BpmTaskRejectReqVO { + + @ApiModelProperty(value = "任务编号", required = true, example = "1024") + @NotEmpty(message = "任务编号不能为空") + private String id; + + @ApiModelProperty(value = "审批意见", required = true, example = "不错不错!") + @NotEmpty(message = "审批意见不能为空") + private String reason; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java new file mode 100644 index 000000000..1f7d2c7fa --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ApiModel("管理后台 - 流程任务的 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmTaskRespVO extends BpmTaskDonePageItemRespVO { + + @ApiModelProperty(value = "任务定义的标识", required = true, example = "user-001") + private String definitionKey; + + /** + * 审核的用户信息 + */ + private User assigneeUser; + + @ApiModel("用户信息") + @Data + public static class User { + + @ApiModelProperty(value = "用户编号", required = true, example = "1") + private Long id; + @ApiModelProperty(value = "用户昵称", required = true, example = "芋艿") + private String nickname; + + @ApiModelProperty(value = "部门编号", required = true, example = "1") + private Long deptId; + @ApiModelProperty(value = "部门名称", required = true, example = "研发部") + private String deptName; + + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageItemRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageItemRespVO.java new file mode 100644 index 000000000..e25e3aa49 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageItemRespVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +@ApiModel("管理后台 - 流程任务的 Running 进行中的分页项 Response VO") +@Data +public class BpmTaskTodoPageItemRespVO { + + @ApiModelProperty(value = "任务编号", required = true, example = "1024") + private String id; + + @ApiModelProperty(value = "任务名字", required = true, example = "芋道") + private String name; + + @ApiModelProperty(value = "接收时间", required = true) + private Date claimTime; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + + @ApiModelProperty(value = "激活状态", required = true, example = "1", notes = "参见 SuspensionState 枚举") + private Integer suspensionState; + + /** + * 所属流程实例 + */ + private ProcessInstance processInstance; + + @Data + @ApiModel("流程实例") + public static class ProcessInstance { + + @ApiModelProperty(value = "流程实例编号", required = true, example = "1024") + private String id; + + @ApiModelProperty(value = "流程实例名称", required = true, example = "芋道") + private String name; + + @ApiModelProperty(value = "发起人的用户编号", required = true, example = "1024") + private Long startUserId; + + @ApiModelProperty(value = "发起人的用户昵称", required = true, example = "芋艿") + private String startUserNickname; + + @ApiModelProperty(value = "流程定义的编号", required = true, example = "2048") + private String processDefinitionId; + + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageReqVO.java new file mode 100644 index 000000000..9f248e198 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("管理后台 - 流程任务的 TODO 待办的分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmTaskTodoPageReqVO extends PageParam { + + @ApiModelProperty(value = "流程任务名", example = "芋道") + private String name; + + @ApiModelProperty(value = "开始的创建收间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date beginCreateTime; + + @ApiModelProperty(value = "结束的创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date endCreateTime; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskUpdateAssigneeReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskUpdateAssigneeReqVO.java new file mode 100644 index 000000000..0dd0ffed4 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskUpdateAssigneeReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import net.bytebuddy.implementation.bind.annotation.Empty; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@ApiModel("管理后台 - 流程任务的更新负责人的 Request VO") +@Data +public class BpmTaskUpdateAssigneeReqVO { + + @ApiModelProperty(value = "任务编号", required = true, example = "1024") + @NotEmpty(message = "任务编号不能为空") + private String id; + + @ApiModelProperty(value = "新审批人的用户编号", required = true, example = "2048") + @NotNull(message = "新审批人的用户编号不能为空") + private Long assigneeUserId; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/app/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/app/package-info.java new file mode 100644 index 000000000..e8d285e35 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/app/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.bpm.controller.app; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/package-info.java new file mode 100644 index 000000000..d1930bd6a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.bpm.controller; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmFormConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmFormConvert.java new file mode 100644 index 000000000..6ba757417 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmFormConvert.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.bpm.convert.definition; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormSimpleRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 动态表单 Convert + * + * @author 芋艿 + */ +@Mapper +public interface BpmFormConvert { + + BpmFormConvert INSTANCE = Mappers.getMapper(BpmFormConvert.class); + + BpmFormDO convert(BpmFormCreateReqVO bean); + + BpmFormDO convert(BpmFormUpdateReqVO bean); + + BpmFormRespVO convert(BpmFormDO bean); + + List convertList2(List list); + + PageResult convertPage(PageResult page); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmModelConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmModelConvert.java new file mode 100644 index 000000000..4d1b2a003 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmModelConvert.java @@ -0,0 +1,140 @@ +package cn.iocoder.yudao.module.bpm.convert.definition; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; +import org.flowable.common.engine.impl.db.SuspensionState; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.Model; +import org.flowable.engine.repository.ProcessDefinition; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 流程模型 Convert + * + * @author yunlongn + */ +@Mapper +public interface BpmModelConvert { + + BpmModelConvert INSTANCE = Mappers.getMapper(BpmModelConvert.class); + + default List convertList(List list, Map formMap, + Map deploymentMap, + Map processDefinitionMap) { + return CollectionUtils.convertList(list, model -> { + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + BpmFormDO form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null; + Deployment deployment = model.getDeploymentId() != null ? deploymentMap.get(model.getDeploymentId()) : null; + ProcessDefinition processDefinition = model.getDeploymentId() != null ? processDefinitionMap.get(model.getDeploymentId()) : null; + return convert(model, form, deployment, processDefinition); + }); + } + + default BpmModelPageItemRespVO convert(Model model, BpmFormDO form, Deployment deployment, ProcessDefinition processDefinition) { + BpmModelPageItemRespVO modelRespVO = new BpmModelPageItemRespVO(); + modelRespVO.setId(model.getId()); + modelRespVO.setCreateTime(model.getCreateTime()); + // 通用 copy + copyTo(model, modelRespVO); + // Form + if (form != null) { + modelRespVO.setFormId(form.getId()); + modelRespVO.setFormName(form.getName()); + } + // ProcessDefinition + modelRespVO.setProcessDefinition(this.convert(processDefinition)); + if (modelRespVO.getProcessDefinition() != null) { + modelRespVO.getProcessDefinition().setSuspensionState(processDefinition.isSuspended() ? + SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode()); + modelRespVO.getProcessDefinition().setDeploymentTime(deployment.getDeploymentTime()); + } + return modelRespVO; + } + + default BpmModelRespVO convert(Model model) { + BpmModelRespVO modelRespVO = new BpmModelRespVO(); + modelRespVO.setId(model.getId()); + modelRespVO.setCreateTime(model.getCreateTime()); + // 通用 copy + copyTo(model, modelRespVO); + return modelRespVO; + } + + default void copyTo(Model model, BpmModelBaseVO to) { + to.setName(model.getName()); + to.setKey(model.getKey()); + to.setCategory(model.getCategory()); + // metaInfo + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + copyTo(metaInfo, to); + } + + BpmModelCreateReqVO convert(BpmModeImportReqVO bean); + + default BpmProcessDefinitionCreateReqDTO convert2(Model model, BpmFormDO form) { + BpmProcessDefinitionCreateReqDTO createReqDTO = new BpmProcessDefinitionCreateReqDTO(); + createReqDTO.setModelId(model.getId()); + createReqDTO.setName(model.getName()); + createReqDTO.setKey(model.getKey()); + createReqDTO.setCategory(model.getCategory()); + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + // metaInfo + copyTo(metaInfo, createReqDTO); + // form + if (form != null) { + createReqDTO.setFormConf(form.getConf()); + createReqDTO.setFormFields(form.getFields()); + } + return createReqDTO; + } + + void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmProcessDefinitionCreateReqDTO to); + + void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmModelBaseVO to); + + BpmModelPageItemRespVO.ProcessDefinition convert(ProcessDefinition bean); + + default void copy(Model model, BpmModelCreateReqVO bean) { + model.setName(bean.getName()); + model.setKey(bean.getKey()); + model.setMetaInfo(buildMetaInfoStr(null, bean.getDescription(), null, null, + null, null)); + } + + default void copy(Model model, BpmModelUpdateReqVO bean) { + model.setName(bean.getName()); + model.setCategory(bean.getCategory()); + model.setMetaInfo(buildMetaInfoStr(JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class), + bean.getDescription(), bean.getFormType(), bean.getFormId(), + bean.getFormCustomCreatePath(), bean.getFormCustomViewPath())); + } + + default String buildMetaInfoStr(BpmModelMetaInfoRespDTO metaInfo, String description, Integer formType, + Long formId, String formCustomCreatePath, String formCustomViewPath) { + if (metaInfo == null) { + metaInfo = new BpmModelMetaInfoRespDTO(); + } + // 只有非空,才进行设置,避免更新时的覆盖 + if (StrUtil.isNotEmpty(description)) { + metaInfo.setDescription(description); + } + if (Objects.nonNull(formType)) { + metaInfo.setFormType(formType); + metaInfo.setFormId(formId); + metaInfo.setFormCustomCreatePath(formCustomCreatePath); + metaInfo.setFormCustomViewPath(formCustomViewPath); + } + return JsonUtils.toJsonString(metaInfo); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java new file mode 100644 index 000000000..8f5bfcd26 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmProcessDefinitionConvert.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.bpm.convert.definition; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; +import org.flowable.common.engine.impl.db.SuspensionState; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.ProcessDefinition; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +/** + * Bpm 流程定义的 Convert + * + * @author yunlong.li + */ +@Mapper +public interface BpmProcessDefinitionConvert { + + BpmProcessDefinitionConvert INSTANCE = Mappers.getMapper(BpmProcessDefinitionConvert.class); + + BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean); + + BpmProcessDefinitionExtDO convert2(BpmProcessDefinitionCreateReqDTO bean); + + default List convertList(List list, Map deploymentMap, + Map processDefinitionDOMap, Map formMap) { + return CollectionUtils.convertList(list, definition -> { + Deployment deployment = definition.getDeploymentId() != null ? deploymentMap.get(definition.getDeploymentId()) : null; + BpmProcessDefinitionExtDO definitionDO = processDefinitionDOMap.get(definition.getId()); + BpmFormDO form = definitionDO != null ? formMap.get(definitionDO.getFormId()) : null; + return convert(definition, deployment, definitionDO, form); + }); + } + + default List convertList3(List list, + Map processDefinitionDOMap) { + return CollectionUtils.convertList(list, processDefinition -> { + BpmProcessDefinitionRespVO respVO = convert3(processDefinition); + BpmProcessDefinitionExtDO processDefinitionExtDO = processDefinitionDOMap.get(processDefinition.getId()); + // 复制通用属性 + copyTo(processDefinitionExtDO, respVO); + return respVO; + }); + } + + @Mapping(source = "suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState") + BpmProcessDefinitionRespVO convert3(ProcessDefinition bean); + + @Named("convertSuspendedToSuspensionState") + default Integer convertSuspendedToSuspensionState(boolean suspended) { + return suspended ? SuspensionState.SUSPENDED.getStateCode() : + SuspensionState.ACTIVE.getStateCode(); + } + + default BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean, Deployment deployment, + BpmProcessDefinitionExtDO processDefinitionExtDO, BpmFormDO form) { + BpmProcessDefinitionPageItemRespVO respVO = convert(bean); + respVO.setSuspensionState(bean.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode()); + if (deployment != null) { + respVO.setDeploymentTime(deployment.getDeploymentTime()); + } + if (form != null) { + respVO.setFormName(form.getName()); + } + // 复制通用属性 + copyTo(processDefinitionExtDO, respVO); + return respVO; + } + + @Mapping(source = "from.id", target = "to.id", ignore = true) + void copyTo(BpmProcessDefinitionExtDO from, @MappingTarget BpmProcessDefinitionRespVO to); +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmTaskAssignRuleConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmTaskAssignRuleConvert.java new file mode 100644 index 000000000..c616e90b0 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmTaskAssignRuleConvert.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.convert.definition; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; +import org.flowable.bpmn.model.UserTask; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface BpmTaskAssignRuleConvert { + BpmTaskAssignRuleConvert INSTANCE = Mappers.getMapper(BpmTaskAssignRuleConvert.class); + + default List convertList(List tasks, List rules) { + Map ruleMap = CollectionUtils.convertMap(rules, BpmTaskAssignRuleDO::getTaskDefinitionKey); + // 以 UserTask 为主维度,原因是:流程图编辑后,一些规则实际就没用了。 + return CollectionUtils.convertList(tasks, task -> { + BpmTaskAssignRuleRespVO respVO = convert(ruleMap.get(task.getId())); + if (respVO == null) { + respVO = new BpmTaskAssignRuleRespVO(); + respVO.setTaskDefinitionKey(task.getId()); + } + respVO.setTaskDefinitionName(task.getName()); + return respVO; + }); + } + + BpmTaskAssignRuleRespVO convert(BpmTaskAssignRuleDO bean); + + BpmTaskAssignRuleDO convert(BpmTaskAssignRuleCreateReqVO bean); + + BpmTaskAssignRuleDO convert(BpmTaskAssignRuleUpdateReqVO bean); + + List convertList2(List list); +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmUserGroupConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmUserGroupConvert.java new file mode 100644 index 000000000..bbf00ba52 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/definition/BpmUserGroupConvert.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.bpm.convert.definition; + +import java.util.*; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.mapstruct.Mapper; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +/** + * 用户组 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface BpmUserGroupConvert { + + BpmUserGroupConvert INSTANCE = Mappers.getMapper(BpmUserGroupConvert.class); + + BpmUserGroupDO convert(BpmUserGroupCreateReqVO bean); + + BpmUserGroupDO convert(BpmUserGroupUpdateReqVO bean); + + BpmUserGroupRespVO convert(BpmUserGroupDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + @Named("convertList2") + List convertList2(List list); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java new file mode 100644 index 000000000..92683f4c9 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.bpm.convert.message; + +import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.Map; + +@Mapper +public interface BpmMessageConvert { + + BpmMessageConvert INSTANCE = Mappers.getMapper(BpmMessageConvert.class); + + SmsSendSingleToUserReqDTO convert(Long userId, String templateCode, Map templateParams); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOALeaveConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOALeaveConvert.java new file mode 100644 index 000000000..f87531bfc --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOALeaveConvert.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.bpm.convert.oa; + +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 请假申请 Convert + * + * @author 芋艿 + */ +@Mapper +public interface BpmOALeaveConvert { + + BpmOALeaveConvert INSTANCE = Mappers.getMapper(BpmOALeaveConvert.class); + + BpmOALeaveDO convert(BpmOALeaveCreateReqVO bean); + + BpmOALeaveRespVO convert(BpmOALeaveDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/package-info.java new file mode 100644 index 000000000..6db6ebc46 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 POJO 类的实体转换 + * + * 目前使用 MapStruct 框架 + */ +package cn.iocoder.yudao.module.bpm.convert; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmActivityConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmActivityConvert.java new file mode 100644 index 000000000..509408457 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmActivityConvert.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.bpm.convert.task; + +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO; +import org.flowable.engine.history.HistoricActivityInstance; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * BPM 活动 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface BpmActivityConvert { + + BpmActivityConvert INSTANCE = Mappers.getMapper(BpmActivityConvert.class); + + List convertList(List list); + + @Mappings({ + @Mapping(source = "activityId", target = "key"), + @Mapping(source = "activityType", target = "type") + }) + BpmActivityRespVO convert(HistoricActivityInstance bean); +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java new file mode 100644 index 000000000..a1eea62e9 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.bpm.convert.task; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; +import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +/** + * 流程实例 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface BpmProcessInstanceConvert { + + BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class); + + default PageResult convertPage(PageResult page, + Map> taskMap) { + List list = convertList(page.getList()); + list.forEach(respVO -> respVO.setTasks(convertList2(taskMap.get(respVO.getId())))); + return new PageResult<>(list, page.getTotal()); + } + + List convertList(List list); + + @Mapping(source = "processInstanceId", target = "id") + BpmProcessInstancePageItemRespVO convert(BpmProcessInstanceExtDO bean); + + List convertList2(List tasks); + + default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, BpmProcessInstanceExtDO processInstanceExt, + ProcessDefinition processDefinition, BpmProcessDefinitionExtDO processDefinitionExt, + String bpmnXml, AdminUserRespDTO startUser, DeptRespDTO dept) { + BpmProcessInstanceRespVO respVO = convert2(processInstance); + copyTo(processInstanceExt, respVO); + // definition + respVO.setProcessDefinition(convert2(processDefinition)); + copyTo(processDefinitionExt, respVO.getProcessDefinition()); + respVO.getProcessDefinition().setBpmnXml(bpmnXml); + // user + if (startUser != null) { + respVO.setStartUser(convert2(startUser)); + if (dept != null) { + respVO.getStartUser().setDeptName(dept.getName()); + } + } + return respVO; + } + + BpmProcessInstanceRespVO convert2(HistoricProcessInstance bean); + + @Mapping(source = "from.id", target = "to.id", ignore = true) + void copyTo(BpmProcessInstanceExtDO from, @MappingTarget BpmProcessInstanceRespVO to); + + BpmProcessInstanceRespVO.ProcessDefinition convert2(ProcessDefinition bean); + + @Mapping(source = "from.id", target = "to.id", ignore = true) + void copyTo(BpmProcessDefinitionExtDO from, @MappingTarget BpmProcessInstanceRespVO.ProcessDefinition to); + + BpmProcessInstanceRespVO.User convert2(AdminUserRespDTO bean); + + default BpmProcessInstanceResultEvent convert(Object source, HistoricProcessInstance instance, Integer result) { + BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source); + event.setId(instance.getId()); + event.setProcessDefinitionKey(instance.getProcessDefinitionKey()); + event.setBusinessKey(instance.getBusinessKey()); + event.setResult(result); + return event; + } + + default BpmProcessInstanceResultEvent convert(Object source, ProcessInstance instance, Integer result) { + BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source); + event.setId(instance.getId()); + event.setProcessDefinitionKey(instance.getProcessDefinitionKey()); + event.setBusinessKey(instance.getBusinessKey()); + event.setResult(result); + return event; + } + + default BpmMessageSendWhenProcessInstanceApproveReqDTO convert2ApprovedReq(ProcessInstance instance){ + return new BpmMessageSendWhenProcessInstanceApproveReqDTO() + .setStartUserId(NumberUtils.parseLong(instance.getStartUserId())) + .setProcessInstanceId(instance.getId()) + .setProcessInstanceName(instance.getName()); + } + + default BpmMessageSendWhenProcessInstanceRejectReqDTO convert2RejectReq(ProcessInstance instance, String reason) { + return new BpmMessageSendWhenProcessInstanceRejectReqDTO() + .setProcessInstanceName(instance.getName()) + .setProcessInstanceId(instance.getId()) + .setReason(reason) + .setStartUserId(NumberUtils.parseLong(instance.getStartUserId())); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java new file mode 100644 index 000000000..91d405925 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java @@ -0,0 +1,168 @@ +package cn.iocoder.yudao.module.bpm.convert.task; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskDonePageItemRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.common.engine.impl.db.SuspensionState; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.mapstruct.*; +import org.mapstruct.factory.Mappers; +import org.springframework.beans.BeanUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Bpm 任务 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface BpmTaskConvert { + + BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class); + + /** + * 复制对象 + * + * @param source 源 要复制的对象 + * @param target 目标 复制到此对象 + * @param + * + * @return + */ + public static T copy(Object source, Class target) { + if (source == null || target == null) { + return null; + } + try { + T newInstance = target.newInstance(); + BeanUtils.copyProperties(source, newInstance); + return newInstance; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + default List copyList(List source, Class target) { + if (null == source || source.isEmpty()) { + return Collections.emptyList(); + } + return source.stream().map(e -> copy(e, target)).collect(Collectors.toList()); + } + + default List convertList1(List tasks, + Map processInstanceMap, Map userMap) { + return CollectionUtils.convertList(tasks, task -> { + BpmTaskTodoPageItemRespVO respVO = convert1(task); + ProcessInstance processInstance = processInstanceMap.get(task.getProcessInstanceId()); + if (processInstance != null) { + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + respVO.setProcessInstance(convert(processInstance, startUser)); + } + return respVO; + }); + } + + @Mapping(source = "suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState") + BpmTaskTodoPageItemRespVO convert1(Task bean); + + @Named("convertSuspendedToSuspensionState") + default Integer convertSuspendedToSuspensionState(boolean suspended) { + return suspended ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode(); + } + + default List convertList2(List tasks, + Map bpmTaskExtDOMap, Map historicProcessInstanceMap, + Map userMap) { + return CollectionUtils.convertList(tasks, task -> { + BpmTaskDonePageItemRespVO respVO = convert2(task); + BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId()); + copyTo(taskExtDO, respVO); + HistoricProcessInstance processInstance = historicProcessInstanceMap.get(task.getProcessInstanceId()); + if (processInstance != null) { + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + respVO.setProcessInstance(convert(processInstance, startUser)); + } + return respVO; + }); + } + + BpmTaskDonePageItemRespVO convert2(HistoricTaskInstance bean); + + @Mappings({@Mapping(source = "processInstance.id", target = "id"), + @Mapping(source = "processInstance.name", target = "name"), + @Mapping(source = "processInstance.startUserId", target = "startUserId"), + @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"), + @Mapping(source = "startUser.nickname", target = "startUserNickname")}) + BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser); + + default List convertList3(List tasks, + Map bpmTaskExtDOMap, HistoricProcessInstance processInstance, + Map userMap, Map deptMap) { + return CollectionUtils.convertList(tasks, task -> { + BpmTaskRespVO respVO = convert3(task); + BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId()); + copyTo(taskExtDO, respVO); + if (processInstance != null) { + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); + respVO.setProcessInstance(convert(processInstance, startUser)); + } + AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); + if (assignUser != null) { + respVO.setAssigneeUser(convert3(assignUser)); + DeptRespDTO dept = deptMap.get(assignUser.getDeptId()); + if (dept != null) { + respVO.getAssigneeUser().setDeptName(dept.getName()); + } + } + return respVO; + }); + } + + @Mapping(source = "taskDefinitionKey", target = "definitionKey") + BpmTaskRespVO convert3(HistoricTaskInstance bean); + + BpmTaskRespVO.User convert3(AdminUserRespDTO bean); + + @Mapping(target = "id", ignore = true) + void copyTo(BpmTaskExtDO from, @MappingTarget BpmTaskDonePageItemRespVO to); + + @Mappings({@Mapping(source = "processInstance.id", target = "id"), + @Mapping(source = "processInstance.name", target = "name"), + @Mapping(source = "processInstance.startUserId", target = "startUserId"), + @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"), + @Mapping(source = "startUser.nickname", target = "startUserNickname")}) + BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance, + AdminUserRespDTO startUser); + + default BpmTaskExtDO convert2TaskExt(Task task) { + BpmTaskExtDO taskExtDO = new BpmTaskExtDO().setTaskId(task.getId()) + .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setName(task.getName()) + .setProcessDefinitionId(task.getProcessDefinitionId()).setProcessInstanceId(task.getProcessInstanceId()); + taskExtDO.setCreateTime(task.getCreateTime()); + return taskExtDO; + } + + default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, + Task task) { + BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO(); + reqDTO.setProcessInstanceId(processInstance.getProcessInstanceId()) + .setProcessInstanceName(processInstance.getName()).setStartUserId(startUser.getId()) + .setStartUserNickname(startUser.getNickname()).setTaskId(task.getId()).setTaskName(task.getName()) + .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())); + return reqDTO; + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/package-info.java new file mode 100644 index 000000000..6a53114a8 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.bpm.convert.task; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md new file mode 100644 index 000000000..8153487b7 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md @@ -0,0 +1 @@ + diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java new file mode 100644 index 000000000..76bf777e5 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * 工作流的表单定义 + * 用于工作流的申请表单,需要动态配置的场景 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_form", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmFormDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 表单名 + */ + private String name; + /** + * 状态 + */ + private Integer status; + /** + * 表单的配置 + */ + private String conf; + /** + * 表单项的数组 + * + * 目前直接将 https://github.com/JakHuang/form-generator 生成的 JSON 串,直接保存 + * 定义:https://github.com/JakHuang/form-generator/issues/46 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List fields; + /** + * 备注 + */ + private String remark; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java new file mode 100644 index 000000000..57abc0b99 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * Bpm 流程定义的拓展表 + * 主要解决 Activiti {@link ProcessDefinition} 不支持拓展字段,所以新建拓展表 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_process_definition_ext", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmProcessDefinitionExtDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 流程定义的编号 + * + * 关联 ProcessDefinition 的 id 属性 + */ + private String processDefinitionId; + /** + * 流程模型的编号 + * + * 关联 Model 的 id 属性 + */ + private String modelId; + /** + * 描述 + */ + private String description; + + /** + * 表单类型 + * + * 关联 {@link BpmModelFormTypeEnum} + */ + private Integer formType; + /** + * 动态表单编号 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + * + * 关联 {@link BpmFormDO#getId()} + */ + private Long formId; + /** + * 表单的配置 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + * + * 冗余 {@link BpmFormDO#getConf()} + */ + private String formConf; + /** + * 表单项的数组 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + * + * 冗余 {@link BpmFormDO#getFields()} ()} + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List formFields; + /** + * 自定义表单的提交路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomCreatePath; + /** + * 自定义表单的查看路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomViewPath; + + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskAssignRuleDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskAssignRuleDO.java new file mode 100644 index 000000000..e65764f1a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskAssignRuleDO.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.util.Set; + +/** + * Bpm 任务分配的规则表,用于自定义配置每个任务的负责人、候选人的分配规则。 + * 也就是说,废弃 BPMN 原本的 UserTask 设置的 assignee、candidateUsers 等配置,而是通过使用该规则进行计算对应的负责人。 + * + * 1. 默认情况下,{@link #processDefinitionId} 为 {@link #PROCESS_DEFINITION_ID_NULL} 值,表示贵改则与流程模型关联 + * 2. 在流程模型部署后,会将他的所有规则记录,复制出一份新部署出来的流程定义,通过设置 {@link #processDefinitionId} 为新的流程定义的编号进行关联 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_task_assign_rule", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmTaskAssignRuleDO extends BaseDO { + + /** + * {@link #processDefinitionId} 空串,用于标识属于流程模型,而不属于流程定义 + */ + public static final String PROCESS_DEFINITION_ID_NULL = ""; + + /** + * 编号 + */ + @TableId + private Long id; + + /** + * 流程模型编号 + * + * 关联 Model 的 id 属性 + */ + private String modelId; + /** + * 流程定义编号 + * + * 关联 ProcessDefinition 的 id 属性 + */ + private String processDefinitionId; + /** + * 流程任务的定义 Key + * + * 关联 Task 的 taskDefinitionKey 属性 + */ + private String taskDefinitionKey; + + /** + * 规则类型 + * + * 枚举 {@link BpmTaskAssignRuleTypeEnum} + */ + @TableField("`type`") + private Integer type; + /** + * 规则值数组,一般关联指定表的编号 + * 根据 type 不同,对应的值是不同的: + * + * 1. {@link BpmTaskAssignRuleTypeEnum#ROLE} 时:角色编号 + * 2. {@link BpmTaskAssignRuleTypeEnum#DEPT_MEMBER} 时:部门编号 + * 3. {@link BpmTaskAssignRuleTypeEnum#DEPT_LEADER} 时:部门编号 + * 4. {@link BpmTaskAssignRuleTypeEnum#USER} 时:用户编号 + * 5. {@link BpmTaskAssignRuleTypeEnum#USER_GROUP} 时:用户组编号 + * 6. {@link BpmTaskAssignRuleTypeEnum#SCRIPT} 时:脚本编号,目前通过 {@link BpmTaskRuleScriptEnum#getId()} 标识 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private Set options; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskMessageRuleDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskMessageRuleDO.java new file mode 100644 index 000000000..db204c027 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmTaskMessageRuleDO.java @@ -0,0 +1,5 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +// TODO 芋艿:先埋个坑。任务消息的配置规则。说白了,就是不同的 +public class BpmTaskMessageRuleDO { +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java new file mode 100644 index 000000000..ec1168180 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.definition; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.util.Set; + +/** + * Bpm 用户组 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_user_group", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmUserGroupDO extends BaseDO { + + /** + * 编号,自增 + */ + @TableId + private Long id; + /** + * 组名 + */ + private String name; + /** + * 描述 + */ + private String description; + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + /** + * 成员用户编号数组 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private Set memberUserIds; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java new file mode 100644 index 000000000..31381a556 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import lombok.*; +import java.util.*; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * OA 请假申请 DO + * + * {@link #day} 请假天数,目前先简单做。一般是分成请假上午和下午,可以是 1 整天,可以是 0.5 半天 + * + * @author jason + * @author 芋道源码 + */ +@TableName("bpm_oa_leave") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOALeaveDO extends BaseDO { + + /** + * 请假表单主键 + */ + @TableId + private Long id; + /** + * 申请人的用户编号 + * + * 关联 AdminUserDO 的 id 属性 + */ + private Long userId; + /** + * 请假类型 + */ + @TableField("`type`") + private String type; + /** + * 原因 + */ + private String reason; + /** + * 开始时间 + */ + private Date startTime; + /** + * 结束时间 + */ + private Date endTime; + /** + * 请假天数 + */ + private Long day; + /** + * 请假的结果 + * + * 枚举 {@link BpmProcessInstanceResultEnum} + * 考虑到简单,所以直接复用了 BpmProcessInstanceResultEnum 枚举,也可以自己定义一个枚举哈 + */ + private Integer result; + + /** + * 对应的流程编号 + * + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmActivityDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmActivityDO.java new file mode 100644 index 000000000..183a04147 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmActivityDO.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.task; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.*; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +/** + * 任务流程关联表 + * + * @author kemengkai + * @create 2022-05-09 10:33 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BpmActivityDO { + + /** + * 任务流程关联id + */ + private String id; + + /** + * 审批结果 + */ + private Integer rev; + + /** + * 任务流程部署id + */ + private String procDefId; + + /** + * 任务流程id + */ + private String processInstanceId; + + /** + * 任务执行id + */ + private String executionId; + + /** + * 任务key + */ + private String activityId; + + /** + * 任务id + */ + private String taskId; + + /** + * 调用流程id + */ + private String callProcInstId; + + /** + * 任务名称 + */ + private String activityName; + + /** + * 任务类型 + */ + private String activityType; + + /** + * 任务审批人id + */ + private String assignee; + + /** + * 任务开始时间 + */ + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private Date startTime; + + /** + * 任务结束时间 + */ + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private Date endTime; + + private Integer transactionOrder; + + private Long duration; + + /** + * 删除结果 + */ + private String deleteReason; + + /** + * 租户id + */ + private String tenantId; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceExtDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceExtDO.java new file mode 100644 index 000000000..b37709962 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceExtDO.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.task; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; +import java.util.Map; + +/** + * Bpm 流程实例的拓展表 + * 主要解决 Activiti ProcessInstance 和 HistoricProcessInstance 不支持拓展字段,所以新建拓展表 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_process_instance_ext", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmProcessInstanceExtDO extends BaseDO { + + /** + * 编号,自增 + */ + @TableId + private Long id; + /** + * 发起流程的用户编号 + * + * 冗余 HistoricProcessInstance 的 startUserId 属性 + */ + private Long startUserId; + /** + * 流程实例的名字 + * + * 冗余 ProcessInstance 的 name 属性,用于筛选 + */ + private String name; + /** + * 流程实例的编号 + * + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + /** + * 流程定义的编号 + * + * 关联 ProcessDefinition 的 id 属性 + */ + private String processDefinitionId; + /** + * 流程分类 + * + * 冗余 ProcessDefinition 的 category 属性 + * 数据字典 bpm_model_category + */ + private String category; + /** + * 流程实例的状态 + * + * 枚举 {@link BpmProcessInstanceStatusEnum} + */ + private Integer status; + /** + * 流程实例的结果 + * + * 枚举 {@link BpmProcessInstanceResultEnum} + */ + private Integer result; + /** + * 结束时间 + * + * 冗余 HistoricProcessInstance 的 endTime 属性 + */ + private Date endTime; + + /** + * 提交的表单值 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map formVariables; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java new file mode 100644 index 000000000..5c6b70fc3 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmTaskExtDO.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.task; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; + +/** + * Bpm 流程任务的拓展表 + * 主要解决 Flowable Task 和 HistoricTaskInstance 不支持拓展字段,所以新建拓展表 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_task_ext", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmTaskExtDO extends BaseDO { + + /** + * 编号,自增 + */ + @TableId + private Long id; + + /** + * 任务的审批人 + * + * 冗余 Task 的 assignee 属性 + */ + private Long assigneeUserId; + /** + * 任务的名字 + * + * 冗余 Task 的 name 属性,为了筛选 + */ + private String name; + /** + * 任务的编号 + * + * 关联 Task 的 id 属性 + */ + private String taskId; +// /** +// * 任务的标识 +// * +// * 关联 {@link Task#getTaskDefinitionKey()} +// */ +// private String definitionKey; + /** + * 任务的结果 + * + * 枚举 {@link BpmProcessInstanceResultEnum} + */ + private Integer result; + /** + * 审批建议 + */ + private String reason; + /** + * 任务的结束时间 + * + * 冗余 HistoricTaskInstance 的 endTime 属性 + */ + private Date endTime; + + /** + * 流程实例的编号 + * + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + /** + * 流程定义的编号 + * + * 关联 ProcessDefinition 的 id 属性 + */ + private String processDefinitionId; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmFormMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmFormMapper.java new file mode 100644 index 000000000..53c01d92e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmFormMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import org.apache.ibatis.annotations.Mapper; + +/** + * 动态表单 Mapper + * + * @author 风里雾里 + */ +@Mapper +public interface BpmFormMapper extends BaseMapperX { + + default PageResult selectPage(BpmFormPageReqVO reqVO) { + return selectPage(reqVO, new QueryWrapperX() + .likeIfPresent("name", reqVO.getName()) + .orderByDesc("id")); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionExtMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionExtMapper.java new file mode 100644 index 000000000..3ff53f2d9 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessDefinitionExtMapper.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface BpmProcessDefinitionExtMapper extends BaseMapperX { + + default List selectListByProcessDefinitionIds(Collection processDefinitionIds) { + return selectList("process_definition_id", processDefinitionIds); + } + + default BpmProcessDefinitionExtDO selectByProcessDefinitionId(String processDefinitionId) { + return selectOne("process_definition_id", processDefinitionId); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmTaskAssignRuleMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmTaskAssignRuleMapper.java new file mode 100644 index 000000000..c4061c0f8 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmTaskAssignRuleMapper.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.lang.Nullable; + +import java.util.List; + +@Mapper +public interface BpmTaskAssignRuleMapper extends BaseMapperX { + + default List selectListByProcessDefinitionId(String processDefinitionId, + @Nullable String taskDefinitionKey) { + return selectList(new QueryWrapperX() + .eq("process_definition_id", processDefinitionId) + .eqIfPresent("task_definition_key", taskDefinitionKey)); + } + + default List selectListByModelId(String modelId) { + return selectList(new QueryWrapperX() + .eq("model_id", modelId) + .eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL)); + } + + default BpmTaskAssignRuleDO selectListByModelIdAndTaskDefinitionKey(String modelId, + String taskDefinitionKey) { + return selectOne(new QueryWrapperX() + .eq("model_id", modelId) + .eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL) + .eq("task_definition_key", taskDefinitionKey)); + } + + + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmUserGroupMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmUserGroupMapper.java new file mode 100644 index 000000000..ed076276c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmUserGroupMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 用户组 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface BpmUserGroupMapper extends BaseMapperX { + + default PageResult selectPage(BpmUserGroupPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(BpmUserGroupDO::getName, reqVO.getName()) + .eqIfPresent(BpmUserGroupDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(BpmUserGroupDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BpmUserGroupDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(BpmUserGroupDO::getStatus, status); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOALeaveMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOALeaveMapper.java new file mode 100644 index 000000000..ad05b9804 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOALeaveMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.oa; + +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import org.apache.ibatis.annotations.Mapper; + +/** + * 请假申请 Mapper + * + * @author jason + * @author 芋道源码 + */ +@Mapper +public interface BpmOALeaveMapper extends BaseMapperX { + + default PageResult selectPage(Long userId, BpmOALeavePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(BpmOALeaveDO::getUserId, userId) + .eqIfPresent(BpmOALeaveDO::getResult, reqVO.getResult()) + .eqIfPresent(BpmOALeaveDO::getType, reqVO.getType()) + .likeIfPresent(BpmOALeaveDO::getReason, reqVO.getReason()) + .betweenIfPresent(BpmOALeaveDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BpmOALeaveDO::getId)); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmActivityMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmActivityMapper.java new file mode 100644 index 000000000..7e93b240f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmActivityMapper.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.task; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmActivityDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface BpmActivityMapper extends BaseMapperX { + + + // TODO @ke:可以试试,把 activiti 的表,映射成对应的实体,然后读取下。我们尽量避免 xml 操作,因为要做多 db 类型的支持,例如说 oracle 等。通过 mybatis plus 帮助我们生成不同数据库的表操作 + /** + * 获取指定流程的历史任务 + * + * @param procInstId 流程id + * + * @return 返回历史任务 + */ + List listAllByProcInstIdAndDelete(@Param("procInstId") String procInstId); + + /** + * 逻辑删除hiActInst表任务 + * + * @param taskIdList 任务列表 + * + * @return 返回是否成功 + */ + Boolean delHiActInstByTaskId(@Param("taskIdList") List taskIdList); + + /** + * 逻辑删除hiTaskInst任务 + * + * @param taskIdList 任务列表 + * + * @return 返回是否成功 + */ + Boolean delHiTaskInstByTaskId(@Param("taskIdList") List taskIdList); +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java new file mode 100644 index 000000000..52e66219c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.task; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BpmProcessInstanceExtMapper extends BaseMapperX { + + default PageResult selectPage(Long userId, BpmProcessInstanceMyPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(BpmProcessInstanceExtDO::getStartUserId, userId) + .likeIfPresent(BpmProcessInstanceExtDO::getName, reqVO.getName()) + .eqIfPresent(BpmProcessInstanceExtDO::getProcessDefinitionId, reqVO.getProcessDefinitionId()) + .eqIfPresent(BpmProcessInstanceExtDO::getCategory, reqVO.getCategory()) + .eqIfPresent(BpmProcessInstanceExtDO::getStatus, reqVO.getStatus()) + .eqIfPresent(BpmProcessInstanceExtDO::getResult, reqVO.getResult()) + .betweenIfPresent(BpmProcessInstanceExtDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BpmProcessInstanceExtDO::getId)); + } + + default BpmProcessInstanceExtDO selectByProcessInstanceId(String processInstanceId) { + return selectOne(BpmProcessInstanceExtDO::getProcessInstanceId, processInstanceId); + } + + default void updateByProcessInstanceId(BpmProcessInstanceExtDO updateObj) { + update(updateObj, new LambdaQueryWrapperX() + .eq(BpmProcessInstanceExtDO::getProcessInstanceId, updateObj.getProcessInstanceId())); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java new file mode 100644 index 000000000..6683b536d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.task; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +@Mapper +public interface BpmTaskExtMapper extends BaseMapperX { + + default void updateByTaskId(BpmTaskExtDO entity) { + update(entity, new LambdaQueryWrapper().eq(BpmTaskExtDO::getTaskId, entity.getTaskId())); + } + + default List selectListByTaskIds(Collection taskIds) { + return selectList(BpmTaskExtDO::getTaskId, taskIds); + } + + default BpmTaskExtDO selectByTaskId(String taskId) { + return selectOne(BpmTaskExtDO::getTaskId, taskId); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCommonConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCommonConfiguration.java new file mode 100644 index 000000000..8915fc6b5 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCommonConfiguration.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.bpm.framework.bpm.config; + +import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * BPM 通用的 Configuration 配置类,提供给 Activiti 和 Flowable + */ +@Configuration +public class BpmCommonConfiguration { + + @Bean + public BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher(ApplicationEventPublisher publisher) { + return new BpmProcessInstanceResultEventPublisher(publisher); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmSecurityConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmSecurityConfiguration.java new file mode 100644 index 000000000..2069f7d11 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmSecurityConfiguration.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.bpm.framework.bpm.config; + +import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; + +/** + * @author kemengkai + * @create 2022-05-07 08:15 + */ +@Configuration("bpmSecurityConfiguration") +public class BpmSecurityConfiguration { + + @Bean("bpmAuthorizeRequestsCustomizer") + public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { + return new AuthorizeRequestsCustomizer() { + + @Override + public void customize(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry) { + // 任务回退接口 + registry.antMatchers(buildAdminApi("/bpm/task/back")).permitAll(); + } + + }; + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEvent.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEvent.java new file mode 100644 index 000000000..9fccbab8e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEvent.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.bpm.framework.bpm.core.event; + +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; +import lombok.Data; +import org.springframework.context.ApplicationEvent; + +import javax.validation.constraints.NotNull; + +/** + * 流程实例的结果发生变化的 Event + * 定位:由于额外增加了 {@link BpmProcessInstanceExtDO#getResult()} 结果,所以增加该事件 + * + * @author 芋道源码 + */ +@SuppressWarnings("ALL") +@Data +public class BpmProcessInstanceResultEvent extends ApplicationEvent { + + /** + * 流程实例的编号 + */ + @NotNull(message = "流程实例的编号不能为空") + private String id; + /** + * 流程实例的 key + */ + @NotNull(message = "流程实例的 key 不能为空") + private String processDefinitionKey; + /** + * 流程实例的结果 + */ + @NotNull(message = "流程实例的结果不能为空") + private Integer result; + /** + * 流程实例对应的业务标识 + * 例如说,请假 + */ + private String businessKey; + + public BpmProcessInstanceResultEvent(Object source) { + super(source); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventListener.java new file mode 100644 index 000000000..c2b215394 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventListener.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.bpm.framework.bpm.core.event; + +import cn.hutool.core.util.StrUtil; +import org.springframework.context.ApplicationListener; + +/** + * {@link BpmProcessInstanceResultEvent} 的监听器 + * + * @author 芋道源码 + */ +public abstract class BpmProcessInstanceResultEventListener + implements ApplicationListener { + + @Override + public final void onApplicationEvent(BpmProcessInstanceResultEvent event) { + if (!StrUtil.equals(event.getProcessDefinitionKey(), getProcessDefinitionKey())) { + return; + } + onEvent(event); + } + + /** + * @return 返回监听的流程定义 Key + */ + protected abstract String getProcessDefinitionKey(); + + /** + * 处理事件 + * + * @param event 事件 + */ + protected abstract void onEvent(BpmProcessInstanceResultEvent event); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventPublisher.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventPublisher.java new file mode 100644 index 000000000..dc5c21b75 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventPublisher.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.bpm.framework.bpm.core.event; + +import lombok.AllArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; + +/** + * {@link BpmProcessInstanceResultEvent} 的生产者 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Validated +public class BpmProcessInstanceResultEventPublisher { + + private final ApplicationEventPublisher publisher; + + public void sendProcessInstanceResultEvent(@Valid BpmProcessInstanceResultEvent event) { + publisher.publishEvent(event); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/package-info.java new file mode 100644 index 000000000..c4a131128 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/package-info.java @@ -0,0 +1,6 @@ +/** + * 自定义 Event 实现,提供方便业务接入的 Listener! + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.bpm.framework.bpm.core.event; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/package-info.java new file mode 100644 index 000000000..b97cb4c8a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.bpm.framework.bpm.core; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/package-info.java new file mode 100644 index 000000000..9a5e3ea96 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供给 Activiti 和 Flowable 的通用封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.bpm.framework.bpm; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java new file mode 100644 index 000000000..cb2b52e61 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.config; + +import cn.hutool.core.collection.ListUtil; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory; +import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; +import org.flowable.common.engine.api.delegate.event.FlowableEventListener; +import org.flowable.spring.SpringProcessEngineConfiguration; +import org.flowable.spring.boot.EngineConfigurationConfigurer; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * BPM 模块的 Flowable 配置类 + * + * @author jason + */ +@Configuration +public class BpmFlowableConfiguration { + + /** + * BPM 模块的 ProcessEngineConfigurationConfigurer 实现类: + * + * 1. 设置各种监听器 + * 2. 设置自定义的 ActivityBehaviorFactory 实现 + */ + @Bean + public EngineConfigurationConfigurer bpmProcessEngineConfigurationConfigurer( + ObjectProvider listeners, + BpmActivityBehaviorFactory bpmActivityBehaviorFactory) { + return configuration -> { + // 注册监听器,例如说 BpmActivityEventListener + configuration.setEventListeners(ListUtil.toList(listeners.iterator())); + // 设置 ActivityBehaviorFactory 实现类,用于流程任务的审核人的自定义 + configuration.setActivityBehaviorFactory(bpmActivityBehaviorFactory); + }; + } + + @Bean + public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskAssignRuleService taskRuleService) { + BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory(); + bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService); + return bpmActivityBehaviorFactory; + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java new file mode 100644 index 000000000..dced1c5bd --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; + +import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Setter; +import lombok.ToString; +import org.flowable.bpmn.model.Activity; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; +import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; +import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory; + +/** + * 自定义的 ActivityBehaviorFactory 实现类,目的如下: + * 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}:实现自定义的流程任务的 assignee 负责人的分配 + * + * @author 芋道源码 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { + + @Setter + private BpmTaskAssignRuleService bpmTaskRuleService; + + @Override + public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { + return new BpmUserTaskActivityBehavior(userTask) + .setBpmTaskRuleService(bpmTaskRuleService); + } + + @Override + public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity, + AbstractBpmnActivityBehavior innerActivityBehavior) { + return new BpmParallelMultiInstanceBehavior(activity, innerActivityBehavior) + .setBpmTaskRuleService(bpmTaskRuleService); + } + + // TODO @ke:SequentialMultiInstanceBehavior 这个抽空也可以看看 + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java new file mode 100644 index 000000000..0b60faa06 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; + +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.Activity; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; +import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; + +import java.util.Set; + +/** + * 自定义的【并行】的【多个】流程任务的 assignee 负责人的分配 + * 第一步,基于分配规则,计算出分配任务的【多个】候选人们。 + * 第二步,将【多个】任务候选人们,设置到 DelegateExecution 的 collectionVariable 变量中,以便 BpmUserTaskActivityBehavior 使用它 + * + * @author kemengkai + * @date 2022-04-21 16:57 + */ +@Slf4j +public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehavior { + + @Setter + private BpmTaskAssignRuleService bpmTaskRuleService; + + public BpmParallelMultiInstanceBehavior(Activity activity, + AbstractBpmnActivityBehavior innerActivityBehavior) { + super(activity, innerActivityBehavior); + } + + /** + * 重写该方法,主要实现两个功能: + * 1. 忽略原有的 collectionVariable、collectionElementVariable 表达式,而是采用自己定义的 + * 2. 获得任务的处理人,并设置到 collectionVariable 中,用于 BpmUserTaskActivityBehavior 从中可以获取任务的处理人 + * + * 注意,多个任务实例,每个任务实例对应一个处理人,所以返回的数量就是任务处理人的数量 + * + * @param execution 执行任务 + * @return 数量 + */ + @Override + protected int resolveNrOfInstances(DelegateExecution execution) { + // 第一步,设置 collectionVariable 和 CollectionVariable + // 从 execution.getVariable() 读取所有任务处理人的 key + super.collectionExpression = null; // collectionExpression 和 collectionVariable 是互斥的 + super.collectionVariable = FlowableUtils.formatCollectionVariable(execution.getCurrentActivityId()); + // 从 execution.getVariable() 读取当前所有任务处理的人的 key + super.collectionElementVariable = FlowableUtils.formatCollectionElementVariable(execution.getCurrentActivityId()); + + // 第二步,获取任务的所有处理人 + Set assigneeUserIds = bpmTaskRuleService.calculateTaskCandidateUsers(execution); + execution.setVariable(super.collectionVariable, assigneeUserIds); + return assigneeUserIds.size(); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java new file mode 100644 index 000000000..aeda4d52c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.UserTask; +import org.flowable.common.engine.impl.el.ExpressionManager; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.util.TaskHelper; +import org.flowable.task.service.TaskService; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; + +import java.util.List; +import java.util.Set; + +/** + * 自定义的【单个】流程任务的 assignee 负责人的分配 + * 第一步,基于分配规则,计算出分配任务的【单个】候选人。如果找不到,则直接报业务异常,不继续执行后续的流程; + * 第二步,随机选择一个候选人,则选择作为 assignee 负责人。 + * + * @author 芋道源码 + */ +@Slf4j +public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { + + @Setter + private BpmTaskAssignRuleService bpmTaskRuleService; + + public BpmUserTaskActivityBehavior(UserTask userTask) { + super(userTask); + } + + @Override + protected void handleAssignments(TaskService taskService, String assignee, String owner, + List candidateUsers, List candidateGroups, TaskEntity task, ExpressionManager expressionManager, + DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) { + // 第一步,获得任务的候选用户 + Long assigneeUserId = calculateTaskCandidateUsers(execution); + Assert.notNull(assigneeUserId, "任务处理人不能为空"); + // 第二步,设置作为负责人 + TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId)); + } + + private Long calculateTaskCandidateUsers(DelegateExecution execution) { + // 情况一,如果是多实例的任务,例如说会签、或签等情况,则从 Variable 中获取。它的任务处理人在 BpmParallelMultiInstanceBehavior 中已经被分配了 + if (super.multiInstanceActivityBehavior != null) { + return execution.getVariable(super.multiInstanceActivityBehavior.getCollectionElementVariable(), Long.class); + } + + // 情况二,如果非多实例的任务,则计算任务处理人 + // 第一步,先计算可处理该任务的处理人们 + Set candidateUserIds = bpmTaskRuleService.calculateTaskCandidateUsers(execution); + // 第二步,后随机选择一个任务的处理人 + // 疑问:为什么一定要选择一个任务处理人? + // 解答:项目对 bpm 的任务是责任到人,所以每个任务有且仅有一个处理人。 + // 如果希望一个任务可以同时被多个人处理,可以考虑使用 BpmParallelMultiInstanceBehavior 实现的会签 or 或签。 + int index = RandomUtil.randomInt(candidateUserIds.size()); + return CollUtil.get(candidateUserIds, index); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java new file mode 100644 index 000000000..b5c91ebad --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script; + +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; +import org.flowable.engine.delegate.DelegateExecution; + +import java.util.Set; + +/** + * Bpm 任务分配的自定义 Script 脚本 + * 使用场景: + * 1. 设置审批人为发起人 + * 2. 设置审批人为发起人的 Leader + * 3. 甚至审批人为发起人的 Leader 的 Leader + * + * @author 芋道源码 + */ +public interface BpmTaskAssignScript { + + /** + * 基于执行任务,获得任务的候选用户们 + * + * @param execution 执行任务 + * @return 候选人用户的编号数组 + */ + Set calculateTaskCandidateUsers(DelegateExecution execution); + + /** + * 获得枚举值 + * + * @return 枚举值 + */ + BpmTaskRuleScriptEnum getEnum(); +} + diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java new file mode 100644 index 000000000..7f77a1b3b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; + +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.context.annotation.Lazy; +import org.springframework.util.Assert; + +import javax.annotation.Resource; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static java.util.Collections.emptySet; + +/** + * 分配给发起人的 Leader 审批的 Script 实现类 + * 目前 Leader 的定义是, + * + * @author 芋道源码 + */ +public abstract class BpmTaskAssignLeaderAbstractScript implements BpmTaskAssignScript { + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + @Resource + @Lazy // 解决循环依赖 + private BpmProcessInstanceService bpmProcessInstanceService; + + protected Set calculateTaskCandidateUsers(DelegateExecution execution, int level) { + Assert.isTrue(level > 0, "level 必须大于 0"); + // 获得发起人 + ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(execution.getProcessInstanceId()); + Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); + // 获得对应 leve 的部门 + DeptRespDTO dept = null; + for (int i = 0; i < level; i++) { + // 获得 level 对应的部门 + if (dept == null) { + dept = getStartUserDept(startUserId); + if (dept == null) { // 找不到发起人的部门,所以无法使用该规则 + return emptySet(); + } + } else { + DeptRespDTO parentDept = deptApi.getDept(dept.getParentId()).getCheckedData(); + if (parentDept == null) { // 找不到父级部门,所以只好结束寻找。原因是:例如说,级别比较高的人,所在部门层级比较少 + break; + } + dept = parentDept; + } + } + return dept.getLeaderUserId() != null ? asSet(dept.getLeaderUserId()) : emptySet(); + } + + private DeptRespDTO getStartUserDept(Long startUserId) { + AdminUserRespDTO startUser = adminUserApi.getUser(startUserId).getCheckedData(); + if (startUser.getDeptId() == null) { // 找不到部门,所以无法使用该规则 + return null; + } + return deptApi.getDept(startUser.getDeptId()).getCheckedData(); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java new file mode 100644 index 000000000..af7d8b5a7 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; + +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * 分配给发起人的一级 Leader 审批的 Script 实现类 + * + * @author 芋道源码 + */ +@Component +public class BpmTaskAssignLeaderX1Script extends BpmTaskAssignLeaderAbstractScript { + + @Override + public Set calculateTaskCandidateUsers(DelegateExecution execution) { + return calculateTaskCandidateUsers(execution, 1); + } + + @Override + public BpmTaskRuleScriptEnum getEnum() { + return BpmTaskRuleScriptEnum.LEADER_X1; + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java new file mode 100644 index 000000000..068ab3d2f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; + +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * 分配给发起人的二级 Leader 审批的 Script 实现类 + * + * @author 芋道源码 + */ +@Component +public class BpmTaskAssignLeaderX2Script extends BpmTaskAssignLeaderAbstractScript { + + @Override + public Set calculateTaskCandidateUsers(DelegateExecution execution) { + return calculateTaskCandidateUsers(execution, 2); + } + + @Override + public BpmTaskRuleScriptEnum getEnum() { + return BpmTaskRuleScriptEnum.LEADER_X2; + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java new file mode 100644 index 000000000..1363f3979 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; + +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Set; + +/** + * 分配给发起人审批的 Script 实现类 + * + * @author 芋道源码 + */ +@Component +public class BpmTaskAssignStartUserScript implements BpmTaskAssignScript { + + @Resource + @Lazy // 解决循环依赖 + private BpmProcessInstanceService bpmProcessInstanceService; + + @Override + public Set calculateTaskCandidateUsers(DelegateExecution execution) { + ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(execution.getProcessInstanceId()); + Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); + return SetUtils.asSet(startUserId); + } + + @Override + public BpmTaskRuleScriptEnum getEnum() { + return BpmTaskRuleScriptEnum.START_USER; + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java new file mode 100644 index 000000000..98bc37f9f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; + +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import com.google.common.collect.ImmutableSet; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; +import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener; +import org.flowable.engine.delegate.event.FlowableCancelledEvent; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Set; + +/** + * 监听 {@link ProcessInstance} 的开始与完成,创建与更新对应的 {@link BpmProcessInstanceExtDO} 记录 + * + * @author jason + */ +@Component +public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEventListener { + + @Resource + @Lazy + private BpmProcessInstanceService processInstanceService; + + public static final Set PROCESS_INSTANCE_EVENTS = ImmutableSet.builder() + .add(FlowableEngineEventType.PROCESS_CREATED) + .add(FlowableEngineEventType.PROCESS_CANCELLED) + .add(FlowableEngineEventType.PROCESS_COMPLETED) + .build(); + + public BpmProcessInstanceEventListener(){ + super(PROCESS_INSTANCE_EVENTS); + } + + @Override + protected void processCreated(FlowableEngineEntityEvent event) { + processInstanceService.createProcessInstanceExt((ProcessInstance)event.getEntity()); + } + + @Override + protected void processCancelled(FlowableCancelledEvent event) { + processInstanceService.updateProcessInstanceExtCancel(event); + } + + @Override + protected void processCompleted(FlowableEngineEntityEvent event) { + processInstanceService.updateProcessInstanceExtComplete((ProcessInstance)event.getEntity()); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java new file mode 100644 index 000000000..745561993 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; +import cn.iocoder.yudao.module.bpm.service.task.BpmActivityService; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +import com.google.common.collect.ImmutableSet; +import lombok.extern.slf4j.Slf4j; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; +import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener; +import org.flowable.engine.delegate.event.FlowableActivityCancelledEvent; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.task.api.Task; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; + +/** + * 监听 {@link org.flowable.task.api.Task} 的开始与完成,创建与更新对应的 {@link BpmTaskExtDO} 记录 + * + * @author jason + */ +@Component +@Slf4j +public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { + + @Resource + @Lazy // 解决循环依赖 + private BpmTaskService taskService; + + @Resource + @Lazy // 解决循环依赖 + private BpmActivityService activityService; + + public static final Set TASK_EVENTS = ImmutableSet.builder() + .add(FlowableEngineEventType.TASK_CREATED) + .add(FlowableEngineEventType.TASK_ASSIGNED) + .add(FlowableEngineEventType.TASK_COMPLETED) + .add(FlowableEngineEventType.ACTIVITY_CANCELLED) + .build(); + + public BpmTaskEventListener(){ + super(TASK_EVENTS); + } + + @Override + protected void taskCreated(FlowableEngineEntityEvent event) { + taskService.createTaskExt((Task) event.getEntity()); + } + + @Override + protected void taskCompleted(FlowableEngineEntityEvent event) { + taskService.updateTaskExtComplete((Task)event.getEntity()); + } + + @Override + protected void taskAssigned(FlowableEngineEntityEvent event) { + taskService.updateTaskExtAssign((Task)event.getEntity()); + } + + @Override + protected void activityCancelled(FlowableActivityCancelledEvent event) { + List activityList = activityService.getHistoricActivityListByExecutionId(event.getExecutionId()); + if (CollUtil.isEmpty(activityList)) { + log.error("[activityCancelled][使用 executionId({}) 查找不到对应的活动实例]", event.getExecutionId()); + return; + } + // 遍历处理 + activityList.forEach(activity -> { + if (StrUtil.isEmpty(activity.getTaskId())) { + return; + } + taskService.updateTaskExtCancel(activity.getTaskId()); + }); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/package-info.java new file mode 100644 index 000000000..52fdb7f93 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 bpm 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.bpm.framework; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java new file mode 100644 index 000000000..6459263cb --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.bpm.framework.rpc.config; + +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.PostApi; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import cn.iocoder.yudao.module.system.api.permission.RoleApi; +import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@EnableFeignClients(clients = {RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class}) +public class RpcConfiguration { +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/package-info.java new file mode 100644 index 000000000..d34205cec --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.bpm.framework.rpc; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/package-info.java new file mode 100644 index 000000000..333ae35a4 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/package-info.java @@ -0,0 +1,12 @@ +/** + * bpm 包下,业务流程管理(Business Process Management),我们放工作流的功能,基于 activiti 7 版本实现。 + * 例如说:流程定义、表单配置、审核中心(我的申请、我的待办、我的已办)等等 + * + * bpm 解释:https://baike.baidu.com/item/BPM/1933 + * + * 1. Controller URL:以 /bpm/ 开头,避免和其它 Module 冲突 + * 2. DataObject 表名:以 bpm_ 开头,方便在数据库中区分 + * + * 注意,由于 Bpm 模块下,容易和其它模块重名,所以类名都加载 Bpm 的前缀~ + */ +package cn.iocoder.yudao.module.bpm; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java new file mode 100644 index 000000000..80355ef5e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormService.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + + +/** + * 动态表单 Service 接口 + * + * @author @风里雾里 + */ +public interface BpmFormService { + + /** + * 创建动态表单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createForm(@Valid BpmFormCreateReqVO createReqVO); + + /** + * 更新动态表单 + * + * @param updateReqVO 更新信息 + */ + void updateForm(@Valid BpmFormUpdateReqVO updateReqVO); + + /** + * 删除动态表单 + * + * @param id 编号 + */ + void deleteForm(Long id); + + /** + * 获得动态表单 + * + * @param id 编号 + * @return 动态表单 + */ + BpmFormDO getForm(Long id); + + /** + * 获得动态表单列表 + * + * @return 动态表单列表 + */ + List getFormList(); + + /** + * 获得动态表单列表 + * + * @param ids 编号 + * @return 动态表单列表 + */ + List getFormList(Collection ids); + + /** + * 获得动态表单 Map + * + * @param ids 编号 + * @return 动态表单 Map + */ + default Map getFormMap(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyMap(); + } + return CollectionUtils.convertMap(this.getFormList(ids), BpmFormDO::getId); + } + + /** + * 获得动态表单分页 + * + * @param pageReqVO 分页查询 + * @return 动态表单分页 + */ + PageResult getFormPage(BpmFormPageReqVO pageReqVO); + + /** + * 校验流程表单已配置 + * + * @param configStr configStr 字段 + * @return 流程表单 + */ + BpmFormDO checkFormConfig(String configStr); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java new file mode 100644 index 000000000..967ab8f49 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceImpl.java @@ -0,0 +1,135 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmFormConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmFormMapper; +import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmFormFieldRespDTO; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; + +/** + * 动态表单 Service 实现类 + * + * @author 风里雾里 + */ +@Service +@Validated +public class BpmFormServiceImpl implements BpmFormService { + + @Resource + private BpmFormMapper formMapper; + + @Override + public Long createForm(BpmFormCreateReqVO createReqVO) { + this.checkFields(createReqVO.getFields()); + // 插入 + BpmFormDO form = BpmFormConvert.INSTANCE.convert(createReqVO); + formMapper.insert(form); + // 返回 + return form.getId(); + } + + @Override + public void updateForm(BpmFormUpdateReqVO updateReqVO) { + this.checkFields(updateReqVO.getFields()); + // 校验存在 + this.validateFormExists(updateReqVO.getId()); + // 更新 + BpmFormDO updateObj = BpmFormConvert.INSTANCE.convert(updateReqVO); + formMapper.updateById(updateObj); + } + + @Override + public void deleteForm(Long id) { + // 校验存在 + this.validateFormExists(id); + // 删除 + formMapper.deleteById(id); + } + + private void validateFormExists(Long id) { + if (formMapper.selectById(id) == null) { + throw exception(ErrorCodeConstants.FORM_NOT_EXISTS); + } + } + + @Override + public BpmFormDO getForm(Long id) { + return formMapper.selectById(id); + } + + @Override + public List getFormList() { + return formMapper.selectList(); + } + + @Override + public List getFormList(Collection ids) { + return formMapper.selectBatchIds(ids); + } + + @Override + public PageResult getFormPage(BpmFormPageReqVO pageReqVO) { + return formMapper.selectPage(pageReqVO); + } + + + @Override + public BpmFormDO checkFormConfig(String configStr) { + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(configStr, BpmModelMetaInfoRespDTO.class); + if (metaInfo == null || metaInfo.getFormType() == null) { + throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); + } + // 校验表单存在 + if (Objects.equals(metaInfo.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) { + BpmFormDO form = getForm(metaInfo.getFormId()); + if (form == null) { + throw exception(FORM_NOT_EXISTS); + } + return form; + } + return null; + } + + private void checkKeyNCName(String key) { + if (!ValidationUtils.isXmlNCName(key)) { + throw exception(MODEL_KEY_VALID); + } + } + /** + * 校验 Field,避免 field 重复 + * + * @param fields field 数组 + */ + private void checkFields(List fields) { + Map fieldMap = new HashMap<>(); // key 是 vModel,value 是 label + for (String field : fields) { + BpmFormFieldRespDTO fieldDTO = JsonUtils.parseObject(field, BpmFormFieldRespDTO.class); + Assert.notNull(fieldDTO); + String oldLabel = fieldMap.put(fieldDTO.getVModel(), fieldDTO.getLabel()); + // 如果不存在,则直接返回 + if (oldLabel == null) { + continue; + } + // 如果存在,则报错 + throw exception(ErrorCodeConstants.FORM_FIELD_REPEAT, oldLabel, fieldDTO.getLabel(), fieldDTO.getVModel()); + } + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java new file mode 100644 index 000000000..a4e4f83d1 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; +import org.flowable.bpmn.model.BpmnModel; + +import javax.validation.Valid; + +/** + * Flowable流程模型接口 + * + * @author yunlongn + */ +public interface BpmModelService { + /** + * 获得流程模型分页 + * + * @param pageVO 分页查询 + * @return 流程模型分页 + */ + PageResult getModelPage(BpmModelPageReqVO pageVO); + + /** + * 创建流程模型 + * + * @param modelVO 创建信息 + * @param bpmnXml BPMN XML + * @return 创建的流程模型的编号 + */ + String createModel(@Valid BpmModelCreateReqVO modelVO, String bpmnXml); + + /** + * 获得流程模块 + * + * @param id 编号 + * @return 流程模型 + */ + BpmModelRespVO getModel(String id); + + /** + * 修改流程模型 + * + * @param updateReqVO 更新信息 + */ + void updateModel(@Valid BpmModelUpdateReqVO updateReqVO); + + /** + * 将流程模型,部署成一个流程定义 + * + * @param id 编号 + */ + void deployModel(String id); + + /** + * 删除模型 + * + * @param id 编号 + */ + void deleteModel(String id); + + /** + * 修改模型的状态,实际更新的部署的流程定义的状态 + * + * @param id 编号 + * @param state 状态 + */ + void updateModelState(String id, Integer state); + + /** + * 获得流程模型编号对应的 BPMN Model + * + * @param id 流程模型编号 + * @return BPMN Model + */ + BpmnModel getBpmnModel(String id); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java new file mode 100644 index 000000000..a4a2d9182 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -0,0 +1,287 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.object.PageUtils; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.common.engine.impl.db.SuspensionState; +import org.flowable.common.engine.impl.util.io.BytesStreamSource; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.Model; +import org.flowable.engine.repository.ModelQuery; +import org.flowable.engine.repository.ProcessDefinition; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.*; + +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.module.bpm.enums.ErrorCodeConstants.*; + +/** + * Flowable流程模型实现 + * 主要进行 Flowable {@link Model} 的维护 + * + * @author yunlongn + * @author 芋道源码 + * @author jason + */ +@Service +@Validated +@Slf4j +public class BpmModelServiceImpl implements BpmModelService { + + @Resource + private RepositoryService repositoryService; + @Resource + private BpmProcessDefinitionService processDefinitionService; + @Resource + private BpmFormService bpmFormService; + @Resource + private BpmTaskAssignRuleService taskAssignRuleService; + + @Override + public PageResult getModelPage(BpmModelPageReqVO pageVO) { + ModelQuery modelQuery = repositoryService.createModelQuery(); + if (StrUtil.isNotBlank(pageVO.getKey())) { + modelQuery.modelKey(pageVO.getKey()); + } + if (StrUtil.isNotBlank(pageVO.getName())) { + modelQuery.modelNameLike("%" + pageVO.getName() + "%"); // 模糊匹配 + } + if (StrUtil.isNotBlank(pageVO.getCategory())) { + modelQuery.modelCategory(pageVO.getCategory()); + } + // 执行查询 + List models = modelQuery.orderByCreateTime().desc() + .listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + + // 获得 Form Map + Set formIds = CollectionUtils.convertSet(models, model -> { + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + return metaInfo != null ? metaInfo.getFormId() : null; + }); + Map formMap = bpmFormService.getFormMap(formIds); + + // 获得 Deployment Map + Set deploymentIds = new HashSet<>(); + models.forEach(model -> CollectionUtils.addIfNotNull(deploymentIds, model.getDeploymentId())); + Map deploymentMap = processDefinitionService.getDeploymentMap(deploymentIds); + // 获得 ProcessDefinition Map + List processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds); + Map processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId); + + // 拼接结果 + long modelCount = modelQuery.count(); + return new PageResult<>(BpmModelConvert.INSTANCE.convertList(models, formMap, deploymentMap, processDefinitionMap), modelCount); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String createModel(@Valid BpmModelCreateReqVO createReqVO, String bpmnXml) { + checkKeyNCName(createReqVO.getKey()); + // 校验流程标识已经存在 + Model keyModel = getModelByKey(createReqVO.getKey()); + if (keyModel != null) { + throw exception(MODEL_KEY_EXISTS, createReqVO.getKey()); + } + + // 创建流程定义 + Model model = repositoryService.newModel(); + BpmModelConvert.INSTANCE.copy(model, createReqVO); + // 保存流程定义 + repositoryService.saveModel(model); + // 保存 BPMN XML + saveModelBpmnXml(model, bpmnXml); + return model.getId(); + } + + private Model getModelByKey(String key) { + return repositoryService.createModelQuery().modelKey(key).singleResult(); + } + + @Override + public BpmModelRespVO getModel(String id) { + Model model = repositoryService.getModel(id); + if (model == null) { + return null; + } + BpmModelRespVO modelRespVO = BpmModelConvert.INSTANCE.convert(model); + // 拼接 bpmn XML + byte[] bpmnBytes = repositoryService.getModelEditorSource(id); + modelRespVO.setBpmnXml(StrUtil.utf8Str(bpmnBytes)); + return modelRespVO; + } + + @Override + @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务 + public void updateModel(@Valid BpmModelUpdateReqVO updateReqVO) { + // 校验流程模型存在 + Model model = repositoryService.getModel(updateReqVO.getId()); + if (model == null) { + throw exception(MODEL_NOT_EXISTS); + } + + // 修改流程定义 + BpmModelConvert.INSTANCE.copy(model, updateReqVO); + // 更新模型 + repositoryService.saveModel(model); + // 更新 BPMN XML + saveModelBpmnXml(model, updateReqVO.getBpmnXml()); + } + + @Override + @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务 + public void deployModel(String id) { + // 1.1 校验流程模型存在 + Model model = repositoryService.getModel(id); + if (ObjectUtils.isEmpty(model)) { + throw exception(MODEL_NOT_EXISTS); + } + // 1.2 校验流程图 + // TODO 芋艿:校验流程图的有效性;例如说,是否有开始的元素,是否有结束的元素; + byte[] bpmnBytes = repositoryService.getModelEditorSource(model.getId()); + if (bpmnBytes == null) { + throw exception(MODEL_NOT_EXISTS); + } + // 1.3 校验表单已配 + BpmFormDO form = checkFormConfig(model.getMetaInfo()); + // 1.4 校验任务分配规则已配置 + taskAssignRuleService.checkTaskAssignRuleAllConfig(id); + + // 1.5 校验模型是否发生修改。如果未修改,则不允许创建 + BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form).setBpmnBytes(bpmnBytes); + if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等 + ProcessDefinition oldProcessDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId()); + if (oldProcessDefinition != null && taskAssignRuleService.isTaskAssignRulesEquals(model.getId(), oldProcessDefinition.getId())) { + throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS); + } + } + + // 2.1 创建流程定义 + String definitionId = processDefinitionService.createProcessDefinition(definitionCreateReqDTO); + + // 2.2 将老的流程定义进行挂起。也就是说,只有最新部署的流程定义,才可以发起任务。 + updateProcessDefinitionSuspended(model.getDeploymentId()); + + // 2.3 更新 model 的 deploymentId,进行关联 + ProcessDefinition definition = processDefinitionService.getProcessDefinition(definitionId); + model.setDeploymentId(definition.getDeploymentId()); + repositoryService.saveModel(model); + + // 2.4 复制任务分配规则 + taskAssignRuleService.copyTaskAssignRules(id, definition.getId()); + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteModel(String id) { + // 校验流程模型存在 + Model model = repositoryService.getModel(id); + if (model == null) { + throw exception(MODEL_NOT_EXISTS); + } + // 执行删除 + repositoryService.deleteModel(id); + // 禁用流程实例 + updateProcessDefinitionSuspended(model.getDeploymentId()); + } + + @Override + public void updateModelState(String id, Integer state) { + // 校验流程模型存在 + Model model = repositoryService.getModel(id); + if (model == null) { + throw exception(MODEL_NOT_EXISTS); + } + // 校验流程定义存在 + ProcessDefinition definition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId()); + if (definition == null) { + throw exception(PROCESS_DEFINITION_NOT_EXISTS); + } + + // 更新状态 + processDefinitionService.updateProcessDefinitionState(definition.getId(), state); + } + + @Override + public BpmnModel getBpmnModel(String id) { + byte[] bpmnBytes = repositoryService.getModelEditorSource(id); + if (ArrayUtil.isEmpty(bpmnBytes)) { + return null; + } + BpmnXMLConverter converter = new BpmnXMLConverter(); + return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true); + } + + private void checkKeyNCName(String key) { + if (!ValidationUtils.isXmlNCName(key)) { + throw exception(MODEL_KEY_VALID); + } + } + + /** + * 校验流程表单已配置 + * + * @param metaInfoStr 流程模型 metaInfo 字段 + * @return 流程表单 + */ + private BpmFormDO checkFormConfig(String metaInfoStr) { + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(metaInfoStr, BpmModelMetaInfoRespDTO.class); + if (metaInfo == null || metaInfo.getFormType() == null) { + throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); + } + // 校验表单存在 + if (Objects.equals(metaInfo.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) { + BpmFormDO form = bpmFormService.getForm(metaInfo.getFormId()); + if (form == null) { + throw exception(FORM_NOT_EXISTS); + } + return form; + } + return null; + } + + private void saveModelBpmnXml(Model model, String bpmnXml) { + if (StrUtil.isEmpty(bpmnXml)) { + return; + } + repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml)); + } + + /** + * 挂起 deploymentId 对应的流程定义。 这里一个deploymentId 只关联一个流程定义 + * @param deploymentId 流程发布Id. + */ + private void updateProcessDefinitionSuspended(String deploymentId) { + if (StrUtil.isEmpty(deploymentId)) { + return; + } + ProcessDefinition oldDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(deploymentId); + if (oldDefinition == null) { + return; + } + processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode()); + } + + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java new file mode 100644 index 000000000..7c26b644e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionService.java @@ -0,0 +1,159 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.ProcessDefinition; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.Set; +/** + * Flowable流程定义接口 + * + * @author yunlong.li + * @author ZJQ + * @author 芋道源码 + */ +public interface BpmProcessDefinitionService { + + /** + * 获得流程定义分页 + * + * @param pageReqVO 分页入参 + * @return 流程定义 Page + */ + PageResult getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageReqVO); + + /** + * 获得流程定义列表 + * + * @param listReqVO 列表入参 + * @return 流程定义列表 + */ + List getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO); + + /** + * 创建流程定义 + * + * @param createReqDTO 创建信息 + * @return 流程编号 + */ + String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO); + + /** + * 更新流程定义状态 + * + * @param id 流程定义的编号 + * @param state 状态 + */ + void updateProcessDefinitionState(String id, Integer state); + + /** + * 获得流程定义对应的 BPMN XML + * + * @param id 流程定义编号 + * @return BPMN XML + */ + String getProcessDefinitionBpmnXML(String id); + + /** + * 获得需要创建的流程定义,是否和当前激活的流程定义相等 + * + * @param createReqDTO 创建信息 + * @return 是否相等 + */ + boolean isProcessDefinitionEquals(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO); + + /** + * 获得编号对应的 BpmProcessDefinitionExtDO + * + * @param id 编号 + * @return 流程定义拓展 + */ + BpmProcessDefinitionExtDO getProcessDefinitionExt(String id); + + /** + * 获得编号对应的 ProcessDefinition + * + * @param id 编号 + * @return 流程定义 + */ + ProcessDefinition getProcessDefinition(String id); + + /** + * 获得编号对应的 ProcessDefinition + * + * 相比 {@link #getProcessDefinition(String)} 方法,category 的取值是正确 + * + * @param id 编号 + * @return 流程定义 + */ + ProcessDefinition getProcessDefinition2(String id); + + /** + * 获得 deploymentId 对应的 ProcessDefinition + * + * @param deploymentId 部署编号 + * @return 流程定义 + */ + ProcessDefinition getProcessDefinitionByDeploymentId(String deploymentId); + + /** + * 获得 deploymentIds 对应的 ProcessDefinition 数组 + * + * @param deploymentIds 部署编号的数组 + * @return 流程定义的数组 + */ + List getProcessDefinitionListByDeploymentIds(Set deploymentIds); + + /** + * 获得流程定义标识对应的激活的流程定义 + * + * @param key 流程定义的标识 + * @return 流程定义 + */ + ProcessDefinition getActiveProcessDefinition(String key); + + /** + * 获得 ids 对应的 Deployment Map + * + * @param ids 部署编号的数组 + * @return 流程部署 Map + */ + default Map getDeploymentMap(Set ids) { + return CollectionUtils.convertMap(getDeployments(ids), Deployment::getId); + } + + /** + * 获得 ids 对应的 Deployment 数组 + * + * @param ids 部署编号的数组 + * @return 流程部署的数组 + */ + List getDeployments(Set ids); + + /** + * 获得 id 对应的 Deployment + * + * @param id 部署编号 + * @return 流程部署 + */ + Deployment getDeployment(String id); + + /** + * 获得 Bpmn 模型 + * + * @param processDefinitionId 流程定义的编号 + * @return Bpmn 模型 + */ + BpmnModel getBpmnModel(String processDefinitionId); +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java new file mode 100644 index 000000000..35464ab6a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java @@ -0,0 +1,286 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.PageUtils; +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.common.engine.impl.db.SuspensionState; +import org.flowable.common.engine.impl.util.io.BytesStreamSource; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.repository.ProcessDefinitionQuery; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_KEY_NOT_MATCH; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_NAME_NOT_MATCH; +import static java.util.Collections.emptyList; + +/** + * 流程定义实现 + * 主要进行 Flowable {@link ProcessDefinition} 和 {@link Deployment} 的维护 + * + * @author yunlongn + * @author ZJQ + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionService { + + private static final String BPMN_FILE_SUFFIX = ".bpmn"; + + @Resource + private RepositoryService repositoryService; + + @Resource + private BpmProcessDefinitionExtMapper processDefinitionMapper; + + @Resource + private BpmFormService formService; + + @Override + public ProcessDefinition getProcessDefinition(String id) { + return repositoryService.getProcessDefinition(id); + } + + @Override + public ProcessDefinition getProcessDefinition2(String id) { + return repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult(); + } + + @Override + public ProcessDefinition getProcessDefinitionByDeploymentId(String deploymentId) { + if (StrUtil.isEmpty(deploymentId)) { + return null; + } + return repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult(); + } + + @Override + public List getProcessDefinitionListByDeploymentIds(Set deploymentIds) { + if (CollUtil.isEmpty(deploymentIds)) { + return emptyList(); + } + return repositoryService.createProcessDefinitionQuery().deploymentIds(deploymentIds).list(); + } + + @Override + public ProcessDefinition getActiveProcessDefinition(String key) { + return repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).active().singleResult(); + } + + @Override + public List getDeployments(Set ids) { + if (CollUtil.isEmpty(ids)) { + return emptyList(); + } + List list = new ArrayList<>(ids.size()); + for (String id : ids) { + addIfNotNull(list, getDeployment(id)); + } + return list; + } + + @Override + public Deployment getDeployment(String id) { + if (StrUtil.isEmpty(id)) { + return null; + } + return repositoryService.createDeploymentQuery().deploymentId(id).singleResult(); + } + + @Override + public BpmnModel getBpmnModel(String processDefinitionId) { + return repositoryService.getBpmnModel(processDefinitionId); + } + + @Override + public String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO) { + // 创建 Deployment 部署 + Deployment deploy = repositoryService.createDeployment() + .key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory()) + .addBytes(createReqDTO.getKey() + BPMN_FILE_SUFFIX, createReqDTO.getBpmnBytes()) + .deploy(); + + // 设置 ProcessDefinition 的 category 分类 + ProcessDefinition definition = repositoryService.createProcessDefinitionQuery() + .deploymentId(deploy.getId()).singleResult(); + repositoryService.setProcessDefinitionCategory(definition.getId(), createReqDTO.getCategory()); + // 注意 1,ProcessDefinition 的 key 和 name 是通过 BPMN 中的 的 id 和 name 决定 + // 注意 2,目前该项目的设计上,需要保证 Model、Deployment、ProcessDefinition 使用相同的 key,保证关联性。 + // 否则,会导致 ProcessDefinition 的分页无法查询到。 + if (!Objects.equals(definition.getKey(), createReqDTO.getKey())) { + throw exception(PROCESS_DEFINITION_KEY_NOT_MATCH, createReqDTO.getKey(), definition.getKey()); + } + if (!Objects.equals(definition.getName(), createReqDTO.getName())) { + throw exception(PROCESS_DEFINITION_NAME_NOT_MATCH, createReqDTO.getName(), definition.getName()); + } + + // 插入拓展表 + BpmProcessDefinitionExtDO definitionDO = BpmProcessDefinitionConvert.INSTANCE.convert2(createReqDTO) + .setProcessDefinitionId(definition.getId()); + processDefinitionMapper.insert(definitionDO); + return definition.getId(); + } + + @Override + public void updateProcessDefinitionState(String id, Integer state) { + // 激活 + if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), state)) { + repositoryService.activateProcessDefinitionById(id, false, null); + return; + } + // 挂起 + if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), state)) { + // suspendProcessInstances = false,进行中的任务,不进行挂起。 + // 原因:只要新的流程不允许发起即可,老流程继续可以执行。 + repositoryService.suspendProcessDefinitionById(id, false, null); + return; + } + log.error("[updateProcessDefinitionState][流程定义({}) 修改未知状态({})]", id, state); + } + + @Override + public String getProcessDefinitionBpmnXML(String id) { + BpmnModel bpmnModel = repositoryService.getBpmnModel(id); + if (bpmnModel == null) { + return null; + } + BpmnXMLConverter converter = new BpmnXMLConverter(); + return StrUtil.utf8Str(converter.convertToXML(bpmnModel)); + } + + @Override + public boolean isProcessDefinitionEquals(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO) { + // 校验 name、description 是否更新 + ProcessDefinition oldProcessDefinition = getActiveProcessDefinition(createReqDTO.getKey()); + if (oldProcessDefinition == null) { + return false; + } + BpmProcessDefinitionExtDO oldProcessDefinitionExt = getProcessDefinitionExt(oldProcessDefinition.getId()); + if (!StrUtil.equals(createReqDTO.getName(), oldProcessDefinition.getName()) + || !StrUtil.equals(createReqDTO.getDescription(), oldProcessDefinitionExt.getDescription()) + || !StrUtil.equals(createReqDTO.getCategory(), oldProcessDefinition.getCategory())) { + return false; + } + // 校验 form 信息是否更新 + if (!ObjectUtil.equal(createReqDTO.getFormType(), oldProcessDefinitionExt.getFormType()) + || !ObjectUtil.equal(createReqDTO.getFormId(), oldProcessDefinitionExt.getFormId()) + || !ObjectUtil.equal(createReqDTO.getFormConf(), oldProcessDefinitionExt.getFormConf()) + || !ObjectUtil.equal(createReqDTO.getFormFields(), oldProcessDefinitionExt.getFormFields()) + || !ObjectUtil.equal(createReqDTO.getFormCustomCreatePath(), oldProcessDefinitionExt.getFormCustomCreatePath()) + || !ObjectUtil.equal(createReqDTO.getFormCustomViewPath(), oldProcessDefinitionExt.getFormCustomViewPath())) { + return false; + } + // 校验 BPMN XML 信息 + BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes()); + BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId()); + // TODO 貌似 flowable 不修改这个也不同。需要看看。 sourceSystemId 不同 + if (FlowableUtils.equals(oldModel, newModel)) { + return false; + } + // 最终发现都一致,则返回 true + return true; + } + + /** + * 构建对应的 BPMN Model + * + * @param bpmnBytes 原始的 BPMN XML 字节数组 + * @return BPMN Model + */ + private BpmnModel buildBpmnModel(byte[] bpmnBytes) { + // 转换成 BpmnModel 对象 + BpmnXMLConverter converter = new BpmnXMLConverter(); + return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true); + } + + @Override + public BpmProcessDefinitionExtDO getProcessDefinitionExt(String id) { + return processDefinitionMapper.selectByProcessDefinitionId(id); + } + + @Override + public List getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO) { + // 拼接查询条件 + ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery(); + if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), listReqVO.getSuspensionState())) { + definitionQuery.suspended(); + } else if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), listReqVO.getSuspensionState())) { + definitionQuery.active(); + } + // 执行查询 + List processDefinitions = definitionQuery.list(); + if (CollUtil.isEmpty(processDefinitions)) { + return Collections.emptyList(); + } + + // 获得 BpmProcessDefinitionDO Map + List processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds( + convertList(processDefinitions, ProcessDefinition::getId)); + Map processDefinitionDOMap = convertMap(processDefinitionDOs, + BpmProcessDefinitionExtDO::getProcessDefinitionId); + // 执行查询,并返回 + return BpmProcessDefinitionConvert.INSTANCE.convertList3(processDefinitions, processDefinitionDOMap); + } + + @Override + public PageResult getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageVO) { + ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery(); + if (StrUtil.isNotBlank(pageVO.getKey())) { + definitionQuery.processDefinitionKey(pageVO.getKey()); + } + + // 执行查询 + List processDefinitions = definitionQuery.orderByProcessDefinitionVersion().desc() + .listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + + if (CollUtil.isEmpty(processDefinitions)) { + return new PageResult<>(emptyList(), definitionQuery.count()); + } + // 获得 Deployment Map + Set deploymentIds = new HashSet<>(); + processDefinitions.forEach(definition -> addIfNotNull(deploymentIds, definition.getDeploymentId())); + Map deploymentMap = getDeploymentMap(deploymentIds); + + // 获得 BpmProcessDefinitionDO Map + List processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds( + convertList(processDefinitions, ProcessDefinition::getId)); + Map processDefinitionDOMap = convertMap(processDefinitionDOs, + BpmProcessDefinitionExtDO::getProcessDefinitionId); + + // 获得 Form Map + Set formIds = convertSet(processDefinitionDOs, BpmProcessDefinitionExtDO::getFormId); + Map formMap = formService.getFormMap(formIds); + + // 拼接结果 + long definitionCount = definitionQuery.count(); + return new PageResult<>(BpmProcessDefinitionConvert.INSTANCE.convertList(processDefinitions, deploymentMap, + processDefinitionDOMap, formMap), definitionCount); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java new file mode 100644 index 000000000..051dd63d3 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.lang.Nullable; + +import javax.validation.Valid; +import java.util.List; +import java.util.Set; + +/** + * BPM 任务分配规则 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmTaskAssignRuleService { + + /** + * 获得流程定义的任务分配规则数组 + * + * @param processDefinitionId 流程定义的编号 + * @param taskDefinitionKey 流程任务定义的 Key。允许空 + * @return 任务规则数组 + */ + List getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId, + @Nullable String taskDefinitionKey); + + /** + * 获得流程模型的任务规则数组 + * + * @param modelId 流程模型的编号 + * @return 任务规则数组 + */ + List getTaskAssignRuleListByModelId(String modelId); + + /** + * 获得流程定义的任务分配规则数组 + * + * @param modelId 流程模型的编号 + * @param processDefinitionId 流程定义的编号 + * @return 任务规则数组 + */ + List getTaskAssignRuleList(String modelId, String processDefinitionId); + + /** + * 创建任务分配规则 + * + * @param reqVO 创建信息 + * @return 规则编号 + */ + Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO); + + /** + * 更新任务分配规则 + * + * @param reqVO 创建信息 + */ + void updateTaskAssignRule(@Valid BpmTaskAssignRuleUpdateReqVO reqVO); + + /** + * 判断指定流程模型和流程定义的分配规则是否相等 + * + * @param modelId 流程模型编号 + * @param processDefinitionId 流程定义编号 + * @return 是否相等 + */ + boolean isTaskAssignRulesEquals(String modelId, String processDefinitionId); + + /** + * 将流程流程模型的任务分配规则,复制一份给流程定义 + * 目的:每次流程模型部署时,都会生成一个新的流程定义,此时考虑到每次部署的流程不可变性,所以需要复制一份给该流程定义 + * + * @param fromModelId 流程模型编号 + * @param toProcessDefinitionId 流程定义编号 + */ + void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId); + + /** + * 校验流程模型的任务分配规则全部都配置了 + * 目的:如果有规则未配置,会导致流程任务找不到负责人,进而流程无法进行下去! + * + * @param id 流程模型编号 + */ + void checkTaskAssignRuleAllConfig(String id); + + /** + * 计算当前执行任务的处理人 + * + * @param execution 执行任务 + * @return 处理人的编号数组 + */ + Set calculateTaskCandidateUsers(DelegateExecution execution); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java new file mode 100644 index 000000000..aa84b83b7 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java @@ -0,0 +1,344 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; +import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.PostApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import cn.iocoder.yudao.module.system.api.permission.RoleApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.google.common.annotations.VisibleForTesting; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.UserTask; +import org.flowable.common.engine.api.FlowableException; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.*; + +import static cn.hutool.core.text.CharSequenceUtil.format; +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.convertSet; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; + +/** + * BPM 任务分配规则 Service 实现类 + */ +@Service +@Validated +@Slf4j +public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { + + @Resource + private BpmTaskAssignRuleMapper taskRuleMapper; + @Resource + @Lazy // 解决循环依赖 + private BpmModelService modelService; + @Resource + @Lazy // 解决循环依赖 + private BpmProcessDefinitionService processDefinitionService; + @Resource + private BpmUserGroupService userGroupService; + @Resource + private RoleApi roleApi; + @Resource + private DeptApi deptApi; + @Resource + private PostApi postApi; + @Resource + private AdminUserApi adminUserApi; + @Resource + private DictDataApi dictDataApi; + @Resource + private PermissionApi permissionApi; + /** + * 任务分配脚本 + */ + private Map scriptMap = Collections.emptyMap(); + + @Resource + public void setScripts(List scripts) { + this.scriptMap = convertMap(scripts, script -> script.getEnum().getId()); + } + + @Override + public List getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId, + String taskDefinitionKey) { + return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey); + } + + @Override + public List getTaskAssignRuleListByModelId(String modelId) { + return taskRuleMapper.selectListByModelId(modelId); + } + + @Override + public List getTaskAssignRuleList(String modelId, String processDefinitionId) { + // 获得规则 + List rules = Collections.emptyList(); + BpmnModel model = null; + if (StrUtil.isNotEmpty(modelId)) { + rules = getTaskAssignRuleListByModelId(modelId); + model = modelService.getBpmnModel(modelId); + } else if (StrUtil.isNotEmpty(processDefinitionId)) { + rules = getTaskAssignRuleListByProcessDefinitionId(processDefinitionId, null); + model = processDefinitionService.getBpmnModel(processDefinitionId); + } + if (model == null) { + return Collections.emptyList(); + } + // 获得用户任务,只有用户任务才可以设置分配规则 + List userTasks = FlowableUtils.getBpmnModelElements(model, UserTask.class); + if (CollUtil.isEmpty(userTasks)) { + return Collections.emptyList(); + } + // 转换数据 + return BpmTaskAssignRuleConvert.INSTANCE.convertList(userTasks, rules); + } + + @Override + public Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO) { + // 校验参数 + validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions()); + // 校验是否已经配置 + BpmTaskAssignRuleDO existRule = + taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey()); + if (existRule != null) { + throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey()); + } + + // 存储 + BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO) + .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建 + taskRuleMapper.insert(rule); + return rule.getId(); + } + + @Override + public void updateTaskAssignRule(@Valid BpmTaskAssignRuleUpdateReqVO reqVO) { + // 校验参数 + validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions()); + // 校验是否存在 + BpmTaskAssignRuleDO existRule = taskRuleMapper.selectById(reqVO.getId()); + if (existRule == null) { + throw exception(TASK_ASSIGN_RULE_NOT_EXISTS); + } + // 只允许修改流程模型的规则 + if (!Objects.equals(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL, existRule.getProcessDefinitionId())) { + throw exception(TASK_UPDATE_FAIL_NOT_MODEL); + } + + // 执行更新 + taskRuleMapper.updateById(BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO)); + } + + @Override + public boolean isTaskAssignRulesEquals(String modelId, String processDefinitionId) { + // 调用 VO 接口的原因是,过滤掉流程模型不需要的规则,保持和 copyTaskAssignRules 方法的一致性 + List modelRules = getTaskAssignRuleList(modelId, null); + List processInstanceRules = getTaskAssignRuleList(null, processDefinitionId); + if (modelRules.size() != processInstanceRules.size()) { + return false; + } + + // 遍历,匹配对应的规则 + Map processInstanceRuleMap = + CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey); + for (BpmTaskAssignRuleRespVO modelRule : modelRules) { + BpmTaskAssignRuleRespVO processInstanceRule = processInstanceRuleMap.get(modelRule.getTaskDefinitionKey()); + if (processInstanceRule == null) { + return false; + } + if (!ObjectUtil.equals(modelRule.getType(), processInstanceRule.getType()) || !ObjectUtil.equal( + modelRule.getOptions(), processInstanceRule.getOptions())) { + return false; + } + } + return true; + } + + @Override + public void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId) { + List rules = getTaskAssignRuleList(fromModelId, null); + if (CollUtil.isEmpty(rules)) { + return; + } + // 开始复制 + List newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules); + newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null).setCreateTime(null) + .setUpdateTime(null)); + taskRuleMapper.insertBatch(newRules); + } + + @Override + public void checkTaskAssignRuleAllConfig(String id) { + // 一个用户任务都没配置,所以无需配置规则 + List taskAssignRules = getTaskAssignRuleList(id, null); + if (CollUtil.isEmpty(taskAssignRules)) { + return; + } + // 校验未配置规则的任务 + taskAssignRules.forEach(rule -> { + if (CollUtil.isEmpty(rule.getOptions())) { + throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, rule.getTaskDefinitionName()); + } + }); + } + + private void validTaskAssignRuleOptions(Integer type, Set options) { + if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) { + roleApi.validRoles(options); + } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), + BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) { + deptApi.validDepts(options); + } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) { + postApi.validPosts(options); + } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER.getType())) { + adminUserApi.validUsers(options); + } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_GROUP.getType())) { + userGroupService.validUserGroups(options); + } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) { + dictDataApi.validDictDatas(DictTypeConstants.TASK_ASSIGN_SCRIPT, + CollectionUtils.convertSet(options, String::valueOf)); + } else { + throw new IllegalArgumentException(format("未知的规则类型({})", type)); + } + } + + @Override + @DataPermission(enable = false) // 忽略数据权限,不然分配会存在问题 + public Set calculateTaskCandidateUsers(DelegateExecution execution) { + BpmTaskAssignRuleDO rule = getTaskRule(execution); + return calculateTaskCandidateUsers(execution, rule); + } + + @VisibleForTesting + BpmTaskAssignRuleDO getTaskRule(DelegateExecution execution) { + List taskRules = getTaskAssignRuleListByProcessDefinitionId( + execution.getProcessDefinitionId(), execution.getCurrentActivityId()); + if (CollUtil.isEmpty(taskRules)) { + throw new FlowableException(format("流程任务({}/{}/{}) 找不到符合的任务规则", + execution.getId(), execution.getProcessDefinitionId(), execution.getCurrentActivityId())); + } + if (taskRules.size() > 1) { + throw new FlowableException(format("流程任务({}/{}/{}) 找到过多任务规则({})", + execution.getId(), execution.getProcessDefinitionId(), execution.getCurrentActivityId())); + } + return taskRules.get(0); + } + + @VisibleForTesting + Set calculateTaskCandidateUsers(DelegateExecution execution, BpmTaskAssignRuleDO rule) { + Set assigneeUserIds = null; + if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByRole(rule); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByDeptMember(rule); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(rule); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByPost(rule); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByUser(rule); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByUserGroup(rule); + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByScript(execution, rule); + } + + // 移除被禁用的用户 + removeDisableUsers(assigneeUserIds); + // 如果候选人为空,抛出异常 + if (CollUtil.isEmpty(assigneeUserIds)) { + log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]", execution.getId(), + execution.getProcessDefinitionId(), execution.getCurrentActivityId(), toJsonString(rule)); + throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER); + } + return assigneeUserIds; + } + + private Set calculateTaskCandidateUsersByRole(BpmTaskAssignRuleDO rule) { + return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions()).getCheckedData(); + } + + private Set calculateTaskCandidateUsersByDeptMember(BpmTaskAssignRuleDO rule) { + List users = adminUserApi.getUsersByDeptIds(rule.getOptions()).getCheckedData(); + return convertSet(users, AdminUserRespDTO::getId); + } + + private Set calculateTaskCandidateUsersByDeptLeader(BpmTaskAssignRuleDO rule) { + List depts = deptApi.getDepts(rule.getOptions()).getCheckedData(); + return convertSet(depts, DeptRespDTO::getLeaderUserId); + } + + private Set calculateTaskCandidateUsersByPost(BpmTaskAssignRuleDO rule) { + List users = adminUserApi.getUsersByPostIds(rule.getOptions()).getCheckedData(); + return convertSet(users, AdminUserRespDTO::getId); + } + + private Set calculateTaskCandidateUsersByUser(BpmTaskAssignRuleDO rule) { + return rule.getOptions(); + } + + private Set calculateTaskCandidateUsersByUserGroup(BpmTaskAssignRuleDO rule) { + List userGroups = userGroupService.getUserGroupList(rule.getOptions()); + Set userIds = new HashSet<>(); + userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds())); + return userIds; + } + + private Set calculateTaskCandidateUsersByScript(DelegateExecution execution, BpmTaskAssignRuleDO rule) { + // 获得对应的脚本 + List scripts = new ArrayList<>(rule.getOptions().size()); + rule.getOptions().forEach(id -> { + BpmTaskAssignScript script = scriptMap.get(id); + if (script == null) { + throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id); + } + scripts.add(script); + }); + // 逐个计算任务 + Set userIds = new HashSet<>(); + scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(execution))); + return userIds; + } + + @VisibleForTesting + void removeDisableUsers(Set assigneeUserIds) { + if (CollUtil.isEmpty(assigneeUserIds)) { + return; + } + Map userMap = adminUserApi.getUserMap(assigneeUserIds); + assigneeUserIds.removeIf(id -> { + AdminUserRespDTO user = userMap.get(id); + return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); + }); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java new file mode 100644 index 000000000..da185105e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupService.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import java.util.*; +import javax.validation.*; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +/** + * 用户组 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmUserGroupService { + + /** + * 创建用户组 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createUserGroup(@Valid BpmUserGroupCreateReqVO createReqVO); + + /** + * 更新用户组 + * + * @param updateReqVO 更新信息 + */ + void updateUserGroup(@Valid BpmUserGroupUpdateReqVO updateReqVO); + + /** + * 删除用户组 + * + * @param id 编号 + */ + void deleteUserGroup(Long id); + + /** + * 获得用户组 + * + * @param id 编号 + * @return 用户组 + */ + BpmUserGroupDO getUserGroup(Long id); + + /** + * 获得用户组列表 + * + * @param ids 编号 + * @return 用户组列表 + */ + List getUserGroupList(Collection ids); + + /** + * 获得指定状态的用户组列表 + * + * @param status 状态 + * @return 用户组列表 + */ + List getUserGroupListByStatus(Integer status); + + /** + * 获得用户组分页 + * + * @param pageReqVO 分页查询 + * @return 用户组分页 + */ + PageResult getUserGroupPage(BpmUserGroupPageReqVO pageReqVO); + + /** + * 校验用户组们是否有效。如下情况,视为无效: + * 1. 用户组编号不存在 + * 2. 用户组被禁用 + * + * @param ids 用户组编号数组 + */ + void validUserGroups(Set ids); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java new file mode 100644 index 000000000..e6a93b45d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceImpl.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; +import cn.iocoder.yudao.module.bpm.convert.definition.BpmUserGroupConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmUserGroupMapper; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; + +/** + * 用户组 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class BpmUserGroupServiceImpl implements BpmUserGroupService { + + @Resource + private BpmUserGroupMapper userGroupMapper; + + @Override + public Long createUserGroup(BpmUserGroupCreateReqVO createReqVO) { + // 插入 + BpmUserGroupDO userGroup = BpmUserGroupConvert.INSTANCE.convert(createReqVO); + userGroupMapper.insert(userGroup); + // 返回 + return userGroup.getId(); + } + + @Override + public void updateUserGroup(BpmUserGroupUpdateReqVO updateReqVO) { + // 校验存在 + this.validateUserGroupExists(updateReqVO.getId()); + // 更新 + BpmUserGroupDO updateObj = BpmUserGroupConvert.INSTANCE.convert(updateReqVO); + userGroupMapper.updateById(updateObj); + } + + @Override + public void deleteUserGroup(Long id) { + // 校验存在 + this.validateUserGroupExists(id); + // 删除 + userGroupMapper.deleteById(id); + } + + private void validateUserGroupExists(Long id) { + if (userGroupMapper.selectById(id) == null) { + throw ServiceExceptionUtil.exception(USER_GROUP_NOT_EXISTS); + } + } + + @Override + public BpmUserGroupDO getUserGroup(Long id) { + return userGroupMapper.selectById(id); + } + + @Override + public List getUserGroupList(Collection ids) { + return userGroupMapper.selectBatchIds(ids); + } + + + @Override + public List getUserGroupListByStatus(Integer status) { + return userGroupMapper.selectListByStatus(status); + } + + @Override + public PageResult getUserGroupPage(BpmUserGroupPageReqVO pageReqVO) { + return userGroupMapper.selectPage(pageReqVO); + } + + @Override + public void validUserGroups(Set ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 获得用户组信息 + List userGroups = userGroupMapper.selectBatchIds(ids); + Map userGroupMap = CollectionUtils.convertMap(userGroups, BpmUserGroupDO::getId); + // 校验 + ids.forEach(id -> { + BpmUserGroupDO userGroup = userGroupMap.get(id); + if (userGroup == null) { + throw ServiceExceptionUtil.exception(USER_GROUP_NOT_EXISTS); + } + if (!CommonStatusEnum.ENABLE.getStatus().equals(userGroup.getStatus())) { + throw exception(USER_GROUP_IS_DISABLE, userGroup.getName()); + } + }); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmFormFieldRespDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmFormFieldRespDTO.java new file mode 100644 index 000000000..1606192ce --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmFormFieldRespDTO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.bpm.service.definition.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * Bpm 表单的 Field 表单项 Response DTO + * 字段的定义,可见 https://github.com/JakHuang/form-generator/issues/46 文档 + * + * @author 芋道源码 + */ +@Data +public class BpmFormFieldRespDTO { + + /** + * 表单标题 + */ + private String label; + /** + * 表单字段的属性名,可自定义 + */ + @JsonProperty(value = "vModel") + private String vModel; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java new file mode 100644 index 000000000..3a36b0eeb --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.service.definition.dto; + +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import lombok.Data; + +/** + * BPM 流程 MetaInfo Response DTO + * 主要用于 { Model#setMetaInfo(String)} 的存储 + * + * @author 芋道源码 + */ +@Data +public class BpmModelMetaInfoRespDTO { + + /** + * 流程描述 + */ + private String description; + /** + * 表单类型 + */ + private Integer formType; + /** + * 表单编号 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + */ + private Long formId; + /** + * 自定义表单的提交路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomCreatePath; + /** + * 自定义表单的查看路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomViewPath; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java new file mode 100644 index 000000000..8b2d22ad5 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/dto/BpmProcessDefinitionCreateReqDTO.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.module.bpm.service.definition.dto; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import lombok.Data; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Objects; + +/** + * 流程定义创建 Request DTO + */ +@Data +public class BpmProcessDefinitionCreateReqDTO { + + // ========== 模型相关 ========== + + /** + * 流程模型的编号 + */ + @NotEmpty(message = "流程模型编号不能为空") + private String modelId; + /** + * 流程标识 + */ + @NotEmpty(message = "流程标识不能为空") + private String key; + /** + * 流程名称 + */ + @NotEmpty(message = "流程名称不能为空") + private String name; + /** + * 流程描述 + */ + private String description; + /** + * 流程分类 + * 参见 bpm_model_category 数据字典 + */ + @NotEmpty(message = "流程分类不能为空") + private String category; + /** + * BPMN XML + */ + @NotEmpty(message = "BPMN XML 不能为空") + private byte[] bpmnBytes; + + // ========== 表单相关 ========== + + /** + * 表单类型 + */ + @NotNull(message = "表单类型不能为空") + private Integer formType; + /** + * 动态表单编号 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + */ + private Long formId; + /** + * 表单的配置 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + */ + private String formConf; + /** + * 表单项的数组 + * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时 + */ + private List formFields; + /** + * 自定义表单的提交路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomCreatePath; + /** + * 自定义表单的查看路径,使用 Vue 的路由地址 + * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时 + */ + private String formCustomViewPath; + + @AssertTrue(message = "流程表单信息不全") + public boolean isNormalFormTypeValid() { + // 如果非业务表单,则直接通过 + if (!Objects.equals(formType, BpmModelFormTypeEnum.NORMAL.getType())) { + return true; + } + return formId != null && StrUtil.isNotEmpty(formConf) && CollUtil.isNotEmpty(formFields); + } + + @AssertTrue(message = "业务表单信息不全") + public boolean isNormalCustomTypeValid() { + // 如果非业务表单,则直接通过 + if (!Objects.equals(formType, BpmModelFormTypeEnum.CUSTOM.getType())) { + return true; + } + return StrUtil.isNotEmpty(formCustomCreatePath) && StrUtil.isNotEmpty(formCustomViewPath); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageService.java new file mode 100644 index 000000000..ff51ae306 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageService.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.service.message; + +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; + +import javax.validation.Valid; + +/** + * BPM 消息 Service 接口 + * + * TODO 芋艿:未来支持消息的可配置;不同的流程,在什么场景下,需要发送什么消息,消息的内容是什么; + * + * @author 芋道源码 + */ +public interface BpmMessageService { + + /** + * 发送流程实例被通过的消息 + * + * @param reqDTO 发送信息 + */ + void sendMessageWhenProcessInstanceApprove(@Valid BpmMessageSendWhenProcessInstanceApproveReqDTO reqDTO); + + /** + * 发送流程实例被不通过的消息 + * + * @param reqDTO 发送信息 + */ + void sendMessageWhenProcessInstanceReject(@Valid BpmMessageSendWhenProcessInstanceRejectReqDTO reqDTO); + + /** + * 发送任务被分配的消息 + * + * @param reqDTO 发送信息 + */ + void sendMessageWhenTaskAssigned(@Valid BpmMessageSendWhenTaskCreatedReqDTO reqDTO); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageServiceImpl.java new file mode 100644 index 000000000..89dfd1227 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageServiceImpl.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.bpm.service.message; + +import cn.iocoder.yudao.framework.web.config.WebProperties; +import cn.iocoder.yudao.module.bpm.convert.message.BpmMessageConvert; +import cn.iocoder.yudao.module.bpm.enums.message.BpmMessageEnum; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; +import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +/** + * BPM 消息 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class BpmMessageServiceImpl implements BpmMessageService { + + @Resource + private SmsSendApi smsSendApi; + + @Resource + private WebProperties webProperties; + + @Override + public void sendMessageWhenProcessInstanceApprove(BpmMessageSendWhenProcessInstanceApproveReqDTO reqDTO) { + Map templateParams = new HashMap<>(); + templateParams.put("processInstanceName", reqDTO.getProcessInstanceName()); + templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId())); + smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getStartUserId(), + BpmMessageEnum.PROCESS_INSTANCE_APPROVE.getSmsTemplateCode(), templateParams)); + } + + @Override + public void sendMessageWhenProcessInstanceReject(BpmMessageSendWhenProcessInstanceRejectReqDTO reqDTO) { + Map templateParams = new HashMap<>(); + templateParams.put("processInstanceName", reqDTO.getProcessInstanceName()); + templateParams.put("reason", reqDTO.getReason()); + templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId())); + smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getStartUserId(), + BpmMessageEnum.PROCESS_INSTANCE_REJECT.getSmsTemplateCode(), templateParams)); + } + + @Override + public void sendMessageWhenTaskAssigned(BpmMessageSendWhenTaskCreatedReqDTO reqDTO) { + Map templateParams = new HashMap<>(); + templateParams.put("processInstanceName", reqDTO.getProcessInstanceName()); + templateParams.put("taskName", reqDTO.getTaskName()); + templateParams.put("startUserNickname", reqDTO.getStartUserNickname()); + templateParams.put("detailUrl", getProcessInstanceDetailUrl(reqDTO.getProcessInstanceId())); + smsSendApi.sendSingleSmsToAdmin(BpmMessageConvert.INSTANCE.convert(reqDTO.getStartUserId(), + BpmMessageEnum.TASK_ASSIGNED.getSmsTemplateCode(), templateParams)); + } + + private String getProcessInstanceDetailUrl(String taskId) { + return webProperties.getAdminUi().getUrl() + "/bpm/process-instance/detail?id=" + taskId; + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceApproveReqDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceApproveReqDTO.java new file mode 100644 index 000000000..7c37734f9 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceApproveReqDTO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.bpm.service.message.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * BPM 发送流程实例被通过 Request DTO + */ +@Data +public class BpmMessageSendWhenProcessInstanceApproveReqDTO { + + /** + * 流程实例的编号 + */ + @NotEmpty(message = "流程实例的编号不能为空") + private String processInstanceId; + /** + * 流程实例的名字 + */ + @NotEmpty(message = "流程实例的名字不能为空") + private String processInstanceName; + @NotNull(message = "发起人的用户编号") + private Long startUserId; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceRejectReqDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceRejectReqDTO.java new file mode 100644 index 000000000..69a266b68 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenProcessInstanceRejectReqDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.service.message.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * BPM 发送流程实例被不通过 Request DTO + */ +@Data +public class BpmMessageSendWhenProcessInstanceRejectReqDTO { + + /** + * 流程实例的编号 + */ + @NotEmpty(message = "流程实例的编号不能为空") + private String processInstanceId; + /** + * 流程实例的名字 + */ + @NotEmpty(message = "流程实例的名字不能为空") + private String processInstanceName; + @NotNull(message = "发起人的用户编号") + private Long startUserId; + + /** + * 不通过理由 + */ + @NotEmpty(message = "不通过理由不能为空") + private String reason; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenTaskCreatedReqDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenTaskCreatedReqDTO.java new file mode 100644 index 000000000..7cb0e3d70 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/dto/BpmMessageSendWhenTaskCreatedReqDTO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.bpm.service.message.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * BPM 发送任务被分配 Request DTO + */ +@Data +public class BpmMessageSendWhenTaskCreatedReqDTO { + + /** + * 流程实例的编号 + */ + @NotEmpty(message = "流程实例的编号不能为空") + private String processInstanceId; + /** + * 流程实例的名字 + */ + @NotEmpty(message = "流程实例的名字不能为空") + private String processInstanceName; + @NotNull(message = "发起人的用户编号") + private Long startUserId; + @NotEmpty(message = "发起人的昵称") + private String startUserNickname; + + /** + * 流程任务的编号 + */ + @NotEmpty(message = "流程任务的编号不能为空") + private String taskId; + /** + * 流程任务的名字 + */ + @NotEmpty(message = "流程任务的名字不能为空") + private String taskName; + + /** + * 审批人的用户编号 + */ + @NotNull(message = "审批人的用户编号不能为空") + private Long assigneeUserId; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveService.java new file mode 100644 index 000000000..a851f403c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveService.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; + +import javax.validation.Valid; + +/** + * 请假申请 Service 接口 + * + * @author jason + * @author 芋道源码 + */ +public interface BpmOALeaveService { + + /** + * 创建请假申请 + * + * @param userId 用户编号 + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createLeave(Long userId, @Valid BpmOALeaveCreateReqVO createReqVO); + + /** + * 更新请假申请的状态 + * + * @param id 编号 + * @param result 结果 + */ + void updateLeaveResult(Long id, Integer result); + + /** + * 获得请假申请 + * + * @param id 编号 + * @return 请假申请 + */ + BpmOALeaveDO getLeave(Long id); + + /** + * 获得请假申请分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页查询 + * @return 请假申请分页 + */ + PageResult getLeavePage(Long userId, BpmOALeavePageReqVO pageReqVO); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java new file mode 100644 index 000000000..d0aadd95e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + +import cn.hutool.core.date.DateUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeaveCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOALeavePageReqVO; +import cn.iocoder.yudao.module.bpm.convert.oa.BpmOALeaveConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOALeaveMapper; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_LEAVE_NOT_EXISTS; + +/** + * OA 请假申请 Service 实现类 + * + * @author jason + * @author 芋道源码 + */ +@Service +@Validated +public class BpmOALeaveServiceImpl implements BpmOALeaveService { + + /** + * OA 请假对应的流程定义 KEY + */ + public static final String PROCESS_KEY = "oa_leave"; + + @Resource + private BpmOALeaveMapper leaveMapper; + + @Resource + private BpmProcessInstanceApi processInstanceApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createLeave(Long userId, BpmOALeaveCreateReqVO createReqVO) { + // 插入 OA 请假单 + long day = DateUtil.betweenDay(createReqVO.getStartTime(), createReqVO.getEndTime(), false); + BpmOALeaveDO leave = BpmOALeaveConvert.INSTANCE.convert(createReqVO).setUserId(userId).setDay(day) + .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); + leaveMapper.insert(leave); + + // 发起 BPM 流程 + Map processInstanceVariables = new HashMap<>(); + processInstanceVariables.put("day", day); + String processInstanceId = processInstanceApi.createProcessInstance(userId, + new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) + .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(leave.getId()))); + + // 将工作流的编号,更新到 OA 请假单中 + leaveMapper.updateById(new BpmOALeaveDO().setId(leave.getId()).setProcessInstanceId(processInstanceId)); + return leave.getId(); + } + + @Override + public void updateLeaveResult(Long id, Integer result) { + validateLeaveExists(id); + leaveMapper.updateById(new BpmOALeaveDO().setId(id).setResult(result)); + } + + private void validateLeaveExists(Long id) { + if (leaveMapper.selectById(id) == null) { + throw exception(OA_LEAVE_NOT_EXISTS); + } + } + + @Override + public BpmOALeaveDO getLeave(Long id) { + return leaveMapper.selectById(id); + } + + @Override + public PageResult getLeavePage(Long userId, BpmOALeavePageReqVO pageReqVO) { + return leaveMapper.selectPage(userId, pageReqVO); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveResultListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveResultListener.java new file mode 100644 index 000000000..2354070f0 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveResultListener.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.bpm.service.oa.listener; + +import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent; +import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventListener; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveServiceImpl; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * OA 请假单的结果的监听器实现类 + * + * @author 芋道源码 + */ +@Component +public class BpmOALeaveResultListener extends BpmProcessInstanceResultEventListener { + + @Resource + private BpmOALeaveService leaveService; + + @Override + protected String getProcessDefinitionKey() { + return BpmOALeaveServiceImpl.PROCESS_KEY; + } + + @Override + protected void onEvent(BpmProcessInstanceResultEvent event) { + leaveService.updateLeaveResult(Long.parseLong(event.getBusinessKey()), event.getResult()); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityService.java new file mode 100644 index 000000000..4bed16413 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityService.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO; +import org.flowable.engine.history.HistoricActivityInstance; + +import java.util.List; + +/** + * BPM 活动实例 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmActivityService { + + /** + * 获得指定流程实例的活动实例列表 + * + * @param processInstanceId 流程实例的编号 + * @return 活动实例列表 + */ + List getActivityListByProcessInstanceId(String processInstanceId); + + /** + * 获得执行编号对应的活动实例 + * + * @param executionId 执行编号 + * @return 活动实例 + */ + List getHistoricActivityListByExecutionId(String executionId); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityServiceImpl.java new file mode 100644 index 000000000..c06445efa --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityServiceImpl.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO; +import cn.iocoder.yudao.module.bpm.convert.task.BpmActivityConvert; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.HistoryService; +import org.flowable.engine.history.HistoricActivityInstance; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + + +/** + * BPM 活动实例 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Slf4j +@Validated +public class BpmActivityServiceImpl implements BpmActivityService { + + @Resource + private HistoryService historyService; + + @Override + public List getActivityListByProcessInstanceId(String processInstanceId) { + List activityList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId).list(); + return BpmActivityConvert.INSTANCE.convertList(activityList); + } + + @Override + public List getHistoricActivityListByExecutionId(String executionId) { + return historyService.createHistoricActivityInstanceQuery().executionId(executionId).list(); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java new file mode 100644 index 000000000..23340ad19 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java @@ -0,0 +1,147 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; +import org.flowable.engine.delegate.event.FlowableCancelledEvent; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.runtime.ProcessInstance; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 流程实例 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmProcessInstanceService { + + /** + * 获得流程实例 + * + * @param id 流程实例的编号 + * @return 流程实例 + */ + ProcessInstance getProcessInstance(String id); + + /** + * 获得流程实例列表 + * + * @param ids 流程实例的编号集合 + * @return 流程实例列表 + */ + List getProcessInstances(Set ids); + + /** + * 获得流程实例 Map + * + * @param ids 流程实例的编号集合 + * @return 流程实例列表 Map + */ + default Map getProcessInstanceMap(Set ids) { + return CollectionUtils.convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId); + } + + /** + * 获得流程实例的分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页请求 + * @return 流程实例的分页 + */ + PageResult getMyProcessInstancePage(Long userId, + @Valid BpmProcessInstanceMyPageReqVO pageReqVO); + /** + * 创建流程实例(提供给前端) + * + * @param userId 用户编号 + * @param createReqVO 创建信息 + * @return 实例的编号 + */ + String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO); + + /** + * 创建流程实例(提供给内部) + * + * @param userId 用户编号 + * @param createReqDTO 创建信息 + * @return 实例的编号 + */ + String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO); + + /** + * 获得流程实例 VO 信息 + * + * @param id 流程实例的编号 + * @return 流程实例 + */ + BpmProcessInstanceRespVO getProcessInstanceVO(String id); + + /** + * 取消流程实例 + * + * @param userId 用户编号 + * @param cancelReqVO 取消信息 + */ + void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO); + + /** + * 获得历史的流程实例 + * + * @param id 流程实例的编号 + * @return 历史的流程实例 + */ + HistoricProcessInstance getHistoricProcessInstance(String id); + + /** + * 获得历史的流程实例列表 + * + * @param ids 流程实例的编号集合 + * @return 历史的流程实例列表 + */ + List getHistoricProcessInstances(Set ids); + + /** + * 获得历史的流程实例 Map + * + * @param ids 流程实例的编号集合 + * @return 历史的流程实例列表 Map + */ + default Map getHistoricProcessInstanceMap(Set ids) { + return CollectionUtils.convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId); + } + + /** + * 创建 ProcessInstance 拓展记录 + * + * @param instance 流程任务 + */ + void createProcessInstanceExt(ProcessInstance instance); + + /** + * 更新 ProcessInstance 拓展记录为取消 + * + * @param event 流程取消事件 + */ + void updateProcessInstanceExtCancel(FlowableCancelledEvent event); + + /** + * 更新 ProcessInstance 拓展记录为完成 + * + * @param instance 流程任务 + */ + void updateProcessInstanceExtComplete(ProcessInstance instance); + + /** + * 更新 ProcessInstance 拓展记录为不通过 + * + * @param id 流程编号 + * @param reason 理由。例如说,审批不通过时,需要传递该值 + */ + void updateProcessInstanceExtReject(String id, String reason); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java new file mode 100644 index 000000000..076ecd8fc --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 创建流程实例 ProcessInstance instance = runtimeService.startProcessInstanceById(definition.getId(), businessKey, variables); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables)); return instance.getId(); } } \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java new file mode 100644 index 000000000..fc45887b7 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java @@ -0,0 +1,131 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; +import org.flowable.task.api.Task; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +/** + * 流程任务实例 Service 接口 + * + * @author jason + * @author 芋道源码 + */ +public interface BpmTaskService { + + /** + * 获得待办的流程任务分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页请求 + * + * @return 流程任务分页 + */ + PageResult getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO); + + /** + * 获得已办的流程任务分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页请求 + * + * @return 流程任务分页 + */ + PageResult getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageReqVO); + + /** + * 获得流程任务 Map + * + * @param processInstanceIds 流程实例的编号数组 + * + * @return 流程任务 Map + */ + default Map> getTaskMapByProcessInstanceIds(List processInstanceIds) { + return CollectionUtils.convertMultiMap(getTasksByProcessInstanceIds(processInstanceIds), + Task::getProcessInstanceId); + } + + /** + * 获得流程任务列表 + * + * @param processInstanceIds 流程实例的编号数组 + * + * @return 流程任务列表 + */ + List getTasksByProcessInstanceIds(List processInstanceIds); + + /** + * 获得指令流程实例的流程任务列表,包括所有状态的 + * + * @param processInstanceId 流程实例的编号 + * + * @return 流程任务列表 + */ + List getTaskListByProcessInstanceId(String processInstanceId); + + /** + * 通过任务 + * + * @param userId 用户编号 + * @param reqVO 通过请求 + */ + void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO); + + /** + * 不通过任务 + * + * @param userId 用户编号 + * @param reqVO 不通过请求 + */ + void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO); + + /** + * 将流程任务分配给指定用户 + * + * @param userId 用户编号 + * @param reqVO 分配请求 + */ + void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO); + + /** + * 将流程任务分配给指定用户 + * + * @param id 流程任务编号 + * @param userId 用户编号 + */ + void updateTaskAssignee(String id, Long userId); + + /** + * 创建 Task 拓展记录 + * + * @param task 任务实体 + */ + void createTaskExt(Task task); + + /** + * 更新 Task 拓展记录为完成 + * + * @param task 任务实体 + */ + void updateTaskExtComplete(Task task); + + /** + * 更新 Task 拓展记录为已取消 + * + * @param taskId 任务的编号 + */ + void updateTaskExtCancel(String taskId); + + /** + * 更新 Task 拓展记录,并发送通知 + * + * @param task 任务实体 + */ + void updateTaskExtAssign(Task task); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java new file mode 100644 index 000000000..b2c12bd2b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -0,0 +1,315 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.PageUtils; +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.dal.dataobject.task.BpmTaskExtDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.HistoryService; +import org.flowable.engine.TaskService; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskQuery; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.flowable.task.api.history.HistoricTaskInstanceQuery; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.*; + +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.convertSet; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; + +/** + * 流程任务实例 Service 实现类 + * + * @author 芋道源码 + * @author jason + */ +@Slf4j +@Service +public class BpmTaskServiceImpl implements BpmTaskService { + + @Resource + private TaskService taskService; + @Resource + private HistoryService historyService; + + @Resource + private BpmProcessInstanceService processInstanceService; + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + @Resource + private BpmTaskExtMapper taskExtMapper; + @Resource + private BpmMessageService messageService; + + @Override + public PageResult getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) { + // 查询待办任务 + TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己 + .orderByTaskCreateTime().desc(); // 创建时间倒序 + if (StrUtil.isNotBlank(pageVO.getName())) { + taskQuery.taskNameLike("%" + pageVO.getName() + "%"); + } + if (pageVO.getBeginCreateTime() != null) { + taskQuery.taskCreatedAfter(pageVO.getBeginCreateTime()); + } + if (pageVO.getEndCreateTime() != null) { + taskQuery.taskCreatedBefore(pageVO.getEndCreateTime()); + } + // 执行查询 + List tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + if (CollUtil.isEmpty(tasks)) { + return PageResult.empty(taskQuery.count()); + } + + // 获得 ProcessInstance Map + Map processInstanceMap = + processInstanceService.getProcessInstanceMap(convertSet(tasks, Task::getProcessInstanceId)); + // 获得 User Map + Map userMap = adminUserApi.getUserMap( + convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); + // 拼接结果 + return new PageResult<>(BpmTaskConvert.INSTANCE.convertList1(tasks, processInstanceMap, userMap), + taskQuery.count()); + } + + @Override + public PageResult getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) { + // 查询已办任务 + HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成 + .taskAssignee(String.valueOf(userId)) // 分配给自己 + .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序 + if (StrUtil.isNotBlank(pageVO.getName())) { + taskQuery.taskNameLike("%" + pageVO.getName() + "%"); + } + if (pageVO.getBeginCreateTime() != null) { + taskQuery.taskCreatedAfter(pageVO.getBeginCreateTime()); + } + if (pageVO.getEndCreateTime() != null) { + taskQuery.taskCreatedBefore(pageVO.getEndCreateTime()); + } + // 执行查询 + List tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); + if (CollUtil.isEmpty(tasks)) { + return PageResult.empty(taskQuery.count()); + } + + // 获得 TaskExtDO Map + List bpmTaskExtDOs = + taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId)); + Map bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId); + // 获得 ProcessInstance Map + Map historicProcessInstanceMap = + processInstanceService.getHistoricProcessInstanceMap( + convertSet(tasks, HistoricTaskInstance::getProcessInstanceId)); + // 获得 User Map + Map userMap = adminUserApi.getUserMap( + convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); + // 拼接结果 + return new PageResult<>( + BpmTaskConvert.INSTANCE.convertList2(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, userMap), + taskQuery.count()); + } + + @Override + public List getTasksByProcessInstanceIds(List processInstanceIds) { + if (CollUtil.isEmpty(processInstanceIds)) { + return Collections.emptyList(); + } + return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list(); + } + + @Override + public List getTaskListByProcessInstanceId(String processInstanceId) { + // 获得任务列表 + List tasks = historyService.createHistoricTaskInstanceQuery() + .processInstanceId(processInstanceId) + .orderByHistoricTaskInstanceStartTime().desc() // 创建时间倒序 + .list(); + if (CollUtil.isEmpty(tasks)) { + return Collections.emptyList(); + } + + // 获得 TaskExtDO Map + List bpmTaskExtDOs = taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId)); + Map bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId); + // 获得 ProcessInstance Map + HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId); + // 获得 User Map + Set userIds = convertSet(tasks, task -> NumberUtils.parseLong(task.getAssignee())); + userIds.add(NumberUtils.parseLong(processInstance.getStartUserId())); + Map userMap = adminUserApi.getUserMap(userIds); + // 获得 Dept Map + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + + // 拼接数据 + return BpmTaskConvert.INSTANCE.convertList3(tasks, bpmTaskExtDOMap, processInstance, userMap, deptMap); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) { + // 校验任务存在 + Task task = checkTask(userId, reqVO.getId()); + // 校验流程实例存在 + ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); + if (instance == null) { + throw exception(PROCESS_INSTANCE_NOT_EXISTS); + } + + // 完成任务,审批通过 + taskService.complete(task.getId(), instance.getProcessVariables()); + + // 更新任务拓展表为通过 + taskExtMapper.updateByTaskId( + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) + .setReason(reqVO.getReason())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) { + Task task = checkTask(userId, reqVO.getId()); + // 校验流程实例存在 + ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); + if (instance == null) { + throw exception(PROCESS_INSTANCE_NOT_EXISTS); + } + + // 更新流程实例为不通过 + processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getReason()); + + // 更新任务拓展表为不通过 + taskExtMapper.updateByTaskId( + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult()) + .setEndTime(new Date()).setReason(reqVO.getReason())); + } + + @Override + public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) { + // 校验任务存在 + Task task = checkTask(userId, reqVO.getId()); + // 更新负责人 + updateTaskAssignee(task.getId(), reqVO.getAssigneeUserId()); + } + + @Override + public void updateTaskAssignee(String id, Long userId) { + taskService.setAssignee(id, String.valueOf(userId)); + } + + /** + * 校验任务是否存在, 并且是否是分配给自己的任务 + * + * @param userId 用户 id + * @param taskId task id + */ + private Task checkTask(Long userId, String taskId) { + Task task = getTask(taskId); + if (task == null) { + throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS); + } + if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) { + throw exception(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF); + } + return task; + } + + @Override + public void createTaskExt(Task task) { + BpmTaskExtDO taskExtDO = + BpmTaskConvert.INSTANCE.convert2TaskExt(task).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); + taskExtMapper.insert(taskExtDO); + } + + @Override + public void updateTaskExtComplete(Task task) { + BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task) + .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) // 不设置也问题不大,因为 Complete 一般是审核通过,已经设置 + .setEndTime(new Date()); + taskExtMapper.updateByTaskId(taskExtDO); + } + + @Override + public void updateTaskExtCancel(String taskId) { + // 需要在事务提交后,才进行查询。不然查询不到历史的原因 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + + @Override + public void afterCommit() { + // 可能只是活动,不是任务,所以查询不到 + HistoricTaskInstance task = getHistoricTask(taskId); + if (task == null) { + return; + } + + // 如果任务拓展表已经是完成的状态,则跳过 + BpmTaskExtDO taskExt = taskExtMapper.selectByTaskId(taskId); + if (taskExt == null) { + log.error("[updateTaskExtCancel][taskId({}) 查找不到对应的记录,可能存在问题]", taskId); + return; + } + // 如果已经是最终的结果,则跳过 + if (BpmProcessInstanceResultEnum.isEndResult(taskExt.getResult())) { + log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, taskExt.getResult()); + return; + } + + // 更新任务 + taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) + .setEndTime(new Date()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason(task.getDeleteReason()))); + } + + }); + } + + @Override + public void updateTaskExtAssign(Task task) { + BpmTaskExtDO taskExtDO = + new BpmTaskExtDO().setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setTaskId(task.getId()); + taskExtMapper.updateByTaskId(taskExtDO); + // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + ProcessInstance processInstance = + processInstanceService.getProcessInstance(task.getProcessInstanceId()); + AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())).getCheckedData(); + messageService.sendMessageWhenTaskAssigned( + BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); + } + }); + } + + private Task getTask(String id) { + return taskService.createTaskQuery().taskId(id).singleResult(); + } + + private HistoricTaskInstance getHistoricTask(String id) { + return historyService.createHistoricTaskInstanceQuery().taskId(id).singleResult(); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/package-info.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/package-info.java new file mode 100644 index 000000000..eaa615302 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.bpm.service.task; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/application-dev.yaml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/application-dev.yaml new file mode 100644 index 000000000..f10e5167e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/application-dev.yaml @@ -0,0 +1,116 @@ +--- #################### 数据库相关配置 #################### +spring: + # 数据源配置项 + autoconfigure: + exclude: + - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源 + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + allow: # 设置白名单,不填则允许所有访问 + url-pattern: /druid/* + login-username: # 控制台管理用户名和密码 + login-password: + filter: + stat: + enabled: true + log-slow-sql: true # 慢 SQL 记录 + slow-sql-millis: 100 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 5 # 初始连接数 + min-idle: 10 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + primary: master + datasource: + master: + name: ruoyi-vue-pro + url: jdbc:mysql://400-infra.server.iocoder.cn:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT&nullCatalogMeansCurrent=true + driver-class-name: com.mysql.jdbc.Driver + username: root + password: 3WLiVUBEwTbvAfsh + slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 + name: ruoyi-vue-pro + url: jdbc:mysql://400-infra.server.iocoder.cn:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT&nullCatalogMeansCurrent=true + driver-class-name: com.mysql.jdbc.Driver + username: root + password: 3WLiVUBEwTbvAfsh + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 400-infra.server.iocoder.cn # 地址 + port: 6379 # 端口 + database: 1 # 数据库索引 +# password: 123456 # 密码,建议生产环境开启 + +jasypt: + encryptor: + password: yuanma # 加解密的秘钥 + +--- #################### MQ 消息队列相关配置 #################### +spring: + cloud: + stream: + rocketmq: + # RocketMQ Binder 配置项,对应 RocketMQBinderConfigurationProperties 类 + binder: + name-server: 127.0.0.1:9876 # RocketMQ Namesrv 地址 + +--- #################### 定时任务相关配置 #################### +xxl: + job: + admin: + addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址 + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项 +lock4j: + acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 + expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 + +--- #################### 监控相关配置 #################### + +# Actuator 监控端点的配置项 +management: + endpoints: + web: + base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +# Spring Boot Admin 配置项 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 设置 Spring Boot Admin Server 地址 + instance: + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + xss: + enable: false + exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系 + - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求 + - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 + demo: true # 开启演示模式 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/application-local.yaml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/application-local.yaml new file mode 100644 index 000000000..2f645bb17 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/application-local.yaml @@ -0,0 +1,143 @@ +--- #################### 数据库相关配置 #################### +spring: + # 数据源配置项 + autoconfigure: + exclude: + - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源 + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + allow: # 设置白名单,不填则允许所有访问 + url-pattern: /druid/* + login-username: # 控制台管理用户名和密码 + login-password: + filter: + stat: + enabled: true + log-slow-sql: true # 慢 SQL 记录 + slow-sql-millis: 100 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 5 # 初始连接数 + min-idle: 10 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + primary: master + datasource: + master: + name: ruoyi-vue-pro + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 +# url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例 +# url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例 +# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 +# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.master.name} # SQLServer 连接的示例 + username: root + password: 123456 +# username: sa +# password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W + slave: # 模拟从库,可根据自己需要修改 + name: ruoyi-vue-pro + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 +# url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例 +# url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.slave.name} # PostgreSQL 连接的示例 +# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 +# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.slave.name} # SQLServer 连接的示例 + username: root + password: 123456 +# username: sa +# password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 6379 # 端口 + database: 0 # 数据库索引 +# password: 123456 # 密码,建议生产环境开启 + +jasypt: + encryptor: + password: yuanma # 加解密的秘钥 + +--- #################### MQ 消息队列相关配置 #################### +spring: + cloud: + stream: + rocketmq: + # RocketMQ Binder 配置项,对应 RocketMQBinderConfigurationProperties 类 + binder: + name-server: 127.0.0.1:9876 # RocketMQ Namesrv 地址 + +--- #################### 定时任务相关配置 #################### + +xxl: + job: + admin: + addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址 + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项 +lock4j: + acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 + expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 + +--- #################### 监控相关配置 #################### + +# Actuator 监控端点的配置项 +management: + endpoints: + web: + base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +# Spring Boot Admin 配置项 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 设置 Spring Boot Admin Server 地址 + instance: + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] + +# 日志文件配置 +logging: + level: + # 配置自己写的 MyBatis Mapper 打印日志 + cn.iocoder.yudao.module.bpm.dal.mysql: debug + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + env: # 多环境的配置项 + tag: ${HOSTNAME} + captcha: + enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试 + security: + mock-enable: true + xss: + enable: false + exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系 + - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求 + - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 + access-log: # 访问日志的配置项 + enable: false + error-code: # 错误码相关配置项 + enable: false + demo: false # 关闭演示模式 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/application.yaml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/application.yaml new file mode 100644 index 000000000..f629bed50 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/application.yaml @@ -0,0 +1,120 @@ +spring: + main: + allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。 + allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Dubbo 或者 Feign 等会存在重复定义的服务 + + # Servlet 配置 + servlet: + # 文件上传相关配置项 + multipart: + max-file-size: 16MB # 单个文件大小 + max-request-size: 32MB # 设置总上传的文件大小 + mvc: + pathmatch: + matching-strategy: ANT_PATH_MATCHER # 解决 SpringFox 与 SpringBoot 2.6.x 不兼容的问题,参见 SpringFoxHandlerProviderBeanPostProcessor 类 + + # Jackson 配置项 + jackson: + serialization: + write-dates-as-timestamps: true # 设置 Date 的格式,使用时间戳 + write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401 + write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳 + fail-on-empty-beans: false # 允许序列化无属性的 Bean + + # Cache 配置项 + cache: + type: REDIS + redis: + time-to-live: 1h # 设置过期时间为 1 小时 + +# 工作流 Flowable 配置 +flowable: + # 1. false: 默认值,Flowable 启动时,对比数据库表中保存的版本,如果不匹配。将抛出异常 + # 2. true: 启动时会对数据库中所有表进行更新操作,如果表存在,不做处理,反之,自动创建表 + # 3. create_drop: 启动时自动创建表,关闭时自动删除表 + # 4. drop_create: 启动时,删除旧表,再创建新表 + database-schema-update: true # 设置为 false,可通过 https://github.com/flowable/flowable-sql 初始化 + db-history-used: true # flowable6 默认 true 生成信息表,无需手动设置 + check-process-definitions: false # 设置为 false,禁用 /resources/processes 自动部署 BPMN XML 流程 + history-level: full # full:保存历史数据的最高级别,可保存全部流程相关细节,包括流程流转各节点参数 + +# MyBatis Plus 的配置项 +mybatis-plus: + configuration: + map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 + global-config: + db-config: + id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。 +# id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库 +# id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库 +# id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解 + logic-delete-value: 1 # 逻辑已删除值(默认为 1) + logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) + type-aliases-package: ${yudao.info.base-package}.dal.dataobject + +--- #################### RPC 远程调用相关配置 #################### +dubbo: + scan: + base-packages: ${yudao.info.base-package}.api # 指定 Dubbo 服务实现类的扫描基准包 + protocol: + name: dubbo # 协议名称 + port: -1 # 协议端口,-1 表示自增端口,从 20880 开始 + registry: + address: spring-cloud://localhost # 设置使用 Spring Cloud 注册中心 + +--- #################### MQ 消息队列相关配置 #################### + +spring: + cloud: + # Spring Cloud Stream 配置项,对应 BindingServiceProperties 类 + stream: + # Spring Cloud Stream RocketMQ 配置项 + rocketmq: + # RocketMQ Binder 配置项,对应 RocketMQBinderConfigurationProperties 类 + binder: + name-server: 127.0.0.1:9876 # RocketMQ Namesrv 地址 + default: # 默认 bindings 全局配置 + producer: # RocketMQ Producer 配置项,对应 RocketMQProducerProperties 类 + group: bpm_producer_group # 生产者分组 + send-type: SYNC # 发送模式,SYNC 同步 + + # Spring Cloud Bus 配置项,对应 BusProperties 类 + bus: + enabled: true # 是否开启,默认为 true + id: ${spring.application.name}:${server.port} # 编号,Spring Cloud Alibaba 建议使用“应用:端口”的格式 + destination: springCloudBus # 目标消息队列,默认为 springCloudBus + +--- #################### 定时任务相关配置 #################### + +xxl: + job: + executor: + appname: ${spring.application.name} # 执行器 AppName + logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径 + accessToken: default_token # 执行器通讯TOKEN + +--- #################### 芋道相关配置 #################### + +yudao: + info: + version: 1.0.0 + base-package: cn.iocoder.yudao.module.bpm + web: + admin-ui: + url: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址 + swagger: + title: 管理后台 + description: 提供管理员管理的所有功能 + version: ${yudao.info.version} + base-package: ${yudao.info.base-package} + captcha: + timeout: 5m + width: 160 + height: 60 + error-code: # 错误码相关配置项 + constants-class-list: + - cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants + tenant: # 多租户相关配置项 + enable: true + +debug: false diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/bootstrap-local.yaml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/bootstrap-local.yaml new file mode 100644 index 000000000..37204cde8 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/bootstrap-local.yaml @@ -0,0 +1,23 @@ +--- #################### 注册中心相关配置 #################### + +spring: + cloud: + nacos: + server-addr: 127.0.0.1:8848 + discovery: + namespace: dev # 命名空间。这里使用 dev 开发环境 + metadata: + version: 1.0.0 # 服务实例的版本号,可用于灰度发布 + +--- #################### 配置中心相关配置 #################### + +spring: + cloud: + nacos: + # Nacos Config 配置项,对应 NacosConfigProperties 配置属性类 + config: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + name: # 使用的 Nacos 配置集的 dataId,默认为 spring.application.name + file-extension: yaml # 使用的 Nacos 配置集的 dataId 的文件拓展名,同时也是 Nacos 配置集的配置格式,默认为 properties diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/bootstrap.yaml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/bootstrap.yaml new file mode 100644 index 000000000..0f30e625a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/bootstrap.yaml @@ -0,0 +1,14 @@ +spring: + application: + name: bpm-server + + profiles: + active: local + +server: + port: 48083 + +# 日志文件配置。注意,如果 logging.file.name 不放在 bootstrap.yaml 配置文件,而是放在 application.yaml 中,会导致出现 LOG_FILE_IS_UNDEFINED 文件 +logging: + file: + name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/logback-spring.xml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..8c85ad493 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/logback-spring.xml @@ -0,0 +1,76 @@ + + + + + + + + + +       + + + ${PATTERN_DEFAULT} + + + + + + + + + + ${PATTERN_DEFAULT} + + + + ${LOG_FILE} + + + ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz} + + ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false} + + ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB} + + ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0} + + ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30} + + + + + + 0 + + 256 + + + + + + + + ${PATTERN_DEFAULT} + + + + + + + + + + + + + + + + + + + + + + diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java new file mode 100644 index 000000000..886677771 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskAssignLeaderX2Script script; + + @Mock + private AdminUserApi adminUserApi; + @Mock + private DeptApi deptApi; + @Mock + private BpmProcessInstanceService bpmProcessInstanceService; + + @Test + public void testCalculateTaskCandidateUsers_noDept() { + // 准备参数 + DelegateExecution execution = mockDelegateExecution(1L); + // mock 方法(startUser) + AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); + when(adminUserApi.getUser(eq(1L))).thenReturn(success(startUser)); + + // 调用 + Set result = script.calculateTaskCandidateUsers(execution); + // 断言 + assertEquals(0, result.size()); + } + + @Test + public void testCalculateTaskCandidateUsers_noParentDept() { + // 准备参数 + DelegateExecution execution = mockDelegateExecution(1L); + // mock 方法(startUser) + AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); + when(adminUserApi.getUser(eq(1L))).thenReturn(success(startUser)); + DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L) + .setLeaderUserId(20L)); + when(deptApi.getDept(eq(10L))).thenReturn(success(startUserDept)); + + // 调用 + Set result = script.calculateTaskCandidateUsers(execution); + // 断言 + assertEquals(asSet(20L), result); + } + + @Test + public void testCalculateTaskCandidateUsers_existParentDept() { + // 准备参数 + DelegateExecution execution = mockDelegateExecution(1L); + // mock 方法(startUser) + AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); + when(adminUserApi.getUser(eq(1L))).thenReturn(success(startUser)); + DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L) + .setLeaderUserId(20L)); + when(deptApi.getDept(eq(10L))).thenReturn(success(startUserDept)); + // mock 方法(父 dept) + DeptRespDTO parentDept = randomPojo(DeptRespDTO.class, o -> o.setId(100L).setParentId(1000L) + .setLeaderUserId(200L)); + when(deptApi.getDept(eq(100L))).thenReturn(success(parentDept)); + + // 调用 + Set result = script.calculateTaskCandidateUsers(execution); + // 断言 + assertEquals(asSet(200L), result); + } + + @SuppressWarnings("SameParameterValue") + private DelegateExecution mockDelegateExecution(Long startUserId) { + ExecutionEntityImpl execution = new ExecutionEntityImpl(); + execution.setProcessInstanceId(randomString()); + // mock 返回 startUserId + ExecutionEntityImpl processInstance = new ExecutionEntityImpl(); + processInstance.setStartUserId(String.valueOf(startUserId)); + when(bpmProcessInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))) + .thenReturn(processInstance); + return execution; + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java new file mode 100644 index 000000000..bdd88afea --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmFormServiceTest.java @@ -0,0 +1,145 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.form.BpmFormUpdateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmFormMapper; +import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmFormFieldRespDTO; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.FORM_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link BpmFormServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(BpmFormServiceImpl.class) +public class BpmFormServiceTest extends BaseDbUnitTest { + + @Resource + private BpmFormServiceImpl formService; + + @Resource + private BpmFormMapper formMapper; + + @Test + public void testCreateForm_success() { + // 准备参数 + BpmFormCreateReqVO reqVO = randomPojo(BpmFormCreateReqVO.class, o -> { + o.setConf("{}"); + o.setFields(randomFields()); + }); + + // 调用 + Long formId = formService.createForm(reqVO); + // 断言 + assertNotNull(formId); + // 校验记录的属性是否正确 + BpmFormDO form = formMapper.selectById(formId); + assertPojoEquals(reqVO, form); + } + + @Test + public void testUpdateForm_success() { + // mock 数据 + BpmFormDO dbForm = randomPojo(BpmFormDO.class, o -> { + o.setConf("{}"); + o.setFields(randomFields()); + }); + formMapper.insert(dbForm);// @Sql: 先插入出一条存在的数据 + // 准备参数 + BpmFormUpdateReqVO reqVO = randomPojo(BpmFormUpdateReqVO.class, o -> { + o.setId(dbForm.getId()); // 设置更新的 ID + o.setConf("{'yudao': 'yuanma'}"); + o.setFields(randomFields()); + }); + + // 调用 + formService.updateForm(reqVO); + // 校验是否更新正确 + BpmFormDO form = formMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, form); + } + + @Test + public void testUpdateForm_notExists() { + // 准备参数 + BpmFormUpdateReqVO reqVO = randomPojo(BpmFormUpdateReqVO.class, o -> { + o.setConf("{'yudao': 'yuanma'}"); + o.setFields(randomFields()); + }); + + // 调用, 并断言异常 + assertServiceException(() -> formService.updateForm(reqVO), FORM_NOT_EXISTS); + } + + @Test + public void testDeleteForm_success() { + // mock 数据 + BpmFormDO dbForm = randomPojo(BpmFormDO.class); + formMapper.insert(dbForm);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbForm.getId(); + + // 调用 + formService.deleteForm(id); + // 校验数据不存在了 + assertNull(formMapper.selectById(id)); + } + + @Test + public void testDeleteForm_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> formService.deleteForm(id), FORM_NOT_EXISTS); + } + + @Test + public void testGetFormPage() { + // mock 数据 + BpmFormDO dbForm = randomPojo(BpmFormDO.class, o -> { // 等会查询到 + o.setName("芋道源码"); + }); + formMapper.insert(dbForm); + // 测试 name 不匹配 + formMapper.insert(cloneIgnoreId(dbForm, o -> o.setName("源码"))); + // 准备参数 + BpmFormPageReqVO reqVO = new BpmFormPageReqVO(); + reqVO.setName("芋道"); + + // 调用 + PageResult pageResult = formService.getFormPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbForm, pageResult.getList().get(0)); + } + + private List randomFields() { + int size = RandomUtil.randomInt(1, 3); + return Stream.iterate(0, i -> i).limit(size) + .map(i -> JsonUtils.toJsonString(randomPojo(BpmFormFieldRespDTO.class))) + .collect(Collectors.toList()); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java new file mode 100644 index 000000000..c37a3f893 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java @@ -0,0 +1,228 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl.BpmTaskAssignStartUserScript; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.PostApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import cn.iocoder.yudao.module.system.api.permission.RoleApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.engine.delegate.DelegateExecution; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Collections.singleton; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * {@link BpmTaskAssignRuleService} 的单元测试 + * + * @author 芋道源码 + */ +@Import({BpmTaskAssignRuleServiceImpl.class, BpmTaskAssignStartUserScript.class}) // Import 引入 BpmTaskAssignStartUserScript 目的是保证不报错 +public class BpmTaskAssignRuleServiceImplTest extends BaseDbUnitTest { + + @Resource + private BpmTaskAssignRuleServiceImpl bpmTaskRuleService; + + @MockBean + private BpmUserGroupService userGroupService; + @MockBean + private DeptApi deptApi; + @MockBean + private AdminUserApi adminUserApi; + @MockBean + private PermissionApi permissionApi; + @MockBean + private RoleApi roleApi; + @MockBean + private PostApi postApi; + @MockBean + private DictDataApi dictDataApi; + + @Test + public void testCalculateTaskCandidateUsers_Role() { + // 准备参数 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) + .setType(BpmTaskAssignRuleTypeEnum.ROLE.getType()); + // mock 方法 + when(permissionApi.getUserRoleIdListByRoleIds(eq(rule.getOptions()))) + .thenReturn(success(asSet(11L, 22L))); + mockGetUserMap(asSet(11L, 22L)); + + // 调用 + Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + + @Test + public void testCalculateTaskCandidateUsers_DeptMember() { + // 准备参数 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) + .setType(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType()); + // mock 方法 + List users = CollectionUtils.convertList(asSet(11L, 22L), + id -> new AdminUserRespDTO().setId(id)); + when(adminUserApi.getUsersByDeptIds(eq(rule.getOptions()))).thenReturn(success(users)); + mockGetUserMap(asSet(11L, 22L)); + + // 调用 + Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + + @Test + public void testCalculateTaskCandidateUsers_DeptLeader() { + // 准备参数 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) + .setType(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType()); + // mock 方法 + DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L)); + DeptRespDTO dept2 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(22L)); + when(deptApi.getDepts(eq(rule.getOptions()))).thenReturn(success(Arrays.asList(dept1, dept2))); + mockGetUserMap(asSet(11L, 22L)); + + // 调用 + Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + + @Test + public void testCalculateTaskCandidateUsers_Post() { + // 准备参数 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) + .setType(BpmTaskAssignRuleTypeEnum.POST.getType()); + // mock 方法 + List users = CollectionUtils.convertList(asSet(11L, 22L), + id -> new AdminUserRespDTO().setId(id)); + when(adminUserApi.getUsersByPostIds(eq(rule.getOptions()))).thenReturn(success(users)); + mockGetUserMap(asSet(11L, 22L)); + + // 调用 + Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + + @Test + public void testCalculateTaskCandidateUsers_User() { + // 准备参数 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) + .setType(BpmTaskAssignRuleTypeEnum.USER.getType()); + // mock 方法 + mockGetUserMap(asSet(1L, 2L)); + + // 调用 + Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); + // 断言 + assertEquals(asSet(1L, 2L), results); + } + + @Test + public void testCalculateTaskCandidateUsers_UserGroup() { + // 准备参数 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) + .setType(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType()); + // mock 方法 + BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(11L, 12L))); + BpmUserGroupDO userGroup2 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(21L, 22L))); + when(userGroupService.getUserGroupList(eq(rule.getOptions()))).thenReturn(Arrays.asList(userGroup1, userGroup2)); + mockGetUserMap(asSet(11L, 12L, 21L, 22L)); + + // 调用 + Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); + // 断言 + assertEquals(asSet(11L, 12L, 21L, 22L), results); + } + + @Test + public void testCalculateTaskCandidateUsers_Script() { + // 准备参数 + BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(20L, 21L)) + .setType(BpmTaskAssignRuleTypeEnum.SCRIPT.getType()); + // mock 方法 + BpmTaskAssignScript script1 = new BpmTaskAssignScript() { + + @Override + public Set calculateTaskCandidateUsers(DelegateExecution task) { + return singleton(11L); + } + + @Override + public BpmTaskRuleScriptEnum getEnum() { + return BpmTaskRuleScriptEnum.LEADER_X1; + } + }; + BpmTaskAssignScript script2 = new BpmTaskAssignScript() { + + @Override + public Set calculateTaskCandidateUsers(DelegateExecution task) { + return singleton(22L); + } + + @Override + public BpmTaskRuleScriptEnum getEnum() { + return BpmTaskRuleScriptEnum.LEADER_X2; + } + }; + bpmTaskRuleService.setScripts(Arrays.asList(script1, script2)); + mockGetUserMap(asSet(11L, 22L)); + + // 调用 + Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + + @Test + public void testRemoveDisableUsers() { + // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到 + Set assigneeUserIds = asSet(1L, 2L, 3L); + // mock 方法 + AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L) + .setStatus(CommonStatusEnum.DISABLE.getStatus())); + Map userMap = MapUtil.builder(user1.getId(), user1) + .put(user2.getId(), user2).build(); + when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); + + // 调用 + bpmTaskRuleService.removeDisableUsers(assigneeUserIds); + // 断言 + assertEquals(asSet(1L), assigneeUserIds); + } + + private void mockGetUserMap(Set assigneeUserIds) { + Map userMap = CollectionUtils.convertMap(assigneeUserIds, id -> id, + id -> new AdminUserRespDTO().setId(id).setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java new file mode 100644 index 000000000..1053c95e1 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java @@ -0,0 +1,132 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.framework.test.core.util.AssertUtils; +import cn.iocoder.yudao.framework.test.core.util.RandomUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmUserGroupMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS; + +/** +* {@link BpmUserGroupServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Import(BpmUserGroupServiceImpl.class) +public class BpmUserGroupServiceTest extends BaseDbUnitTest { + + @Resource + private BpmUserGroupServiceImpl userGroupService; + + @Resource + private BpmUserGroupMapper userGroupMapper; + + @Test + public void testCreateUserGroup_success() { + // 准备参数 + BpmUserGroupCreateReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupCreateReqVO.class); + + // 调用 + Long userGroupId = userGroupService.createUserGroup(reqVO); + // 断言 + Assertions.assertNotNull(userGroupId); + // 校验记录的属性是否正确 + BpmUserGroupDO userGroup = userGroupMapper.selectById(userGroupId); + AssertUtils.assertPojoEquals(reqVO, userGroup); + } + + @Test + public void testUpdateUserGroup_success() { + // mock 数据 + BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class); + userGroupMapper.insert(dbUserGroup);// @Sql: 先插入出一条存在的数据 + // 准备参数 + BpmUserGroupUpdateReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupUpdateReqVO.class, o -> { + o.setId(dbUserGroup.getId()); // 设置更新的 ID + }); + + // 调用 + userGroupService.updateUserGroup(reqVO); + // 校验是否更新正确 + BpmUserGroupDO userGroup = userGroupMapper.selectById(reqVO.getId()); // 获取最新的 + AssertUtils.assertPojoEquals(reqVO, userGroup); + } + + @Test + public void testUpdateUserGroup_notExists() { + // 准备参数 + BpmUserGroupUpdateReqVO reqVO = RandomUtils.randomPojo(BpmUserGroupUpdateReqVO.class); + + // 调用, 并断言异常 + AssertUtils.assertServiceException(() -> userGroupService.updateUserGroup(reqVO), USER_GROUP_NOT_EXISTS); + } + + @Test + public void testDeleteUserGroup_success() { + // mock 数据 + BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class); + userGroupMapper.insert(dbUserGroup);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbUserGroup.getId(); + + // 调用 + userGroupService.deleteUserGroup(id); + // 校验数据不存在了 + Assertions.assertNull(userGroupMapper.selectById(id)); + } + + @Test + public void testDeleteUserGroup_notExists() { + // 准备参数 + Long id = RandomUtils.randomLongId(); + + // 调用, 并断言异常 + AssertUtils.assertServiceException(() -> userGroupService.deleteUserGroup(id), USER_GROUP_NOT_EXISTS); + } + + @Test + public void testGetUserGroupPage() { + // mock 数据 + BpmUserGroupDO dbUserGroup = RandomUtils.randomPojo(BpmUserGroupDO.class, o -> { // 等会查询到 + o.setName("芋道源码"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(DateUtils.buildTime(2021, 11, 11)); + }); + userGroupMapper.insert(dbUserGroup); + // 测试 name 不匹配 + userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setName("芋道"))); + // 测试 status 不匹配 + userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + userGroupMapper.insert(cloneIgnoreId(dbUserGroup, o -> o.setCreateTime(DateUtils.buildTime(2021, 12, 12)))); + // 准备参数 + BpmUserGroupPageReqVO reqVO = new BpmUserGroupPageReqVO(); + reqVO.setName("源码"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime((new Date[]{buildTime(2021, 11, 10),buildTime(2021, 11, 12)})); + + // 调用 + PageResult pageResult = userGroupService.getUserGroupPage(reqVO); + // 断言 + Assertions.assertEquals(1, pageResult.getTotal()); + Assertions.assertEquals(1, pageResult.getList().size()); + AssertUtils.assertPojoEquals(dbUserGroup, pageResult.getList().get(0)); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/application-unit-test.yaml b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/application-unit-test.yaml new file mode 100644 index 000000000..25bfe0a62 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/application-unit-test.yaml @@ -0,0 +1,44 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + datasource: + name: ruoyi-vue-pro + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 + driver-class-name: org.h2.Driver + username: sa + password: + druid: + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 + initial-size: 1 # 单元测试,配置为 1,提升启动速度 + sql: + init: + schema-locations: classpath:/sql/create_tables.sql + +mybatis-plus: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 + type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +# Resilience4j 配置项 + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + info: + base-package: cn.iocoder.yudao.module diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/logback.xml b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/logback.xml new file mode 100644 index 000000000..daf756bff --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/logback.xml @@ -0,0 +1,4 @@ + + + + diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/clean.sql b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/clean.sql new file mode 100644 index 000000000..6e42d3cfc --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/clean.sql @@ -0,0 +1,2 @@ +DELETE FROM "bpm_form"; +DELETE FROM "bpm_user_group"; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql new file mode 100644 index 000000000..20a939b76 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,28 @@ +CREATE TABLE IF NOT EXISTS "bpm_user_group" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(63) NOT NULL, + "description" varchar(255) NOT NULL, + "status" tinyint NOT NULL, + "member_user_ids" varchar(255) NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '用户组'; + +CREATE TABLE IF NOT EXISTS "bpm_form" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(63) NOT NULL, + "status" tinyint NOT NULL, + "fields" varchar(255) NOT NULL, + "conf" varchar(255) NOT NULL, + "remark" varchar(255), + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '动态表单'; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java index 491a7d87c..adff119b0 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTablePageReqVO.java @@ -24,12 +24,8 @@ public class CodegenTablePageReqVO extends PageParam { @ApiModelProperty(value = "表描述", example = "芋道", notes = "模糊匹配") private String tableComment; - @ApiModelProperty(value = "开始创建时间", example = "2020-10-24 00:00:00") + @ApiModelProperty(value = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date beginCreateTime; - - @ApiModelProperty(value = "结束创建时间", example = "2020-10-24 23:59:59") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date endCreateTime; + private Date[] createTime; } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java index fcdca025f..5ea52b7e5 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java @@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; @@ -59,6 +60,7 @@ public class FileController { } @GetMapping("/{configId}/get/{path}") + @PermitAll @ApiOperation("下载文件") @ApiImplicitParams({ @ApiImplicitParam(name = "configId", value = "配置编号", required = true, dataTypeClass = Long.class), diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java index 3b3f0d4e5..3752b37c5 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java @@ -24,12 +24,8 @@ public class FileConfigPageReqVO extends PageParam { @ApiModelProperty(value = "存储器", example = "1") private Integer storage; + @ApiModelProperty(value = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + private Date[] createTime; } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePageReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePageReqVO.java index 346314e83..0ae43bbe0 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePageReqVO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FilePageReqVO.java @@ -24,12 +24,8 @@ public class FilePageReqVO extends PageParam { @ApiModelProperty(value = "文件类型", example = "jpg", notes = "模糊匹配") private String type; + @ApiModelProperty(value = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + private Date[] createTime; } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogExportReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogExportReqVO.java index 83eefabd6..dc2ef8714 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogExportReqVO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogExportReqVO.java @@ -25,13 +25,9 @@ public class ApiAccessLogExportReqVO { @ApiModelProperty(value = "请求地址", example = "/xxx/yyy", notes = "模糊匹配") private String requestUrl; + @ApiModelProperty(value = "开始时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始开始请求时间") - private Date beginBeginTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束开始请求时间") - private Date endBeginTime; + private Date[] beginTime; @ApiModelProperty(value = "执行时长", example = "100", notes = "大于等于,单位:毫秒") private Integer duration; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java index d318bfa92..97ff8e949 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apiaccesslog/ApiAccessLogPageReqVO.java @@ -30,13 +30,9 @@ public class ApiAccessLogPageReqVO extends PageParam { @ApiModelProperty(value = "请求地址", example = "/xxx/yyy", notes = "模糊匹配") private String requestUrl; + @ApiModelProperty(value = "开始时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始开始请求时间") - private Date beginBeginTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束开始请求时间") - private Date endBeginTime; + private Date[] beginTime; @ApiModelProperty(value = "执行时长", example = "100", notes = "大于等于,单位:毫秒") private Integer duration; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogExportReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogExportReqVO.java index b799a3238..d8e121e0b 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogExportReqVO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogExportReqVO.java @@ -26,12 +26,8 @@ public class ApiErrorLogExportReqVO { private String requestUrl; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始异常发生时间") - private Date beginExceptionTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束异常发生时间") - private Date endExceptionTime; + @ApiModelProperty(value = "异常发生时间") + private Date[] exceptionTime; @ApiModelProperty(value = "处理状态", example = "0") private Integer processStatus; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogPageReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogPageReqVO.java index e9a36af96..fda23ba14 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogPageReqVO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/vo/apierrorlog/ApiErrorLogPageReqVO.java @@ -31,12 +31,8 @@ public class ApiErrorLogPageReqVO extends PageParam { private String requestUrl; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始异常发生时间") - private Date beginExceptionTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束异常发生时间") - private Date endExceptionTime; + @ApiModelProperty(value = "异常发生时间") + private Date[] exceptionTime; @ApiModelProperty(value = "处理状态", example = "0") private Integer processStatus; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.java index 303e67184..7d53c7332 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.java @@ -1,24 +1,30 @@ package cn.iocoder.yudao.module.infra.controller.admin.redis; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine; import cn.iocoder.yudao.framework.redis.core.RedisKeyRegistry; -import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyDefineRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyValueRespVO; import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO; import cn.iocoder.yudao.module.infra.convert.redis.RedisConvert; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import org.springframework.data.redis.connection.RedisServerCommands; +import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import java.util.LinkedHashSet; import java.util.List; import java.util.Properties; +import java.util.Set; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -44,12 +50,66 @@ public class RedisController { return success(RedisConvert.INSTANCE.build(info, dbSize, commandStats)); } - @GetMapping("/get-key-list") - @ApiOperation("获得 Redis Key 列表") + @GetMapping("/get-key-define-list") + @ApiOperation("获得 Redis Key 模板列表") @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')") - public CommonResult> getKeyList() { + public CommonResult> getKeyDefineList() { List keyDefines = RedisKeyRegistry.list(); return success(RedisConvert.INSTANCE.convertList(keyDefines)); } + @GetMapping("/get-key-list") + @ApiOperation("获得 Redis keys 键名列表") + @ApiImplicitParam(name = "keyTemplate", value = "Redis Key 定义", example = "true", dataTypeClass = String.class) + @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')") + public CommonResult> getKeyDefineList(@RequestParam("keyTemplate") String keyTemplate) { + return success(getKeyDefineList0(keyTemplate)); + } + + private Set getKeyDefineList0(String keyTemplate) { + // key 格式化 + String key = StrUtil.replace(keyTemplate, "%[s|c|b|d|x|o|f|a|e|g]", parameter -> "*"); + // scan 扫描 key + Set keys = new LinkedHashSet<>(); + stringRedisTemplate.execute((RedisCallback>) connection -> { + try (Cursor cursor = connection.scan(ScanOptions.scanOptions().match(key).count(100).build())) { + cursor.forEachRemaining(value -> keys.add(StrUtil.utf8Str(value))); + } catch (Exception e) { + throw new RuntimeException(e); + } + return keys; + }); + return keys; + } + + @GetMapping("/get-key-value") + @ApiOperation("获得 Redis key 内容") + @ApiImplicitParam(name = "key", value = "Redis Key", example = "oauth2_access_token:233", dataTypeClass = String.class) + @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')") + public CommonResult getKeyValue(@RequestParam("key") String key) { + String value = stringRedisTemplate.opsForValue().get(key); + return success(new RedisKeyValueRespVO(key, value)); + } + + @DeleteMapping("/delete-key") + @ApiOperation("删除 Redis Key") + @ApiImplicitParam(name = "key", value = "Redis Key", example = "oauth2_access_token:233", dataTypeClass = String.class) + @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')") + public CommonResult deleteKey(@RequestParam("key") String key) { + stringRedisTemplate.delete(key); + return success(Boolean.TRUE); + } + + @DeleteMapping("/delete-keys") + @ApiOperation("删除 Redis Key 根据模板") + @ApiImplicitParam(name = "keyTemplate", value = "Redis Key 定义", example = "true", dataTypeClass = String.class) + @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')") + public CommonResult deleteKeys(@RequestParam("keyTemplate") String keyTemplate) { + Set keys = getKeyDefineList0(keyTemplate); + if (CollUtil.isNotEmpty(keys)) { + stringRedisTemplate.delete(keys); + } + return success(Boolean.TRUE); + } + } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyDefineRespVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyDefineRespVO.java new file mode 100644 index 000000000..4c1b5acd8 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyDefineRespVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.infra.controller.admin.redis.vo; + +import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +import java.time.Duration; + +@ApiModel("管理后台 - Redis Key 信息 Response VO") +@Data +@Builder +@AllArgsConstructor +public class RedisKeyDefineRespVO { + + @ApiModelProperty(value = "Key 模板", required = true, example = "login_user:%s") + private String keyTemplate; + + @ApiModelProperty(value = "Key 类型的枚举", required = true, example = "String") + private RedisKeyDefine.KeyTypeEnum keyType; + + @ApiModelProperty(value = "Value 类型", required = true, example = "java.lang.String") + private Class valueType; + + @ApiModelProperty(value = "超时类型", required = true, example = "1") + private RedisKeyDefine.TimeoutTypeEnum timeoutType; + + @ApiModelProperty(value = "过期时间,单位:毫秒", required = true, example = "1024") + private Duration timeout; + + @ApiModelProperty(value = "备注", required = true, example = "啦啦啦啦~") + private String memo; + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyValueRespVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyValueRespVO.java new file mode 100644 index 000000000..0f16f0640 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyValueRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.infra.controller.admin.redis.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; + +@ApiModel("管理后台 - 单个 Redis Key Value Response VO") +@Data +@AllArgsConstructor +public class RedisKeyValueRespVO { + + @ApiModelProperty(value = "c5f6990767804a928f4bb96ca249febf", required = true, example = "String") + private String key; + + @ApiModelProperty(required = true, example = "String") + private String value; + +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoExportReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoExportReqVO.java index 09011682e..8836919a6 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoExportReqVO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoExportReqVO.java @@ -1,11 +1,12 @@ package cn.iocoder.yudao.module.infra.controller.admin.test.vo; -import lombok.*; -import java.util.*; -import io.swagger.annotations.*; -import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; +import java.util.Date; + import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @ApiModel(value = "管理后台 - 字典类型 Excel 导出 Request VO", description = "参数和 TestDemoPageReqVO 是一致的") @@ -28,11 +29,7 @@ public class TestDemoExportReqVO { private String remark; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoPageReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoPageReqVO.java index 75cf79140..0ee9e060c 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoPageReqVO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoPageReqVO.java @@ -1,11 +1,15 @@ package cn.iocoder.yudao.module.infra.controller.admin.test.vo; -import lombok.*; -import java.util.*; -import io.swagger.annotations.*; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; +import java.util.Date; + import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @ApiModel("管理后台 - 字典类型分页 Request VO") @@ -30,11 +34,7 @@ public class TestDemoPageReqVO extends PageParam { private String remark; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/redis/RedisConvert.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/redis/RedisConvert.java index e1c931184..6a1ded7d2 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/redis/RedisConvert.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/redis/RedisConvert.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.infra.convert.redis; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine; -import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyDefineRespVO; import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -29,6 +29,6 @@ public interface RedisConvert { return respVO; } - List convertList(List list); + List convertList(List list); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java index 7e81280da..c0fb007e1 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java @@ -5,8 +5,6 @@ import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; -import java.io.InputStream; - /** * 文件表 * 每次文件上传,都会记录一条记录到该表中 @@ -46,9 +44,7 @@ public class FileDO extends BaseDO { */ private String url; /** - * 文件类型 - * - * 通过 {@link cn.hutool.core.io.FileTypeUtil#getType(InputStream)} 获取 + * 文件的 MIME 类型,例如 "application/octet-stream" */ private String type; /** diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenTableMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenTableMapper.java index 6e8ad3de9..c53268de0 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenTableMapper.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenTableMapper.java @@ -21,7 +21,7 @@ public interface CodegenTableMapper extends BaseMapperX { return selectPage(pageReqVO, new LambdaQueryWrapperX() .likeIfPresent(CodegenTableDO::getTableName, pageReqVO.getTableName()) .likeIfPresent(CodegenTableDO::getTableComment, pageReqVO.getTableComment()) - .betweenIfPresent(CodegenTableDO::getCreateTime, pageReqVO.getBeginCreateTime(), pageReqVO.getEndCreateTime())); + .betweenIfPresent(CodegenTableDO::getCreateTime, pageReqVO.getCreateTime())); } default List selectListByDataSourceConfigId(Long dataSourceConfigId) { diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java index 5d29a98aa..69a1e1cd7 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java @@ -22,7 +22,7 @@ public interface FileConfigMapper extends BaseMapperX { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(FileConfigDO::getName, reqVO.getName()) .eqIfPresent(FileConfigDO::getStorage, reqVO.getStorage()) - .betweenIfPresent(FileConfigDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(FileConfigDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(FileConfigDO::getId)); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java index 845addc14..11233a457 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java @@ -19,7 +19,7 @@ public interface FileMapper extends BaseMapperX { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(FileDO::getPath, reqVO.getPath()) .likeIfPresent(FileDO::getType, reqVO.getType()) - .betweenIfPresent(FileDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(FileDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(FileDO::getId)); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiAccessLogMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiAccessLogMapper.java index 8f00fbebc..427675636 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiAccessLogMapper.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiAccessLogMapper.java @@ -1,10 +1,10 @@ package cn.iocoder.yudao.module.infra.dal.mysql.logger; -import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogExportReqVO; -import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogExportReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO; import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO; import org.apache.ibatis.annotations.Mapper; @@ -19,28 +19,28 @@ import java.util.List; public interface ApiAccessLogMapper extends BaseMapperX { default PageResult selectPage(ApiAccessLogPageReqVO reqVO) { - return selectPage(reqVO, new QueryWrapperX() - .eqIfPresent("user_id", reqVO.getUserId()) - .eqIfPresent("user_type", reqVO.getUserType()) - .eqIfPresent("application_name", reqVO.getApplicationName()) - .likeIfPresent("request_url", reqVO.getRequestUrl()) - .betweenIfPresent("begin_time", reqVO.getBeginBeginTime(), reqVO.getEndBeginTime()) - .geIfPresent("duration", reqVO.getDuration()) - .eqIfPresent("result_code", reqVO.getResultCode()) - .orderByDesc("id") + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ApiAccessLogDO::getUserId, reqVO.getUserId()) + .eqIfPresent(ApiAccessLogDO::getUserType, reqVO.getUserType()) + .eqIfPresent(ApiAccessLogDO::getApplicationName, reqVO.getApplicationName()) + .likeIfPresent(ApiAccessLogDO::getRequestUrl, reqVO.getRequestUrl()) + .betweenIfPresent(ApiAccessLogDO::getBeginTime, reqVO.getBeginTime()) + .geIfPresent(ApiAccessLogDO::getDuration, reqVO.getDuration()) + .eqIfPresent(ApiAccessLogDO::getResultCode, reqVO.getResultCode()) + .orderByDesc(ApiAccessLogDO::getId) ); } default List selectList(ApiAccessLogExportReqVO reqVO) { - return selectList(new QueryWrapperX() - .eqIfPresent("user_id", reqVO.getUserId()) - .eqIfPresent("user_type", reqVO.getUserType()) - .eqIfPresent("application_name", reqVO.getApplicationName()) - .likeIfPresent("request_url", reqVO.getRequestUrl()) - .betweenIfPresent("begin_time", reqVO.getBeginBeginTime(), reqVO.getEndBeginTime()) - .geIfPresent("duration", reqVO.getDuration()) - .eqIfPresent("result_code", reqVO.getResultCode()) - .orderByDesc("id") + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(ApiAccessLogDO::getUserId, reqVO.getUserId()) + .eqIfPresent(ApiAccessLogDO::getUserType, reqVO.getUserType()) + .eqIfPresent(ApiAccessLogDO::getApplicationName, reqVO.getApplicationName()) + .likeIfPresent(ApiAccessLogDO::getRequestUrl, reqVO.getRequestUrl()) + .betweenIfPresent(ApiAccessLogDO::getBeginTime, reqVO.getBeginTime()) + .geIfPresent(ApiAccessLogDO::getDuration, reqVO.getDuration()) + .eqIfPresent(ApiAccessLogDO::getResultCode, reqVO.getResultCode()) + .orderByDesc(ApiAccessLogDO::getId) ); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiErrorLogMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiErrorLogMapper.java index 7e4ab62c3..e9748b624 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiErrorLogMapper.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/logger/ApiErrorLogMapper.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.infra.dal.mysql.logger; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogExportReqVO; import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO; import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO; @@ -19,26 +19,26 @@ import java.util.List; public interface ApiErrorLogMapper extends BaseMapperX { default PageResult selectPage(ApiErrorLogPageReqVO reqVO) { - return selectPage(reqVO, new QueryWrapperX() - .eqIfPresent("user_id", reqVO.getUserId()) - .eqIfPresent("user_type", reqVO.getUserType()) - .eqIfPresent("application_name", reqVO.getApplicationName()) - .likeIfPresent("request_url", reqVO.getRequestUrl()) - .betweenIfPresent("exception_time", reqVO.getBeginExceptionTime(), reqVO.getEndExceptionTime()) - .eqIfPresent("process_status", reqVO.getProcessStatus()) - .orderByDesc("id") + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ApiErrorLogDO::getUserId, reqVO.getUserId()) + .eqIfPresent(ApiErrorLogDO::getUserType, reqVO.getUserType()) + .eqIfPresent(ApiErrorLogDO::getApplicationName, reqVO.getApplicationName()) + .likeIfPresent(ApiErrorLogDO::getRequestUrl, reqVO.getRequestUrl()) + .betweenIfPresent(ApiErrorLogDO::getExceptionTime, reqVO.getExceptionTime()) + .eqIfPresent(ApiErrorLogDO::getProcessStatus, reqVO.getProcessStatus()) + .orderByDesc(ApiErrorLogDO::getId) ); } default List selectList(ApiErrorLogExportReqVO reqVO) { - return selectList(new QueryWrapperX() - .eqIfPresent("user_id", reqVO.getUserId()) - .eqIfPresent("user_type", reqVO.getUserType()) - .eqIfPresent("application_name", reqVO.getApplicationName()) - .likeIfPresent("request_url", reqVO.getRequestUrl()) - .betweenIfPresent("exception_time", reqVO.getBeginExceptionTime(), reqVO.getEndExceptionTime()) - .eqIfPresent("process_status", reqVO.getProcessStatus()) - .orderByDesc("id") + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(ApiErrorLogDO::getUserId, reqVO.getUserId()) + .eqIfPresent(ApiErrorLogDO::getUserType, reqVO.getUserType()) + .eqIfPresent(ApiErrorLogDO::getApplicationName, reqVO.getApplicationName()) + .likeIfPresent(ApiErrorLogDO::getRequestUrl, reqVO.getRequestUrl()) + .betweenIfPresent(ApiErrorLogDO::getExceptionTime, reqVO.getExceptionTime()) + .eqIfPresent(ApiErrorLogDO::getProcessStatus, reqVO.getProcessStatus()) + .orderByDesc(ApiErrorLogDO::getId) ); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/test/TestDemoMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/test/TestDemoMapper.java index 7b7dd315a..d600b3f4b 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/test/TestDemoMapper.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/test/TestDemoMapper.java @@ -25,7 +25,7 @@ public interface TestDemoMapper extends BaseMapperX { .eqIfPresent(TestDemoDO::getType, reqVO.getType()) .eqIfPresent(TestDemoDO::getCategory, reqVO.getCategory()) .eqIfPresent(TestDemoDO::getRemark, reqVO.getRemark()) - .betweenIfPresent(TestDemoDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(TestDemoDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(TestDemoDO::getId)); } @@ -36,7 +36,7 @@ public interface TestDemoMapper extends BaseMapperX { .eqIfPresent(TestDemoDO::getType, reqVO.getType()) .eqIfPresent(TestDemoDO::getCategory, reqVO.getCategory()) .eqIfPresent(TestDemoDO::getRemark, reqVO.getRemark()) - .betweenIfPresent(TestDemoDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(TestDemoDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(TestDemoDO::getId)); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java index 306511206..4da36c493 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java @@ -36,8 +36,6 @@ public class SecurityConfiguration { // Spring Boot Admin Server 的安全配置 registry.antMatchers(adminSeverContextPath).anonymous() .antMatchers(adminSeverContextPath + "/**").anonymous(); - // 文件的获取接口,可匿名访问 - registry.antMatchers(buildAdminApi("/infra/file/*/get/**"), buildAppApi("/infra/file/get/**")).permitAll(); // TODO 芋艿:这个每个项目都需要重复配置,得捉摸有没通用的方案 // RPC 服务的安全配置 diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java index f447472dd..cec246bfc 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java @@ -79,11 +79,20 @@ public class CodegenEngine { javaModuleImplTestFilePath("service/${table.businessName}/${table.className}ServiceImplTest")) // Java module-api Main .put(javaTemplatePath("enums/errorcode"), javaModuleApiMainFilePath("enums/ErrorCodeConstants_手动操作")) - // Vue + // Vue2 .put(vueTemplatePath("views/index.vue"), vueFilePath("views/${table.moduleName}/${classNameVar}/index.vue")) .put(vueTemplatePath("api/api.js"), vueFilePath("api/${table.moduleName}/${classNameVar}.js")) + // Vue3 + .put(vue3TemplatePath("views/index.vue"), + vue3FilePath("views/${table.moduleName}/${classNameVar}/index.vue")) + .put(vue3TemplatePath("views/data.ts"), + vue3FilePath("views/${table.moduleName}/${classNameVar}/${classNameVar}.data.ts")) + .put(vue3TemplatePath("api/api.ts"), + vue3FilePath("api/${table.moduleName}/${classNameVar}/index.ts")) + .put(vue3TemplatePath("api/types.ts"), + vue3FilePath("api/${table.moduleName}/${classNameVar}/types.ts")) // SQL .put("codegen/sql/sql.vm", "sql/sql.sql") .put("codegen/sql/h2.vm", "sql/h2.sql") @@ -228,5 +237,12 @@ public class CodegenEngine { return "yudao-ui-${sceneEnum.basePackage}/" + // 顶级目录 "src/" + path; } + private static String vue3TemplatePath(String path) { + return "codegen/vue3/" + path + ".vm"; + } + private static String vue3FilePath(String path) { + return "yudao-ui-${sceneEnum.basePackage}-vue3/" + // 顶级目录 + "src/" + path; + } } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java index b90e92752..493a9ed1f 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java @@ -1,11 +1,11 @@ package cn.iocoder.yudao.module.infra.service.file; -import cn.hutool.core.io.FileTypeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; -import cn.hutool.crypto.digest.DigestUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.io.FileUtils; import cn.iocoder.yudao.framework.file.core.client.FileClient; +import cn.iocoder.yudao.framework.file.core.utils.FileTypeUtils; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; @@ -13,7 +13,6 @@ import lombok.SneakyThrows; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.io.ByteArrayInputStream; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS; @@ -41,9 +40,9 @@ public class FileServiceImpl implements FileService { @SneakyThrows public String createFile(String name, String path, byte[] content) { // 计算默认的 path 名 - String type = FileTypeUtil.getType(new ByteArrayInputStream(content), name); + String type = FileTypeUtils.getMineType(content, name); if (StrUtil.isEmpty(path)) { - path = DigestUtil.md5Hex(content) + '.' + type; + path = FileUtils.generatePath(content, name); } // 如果 name 为空,则使用 path 填充 if (StrUtil.isEmpty(name)) { diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-dev.yaml b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-dev.yaml index 04331a4a7..a75288fc5 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-dev.yaml +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-dev.yaml @@ -102,7 +102,7 @@ spring: client: url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 设置 Spring Boot Admin Server 地址 instance: - prefer-ip: true # 注册实例时,优先使用 IP + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] # Spring Boot Admin Server 服务端的相关配置 context-path: /admin # 配置 Spring diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-local.yaml b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-local.yaml index 62d4abf6c..70d12a8be 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-local.yaml +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application-local.yaml @@ -113,7 +113,7 @@ spring: client: url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 设置 Spring Boot Admin Server 地址 instance: - prefer-ip: true # 注册实例时,优先使用 IP + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] # Spring Boot Admin Server 服务端的相关配置 context-path: /admin # 配置 Spring diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application.yaml b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application.yaml index 71fdaebc7..b23c5710b 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application.yaml +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/application.yaml @@ -75,7 +75,7 @@ spring: name-server: 127.0.0.1:9876 # RocketMQ Namesrv 地址 default: # 默认 bindings 全局配置 producer: # RocketMQ Producer 配置项,对应 RocketMQProducerProperties 类 - group: system_producer_group # 生产者分组 + group: infra_producer_group # 生产者分组 send-type: SYNC # 发送模式,SYNC 同步 # Spring Cloud Bus 配置项,对应 BusProperties 类 diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/baseVO.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/baseVO.vm index 3036c16ed..8b9fbaac2 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/baseVO.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/baseVO.vm @@ -2,6 +2,12 @@ package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePac import lombok.*; import java.util.*; +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#break +#end +#end import io.swagger.annotations.*; import javax.validation.constraints.*; ## 处理 Date 字段的引入 diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/excelVO.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/excelVO.vm index 2ce6f28a8..6b3ea2467 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/excelVO.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/excelVO.vm @@ -2,6 +2,12 @@ package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePac import lombok.*; import java.util.*; +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#break +#end +#end import io.swagger.annotations.*; import com.alibaba.excel.annotation.ExcelProperty; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/exportReqVO.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/exportReqVO.vm index 10ab97afc..afd583c28 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/exportReqVO.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/exportReqVO.vm @@ -15,9 +15,6 @@ import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; #end ## 字段模板 #macro(columnTpl $prefix $prefixStr) -#if (${column.javaType} == "Date")## 时间类型 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) -#end @ApiModelProperty(value = "${prefixStr}${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) private ${column.javaType}#if ("$!prefix" != "") ${prefix}${JavaField}#else ${column.javaField}#end; #end @@ -27,12 +24,11 @@ import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; public class ${sceneEnum.prefixClass}${table.className}ExportReqVO { #foreach ($column in $columns) -#set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写 #if (${column.listOperation})##查询操作 #if (${column.listOperationCondition} == "BETWEEN")## 情况一,Between 的时候 - #columnTpl('begin', '开始') - - #columnTpl('end', '结束') + @ApiModelProperty(value = "${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private ${column.javaType}[] ${column.javaField}; #else##情况二,非 Between 的时间 #columnTpl('', '') #end diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/pageReqVO.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/pageReqVO.vm index 5f5952c59..df2be7036 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/pageReqVO.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/pageReqVO.vm @@ -15,9 +15,6 @@ import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; #end ## 字段模板 #macro(columnTpl $prefix $prefixStr) -#if (${column.javaType} == "Date")## 时间类型 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) -#end @ApiModelProperty(value = "${prefixStr}${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) private ${column.javaType}#if ("$!prefix" != "") ${prefix}${JavaField}#else ${column.javaField}#end; #end @@ -29,12 +26,11 @@ import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; public class ${sceneEnum.prefixClass}${table.className}PageReqVO extends PageParam { #foreach ($column in $columns) -#set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写 #if (${column.listOperation})##查询操作 #if (${column.listOperationCondition} == "BETWEEN")## 情况一,Between 的时候 - #columnTpl('begin', '开始') - - #columnTpl('end', '结束') + @ApiModelProperty(value = "${column.columnComment}"#if ("$!column.example" != ""), example = "${column.example}"#end) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private ${column.javaType}[] ${column.javaField}; #else##情况二,非 Between 的时间 #columnTpl('', '') #end diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do.vm index 5c22e388a..4abae1591 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do.vm @@ -2,6 +2,12 @@ package ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.busines import lombok.*; import java.util.*; +#foreach ($column in $columns) +#if (${column.javaType} == "BigDecimal") +import java.math.BigDecimal; +#break +#end +#end import com.baomidou.mybatisplus.annotation.*; import ${BaseDOClassName}; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm index cab43effb..615ae337b 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm @@ -36,7 +36,7 @@ import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePack .likeIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) #end #if (${column.listOperationCondition} == "BETWEEN")##情况八,Between 的时候 - .betweenIfPresent(${table.className}DO::get${JavaField}, reqVO.getBegin${JavaField}(), reqVO.getEnd${JavaField}()) + .betweenIfPresent(${table.className}DO::get${JavaField}, reqVO.get${JavaField}()) #end #end #end diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm index 6cf0c6196..1b5c60a3f 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm @@ -51,8 +51,7 @@ import static org.mockito.Mockito.*; #if (${column.listOperation}) #set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写 #if (${column.listOperationCondition} == "BETWEEN")## BETWEEN 的情况 - reqVO.setBegin${JavaField}(null); - reqVO.setEnd${JavaField}(null); + reqVO.set${JavaField}((new Date[]{})); #else reqVO.set$JavaField(null); #end diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/index.vue.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/index.vue.vm index 87bb2b21f..95f7d66a2 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/index.vue.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/views/index.vue.vm @@ -30,9 +30,9 @@ #else## 范围 - - + + #end #end @@ -219,22 +219,19 @@ export default { title: "", // 是否显示弹出层 open: false, - #foreach ($column in $columns)## 时间范围 - #if ($column.listOperation) - #if ($column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN") - #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) - dateRange${AttrName}: [], - #end - #end - #end // 查询参数 queryParams: { pageNo: 1, pageSize: 10, #foreach ($column in $columns) - #if ($column.listOperation && $column.listOperationCondition != 'BETWEEN') + #if ($column.listOperation) + #if ($column.listOperationCondition != 'BETWEEN') $column.javaField: null, #end + #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN") + $column.javaField: [], + #end + #end #end }, // 表单参数 @@ -257,18 +254,8 @@ export default { /** 查询列表 */ getList() { this.loading = true; - // 处理查询参数 - let params = {...this.queryParams}; - #foreach ($column in $columns) - #if ($column.listOperation) - #if ($column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN") - #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) - this.addBeginAndEndTime(params, this.dateRange${AttrName}, '${column.javaField}'); - #end - #end - #end // 执行查询 - get${simpleClassName}Page(params).then(response => { + get${simpleClassName}Page(this.queryParams).then(response => { this.list = response.data.list; this.total = response.data.total; this.loading = false; @@ -301,14 +288,6 @@ export default { }, /** 重置按钮操作 */ resetQuery() { - #foreach ($column in $columns) - #if ($column.listOperation) - #if ($column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN") - #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) - this.dateRange${AttrName} = []; - #end - #end - #end this.resetForm("queryForm"); this.handleQuery(); }, @@ -377,15 +356,6 @@ export default { let params = {...this.queryParams}; params.pageNo = undefined; params.pageSize = undefined; - #foreach ($column in $columns) - #if ($column.listOperation) - #if ($column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN") - #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) - this.addBeginAndEndTime(params, this.dateRange${AttrName}, '${column.javaField}'); - #end - #end - #end - // 执行导出 this.#[[$modal]]#.confirm('是否确认导出所有${table.classComment}数据项?').then(() => { this.exportLoading = true; return export${simpleClassName}Excel(params); diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm new file mode 100644 index 000000000..b37365a07 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm @@ -0,0 +1,35 @@ +import { useAxios } from '@/hooks/web/useAxios' +import { ${simpleClassName}VO,${simpleClassName}PageReqVO,${simpleClassName}ExcelReqVO } from './types' + +const request = useAxios() + +#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}") +// 查询${table.classComment}列表 +export const getPostPageApi = async (params: ${simpleClassName}PageReqVO) => { + return await request.get({ url: '${baseURL}/page', params }) +} + +// 查询${table.classComment}详情 +export const getPostApi = async (id: number) => { + return await request.get({ url: '${baseURL}/get?id=' + id }) +} + +// 新增${table.classComment} +export const createPostApi = async (data: ${simpleClassName}VO) => { + return await request.post({ url: '${baseURL}/create', data }) +} + +// 修改${table.classComment} +export const updatePostApi = async (data: ${simpleClassName}VO) => { + return await request.put({ url: '${baseURL}/update', data }) +} + +// 删除${table.classComment} +export const deletePostApi = async (id: number) => { + return await request.delete({ url: '${baseURL}/delete?id=' + id }) +} + +// 导出${table.classComment} Excel +export const exportPostApi = async (params: ${simpleClassName}ExcelReqVO) => { + return await request.download({ url: '${baseURL}/export-excel', params }) +} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/types.ts.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/types.ts.vm new file mode 100644 index 000000000..d5b5d937d --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/types.ts.vm @@ -0,0 +1,35 @@ +export type ${simpleClassName}VO = { +#foreach ($column in $columns) +#if ($column.createOperation || $column.updateOperation) +#if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer") + ${column.javaField}: number +#else + ${column.javaField}: ${column.javaType.toLowerCase()} +#end +#end +#end +} + +export type ${simpleClassName}PageReqVO = { +#foreach ($column in $columns) +#if (${column.listOperation})##查询操作 +#if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer") + ${column.javaField}: number +#else + ${column.javaField}: ${column.javaType.toLowerCase()} +#end +#end +#end +} + +export type ${simpleClassName}ExcelReqVO = { +#foreach ($column in $columns) +#if (${column.listOperation})##查询操作 +#if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer") + ${column.javaField}: number +#else + ${column.javaField}: ${column.javaType.toLowerCase()} +#end +#end +#end +} \ No newline at end of file diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/data.ts.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/data.ts.vm new file mode 100644 index 000000000..965fe49ab --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/data.ts.vm @@ -0,0 +1,111 @@ +import { reactive } from 'vue' +import { useI18n } from '@/hooks/web/useI18n' +import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas' +import { DICT_TYPE } from '@/utils/dict' +const { t } = useI18n() // 国际化 +// 表单校验 +export const rules = reactive({ +#foreach ($column in $columns) +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键 +#set($comment=$column.columnComment) + $column.javaField: [{ required: true, message: "${comment}不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }], +#end +#end +}) +// CrudSchema +const crudSchemas = reactive([ +#foreach($column in $columns) + #if ($column.listOperation || $column.listOperationResult || $column.createOperation || $column.updateOperation) + #set ($dictType = $column.dictType) + { + label: '${column.columnComment}', + field: '${column.javaField}', + #if ("" != $dictType)## 有数据字典 + dictType: DICT_TYPE.$dictType.toUpperCase(), + #end + #if($column.primaryKey) + type: 'index', + form: { + show: false + }, + detail: { + show: false + } + #else + #if (!$column.createOperation && !$column.updateOperation) + form: { + false + }, + #elseif(!("" != $column.dictType)) + form: { + show: true, + #if ($column.htmlType == "datetime")## 时间框 + component: 'DatePicker', + componentProps: { + type: 'datetime', + valueFormat: 'YYYY-MM-DD HH:mm:ss' + } + #elseif($column.htmlType == "editor")## 文本编辑器 + component: 'Editor', + colProps: { + span: 24 + }, + componentProps: { + valueHtml: '' + } + #elseif($column.htmlType == "textarea")## 文本框 + component: 'Input', + componentProps: { + type: 'textarea', + rows: 4 + }, + colProps: { + span: 24 + } + #end + }, + #end + #if ($column.listOperationResult) + search: { + #if($column.htmlType == "input") + show: true + #else + #if($column.htmlType == "datetime") + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss' + } + #elseif($column.htmlType == "select" || $column.htmlType == "radio") + #if ("" == $dictType)## 没有数据字典 + show: true, + component: 'Select', + componentProps: { + option: [{'','请选择字典生成'}] + } + #else + show: true + #end + #end + #end + } + #end + #end + }, + #end +#end + { + label: t('table.action'), + field: 'action', + width: '240px', + form: { + show: false + }, + detail: { + show: false + } + } +]) + +export const { allSchemas } = useCrudSchemas(crudSchemas) \ No newline at end of file diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm new file mode 100644 index 000000000..d02892265 --- /dev/null +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm @@ -0,0 +1,214 @@ + + + diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java index 9eb3a70f1..cdd9db27e 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java @@ -22,6 +22,7 @@ import org.springframework.context.annotation.Import; import javax.annotation.Resource; import javax.validation.Validator; import java.io.Serializable; +import java.util.Date; import java.util.Map; import static cn.hutool.core.util.RandomUtil.randomEle; @@ -39,10 +40,10 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; /** -* {@link FileConfigServiceImpl} 的单元测试类 -* -* @author 芋道源码 -*/ + * {@link FileConfigServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ @Import(FileConfigServiceImpl.class) public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -172,8 +173,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { // 调用 fileConfigService.deleteFileConfig(id); - // 校验数据不存在了 - assertNull(fileConfigMapper.selectById(id)); + // 校验数据不存在了 + assertNull(fileConfigMapper.selectById(id)); // verify 调用 verify(fileConfigProducer).sendFileConfigRefreshMessage(); } @@ -201,30 +202,29 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @Test public void testGetFileConfigPage() { - // mock 数据 - FileConfigDO dbFileConfig = randomFileConfigDO().setName("芋道源码") - .setStorage(FileStorageEnum.LOCAL.getStorage()); - dbFileConfig.setCreateTime(buildTime(2022, 11, 11));// 等会查询到 - fileConfigMapper.insert(dbFileConfig); - // 测试 name 不匹配 - fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setName("源码"))); - // 测试 storage 不匹配 - fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setStorage(FileStorageEnum.DB.getStorage()))); - // 测试 createTime 不匹配 - fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setCreateTime(buildTime(2022, 12, 12)))); - // 准备参数 - FileConfigPageReqVO reqVO = new FileConfigPageReqVO(); - reqVO.setName("芋道"); - reqVO.setStorage(FileStorageEnum.LOCAL.getStorage()); - reqVO.setBeginCreateTime(buildTime(2022, 11, 10)); - reqVO.setEndCreateTime(buildTime(2022, 11, 12)); + // mock 数据 + FileConfigDO dbFileConfig = randomFileConfigDO().setName("芋道源码") + .setStorage(FileStorageEnum.LOCAL.getStorage()); + dbFileConfig.setCreateTime(buildTime(2022, 11, 11));// 等会查询到 + fileConfigMapper.insert(dbFileConfig); + // 测试 name 不匹配 + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setName("源码"))); + // 测试 storage 不匹配 + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setStorage(FileStorageEnum.DB.getStorage()))); + // 测试 createTime 不匹配 + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setCreateTime(buildTime(2022, 12, 12)))); + // 准备参数 + FileConfigPageReqVO reqVO = new FileConfigPageReqVO(); + reqVO.setName("芋道"); + reqVO.setStorage(FileStorageEnum.LOCAL.getStorage()); + reqVO.setCreateTime((new Date[]{buildTime(2022, 11, 10),buildTime(2022, 11, 12)})); - // 调用 - PageResult pageResult = fileConfigService.getFileConfigPage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbFileConfig, pageResult.getList().get(0)); + // 调用 + PageResult pageResult = fileConfigService.getFileConfigPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbFileConfig, pageResult.getList().get(0)); } @Test diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceTest.java index e61039385..2ccceac69 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceTest.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceTest.java @@ -15,6 +15,8 @@ import org.springframework.context.annotation.Import; import javax.annotation.Resource; +import java.util.Date; + import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; @@ -40,7 +42,7 @@ public class FileServiceTest extends BaseDbUnitTest { // mock 数据 FileDO dbFile = randomPojo(FileDO.class, o -> { // 等会查询到 o.setPath("yunai"); - o.setType("jpg"); + o.setType("image/jpg"); o.setCreateTime(buildTime(2021, 1, 15)); }); fileMapper.insert(dbFile); @@ -48,7 +50,7 @@ public class FileServiceTest extends BaseDbUnitTest { fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setPath("tudou"))); // 测试 type 不匹配 fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { - o.setType("png"); + o.setType("image/png"); })); // 测试 createTime 不匹配 fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { @@ -58,8 +60,7 @@ public class FileServiceTest extends BaseDbUnitTest { FilePageReqVO reqVO = new FilePageReqVO(); reqVO.setPath("yunai"); reqVO.setType("jp"); - reqVO.setBeginCreateTime(buildTime(2021, 1, 10)); - reqVO.setEndCreateTime(buildTime(2021, 1, 20)); + reqVO.setCreateTime((new Date[]{buildTime(2021, 1, 10),buildTime(2021, 1, 20)})); // 调用 PageResult pageResult = fileService.getFilePage(reqVO); @@ -90,7 +91,7 @@ public class FileServiceTest extends BaseDbUnitTest { assertEquals(10L, file.getConfigId()); assertEquals(path, file.getPath()); assertEquals(url, file.getUrl()); - assertEquals("jpg", file.getType()); + assertEquals("image/jpg", file.getType()); assertEquals(content.length, file.getSize()); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImplTest.java index 1aa699042..3da29f2df 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImplTest.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImplTest.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.infra.service.logger; import cn.hutool.core.util.RandomUtil; -import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -78,8 +77,7 @@ public class ApiAccessLogServiceImplTest extends BaseDbUnitTest { reqVO.setUserType(userType); reqVO.setApplicationName(applicationName); reqVO.setRequestUrl(requestUrl); - reqVO.setBeginBeginTime(buildTime(2021, 3, 12)); - reqVO.setEndBeginTime(buildTime(2021, 3, 14)); + reqVO.setBeginTime((new Date[]{buildTime(2021, 3, 12),buildTime(2021, 3, 14)})); reqVO.setDuration(duration); reqVO.setResultCode(resultCode); @@ -136,8 +134,7 @@ public class ApiAccessLogServiceImplTest extends BaseDbUnitTest { reqVO.setUserType(userType); reqVO.setApplicationName(applicationName); reqVO.setRequestUrl(requestUrl); - reqVO.setBeginBeginTime(buildTime(2021, 3, 12)); - reqVO.setEndBeginTime(buildTime(2021, 3, 14)); + reqVO.setBeginTime((new Date[]{buildTime(2021, 3, 12),buildTime(2021, 3, 14)})); reqVO.setDuration(duration); reqVO.setResultCode(resultCode); @@ -150,7 +147,7 @@ public class ApiAccessLogServiceImplTest extends BaseDbUnitTest { } @Test - public void testCreateApiAccessLog() { + public void testCreateApiAccessLogAsync() { // 准备参数 ApiAccessLogCreateReqDTO createDTO = RandomUtils.randomPojo(ApiAccessLogCreateReqDTO.class, dto -> dto.setUserType(RandomUtil.randomEle(UserTypeEnum.values()).getValue())); @@ -163,5 +160,4 @@ public class ApiAccessLogServiceImplTest extends BaseDbUnitTest { assertPojoEquals(createDTO, infApiAccessLogDO); } - } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImplTest.java index 6fdd7a368..4c4612716 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImplTest.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImplTest.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.infra.service.logger; import cn.hutool.core.util.RandomUtil; -import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLog; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; @@ -78,8 +77,7 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest { reqVO.setUserType(userType); reqVO.setApplicationName(applicationName); reqVO.setRequestUrl(requestUrl); - reqVO.setBeginExceptionTime(buildTime(2021, 3, 12)); - reqVO.setEndExceptionTime(buildTime(2021, 3, 14)); + reqVO.setExceptionTime((new Date[]{buildTime(2021, 3, 12),buildTime(2021, 3, 14)})); reqVO.setProcessStatus(progressStatus); // 调用service方法 @@ -131,8 +129,7 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest { reqVO.setUserType(userType); reqVO.setApplicationName(applicationName); reqVO.setRequestUrl(requestUrl); - reqVO.setBeginExceptionTime(buildTime(2021, 3, 12)); - reqVO.setEndExceptionTime(buildTime(2021, 3, 14)); + reqVO.setExceptionTime((new Date[]{buildTime(2021, 3, 12),buildTime(2021, 3, 14)})); reqVO.setProcessStatus(progressStatus); // 调用service方法 @@ -182,7 +179,7 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest { } @Test - public void testCreateApiErrorLog() { + public void testCreateApiErrorLogAsync() { // 准备参数 ApiErrorLogCreateReqDTO createDTO = RandomUtils.randomPojo(ApiErrorLogCreateReqDTO.class, dto -> dto.setUserType(RandomUtil.randomEle(UserTypeEnum.values()).getValue())); diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/test/TestDemoServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/test/TestDemoServiceImplTest.java index be02b0ed6..a099bc787 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/test/TestDemoServiceImplTest.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/test/TestDemoServiceImplTest.java @@ -14,8 +14,10 @@ import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; import javax.annotation.Resource; +import java.util.Date; import java.util.List; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; @@ -132,8 +134,7 @@ public class TestDemoServiceImplTest extends BaseDbUnitTest { reqVO.setType(1); reqVO.setCategory(2); reqVO.setRemark("哈哈哈"); - reqVO.setBeginCreateTime(DateUtils.buildTime(2021, 11, 10)); - reqVO.setEndCreateTime(DateUtils.buildTime(2021, 11, 12)); + reqVO.setCreateTime((new Date[]{buildTime(2021, 11, 10),buildTime(2021, 11, 12)})); // 调用 PageResult pageResult = testDemoService.getTestDemoPage(reqVO); @@ -174,8 +175,7 @@ public class TestDemoServiceImplTest extends BaseDbUnitTest { reqVO.setType(1); reqVO.setCategory(2); reqVO.setRemark("哈哈哈"); - reqVO.setBeginCreateTime(DateUtils.buildTime(2021, 11, 10)); - reqVO.setEndCreateTime(DateUtils.buildTime(2021, 11, 12)); + reqVO.setCreateTime((new Date[]{buildTime(2021, 11, 10),buildTime(2021, 11, 12)})); // 调用 List list = testDemoService.getTestDemoList(reqVO); diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserBindReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserBindReqDTO.java index ccc1c62ae..a3bb6b315 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserBindReqDTO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserBindReqDTO.java @@ -3,7 +3,9 @@ package cn.iocoder.yudao.module.system.api.social.dto; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; @@ -14,6 +16,8 @@ import javax.validation.constraints.NotNull; * @author 芋道源码 */ @Data +@NoArgsConstructor +@AllArgsConstructor public class SocialUserBindReqDTO { /** diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/auth/OAuth2ClientConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2ClientConstants.java similarity index 75% rename from yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/auth/OAuth2ClientConstants.java rename to yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2ClientConstants.java index e48e132ff..a123d57b9 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/auth/OAuth2ClientConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2ClientConstants.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.system.enums.auth; +package cn.iocoder.yudao.module.system.enums.oauth2; /** * OAuth2.0 客户端的通用枚举 diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/auth/OAuth2GrantTypeEnum.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2GrantTypeEnum.java similarity index 93% rename from yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/auth/OAuth2GrantTypeEnum.java rename to yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2GrantTypeEnum.java index 20eb8fce3..80ce4610b 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/auth/OAuth2GrantTypeEnum.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/oauth2/OAuth2GrantTypeEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.system.enums.auth; +package cn.iocoder.yudao.module.system.enums.oauth2; import cn.hutool.core.util.ArrayUtil; import lombok.AllArgsConstructor; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java index e42a5dfa5..ac12b5394 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java @@ -27,6 +27,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.util.List; @@ -59,6 +60,7 @@ public class AuthController { private SecurityProperties securityProperties; @PostMapping("/login") + @PermitAll @ApiOperation("使用账号密码登录") @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 public CommonResult login(@RequestBody @Valid AuthLoginReqVO reqVO) { @@ -66,6 +68,7 @@ public class AuthController { } @PostMapping("/logout") + @PermitAll @ApiOperation("登出系统") @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 public CommonResult logout(HttpServletRequest request) { @@ -77,6 +80,7 @@ public class AuthController { } @PostMapping("/refresh-token") + @PermitAll @ApiOperation("刷新令牌") @ApiImplicitParam(name = "refreshToken", value = "刷新令牌", required = true, dataTypeClass = String.class) @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 @@ -119,6 +123,7 @@ public class AuthController { // ========== 短信登录相关 ========== @PostMapping("/sms-login") + @PermitAll @ApiOperation("使用短信验证码登录") @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 public CommonResult smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) { @@ -126,6 +131,7 @@ public class AuthController { } @PostMapping("/send-sms-code") + @PermitAll @ApiOperation(value = "发送手机验证码") @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 public CommonResult sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) { @@ -136,28 +142,23 @@ public class AuthController { // ========== 社交登录相关 ========== @GetMapping("/social-auth-redirect") + @PermitAll @ApiOperation("社交授权的跳转") @ApiImplicitParams({ @ApiImplicitParam(name = "type", value = "社交类型", required = true, dataTypeClass = Integer.class), @ApiImplicitParam(name = "redirectUri", value = "回调路径", dataTypeClass = String.class) }) - public CommonResult socialAuthRedirect(@RequestParam("type") Integer type, - @RequestParam("redirectUri") String redirectUri) { + public CommonResult socialLogin(@RequestParam("type") Integer type, + @RequestParam("redirectUri") String redirectUri) { return CommonResult.success(socialUserService.getAuthorizeUrl(type, redirectUri)); } - @PostMapping("/social-quick-login") - @ApiOperation("社交快捷登录,使用 code 授权码") + @PostMapping("/social-login") + @PermitAll + @ApiOperation(value = "社交快捷登录,使用 code 授权码", notes = "适合未登录的用户,但是社交账号已绑定用户") @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 - public CommonResult socialQuickLogin(@RequestBody @Valid AuthSocialQuickLoginReqVO reqVO) { - return success(authService.socialQuickLogin(reqVO)); - } - - @PostMapping("/social-bind-login") - @ApiOperation("社交绑定登录,使用 code 授权码 + 账号密码") - @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 - public CommonResult socialBindLogin(@RequestBody @Valid AuthSocialBindLoginReqVO reqVO) { - return success(authService.socialBindLogin(reqVO)); + public CommonResult socialQuickLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) { + return success(authService.socialLogin(reqVO)); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java index 0ecd3d670..67e80d24a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthLoginReqVO.java @@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.system.controller.admin.auth.vo; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; @@ -8,10 +11,11 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.Length; +import javax.validation.constraints.AssertTrue; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Pattern; -@ApiModel("管理后台 - 账号密码登录 Request VO") +@ApiModel(value = "管理后台 - 账号密码登录 Request VO", description = "如果登录并绑定社交用户,需要传递 social 开头的参数") @Data @NoArgsConstructor @AllArgsConstructor @@ -29,6 +33,8 @@ public class AuthLoginReqVO { @Length(min = 4, max = 16, message = "密码长度为 4-16 位") private String password; + // ========== 图片验证码相关 ========== + @ApiModelProperty(value = "验证码", required = true, example = "1024", notes = "验证码开启时,需要传递") @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class) private String code; @@ -37,9 +43,31 @@ public class AuthLoginReqVO { @NotEmpty(message = "唯一标识不能为空", groups = CodeEnableGroup.class) private String uuid; + // ========== 绑定社交登录时,需要传递如下参数 ========== + + @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值") + @InEnum(SocialTypeEnum.class) + private Integer socialType; + + @ApiModelProperty(value = "授权码", required = true, example = "1024") + private String socialCode; + + @ApiModelProperty(value = "state", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + private String socialState; + /** * 开启验证码的 Group */ public interface CodeEnableGroup {} + @AssertTrue(message = "授权码不能为空") + public boolean isSocialCodeValid() { + return socialType == null || StrUtil.isNotEmpty(socialCode); + } + + @AssertTrue(message = "授权 state 不能为空") + public boolean isSocialState() { + return socialType == null || StrUtil.isNotEmpty(socialState); + } + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java index 5e4135546..b641bcca6 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSmsLoginReqVO.java @@ -1,17 +1,16 @@ package cn.iocoder.yudao.module.system.controller.admin.auth.vo; +import cn.iocoder.yudao.framework.common.validation.Mobile; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.Pattern; -@ApiModel("管理后台 - 短信验证码的呢老姑 Request VO") +@ApiModel("管理后台 - 短信验证码的登录 Request VO") @Data @NoArgsConstructor @AllArgsConstructor @@ -20,19 +19,11 @@ public class AuthSmsLoginReqVO { @ApiModelProperty(value = "手机号", required = true, example = "yudaoyuanma") @NotEmpty(message = "手机号不能为空") - @Length(min = 11, max = 11, message = "手机号格式错误,仅支持大陆手机号") - @Pattern(regexp = "^[1](([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}$", message = "账号格式为数字以及字母") + @Mobile private String mobile; - - - @ApiModelProperty(value = "短信验证码", required = true, example = "1024", notes = "验证码开启时,需要传递") - @NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class) + @ApiModelProperty(value = "短信验证码", required = true, example = "1024") + @NotEmpty(message = "验证码不能为空") private String code; - /** - * 开启验证码的 Group - */ - public interface CodeEnableGroup {} - } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialQuickLoginReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java similarity index 89% rename from yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialQuickLoginReqVO.java rename to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java index 4b7ebb175..e52a49288 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialQuickLoginReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthSocialLoginReqVO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.system.controller.admin.auth.vo; -import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; @@ -12,12 +12,12 @@ import lombok.NoArgsConstructor; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -@ApiModel("管理后台 - 社交快捷登录 Request VO,使用 code 授权码") +@ApiModel("管理后台 - 社交绑定登录 Request VO,使用 code 授权码 + 账号密码") @Data @NoArgsConstructor @AllArgsConstructor @Builder -public class AuthSocialQuickLoginReqVO { +public class AuthSocialLoginReqVO { @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 UserSocialTypeEnum 枚举值") @InEnum(SocialTypeEnum.class) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/common/CaptchaController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/common/CaptchaController.java index 5fc0b0a6b..546bbde00 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/common/CaptchaController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/common/CaptchaController.java @@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -22,6 +23,7 @@ public class CaptchaController { private CaptchaService captchaService; @GetMapping("/get-image") + @PermitAll @ApiOperation("生成图片验证码") public CommonResult getCaptchaImage() { return success(captchaService.getCaptchaImage()); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeExportReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeExportReqVO.java index 1043a1e72..e952b6b2f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeExportReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypeExportReqVO.java @@ -23,11 +23,7 @@ public class DictTypeExportReqVO { private Integer status; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypePageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypePageReqVO.java index 84635621c..5eab6bd80 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypePageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/vo/type/DictTypePageReqVO.java @@ -28,11 +28,7 @@ public class DictTypePageReqVO extends PageParam { private Integer status; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeExportReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeExportReqVO.java index 9f716152c..8659602f7 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeExportReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeExportReqVO.java @@ -26,11 +26,7 @@ public class ErrorCodeExportReqVO { private String message; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodePageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodePageReqVO.java index ff3d09833..cd01bdd43 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodePageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodePageReqVO.java @@ -31,11 +31,7 @@ public class ErrorCodePageReqVO extends PageParam { private String message; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogExportReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogExportReqVO.java index df1a57ea5..558c24cd1 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogExportReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogExportReqVO.java @@ -22,12 +22,8 @@ public class LoginLogExportReqVO { @ApiModelProperty(value = "操作状态", example = "true") private Boolean status; - @ApiModelProperty(value = "开始时间", example = "2020-10-24") + @ApiModelProperty(value = "登录时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date beginTime; - - @ApiModelProperty(value = "结束时间", example = "2020-10-24") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date endTime; + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogPageReqVO.java index ebefb728e..b792f6a9b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogPageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/loginlog/LoginLogPageReqVO.java @@ -25,12 +25,8 @@ public class LoginLogPageReqVO extends PageParam { @ApiModelProperty(value = "操作状态", example = "true") private Boolean status; - @ApiModelProperty(value = "开始时间", example = "2020-10-24") + @ApiModelProperty(value = "登录时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date beginTime; - - @ApiModelProperty(value = "结束时间", example = "2020-10-24") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date endTime; + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogExportReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogExportReqVO.java index 90adb822e..12eaa7d66 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogExportReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogExportReqVO.java @@ -25,12 +25,8 @@ public class OperateLogExportReqVO { @ApiModelProperty(value = "操作状态", example = "true") private Boolean success; - @ApiModelProperty(value = "开始时间", example = "2020-10-24") + @ApiModelProperty(value = "开始时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date beginTime; - - @ApiModelProperty(value = "结束时间", example = "2020-10-24") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date endTime; + private Date[] startTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java index 0741abd88..f8c594323 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/vo/operatelog/OperateLogPageReqVO.java @@ -26,12 +26,8 @@ public class OperateLogPageReqVO extends PageParam { @ApiModelProperty(value = "操作状态", example = "true") private Boolean success; - @ApiModelProperty(value = "开始时间", example = "2020-10-24") + @ApiModelProperty(value = "开始时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date beginTime; - - @ApiModelProperty(value = "结束时间", example = "2020-10-24") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date endTime; + private Date[] startTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java index 45618c4bd..8ab096587 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java @@ -16,7 +16,7 @@ import cn.iocoder.yudao.module.system.convert.oauth2.OAuth2OpenConvert; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; -import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum; +import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2GrantTypeEnum; import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService; import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService; @@ -31,6 +31,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import javax.servlet.http.HttpServletRequest; import java.util.Collections; import java.util.List; @@ -82,6 +83,7 @@ public class OAuth2OpenController { * 注意,默认需要传递 client_id + client_secret 参数 */ @PostMapping("/token") + @PermitAll @ApiOperation(value = "获得访问令牌", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用") @ApiImplicitParams({ @ApiImplicitParam(name = "grant_type", required = true, value = "授权类型", example = "code", dataTypeClass = String.class), @@ -141,6 +143,7 @@ public class OAuth2OpenController { } @DeleteMapping("/token") + @PermitAll @ApiOperation(value = "删除访问令牌") @ApiImplicitParam(name = "token", required = true, value = "访问令牌", example = "biu", dataTypeClass = String.class) @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 @@ -159,6 +162,7 @@ public class OAuth2OpenController { * 对应 Spring Security OAuth 的 CheckTokenEndpoint 类的 checkToken 方法 */ @PostMapping("/check-token") + @PermitAll @ApiOperation(value = "校验访问令牌") @ApiImplicitParam(name = "token", required = true, value = "访问令牌", example = "biu", dataTypeClass = String.class) @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleExportReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleExportReqVO.java index 02e47ac6f..d3ab4565f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleExportReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleExportReqVO.java @@ -22,12 +22,8 @@ public class RoleExportReqVO { @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类") private Integer status; - @ApiModelProperty(value = "开始时间", example = "2020-10-24") + @ApiModelProperty(value = "开始时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date beginTime; - - @ApiModelProperty(value = "结束时间", example = "2020-10-24") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date endTime; + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RolePageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RolePageReqVO.java index 2f4cc1858..ca81b9c13 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RolePageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RolePageReqVO.java @@ -25,12 +25,7 @@ public class RolePageReqVO extends PageParam { @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类") private Integer status; - @ApiModelProperty(value = "开始时间", example = "2020-10-24") + @ApiModelProperty(value = "开始时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date beginTime; - - @ApiModelProperty(value = "结束时间", example = "2020-10-24") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date endTime; - + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordExportReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordExportReqVO.java index cec4944de..85e2aa92e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordExportReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordExportReqVO.java @@ -23,11 +23,7 @@ public class SensitiveWordExportReqVO { private Integer status; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordPageReqVO.java index 45d9cf161..411ff6e69 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordPageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordPageReqVO.java @@ -28,11 +28,7 @@ public class SensitiveWordPageReqVO extends PageParam { private Integer status; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java index a21582cbd..ed32e00cf 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java @@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import javax.servlet.http.HttpServletRequest; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -28,6 +29,7 @@ public class SmsCallbackController { private SmsSendService smsSendService; @PostMapping("/yunpian") + @PermitAll @ApiOperation(value = "云片短信的回调", notes = "参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档") @ApiImplicitParam(name = "sms_status", value = "发送状态", required = true, example = "[{具体内容}]", dataTypeClass = String.class) @OperateLog(enable = false) @@ -38,6 +40,7 @@ public class SmsCallbackController { } @PostMapping("/aliyun") + @PermitAll @ApiOperation(value = "阿里云短信的回调", notes = "参见 https://help.aliyun.com/document_detail/120998.html 文档") @OperateLog(enable = false) public CommonResult receiveAliyunSmsStatus(HttpServletRequest request) throws Throwable { @@ -47,6 +50,7 @@ public class SmsCallbackController { } @PostMapping("/tencent") + @PermitAll @ApiOperation(value = "腾讯云短信的回调", notes = "参见 https://cloud.tencent.com/document/product/382/52077 文档") @OperateLog(enable = false) public CommonResult receiveTencentSmsStatus(HttpServletRequest request) throws Throwable { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelPageReqVO.java index 306c7d06f..b41ecc88c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelPageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/channel/SmsChannelPageReqVO.java @@ -25,11 +25,7 @@ public class SmsChannelPageReqVO extends PageParam { private String signature; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogExportReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogExportReqVO.java index 6754b43b2..0f493fa2b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogExportReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogExportReqVO.java @@ -27,21 +27,13 @@ public class SmsLogExportReqVO { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @ApiModelProperty(value = "开始发送时间") - private Date beginSendTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束发送时间") - private Date endSendTime; + private Date[] sendTime; @ApiModelProperty(value = "接收状态", example = "0") private Integer receiveStatus; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @ApiModelProperty(value = "开始接收时间") - private Date beginReceiveTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束接收时间") - private Date endReceiveTime; + private Date[] receiveTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogPageReqVO.java index 767201f81..1bf4b04d2 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogPageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogPageReqVO.java @@ -32,21 +32,13 @@ public class SmsLogPageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @ApiModelProperty(value = "开始发送时间") - private Date beginSendTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束发送时间") - private Date endSendTime; + private Date[] sendTime; @ApiModelProperty(value = "接收状态", example = "0", notes = "参见 SmsReceiveStatusEnum 枚举类") private Integer receiveStatus; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @ApiModelProperty(value = "开始接收时间") - private Date beginReceiveTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束接收时间") - private Date endReceiveTime; + private Date[] receiveTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateExportReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateExportReqVO.java index e775e4c70..b25e60548 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateExportReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateExportReqVO.java @@ -32,11 +32,7 @@ public class SmsTemplateExportReqVO { private Long channelId; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplatePageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplatePageReqVO.java index 6932d2946..5a6a3d47f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplatePageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplatePageReqVO.java @@ -37,11 +37,7 @@ public class SmsTemplatePageReqVO extends PageParam { private Long channelId; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java index 427172b18..acc21d3fa 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java @@ -15,6 +15,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; @@ -32,6 +33,7 @@ public class TenantController { private TenantService tenantService; @GetMapping("/get-id-by-name") + @PermitAll @ApiOperation(value = "使用租户名,获得租户编号", notes = "登录界面,根据用户的租户名,获得租户编号") @ApiImplicitParam(name = "name", value = "租户名", required = true, example = "1024", dataTypeClass = Long.class) public CommonResult getTenantIdByName(@RequestParam("name") String name) { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackagePageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackagePageReqVO.java index 8dd5b609d..66e9a77ad 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackagePageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackagePageReqVO.java @@ -28,11 +28,7 @@ public class TenantPackagePageReqVO extends PageParam { private String remark; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantExportReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantExportReqVO.java index 1ce620efd..dcf0bb120 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantExportReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantExportReqVO.java @@ -26,11 +26,7 @@ public class TenantExportReqVO { private Integer status; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java index 9723985a3..711ac3c84 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantPageReqVO.java @@ -31,11 +31,7 @@ public class TenantPageReqVO extends PageParam { private Integer status; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "开始创建时间") - private Date beginCreateTime; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "结束创建时间") - private Date endCreateTime; + @ApiModelProperty(value = "创建时间") + private Date[] createTime; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserExportReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserExportReqVO.java index a25ba0b0f..4c25d0ce2 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserExportReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserExportReqVO.java @@ -26,13 +26,9 @@ public class UserExportReqVO { @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类") private Integer status; - @ApiModelProperty(value = "开始时间", example = "2020-10-24") + @ApiModelProperty(value = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date beginTime; - - @ApiModelProperty(value = "结束时间", example = "2020-10-24") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date endTime; + private Date[] createTime; @ApiModelProperty(value = "部门编号", example = "1024", notes = "同时筛选子部门") private Long deptId; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserPageReqVO.java index 00f20eb4d..c4f13a21e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserPageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserPageReqVO.java @@ -29,13 +29,9 @@ public class UserPageReqVO extends PageParam { @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 CommonStatusEnum 枚举类") private Integer status; - @ApiModelProperty(value = "开始时间", example = "2020-10-24") + @ApiModelProperty(value = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date beginTime; - - @ApiModelProperty(value = "结束时间", example = "2020-10-24") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date endTime; + private Date[] createTime; @ApiModelProperty(value = "部门编号", example = "1024", notes = "同时筛选子部门") private Long deptId; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java index 62784defa..7bbd24c45 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java @@ -66,7 +66,6 @@ public interface AuthConvert { } SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialBindLoginReqVO reqVO); - SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialQuickLoginReqVO reqVO); SmsCodeSendReqDTO convert(AuthSmsSendReqVO reqVO); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2ClientDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2ClientDO.java index 7264f6c41..721a42e91 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2ClientDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/oauth2/OAuth2ClientDO.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.oauth2; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum; +import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2GrantTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictTypeMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictTypeMapper.java index 85c2acee4..7f87fde77 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictTypeMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictTypeMapper.java @@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypeExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.dict.vo.type.DictTypePageReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO; import org.apache.ibatis.annotations.Mapper; @@ -19,7 +18,7 @@ public interface DictTypeMapper extends BaseMapperX { .likeIfPresent(DictTypeDO::getName, reqVO.getName()) .likeIfPresent(DictTypeDO::getType, reqVO.getType()) .eqIfPresent(DictTypeDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(DictTypeDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(DictTypeDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(DictTypeDO::getId)); } @@ -28,7 +27,7 @@ public interface DictTypeMapper extends BaseMapperX { .likeIfPresent(DictTypeDO::getName, reqVO.getName()) .likeIfPresent(DictTypeDO::getType, reqVO.getType()) .eqIfPresent(DictTypeDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(DictTypeDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())); + .betweenIfPresent(DictTypeDO::getCreateTime, reqVO.getCreateTime())); } default DictTypeDO selectByType(String type) { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/errorcode/ErrorCodeMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/errorcode/ErrorCodeMapper.java index 84842497c..0fcfbf68b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/errorcode/ErrorCodeMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/errorcode/ErrorCodeMapper.java @@ -2,11 +2,10 @@ package cn.iocoder.yudao.module.system.dal.mysql.errorcode; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodeExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodePageReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.errorcode.ErrorCodeDO; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.apache.ibatis.annotations.Mapper; import java.util.Collection; @@ -17,36 +16,36 @@ import java.util.List; public interface ErrorCodeMapper extends BaseMapperX { default PageResult selectPage(ErrorCodePageReqVO reqVO) { - return selectPage(reqVO, new QueryWrapperX() - .eqIfPresent("type", reqVO.getType()) - .likeIfPresent("application_name", reqVO.getApplicationName()) - .eqIfPresent("code", reqVO.getCode()) - .likeIfPresent("message", reqVO.getMessage()) - .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) - .orderByDesc("code")); + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ErrorCodeDO::getType, reqVO.getType()) + .likeIfPresent(ErrorCodeDO::getApplicationName, reqVO.getApplicationName()) + .eqIfPresent(ErrorCodeDO::getCode, reqVO.getCode()) + .likeIfPresent(ErrorCodeDO::getMessage, reqVO.getMessage()) + .betweenIfPresent(ErrorCodeDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ErrorCodeDO::getCode)); } default List selectList(ErrorCodeExportReqVO reqVO) { - return selectList(new QueryWrapperX() - .eqIfPresent("type", reqVO.getType()) - .likeIfPresent("application_name", reqVO.getApplicationName()) - .eqIfPresent("code", reqVO.getCode()) - .likeIfPresent("message", reqVO.getMessage()) - .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) - .orderByAsc("application_name", "code")); + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(ErrorCodeDO::getType, reqVO.getType()) + .likeIfPresent(ErrorCodeDO::getApplicationName, reqVO.getApplicationName()) + .eqIfPresent(ErrorCodeDO::getCode, reqVO.getCode()) + .likeIfPresent(ErrorCodeDO::getMessage, reqVO.getMessage()) + .betweenIfPresent(ErrorCodeDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ErrorCodeDO::getCode)); } default List selectListByCodes(Collection codes) { - return selectList(new QueryWrapper().in("code", codes)); + return selectList(new LambdaQueryWrapperX().in(ErrorCodeDO::getCode, codes)); } default ErrorCodeDO selectByCode(Integer code) { - return selectOne(new QueryWrapper().eq("code", code)); + return selectOne(new LambdaQueryWrapperX().eq(ErrorCodeDO::getCode, code)); } default List selectListByApplicationNameAndUpdateTimeGt(String applicationName, Date minUpdateTime) { - return selectList(new QueryWrapperX().eq("application_name", applicationName) - .gtIfPresent("update_time", minUpdateTime)); + return selectList(new LambdaQueryWrapperX().eq(ErrorCodeDO::getApplicationName, applicationName) + .gtIfPresent(ErrorCodeDO::getUpdateTime, minUpdateTime)); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/LoginLogMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/LoginLogMapper.java index a2731a5f6..1617fe075 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/LoginLogMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/LoginLogMapper.java @@ -1,11 +1,11 @@ package cn.iocoder.yudao.module.system.dal.mysql.logger; -import cn.iocoder.yudao.module.system.dal.dataobject.logger.LoginLogDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.logger.LoginLogDO; import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; import org.apache.ibatis.annotations.Mapper; @@ -15,30 +15,30 @@ import java.util.List; public interface LoginLogMapper extends BaseMapperX { default PageResult selectPage(LoginLogPageReqVO reqVO) { - QueryWrapperX query = new QueryWrapperX() - .likeIfPresent("user_ip", reqVO.getUserIp()) - .likeIfPresent("username", reqVO.getUsername()) - .betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()); + LambdaQueryWrapperX query = new LambdaQueryWrapperX() + .likeIfPresent(LoginLogDO::getUserIp, reqVO.getUserIp()) + .likeIfPresent(LoginLogDO::getUsername, reqVO.getUsername()) + .betweenIfPresent(LoginLogDO::getCreateTime, reqVO.getCreateTime()); if (Boolean.TRUE.equals(reqVO.getStatus())) { - query.eq("result", LoginResultEnum.SUCCESS.getResult()); + query.eq(LoginLogDO::getResult, LoginResultEnum.SUCCESS.getResult()); } else if (Boolean.FALSE.equals(reqVO.getStatus())) { - query.gt("result", LoginResultEnum.SUCCESS.getResult()); + query.gt(LoginLogDO::getResult, LoginResultEnum.SUCCESS.getResult()); } - query.orderByDesc("id"); // 降序 + query.orderByDesc(LoginLogDO::getId); // 降序 return selectPage(reqVO, query); } default List selectList(LoginLogExportReqVO reqVO) { - QueryWrapperX query = new QueryWrapperX() - .likeIfPresent("user_ip", reqVO.getUserIp()) - .likeIfPresent("username", reqVO.getUsername()) - .betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()); + LambdaQueryWrapperX query = new LambdaQueryWrapperX() + .likeIfPresent(LoginLogDO::getUserIp, reqVO.getUserIp()) + .likeIfPresent(LoginLogDO::getUsername, reqVO.getUsername()) + .betweenIfPresent(LoginLogDO::getCreateTime, reqVO.getCreateTime()); if (Boolean.TRUE.equals(reqVO.getStatus())) { - query.eq("result", LoginResultEnum.SUCCESS.getResult()); + query.eq(LoginLogDO::getResult, LoginResultEnum.SUCCESS.getResult()); } else if (Boolean.FALSE.equals(reqVO.getStatus())) { - query.gt("result", LoginResultEnum.SUCCESS.getResult()); + query.gt(LoginLogDO::getResult, LoginResultEnum.SUCCESS.getResult()); } - query.orderByDesc("id"); // 降序 + query.orderByDesc(LoginLogDO::getId); // 降序 return selectList(query); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogMapper.java index c8e0f2442..86e53a510 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogMapper.java @@ -20,7 +20,7 @@ public interface OperateLogMapper extends BaseMapperX { .likeIfPresent(OperateLogDO::getModule, reqVO.getModule()) .inIfPresent(OperateLogDO::getUserId, userIds) .eqIfPresent(OperateLogDO::getType, reqVO.getType()) - .betweenIfPresent(OperateLogDO::getStartTime, reqVO.getBeginTime(), reqVO.getEndTime()); + .betweenIfPresent(OperateLogDO::getStartTime, reqVO.getStartTime()); if (Boolean.TRUE.equals(reqVO.getSuccess())) { query.eq(OperateLogDO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode()); } else if (Boolean.FALSE.equals(reqVO.getSuccess())) { @@ -35,7 +35,7 @@ public interface OperateLogMapper extends BaseMapperX { .likeIfPresent(OperateLogDO::getModule, reqVO.getModule()) .inIfPresent(OperateLogDO::getUserId, userIds) .eqIfPresent(OperateLogDO::getType, reqVO.getType()) - .betweenIfPresent(OperateLogDO::getStartTime, reqVO.getBeginTime(), reqVO.getEndTime()); + .betweenIfPresent(OperateLogDO::getStartTime, reqVO.getStartTime()); if (Boolean.TRUE.equals(reqVO.getSuccess())) { query.eq(OperateLogDO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode()); } else if (Boolean.FALSE.equals(reqVO.getSuccess())) { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java index 359c7290b..de0bb68d9 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java @@ -23,7 +23,7 @@ public interface RoleMapper extends BaseMapperX { .likeIfPresent(RoleDO::getName, reqVO.getName()) .likeIfPresent(RoleDO::getCode, reqVO.getCode()) .eqIfPresent(RoleDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(BaseDO::getCreateTime, reqVO.getBeginTime(), reqVO.getEndTime()) + .betweenIfPresent(BaseDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(RoleDO::getId)); } @@ -32,7 +32,7 @@ public interface RoleMapper extends BaseMapperX { .likeIfPresent(RoleDO::getName, reqVO.getName()) .likeIfPresent(RoleDO::getCode, reqVO.getCode()) .eqIfPresent(RoleDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(BaseDO::getCreateTime, reqVO.getBeginTime(), reqVO.getEndTime())); + .betweenIfPresent(BaseDO::getCreateTime, reqVO.getCreateTime())); } default RoleDO selectByName(String name) { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sensitiveword/SensitiveWordMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sensitiveword/SensitiveWordMapper.java index 4529f1a50..85d5dd3e9 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sensitiveword/SensitiveWordMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sensitiveword/SensitiveWordMapper.java @@ -25,7 +25,7 @@ public interface SensitiveWordMapper extends BaseMapperX { .likeIfPresent(SensitiveWordDO::getName, reqVO.getName()) .likeIfPresent(SensitiveWordDO::getTags, reqVO.getTag()) .eqIfPresent(SensitiveWordDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(SensitiveWordDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(SensitiveWordDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(SensitiveWordDO::getId)); } @@ -34,7 +34,7 @@ public interface SensitiveWordMapper extends BaseMapperX { .likeIfPresent(SensitiveWordDO::getName, reqVO.getName()) .likeIfPresent(SensitiveWordDO::getTags, reqVO.getTag()) .eqIfPresent(SensitiveWordDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(SensitiveWordDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(SensitiveWordDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(SensitiveWordDO::getId)); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsChannelMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsChannelMapper.java index fbef490a5..d331ee43e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsChannelMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsChannelMapper.java @@ -17,7 +17,7 @@ public interface SmsChannelMapper extends BaseMapperX { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(SmsChannelDO::getSignature, reqVO.getSignature()) .eqIfPresent(SmsChannelDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(SmsChannelDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(SmsChannelDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(SmsChannelDO::getId)); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsLogMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsLogMapper.java index 01ea77a46..33f93a8a1 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsLogMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsLogMapper.java @@ -1,11 +1,11 @@ package cn.iocoder.yudao.module.system.dal.mysql.sms; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -14,27 +14,27 @@ import java.util.List; public interface SmsLogMapper extends BaseMapperX { default PageResult selectPage(SmsLogPageReqVO reqVO) { - return selectPage(reqVO, new QueryWrapperX() - .eqIfPresent("channel_id", reqVO.getChannelId()) - .eqIfPresent("template_id", reqVO.getTemplateId()) - .likeIfPresent("mobile", reqVO.getMobile()) - .eqIfPresent("send_status", reqVO.getSendStatus()) - .betweenIfPresent("send_time", reqVO.getBeginSendTime(), reqVO.getEndSendTime()) - .eqIfPresent("receive_status", reqVO.getReceiveStatus()) - .betweenIfPresent("receive_time", reqVO.getBeginReceiveTime(), reqVO.getEndReceiveTime()) - .orderByDesc("id")); + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(SmsLogDO::getChannelId, reqVO.getChannelId()) + .eqIfPresent(SmsLogDO::getTemplateId, reqVO.getTemplateId()) + .likeIfPresent(SmsLogDO::getMobile, reqVO.getMobile()) + .eqIfPresent(SmsLogDO::getSendStatus, reqVO.getSendStatus()) + .betweenIfPresent(SmsLogDO::getSendTime, reqVO.getSendTime()) + .eqIfPresent(SmsLogDO::getSendStatus, reqVO.getReceiveStatus()) + .betweenIfPresent(SmsLogDO::getReceiveTime, reqVO.getReceiveTime()) + .orderByDesc(SmsLogDO::getId)); } default List selectList(SmsLogExportReqVO reqVO) { - return selectList(new QueryWrapperX() - .eqIfPresent("channel_id", reqVO.getChannelId()) - .eqIfPresent("template_id", reqVO.getTemplateId()) - .likeIfPresent("mobile", reqVO.getMobile()) - .eqIfPresent("send_status", reqVO.getSendStatus()) - .betweenIfPresent("send_time", reqVO.getBeginSendTime(), reqVO.getEndSendTime()) - .eqIfPresent("receive_status", reqVO.getReceiveStatus()) - .betweenIfPresent("receive_time", reqVO.getBeginReceiveTime(), reqVO.getEndReceiveTime()) - .orderByDesc("id")); + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(SmsLogDO::getChannelId, reqVO.getChannelId()) + .eqIfPresent(SmsLogDO::getTemplateId, reqVO.getTemplateId()) + .likeIfPresent(SmsLogDO::getMobile, reqVO.getMobile()) + .eqIfPresent(SmsLogDO::getSendStatus, reqVO.getSendStatus()) + .betweenIfPresent(SmsLogDO::getSendTime, reqVO.getSendTime()) + .eqIfPresent(SmsLogDO::getSendStatus, reqVO.getReceiveStatus()) + .betweenIfPresent(SmsLogDO::getReceiveTime, reqVO.getReceiveTime()) + .orderByDesc(SmsLogDO::getId)); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java index d89449156..d41ee75b0 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java @@ -30,7 +30,7 @@ public interface SmsTemplateMapper extends BaseMapperX { .likeIfPresent(SmsTemplateDO::getContent, reqVO.getContent()) .likeIfPresent(SmsTemplateDO::getApiTemplateId, reqVO.getApiTemplateId()) .eqIfPresent(SmsTemplateDO::getChannelId, reqVO.getChannelId()) - .betweenIfPresent(SmsTemplateDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(SmsTemplateDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(SmsTemplateDO::getId)); } @@ -42,7 +42,7 @@ public interface SmsTemplateMapper extends BaseMapperX { .likeIfPresent(SmsTemplateDO::getContent, reqVO.getContent()) .likeIfPresent(SmsTemplateDO::getApiTemplateId, reqVO.getApiTemplateId()) .eqIfPresent(SmsTemplateDO::getChannelId, reqVO.getChannelId()) - .betweenIfPresent(SmsTemplateDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(SmsTemplateDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(SmsTemplateDO::getId)); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java index 39d04edd3..33771eeb2 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java @@ -26,7 +26,7 @@ public interface TenantMapper extends BaseMapperX { .likeIfPresent(TenantDO::getContactName, reqVO.getContactName()) .likeIfPresent(TenantDO::getContactMobile, reqVO.getContactMobile()) .eqIfPresent(TenantDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(TenantDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(TenantDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(TenantDO::getId)); } @@ -36,7 +36,7 @@ public interface TenantMapper extends BaseMapperX { .likeIfPresent(TenantDO::getContactName, reqVO.getContactName()) .likeIfPresent(TenantDO::getContactMobile, reqVO.getContactMobile()) .eqIfPresent(TenantDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(TenantDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(TenantDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(TenantDO::getId)); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantPackageMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantPackageMapper.java index 2f7006555..e8a41c770 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantPackageMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantPackageMapper.java @@ -22,7 +22,7 @@ public interface TenantPackageMapper extends BaseMapperX { .likeIfPresent(TenantPackageDO::getName, reqVO.getName()) .eqIfPresent(TenantPackageDO::getStatus, reqVO.getStatus()) .likeIfPresent(TenantPackageDO::getRemark, reqVO.getRemark()) - .betweenIfPresent(TenantPackageDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .betweenIfPresent(TenantPackageDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(TenantPackageDO::getId)); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java index b7d5e3daa..e6713bacb 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java @@ -1,12 +1,11 @@ package cn.iocoder.yudao.module.system.dal.mysql.user; -import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserExportReqVO; -import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; -import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserExportReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; @@ -33,10 +32,9 @@ public interface AdminUserMapper extends BaseMapperX { .likeIfPresent(AdminUserDO::getUsername, reqVO.getUsername()) .likeIfPresent(AdminUserDO::getMobile, reqVO.getMobile()) .eqIfPresent(AdminUserDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(AdminUserDO::getCreateTime, reqVO.getBeginTime(), reqVO.getEndTime()) + .betweenIfPresent(AdminUserDO::getCreateTime, reqVO.getCreateTime()) .inIfPresent(AdminUserDO::getDeptId, deptIds) .orderByDesc(AdminUserDO::getId)); - } default List selectList(UserExportReqVO reqVO, Collection deptIds) { @@ -44,7 +42,7 @@ public interface AdminUserMapper extends BaseMapperX { .likeIfPresent(AdminUserDO::getUsername, reqVO.getUsername()) .likeIfPresent(AdminUserDO::getMobile, reqVO.getMobile()) .eqIfPresent(AdminUserDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(AdminUserDO::getCreateTime, reqVO.getBeginTime(), reqVO.getEndTime()) + .betweenIfPresent(AdminUserDO::getCreateTime, reqVO.getCreateTime()) .inIfPresent(AdminUserDO::getDeptId, deptIds)); } @@ -65,4 +63,3 @@ public interface AdminUserMapper extends BaseMapperX { } } - diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java index e7794420c..8fa03ca41 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java @@ -19,27 +19,6 @@ public class SecurityConfiguration { @Override public void customize(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry) { - // 登录的接口 - registry.antMatchers(buildAdminApi("/system/auth/login")).permitAll(); - registry.antMatchers(buildAdminApi("/system/auth/logout")).permitAll(); - registry.antMatchers(buildAdminApi("/system/auth/refresh-token")).permitAll(); - // 社交登陆的接口 - registry.antMatchers(buildAdminApi("/system/auth/social-auth-redirect")).permitAll(); - registry.antMatchers(buildAdminApi("/system/auth/social-quick-login")).permitAll(); - registry.antMatchers(buildAdminApi("/system/auth/social-bind-login")).permitAll(); - // 登录登录的接口 - registry.antMatchers(buildAdminApi("/system/auth/sms-login")).permitAll(); - registry.antMatchers(buildAdminApi("/system/auth/send-sms-code")).permitAll(); - // 验证码的接口 - registry.antMatchers(buildAdminApi("/system/captcha/**")).permitAll(); - // 获得租户编号的接口 - registry.antMatchers(buildAdminApi("/system/tenant/get-id-by-name")).permitAll(); - // 短信回调 API - registry.antMatchers(buildAdminApi("/system/sms/callback/**")).permitAll(); - // OAuth2 API - registry.antMatchers(buildAdminApi("/system/oauth2/token")).permitAll(); - registry.antMatchers(buildAdminApi("/system/oauth2/check-token")).permitAll(); - // TODO 芋艿:这个每个项目都需要重复配置,得捉摸有没通用的方案 // Swagger 接口文档 registry.antMatchers("/swagger-ui.html").anonymous() diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java index 3a53c1aa3..52796ec2f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java @@ -60,15 +60,7 @@ public interface AdminAuthService { * @param reqVO 登录信息 * @return 登录结果 */ - AuthLoginRespVO socialQuickLogin(@Valid AuthSocialQuickLoginReqVO reqVO); - - /** - * 社交绑定登录,使用 code 授权码 + 账号密码 - * - * @param reqVO 登录信息 - * @return 登录结果 - */ - AuthLoginRespVO socialBindLogin(@Valid AuthSocialBindLoginReqVO reqVO); + AuthLoginRespVO socialLogin(@Valid AuthSocialLoginReqVO reqVO); /** * 刷新访问令牌 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java index 5264cae2b..8f54e9f61 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java @@ -8,13 +8,14 @@ import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; -import cn.iocoder.yudao.module.system.enums.auth.OAuth2ClientConstants; import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; +import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants; import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; import cn.iocoder.yudao.module.system.service.common.CaptchaService; import cn.iocoder.yudao.module.system.service.logger.LoginLogService; @@ -91,6 +92,12 @@ public class AdminAuthServiceImpl implements AdminAuthService { // 使用账号密码,进行登录 AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword()); + // 如果 socialType 非空,说明需要绑定社交用户 + if (reqVO.getSocialType() != null) { + socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), + reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); + } + // 创建 Token 令牌,记录登录日志 return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME); } @@ -116,7 +123,7 @@ public class AdminAuthServiceImpl implements AdminAuthService { throw exception(USER_NOT_EXISTS); } - // 缓存登陆用户到 Redis 中,返回 sessionId 编号 + // 创建 Token 令牌,记录登录日志 return createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE); } @@ -166,7 +173,7 @@ public class AdminAuthServiceImpl implements AdminAuthService { } @Override - public AuthLoginRespVO socialQuickLogin(AuthSocialQuickLoginReqVO reqVO) { + public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) { // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 Long userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), reqVO.getCode(), reqVO.getState()); @@ -184,18 +191,6 @@ public class AdminAuthServiceImpl implements AdminAuthService { return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL); } - @Override - public AuthLoginRespVO socialBindLogin(AuthSocialBindLoginReqVO reqVO) { - // 使用账号密码,进行登录。 - AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword()); - - // 绑定社交用户 - socialUserService.bindSocialUser(AuthConvert.INSTANCE.convert(user.getId(), getUserType().getValue(), reqVO)); - - // 创建 Token 令牌,记录登录日志 - return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL); - } - @Override public AuthLoginRespVO refreshToken(String refreshToken) { OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImpl.java index 608985454..bd2f1d409 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImpl.java @@ -11,6 +11,7 @@ import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; @@ -40,7 +41,8 @@ public class SmsSendServiceImpl implements SmsSendService { private AdminUserService adminUserService; @Resource private MemberService memberService; - + @Resource + private SmsChannelService smsChannelService; @Resource private SmsTemplateService smsTemplateService; @Resource @@ -80,13 +82,18 @@ public class SmsSendServiceImpl implements SmsSendService { String templateCode, Map templateParams) { // 校验短信模板是否合法 SmsTemplateDO template = this.checkSmsTemplateValid(templateCode); + // 校验短信渠道是否合法 + SmsChannelDO smsChannel = this.checkSmsChannelValid(template.getChannelId()); + // 校验手机号码是否存在 mobile = this.checkMobile(mobile); // 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志 List> newTemplateParams = this.buildTemplateParams(template, templateParams); // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志 - Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); + Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()) + && CommonStatusEnum.ENABLE.getStatus().equals(smsChannel.getStatus()); + ; String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams); Long sendLogId = smsLogService.createSmsLog(mobile, userId, userType, isSend, template, content, templateParams); @@ -98,6 +105,16 @@ public class SmsSendServiceImpl implements SmsSendService { return sendLogId; } + @VisibleForTesting + public SmsChannelDO checkSmsChannelValid(Long channelId) { + // 获得短信模板。考虑到效率,从缓存中获取 + SmsChannelDO channelDO = smsChannelService.getSmsChannel(channelId); + // 短信模板不存在 + if (channelDO == null) { + throw exception(SMS_SEND_TEMPLATE_NOT_EXISTS); + } + return channelDO; + } @VisibleForTesting public SmsTemplateDO checkSmsTemplateValid(String templateCode) { @@ -112,10 +129,10 @@ public class SmsSendServiceImpl implements SmsSendService { /** * 将参数模板,处理成有序的 KeyValue 数组 - * + *

* 原因是,部分短信平台并不是使用 key 作为参数,而是数组下标,例如说腾讯云 https://cloud.tencent.com/document/product/382/39023 * - * @param template 短信模板 + * @param template 短信模板 * @param templateParams 原始参数 * @return 处理后的参数 */ diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml b/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml index 0d8092d3b..7873a0d66 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml @@ -102,7 +102,7 @@ spring: client: url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 设置 Spring Boot Admin Server 地址 instance: - prefer-ip: true # 注册实例时,优先使用 IP + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] # Spring Boot Admin Server 服务端的相关配置 context-path: /admin # 配置 Spring diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java index fe787a953..3e6cc282e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java @@ -14,7 +14,7 @@ import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2Open import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; -import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum; +import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2GrantTypeEnum; import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService; import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService; diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceTest.java index 127e602ea..a3ac2cba3 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceTest.java @@ -16,6 +16,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import javax.annotation.Resource; +import java.util.Date; import java.util.List; import java.util.function.Consumer; @@ -42,36 +43,35 @@ public class DictTypeServiceTest extends BaseDbUnitTest { @Test public void testGetDictTypePage() { - // mock 数据 - DictTypeDO dbDictType = randomPojo(DictTypeDO.class, o -> { // 等会查询到 - o.setName("yunai"); - o.setType("芋艿"); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - o.setCreateTime(buildTime(2021, 1, 15)); - }); - dictTypeMapper.insert(dbDictType); - // 测试 name 不匹配 - dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setName("tudou"))); - // 测试 type 不匹配 - dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setType("土豆"))); - // 测试 status 不匹配 - dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); - // 测试 createTime 不匹配 - dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setCreateTime(buildTime(2021, 1, 1)))); - // 准备参数 - DictTypePageReqVO reqVO = new DictTypePageReqVO(); - reqVO.setName("nai"); - reqVO.setType("艿"); - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setBeginCreateTime(buildTime(2021, 1, 10)); - reqVO.setEndCreateTime(buildTime(2021, 1, 20)); + // mock 数据 + DictTypeDO dbDictType = randomPojo(DictTypeDO.class, o -> { // 等会查询到 + o.setName("yunai"); + o.setType("芋艿"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2021, 1, 15)); + }); + dictTypeMapper.insert(dbDictType); + // 测试 name 不匹配 + dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setName("tudou"))); + // 测试 type 不匹配 + dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setType("土豆"))); + // 测试 status 不匹配 + dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setCreateTime(buildTime(2021, 1, 1)))); + // 准备参数 + DictTypePageReqVO reqVO = new DictTypePageReqVO(); + reqVO.setName("nai"); + reqVO.setType("艿"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime((new Date[]{buildTime(2021, 1, 10),buildTime(2021, 1, 20)})); - // 调用 - PageResult pageResult = dictTypeService.getDictTypePage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbDictType, pageResult.getList().get(0)); + // 调用 + PageResult pageResult = dictTypeService.getDictTypePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbDictType, pageResult.getList().get(0)); } @Test @@ -97,8 +97,7 @@ public class DictTypeServiceTest extends BaseDbUnitTest { reqVO.setName("nai"); reqVO.setType("艿"); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setBeginCreateTime(buildTime(2021, 1, 10)); - reqVO.setEndCreateTime(buildTime(2021, 1, 20)); + reqVO.setCreateTime((new Date[]{buildTime(2021, 1, 10),buildTime(2021, 1, 20)})); // 调用 List list = dictTypeService.getDictTypeList(reqVO); diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceTest.java index c8181d8a2..bbddae3c6 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceTest.java @@ -1,32 +1,33 @@ package cn.iocoder.yudao.module.system.service.errorcode; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeAutoGenerateReqDTO; -import cn.iocoder.yudao.module.system.dal.dataobject.errorcode.ErrorCodeDO; import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodeCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodeExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodeUpdateReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.errorcode.ErrorCodeDO; import cn.iocoder.yudao.module.system.dal.mysql.errorcode.ErrorCodeMapper; import cn.iocoder.yudao.module.system.enums.errorcode.ErrorCodeTypeEnum; -import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import org.assertj.core.util.Lists; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; import javax.annotation.Resource; +import java.util.Date; import java.util.List; import java.util.function.Consumer; import static cn.hutool.core.util.RandomUtil.randomEle; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.ERROR_CODE_DUPLICATE; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.ERROR_CODE_NOT_EXISTS; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.ERROR_CODE_DUPLICATE; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.ERROR_CODE_NOT_EXISTS; import static org.junit.jupiter.api.Assertions.*; @Import(ErrorCodeServiceImpl.class) @@ -81,29 +82,28 @@ public class ErrorCodeServiceTest extends BaseDbUnitTest { // 调用 errorCodeService.deleteErrorCode(id); - // 校验数据不存在了 - assertNull(errorCodeMapper.selectById(id)); + // 校验数据不存在了 + assertNull(errorCodeMapper.selectById(id)); } @Test public void testGetErrorCodePage() { - // mock 数据 - ErrorCodeDO dbErrorCode = initGetErrorCodePage(); - // 准备参数 - ErrorCodePageReqVO reqVO = new ErrorCodePageReqVO(); - reqVO.setType(ErrorCodeTypeEnum.AUTO_GENERATION.getType()); - reqVO.setApplicationName("tu"); - reqVO.setCode(1); - reqVO.setMessage("ma"); - reqVO.setBeginCreateTime(buildTime(2020, 11, 1)); - reqVO.setEndCreateTime(buildTime(2020, 11, 30)); + // mock 数据 + ErrorCodeDO dbErrorCode = initGetErrorCodePage(); + // 准备参数 + ErrorCodePageReqVO reqVO = new ErrorCodePageReqVO(); + reqVO.setType(ErrorCodeTypeEnum.AUTO_GENERATION.getType()); + reqVO.setApplicationName("tu"); + reqVO.setCode(1); + reqVO.setMessage("ma"); + reqVO.setCreateTime((new Date[]{buildTime(2020, 11, 1),buildTime(2020, 11, 30)})); - // 调用 - PageResult pageResult = errorCodeService.getErrorCodePage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbErrorCode, pageResult.getList().get(0)); + // 调用 + PageResult pageResult = errorCodeService.getErrorCodePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbErrorCode, pageResult.getList().get(0)); } /** @@ -141,8 +141,7 @@ public class ErrorCodeServiceTest extends BaseDbUnitTest { reqVO.setApplicationName("tu"); reqVO.setCode(1); reqVO.setMessage("ma"); - reqVO.setBeginCreateTime(buildTime(2020, 11, 1)); - reqVO.setEndCreateTime(buildTime(2020, 11, 30)); + reqVO.setCreateTime((new Date[]{buildTime(2020, 11, 1),buildTime(2020, 11, 30)})); // 调用 List list = errorCodeService.getErrorCodeList(reqVO); @@ -250,7 +249,7 @@ public class ErrorCodeServiceTest extends BaseDbUnitTest { // 准备参数 ErrorCodeAutoGenerateReqDTO generateReqDTO = randomPojo(ErrorCodeAutoGenerateReqDTO.class, o -> o.setCode(dbErrorCode.getCode()).setApplicationName(dbErrorCode.getApplicationName()) - .setMessage(dbErrorCode.getMessage())); + .setMessage(dbErrorCode.getMessage())); // mock 方法 // 调用 diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/LoginLogServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/LoginLogServiceImplTest.java index b42a7db96..363f497dc 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/LoginLogServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/LoginLogServiceImplTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; import javax.annotation.Resource; +import java.util.Date; import java.util.List; import static cn.hutool.core.util.RandomUtil.randomEle; @@ -66,8 +67,7 @@ public class LoginLogServiceImplTest extends BaseDbUnitTest { reqVO.setUsername("wangkai"); reqVO.setUserIp("192.168.199"); reqVO.setStatus(true); - reqVO.setBeginTime(buildTime(2021, 3, 5)); - reqVO.setEndTime(buildTime(2021, 3, 7)); + reqVO.setCreateTime((new Date[]{buildTime(2021, 3, 5),buildTime(2021, 3, 5)})); // 调用service方法 PageResult pageResult = loginLogService.getLoginLogPage(reqVO); @@ -105,15 +105,12 @@ public class LoginLogServiceImplTest extends BaseDbUnitTest { // 构造一个早期时间 2021-02-06 00:00:00 loginLogMapper.insert(ObjectUtils.cloneIgnoreId(loginLogDO, logDO -> logDO.setCreateTime(buildTime(2021, 2, 6)))); - // 构造调用参数 LoginLogExportReqVO reqVO = new LoginLogExportReqVO(); reqVO.setUsername("wangxiaokai"); reqVO.setUserIp("192.168.111"); reqVO.setStatus(true); - reqVO.setBeginTime(buildTime(2021, 3, 5)); - reqVO.setEndTime(buildTime(2021, 3, 7)); - + reqVO.setCreateTime((new Date[]{buildTime(2021, 3, 5),buildTime(2021, 3, 5)})); // 调用service方法 List loginLogList = loginLogService.getLoginLogList(reqVO); diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImplTest.java index 948ea3abc..1f1c0809e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImplTest.java @@ -7,8 +7,8 @@ import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstant import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.framework.operatelog.core.service.OperateLog; import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.util.RandomUtils; import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO; @@ -18,16 +18,14 @@ import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper; import cn.iocoder.yudao.module.system.enums.common.SexEnum; import cn.iocoder.yudao.module.system.service.user.AdminUserService; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import javax.annotation.Resource; import java.util.Collections; +import java.util.Date; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; @@ -106,8 +104,7 @@ public class OperateLogServiceImplTest extends BaseDbUnitTest { reqVO.setUserNickname("wangkai"); reqVO.setModule("order"); reqVO.setType(OperateTypeEnum.CREATE.getType()); - reqVO.setBeginTime(buildTime(2021, 3, 5)); - reqVO.setEndTime(buildTime(2021, 3, 7)); + reqVO.setStartTime((new Date[]{buildTime(2021, 3, 5),buildTime(2021, 3, 7)})); reqVO.setSuccess(true); // 调用service方法 @@ -158,8 +155,7 @@ public class OperateLogServiceImplTest extends BaseDbUnitTest { reqVO.setUserNickname("wangkai"); reqVO.setModule("order"); reqVO.setType(OperateTypeEnum.CREATE.getType()); - reqVO.setBeginTime(buildTime(2021, 3, 5)); - reqVO.setEndTime(buildTime(2021, 3, 7)); + reqVO.setStartTime((new Date[]{buildTime(2021, 3, 5),buildTime(2021, 3, 7)})); reqVO.setSuccess(true); // 调用 service 方法 diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceTest.java index b81777fb6..b471a4cd5 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceTest.java @@ -22,6 +22,7 @@ import javax.annotation.Resource; import java.util.*; import java.util.stream.Collectors; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; @@ -178,8 +179,7 @@ public class RoleServiceTest extends BaseDbUnitTest { reqVO.setName("土豆"); reqVO.setCode("tu"); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setBeginTime(DateUtils.buildTime(2022, 2, 1)); - reqVO.setEndTime(DateUtils.buildTime(2022, 2, 12)); + reqVO.setCreateTime((new Date[]{buildTime(2022, 2, 1),buildTime(2022, 2, 12)})); // 调用 List list = roleService.getRoleList(reqVO); @@ -209,8 +209,7 @@ public class RoleServiceTest extends BaseDbUnitTest { reqVO.setName("土豆"); reqVO.setCode("tu"); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setBeginTime(DateUtils.buildTime(2022, 2, 1)); - reqVO.setEndTime(DateUtils.buildTime(2022, 2, 12)); + reqVO.setCreateTime((new Date[]{buildTime(2022, 2, 1),buildTime(2022, 2, 12)})); // 调用 PageResult pageResult = roleService.getRolePage(reqVO); diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java index 09edfb910..8c347b97d 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java @@ -18,8 +18,10 @@ import org.springframework.context.annotation.Import; import javax.annotation.Resource; import java.util.Arrays; +import java.util.Date; import java.util.List; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; @@ -157,8 +159,7 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { reqVO.setName("笨"); reqVO.setTag("论坛"); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setBeginCreateTime(DateUtils.buildTime(2022, 2, 1)); - reqVO.setEndCreateTime(DateUtils.buildTime(2022, 2, 12)); + reqVO.setCreateTime((new Date[]{buildTime(2022, 2, 1),buildTime(2022, 2, 12)})); // 调用 PageResult pageResult = sensitiveWordService.getSensitiveWordPage(reqVO); @@ -189,8 +190,7 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { reqVO.setName("笨"); reqVO.setTag("论坛"); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setBeginCreateTime(DateUtils.buildTime(2022, 2, 1)); - reqVO.setEndCreateTime(DateUtils.buildTime(2022, 2, 12)); + reqVO.setCreateTime((new Date[]{buildTime(2022, 2, 1),buildTime(2022, 2, 12)})); // 调用 List list = sensitiveWordService.getSensitiveWordList(reqVO); diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java index a53a06fab..df851124b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java @@ -124,8 +124,8 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { // 调用 smsChannelService.deleteSmsChannel(id); - // 校验数据不存在了 - assertNull(smsChannelMapper.selectById(id)); + // 校验数据不存在了 + assertNull(smsChannelMapper.selectById(id)); // 校验调用 verify(smsProducer, times(1)).sendSmsChannelRefreshMessage(); } @@ -155,32 +155,31 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { @Test public void testGetSmsChannelPage() { - // mock 数据 - SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class, o -> { // 等会查询到 - o.setSignature("芋道源码"); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - o.setCreateTime(buildTime(2020, 12, 12)); - }); - smsChannelMapper.insert(dbSmsChannel); - // 测试 signature 不匹配 - smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setSignature("源码"))); - // 测试 status 不匹配 - smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); - // 测试 createTime 不匹配 - smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11)))); - // 准备参数 - SmsChannelPageReqVO reqVO = new SmsChannelPageReqVO(); - reqVO.setSignature("芋道"); - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setBeginCreateTime(buildTime(2020, 12, 1)); - reqVO.setEndCreateTime(buildTime(2020, 12, 24)); + // mock 数据 + SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class, o -> { // 等会查询到 + o.setSignature("芋道源码"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2020, 12, 12)); + }); + smsChannelMapper.insert(dbSmsChannel); + // 测试 signature 不匹配 + smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setSignature("源码"))); + // 测试 status 不匹配 + smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11)))); + // 准备参数 + SmsChannelPageReqVO reqVO = new SmsChannelPageReqVO(); + reqVO.setSignature("芋道"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCreateTime((new Date[]{buildTime(2020, 12, 1),buildTime(2020, 12, 24)})); - // 调用 - PageResult pageResult = smsChannelService.getSmsChannelPage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbSmsChannel, pageResult.getList().get(0)); + // 调用 + PageResult pageResult = smsChannelService.getSmsChannelPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbSmsChannel, pageResult.getList().get(0)); } // ========== 随机对象 ========== diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceTest.java index c4205f538..f69f30e92 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceTest.java @@ -43,49 +43,47 @@ public class SmsLogServiceTest extends BaseDbUnitTest { @Test public void testGetSmsLogPage() { - // mock 数据 - SmsLogDO dbSmsLog = randomSmsLogDO(o -> { // 等会查询到 - o.setChannelId(1L); - o.setTemplateId(10L); - o.setMobile("15601691300"); - o.setSendStatus(SmsSendStatusEnum.INIT.getStatus()); - o.setSendTime(buildTime(2020, 11, 11)); - o.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); - o.setReceiveTime(buildTime(2021, 11, 11)); - }); - smsLogMapper.insert(dbSmsLog); - // 测试 channelId 不匹配 - smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setChannelId(2L))); - // 测试 templateId 不匹配 - smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setTemplateId(20L))); - // 测试 mobile 不匹配 - smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setMobile("18818260999"))); - // 测试 sendStatus 不匹配 - smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setSendStatus(SmsSendStatusEnum.IGNORE.getStatus()))); - // 测试 sendTime 不匹配 - smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12)))); - // 测试 receiveStatus 不匹配 - smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setReceiveStatus(SmsReceiveStatusEnum.SUCCESS.getStatus()))); - // 测试 receiveTime 不匹配 - smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12)))); - // 准备参数 - SmsLogPageReqVO reqVO = new SmsLogPageReqVO(); - reqVO.setChannelId(1L); - reqVO.setTemplateId(10L); - reqVO.setMobile("156"); - reqVO.setSendStatus(SmsSendStatusEnum.INIT.getStatus()); - reqVO.setBeginSendTime(buildTime(2020, 11, 1)); - reqVO.setEndSendTime(buildTime(2020, 11, 30)); - reqVO.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); - reqVO.setBeginReceiveTime(buildTime(2021, 11, 1)); - reqVO.setEndReceiveTime(buildTime(2021, 11, 30)); + // mock 数据 + SmsLogDO dbSmsLog = randomSmsLogDO(o -> { // 等会查询到 + o.setChannelId(1L); + o.setTemplateId(10L); + o.setMobile("15601691300"); + o.setSendStatus(SmsSendStatusEnum.INIT.getStatus()); + o.setSendTime(buildTime(2020, 11, 11)); + o.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); + o.setReceiveTime(buildTime(2021, 11, 11)); + }); + smsLogMapper.insert(dbSmsLog); + // 测试 channelId 不匹配 + smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setChannelId(2L))); + // 测试 templateId 不匹配 + smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setTemplateId(20L))); + // 测试 mobile 不匹配 + smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setMobile("18818260999"))); + // 测试 sendStatus 不匹配 + smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setSendStatus(SmsSendStatusEnum.IGNORE.getStatus()))); + // 测试 sendTime 不匹配 + smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12)))); + // 测试 receiveStatus 不匹配 + smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setReceiveStatus(SmsReceiveStatusEnum.SUCCESS.getStatus()))); + // 测试 receiveTime 不匹配 + smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12)))); + // 准备参数 + SmsLogPageReqVO reqVO = new SmsLogPageReqVO(); + reqVO.setChannelId(1L); + reqVO.setTemplateId(10L); + reqVO.setMobile("156"); + reqVO.setSendStatus(SmsSendStatusEnum.INIT.getStatus()); + reqVO.setSendTime((new Date[]{buildTime(2020, 11, 1),buildTime(2020, 11, 30)})); + reqVO.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); + reqVO.setReceiveTime((new Date[]{buildTime(2021, 11, 1),buildTime(2021, 11, 30)})); - // 调用 - PageResult pageResult = smsLogService.getSmsLogPage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbSmsLog, pageResult.getList().get(0)); + // 调用 + PageResult pageResult = smsLogService.getSmsLogPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbSmsLog, pageResult.getList().get(0)); } @Test @@ -121,17 +119,15 @@ public class SmsLogServiceTest extends BaseDbUnitTest { reqVO.setTemplateId(10L); reqVO.setMobile("156"); reqVO.setSendStatus(SmsSendStatusEnum.INIT.getStatus()); - reqVO.setBeginSendTime(buildTime(2020, 11, 1)); - reqVO.setEndSendTime(buildTime(2020, 11, 30)); + reqVO.setSendTime((new Date[]{buildTime(2020, 11, 1),buildTime(2020, 11, 30)})); reqVO.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); - reqVO.setBeginReceiveTime(buildTime(2021, 11, 1)); - reqVO.setEndReceiveTime(buildTime(2021, 11, 30)); + reqVO.setReceiveTime((new Date[]{buildTime(2021, 11, 1),buildTime(2021, 11, 30)})); - // 调用 - List list = smsLogService.getSmsLogList(reqVO); - // 断言 - assertEquals(1, list.size()); - assertPojoEquals(dbSmsLog, list.get(0)); + // 调用 + List list = smsLogService.getSmsLogList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbSmsLog, list.get(0)); } @Test diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceTest.java index 50f1b3fd8..2a3860b0c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceTest.java @@ -180,8 +180,8 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest { // 调用 smsTemplateService.deleteSmsTemplate(id); - // 校验数据不存在了 - assertNull(smsTemplateMapper.selectById(id)); + // 校验数据不存在了 + assertNull(smsTemplateMapper.selectById(id)); // 校验调用 verify(smsProducer, times(1)).sendSmsTemplateRefreshMessage(); } @@ -197,48 +197,47 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest { @Test public void testGetSmsTemplatePage() { - // mock 数据 - SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到 - o.setType(SmsTemplateTypeEnum.PROMOTION.getType()); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - o.setCode("tudou"); - o.setContent("芋道源码"); - o.setApiTemplateId("yunai"); - o.setChannelId(1L); - o.setCreateTime(buildTime(2021, 11, 11)); - }); - smsTemplateMapper.insert(dbSmsTemplate); - // 测试 type 不匹配 - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setType(SmsTemplateTypeEnum.VERIFICATION_CODE.getType()))); - // 测试 status 不匹配 - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); - // 测试 code 不匹配 - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCode("yuanma"))); - // 测试 content 不匹配 - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setContent("源码"))); - // 测试 apiTemplateId 不匹配 - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setApiTemplateId("nai"))); - // 测试 channelId 不匹配 - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L))); - // 测试 createTime 不匹配 - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12)))); - // 准备参数 - SmsTemplatePageReqVO reqVO = new SmsTemplatePageReqVO(); - reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType()); - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setCode("tu"); - reqVO.setContent("芋道"); - reqVO.setApiTemplateId("yu"); - reqVO.setChannelId(1L); - reqVO.setBeginCreateTime(buildTime(2021, 11, 1)); - reqVO.setEndCreateTime(buildTime(2021, 12, 1)); + // mock 数据 + SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到 + o.setType(SmsTemplateTypeEnum.PROMOTION.getType()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCode("tudou"); + o.setContent("芋道源码"); + o.setApiTemplateId("yunai"); + o.setChannelId(1L); + o.setCreateTime(buildTime(2021, 11, 11)); + }); + smsTemplateMapper.insert(dbSmsTemplate); + // 测试 type 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setType(SmsTemplateTypeEnum.VERIFICATION_CODE.getType()))); + // 测试 status 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 code 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCode("yuanma"))); + // 测试 content 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setContent("源码"))); + // 测试 apiTemplateId 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setApiTemplateId("nai"))); + // 测试 channelId 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L))); + // 测试 createTime 不匹配 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12)))); + // 准备参数 + SmsTemplatePageReqVO reqVO = new SmsTemplatePageReqVO(); + reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType()); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCode("tu"); + reqVO.setContent("芋道"); + reqVO.setApiTemplateId("yu"); + reqVO.setChannelId(1L); + reqVO.setCreateTime((new Date[]{buildTime(2021, 11, 1),buildTime(2021, 12, 1)})); - // 调用 - PageResult pageResult = smsTemplateService.getSmsTemplatePage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbSmsTemplate, pageResult.getList().get(0)); + // 调用 + PageResult pageResult = smsTemplateService.getSmsTemplatePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbSmsTemplate, pageResult.getList().get(0)); } @Test @@ -276,14 +275,13 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest { reqVO.setContent("芋道"); reqVO.setApiTemplateId("yu"); reqVO.setChannelId(1L); - reqVO.setBeginCreateTime(buildTime(2021, 11, 1)); - reqVO.setEndCreateTime(buildTime(2021, 12, 1)); + reqVO.setCreateTime((new Date[]{buildTime(2021, 11, 1),buildTime(2021, 12, 1)})); - // 调用 - List list = smsTemplateService.getSmsTemplateList(reqVO); - // 断言 - assertEquals(1, list.size()); - assertPojoEquals(dbSmsTemplate, list.get(0)); + // 调用 + List list = smsTemplateService.getSmsTemplateList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbSmsTemplate, list.get(0)); } @Test diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImplTest.java index 32ed34972..406920ed1 100755 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImplTest.java @@ -15,6 +15,8 @@ import org.springframework.context.annotation.Import; import javax.annotation.Resource; +import java.util.Date; + import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; @@ -29,10 +31,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** -* {@link TenantPackageServiceImpl} 的单元测试类 -* -* @author 芋道源码 -*/ + * {@link TenantPackageServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ @Import(TenantPackageServiceImpl.class) public class TenantPackageServiceImplTest extends BaseDbUnitTest { @@ -106,8 +108,8 @@ public class TenantPackageServiceImplTest extends BaseDbUnitTest { // 调用 tenantPackageService.deleteTenantPackage(id); - // 校验数据不存在了 - assertNull(tenantPackageMapper.selectById(id)); + // 校验数据不存在了 + assertNull(tenantPackageMapper.selectById(id)); } @Test @@ -135,36 +137,35 @@ public class TenantPackageServiceImplTest extends BaseDbUnitTest { @Test public void testGetTenantPackagePage() { - // mock 数据 - TenantPackageDO dbTenantPackage = randomPojo(TenantPackageDO.class, o -> { // 等会查询到 - o.setName("芋道源码"); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - o.setRemark("源码解析"); - o.setCreateTime(buildTime(2022, 10, 10)); - }); - tenantPackageMapper.insert(dbTenantPackage); - // 测试 name 不匹配 - tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setName("源码"))); - // 测试 status 不匹配 - tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); - // 测试 remark 不匹配 - tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setRemark("解析"))); - // 测试 createTime 不匹配 - tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setCreateTime(buildTime(2022, 11, 11)))); - // 准备参数 - TenantPackagePageReqVO reqVO = new TenantPackagePageReqVO(); - reqVO.setName("芋道"); - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setRemark("源码"); - reqVO.setBeginCreateTime(buildTime(2022, 10, 9)); - reqVO.setEndCreateTime(buildTime(2022, 10, 11)); + // mock 数据 + TenantPackageDO dbTenantPackage = randomPojo(TenantPackageDO.class, o -> { // 等会查询到 + o.setName("芋道源码"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setRemark("源码解析"); + o.setCreateTime(buildTime(2022, 10, 10)); + }); + tenantPackageMapper.insert(dbTenantPackage); + // 测试 name 不匹配 + tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setName("源码"))); + // 测试 status 不匹配 + tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 remark 不匹配 + tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setRemark("解析"))); + // 测试 createTime 不匹配 + tenantPackageMapper.insert(cloneIgnoreId(dbTenantPackage, o -> o.setCreateTime(buildTime(2022, 11, 11)))); + // 准备参数 + TenantPackagePageReqVO reqVO = new TenantPackagePageReqVO(); + reqVO.setName("芋道"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setRemark("源码"); + reqVO.setCreateTime((new Date[]{buildTime(2022, 10, 9),buildTime(2022, 10, 11)})); - // 调用 - PageResult pageResult = tenantPackageService.getTenantPackagePage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbTenantPackage, pageResult.getList().get(0)); + // 调用 + PageResult pageResult = tenantPackageService.getTenantPackagePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbTenantPackage, pageResult.getList().get(0)); } @Test diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java index 61daa866f..1f7164e02 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java @@ -31,6 +31,7 @@ import javax.annotation.Resource; import java.time.Duration; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.List; import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; @@ -311,8 +312,7 @@ public class TenantServiceImplTest extends BaseDbUnitTest { reqVO.setContactName("艿"); reqVO.setContactMobile("1560"); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setBeginCreateTime(buildTime(2020, 12, 1)); - reqVO.setEndCreateTime(buildTime(2020, 12, 24)); + reqVO.setCreateTime(new Date[]{buildTime(2020, 12, 1),buildTime(2020, 12, 24)}); // 调用 PageResult pageResult = tenantService.getTenantPage(reqVO); @@ -349,8 +349,7 @@ public class TenantServiceImplTest extends BaseDbUnitTest { reqVO.setContactName("艿"); reqVO.setContactMobile("1560"); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setBeginCreateTime(buildTime(2020, 12, 1)); - reqVO.setEndCreateTime(buildTime(2020, 12, 24)); + reqVO.setCreateTime(new Date[]{buildTime(2020, 12, 1),buildTime(2020, 12, 24)}); // 调用 List list = tenantService.getTenantList(reqVO); @@ -457,7 +456,7 @@ public class TenantServiceImplTest extends BaseDbUnitTest { TenantContextHolder.setTenantId(dbTenant.getId()); // mock 菜单 when(menuService.getMenus()).thenReturn(Arrays.asList(randomPojo(MenuDO.class, o -> o.setId(100L)), - randomPojo(MenuDO.class, o -> o.setId(101L)))); + randomPojo(MenuDO.class, o -> o.setId(101L)))); // 调用 tenantService.handleTenantMenu(handler); diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java index 4bacb2657..0884f8187 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java @@ -33,6 +33,7 @@ import org.springframework.security.crypto.password.PasswordEncoder; import javax.annotation.Resource; import java.io.ByteArrayInputStream; import java.util.Collection; +import java.util.Date; import java.util.List; import java.util.function.Consumer; @@ -225,7 +226,7 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes); // mock 方法 String avatar = randomString(); - when(fileApi.createFile(eq(avatarFileBytes))).thenReturn(avatar); + when(fileApi.createFile(eq( avatarFileBytes))).thenReturn(avatar); // 调用 userService.updateUserAvatar(userId, avatarFile); @@ -294,8 +295,7 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { reqVO.setUsername("tu"); reqVO.setMobile("1560"); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setBeginTime(buildTime(2020, 12, 1)); - reqVO.setEndTime(buildTime(2020, 12, 24)); + reqVO.setCreateTime((new Date[]{buildTime(2020, 12, 1),buildTime(2020, 12, 24)})); reqVO.setDeptId(1L); // 其中,1L 是 2L 的父部门 // mock 方法 List deptList = newArrayList(randomPojo(DeptDO.class, o -> o.setId(2L))); @@ -318,8 +318,7 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { reqVO.setUsername("tu"); reqVO.setMobile("1560"); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setBeginTime(buildTime(2020, 12, 1)); - reqVO.setEndTime(buildTime(2020, 12, 24)); + reqVO.setCreateTime((new Date[]{buildTime(2020, 12, 1),buildTime(2020, 12, 24)})); reqVO.setDeptId(1L); // 其中,1L 是 2L 的父部门 // mock 方法 List deptList = newArrayList(randomPojo(DeptDO.class, o -> o.setId(2L)));