Compare commits
1 Commits
updateMenu
...
flowUpdate
| Author | SHA1 | Date | |
|---|---|---|---|
| f6e01abe0e |
@ -18,7 +18,7 @@
|
|||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<java.version>21</java.version>
|
<java.version>21</java.version>
|
||||||
<mybatis.version>3.5.16</mybatis.version>
|
<mybatis.version>3.5.16</mybatis.version>
|
||||||
<springdoc.version>2.8.4</springdoc.version>
|
<springdoc.version>2.3.0</springdoc.version>
|
||||||
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
|
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
|
||||||
<easyexcel.version>4.0.3</easyexcel.version>
|
<easyexcel.version>4.0.3</easyexcel.version>
|
||||||
<velocity.version>2.3</velocity.version>
|
<velocity.version>2.3</velocity.version>
|
||||||
@ -49,7 +49,7 @@
|
|||||||
<!-- 面向运行时的D-ORM依赖 -->
|
<!-- 面向运行时的D-ORM依赖 -->
|
||||||
<anyline.version>8.7.2-20250101</anyline.version>
|
<anyline.version>8.7.2-20250101</anyline.version>
|
||||||
<!--工作流配置-->
|
<!--工作流配置-->
|
||||||
<warm-flow.version>1.7.4</warm-flow.version>
|
<warm-flow.version>1.8.2</warm-flow.version>
|
||||||
|
|
||||||
<!-- 插件版本 -->
|
<!-- 插件版本 -->
|
||||||
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
|
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
|
||||||
|
|||||||
@ -59,9 +59,9 @@ spring:
|
|||||||
driverClassName: com.mysql.cj.jdbc.Driver
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
|
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
|
||||||
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
|
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
|
||||||
url: jdbc:mysql://192.168.110.2:13386/xinnengyuandev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
url: jdbc:mysql://192.168.110.2:13386/xinnengyuandev-update?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
username: xinnengyuandev
|
username: xinnengyuandev-update
|
||||||
password: StRWCZdZirysNSs2
|
password: cp7cAbWLZnRc6wyp
|
||||||
# url: jdbc:mysql://192.168.110.2:13386/xinnengyuan?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
# url: jdbc:mysql://192.168.110.2:13386/xinnengyuan?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
# username: xinnengyuan
|
# username: xinnengyuan
|
||||||
# password: mEZPC5Sdf3r2HENi
|
# password: mEZPC5Sdf3r2HENi
|
||||||
|
|||||||
@ -0,0 +1,45 @@
|
|||||||
|
package org.dromara.common.core.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例业务扩展对象
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
* @date 2025-08-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FlowInstanceBizExtDTO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例ID
|
||||||
|
*/
|
||||||
|
private Long instanceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务ID
|
||||||
|
*/
|
||||||
|
private String businessId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务编码
|
||||||
|
*/
|
||||||
|
private String businessCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务标题
|
||||||
|
*/
|
||||||
|
private String businessTitle;
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package org.dromara.common.core.domain.dto;
|
package org.dromara.common.core.domain.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
@ -30,11 +31,21 @@ public class StartProcessDTO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String flowCode;
|
private String flowCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 办理人(可不填 用于覆盖当前节点办理人)
|
||||||
|
*/
|
||||||
|
private String handler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}}
|
* 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}}
|
||||||
*/
|
*/
|
||||||
private Map<String, Object> variables;
|
private Map<String, Object> variables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程业务扩展信息
|
||||||
|
*/
|
||||||
|
private FlowInstanceBizExtDTO bizExt;
|
||||||
|
|
||||||
public Map<String, Object> getVariables() {
|
public Map<String, Object> getVariables() {
|
||||||
if (variables == null) {
|
if (variables == null) {
|
||||||
return new HashMap<>(16);
|
return new HashMap<>(16);
|
||||||
@ -42,4 +53,11 @@ public class StartProcessDTO implements Serializable {
|
|||||||
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||||
return variables;
|
return variables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FlowInstanceBizExtDTO getBizExt() {
|
||||||
|
if (ObjectUtil.isNull(bizExt)) {
|
||||||
|
bizExt = new FlowInstanceBizExtDTO();
|
||||||
|
}
|
||||||
|
return bizExt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,21 +52,23 @@ public class TaskAssigneeDTO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public static <T> List<TaskHandler> convertToHandlerList(
|
public static <T> List<TaskHandler> convertToHandlerList(
|
||||||
List<T> sourceList,
|
List<T> sourceList,
|
||||||
Function<T, Long> storageId,
|
Function<T, String> storageId,
|
||||||
Function<T, String> handlerCode,
|
Function<T, String> handlerCode,
|
||||||
Function<T, String> handlerName,
|
Function<T, String> handlerName,
|
||||||
Function<T, Long> groupName,
|
Function<T, String> groupName,
|
||||||
Function<T, Date> createTimeMapper) {
|
Function<T, Date> createTimeMapper) {
|
||||||
return sourceList.stream()
|
return sourceList.stream()
|
||||||
.map(item -> new TaskHandler(
|
.map(item -> new TaskHandler(
|
||||||
String.valueOf(storageId.apply(item)),
|
storageId.apply(item),
|
||||||
handlerCode.apply(item),
|
handlerCode.apply(item),
|
||||||
handlerName.apply(item),
|
handlerName.apply(item),
|
||||||
groupName != null ? String.valueOf(groupName.apply(item)) : null,
|
groupName.apply(item),
|
||||||
createTimeMapper.apply(item)
|
createTimeMapper.apply(item)
|
||||||
)).collect(Collectors.toList());
|
)).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
|||||||
@ -62,4 +62,10 @@ public class ProcessEvent implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private Boolean submit;
|
private Boolean submit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实例id
|
||||||
|
*/
|
||||||
|
private Long instanceId;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import lombok.Data;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程办理监听
|
* 流程办理监听
|
||||||
@ -56,4 +57,14 @@ public class ProcessTaskEvent implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实例id
|
||||||
|
*/
|
||||||
|
private Long instanceId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 办理参数
|
||||||
|
*/
|
||||||
|
private Map<String, Object> params;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package org.dromara.common.core.exception;
|
package org.dromara.common.core.exception;
|
||||||
|
|
||||||
|
import cn.hutool.core.text.StrFormatter;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
@ -56,4 +57,8 @@ public final class ServiceException extends RuntimeException {
|
|||||||
this.detailMessage = detailMessage;
|
this.detailMessage = detailMessage;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ServiceException(String message, Object... args) {
|
||||||
|
this.message = StrFormatter.format(message, args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,6 +82,7 @@ public interface WorkflowService {
|
|||||||
* completeTask.getVariables().put("ignore", true);
|
* completeTask.getVariables().put("ignore", true);
|
||||||
*
|
*
|
||||||
* @param completeTask 参数
|
* @param completeTask 参数
|
||||||
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
boolean completeTask(CompleteTaskDTO completeTask);
|
boolean completeTask(CompleteTaskDTO completeTask);
|
||||||
|
|
||||||
@ -90,6 +91,15 @@ public interface WorkflowService {
|
|||||||
*
|
*
|
||||||
* @param taskId 任务ID
|
* @param taskId 任务ID
|
||||||
* @param message 办理意见
|
* @param message 办理意见
|
||||||
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
boolean completeTask(Long taskId, String message);
|
boolean completeTask(Long taskId, String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动流程并办理第一个任务
|
||||||
|
*
|
||||||
|
* @param startProcess 参数
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
boolean startCompleteTask(StartProcessDTO startProcess);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import lombok.NoArgsConstructor;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -31,8 +30,10 @@ public class StreamUtils {
|
|||||||
if (CollUtil.isEmpty(collection)) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return CollUtil.newArrayList();
|
return CollUtil.newArrayList();
|
||||||
}
|
}
|
||||||
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
|
return collection.stream()
|
||||||
return collection.stream().filter(function).collect(Collectors.toList());
|
.filter(function)
|
||||||
|
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,13 +41,26 @@ public class StreamUtils {
|
|||||||
*
|
*
|
||||||
* @param collection 需要查询的集合
|
* @param collection 需要查询的集合
|
||||||
* @param function 过滤方法
|
* @param function 过滤方法
|
||||||
* @return 找到符合条件的第一个元素,没有则返回null
|
* @return 找到符合条件的第一个元素,没有则返回 Optional.empty()
|
||||||
*/
|
*/
|
||||||
public static <E> E findFirst(Collection<E> collection, Predicate<E> function) {
|
public static <E> Optional<E> findFirst(Collection<E> collection, Predicate<E> function) {
|
||||||
if (CollUtil.isEmpty(collection)) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return null;
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
return collection.stream().filter(function).findFirst().orElse(null);
|
return collection.stream()
|
||||||
|
.filter(function)
|
||||||
|
.findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 找到流中满足条件的第一个元素值
|
||||||
|
*
|
||||||
|
* @param collection 需要查询的集合
|
||||||
|
* @param function 过滤方法
|
||||||
|
* @return 找到符合条件的第一个元素,没有则返回 null
|
||||||
|
*/
|
||||||
|
public static <E> E findFirstValue(Collection<E> collection, Predicate<E> function) {
|
||||||
|
return findFirst(collection,function).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,13 +68,26 @@ public class StreamUtils {
|
|||||||
*
|
*
|
||||||
* @param collection 需要查询的集合
|
* @param collection 需要查询的集合
|
||||||
* @param function 过滤方法
|
* @param function 过滤方法
|
||||||
* @return 找到符合条件的任意一个元素,没有则返回null
|
* @return 找到符合条件的任意一个元素,没有则返回 Optional.empty()
|
||||||
*/
|
*/
|
||||||
public static <E> Optional<E> findAny(Collection<E> collection, Predicate<E> function) {
|
public static <E> Optional<E> findAny(Collection<E> collection, Predicate<E> function) {
|
||||||
if (CollUtil.isEmpty(collection)) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
return collection.stream().filter(function).findAny();
|
return collection.stream()
|
||||||
|
.filter(function)
|
||||||
|
.findAny();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 找到流中任意一个满足条件的元素值
|
||||||
|
*
|
||||||
|
* @param collection 需要查询的集合
|
||||||
|
* @param function 过滤方法
|
||||||
|
* @return 找到符合条件的任意一个元素,没有则返回null
|
||||||
|
*/
|
||||||
|
public static <E> E findAnyValue(Collection<E> collection, Predicate<E> function) {
|
||||||
|
return findAny(collection,function).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,7 +113,10 @@ public class StreamUtils {
|
|||||||
if (CollUtil.isEmpty(collection)) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return StringUtils.EMPTY;
|
return StringUtils.EMPTY;
|
||||||
}
|
}
|
||||||
return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));
|
return collection.stream()
|
||||||
|
.map(function)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.joining(delimiter));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,8 +130,11 @@ public class StreamUtils {
|
|||||||
if (CollUtil.isEmpty(collection)) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return CollUtil.newArrayList();
|
return CollUtil.newArrayList();
|
||||||
}
|
}
|
||||||
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
|
return collection.stream()
|
||||||
return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList());
|
.filter(Objects::nonNull)
|
||||||
|
.sorted(comparing)
|
||||||
|
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,7 +151,9 @@ public class StreamUtils {
|
|||||||
if (CollUtil.isEmpty(collection)) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return MapUtil.newHashMap();
|
return MapUtil.newHashMap();
|
||||||
}
|
}
|
||||||
return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
|
return collection.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,7 +172,25 @@ public class StreamUtils {
|
|||||||
if (CollUtil.isEmpty(collection)) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return MapUtil.newHashMap();
|
return MapUtil.newHashMap();
|
||||||
}
|
}
|
||||||
return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l));
|
return collection.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(key, value, (l, r) -> l));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 map 中的数据作为新 Map 的 value ,key 不变
|
||||||
|
* @param map 需要处理的map
|
||||||
|
* @param take 取值函数
|
||||||
|
* @param <K> map中的key类型
|
||||||
|
* @param <E> map中的value类型
|
||||||
|
* @param <V> 新map中的value类型
|
||||||
|
* @return 新的map
|
||||||
|
*/
|
||||||
|
public static <K, E, V> Map<K, V> toMap(Map<K, E> map, BiFunction<K, E, V> take) {
|
||||||
|
if (CollUtil.isEmpty(map)) {
|
||||||
|
return MapUtil.newHashMap();
|
||||||
|
}
|
||||||
|
return toMap(map.entrySet(), Map.Entry::getKey, entry -> take.apply(entry.getKey(), entry.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -154,8 +207,8 @@ public class StreamUtils {
|
|||||||
if (CollUtil.isEmpty(collection)) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return MapUtil.newHashMap();
|
return MapUtil.newHashMap();
|
||||||
}
|
}
|
||||||
return collection
|
return collection.stream()
|
||||||
.stream().filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));
|
.collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,8 +228,8 @@ public class StreamUtils {
|
|||||||
if (CollUtil.isEmpty(collection)) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return MapUtil.newHashMap();
|
return MapUtil.newHashMap();
|
||||||
}
|
}
|
||||||
return collection
|
return collection.stream()
|
||||||
.stream().filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList())));
|
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,11 +246,11 @@ public class StreamUtils {
|
|||||||
* @return 分类后的map
|
* @return 分类后的map
|
||||||
*/
|
*/
|
||||||
public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1, Function<E, U> key2) {
|
public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1, Function<E, U> key2) {
|
||||||
if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return MapUtil.newHashMap();
|
return MapUtil.newHashMap();
|
||||||
}
|
}
|
||||||
return collection
|
return collection.stream()
|
||||||
.stream().filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
|
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,8 +268,7 @@ public class StreamUtils {
|
|||||||
if (CollUtil.isEmpty(collection)) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return CollUtil.newArrayList();
|
return CollUtil.newArrayList();
|
||||||
}
|
}
|
||||||
return collection
|
return collection.stream()
|
||||||
.stream()
|
|
||||||
.map(function)
|
.map(function)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
|
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
|
||||||
@ -234,11 +286,10 @@ public class StreamUtils {
|
|||||||
* @return 转化后的Set
|
* @return 转化后的Set
|
||||||
*/
|
*/
|
||||||
public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) {
|
public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) {
|
||||||
if (CollUtil.isEmpty(collection) || function == null) {
|
if (CollUtil.isEmpty(collection)) {
|
||||||
return CollUtil.newHashSet();
|
return CollUtil.newHashSet();
|
||||||
}
|
}
|
||||||
return collection
|
return collection.stream()
|
||||||
.stream()
|
|
||||||
.map(function)
|
.map(function)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
@ -258,26 +309,20 @@ public class StreamUtils {
|
|||||||
* @return 合并后的map
|
* @return 合并后的map
|
||||||
*/
|
*/
|
||||||
public static <K, X, Y, V> Map<K, V> merge(Map<K, X> map1, Map<K, Y> map2, BiFunction<X, Y, V> merge) {
|
public static <K, X, Y, V> Map<K, V> merge(Map<K, X> map1, Map<K, Y> map2, BiFunction<X, Y, V> merge) {
|
||||||
if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) {
|
if (CollUtil.isEmpty(map1) && CollUtil.isEmpty(map2)) {
|
||||||
|
// 如果两个 map 都为空,则直接返回空的 map
|
||||||
return MapUtil.newHashMap();
|
return MapUtil.newHashMap();
|
||||||
} else if (MapUtil.isEmpty(map1)) {
|
} else if (CollUtil.isEmpty(map1)) {
|
||||||
map1 = MapUtil.newHashMap();
|
// 如果 map1 为空,则直接处理返回 map2
|
||||||
} else if (MapUtil.isEmpty(map2)) {
|
return toMap(map2.entrySet(), Map.Entry::getKey, entry -> merge.apply(null, entry.getValue()));
|
||||||
map2 = MapUtil.newHashMap();
|
} else if (CollUtil.isEmpty(map2)) {
|
||||||
|
// 如果 map2 为空,则直接处理返回 map1
|
||||||
|
return toMap(map1.entrySet(), Map.Entry::getKey, entry -> merge.apply(entry.getValue(), null));
|
||||||
}
|
}
|
||||||
Set<K> key = new HashSet<>();
|
Set<K> keySet = new HashSet<>();
|
||||||
key.addAll(map1.keySet());
|
keySet.addAll(map1.keySet());
|
||||||
key.addAll(map2.keySet());
|
keySet.addAll(map2.keySet());
|
||||||
Map<K, V> map = new HashMap<>();
|
return toMap(keySet, key -> key, key -> merge.apply(map1.get(key), map2.get(key)));
|
||||||
for (K t : key) {
|
|
||||||
X x = map1.get(t);
|
|
||||||
Y y = map2.get(t);
|
|
||||||
V z = merge.apply(x, y);
|
|
||||||
if (z != null) {
|
|
||||||
map.put(t, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -351,4 +351,14 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
|
|||||||
return noSpaces.matches("\\d+");
|
return noSpaces.matches("\\d+");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将可迭代对象中的元素使用逗号拼接成字符串
|
||||||
|
*
|
||||||
|
* @param iterable 可迭代对象,如 List、Set 等
|
||||||
|
* @return 拼接后的字符串
|
||||||
|
*/
|
||||||
|
public static String joinComma(Iterable<?> iterable) {
|
||||||
|
return StringUtils.join(iterable, SEPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,6 +45,16 @@
|
|||||||
<groupId>com.github.xiaoymin</groupId>
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||||
<version>4.5.0</version>
|
<version>4.5.0</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@ -384,13 +384,13 @@ public class DesTechnicalStandardServiceImpl extends ServiceImpl<DesTechnicalSta
|
|||||||
List<Tree<Long>> treeList = CollUtil.newArrayList();
|
List<Tree<Long>> treeList = CollUtil.newArrayList();
|
||||||
for (DesTechnicalStandard d : documentList) {
|
for (DesTechnicalStandard d : documentList) {
|
||||||
Long parentId = d.getPid();
|
Long parentId = d.getPid();
|
||||||
DesTechnicalStandard document = StreamUtils.findFirst(documentList, it -> Objects.equals(it.getId(), parentId));
|
DesTechnicalStandard document = StreamUtils.findFirst(documentList, it -> Objects.equals(it.getId(), parentId)).orElse(null);
|
||||||
if (ObjectUtil.isNull(document)) {
|
if (ObjectUtil.isNull(document)) {
|
||||||
List<Tree<Long>> trees = TreeBuildUtils.build(documentList, parentId, (desTechnicalStandard, tree) ->
|
List<Tree<Long>> trees = TreeBuildUtils.build(documentList, parentId, (desTechnicalStandard, tree) ->
|
||||||
tree.setId(desTechnicalStandard.getId())
|
tree.setId(desTechnicalStandard.getId())
|
||||||
.setParentId(desTechnicalStandard.getPid())
|
.setParentId(desTechnicalStandard.getPid())
|
||||||
.setName(desTechnicalStandard.getFileName()));
|
.setName(desTechnicalStandard.getFileName()));
|
||||||
Tree<Long> tree = StreamUtils.findFirst(trees, it -> Objects.equals(it.getId(), d.getId()));
|
Tree<Long> tree = StreamUtils.findFirst(trees, it -> Objects.equals(it.getId(), d.getId())).orElse(null);
|
||||||
treeList.add(tree);
|
treeList.add(tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -524,7 +524,7 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
|
|||||||
log.error("同步数据失败,项目[{}]新增技术标准管理文件夹模版失败", id);
|
log.error("同步数据失败,项目[{}]新增技术标准管理文件夹模版失败", id);
|
||||||
}
|
}
|
||||||
// 流程定义模版
|
// 流程定义模版
|
||||||
flwDefinitionService.insertDefByProjectId(id);
|
// flwDefinitionService.insertDefByProjectId(id);
|
||||||
return CompletableFuture.completedFuture(true);
|
return CompletableFuture.completedFuture(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -376,13 +376,13 @@ public class QltKnowledgeDocumentServiceImpl extends ServiceImpl<QltKnowledgeDoc
|
|||||||
List<Tree<Long>> treeList = CollUtil.newArrayList();
|
List<Tree<Long>> treeList = CollUtil.newArrayList();
|
||||||
for (QltKnowledgeDocument d : documentList) {
|
for (QltKnowledgeDocument d : documentList) {
|
||||||
Long parentId = d.getPid();
|
Long parentId = d.getPid();
|
||||||
QltKnowledgeDocument document = StreamUtils.findFirst(documentList, it -> Objects.equals(it.getId(), parentId));
|
QltKnowledgeDocument document = StreamUtils.findFirst(documentList, it -> Objects.equals(it.getId(), parentId)).orElse(null);
|
||||||
if (ObjectUtil.isNull(document)) {
|
if (ObjectUtil.isNull(document)) {
|
||||||
List<Tree<Long>> trees = TreeBuildUtils.build(documentList, parentId, (knowledgeDocument, tree) ->
|
List<Tree<Long>> trees = TreeBuildUtils.build(documentList, parentId, (knowledgeDocument, tree) ->
|
||||||
tree.setId(knowledgeDocument.getId())
|
tree.setId(knowledgeDocument.getId())
|
||||||
.setParentId(knowledgeDocument.getPid())
|
.setParentId(knowledgeDocument.getPid())
|
||||||
.setName(knowledgeDocument.getFileName()));
|
.setName(knowledgeDocument.getFileName()));
|
||||||
Tree<Long> tree = StreamUtils.findFirst(trees, it -> Objects.equals(it.getId(), d.getId()));
|
Tree<Long> tree = StreamUtils.findFirst(trees, it -> Objects.equals(it.getId(), d.getId())).orElse(null);
|
||||||
treeList.add(tree);
|
treeList.add(tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -377,13 +377,13 @@ public class HseKnowledgeDocumentServiceImpl extends ServiceImpl<HseKnowledgeDoc
|
|||||||
List<Tree<Long>> treeList = CollUtil.newArrayList();
|
List<Tree<Long>> treeList = CollUtil.newArrayList();
|
||||||
for (HseKnowledgeDocument d : documentList) {
|
for (HseKnowledgeDocument d : documentList) {
|
||||||
Long parentId = d.getPid();
|
Long parentId = d.getPid();
|
||||||
HseKnowledgeDocument document = StreamUtils.findFirst(documentList, it -> Objects.equals(it.getId(), parentId));
|
HseKnowledgeDocument document = StreamUtils.findFirst(documentList, it -> Objects.equals(it.getId(), parentId)).orElse(null);
|
||||||
if (ObjectUtil.isNull(document)) {
|
if (ObjectUtil.isNull(document)) {
|
||||||
List<Tree<Long>> trees = TreeBuildUtils.build(documentList, parentId, (knowledgeDocument, tree) ->
|
List<Tree<Long>> trees = TreeBuildUtils.build(documentList, parentId, (knowledgeDocument, tree) ->
|
||||||
tree.setId(knowledgeDocument.getId())
|
tree.setId(knowledgeDocument.getId())
|
||||||
.setParentId(knowledgeDocument.getPid())
|
.setParentId(knowledgeDocument.getPid())
|
||||||
.setName(knowledgeDocument.getFileName()));
|
.setName(knowledgeDocument.getFileName()));
|
||||||
Tree<Long> tree = StreamUtils.findFirst(trees, it -> Objects.equals(it.getId(), d.getId()));
|
Tree<Long> tree = StreamUtils.findFirst(trees, it -> Objects.equals(it.getId(), d.getId())).orElse(null);
|
||||||
treeList.add(tree);
|
treeList.add(tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,4 +91,9 @@ public class SysDeptBo extends BaseEntity {
|
|||||||
|
|
||||||
private List<String> deptTypes;
|
private List<String> deptTypes;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 归属部门id(部门树)
|
||||||
|
*/
|
||||||
|
private Long belongDeptId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.toolkit.Constants;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
import org.dromara.common.mybatis.annotation.DataColumn;
|
import org.dromara.common.mybatis.annotation.DataColumn;
|
||||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||||
@ -123,4 +124,11 @@ public interface SysDeptMapper extends BaseMapperPlus<SysDept, SysDeptVo> {
|
|||||||
*/
|
*/
|
||||||
SysDeptBo selectDeptByIdBo(@Param("deptId") Long deptId);
|
SysDeptBo selectDeptByIdBo(@Param("deptId") Long deptId);
|
||||||
|
|
||||||
|
|
||||||
|
default List<Long> selectDeptAndChildById(Long parentId) {
|
||||||
|
List<SysDept> deptList = this.selectListByParentId(parentId);
|
||||||
|
List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
|
||||||
|
deptIds.add(parentId);
|
||||||
|
return deptIds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package org.dromara.system.service;
|
package org.dromara.system.service;
|
||||||
|
|
||||||
import cn.hutool.core.lang.tree.Tree;
|
import cn.hutool.core.lang.tree.Tree;
|
||||||
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.system.domain.SysDept;
|
import org.dromara.system.domain.SysDept;
|
||||||
import org.dromara.system.domain.bo.SysDeptBo;
|
import org.dromara.system.domain.bo.SysDeptBo;
|
||||||
import org.dromara.system.domain.vo.SysDeptVo;
|
import org.dromara.system.domain.vo.SysDeptVo;
|
||||||
@ -167,4 +169,14 @@ public interface ISysDeptService {
|
|||||||
List<SysDeptVo> querListDept();
|
List<SysDeptVo> querListDept();
|
||||||
|
|
||||||
String selectDeptNameById(Long id);
|
String selectDeptNameById(Long id);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询部门管理数据
|
||||||
|
*
|
||||||
|
* @param dept 部门信息
|
||||||
|
* @param pageQuery 分页对象
|
||||||
|
* @return 部门信息集合
|
||||||
|
*/
|
||||||
|
TableDataInfo<SysDeptVo> selectPageDeptList(SysDeptBo dept, PageQuery pageQuery);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import cn.hutool.core.util.ObjectUtil;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.common.core.constant.CacheNames;
|
import org.dromara.common.core.constant.CacheNames;
|
||||||
@ -18,6 +19,8 @@ import org.dromara.common.core.domain.dto.DeptDTO;
|
|||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.core.service.DeptService;
|
import org.dromara.common.core.service.DeptService;
|
||||||
import org.dromara.common.core.utils.*;
|
import org.dromara.common.core.utils.*;
|
||||||
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
||||||
import org.dromara.common.redis.utils.CacheUtils;
|
import org.dromara.common.redis.utils.CacheUtils;
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
@ -88,6 +91,7 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private LambdaQueryWrapper<SysDept> buildQueryWrapper(SysDeptBo bo) {
|
private LambdaQueryWrapper<SysDept> buildQueryWrapper(SysDeptBo bo) {
|
||||||
|
Map<String, Object> params = bo.getParams();
|
||||||
LambdaQueryWrapper<SysDept> lqw = Wrappers.lambdaQuery();
|
LambdaQueryWrapper<SysDept> lqw = Wrappers.lambdaQuery();
|
||||||
lqw.eq(SysDept::getDelFlag, SystemConstants.NORMAL);
|
lqw.eq(SysDept::getDelFlag, SystemConstants.NORMAL);
|
||||||
lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId());
|
lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId());
|
||||||
@ -95,14 +99,19 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
|
|||||||
lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName());
|
lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName());
|
||||||
lqw.like(StringUtils.isNotBlank(bo.getDeptCategory()), SysDept::getDeptCategory, bo.getDeptCategory());
|
lqw.like(StringUtils.isNotBlank(bo.getDeptCategory()), SysDept::getDeptCategory, bo.getDeptCategory());
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus());
|
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus());
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus());
|
lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getIsShow()), SysDept::getIsShow, bo.getIsShow());
|
SysDept::getCreateTime, params.get("beginTime"), params.get("endTime"));
|
||||||
lqw.eq(StringUtils.isNotBlank(bo.getDeptType()), SysDept::getDeptType, bo.getDeptType());
|
|
||||||
lqw.in(CollectionUtil.isNotEmpty(bo.getDeptTypes()), SysDept::getDeptType, bo.getDeptTypes());
|
|
||||||
lqw.orderByAsc(SysDept::getAncestors);
|
lqw.orderByAsc(SysDept::getAncestors);
|
||||||
lqw.orderByAsc(SysDept::getParentId);
|
lqw.orderByAsc(SysDept::getParentId);
|
||||||
lqw.orderByAsc(SysDept::getOrderNum);
|
lqw.orderByAsc(SysDept::getOrderNum);
|
||||||
lqw.orderByAsc(SysDept::getDeptId);
|
lqw.orderByAsc(SysDept::getDeptId);
|
||||||
|
if (ObjectUtil.isNotNull(bo.getBelongDeptId())) {
|
||||||
|
//部门树搜索
|
||||||
|
lqw.and(x -> {
|
||||||
|
List<Long> deptIds = baseMapper.selectDeptAndChildById(bo.getBelongDeptId());
|
||||||
|
x.in(SysDept::getDeptId, deptIds);
|
||||||
|
});
|
||||||
|
}
|
||||||
return lqw;
|
return lqw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +130,7 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
|
|||||||
List<Tree<Long>> treeList = CollUtil.newArrayList();
|
List<Tree<Long>> treeList = CollUtil.newArrayList();
|
||||||
for (SysDeptVo d : depts) {
|
for (SysDeptVo d : depts) {
|
||||||
Long parentId = d.getParentId();
|
Long parentId = d.getParentId();
|
||||||
SysDeptVo sysDeptVo = StreamUtils.findFirst(depts, it -> it.getDeptId().longValue() == parentId);
|
SysDeptVo sysDeptVo = StreamUtils.findFirst(depts, it -> it.getDeptId().longValue() == parentId).orElse(null);
|
||||||
if (ObjectUtil.isNull(sysDeptVo)) {
|
if (ObjectUtil.isNull(sysDeptVo)) {
|
||||||
List<Tree<Long>> trees = TreeBuildUtils.build(depts, parentId, (dept, tree) -> {
|
List<Tree<Long>> trees = TreeBuildUtils.build(depts, parentId, (dept, tree) -> {
|
||||||
tree.setId(dept.getDeptId())
|
tree.setId(dept.getDeptId())
|
||||||
@ -132,7 +141,7 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
|
|||||||
tree.putExtra("deptType", dept.getDeptType());
|
tree.putExtra("deptType", dept.getDeptType());
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Tree<Long> tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getDeptId());
|
Tree<Long> tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getDeptId()).orElse(null);
|
||||||
treeList.add(tree);
|
treeList.add(tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,7 +176,7 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
|
|||||||
List<Tree<Long>> treeList = CollUtil.newArrayList();
|
List<Tree<Long>> treeList = CollUtil.newArrayList();
|
||||||
for (SysDeptVo d : deptVoList) {
|
for (SysDeptVo d : deptVoList) {
|
||||||
Long parentId = d.getParentId();
|
Long parentId = d.getParentId();
|
||||||
SysDeptVo sysDeptVo = StreamUtils.findFirst(deptVoList, it -> it.getDeptId().longValue() == parentId);
|
SysDeptVo sysDeptVo = StreamUtils.findFirst(deptVoList, it -> it.getDeptId().longValue() == parentId).orElse(null);
|
||||||
if (ObjectUtil.isNull(sysDeptVo)) {
|
if (ObjectUtil.isNull(sysDeptVo)) {
|
||||||
List<Tree<Long>> trees = TreeBuildUtils.build(deptVoList, parentId, (deptVo, tree) -> {
|
List<Tree<Long>> trees = TreeBuildUtils.build(deptVoList, parentId, (deptVo, tree) -> {
|
||||||
Long deptId = deptVo.getDeptId();
|
Long deptId = deptVo.getDeptId();
|
||||||
@ -181,7 +190,7 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
|
|||||||
tree.putExtra("roleVoList", roleVoMap.get(deptId));
|
tree.putExtra("roleVoList", roleVoMap.get(deptId));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Tree<Long> tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getDeptId());
|
Tree<Long> tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getDeptId()).orElse(null);
|
||||||
treeList.add(tree);
|
treeList.add(tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -595,4 +604,9 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
|
|||||||
return new ArrayList<>(deptIds);
|
return new ArrayList<>(deptIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableDataInfo<SysDeptVo> selectPageDeptList(SysDeptBo dept, PageQuery pageQuery) {
|
||||||
|
Page<SysDeptVo> page = baseMapper.selectPageDeptList(pageQuery.build(), buildQueryWrapper(dept));
|
||||||
|
return TableDataInfo.build(page);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package org.dromara.system.service.impl;
|
package org.dromara.system.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
@ -12,10 +13,15 @@ import org.dromara.common.core.service.TaskAssigneeService;
|
|||||||
import org.dromara.common.core.utils.StreamUtils;
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.system.domain.SysDept;
|
import org.dromara.system.domain.SysDept;
|
||||||
import org.dromara.system.domain.SysPost;
|
import org.dromara.system.domain.SysPost;
|
||||||
import org.dromara.system.domain.SysRole;
|
import org.dromara.system.domain.SysRole;
|
||||||
import org.dromara.system.domain.SysUser;
|
import org.dromara.system.domain.SysUser;
|
||||||
|
import org.dromara.system.domain.bo.SysDeptBo;
|
||||||
|
import org.dromara.system.domain.bo.SysPostBo;
|
||||||
|
import org.dromara.system.domain.bo.SysRoleBo;
|
||||||
|
import org.dromara.system.domain.bo.SysUserBo;
|
||||||
import org.dromara.system.domain.vo.SysDeptVo;
|
import org.dromara.system.domain.vo.SysDeptVo;
|
||||||
import org.dromara.system.domain.vo.SysPostVo;
|
import org.dromara.system.domain.vo.SysPostVo;
|
||||||
import org.dromara.system.domain.vo.SysRoleVo;
|
import org.dromara.system.domain.vo.SysRoleVo;
|
||||||
@ -24,9 +30,14 @@ import org.dromara.system.mapper.SysDeptMapper;
|
|||||||
import org.dromara.system.mapper.SysPostMapper;
|
import org.dromara.system.mapper.SysPostMapper;
|
||||||
import org.dromara.system.mapper.SysRoleMapper;
|
import org.dromara.system.mapper.SysRoleMapper;
|
||||||
import org.dromara.system.mapper.SysUserMapper;
|
import org.dromara.system.mapper.SysUserMapper;
|
||||||
|
import org.dromara.system.service.ISysDeptService;
|
||||||
|
import org.dromara.system.service.ISysPostService;
|
||||||
|
import org.dromara.system.service.ISysRoleService;
|
||||||
|
import org.dromara.system.service.ISysUserService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作流设计器获取任务执行人
|
* 工作流设计器获取任务执行人
|
||||||
@ -37,10 +48,15 @@ import java.util.List;
|
|||||||
@Service
|
@Service
|
||||||
public class SysTaskAssigneeServiceImpl implements TaskAssigneeService {
|
public class SysTaskAssigneeServiceImpl implements TaskAssigneeService {
|
||||||
|
|
||||||
private final SysPostMapper postMapper;
|
// private final SysPostMapper postMapper;
|
||||||
private final SysDeptMapper deptMapper;
|
// private final SysDeptMapper deptMapper;
|
||||||
private final SysUserMapper userMapper;
|
// private final SysUserMapper userMapper;
|
||||||
private final SysRoleMapper roleMapper;
|
// private final SysRoleMapper roleMapper;
|
||||||
|
private final ISysPostService postService;
|
||||||
|
private final ISysDeptService deptService;
|
||||||
|
private final ISysUserService userService;
|
||||||
|
private final ISysRoleService roleService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询角色并返回任务指派的列表,支持分页
|
* 查询角色并返回任务指派的列表,支持分页
|
||||||
@ -50,18 +66,31 @@ public class SysTaskAssigneeServiceImpl implements TaskAssigneeService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TaskAssigneeDTO selectRolesByTaskAssigneeList(TaskAssigneeBody taskQuery) {
|
public TaskAssigneeDTO selectRolesByTaskAssigneeList(TaskAssigneeBody taskQuery) {
|
||||||
|
// PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
||||||
|
// QueryWrapper<SysRole> wrapper = Wrappers.query();
|
||||||
|
// wrapper.eq("r.del_flag", SystemConstants.NORMAL)
|
||||||
|
// .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), "r.role_name", taskQuery.getHandlerCode())
|
||||||
|
// .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), "r.role_key", taskQuery.getHandlerName())
|
||||||
|
// .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()),
|
||||||
|
// "r.create_time", taskQuery.getBeginTime(), taskQuery.getEndTime())
|
||||||
|
// .orderByAsc("r.role_sort").orderByAsc("r.create_time");
|
||||||
|
// Page<SysRoleVo> page = roleMapper.selectPageRoleList(pageQuery.build(), wrapper);
|
||||||
|
// // 使用封装的字段映射方法进行转换
|
||||||
|
// List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
|
||||||
|
// item -> Convert.toStr(item.getPostId()), SysRoleVo::getRoleKey, SysRoleVo::getRoleName, SysPostVo::getPostName, item -> Convert.toStr(item.getDeptId()), SysRoleVo::getCreateTime);
|
||||||
|
// return new TaskAssigneeDTO(page.getTotal(), handlers);
|
||||||
PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
||||||
QueryWrapper<SysRole> wrapper = Wrappers.query();
|
SysRoleBo bo = new SysRoleBo();
|
||||||
wrapper.eq("r.del_flag", SystemConstants.NORMAL)
|
bo.setRoleKey(taskQuery.getHandlerCode());
|
||||||
.like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), "r.role_name", taskQuery.getHandlerCode())
|
bo.setRoleName(taskQuery.getHandlerName());
|
||||||
.like(StringUtils.isNotBlank(taskQuery.getHandlerName()), "r.role_key", taskQuery.getHandlerName())
|
bo.setStatus(SystemConstants.NORMAL);
|
||||||
.between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()),
|
Map<String, Object> params = bo.getParams();
|
||||||
"r.create_time", taskQuery.getBeginTime(), taskQuery.getEndTime())
|
params.put("beginTime", taskQuery.getBeginTime());
|
||||||
.orderByAsc("r.role_sort").orderByAsc("r.create_time");
|
params.put("endTime", taskQuery.getEndTime());
|
||||||
Page<SysRoleVo> page = roleMapper.selectPageRoleList(pageQuery.build(), wrapper);
|
TableDataInfo<SysRoleVo> page = roleService.selectPageRoleList(bo, pageQuery);
|
||||||
// 使用封装的字段映射方法进行转换
|
// 使用封装的字段映射方法进行转换
|
||||||
List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
|
List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRows(),
|
||||||
SysRoleVo::getRoleId, SysRoleVo::getRoleKey, SysRoleVo::getRoleName, null, SysRoleVo::getCreateTime);
|
item -> Convert.toStr(item.getRoleId()), SysRoleVo::getRoleKey, SysRoleVo::getRoleName, item -> "", SysRoleVo::getCreateTime);
|
||||||
return new TaskAssigneeDTO(page.getTotal(), handlers);
|
return new TaskAssigneeDTO(page.getTotal(), handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,25 +102,40 @@ public class SysTaskAssigneeServiceImpl implements TaskAssigneeService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TaskAssigneeDTO selectPostsByTaskAssigneeList(TaskAssigneeBody taskQuery) {
|
public TaskAssigneeDTO selectPostsByTaskAssigneeList(TaskAssigneeBody taskQuery) {
|
||||||
|
// PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
||||||
|
// LambdaQueryWrapper<SysPost> wrapper = Wrappers.<SysPost>lambdaQuery()
|
||||||
|
// .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), SysPost::getPostCategory, taskQuery.getHandlerCode())
|
||||||
|
// .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), SysPost::getPostName, taskQuery.getHandlerName())
|
||||||
|
// .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()),
|
||||||
|
// SysPost::getCreateTime, taskQuery.getBeginTime(), taskQuery.getEndTime());
|
||||||
|
// if (StringUtils.isNotBlank(taskQuery.getGroupId())) {
|
||||||
|
// Long belongDeptId = Long.valueOf(taskQuery.getGroupId());
|
||||||
|
// wrapper.and(x -> {
|
||||||
|
// List<SysDept> deptList = deptMapper.selectListByParentId(belongDeptId);
|
||||||
|
// List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
|
||||||
|
// deptIds.add(belongDeptId);
|
||||||
|
// x.in(SysPost::getDeptId, deptIds);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// Page<SysPostVo> page = postMapper.selectPagePostList(pageQuery.build(), wrapper);
|
||||||
|
// // 使用封装的字段映射方法进行转换
|
||||||
|
// List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
|
||||||
|
// SysPostVo::getPostId, SysPostVo::getPostCategory, SysPostVo::getPostName, SysPostVo::getDeptId, SysPostVo::getCreateTime);
|
||||||
|
// return new TaskAssigneeDTO(page.getTotal(), handlers);
|
||||||
|
|
||||||
PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
||||||
LambdaQueryWrapper<SysPost> wrapper = Wrappers.<SysPost>lambdaQuery()
|
SysPostBo bo = new SysPostBo();
|
||||||
.like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), SysPost::getPostCategory, taskQuery.getHandlerCode())
|
bo.setPostCategory(taskQuery.getHandlerCode());
|
||||||
.like(StringUtils.isNotBlank(taskQuery.getHandlerName()), SysPost::getPostName, taskQuery.getHandlerName())
|
bo.setPostName(taskQuery.getHandlerName());
|
||||||
.between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()),
|
bo.setStatus(SystemConstants.NORMAL);
|
||||||
SysPost::getCreateTime, taskQuery.getBeginTime(), taskQuery.getEndTime());
|
Map<String, Object> params = bo.getParams();
|
||||||
if (StringUtils.isNotBlank(taskQuery.getGroupId())) {
|
params.put("beginTime", taskQuery.getBeginTime());
|
||||||
Long belongDeptId = Long.valueOf(taskQuery.getGroupId());
|
params.put("endTime", taskQuery.getEndTime());
|
||||||
wrapper.and(x -> {
|
bo.setBelongDeptId(Convert.toLong(taskQuery.getGroupId()));
|
||||||
List<SysDept> deptList = deptMapper.selectListByParentId(belongDeptId);
|
TableDataInfo<SysPostVo> page = postService.selectPagePostList(bo, pageQuery);
|
||||||
List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
|
|
||||||
deptIds.add(belongDeptId);
|
|
||||||
x.in(SysPost::getDeptId, deptIds);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Page<SysPostVo> page = postMapper.selectPagePostList(pageQuery.build(), wrapper);
|
|
||||||
// 使用封装的字段映射方法进行转换
|
// 使用封装的字段映射方法进行转换
|
||||||
List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
|
List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRows(),
|
||||||
SysPostVo::getPostId, SysPostVo::getPostCategory, SysPostVo::getPostName, SysPostVo::getDeptId, SysPostVo::getCreateTime);
|
item -> Convert.toStr(item.getPostId()), SysPostVo::getPostCategory, SysPostVo::getPostName, item -> Convert.toStr(item.getDeptId()), SysPostVo::getCreateTime);
|
||||||
return new TaskAssigneeDTO(page.getTotal(), handlers);
|
return new TaskAssigneeDTO(page.getTotal(), handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,31 +147,45 @@ public class SysTaskAssigneeServiceImpl implements TaskAssigneeService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TaskAssigneeDTO selectDeptsByTaskAssigneeList(TaskAssigneeBody taskQuery) {
|
public TaskAssigneeDTO selectDeptsByTaskAssigneeList(TaskAssigneeBody taskQuery) {
|
||||||
|
// PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
||||||
|
// LambdaQueryWrapper<SysDept> wrapper = Wrappers.<SysDept>lambdaQuery()
|
||||||
|
// .eq(SysDept::getDelFlag, SystemConstants.NORMAL)
|
||||||
|
// .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), SysDept::getDeptCategory, taskQuery.getHandlerCode())
|
||||||
|
// .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), SysDept::getDeptName, taskQuery.getHandlerName())
|
||||||
|
// .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()),
|
||||||
|
// SysDept::getCreateTime, taskQuery.getBeginTime(), taskQuery.getEndTime())
|
||||||
|
// .orderByAsc(SysDept::getAncestors)
|
||||||
|
// .orderByAsc(SysDept::getParentId)
|
||||||
|
// .orderByAsc(SysDept::getOrderNum)
|
||||||
|
// .orderByAsc(SysDept::getDeptId);
|
||||||
|
// if (StringUtils.isNotBlank(taskQuery.getGroupId())) {
|
||||||
|
// //部门树搜索
|
||||||
|
// wrapper.and(x -> {
|
||||||
|
// Long parentId = Long.valueOf(taskQuery.getGroupId());
|
||||||
|
// List<SysDept> deptList = deptMapper.selectListByParentId(parentId);
|
||||||
|
// List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
|
||||||
|
// deptIds.add(parentId);
|
||||||
|
// x.in(SysDept::getDeptId, deptIds);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// Page<SysDeptVo> page = deptMapper.selectPageDeptList(pageQuery.build(), wrapper);
|
||||||
|
// // 使用封装的字段映射方法进行转换
|
||||||
|
// List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
|
||||||
|
// SysDeptVo::getDeptId, SysDeptVo::getDeptCategory, SysDeptVo::getDeptName, SysDeptVo::getParentId, SysDeptVo::getCreateTime);
|
||||||
|
// return new TaskAssigneeDTO(page.getTotal(), handlers);
|
||||||
PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
||||||
LambdaQueryWrapper<SysDept> wrapper = Wrappers.<SysDept>lambdaQuery()
|
SysDeptBo bo = new SysDeptBo();
|
||||||
.eq(SysDept::getDelFlag, SystemConstants.NORMAL)
|
bo.setDeptCategory(taskQuery.getHandlerCode());
|
||||||
.like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), SysDept::getDeptCategory, taskQuery.getHandlerCode())
|
bo.setDeptName(taskQuery.getHandlerName());
|
||||||
.like(StringUtils.isNotBlank(taskQuery.getHandlerName()), SysDept::getDeptName, taskQuery.getHandlerName())
|
bo.setStatus(SystemConstants.NORMAL);
|
||||||
.between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()),
|
Map<String, Object> params = bo.getParams();
|
||||||
SysDept::getCreateTime, taskQuery.getBeginTime(), taskQuery.getEndTime())
|
params.put("beginTime", taskQuery.getBeginTime());
|
||||||
.orderByAsc(SysDept::getAncestors)
|
params.put("endTime", taskQuery.getEndTime());
|
||||||
.orderByAsc(SysDept::getParentId)
|
bo.setBelongDeptId(Convert.toLong(taskQuery.getGroupId()));
|
||||||
.orderByAsc(SysDept::getOrderNum)
|
TableDataInfo<SysDeptVo> page = deptService.selectPageDeptList(bo, pageQuery);
|
||||||
.orderByAsc(SysDept::getDeptId);
|
|
||||||
if (StringUtils.isNotBlank(taskQuery.getGroupId())) {
|
|
||||||
//部门树搜索
|
|
||||||
wrapper.and(x -> {
|
|
||||||
Long parentId = Long.valueOf(taskQuery.getGroupId());
|
|
||||||
List<SysDept> deptList = deptMapper.selectListByParentId(parentId);
|
|
||||||
List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
|
|
||||||
deptIds.add(parentId);
|
|
||||||
x.in(SysDept::getDeptId, deptIds);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Page<SysDeptVo> page = deptMapper.selectPageDeptList(pageQuery.build(), wrapper);
|
|
||||||
// 使用封装的字段映射方法进行转换
|
// 使用封装的字段映射方法进行转换
|
||||||
List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
|
List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRows(),
|
||||||
SysDeptVo::getDeptId, SysDeptVo::getDeptCategory, SysDeptVo::getDeptName, SysDeptVo::getParentId, SysDeptVo::getCreateTime);
|
item -> Convert.toStr(item.getDeptId()), SysDeptVo::getDeptCategory, SysDeptVo::getDeptName, item -> Convert.toStr(item.getParentId()), SysDeptVo::getCreateTime);
|
||||||
return new TaskAssigneeDTO(page.getTotal(), handlers);
|
return new TaskAssigneeDTO(page.getTotal(), handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,28 +198,43 @@ public class SysTaskAssigneeServiceImpl implements TaskAssigneeService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TaskAssigneeDTO selectUsersByTaskAssigneeList(TaskAssigneeBody taskQuery) {
|
public TaskAssigneeDTO selectUsersByTaskAssigneeList(TaskAssigneeBody taskQuery) {
|
||||||
|
// PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
||||||
|
// QueryWrapper<SysUser> wrapper = Wrappers.query();
|
||||||
|
// wrapper.eq("u.del_flag", SystemConstants.NORMAL)
|
||||||
|
// .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), "u.user_name", taskQuery.getHandlerCode())
|
||||||
|
// .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), "u.nick_name", taskQuery.getHandlerName())
|
||||||
|
// .between(taskQuery.getBeginTime() != null && taskQuery.getEndTime() != null,
|
||||||
|
// "u.create_time", taskQuery.getBeginTime(), taskQuery.getEndTime())
|
||||||
|
// .orderByAsc("u.user_id");
|
||||||
|
// if (StringUtils.isNotBlank(taskQuery.getGroupId())) {
|
||||||
|
// //部门树搜索
|
||||||
|
// wrapper.and(x -> {
|
||||||
|
// Long parentId = Long.valueOf(taskQuery.getGroupId());
|
||||||
|
// List<SysDept> deptList = deptMapper.selectListByParentId(parentId);
|
||||||
|
// List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
|
||||||
|
// deptIds.add(parentId);
|
||||||
|
// x.in("u.dept_id", deptIds);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// Page<SysUserVo> page = userMapper.selectPageUserList(pageQuery.build(), wrapper);
|
||||||
|
// // 使用封装的字段映射方法进行转换
|
||||||
|
// List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
|
||||||
|
// SysUserVo::getUserId, SysUserVo::getUserName, SysUserVo::getNickName, SysUserVo::getDeptId, SysUserVo::getCreateTime);
|
||||||
|
// return new TaskAssigneeDTO(page.getTotal(), handlers);
|
||||||
|
|
||||||
PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
||||||
QueryWrapper<SysUser> wrapper = Wrappers.query();
|
SysUserBo bo = new SysUserBo();
|
||||||
wrapper.eq("u.del_flag", SystemConstants.NORMAL)
|
bo.setUserName(taskQuery.getHandlerCode());
|
||||||
.like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), "u.user_name", taskQuery.getHandlerCode())
|
bo.setNickName(taskQuery.getHandlerName());
|
||||||
.like(StringUtils.isNotBlank(taskQuery.getHandlerName()), "u.nick_name", taskQuery.getHandlerName())
|
bo.setStatus(SystemConstants.NORMAL);
|
||||||
.between(taskQuery.getBeginTime() != null && taskQuery.getEndTime() != null,
|
Map<String, Object> params = bo.getParams();
|
||||||
"u.create_time", taskQuery.getBeginTime(), taskQuery.getEndTime())
|
params.put("beginTime", taskQuery.getBeginTime());
|
||||||
.orderByAsc("u.user_id");
|
params.put("endTime", taskQuery.getEndTime());
|
||||||
if (StringUtils.isNotBlank(taskQuery.getGroupId())) {
|
bo.setDeptId(Convert.toLong(taskQuery.getGroupId()));
|
||||||
//部门树搜索
|
TableDataInfo<SysUserVo> page = userService.selectPageUserList(bo, pageQuery);
|
||||||
wrapper.and(x -> {
|
|
||||||
Long parentId = Long.valueOf(taskQuery.getGroupId());
|
|
||||||
List<SysDept> deptList = deptMapper.selectListByParentId(parentId);
|
|
||||||
List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
|
|
||||||
deptIds.add(parentId);
|
|
||||||
x.in("u.dept_id", deptIds);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Page<SysUserVo> page = userMapper.selectPageUserList(pageQuery.build(), wrapper);
|
|
||||||
// 使用封装的字段映射方法进行转换
|
// 使用封装的字段映射方法进行转换
|
||||||
List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(),
|
List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRows(),
|
||||||
SysUserVo::getUserId, SysUserVo::getUserName, SysUserVo::getNickName, SysUserVo::getDeptId, SysUserVo::getCreateTime);
|
item -> Convert.toStr(item.getUserId()), SysUserVo::getUserName, SysUserVo::getNickName, item -> Convert.toStr(item.getDeptId()), SysUserVo::getCreateTime);
|
||||||
return new TaskAssigneeDTO(page.getTotal(), handlers);
|
return new TaskAssigneeDTO(page.getTotal(), handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,11 @@ public interface FlowConstant {
|
|||||||
*/
|
*/
|
||||||
String BUSINESS_ID = "businessId";
|
String BUSINESS_ID = "businessId";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门id
|
||||||
|
*/
|
||||||
|
String INITIATOR_DEPT_ID = "initiatorDeptId";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 委托
|
* 委托
|
||||||
*/
|
*/
|
||||||
@ -78,4 +83,13 @@ public interface FlowConstant {
|
|||||||
*/
|
*/
|
||||||
String WF_TASK_STATUS = "wf_task_status";
|
String WF_TASK_STATUS = "wf_task_status";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动通过
|
||||||
|
*/
|
||||||
|
String AUTO_PASS = "autoPass";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务编码
|
||||||
|
*/
|
||||||
|
String BUSINESS_CODE = "businessCode";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ public enum ButtonPermissionEnum implements NodeExtEnum {
|
|||||||
/**
|
/**
|
||||||
* 是否能抄送
|
* 是否能抄送
|
||||||
*/
|
*/
|
||||||
COPY("是否能抄送", "copy", false),
|
COPY("是否能抄送", "copy", true),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否显示退回
|
* 是否显示退回
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
package org.dromara.workflow.common.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抄送设置枚举
|
||||||
|
*
|
||||||
|
* @author AprilWind
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum CopySettingEnum implements NodeExtEnum {
|
||||||
|
;
|
||||||
|
private final String label;
|
||||||
|
private final String value;
|
||||||
|
private final boolean selected;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -3,6 +3,7 @@ package org.dromara.workflow.common.enums;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -35,7 +36,12 @@ public enum TaskAssigneeEnum {
|
|||||||
/**
|
/**
|
||||||
* 岗位
|
* 岗位
|
||||||
*/
|
*/
|
||||||
POST("岗位", "post:");
|
POST("岗位", "post:"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SPEL表达式
|
||||||
|
*/
|
||||||
|
SPEL("SpEL表达式", "");
|
||||||
|
|
||||||
private final String desc;
|
private final String desc;
|
||||||
private final String code;
|
private final String code;
|
||||||
@ -105,5 +111,30 @@ public enum TaskAssigneeEnum {
|
|||||||
.map(TaskAssigneeEnum::getCode)
|
.map(TaskAssigneeEnum::getCode)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前办理人类型是否需要调用部门服务(deptService)
|
||||||
|
*
|
||||||
|
* @return 如果类型是 USER、DEPT 或 POST,则返回 true;否则返回 false
|
||||||
|
*/
|
||||||
|
public boolean needsDeptService() {
|
||||||
|
return this == USER || this == DEPT || this == POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定字符串是否符合 SPEL 表达式格式(以 $ 或 # 开头)
|
||||||
|
*
|
||||||
|
* @param value 待判断字符串
|
||||||
|
* @return 是否为 SPEL 表达式
|
||||||
|
*/
|
||||||
|
public static boolean isSpelExpression(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// $前缀表示默认办理人变量策略
|
||||||
|
// #前缀表示spel办理人变量策略
|
||||||
|
return StringUtils.startsWith(value, "$") || StringUtils.startsWith(value, "#");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -100,5 +100,15 @@ public enum TaskStatusEnum {
|
|||||||
return STATUS_DESC_MAP.getOrDefault(status, StrUtil.EMPTY);
|
return STATUS_DESC_MAP.getOrDefault(status, StrUtil.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断状态是否为通过或退回
|
||||||
|
*
|
||||||
|
* @param status 状态值
|
||||||
|
* @return true 表示是通过或退回状态
|
||||||
|
*/
|
||||||
|
public static boolean isPassOrBack(String status) {
|
||||||
|
return PASS.getStatus().equals(status) || BACK.getStatus().equals(status);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
package org.dromara.workflow.common.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变量枚举
|
||||||
|
*
|
||||||
|
* @author AprilWind
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum VariablesEnum implements NodeExtEnum {
|
||||||
|
;
|
||||||
|
private final String label;
|
||||||
|
private final String value;
|
||||||
|
private final boolean selected;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -66,7 +66,6 @@ public class FlwCategoryController extends BaseController {
|
|||||||
@SaCheckPermission("workflow:category:query")
|
@SaCheckPermission("workflow:category:query")
|
||||||
@GetMapping("/{categoryId}")
|
@GetMapping("/{categoryId}")
|
||||||
public R<FlowCategoryVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long categoryId) {
|
public R<FlowCategoryVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long categoryId) {
|
||||||
flwCategoryService.checkCategoryDataScope(categoryId);
|
|
||||||
return R.ok(flwCategoryService.queryById(categoryId));
|
return R.ok(flwCategoryService.queryById(categoryId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +92,6 @@ public class FlwCategoryController extends BaseController {
|
|||||||
@PutMapping()
|
@PutMapping()
|
||||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody FlowCategoryBo category) {
|
public R<Void> edit(@Validated(EditGroup.class) @RequestBody FlowCategoryBo category) {
|
||||||
Long categoryId = category.getCategoryId();
|
Long categoryId = category.getCategoryId();
|
||||||
flwCategoryService.checkCategoryDataScope(categoryId);
|
|
||||||
if (!flwCategoryService.checkCategoryNameUnique(category)) {
|
if (!flwCategoryService.checkCategoryNameUnique(category)) {
|
||||||
return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在");
|
return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在");
|
||||||
} else if (category.getParentId().equals(categoryId)) {
|
} else if (category.getParentId().equals(categoryId)) {
|
||||||
|
|||||||
@ -9,15 +9,10 @@ import org.dromara.common.log.enums.BusinessType;
|
|||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.common.web.core.BaseController;
|
import org.dromara.common.web.core.BaseController;
|
||||||
import org.dromara.warm.flow.core.FlowEngine;
|
|
||||||
import org.dromara.warm.flow.core.entity.Definition;
|
import org.dromara.warm.flow.core.entity.Definition;
|
||||||
import org.dromara.warm.flow.core.entity.Node;
|
|
||||||
import org.dromara.warm.flow.core.entity.Skip;
|
|
||||||
import org.dromara.warm.flow.core.service.DefService;
|
import org.dromara.warm.flow.core.service.DefService;
|
||||||
import org.dromara.warm.flow.core.utils.AssertUtil;
|
|
||||||
import org.dromara.warm.flow.orm.entity.FlowDefinition;
|
import org.dromara.warm.flow.orm.entity.FlowDefinition;
|
||||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
import org.dromara.workflow.domain.bo.FlowDefinitionBo;
|
|
||||||
import org.dromara.workflow.domain.vo.FlowDefinitionVo;
|
import org.dromara.workflow.domain.vo.FlowDefinitionVo;
|
||||||
import org.dromara.workflow.service.IFlwDefinitionService;
|
import org.dromara.workflow.service.IFlwDefinitionService;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -27,7 +22,6 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程定义管理 控制层
|
* 流程定义管理 控制层
|
||||||
@ -47,23 +41,23 @@ public class FlwDefinitionController extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* 查询流程定义列表
|
* 查询流程定义列表
|
||||||
*
|
*
|
||||||
* @param flowDefinitionBo 参数
|
* @param flowDefinition 参数
|
||||||
* @param pageQuery 分页
|
* @param pageQuery 分页
|
||||||
*/
|
*/
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo<FlowDefinitionVo> list(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery) {
|
public TableDataInfo<FlowDefinitionVo> list(FlowDefinition flowDefinition, PageQuery pageQuery) {
|
||||||
return flwDefinitionService.queryList(flowDefinitionBo, pageQuery);
|
return flwDefinitionService.queryList(flowDefinition, pageQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询未发布的流程定义列表
|
* 查询未发布的流程定义列表
|
||||||
*
|
*
|
||||||
* @param flowDefinitionBo 参数
|
* @param flowDefinition 参数
|
||||||
* @param pageQuery 分页
|
* @param pageQuery 分页
|
||||||
*/
|
*/
|
||||||
@GetMapping("/unPublishList")
|
@GetMapping("/unPublishList")
|
||||||
public TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery) {
|
public TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) {
|
||||||
return flwDefinitionService.unPublishList(flowDefinitionBo, pageQuery);
|
return flwDefinitionService.unPublishList(flowDefinition, pageQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,6 +72,8 @@ public class FlwDefinitionController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增流程定义
|
* 新增流程定义
|
||||||
|
*
|
||||||
|
* @param flowDefinition 参数
|
||||||
*/
|
*/
|
||||||
@Log(title = "流程定义", businessType = BusinessType.INSERT)
|
@Log(title = "流程定义", businessType = BusinessType.INSERT)
|
||||||
@PostMapping
|
@PostMapping
|
||||||
@ -195,50 +191,4 @@ public class FlwDefinitionController extends BaseController {
|
|||||||
return R.ok(active ? defService.active(id) : defService.unActive(id));
|
return R.ok(active ? defService.active(id) : defService.unActive(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 复制流程定义到另一项目
|
|
||||||
*
|
|
||||||
* @param id 流程定义id
|
|
||||||
*/
|
|
||||||
@Log(title = "复制流程定义到另一项目", businessType = BusinessType.INSERT)
|
|
||||||
@PostMapping("/copyToProject/{id}/{projectId}")
|
|
||||||
@RepeatSubmit()
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public R<Boolean> copyToProjectById(@PathVariable Long id, @PathVariable Long projectId) {
|
|
||||||
Definition definition = FlowEngine.defService().getById(id).copy();
|
|
||||||
definition.setVersion("1");
|
|
||||||
AssertUtil.isNull(definition, "流程定义不存在!");
|
|
||||||
String[] split = definition.getFlowCode().split("_");
|
|
||||||
definition.setFlowCode(projectId + "_" + split[1]);
|
|
||||||
List<Node> nodeList = (List) FlowEngine.nodeService().getByDefId(id).stream().map(Node::copy).collect(Collectors.toList());
|
|
||||||
List<Skip> skipList = (List)FlowEngine.skipService().getByDefId(id).stream().map(Skip::copy).collect(Collectors.toList());
|
|
||||||
FlowEngine.dataFillHandler().idFill(definition);
|
|
||||||
nodeList.forEach((node) -> {
|
|
||||||
node.setDefinitionId(definition.getId()).setVersion(definition.getVersion());
|
|
||||||
});
|
|
||||||
FlowEngine.nodeService().saveBatch(nodeList);
|
|
||||||
skipList.forEach((skip) -> {
|
|
||||||
skip.setDefinitionId(definition.getId());
|
|
||||||
});
|
|
||||||
FlowEngine.skipService().saveBatch(skipList);
|
|
||||||
boolean save = FlowEngine.defService().save(definition);
|
|
||||||
return R.ok(save);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("/copyAllProject/{projectId}/{toProjectId}")
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
@RepeatSubmit()
|
|
||||||
public R<Boolean> copyToProject(@PathVariable Long projectId,@PathVariable Long toProjectId) {
|
|
||||||
FlowDefinitionBo flowDefinitionBo = new FlowDefinitionBo();
|
|
||||||
flowDefinitionBo.setProjectId(projectId);
|
|
||||||
PageQuery pageQuery = new PageQuery(9999,1);
|
|
||||||
TableDataInfo<FlowDefinitionVo> flowDefinitionVoTableDataInfo = flwDefinitionService.queryList(flowDefinitionBo, pageQuery);
|
|
||||||
List<FlowDefinitionVo> list = flowDefinitionVoTableDataInfo.getRows();
|
|
||||||
for (FlowDefinitionVo flowDefinitionVo : list) {
|
|
||||||
copyToProjectById(flowDefinitionVo.getId(),toProjectId);
|
|
||||||
}
|
|
||||||
return R.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import org.dromara.workflow.common.ConditionalOnEnable;
|
|||||||
import org.dromara.workflow.domain.bo.FlowCancelBo;
|
import org.dromara.workflow.domain.bo.FlowCancelBo;
|
||||||
import org.dromara.workflow.domain.bo.FlowInstanceBo;
|
import org.dromara.workflow.domain.bo.FlowInstanceBo;
|
||||||
import org.dromara.workflow.domain.bo.FlowInvalidBo;
|
import org.dromara.workflow.domain.bo.FlowInvalidBo;
|
||||||
|
import org.dromara.workflow.domain.bo.FlowVariableBo;
|
||||||
import org.dromara.workflow.domain.vo.FlowInstanceVo;
|
import org.dromara.workflow.domain.vo.FlowInstanceVo;
|
||||||
import org.dromara.workflow.service.IFlwInstanceService;
|
import org.dromara.workflow.service.IFlwInstanceService;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
@ -88,6 +89,16 @@ public class FlwInstanceController extends BaseController {
|
|||||||
return toAjax(flwInstanceService.deleteByInstanceIds(instanceIds));
|
return toAjax(flwInstanceService.deleteByInstanceIds(instanceIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按照实例id删除已完成得流程实例
|
||||||
|
*
|
||||||
|
* @param instanceIds 实例id
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/deleteHisByInstanceIds/{instanceIds}")
|
||||||
|
public R<Void> deleteHisByInstanceIds(@PathVariable List<Long> instanceIds) {
|
||||||
|
return toAjax(flwInstanceService.deleteHisByInstanceIds(instanceIds));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 撤销流程
|
* 撤销流程
|
||||||
*
|
*
|
||||||
@ -142,6 +153,17 @@ public class FlwInstanceController extends BaseController {
|
|||||||
return R.ok(flwInstanceService.instanceVariable(instanceId));
|
return R.ok(flwInstanceService.instanceVariable(instanceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改流程变量
|
||||||
|
*
|
||||||
|
* @param bo 参数
|
||||||
|
*/
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PutMapping("/updateVariable")
|
||||||
|
public R<Void> updateVariable(@Validated @RequestBody FlowVariableBo bo) {
|
||||||
|
return toAjax(flwInstanceService.updateVariable(bo));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 作废流程
|
* 作废流程
|
||||||
*
|
*
|
||||||
|
|||||||
@ -0,0 +1,93 @@
|
|||||||
|
package org.dromara.workflow.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.dromara.common.core.domain.R;
|
||||||
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
|
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||||
|
import org.dromara.common.log.annotation.Log;
|
||||||
|
import org.dromara.common.log.enums.BusinessType;
|
||||||
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
|
import org.dromara.common.web.core.BaseController;
|
||||||
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
|
import org.dromara.workflow.domain.bo.FlowSpelBo;
|
||||||
|
import org.dromara.workflow.domain.vo.FlowSpelVo;
|
||||||
|
import org.dromara.workflow.service.IFlwSpelService;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程spel达式定义
|
||||||
|
*
|
||||||
|
* @author Michelle.Chung
|
||||||
|
* @date 2025-07-04
|
||||||
|
*/
|
||||||
|
@ConditionalOnEnable
|
||||||
|
@Validated
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/workflow/spel")
|
||||||
|
public class FlwSpelController extends BaseController {
|
||||||
|
|
||||||
|
private final IFlwSpelService flwSpelService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询流程spel达式定义列表
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("workflow:spel:list")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo<FlowSpelVo> list(FlowSpelBo bo, PageQuery pageQuery) {
|
||||||
|
return flwSpelService.queryPageList(bo, pageQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程spel达式定义详细信息
|
||||||
|
*
|
||||||
|
* @param id 主键
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("workflow:spel:query")
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public R<FlowSpelVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||||
|
return R.ok(flwSpelService.queryById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增流程spel达式定义
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("workflow:spel:add")
|
||||||
|
@Log(title = "流程spel达式定义", businessType = BusinessType.INSERT)
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PostMapping()
|
||||||
|
public R<Void> add(@Validated(AddGroup.class) @RequestBody FlowSpelBo bo) {
|
||||||
|
return toAjax(flwSpelService.insertByBo(bo));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改流程spel达式定义
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("workflow:spel:edit")
|
||||||
|
@Log(title = "流程spel达式定义", businessType = BusinessType.UPDATE)
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PutMapping()
|
||||||
|
public R<Void> edit(@Validated(EditGroup.class) @RequestBody FlowSpelBo bo) {
|
||||||
|
return toAjax(flwSpelService.updateByBo(bo));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除流程spel达式定义
|
||||||
|
*
|
||||||
|
* @param ids 主键串
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("workflow:spel:remove")
|
||||||
|
@Log(title = "流程spel达式定义", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||||
|
return toAjax(flwSpelService.deleteWithValidByIds(List.of(ids), true));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -191,12 +191,12 @@ public class FlwTaskController extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* 获取可驳回的前置节点
|
* 获取可驳回的前置节点
|
||||||
*
|
*
|
||||||
* @param definitionId 流程定义id
|
* @param taskId 任务id
|
||||||
* @param nowNodeCode 当前节点
|
* @param nowNodeCode 当前节点
|
||||||
*/
|
*/
|
||||||
@GetMapping("/getBackTaskNode/{definitionId}/{nowNodeCode}")
|
@GetMapping("/getBackTaskNode/{taskId}/{nowNodeCode}")
|
||||||
public R<List<Node>> getBackTaskNode(@PathVariable Long definitionId, @PathVariable String nowNodeCode) {
|
public R<List<Node>> getBackTaskNode(@PathVariable Long taskId, @PathVariable String nowNodeCode) {
|
||||||
return R.ok(flwTaskService.getBackTaskNode(definitionId, nowNodeCode));
|
return R.ok(flwTaskService.getBackTaskNode(taskId, nowNodeCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -206,13 +206,19 @@ public class FlwTaskController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/currentTaskAllUser/{taskId}")
|
@GetMapping("/currentTaskAllUser/{taskId}")
|
||||||
public R<List<UserDTO>> currentTaskAllUser(@PathVariable Long taskId) {
|
public R<List<UserDTO>> currentTaskAllUser(@PathVariable Long taskId) {
|
||||||
return R.ok(flwTaskService.currentTaskAllUser(taskId));
|
return R.ok(flwTaskService.currentTaskAllUser(List.of(taskId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 催办任务
|
||||||
|
*
|
||||||
|
* @param bo 参数
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@PostMapping("/urgeTask")
|
||||||
|
public R<Void> urgeTask(@RequestBody FlowUrgeTaskBo bo) {
|
||||||
|
return toAjax(flwTaskService.urgeTask(bo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@PutMapping("/copyRead/{flowUserId}")
|
|
||||||
public R<Void> copyRead(@PathVariable Long flowUserId) {
|
|
||||||
flwTaskService.copyRead(flowUserId);
|
|
||||||
return R.ok();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,6 +82,17 @@ public class TestLeaveController extends BaseController {
|
|||||||
return R.ok(testLeaveService.insertByBo(bo));
|
return R.ok(testLeaveService.insertByBo(bo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交请假并提交流程
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("workflow:leave:add")
|
||||||
|
@Log(title = "请假", businessType = BusinessType.INSERT)
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PostMapping("/submitAndFlowStart")
|
||||||
|
public R<TestLeaveVo> submitAndFlowStart(@Validated(AddGroup.class) @RequestBody TestLeaveBo bo) {
|
||||||
|
return R.ok(testLeaveService.submitAndFlowStart(bo));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改请假
|
* 修改请假
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,59 @@
|
|||||||
|
package org.dromara.workflow.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.common.tenant.core.TenantEntity;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例业务扩展对象 flow_instance_biz_ext
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
* @date 2025-08-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("flow_instance_biz_ext")
|
||||||
|
public class FlowInstanceBizExt extends TenantEntity {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@TableId(value = "id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例ID
|
||||||
|
*/
|
||||||
|
private Long instanceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务ID
|
||||||
|
*/
|
||||||
|
private String businessId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务编码
|
||||||
|
*/
|
||||||
|
private String businessCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务标题
|
||||||
|
*/
|
||||||
|
private String businessTitle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除标志(0代表存在 1代表删除)
|
||||||
|
*/
|
||||||
|
@TableLogic
|
||||||
|
private String delFlag;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
package org.dromara.workflow.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程spel达式定义对象 flow_spel
|
||||||
|
*
|
||||||
|
* @author Michelle.Chung
|
||||||
|
* @date 2025-07-04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("flow_spel")
|
||||||
|
public class FlowSpel extends BaseEntity {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件名称
|
||||||
|
*/
|
||||||
|
private String componentName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方法名
|
||||||
|
*/
|
||||||
|
private String methodName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
|
private String methodParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预览spel表达式
|
||||||
|
*/
|
||||||
|
private String viewSpel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除标志
|
||||||
|
*/
|
||||||
|
@TableLogic
|
||||||
|
private String delFlag;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -29,6 +29,11 @@ public class TestLeave extends BaseEntity {
|
|||||||
@TableId(value = "id")
|
@TableId(value = "id")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请编号
|
||||||
|
*/
|
||||||
|
private String applyCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请假类型
|
* 请假类型
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -53,6 +53,11 @@ public class CompleteTaskBo implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String notice;
|
private String notice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 办理人(可不填 用于覆盖当前节点办理人)
|
||||||
|
*/
|
||||||
|
private String handler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程变量
|
* 流程变量
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,60 @@
|
|||||||
|
package org.dromara.workflow.domain.bo;
|
||||||
|
|
||||||
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
|
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||||
|
import org.dromara.workflow.domain.FlowSpel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程spel达式定义业务对象 flow_spel
|
||||||
|
*
|
||||||
|
* @author Michelle.Chung
|
||||||
|
* @date 2025-07-04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@AutoMapper(target = FlowSpel.class, reverseConvertGenerate = false)
|
||||||
|
public class FlowSpelBo extends BaseEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件名称
|
||||||
|
*/
|
||||||
|
private String componentName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方法名
|
||||||
|
*/
|
||||||
|
private String methodName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
|
private String methodParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预览spel值
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "预览spel值不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
|
private String viewSpel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "状态(0正常 1停用)不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
}
|
||||||
@ -32,8 +32,6 @@ public class FlowTaskBo implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String flowCode;
|
private String flowCode;
|
||||||
|
|
||||||
private String projectId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程分类id
|
* 流程分类id
|
||||||
*/
|
*/
|
||||||
@ -60,4 +58,5 @@ public class FlowTaskBo implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String isRead;
|
private String isRead;
|
||||||
|
|
||||||
|
private String projectId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,38 @@
|
|||||||
|
package org.dromara.workflow.domain.bo;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程变量参数
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FlowUrgeTaskBo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "任务id为空", groups = AddGroup.class)
|
||||||
|
private List<Long> taskIdList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息类型
|
||||||
|
*/
|
||||||
|
private List<String> messageType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 催办内容
|
||||||
|
*/
|
||||||
|
@NotNull(message = "催办内容为空", groups = AddGroup.class)
|
||||||
|
private String message;
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package org.dromara.workflow.domain.bo;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程变量参数
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FlowVariableBo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "流程实例id为空", groups = AddGroup.class)
|
||||||
|
private Long instanceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程变量key
|
||||||
|
*/
|
||||||
|
@NotNull(message = "流程变量key为空", groups = AddGroup.class)
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程变量value
|
||||||
|
*/
|
||||||
|
@NotNull(message = "流程变量value为空", groups = AddGroup.class)
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,9 +1,11 @@
|
|||||||
package org.dromara.workflow.domain.bo;
|
package org.dromara.workflow.domain.bo;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.dromara.common.core.validate.AddGroup;
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
|
import org.dromara.workflow.domain.FlowInstanceBizExt;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@ -34,11 +36,21 @@ public class StartProcessBo implements Serializable {
|
|||||||
@NotBlank(message = "流程定义编码不能为空", groups = {AddGroup.class})
|
@NotBlank(message = "流程定义编码不能为空", groups = {AddGroup.class})
|
||||||
private String flowCode;
|
private String flowCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 办理人(可不填 用于覆盖当前节点办理人)
|
||||||
|
*/
|
||||||
|
private String handler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}}
|
* 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}}
|
||||||
*/
|
*/
|
||||||
private Map<String, Object> variables;
|
private Map<String, Object> variables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程业务扩展信息
|
||||||
|
*/
|
||||||
|
private FlowInstanceBizExt bizExt;
|
||||||
|
|
||||||
public Map<String, Object> getVariables() {
|
public Map<String, Object> getVariables() {
|
||||||
if (variables == null) {
|
if (variables == null) {
|
||||||
return new HashMap<>(16);
|
return new HashMap<>(16);
|
||||||
@ -46,4 +58,11 @@ public class StartProcessBo implements Serializable {
|
|||||||
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||||
return variables;
|
return variables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FlowInstanceBizExt getBizExt() {
|
||||||
|
if (ObjectUtil.isNull(bizExt)) {
|
||||||
|
bizExt = new FlowInstanceBizExt();
|
||||||
|
}
|
||||||
|
return bizExt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,16 @@ public class TestLeaveBo extends BaseEntity {
|
|||||||
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
|
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程code
|
||||||
|
*/
|
||||||
|
private String flowCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请编号
|
||||||
|
*/
|
||||||
|
private String applyCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请假类型
|
* 请假类型
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package org.dromara.workflow.domain.vo;
|
package org.dromara.workflow.domain.vo;
|
||||||
|
|
||||||
|
|
||||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
import io.github.linpeilie.annotations.AutoMapper;
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
|
|||||||
@ -0,0 +1,36 @@
|
|||||||
|
package org.dromara.workflow.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.translation.annotation.Translation;
|
||||||
|
import org.dromara.common.translation.constant.TransConstant;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抄送对象
|
||||||
|
*
|
||||||
|
* @author AprilWind
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FlowCopyVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名称
|
||||||
|
*/
|
||||||
|
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "userId")
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
public FlowCopyVo(Long userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -9,7 +9,6 @@ import org.dromara.workflow.common.constant.FlowConstant;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -51,9 +50,6 @@ public class FlowHisTaskVo implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private Long definitionId;
|
private Long definitionId;
|
||||||
|
|
||||||
|
|
||||||
private String projectName;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程定义名称
|
* 流程定义名称
|
||||||
*/
|
*/
|
||||||
@ -207,10 +203,19 @@ public class FlowHisTaskVo implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String runDuration;
|
private String runDuration;
|
||||||
|
|
||||||
|
//业务扩展信息开始
|
||||||
/**
|
/**
|
||||||
* 运行时长数字
|
* 业务编码
|
||||||
*/
|
*/
|
||||||
private Long runDurationNum;
|
private String businessCode;
|
||||||
|
|
||||||
|
private String projectName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务标题
|
||||||
|
*/
|
||||||
|
private String businessTitle;
|
||||||
|
//业务扩展信息结束
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置创建时间并计算任务运行时长
|
* 设置创建时间并计算任务运行时长
|
||||||
@ -239,7 +244,6 @@ public class FlowHisTaskVo implements Serializable {
|
|||||||
// 如果创建时间和更新时间均不为空,计算它们之间的时长
|
// 如果创建时间和更新时间均不为空,计算它们之间的时长
|
||||||
if (this.updateTime != null && this.createTime != null) {
|
if (this.updateTime != null && this.createTime != null) {
|
||||||
this.runDuration = DateUtils.getTimeDifference(this.updateTime, this.createTime);
|
this.runDuration = DateUtils.getTimeDifference(this.updateTime, this.createTime);
|
||||||
this.runDurationNum = DateUtils.difference(this.createTime, this.updateTime, ChronoUnit.SECONDS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,8 +42,6 @@ public class FlowInstanceVo {
|
|||||||
*/
|
*/
|
||||||
private Long definitionId;
|
private Long definitionId;
|
||||||
|
|
||||||
private String projectName;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程定义名称
|
* 流程定义名称
|
||||||
*/
|
*/
|
||||||
@ -136,4 +134,17 @@ public class FlowInstanceVo {
|
|||||||
@Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category")
|
@Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category")
|
||||||
private String categoryName;
|
private String categoryName;
|
||||||
|
|
||||||
|
//业务扩展信息开始
|
||||||
|
/**
|
||||||
|
* 业务编码
|
||||||
|
*/
|
||||||
|
private String businessCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务标题
|
||||||
|
*/
|
||||||
|
private String businessTitle;
|
||||||
|
//业务扩展信息结束
|
||||||
|
|
||||||
|
private String projectName;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,80 @@
|
|||||||
|
package org.dromara.workflow.domain.vo;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||||
|
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||||
|
import org.dromara.workflow.domain.FlowSpel;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程spel达式定义视图对象 flow_spel
|
||||||
|
*
|
||||||
|
* @author Michelle.Chung
|
||||||
|
* @date 2025-07-04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ExcelIgnoreUnannotated
|
||||||
|
@AutoMapper(target = FlowSpel.class)
|
||||||
|
public class FlowSpelVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "主键id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件名称
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "组件名称")
|
||||||
|
private String componentName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方法名
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "方法名")
|
||||||
|
private String methodName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "参数")
|
||||||
|
private String methodParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预览spel值
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "预览spel值")
|
||||||
|
private String viewSpel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
|
||||||
|
@ExcelDictFormat(readConverterExp = "0=正常,1=停用")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
}
|
||||||
@ -11,6 +11,7 @@ import java.io.Serializable;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务视图
|
* 任务视图
|
||||||
@ -50,9 +51,6 @@ public class FlowTaskVo implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private Long definitionId;
|
private Long definitionId;
|
||||||
|
|
||||||
|
|
||||||
private String projectName;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程实例表id
|
* 流程实例表id
|
||||||
*/
|
*/
|
||||||
@ -148,6 +146,7 @@ public class FlowTaskVo implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 办理人名称
|
* 办理人名称
|
||||||
*/
|
*/
|
||||||
|
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "assigneeIds")
|
||||||
private String assigneeNames;
|
private String assigneeNames;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,8 +186,31 @@ public class FlowTaskVo implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private List<ButtonPermissionVo> buttonList;
|
private List<ButtonPermissionVo> buttonList;
|
||||||
|
|
||||||
private Long flowUserId;
|
/**
|
||||||
|
* 抄送对象 ID 集合
|
||||||
|
* <p>
|
||||||
|
* 根据扩展属性中 CopySettingEnum 类型的数据生成,存储需要抄送的对象 ID
|
||||||
|
*/
|
||||||
|
private List<FlowCopyVo> copyList;
|
||||||
|
|
||||||
private String isRead;
|
/**
|
||||||
|
* 自定义参数 Map
|
||||||
|
* <p>
|
||||||
|
* 根据扩展属性中 VariablesEnum 类型的数据生成,存储 key=value 格式的自定义参数
|
||||||
|
*/
|
||||||
|
private Map<String, String> varList;
|
||||||
|
|
||||||
|
//业务扩展信息开始
|
||||||
|
/**
|
||||||
|
* 业务编码
|
||||||
|
*/
|
||||||
|
private String businessCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务标题
|
||||||
|
*/
|
||||||
|
private String businessTitle;
|
||||||
|
//业务扩展信息结束
|
||||||
|
|
||||||
|
private String projectName;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,45 @@
|
|||||||
|
package org.dromara.workflow.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node 扩展属性解析结果 VO
|
||||||
|
* <p>
|
||||||
|
* 用于封装从扩展属性 JSON 中解析出的各类信息,包括按钮权限、抄送对象和自定义参数。
|
||||||
|
*
|
||||||
|
* @author AprilWind
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class NodeExtVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按钮权限列表
|
||||||
|
* <p>
|
||||||
|
* 根据扩展属性中 ButtonPermissionEnum 类型的数据生成,每个元素表示一个按钮及其是否勾选。
|
||||||
|
*/
|
||||||
|
private List<ButtonPermissionVo> buttonPermissions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抄送对象 ID 集合
|
||||||
|
* <p>
|
||||||
|
* 根据扩展属性中 CopySettingEnum 类型的数据生成,存储需要抄送的对象 ID
|
||||||
|
*/
|
||||||
|
private Set<String> copySettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义参数 Map
|
||||||
|
* <p>
|
||||||
|
* 根据扩展属性中 VariablesEnum 类型的数据生成,存储 key=value 格式的自定义参数
|
||||||
|
*/
|
||||||
|
private Map<String, String> variables;
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package org.dromara.workflow.domain.vo;
|
package org.dromara.workflow.domain.vo;
|
||||||
|
|
||||||
|
|
||||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
import io.github.linpeilie.annotations.AutoMapper;
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
@ -31,6 +32,12 @@ public class TestLeaveVo implements Serializable {
|
|||||||
@ExcelProperty(value = "主键")
|
@ExcelProperty(value = "主键")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请编号
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "申请编号")
|
||||||
|
private String applyCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请假类型
|
* 请假类型
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package org.dromara.workflow.handler;
|
package org.dromara.workflow.handler;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.common.core.domain.event.ProcessTaskEvent;
|
|
||||||
import org.dromara.common.core.domain.event.ProcessDeleteEvent;
|
import org.dromara.common.core.domain.event.ProcessDeleteEvent;
|
||||||
import org.dromara.common.core.domain.event.ProcessEvent;
|
import org.dromara.common.core.domain.event.ProcessEvent;
|
||||||
|
import org.dromara.common.core.domain.event.ProcessTaskEvent;
|
||||||
import org.dromara.common.core.utils.SpringUtils;
|
import org.dromara.common.core.utils.SpringUtils;
|
||||||
import org.dromara.common.tenant.helper.TenantHelper;
|
import org.dromara.common.tenant.helper.TenantHelper;
|
||||||
import org.dromara.warm.flow.core.entity.Instance;
|
import org.dromara.warm.flow.core.entity.Instance;
|
||||||
@ -24,7 +24,7 @@ import java.util.Map;
|
|||||||
public class FlowProcessEventHandler {
|
public class FlowProcessEventHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
|
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成等)
|
||||||
*
|
*
|
||||||
* @param flowCode 流程定义编码
|
* @param flowCode 流程定义编码
|
||||||
* @param instance 实例数据
|
* @param instance 实例数据
|
||||||
@ -39,6 +39,7 @@ public class FlowProcessEventHandler {
|
|||||||
ProcessEvent processEvent = new ProcessEvent();
|
ProcessEvent processEvent = new ProcessEvent();
|
||||||
processEvent.setTenantId(tenantId);
|
processEvent.setTenantId(tenantId);
|
||||||
processEvent.setFlowCode(flowCode);
|
processEvent.setFlowCode(flowCode);
|
||||||
|
processEvent.setInstanceId(instance.getId());
|
||||||
processEvent.setBusinessId(instance.getBusinessId());
|
processEvent.setBusinessId(instance.getBusinessId());
|
||||||
processEvent.setNodeType(instance.getNodeType());
|
processEvent.setNodeType(instance.getNodeType());
|
||||||
processEvent.setNodeCode(instance.getNodeCode());
|
processEvent.setNodeCode(instance.getNodeCode());
|
||||||
@ -55,20 +56,23 @@ public class FlowProcessEventHandler {
|
|||||||
* @param flowCode 流程定义编码
|
* @param flowCode 流程定义编码
|
||||||
* @param instance 实例数据
|
* @param instance 实例数据
|
||||||
* @param taskId 任务id
|
* @param taskId 任务id
|
||||||
|
* @param params 上一个任务的办理参数
|
||||||
*/
|
*/
|
||||||
public void processTaskHandler(String flowCode, Instance instance, Long taskId) {
|
public void processTaskHandler(String flowCode, Instance instance, Long taskId, Map<String, Object> params) {
|
||||||
String tenantId = TenantHelper.getTenantId();
|
String tenantId = TenantHelper.getTenantId();
|
||||||
log.info("【流程任务事件发布】租户ID: {}, 流程编码: {}, 业务ID: {}, 节点类型: {}, 节点编码: {}, 节点名称: {}, 任务ID: {}",
|
log.info("【流程任务事件发布】租户ID: {}, 流程编码: {}, 业务ID: {}, 节点类型: {}, 节点编码: {}, 节点名称: {}, 任务ID: {}",
|
||||||
tenantId, flowCode, instance.getBusinessId(), instance.getNodeType(), instance.getNodeCode(), instance.getNodeName(), taskId);
|
tenantId, flowCode, instance.getBusinessId(), instance.getNodeType(), instance.getNodeCode(), instance.getNodeName(), taskId);
|
||||||
ProcessTaskEvent processTaskEvent = new ProcessTaskEvent();
|
ProcessTaskEvent processTaskEvent = new ProcessTaskEvent();
|
||||||
processTaskEvent.setTenantId(tenantId);
|
processTaskEvent.setTenantId(tenantId);
|
||||||
processTaskEvent.setFlowCode(flowCode);
|
processTaskEvent.setFlowCode(flowCode);
|
||||||
|
processTaskEvent.setInstanceId(instance.getId());
|
||||||
processTaskEvent.setBusinessId(instance.getBusinessId());
|
processTaskEvent.setBusinessId(instance.getBusinessId());
|
||||||
processTaskEvent.setNodeType(instance.getNodeType());
|
processTaskEvent.setNodeType(instance.getNodeType());
|
||||||
processTaskEvent.setNodeCode(instance.getNodeCode());
|
processTaskEvent.setNodeCode(instance.getNodeCode());
|
||||||
processTaskEvent.setNodeName(instance.getNodeName());
|
processTaskEvent.setNodeName(instance.getNodeName());
|
||||||
processTaskEvent.setTaskId(taskId);
|
processTaskEvent.setTaskId(taskId);
|
||||||
processTaskEvent.setStatus(instance.getFlowStatus());
|
processTaskEvent.setStatus(instance.getFlowStatus());
|
||||||
|
processTaskEvent.setParams(params);
|
||||||
SpringUtils.context().publishEvent(processTaskEvent);
|
SpringUtils.context().publishEvent(processTaskEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,17 @@
|
|||||||
package org.dromara.workflow.handler;
|
package org.dromara.workflow.handler;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.core.domain.dto.UserDTO;
|
||||||
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||||
import org.dromara.warm.flow.core.handler.PermissionHandler;
|
import org.dromara.warm.flow.core.handler.PermissionHandler;
|
||||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
import org.dromara.workflow.service.IFlwCommonService;
|
import org.dromara.workflow.service.IFlwTaskAssigneeService;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -24,7 +28,7 @@ import java.util.List;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class WorkflowPermissionHandler implements PermissionHandler {
|
public class WorkflowPermissionHandler implements PermissionHandler {
|
||||||
|
|
||||||
private final IFlwCommonService flwCommonService;
|
private final IFlwTaskAssigneeService flwTaskAssigneeService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 办理人权限标识,比如用户,角色,部门等,用于校验是否有权限办理任务
|
* 办理人权限标识,比如用户,角色,部门等,用于校验是否有权限办理任务
|
||||||
@ -51,9 +55,11 @@ public class WorkflowPermissionHandler implements PermissionHandler {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<String> convertPermissions(List<String> permissions) {
|
public List<String> convertPermissions(List<String> permissions) {
|
||||||
if (CollUtil.isNotEmpty(permissions)) {
|
if (CollUtil.isEmpty(permissions)) {
|
||||||
permissions = flwCommonService.buildUser(permissions);
|
return permissions;
|
||||||
}
|
}
|
||||||
return permissions;
|
String storageIds = CollUtil.join(permissions, StringUtils.SEPARATOR);
|
||||||
|
List<UserDTO> users = flwTaskAssigneeService.fetchUsersByStorageIds(storageIds,null);
|
||||||
|
return StreamUtils.toList(users, userDTO -> Convert.toStr(userDTO.getUserId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package org.dromara.workflow.listener;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.lang.TypeReference;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
@ -11,6 +13,7 @@ import org.dromara.common.core.domain.dto.UserDTO;
|
|||||||
import org.dromara.common.core.domain.model.LoginUser;
|
import org.dromara.common.core.domain.model.LoginUser;
|
||||||
import org.dromara.common.core.enums.BusinessStatusEnum;
|
import org.dromara.common.core.enums.BusinessStatusEnum;
|
||||||
import org.dromara.common.core.service.UserService;
|
import org.dromara.common.core.service.UserService;
|
||||||
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.warm.flow.core.FlowEngine;
|
import org.dromara.warm.flow.core.FlowEngine;
|
||||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||||
@ -28,11 +31,9 @@ import org.dromara.workflow.common.ConditionalOnEnable;
|
|||||||
import org.dromara.workflow.common.constant.FlowConstant;
|
import org.dromara.workflow.common.constant.FlowConstant;
|
||||||
import org.dromara.workflow.common.enums.TaskStatusEnum;
|
import org.dromara.workflow.common.enums.TaskStatusEnum;
|
||||||
import org.dromara.workflow.domain.bo.FlowCopyBo;
|
import org.dromara.workflow.domain.bo.FlowCopyBo;
|
||||||
|
import org.dromara.workflow.domain.vo.NodeExtVo;
|
||||||
import org.dromara.workflow.handler.FlowProcessEventHandler;
|
import org.dromara.workflow.handler.FlowProcessEventHandler;
|
||||||
import org.dromara.workflow.service.IFlwCommonService;
|
import org.dromara.workflow.service.*;
|
||||||
import org.dromara.workflow.service.IFlwInstanceService;
|
|
||||||
import org.dromara.workflow.service.IFlwTaskAssigneeService;
|
|
||||||
import org.dromara.workflow.service.IFlwTaskService;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -56,7 +57,8 @@ public class WorkflowGlobalListener implements GlobalListener {
|
|||||||
private final InsService insService;
|
private final InsService insService;
|
||||||
private final IFlwTaskAssigneeService flwTaskAssigneeService;
|
private final IFlwTaskAssigneeService flwTaskAssigneeService;
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
private final IFlwInstanceService flwInstanceService;
|
||||||
|
private final IFlwNodeExtService nodeExtService;
|
||||||
|
|
||||||
|
|
||||||
// 需要分专业的角色
|
// 需要分专业的角色
|
||||||
@ -76,42 +78,6 @@ public class WorkflowGlobalListener implements GlobalListener {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void create(ListenerVariable listenerVariable) {
|
public void create(ListenerVariable listenerVariable) {
|
||||||
log.info("全局创建监听器开始执行......");
|
|
||||||
|
|
||||||
// 获取相关变量
|
|
||||||
// List<Task> nextTasks = listenerVariable.getNextTasks();
|
|
||||||
// Definition definition = listenerVariable.getDefinition();
|
|
||||||
// Map<String, Object> variable = listenerVariable.getVariable();
|
|
||||||
//
|
|
||||||
// for (Task flowTask : nextTasks) {
|
|
||||||
// String nodeCode = flowTask.getNodeCode();
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// // 查询节点信息
|
|
||||||
// FlowNode byNodeCode = flwTaskService.getByNodeCode(nodeCode, definition.getId());
|
|
||||||
//
|
|
||||||
// // 获取原来的办理人信息
|
|
||||||
// List<String> originalPermissionList = flowTask.getPermissionList();
|
|
||||||
// log.info("节点 {} 原来的办理人信息: {}", nodeCode, originalPermissionList);
|
|
||||||
// String permissionFlag = byNodeCode.getPermissionFlag();
|
|
||||||
// try {
|
|
||||||
// if(permissionFlag.contains("role")){
|
|
||||||
// permissionFlag = permissionFlag.replace("@@", ",");
|
|
||||||
//
|
|
||||||
// String flowCode = definition.getFlowCode();
|
|
||||||
// String projectId = flowCode.split("_")[0];
|
|
||||||
//
|
|
||||||
// List<UserDTO> userDTOS = flwTaskAssigneeService.fetchUsersByStorageIds(permissionFlag, Long.valueOf(projectId));
|
|
||||||
// variable.put("userList", userDTOS.stream().map(UserDTO::getUserId).map(String::valueOf).collect(Collectors.toList()));
|
|
||||||
// flowTask.setPermissionList(userDTOS.stream().map(UserDTO::getUserId).map(String::valueOf).collect(Collectors.toList()));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }catch (Exception e) {
|
|
||||||
// log.error("设置失败: {}", e.getMessage());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
log.info("全局创建监听器执行结束......");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -123,7 +89,25 @@ public class WorkflowGlobalListener implements GlobalListener {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void start(ListenerVariable listenerVariable) {
|
public void start(ListenerVariable listenerVariable) {
|
||||||
|
String ext = listenerVariable.getNode().getExt();
|
||||||
|
if (StringUtils.isNotBlank(ext)) {
|
||||||
|
Map<String, Object> variable = listenerVariable.getVariable();
|
||||||
|
NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext, variable);
|
||||||
|
Set<String> copyList = nodeExt.getCopySettings();
|
||||||
|
if (CollUtil.isNotEmpty(copyList)) {
|
||||||
|
List<FlowCopyBo> list = StreamUtils.toList(copyList, x -> {
|
||||||
|
FlowCopyBo bo = new FlowCopyBo();
|
||||||
|
Long id = Convert.toLong(x);
|
||||||
|
bo.setUserId(id);
|
||||||
|
bo.setUserName(userService.selectUserNameById(id));
|
||||||
|
return bo;
|
||||||
|
});
|
||||||
|
variable.put(FlowConstant.FLOW_COPY_LIST, list);
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(nodeExt.getVariables())) {
|
||||||
|
variable.putAll(nodeExt.getVariables());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -223,6 +207,7 @@ public class WorkflowGlobalListener implements GlobalListener {
|
|||||||
Instance instance = listenerVariable.getInstance();
|
Instance instance = listenerVariable.getInstance();
|
||||||
Definition definition = listenerVariable.getDefinition();
|
Definition definition = listenerVariable.getDefinition();
|
||||||
Task task = listenerVariable.getTask();
|
Task task = listenerVariable.getTask();
|
||||||
|
List<Task> nextTasks = listenerVariable.getNextTasks();
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
FlowParams flowParams = listenerVariable.getFlowParams();
|
FlowParams flowParams = listenerVariable.getFlowParams();
|
||||||
Map<String, Object> variable = new HashMap<>();
|
Map<String, Object> variable = new HashMap<>();
|
||||||
@ -245,52 +230,61 @@ public class WorkflowGlobalListener implements GlobalListener {
|
|||||||
if (StringUtils.isNotBlank(status)) {
|
if (StringUtils.isNotBlank(status)) {
|
||||||
flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, status, params, false);
|
flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, status, params, false);
|
||||||
}
|
}
|
||||||
|
if (!BusinessStatusEnum.initialState(instance.getFlowStatus())) {
|
||||||
|
if (task != null && CollUtil.isNotEmpty(nextTasks) && nextTasks.size() == 1
|
||||||
|
&& flwCommonService.applyNodeCode(definition.getId()).equals(nextTasks.get(0).getNodeCode())) {
|
||||||
|
// 如果为画线指定驳回 线条指定为驳回 驳回得节点为申请人节点 则修改流程状态为退回
|
||||||
|
flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, BusinessStatusEnum.BACK.getStatus(), params, false);
|
||||||
|
// 修改流程实例状态
|
||||||
|
instance.setFlowStatus(BusinessStatusEnum.BACK.getStatus());
|
||||||
|
FlowEngine.insService().updateById(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//发布任务事件
|
//发布任务事件
|
||||||
if (task != null) {
|
if (CollUtil.isNotEmpty(nextTasks)) {
|
||||||
flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), instance, task.getId());
|
for (Task nextTask : nextTasks) {
|
||||||
|
flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), instance, nextTask.getId(), params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ObjectUtil.isNull(flowParams)) {
|
if (ObjectUtil.isNull(flowParams)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//给处理人发消息重新统计数据
|
// 只有办理或者退回的时候才执行消息通知和抄送
|
||||||
|
if (!TaskStatusEnum.isPassOrBack(flowParams.getHisStatus())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ObjectUtil.isNull(variable)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (variable.containsKey(FlowConstant.FLOW_COPY_LIST)) {
|
||||||
|
List<FlowCopyBo> flowCopyList = MapUtil.get(variable, FlowConstant.FLOW_COPY_LIST, new TypeReference<>() {
|
||||||
|
});
|
||||||
|
// 添加抄送人
|
||||||
|
flwTaskService.setCopy(task, flowCopyList);
|
||||||
|
//发送抄送消息
|
||||||
|
flwCommonService.sendCopyMessage(definition.getFlowName(), definition.getFlowCode(), flowCopyList);
|
||||||
|
}
|
||||||
|
if (variable.containsKey(FlowConstant.MESSAGE_TYPE)) {
|
||||||
|
List<String> messageType = MapUtil.get(variable, FlowConstant.MESSAGE_TYPE, new TypeReference<>() {
|
||||||
|
});
|
||||||
|
String notice = MapUtil.getStr(variable, FlowConstant.MESSAGE_NOTICE);
|
||||||
|
flwCommonService.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice);
|
||||||
|
}
|
||||||
|
FlowEngine.insService().removeVariables(instance.getId(),
|
||||||
|
FlowConstant.FLOW_COPY_LIST,
|
||||||
|
FlowConstant.MESSAGE_TYPE,
|
||||||
|
FlowConstant.MESSAGE_NOTICE,
|
||||||
|
FlowConstant.SUBMIT
|
||||||
|
);
|
||||||
|
|
||||||
|
//给处理人发消息重新统计数据
|
||||||
if (task != null) {
|
if (task != null) {
|
||||||
flwCommonService.sendCountMessage(task);
|
flwCommonService.sendCountMessage(task);
|
||||||
}
|
}
|
||||||
// 只有办理或者退回的时候才执行消息通知和抄送
|
|
||||||
if (TaskStatusEnum.PASS.getStatus().equals(flowParams.getHisStatus())
|
|
||||||
|| TaskStatusEnum.BACK.getStatus().equals(flowParams.getHisStatus())) {
|
|
||||||
if (variable != null) {
|
|
||||||
if (variable.containsKey(FlowConstant.FLOW_COPY_LIST)) {
|
|
||||||
List<FlowCopyBo> flowCopyList = (List<FlowCopyBo>) variable.get(FlowConstant.FLOW_COPY_LIST);
|
|
||||||
// 添加抄送人
|
|
||||||
flwTaskService.setCopy(task, flowCopyList);
|
|
||||||
//发送抄送消息
|
|
||||||
flwCommonService.sendCopyMessage(definition.getFlowName(), definition.getFlowCode(), flowCopyList);
|
|
||||||
}
|
|
||||||
if (variable.containsKey(FlowConstant.MESSAGE_TYPE)) {
|
|
||||||
List<String> messageType = (List<String>) variable.get(FlowConstant.MESSAGE_TYPE);
|
|
||||||
String notice = (String) variable.get(FlowConstant.MESSAGE_NOTICE);
|
|
||||||
// 消息通知
|
|
||||||
if (CollUtil.isNotEmpty(messageType)) {
|
|
||||||
flwCommonService.sendMessage(definition.getFlowName(),definition.getFlowCode(), instance.getId(), messageType, notice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FlowInstance ins = new FlowInstance();
|
|
||||||
Map<String, Object> variableMap = instance.getVariableMap();
|
|
||||||
variableMap.remove(FlowConstant.FLOW_COPY_LIST);
|
|
||||||
variableMap.remove(FlowConstant.MESSAGE_TYPE);
|
|
||||||
variableMap.remove(FlowConstant.MESSAGE_NOTICE);
|
|
||||||
variableMap.remove(FlowConstant.SUBMIT);
|
|
||||||
ins.setId(instance.getId());
|
|
||||||
ins.setVariable(FlowEngine.jsonConvert.objToStr(variableMap));
|
|
||||||
insService.updateById(ins);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 根据流程实例确定最终状态
|
* 根据流程实例确定最终状态
|
||||||
*
|
*
|
||||||
@ -304,11 +298,10 @@ public class WorkflowGlobalListener implements GlobalListener {
|
|||||||
return flowStatus;
|
return flowStatus;
|
||||||
} else {
|
} else {
|
||||||
Long instanceId = instance.getId();
|
Long instanceId = instance.getId();
|
||||||
List<FlowTask> flowTasks = flwTaskService.selectByInstId(instanceId);
|
if (flwTaskService.isTaskEnd(instanceId)) {
|
||||||
if (CollUtil.isEmpty(flowTasks)) {
|
|
||||||
String status = BusinessStatusEnum.FINISH.getStatus();
|
String status = BusinessStatusEnum.FINISH.getStatus();
|
||||||
// 更新流程状态为已完成
|
// 更新流程状态为已完成
|
||||||
instanceService.updateStatus(instanceId, status);
|
flwInstanceService.updateStatus(instanceId, status);
|
||||||
log.info("流程已结束,状态更新为: {}", status);
|
log.info("流程已结束,状态更新为: {}", status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
package org.dromara.workflow.mapper;
|
package org.dromara.workflow.mapper;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import org.dromara.common.mybatis.annotation.DataColumn;
|
|
||||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
|
||||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
||||||
import org.dromara.workflow.domain.FlowCategory;
|
import org.dromara.workflow.domain.FlowCategory;
|
||||||
@ -20,19 +18,6 @@ import java.util.stream.Stream;
|
|||||||
*/
|
*/
|
||||||
public interface FlwCategoryMapper extends BaseMapperPlus<FlowCategory, FlowCategoryVo> {
|
public interface FlwCategoryMapper extends BaseMapperPlus<FlowCategory, FlowCategoryVo> {
|
||||||
|
|
||||||
/**
|
|
||||||
* 统计指定流程分类ID的分类数量
|
|
||||||
*
|
|
||||||
* @param categoryId 流程分类ID
|
|
||||||
* @return 该流程分类ID的分类数量
|
|
||||||
*/
|
|
||||||
@DataPermission({
|
|
||||||
@DataColumn(key = "deptName", value = "createDept")
|
|
||||||
})
|
|
||||||
default long countCategoryById(Long categoryId) {
|
|
||||||
return this.selectCount(new LambdaQueryWrapper<FlowCategory>().eq(FlowCategory::getCategoryId, categoryId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据父流程分类ID查询其所有子流程分类的列表
|
* 根据父流程分类ID查询其所有子流程分类的列表
|
||||||
*
|
*
|
||||||
|
|||||||
@ -0,0 +1,61 @@
|
|||||||
|
package org.dromara.workflow.mapper;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||||
|
import org.dromara.workflow.domain.FlowInstanceBizExt;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例业务扩展Mapper接口
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
* @date 2025-08-05
|
||||||
|
*/
|
||||||
|
public interface FlwInstanceBizExtMapper extends BaseMapperPlus<FlowInstanceBizExt, FlowInstanceBizExt> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 instanceId 保存或更新流程实例业务扩展
|
||||||
|
*
|
||||||
|
* @param entity 流程实例业务扩展实体
|
||||||
|
* @return 操作是否成功
|
||||||
|
*/
|
||||||
|
default int saveOrUpdateByInstanceId(FlowInstanceBizExt entity) {
|
||||||
|
// 查询是否存在
|
||||||
|
FlowInstanceBizExt exist = this.selectOne(new LambdaQueryWrapper<FlowInstanceBizExt>()
|
||||||
|
.eq(FlowInstanceBizExt::getInstanceId, entity.getInstanceId()));
|
||||||
|
|
||||||
|
if (ObjectUtil.isNotNull(exist)) {
|
||||||
|
// 存在就带上主键更新
|
||||||
|
entity.setId(exist.getId());
|
||||||
|
return updateById(entity);
|
||||||
|
} else {
|
||||||
|
// 不存在就插入
|
||||||
|
return insert(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按照流程实例ID删除单个流程实例业务扩展
|
||||||
|
*
|
||||||
|
* @param instanceId 流程实例ID
|
||||||
|
* @return 删除的行数
|
||||||
|
*/
|
||||||
|
default int deleteByInstId(Long instanceId) {
|
||||||
|
return this.delete(new LambdaQueryWrapper<FlowInstanceBizExt>()
|
||||||
|
.eq(FlowInstanceBizExt::getInstanceId, instanceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按照流程实例ID批量删除流程实例业务扩展
|
||||||
|
*
|
||||||
|
* @param instanceIds 流程实例ID列表
|
||||||
|
* @return 删除的行数
|
||||||
|
*/
|
||||||
|
default int deleteByInstIds(List<Long> instanceIds) {
|
||||||
|
return this.delete(new LambdaQueryWrapper<FlowInstanceBizExt>()
|
||||||
|
.in(FlowInstanceBizExt::getInstanceId, instanceIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package org.dromara.workflow.mapper;
|
||||||
|
|
||||||
|
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||||
|
import org.dromara.workflow.domain.FlowSpel;
|
||||||
|
import org.dromara.workflow.domain.vo.FlowSpelVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程spel达式定义Mapper接口
|
||||||
|
*
|
||||||
|
* @author Michelle.Chung
|
||||||
|
* @date 2025-07-04
|
||||||
|
*/
|
||||||
|
public interface FlwSpelMapper extends BaseMapperPlus<FlowSpel, FlowSpelVo> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -19,7 +19,6 @@ import java.util.List;
|
|||||||
* @date 2024-03-02
|
* @date 2024-03-02
|
||||||
*/
|
*/
|
||||||
public interface FlwTaskMapper {
|
public interface FlwTaskMapper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取待办信息
|
* 获取待办信息
|
||||||
*
|
*
|
||||||
@ -28,23 +27,6 @@ public interface FlwTaskMapper {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
Page<FlowTaskVo> getListRunTask(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
Page<FlowTaskVo> getListRunTask(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
||||||
Page<FlowTaskVo> getListRunTaskDefinitionIds(@Param("page") Page<FlowTaskVo> page, @Param("definitionIds") List<Long> definitionIds, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 不分页版
|
|
||||||
* @param definitionIds
|
|
||||||
* @param queryWrapper
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
List<FlowTaskVo> getListRunTaskDefinitionInfo(@Param("definitionIds") List<Long> definitionIds, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取待办信息
|
|
||||||
*
|
|
||||||
* @param queryWrapper 条件
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
List<FlowTaskVo> getListRunTask(@Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取已办
|
* 获取已办
|
||||||
@ -54,7 +36,6 @@ public interface FlwTaskMapper {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
Page<FlowHisTaskVo> getListFinishTask(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
Page<FlowHisTaskVo> getListFinishTask(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
||||||
Page<FlowHisTaskVo> getListFinishDefinitionIdsTask(@Param("page") Page<FlowTaskVo> page,@Param("definitionIds") List<Long> definitionIds, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询当前用户的抄送
|
* 查询当前用户的抄送
|
||||||
@ -65,9 +46,24 @@ public interface FlwTaskMapper {
|
|||||||
*/
|
*/
|
||||||
Page<FlowTaskVo> getTaskCopyByPage(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) QueryWrapper<FlowTaskBo> queryWrapper);
|
Page<FlowTaskVo> getTaskCopyByPage(@Param("page") Page<FlowTaskVo> page, @Param(Constants.WRAPPER) QueryWrapper<FlowTaskBo> queryWrapper);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Page<FlowTaskVo> getTaskCopyDefinitionIdsByPage(@Param("page") Page<FlowTaskVo> page,@Param("definitionIds") List<Long> definitionIds, @Param(Constants.WRAPPER) QueryWrapper<FlowTaskBo> queryWrapper);
|
Page<FlowTaskVo> getTaskCopyDefinitionIdsByPage(@Param("page") Page<FlowTaskVo> page,@Param("definitionIds") List<Long> definitionIds, @Param(Constants.WRAPPER) QueryWrapper<FlowTaskBo> queryWrapper);
|
||||||
|
|
||||||
void copyRead(@Param("flowUserId") Long flowUserId);
|
void copyRead(@Param("flowUserId") Long flowUserId);
|
||||||
|
/**
|
||||||
|
* 不分页版
|
||||||
|
* @param definitionIds
|
||||||
|
* @param queryWrapper
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<FlowTaskVo> getListRunTaskDefinitionInfo(@Param("definitionIds") List<Long> definitionIds, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
||||||
|
|
||||||
|
Page<FlowHisTaskVo> getListFinishDefinitionIdsTask(@Param("page") Page<FlowTaskVo> page,@Param("definitionIds") List<Long> definitionIds, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
||||||
|
|
||||||
|
Page<FlowTaskVo> getListRunTaskDefinitionIds(@Param("page") Page<FlowTaskVo> page, @Param("definitionIds") List<Long> definitionIds, @Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,38 @@
|
|||||||
|
package org.dromara.workflow.rule;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
|
import org.dromara.common.core.service.DeptService;
|
||||||
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spel表达式规则组件
|
||||||
|
* <p>
|
||||||
|
* 通过该组件统一管理流程定义中的spel表达式
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Michelle.Chung
|
||||||
|
*/
|
||||||
|
@ConditionalOnEnable
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SpelRuleComponent {
|
||||||
|
|
||||||
|
private final DeptService deptService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过发起人部门id获取部门负责人
|
||||||
|
*/
|
||||||
|
public Long selectDeptLeaderById(Long initiatorDeptId) {
|
||||||
|
Long leaderId = deptService.selectDeptLeaderById(initiatorDeptId);
|
||||||
|
if (ObjectUtil.isNull(leaderId)) {
|
||||||
|
throw new ServiceException("当前部门未设置负责人,请联系管理员操作。");
|
||||||
|
}
|
||||||
|
return leaderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -45,13 +45,6 @@ public interface IFlwCategoryService {
|
|||||||
*/
|
*/
|
||||||
List<Tree<String>> selectCategoryTreeList(FlowCategoryBo category);
|
List<Tree<String>> selectCategoryTreeList(FlowCategoryBo category);
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验流程分类是否有数据权限
|
|
||||||
*
|
|
||||||
* @param categoryId 流程分类ID
|
|
||||||
*/
|
|
||||||
void checkCategoryDataScope(Long categoryId);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验流程分类名称是否唯一
|
* 校验流程分类名称是否唯一
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package org.dromara.workflow.service;
|
package org.dromara.workflow.service;
|
||||||
|
|
||||||
|
import org.dromara.common.core.domain.dto.UserDTO;
|
||||||
import org.dromara.warm.flow.core.entity.Task;
|
import org.dromara.warm.flow.core.entity.Task;
|
||||||
import org.dromara.workflow.domain.bo.FlowCopyBo;
|
import org.dromara.workflow.domain.bo.FlowCopyBo;
|
||||||
|
|
||||||
@ -12,14 +13,6 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface IFlwCommonService {
|
public interface IFlwCommonService {
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建工作流用户
|
|
||||||
*
|
|
||||||
* @param permissionList 办理用户
|
|
||||||
* @return 用户
|
|
||||||
*/
|
|
||||||
List<String> buildUser(List<String> permissionList);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送消息
|
* 发送消息
|
||||||
*
|
*
|
||||||
@ -47,4 +40,27 @@ public interface IFlwCommonService {
|
|||||||
* @return 申请人节点编码
|
* @return 申请人节点编码
|
||||||
*/
|
*/
|
||||||
String applyNodeCode(Long definitionId);
|
String applyNodeCode(Long definitionId);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息
|
||||||
|
*
|
||||||
|
* @param messageType 消息类型
|
||||||
|
* @param message 消息内容
|
||||||
|
* @param subject 邮件标题
|
||||||
|
* @param userList 接收用户
|
||||||
|
*/
|
||||||
|
void sendMessage(List<String> messageType, String message, String subject, List<UserDTO> userList);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息
|
||||||
|
*
|
||||||
|
* @param flowName 流程定义名称
|
||||||
|
* @param instId 实例id
|
||||||
|
* @param messageType 消息类型
|
||||||
|
* @param message 消息内容,为空则发送默认配置的消息内容
|
||||||
|
*/
|
||||||
|
void sendMessage(String flowName, Long instId, List<String> messageType, String message);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package org.dromara.workflow.service;
|
|||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.workflow.domain.bo.FlowDefinitionBo;
|
import org.dromara.warm.flow.orm.entity.FlowDefinition;
|
||||||
import org.dromara.workflow.domain.vo.FlowDefinitionVo;
|
import org.dromara.workflow.domain.vo.FlowDefinitionVo;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@ -20,20 +20,20 @@ public interface IFlwDefinitionService {
|
|||||||
/**
|
/**
|
||||||
* 查询流程定义列表
|
* 查询流程定义列表
|
||||||
*
|
*
|
||||||
* @param flowDefinitionBo 参数
|
* @param flowDefinition 参数
|
||||||
* @param pageQuery 分页
|
* @param pageQuery 分页
|
||||||
* @return 返回分页列表
|
* @return 返回分页列表
|
||||||
*/
|
*/
|
||||||
TableDataInfo<FlowDefinitionVo> queryList(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery);
|
TableDataInfo<FlowDefinitionVo> queryList(FlowDefinition flowDefinition, PageQuery pageQuery);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询未发布的流程定义列表
|
* 查询未发布的流程定义列表
|
||||||
*
|
*
|
||||||
* @param flowDefinitionBo 参数
|
* @param flowDefinition 参数
|
||||||
* @param pageQuery 分页
|
* @param pageQuery 分页
|
||||||
* @return 返回分页列表
|
* @return 返回分页列表
|
||||||
*/
|
*/
|
||||||
TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery);
|
TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发布流程定义
|
* 发布流程定义
|
||||||
@ -69,13 +69,6 @@ public interface IFlwDefinitionService {
|
|||||||
*/
|
*/
|
||||||
boolean removeDef(List<Long> ids);
|
boolean removeDef(List<Long> ids);
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增流程定义
|
|
||||||
*
|
|
||||||
* @param projectId 项目id
|
|
||||||
*/
|
|
||||||
void insertDefByProjectId(Long projectId);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增租户流程定义
|
* 新增租户流程定义
|
||||||
*
|
*
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import org.dromara.warm.flow.orm.entity.FlowInstance;
|
|||||||
import org.dromara.workflow.domain.bo.FlowCancelBo;
|
import org.dromara.workflow.domain.bo.FlowCancelBo;
|
||||||
import org.dromara.workflow.domain.bo.FlowInstanceBo;
|
import org.dromara.workflow.domain.bo.FlowInstanceBo;
|
||||||
import org.dromara.workflow.domain.bo.FlowInvalidBo;
|
import org.dromara.workflow.domain.bo.FlowInvalidBo;
|
||||||
|
import org.dromara.workflow.domain.bo.FlowVariableBo;
|
||||||
import org.dromara.workflow.domain.vo.FlowInstanceVo;
|
import org.dromara.workflow.domain.vo.FlowInstanceVo;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -84,6 +85,14 @@ public interface IFlwInstanceService {
|
|||||||
*/
|
*/
|
||||||
boolean deleteByInstanceIds(List<Long> instanceIds);
|
boolean deleteByInstanceIds(List<Long> instanceIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按照实例id删除已完成得流程实例
|
||||||
|
*
|
||||||
|
* @param instanceIds 删除的实例id
|
||||||
|
* @return 删除结果
|
||||||
|
*/
|
||||||
|
boolean deleteHisByInstanceIds(List<Long> instanceIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 撤销流程
|
* 撤销流程
|
||||||
*
|
*
|
||||||
@ -125,6 +134,14 @@ public interface IFlwInstanceService {
|
|||||||
*/
|
*/
|
||||||
Map<String, Object> instanceVariable(Long instanceId);
|
Map<String, Object> instanceVariable(Long instanceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新流程变量
|
||||||
|
*
|
||||||
|
* @param bo 参数
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
boolean updateVariable(FlowVariableBo bo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置流程变量
|
* 设置流程变量
|
||||||
*
|
*
|
||||||
@ -141,14 +158,6 @@ public interface IFlwInstanceService {
|
|||||||
*/
|
*/
|
||||||
FlowInstance selectByTaskId(Long taskId);
|
FlowInstance selectByTaskId(Long taskId);
|
||||||
|
|
||||||
/**
|
|
||||||
* 按任务id查询实例
|
|
||||||
*
|
|
||||||
* @param taskIdList 任务id
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
List<FlowInstance> selectByTaskIdList(List<Long> taskIdList);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 作废流程
|
* 作废流程
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
package org.dromara.workflow.service;
|
package org.dromara.workflow.service;
|
||||||
|
|
||||||
import org.dromara.workflow.domain.vo.ButtonPermissionVo;
|
import org.dromara.workflow.domain.vo.NodeExtVo;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程节点扩展属性 服务层
|
* 流程节点扩展属性 服务层
|
||||||
@ -12,11 +12,24 @@ import java.util.List;
|
|||||||
public interface IFlwNodeExtService {
|
public interface IFlwNodeExtService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选
|
* 解析扩展属性 JSON 并构建 Node 扩展属性对象
|
||||||
|
* <p>
|
||||||
|
* 根据传入的 JSON 字符串,将扩展属性分为三类:
|
||||||
|
* 1. ButtonPermissionEnum:解析为按钮权限列表,标记每个按钮是否勾选
|
||||||
|
* 2. CopySettingEnum:解析为抄送对象 ID 集合
|
||||||
|
* 3. VariablesEnum:解析为自定义参数 Map
|
||||||
*
|
*
|
||||||
* @param ext 扩展属性 JSON 字符串
|
* <p>示例 JSON:
|
||||||
* @return 按钮权限 VO 列表
|
* [
|
||||||
|
* {"code": "ButtonPermissionEnum", "value": "back,termination"},
|
||||||
|
* {"code": "CopySettingEnum", "value": "1"},
|
||||||
|
* {"code": "VariablesEnum", "value": "key1=value1,key2=value2"}
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* @param ext 扩展属性 JSON 字符串
|
||||||
|
* @param variable 流程变量
|
||||||
|
* @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map
|
||||||
*/
|
*/
|
||||||
List<ButtonPermissionVo> buildButtonPermissionsFromExt(String ext);
|
NodeExtVo parseNodeExt(String ext, Map<String, Object> variable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,88 @@
|
|||||||
|
package org.dromara.workflow.service;
|
||||||
|
|
||||||
|
import org.dromara.common.core.domain.dto.TaskAssigneeDTO;
|
||||||
|
import org.dromara.common.core.domain.model.TaskAssigneeBody;
|
||||||
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
|
import org.dromara.workflow.domain.bo.FlowSpelBo;
|
||||||
|
import org.dromara.workflow.domain.vo.FlowSpelVo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程spel达式定义Service接口
|
||||||
|
*
|
||||||
|
* @author Michelle.Chung
|
||||||
|
* @date 2025-07-04
|
||||||
|
*/
|
||||||
|
public interface IFlwSpelService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询流程spel达式定义
|
||||||
|
*
|
||||||
|
* @param id 主键
|
||||||
|
* @return 流程spel达式定义
|
||||||
|
*/
|
||||||
|
FlowSpelVo queryById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询流程spel达式定义列表
|
||||||
|
*
|
||||||
|
* @param bo 查询条件
|
||||||
|
* @param pageQuery 分页参数
|
||||||
|
* @return 流程spel达式定义分页列表
|
||||||
|
*/
|
||||||
|
TableDataInfo<FlowSpelVo> queryPageList(FlowSpelBo bo, PageQuery pageQuery);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询符合条件的流程spel达式定义列表
|
||||||
|
*
|
||||||
|
* @param bo 查询条件
|
||||||
|
* @return 流程spel达式定义列表
|
||||||
|
*/
|
||||||
|
List<FlowSpelVo> queryList(FlowSpelBo bo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增流程spel达式定义
|
||||||
|
*
|
||||||
|
* @param bo 流程spel达式定义
|
||||||
|
* @return 是否新增成功
|
||||||
|
*/
|
||||||
|
Boolean insertByBo(FlowSpelBo bo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改流程spel达式定义
|
||||||
|
*
|
||||||
|
* @param bo 流程spel达式定义
|
||||||
|
* @return 是否修改成功
|
||||||
|
*/
|
||||||
|
Boolean updateByBo(FlowSpelBo bo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验并批量删除流程spel达式定义信息
|
||||||
|
*
|
||||||
|
* @param ids 待删除的主键集合
|
||||||
|
* @param isValid 是否进行有效性校验
|
||||||
|
* @return 是否删除成功
|
||||||
|
*/
|
||||||
|
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询spel并返回任务指派的列表,支持分页
|
||||||
|
*
|
||||||
|
* @param taskQuery 查询条件
|
||||||
|
* @return 办理人
|
||||||
|
*/
|
||||||
|
TaskAssigneeDTO selectSpelByTaskAssigneeList(TaskAssigneeBody taskQuery);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据视图 SpEL 表达式列表,查询对应的备注信息
|
||||||
|
*
|
||||||
|
* @param viewSpels SpEL 表达式列表
|
||||||
|
* @return 映射表:key 为 SpEL 表达式,value 为对应备注;若为空则返回空 Map
|
||||||
|
*/
|
||||||
|
Map<String, String> selectRemarksBySpels(List<String> viewSpels);
|
||||||
|
|
||||||
|
}
|
||||||
@ -12,10 +12,8 @@ import org.dromara.warm.flow.orm.entity.FlowTask;
|
|||||||
import org.dromara.workflow.domain.bo.*;
|
import org.dromara.workflow.domain.bo.*;
|
||||||
import org.dromara.workflow.domain.vo.FlowHisTaskVo;
|
import org.dromara.workflow.domain.vo.FlowHisTaskVo;
|
||||||
import org.dromara.workflow.domain.vo.FlowTaskVo;
|
import org.dromara.workflow.domain.vo.FlowTaskVo;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务 服务层
|
* 任务 服务层
|
||||||
@ -113,11 +111,11 @@ public interface IFlwTaskService {
|
|||||||
/**
|
/**
|
||||||
* 获取可驳回的前置节点
|
* 获取可驳回的前置节点
|
||||||
*
|
*
|
||||||
* @param definitionId 流程定义id
|
* @param taskId 任务id
|
||||||
* @param nowNodeCode 当前节点
|
* @param nowNodeCode 当前节点
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
List<Node> getBackTaskNode(Long definitionId, String nowNodeCode);
|
List<Node> getBackTaskNode(Long taskId, String nowNodeCode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 终止任务
|
* 终止任务
|
||||||
@ -151,14 +149,6 @@ public interface IFlwTaskService {
|
|||||||
*/
|
*/
|
||||||
List<FlowNode> getNextNodeList(FlowNextNodeBo bo);
|
List<FlowNode> getNextNodeList(FlowNextNodeBo bo);
|
||||||
|
|
||||||
/**
|
|
||||||
* 按照任务id查询任务
|
|
||||||
*
|
|
||||||
* @param taskIdList 任务id
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
List<FlowHisTask> selectHisTaskByIdList(List<Long> taskIdList);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按照任务id查询任务
|
* 按照任务id查询任务
|
||||||
*
|
*
|
||||||
@ -167,14 +157,6 @@ public interface IFlwTaskService {
|
|||||||
*/
|
*/
|
||||||
FlowHisTask selectHisTaskById(Long taskId);
|
FlowHisTask selectHisTaskById(Long taskId);
|
||||||
|
|
||||||
/**
|
|
||||||
* 按照实例id查询任务
|
|
||||||
*
|
|
||||||
* @param instanceIdList 流程实例id
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
List<FlowTask> selectByInstIdList(List<Long> instanceIdList);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按照实例id查询任务
|
* 按照实例id查询任务
|
||||||
*
|
*
|
||||||
@ -183,6 +165,22 @@ public interface IFlwTaskService {
|
|||||||
*/
|
*/
|
||||||
List<FlowTask> selectByInstId(Long instanceId);
|
List<FlowTask> selectByInstId(Long instanceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按照实例id查询任务
|
||||||
|
*
|
||||||
|
* @param instanceIds 列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
List<FlowTask> selectByInstIds(List<Long> instanceIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断流程是否已结束(即该流程实例下是否还有未完成的任务)
|
||||||
|
*
|
||||||
|
* @param instanceId 流程实例ID
|
||||||
|
* @return true 表示任务已全部结束;false 表示仍有任务存在
|
||||||
|
*/
|
||||||
|
boolean isTaskEnd(Long instanceId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务操作
|
* 任务操作
|
||||||
*
|
*
|
||||||
@ -192,21 +190,13 @@ public interface IFlwTaskService {
|
|||||||
*/
|
*/
|
||||||
boolean taskOperation(TaskOperationBo bo, String taskOperation);
|
boolean taskOperation(TaskOperationBo bo, String taskOperation);
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取任务所有办理人
|
|
||||||
*
|
|
||||||
* @param taskIdList 任务id
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
Map<Long, List<UserDTO>> currentTaskAllUser(List<Long> taskIdList);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前任务的所有办理人
|
* 获取当前任务的所有办理人
|
||||||
*
|
*
|
||||||
* @param taskId 任务id
|
* @param taskIds 任务id
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
List<UserDTO> currentTaskAllUser(Long taskId);
|
List<UserDTO> currentTaskAllUser(List<Long> taskIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按照节点编码查询节点
|
* 按照节点编码查询节点
|
||||||
@ -217,6 +207,11 @@ public interface IFlwTaskService {
|
|||||||
*/
|
*/
|
||||||
FlowNode getByNodeCode(String nodeCode, Long definitionId);
|
FlowNode getByNodeCode(String nodeCode, Long definitionId);
|
||||||
|
|
||||||
|
/**
|
||||||
void copyRead(@PathVariable Long flowUserId);
|
* 催办任务
|
||||||
|
*
|
||||||
|
* @param bo 参数
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
boolean urgeTask(FlowUrgeTaskBo bo);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,6 +35,11 @@ public interface ITestLeaveService {
|
|||||||
*/
|
*/
|
||||||
TestLeaveVo insertByBo(TestLeaveBo bo);
|
TestLeaveVo insertByBo(TestLeaveBo bo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交请假并发起流程
|
||||||
|
*/
|
||||||
|
TestLeaveVo submitAndFlowStart(TestLeaveBo bo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改请假
|
* 修改请假
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package org.dromara.workflow.service.impl;
|
package org.dromara.workflow.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.lang.tree.Tree;
|
import cn.hutool.core.lang.tree.Tree;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
@ -8,14 +9,11 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.dromara.common.core.constant.SystemConstants;
|
import org.dromara.common.core.constant.SystemConstants;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.core.utils.MapstructUtils;
|
import org.dromara.common.core.utils.*;
|
||||||
import org.dromara.common.core.utils.ObjectUtils;
|
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
|
||||||
import org.dromara.common.core.utils.TreeBuildUtils;
|
|
||||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
|
||||||
import org.dromara.warm.flow.core.service.DefService;
|
import org.dromara.warm.flow.core.service.DefService;
|
||||||
import org.dromara.warm.flow.orm.entity.FlowDefinition;
|
import org.dromara.warm.flow.orm.entity.FlowDefinition;
|
||||||
|
import org.dromara.warm.flow.ui.service.CategoryService;
|
||||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
import org.dromara.workflow.common.constant.FlowConstant;
|
import org.dromara.workflow.common.constant.FlowConstant;
|
||||||
import org.dromara.workflow.domain.FlowCategory;
|
import org.dromara.workflow.domain.FlowCategory;
|
||||||
@ -26,6 +24,7 @@ import org.dromara.workflow.service.IFlwCategoryService;
|
|||||||
import org.springframework.cache.annotation.CacheEvict;
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -38,7 +37,7 @@ import java.util.List;
|
|||||||
@ConditionalOnEnable
|
@ConditionalOnEnable
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service
|
@Service
|
||||||
public class FlwCategoryServiceImpl implements IFlwCategoryService {
|
public class FlwCategoryServiceImpl implements IFlwCategoryService, CategoryService {
|
||||||
|
|
||||||
private final DefService defService;
|
private final DefService defService;
|
||||||
private final FlwCategoryMapper baseMapper;
|
private final FlwCategoryMapper baseMapper;
|
||||||
@ -97,32 +96,29 @@ public class FlwCategoryServiceImpl implements IFlwCategoryService {
|
|||||||
}
|
}
|
||||||
return TreeBuildUtils.buildMultiRoot(
|
return TreeBuildUtils.buildMultiRoot(
|
||||||
categoryList,
|
categoryList,
|
||||||
node -> String.valueOf(node.getCategoryId()),
|
node -> Convert.toStr(node.getCategoryId()),
|
||||||
node -> String.valueOf(node.getParentId()),
|
node -> Convert.toStr(node.getParentId()),
|
||||||
(node, treeNode) -> treeNode
|
(node, treeNode) -> treeNode
|
||||||
.setId(String.valueOf(node.getCategoryId()))
|
.setId(Convert.toStr(node.getCategoryId()))
|
||||||
.setParentId(String.valueOf(node.getParentId()))
|
.setParentId(Convert.toStr(node.getParentId()))
|
||||||
.setName(node.getCategoryName())
|
.setName(node.getCategoryName())
|
||||||
.setWeight(node.getOrderNum())
|
.setWeight(node.getOrderNum())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验流程分类是否有数据权限
|
* 工作流查询分类
|
||||||
*
|
*
|
||||||
* @param categoryId 流程分类ID
|
* @return 分类树结构列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void checkCategoryDataScope(Long categoryId) {
|
public List<org.dromara.warm.flow.core.dto.Tree> queryCategory() {
|
||||||
if (ObjectUtil.isNull(categoryId)) {
|
List<FlowCategoryVo> list = this.queryList(new FlowCategoryBo());
|
||||||
return;
|
return StreamUtils.toList(list, category -> new org.dromara.warm.flow.core.dto.Tree()
|
||||||
}
|
.setId(Convert.toStr(category.getCategoryId()))
|
||||||
if (LoginHelper.isSuperAdmin()) {
|
.setName(category.getCategoryName())
|
||||||
return;
|
.setParentId(Convert.toStr(category.getParentId()))
|
||||||
}
|
);
|
||||||
if (baseMapper.countCategoryById(categoryId) == 0) {
|
|
||||||
throw new ServiceException("没有权限访问流程分类数据!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,6 +183,9 @@ public class FlwCategoryServiceImpl implements IFlwCategoryService {
|
|||||||
@Override
|
@Override
|
||||||
public int insertByBo(FlowCategoryBo bo) {
|
public int insertByBo(FlowCategoryBo bo) {
|
||||||
FlowCategory info = baseMapper.selectById(bo.getParentId());
|
FlowCategory info = baseMapper.selectById(bo.getParentId());
|
||||||
|
if (ObjectUtil.isNull(info)) {
|
||||||
|
throw new ServiceException("父级流程分类不存在!");
|
||||||
|
}
|
||||||
FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class);
|
FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class);
|
||||||
category.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + category.getParentId());
|
category.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + category.getParentId());
|
||||||
return baseMapper.insert(category);
|
return baseMapper.insert(category);
|
||||||
@ -200,6 +199,7 @@ public class FlwCategoryServiceImpl implements IFlwCategoryService {
|
|||||||
*/
|
*/
|
||||||
@CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#bo.categoryId")
|
@CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#bo.categoryId")
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int updateByBo(FlowCategoryBo bo) {
|
public int updateByBo(FlowCategoryBo bo) {
|
||||||
FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class);
|
FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class);
|
||||||
FlowCategory oldCategory = baseMapper.selectById(category.getCategoryId());
|
FlowCategory oldCategory = baseMapper.selectById(category.getCategoryId());
|
||||||
@ -207,14 +207,14 @@ public class FlwCategoryServiceImpl implements IFlwCategoryService {
|
|||||||
throw new ServiceException("流程分类不存在,无法修改");
|
throw new ServiceException("流程分类不存在,无法修改");
|
||||||
}
|
}
|
||||||
if (!oldCategory.getParentId().equals(category.getParentId())) {
|
if (!oldCategory.getParentId().equals(category.getParentId())) {
|
||||||
// 如果是新父流程分类 则校验是否具有新父流程分类权限 避免越权
|
|
||||||
this.checkCategoryDataScope(category.getParentId());
|
|
||||||
FlowCategory newParentCategory = baseMapper.selectById(category.getParentId());
|
FlowCategory newParentCategory = baseMapper.selectById(category.getParentId());
|
||||||
if (ObjectUtil.isNotNull(newParentCategory)) {
|
if (ObjectUtil.isNotNull(newParentCategory)) {
|
||||||
String newAncestors = newParentCategory.getAncestors() + StringUtils.SEPARATOR + newParentCategory.getCategoryId();
|
String newAncestors = newParentCategory.getAncestors() + StringUtils.SEPARATOR + newParentCategory.getCategoryId();
|
||||||
String oldAncestors = oldCategory.getAncestors();
|
String oldAncestors = oldCategory.getAncestors();
|
||||||
category.setAncestors(newAncestors);
|
category.setAncestors(newAncestors);
|
||||||
updateCategoryChildren(category.getCategoryId(), newAncestors, oldAncestors);
|
updateCategoryChildren(category.getCategoryId(), newAncestors, oldAncestors);
|
||||||
|
} else {
|
||||||
|
throw new ServiceException("父级流程分类不存在!");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
category.setAncestors(oldCategory.getAncestors());
|
category.setAncestors(oldCategory.getAncestors());
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import org.dromara.common.core.service.DeptService;
|
|||||||
import org.dromara.common.core.service.DictService;
|
import org.dromara.common.core.service.DictService;
|
||||||
import org.dromara.common.core.service.UserService;
|
import org.dromara.common.core.service.UserService;
|
||||||
import org.dromara.common.core.utils.DateUtils;
|
import org.dromara.common.core.utils.DateUtils;
|
||||||
import org.dromara.common.core.utils.ServletUtils;
|
|
||||||
import org.dromara.common.core.utils.StreamUtils;
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.warm.flow.core.dto.DefJson;
|
import org.dromara.warm.flow.core.dto.DefJson;
|
||||||
@ -25,10 +24,15 @@ import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper;
|
|||||||
import org.dromara.warm.flow.ui.service.ChartExtService;
|
import org.dromara.warm.flow.ui.service.ChartExtService;
|
||||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
import org.dromara.workflow.common.constant.FlowConstant;
|
import org.dromara.workflow.common.constant.FlowConstant;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程图提示信息
|
* 流程图提示信息
|
||||||
@ -45,6 +49,8 @@ public class FlwChartExtServiceImpl implements ChartExtService {
|
|||||||
private final DeptService deptService;
|
private final DeptService deptService;
|
||||||
private final FlowHisTaskMapper flowHisTaskMapper;
|
private final FlowHisTaskMapper flowHisTaskMapper;
|
||||||
private final DictService dictService;
|
private final DictService dictService;
|
||||||
|
@Value("${warm-flow.node-tooltip:true}")
|
||||||
|
private boolean nodeTooltip;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置流程图提示信息
|
* 设置流程图提示信息
|
||||||
@ -53,12 +59,13 @@ public class FlwChartExtServiceImpl implements ChartExtService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void execute(DefJson defJson) {
|
public void execute(DefJson defJson) {
|
||||||
// 临时修复 后续版本将通过defjson获取流程实例ID
|
// 配置关闭,直接返回,不渲染悬浮窗
|
||||||
String[] parts = ServletUtils.getRequest().getRequestURI().split("/");
|
if (!nodeTooltip) {
|
||||||
Long instanceId = Convert.toLong(parts[parts.length - 1]);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 根据流程实例ID查询所有相关的历史任务列表
|
// 根据流程实例ID查询所有相关的历史任务列表
|
||||||
List<FlowHisTask> flowHisTasks = this.getHisTaskGroupedByNode(instanceId);
|
List<FlowHisTask> flowHisTasks = this.getHisTaskGroupedByNode(defJson.getInstance().getId());
|
||||||
if (CollUtil.isEmpty(flowHisTasks)) {
|
if (CollUtil.isEmpty(flowHisTasks)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -74,15 +81,26 @@ public class FlwChartExtServiceImpl implements ChartExtService {
|
|||||||
|
|
||||||
Map<String, String> dictType = dictService.getAllDictByDictType(FlowConstant.WF_TASK_STATUS);
|
Map<String, String> dictType = dictService.getAllDictByDictType(FlowConstant.WF_TASK_STATUS);
|
||||||
|
|
||||||
// 遍历流程定义中的每个节点,调用处理方法,将对应节点的任务列表及用户信息传入,生成扩展提示内容
|
|
||||||
for (NodeJson nodeJson : defJson.getNodeList()) {
|
for (NodeJson nodeJson : defJson.getNodeList()) {
|
||||||
// 获取当前节点对应的历史任务列表,如果没有则返回空列表避免空指针
|
|
||||||
List<FlowHisTask> taskList = groupedByNode.get(nodeJson.getNodeCode());
|
List<FlowHisTask> taskList = groupedByNode.get(nodeJson.getNodeCode());
|
||||||
if (CollUtil.isEmpty(taskList)) {
|
if (CollUtil.isEmpty(taskList)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 处理当前节点的扩展信息,包括构建审批人提示内容等
|
|
||||||
this.processNodeExtInfo(nodeJson, taskList, userMap, dictType);
|
// 按审批人分组去重,保留最新处理记录,最终转换成 List
|
||||||
|
List<FlowHisTask> latestPerApprover = taskList.stream()
|
||||||
|
.collect(Collectors.collectingAndThen(
|
||||||
|
Collectors.toMap(
|
||||||
|
FlowHisTask::getApprover,
|
||||||
|
Function.identity(),
|
||||||
|
(oldTask, newTask) -> newTask.getUpdateTime().after(oldTask.getUpdateTime()) ? newTask : oldTask,
|
||||||
|
LinkedHashMap::new
|
||||||
|
),
|
||||||
|
map -> new ArrayList<>(map.values())
|
||||||
|
));
|
||||||
|
|
||||||
|
// 处理当前节点的扩展信息
|
||||||
|
this.processNodeExtInfo(nodeJson, latestPerApprover, userMap, dictType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,6 +111,11 @@ public class FlwChartExtServiceImpl implements ChartExtService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initPromptContent(DefJson defJson) {
|
public void initPromptContent(DefJson defJson) {
|
||||||
|
// 配置关闭,直接返回,不渲染悬浮窗
|
||||||
|
if (!nodeTooltip) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
defJson.setTopText("流程名称: " + defJson.getFlowName());
|
defJson.setTopText("流程名称: " + defJson.getFlowName());
|
||||||
defJson.getNodeList().forEach(nodeJson -> {
|
defJson.getNodeList().forEach(nodeJson -> {
|
||||||
nodeJson.setPromptContent(
|
nodeJson.setPromptContent(
|
||||||
@ -128,7 +151,8 @@ public class FlwChartExtServiceImpl implements ChartExtService {
|
|||||||
"fontSize", "14px",
|
"fontSize", "14px",
|
||||||
"zIndex", "1000",
|
"zIndex", "1000",
|
||||||
"maxWidth", "500px",
|
"maxWidth", "500px",
|
||||||
"overflowY", "visible",
|
"maxHeight", "300px",
|
||||||
|
"overflowY", "auto",
|
||||||
"overflowX", "hidden",
|
"overflowX", "hidden",
|
||||||
"color", "#333",
|
"color", "#333",
|
||||||
"pointerEvents", "auto",
|
"pointerEvents", "auto",
|
||||||
@ -141,8 +165,10 @@ public class FlwChartExtServiceImpl implements ChartExtService {
|
|||||||
/**
|
/**
|
||||||
* 处理节点的扩展信息,构建用于流程图悬浮提示的内容
|
* 处理节点的扩展信息,构建用于流程图悬浮提示的内容
|
||||||
*
|
*
|
||||||
* @param nodeJson 当前节点对象
|
* @param nodeJson 当前流程节点对象,包含节点基础信息和提示内容容器
|
||||||
* @param taskList 当前节点对应的历史审批任务列表
|
* @param taskList 当前节点关联的历史审批任务列表,用于生成提示信息
|
||||||
|
* @param userMap 用户信息映射表,key 为用户ID,value 为用户DTO对象,用于获取审批人信息
|
||||||
|
* @param dictType 数据字典映射表,key 为字典项编码,value 为对应显示值,用于翻译审批状态等
|
||||||
*/
|
*/
|
||||||
private void processNodeExtInfo(NodeJson nodeJson, List<FlowHisTask> taskList, Map<Long, UserDTO> userMap, Map<String, String> dictType) {
|
private void processNodeExtInfo(NodeJson nodeJson, List<FlowHisTask> taskList, Map<Long, UserDTO> userMap, Map<String, String> dictType) {
|
||||||
|
|
||||||
@ -240,7 +266,7 @@ public class FlwChartExtServiceImpl implements ChartExtService {
|
|||||||
LambdaQueryWrapper<FlowHisTask> wrapper = Wrappers.lambdaQuery();
|
LambdaQueryWrapper<FlowHisTask> wrapper = Wrappers.lambdaQuery();
|
||||||
wrapper.eq(FlowHisTask::getInstanceId, instanceId)
|
wrapper.eq(FlowHisTask::getInstanceId, instanceId)
|
||||||
.eq(FlowHisTask::getNodeType, NodeType.BETWEEN.getKey())
|
.eq(FlowHisTask::getNodeType, NodeType.BETWEEN.getKey())
|
||||||
.orderByDesc(FlowHisTask::getCreateTime, FlowHisTask::getUpdateTime);
|
.orderByDesc(FlowHisTask::getUpdateTime);
|
||||||
return flowHisTaskMapper.selectList(wrapper);
|
return flowHisTaskMapper.selectList(wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,10 +35,7 @@ import org.dromara.workflow.service.IFlwTaskAssigneeService;
|
|||||||
import org.dromara.workflow.service.IFlwTaskService;
|
import org.dromara.workflow.service.IFlwTaskService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
@ -56,25 +53,6 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
|
|||||||
|
|
||||||
private final SseProperties properties;
|
private final SseProperties properties;
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建工作流用户
|
|
||||||
*
|
|
||||||
* @param permissionList 办理用户
|
|
||||||
* @return 用户
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<String> buildUser(List<String> permissionList) {
|
|
||||||
if (CollUtil.isEmpty(permissionList)) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
IFlwTaskAssigneeService taskAssigneeService = SpringUtils.getBean(IFlwTaskAssigneeService.class);
|
|
||||||
String processedBys = CollUtil.join(permissionList, StringUtils.SEPARATOR);
|
|
||||||
// 根据 processedBy 前缀判断处理人类型,分别获取用户列表
|
|
||||||
List<UserDTO> users = taskAssigneeService.fetchUsersByStorageIds(processedBys, null);
|
|
||||||
|
|
||||||
return StreamUtils.toList(users, userDTO -> String.valueOf(userDTO.getUserId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送消息
|
* 发送消息
|
||||||
@ -93,7 +71,7 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Task task : list) {
|
for (Task task : list) {
|
||||||
List<UserDTO> users = flwTaskService.currentTaskAllUser(task.getId());
|
List<UserDTO> users = flwTaskService.currentTaskAllUser(StreamUtils.toList(list, FlowTask::getId));
|
||||||
if (CollUtil.isNotEmpty(users)) {
|
if (CollUtil.isNotEmpty(users)) {
|
||||||
userList.addAll(users);
|
userList.addAll(users);
|
||||||
}
|
}
|
||||||
@ -194,6 +172,76 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
|
|||||||
SseMessageUtils.publishMessage(dto);
|
SseMessageUtils.publishMessage(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static final String DEFAULT_SUBJECT = "单据审批提醒";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据流程实例发送消息给当前处理人
|
||||||
|
*
|
||||||
|
* @param flowName 流程定义名称
|
||||||
|
* @param instId 流程实例ID
|
||||||
|
* @param messageType 消息类型列表
|
||||||
|
* @param message 消息内容,为空则使用默认消息
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String flowName, Long instId, List<String> messageType, String message) {
|
||||||
|
if (CollUtil.isEmpty(messageType)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IFlwTaskService flwTaskService = SpringUtils.getBean(IFlwTaskService.class);
|
||||||
|
List<FlowTask> list = flwTaskService.selectByInstId(instId);
|
||||||
|
if (CollUtil.isEmpty(list)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(message)) {
|
||||||
|
message = "有新的【" + flowName + "】单据已经提交至您,请您及时处理。";
|
||||||
|
}
|
||||||
|
List<UserDTO> userList = flwTaskService.currentTaskAllUser(StreamUtils.toList(list, FlowTask::getId));
|
||||||
|
if (CollUtil.isEmpty(userList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendMessage(messageType, message, DEFAULT_SUBJECT, userList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息给指定用户列表
|
||||||
|
*
|
||||||
|
* @param messageType 消息类型列表
|
||||||
|
* @param message 消息内容
|
||||||
|
* @param subject 邮件标题
|
||||||
|
* @param userList 接收用户列表
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void sendMessage(List<String> messageType, String message, String subject, List<UserDTO> userList) {
|
||||||
|
if (CollUtil.isEmpty(messageType) || CollUtil.isEmpty(userList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Long> userIds = new ArrayList<>(StreamUtils.toSet(userList, UserDTO::getUserId));
|
||||||
|
Set<String> emails = StreamUtils.toSet(userList, UserDTO::getEmail);
|
||||||
|
|
||||||
|
for (String code : messageType) {
|
||||||
|
MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code);
|
||||||
|
if (ObjectUtil.isEmpty(messageTypeEnum)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (messageTypeEnum) {
|
||||||
|
case SYSTEM_MESSAGE -> {
|
||||||
|
SseMessageDto dto = new SseMessageDto();
|
||||||
|
dto.setUserIds(userIds);
|
||||||
|
dto.setMessage(message);
|
||||||
|
SseMessageUtils.publishMessage(dto);
|
||||||
|
}
|
||||||
|
case EMAIL_MESSAGE -> MailUtils.sendText(emails, subject, message);
|
||||||
|
case SMS_MESSAGE -> {
|
||||||
|
//todo 短信发送
|
||||||
|
}
|
||||||
|
default -> throw new IllegalStateException("Unexpected value: " + messageTypeEnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 申请人节点编码
|
* 申请人节点编码
|
||||||
*
|
*
|
||||||
@ -202,8 +250,7 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String applyNodeCode(Long definitionId) {
|
public String applyNodeCode(Long definitionId) {
|
||||||
Node startNode = nodeService.getStartNode(definitionId);
|
List<Node> firstBetweenNode = FlowEngine.nodeService().getFirstBetweenNode(definitionId, new HashMap<>());
|
||||||
Node nextNode = nodeService.getNextNode(definitionId, startNode.getNodeCode(), null, SkipType.PASS.getKey());
|
return firstBetweenNode.get(0).getNodeCode();
|
||||||
return nextNode.getNodeCode();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,9 +30,7 @@ import org.dromara.warm.flow.orm.mapper.FlowNodeMapper;
|
|||||||
import org.dromara.warm.flow.orm.mapper.FlowSkipMapper;
|
import org.dromara.warm.flow.orm.mapper.FlowSkipMapper;
|
||||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
import org.dromara.workflow.common.constant.FlowConstant;
|
import org.dromara.workflow.common.constant.FlowConstant;
|
||||||
import org.dromara.workflow.common.enums.FlwDefinitionSuffixTemplateEnum;
|
|
||||||
import org.dromara.workflow.domain.FlowCategory;
|
import org.dromara.workflow.domain.FlowCategory;
|
||||||
import org.dromara.workflow.domain.bo.FlowDefinitionBo;
|
|
||||||
import org.dromara.workflow.domain.vo.FlowDefinitionVo;
|
import org.dromara.workflow.domain.vo.FlowDefinitionVo;
|
||||||
import org.dromara.workflow.mapper.FlwCategoryMapper;
|
import org.dromara.workflow.mapper.FlwCategoryMapper;
|
||||||
import org.dromara.workflow.service.IFlwCommonService;
|
import org.dromara.workflow.service.IFlwCommonService;
|
||||||
@ -71,13 +69,13 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
|
|||||||
/**
|
/**
|
||||||
* 查询流程定义列表
|
* 查询流程定义列表
|
||||||
*
|
*
|
||||||
* @param flowDefinitionBo 流程定义信息
|
* @param flowDefinition 流程定义信息
|
||||||
* @param pageQuery 分页
|
* @param pageQuery 分页
|
||||||
* @return 返回分页列表
|
* @return 返回分页列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TableDataInfo<FlowDefinitionVo> queryList(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery) {
|
public TableDataInfo<FlowDefinitionVo> queryList(FlowDefinition flowDefinition, PageQuery pageQuery) {
|
||||||
LambdaQueryWrapper<FlowDefinition> wrapper = buildQueryWrapper(flowDefinitionBo);
|
LambdaQueryWrapper<FlowDefinition> wrapper = buildQueryWrapper(flowDefinition);
|
||||||
wrapper.eq(FlowDefinition::getIsPublish, PublishStatus.PUBLISHED.getKey());
|
wrapper.eq(FlowDefinition::getIsPublish, PublishStatus.PUBLISHED.getKey());
|
||||||
Page<FlowDefinition> page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper);
|
Page<FlowDefinition> page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper);
|
||||||
List<FlowDefinitionVo> list = BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class);
|
List<FlowDefinitionVo> list = BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class);
|
||||||
@ -87,28 +85,27 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
|
|||||||
/**
|
/**
|
||||||
* 查询未发布的流程定义列表
|
* 查询未发布的流程定义列表
|
||||||
*
|
*
|
||||||
* @param flowDefinitionBo 流程定义信息
|
* @param flowDefinition 流程定义信息
|
||||||
* @param pageQuery 分页
|
* @param pageQuery 分页
|
||||||
* @return 返回分页列表
|
* @return 返回分页列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinitionBo flowDefinitionBo, PageQuery pageQuery) {
|
public TableDataInfo<FlowDefinitionVo> unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) {
|
||||||
LambdaQueryWrapper<FlowDefinition> wrapper = buildQueryWrapper(flowDefinitionBo);
|
LambdaQueryWrapper<FlowDefinition> wrapper = buildQueryWrapper(flowDefinition);
|
||||||
wrapper.in(FlowDefinition::getIsPublish, Arrays.asList(PublishStatus.UNPUBLISHED.getKey(), PublishStatus.EXPIRED.getKey()));
|
wrapper.in(FlowDefinition::getIsPublish, Arrays.asList(PublishStatus.UNPUBLISHED.getKey(), PublishStatus.EXPIRED.getKey()));
|
||||||
Page<FlowDefinition> page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper);
|
Page<FlowDefinition> page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper);
|
||||||
List<FlowDefinitionVo> list = BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class);
|
List<FlowDefinitionVo> list = BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class);
|
||||||
return new TableDataInfo<>(list, page.getTotal());
|
return new TableDataInfo<>(list, page.getTotal());
|
||||||
}
|
}
|
||||||
|
|
||||||
private LambdaQueryWrapper<FlowDefinition> buildQueryWrapper(FlowDefinitionBo flowDefinitionBo) {
|
private LambdaQueryWrapper<FlowDefinition> buildQueryWrapper(FlowDefinition flowDefinition) {
|
||||||
LambdaQueryWrapper<FlowDefinition> wrapper = Wrappers.lambdaQuery();
|
LambdaQueryWrapper<FlowDefinition> wrapper = Wrappers.lambdaQuery();
|
||||||
wrapper.like(StringUtils.isNotBlank(flowDefinitionBo.getFlowCode()), FlowDefinition::getFlowCode, flowDefinitionBo.getFlowCode());
|
wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowCode()), FlowDefinition::getFlowCode, flowDefinition.getFlowCode());
|
||||||
wrapper.like(StringUtils.isNotBlank(flowDefinitionBo.getFlowName()), FlowDefinition::getFlowName, flowDefinitionBo.getFlowName());
|
wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowName()), FlowDefinition::getFlowName, flowDefinition.getFlowName());
|
||||||
if (StringUtils.isNotBlank(flowDefinitionBo.getCategory())) {
|
if (StringUtils.isNotBlank(flowDefinition.getCategory())) {
|
||||||
List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowDefinitionBo.getCategory()));
|
List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowDefinition.getCategory()));
|
||||||
wrapper.in(FlowDefinition::getCategory, StreamUtils.toList(categoryIds, Convert::toStr));
|
wrapper.in(FlowDefinition::getCategory, StreamUtils.toList(categoryIds, Convert::toStr));
|
||||||
}
|
}
|
||||||
wrapper.likeRight(FlowDefinition::getFlowCode, flowDefinitionBo.getProjectId() + "_");
|
|
||||||
wrapper.orderByDesc(FlowDefinition::getCreateTime);
|
wrapper.orderByDesc(FlowDefinition::getCreateTime);
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
@ -124,14 +121,14 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
|
|||||||
List<FlowNode> flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper<FlowNode>().eq(FlowNode::getDefinitionId, id));
|
List<FlowNode> flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper<FlowNode>().eq(FlowNode::getDefinitionId, id));
|
||||||
List<String> errorMsg = new ArrayList<>();
|
List<String> errorMsg = new ArrayList<>();
|
||||||
if (CollUtil.isNotEmpty(flowNodes)) {
|
if (CollUtil.isNotEmpty(flowNodes)) {
|
||||||
|
String applyNodeCode = flwCommonService.applyNodeCode(id);
|
||||||
for (FlowNode flowNode : flowNodes) {
|
for (FlowNode flowNode : flowNodes) {
|
||||||
String applyNodeCode = flwCommonService.applyNodeCode(id);
|
|
||||||
if (StringUtils.isBlank(flowNode.getPermissionFlag()) && !applyNodeCode.equals(flowNode.getNodeCode()) && NodeType.BETWEEN.getKey().equals(flowNode.getNodeType())) {
|
if (StringUtils.isBlank(flowNode.getPermissionFlag()) && !applyNodeCode.equals(flowNode.getNodeCode()) && NodeType.BETWEEN.getKey().equals(flowNode.getNodeType())) {
|
||||||
errorMsg.add(flowNode.getNodeName());
|
errorMsg.add(flowNode.getNodeName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (CollUtil.isNotEmpty(errorMsg)) {
|
if (CollUtil.isNotEmpty(errorMsg)) {
|
||||||
throw new ServiceException("节点【" + StringUtils.join(errorMsg, ",") + "】未配置办理人!");
|
throw new ServiceException("节点【{}】未配置办理人!", StringUtils.joinComma(errorMsg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return defService.publish(id);
|
return defService.publish(id);
|
||||||
@ -191,7 +188,7 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
|
|||||||
if (CollUtil.isNotEmpty(flowDefinitions)) {
|
if (CollUtil.isNotEmpty(flowDefinitions)) {
|
||||||
String join = StreamUtils.join(flowDefinitions, FlowDefinition::getFlowCode);
|
String join = StreamUtils.join(flowDefinitions, FlowDefinition::getFlowCode);
|
||||||
log.info("流程定义【{}】已被使用不可被删除!", join);
|
log.info("流程定义【{}】已被使用不可被删除!", join);
|
||||||
throw new ServiceException("流程定义【" + join + "】已被使用不可被删除!");
|
throw new ServiceException("流程定义【{}】已被使用不可被删除!", join);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -203,27 +200,6 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增流程定义
|
|
||||||
*
|
|
||||||
* @param projectId 项目id
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void insertDefByProjectId(Long projectId) {
|
|
||||||
FlwDefinitionSuffixTemplateEnum[] suffixList = FlwDefinitionSuffixTemplateEnum.values();
|
|
||||||
for (FlwDefinitionSuffixTemplateEnum suffix : suffixList) {
|
|
||||||
FlowDefinition definition = new FlowDefinition();
|
|
||||||
definition.setCategory("100");
|
|
||||||
definition.setFlowCode(projectId + suffix.getCode());
|
|
||||||
definition.setFlowName(suffix.getName());
|
|
||||||
definition.setFormPath(suffix.getPath());
|
|
||||||
boolean result = defService.checkAndSave(definition);
|
|
||||||
if (!result) {
|
|
||||||
log.info("流程定义[{}-{}]失败!", suffix.getName(), projectId + suffix.getCode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增租户流程定义
|
* 新增租户流程定义
|
||||||
*
|
*
|
||||||
@ -237,9 +213,11 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FlowCategory flowCategory = flwCategoryMapper.selectOne(new LambdaQueryWrapper<FlowCategory>()
|
FlowCategory flowCategory = flwCategoryMapper.selectOne(new LambdaQueryWrapper<FlowCategory>()
|
||||||
.eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID).eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID));
|
.eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID)
|
||||||
|
.eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID));
|
||||||
flowCategory.setCategoryId(null);
|
flowCategory.setCategoryId(null);
|
||||||
flowCategory.setTenantId(tenantId);
|
flowCategory.setTenantId(tenantId);
|
||||||
|
flowCategory.setCreateDept(null);
|
||||||
flowCategory.setCreateBy(null);
|
flowCategory.setCreateBy(null);
|
||||||
flowCategory.setCreateTime(null);
|
flowCategory.setCreateTime(null);
|
||||||
flowCategory.setUpdateBy(null);
|
flowCategory.setUpdateBy(null);
|
||||||
@ -253,7 +231,7 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
|
|||||||
flowDefinition.setId(null);
|
flowDefinition.setId(null);
|
||||||
flowDefinition.setTenantId(tenantId);
|
flowDefinition.setTenantId(tenantId);
|
||||||
flowDefinition.setIsPublish(0);
|
flowDefinition.setIsPublish(0);
|
||||||
flowDefinition.setCategory(String.valueOf(flowCategory.getCategoryId()));
|
flowDefinition.setCategory(Convert.toStr(flowCategory.getCategoryId()));
|
||||||
int insert = flowDefinitionMapper.insert(flowDefinition);
|
int insert = flowDefinitionMapper.insert(flowDefinition);
|
||||||
if (insert <= 0) {
|
if (insert <= 0) {
|
||||||
log.info("同步流程定义【{}】失败!", definition.getFlowCode());
|
log.info("同步流程定义【{}】失败!", definition.getFlowCode());
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.common.core.domain.dto.UserDTO;
|
|
||||||
import org.dromara.common.core.enums.BusinessStatusEnum;
|
import org.dromara.common.core.enums.BusinessStatusEnum;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.core.utils.StreamUtils;
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
@ -19,11 +18,13 @@ import org.dromara.common.core.utils.StringUtils;
|
|||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
|
import org.dromara.warm.flow.core.FlowEngine;
|
||||||
import org.dromara.warm.flow.core.constant.ExceptionCons;
|
import org.dromara.warm.flow.core.constant.ExceptionCons;
|
||||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||||
import org.dromara.warm.flow.core.entity.Definition;
|
import org.dromara.warm.flow.core.entity.Definition;
|
||||||
import org.dromara.warm.flow.core.entity.Instance;
|
import org.dromara.warm.flow.core.entity.Instance;
|
||||||
import org.dromara.warm.flow.core.entity.Task;
|
import org.dromara.warm.flow.core.entity.Task;
|
||||||
|
import org.dromara.warm.flow.core.entity.User;
|
||||||
import org.dromara.warm.flow.core.enums.NodeType;
|
import org.dromara.warm.flow.core.enums.NodeType;
|
||||||
import org.dromara.warm.flow.core.service.DefService;
|
import org.dromara.warm.flow.core.service.DefService;
|
||||||
import org.dromara.warm.flow.core.service.InsService;
|
import org.dromara.warm.flow.core.service.InsService;
|
||||||
@ -40,6 +41,7 @@ import org.dromara.workflow.common.enums.TaskStatusEnum;
|
|||||||
import org.dromara.workflow.domain.bo.FlowCancelBo;
|
import org.dromara.workflow.domain.bo.FlowCancelBo;
|
||||||
import org.dromara.workflow.domain.bo.FlowInstanceBo;
|
import org.dromara.workflow.domain.bo.FlowInstanceBo;
|
||||||
import org.dromara.workflow.domain.bo.FlowInvalidBo;
|
import org.dromara.workflow.domain.bo.FlowInvalidBo;
|
||||||
|
import org.dromara.workflow.domain.bo.FlowVariableBo;
|
||||||
import org.dromara.workflow.domain.vo.FlowHisTaskVo;
|
import org.dromara.workflow.domain.vo.FlowHisTaskVo;
|
||||||
import org.dromara.workflow.domain.vo.FlowInstanceVo;
|
import org.dromara.workflow.domain.vo.FlowInstanceVo;
|
||||||
import org.dromara.workflow.handler.FlowProcessEventHandler;
|
import org.dromara.workflow.handler.FlowProcessEventHandler;
|
||||||
@ -51,7 +53,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程实例 服务层实现
|
* 流程实例 服务层实现
|
||||||
@ -111,7 +113,7 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public FlowInstanceVo queryByBusinessId(Long businessId) {
|
public FlowInstanceVo queryByBusinessId(Long businessId) {
|
||||||
FlowInstance instance = this.selectInstByBusinessId(String.valueOf(businessId));
|
FlowInstance instance = this.selectInstByBusinessId(Convert.toStr(businessId));
|
||||||
FlowInstanceVo instanceVo = BeanUtil.toBean(instance, FlowInstanceVo.class);
|
FlowInstanceVo instanceVo = BeanUtil.toBean(instance, FlowInstanceVo.class);
|
||||||
Definition definition = defService.getById(instanceVo.getDefinitionId());
|
Definition definition = defService.getById(instanceVo.getDefinitionId());
|
||||||
instanceVo.setFlowName(definition.getFlowName());
|
instanceVo.setFlowName(definition.getFlowName());
|
||||||
@ -206,22 +208,77 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 获取定义信息
|
// 获取定义信息
|
||||||
Map<Long, Definition> definitionMap = defService.getByIds(
|
Map<Long, Definition> definitionMap = StreamUtils.toMap(
|
||||||
StreamUtils.toList(instances, Instance::getDefinitionId)
|
defService.getByIds(StreamUtils.toList(instances, Instance::getDefinitionId)),
|
||||||
).stream().collect(Collectors.toMap(Definition::getId, definition -> definition));
|
Definition::getId,
|
||||||
|
Function.identity()
|
||||||
|
);
|
||||||
|
|
||||||
// 逐一触发删除事件
|
try {
|
||||||
instances.forEach(instance -> {
|
// 逐一触发删除事件
|
||||||
Definition definition = definitionMap.get(instance.getDefinitionId());
|
instances.forEach(instance -> {
|
||||||
if (ObjectUtil.isNull(definition)) {
|
Definition definition = definitionMap.get(instance.getDefinitionId());
|
||||||
log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId());
|
if (ObjectUtil.isNull(definition)) {
|
||||||
return;
|
log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId());
|
||||||
|
});
|
||||||
|
// 删除实例
|
||||||
|
boolean remove = insService.remove(instanceIds);
|
||||||
|
if (!remove) {
|
||||||
|
log.warn("删除流程实例失败!");
|
||||||
|
throw new ServiceException("删除流程实例失败");
|
||||||
}
|
}
|
||||||
flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId());
|
} catch (Exception e) {
|
||||||
});
|
log.warn("操作失败!{}", e.getMessage());
|
||||||
|
throw new ServiceException(e.getMessage());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// 删除实例
|
/**
|
||||||
return insService.remove(instanceIds);
|
* 按照实例id删除已完成的流程实例
|
||||||
|
*
|
||||||
|
* @param instanceIds 实例id
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean deleteHisByInstanceIds(List<Long> instanceIds) {
|
||||||
|
// 获取实例信息
|
||||||
|
List<Instance> instances = insService.getByIds(instanceIds);
|
||||||
|
if (CollUtil.isEmpty(instances)) {
|
||||||
|
log.warn("未找到对应的流程实例信息,无法执行删除操作。");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 获取定义信息
|
||||||
|
Map<Long, Definition> definitionMap = StreamUtils.toMap(
|
||||||
|
defService.getByIds(StreamUtils.toList(instances, Instance::getDefinitionId)),
|
||||||
|
Definition::getId,
|
||||||
|
Function.identity()
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
// 逐一触发删除事件
|
||||||
|
instances.forEach(instance -> {
|
||||||
|
Definition definition = definitionMap.get(instance.getDefinitionId());
|
||||||
|
if (ObjectUtil.isNull(definition)) {
|
||||||
|
log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId());
|
||||||
|
});
|
||||||
|
List<FlowTask> flowTaskList = flwTaskService.selectByInstIds(instanceIds);
|
||||||
|
if (CollUtil.isNotEmpty(flowTaskList)) {
|
||||||
|
FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTaskList, FlowTask::getId));
|
||||||
|
}
|
||||||
|
FlowEngine.taskService().deleteByInsIds(instanceIds);
|
||||||
|
FlowEngine.hisTaskService().deleteByInsIds(instanceIds);
|
||||||
|
FlowEngine.insService().removeByIds(instanceIds);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("操作失败!{}", e.getMessage());
|
||||||
|
throw new ServiceException(e.getMessage());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -267,6 +324,7 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
|||||||
@Override
|
@Override
|
||||||
public TableDataInfo<FlowInstanceVo> selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery) {
|
public TableDataInfo<FlowInstanceVo> selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery) {
|
||||||
QueryWrapper<FlowInstanceBo> queryWrapper = buildQueryWrapper(instanceBo);
|
QueryWrapper<FlowInstanceBo> queryWrapper = buildQueryWrapper(instanceBo);
|
||||||
|
queryWrapper.eq("fi.create_by", LoginHelper.getUserIdStr());
|
||||||
if (!"0".equals(instanceBo.getProjectId())){
|
if (!"0".equals(instanceBo.getProjectId())){
|
||||||
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>()
|
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>()
|
||||||
.select(FlowDefinition::getId)
|
.select(FlowDefinition::getId)
|
||||||
@ -282,7 +340,6 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
|||||||
}
|
}
|
||||||
queryWrapper.in("fi.definition_id",definitionIds);
|
queryWrapper.in("fi.definition_id",definitionIds);
|
||||||
}
|
}
|
||||||
queryWrapper.eq("fi.create_by", LoginHelper.getUserIdStr());
|
|
||||||
Page<FlowInstanceVo> page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper);
|
Page<FlowInstanceVo> page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper);
|
||||||
return TableDataInfo.build(page);
|
return TableDataInfo.build(page);
|
||||||
}
|
}
|
||||||
@ -299,37 +356,47 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
|||||||
throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE);
|
throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE);
|
||||||
}
|
}
|
||||||
Long instanceId = flowInstance.getId();
|
Long instanceId = flowInstance.getId();
|
||||||
//运行中的任务
|
|
||||||
List<FlowHisTaskVo> list = new ArrayList<>();
|
// 先组装待审批任务(运行中的任务)
|
||||||
List<FlowTask> flowTaskList = flwTaskService.selectByInstId(instanceId);
|
List<FlowHisTaskVo> runningTaskVos = new ArrayList<>();
|
||||||
if (CollUtil.isNotEmpty(flowTaskList)) {
|
List<FlowTask> runningTasks = flwTaskService.selectByInstId(instanceId);
|
||||||
List<FlowHisTaskVo> flowHisTaskVos = BeanUtil.copyToList(flowTaskList, FlowHisTaskVo.class);
|
if (CollUtil.isNotEmpty(runningTasks)) {
|
||||||
for (FlowHisTaskVo flowHisTaskVo : flowHisTaskVos) {
|
runningTaskVos = BeanUtil.copyToList(runningTasks, FlowHisTaskVo.class);
|
||||||
flowHisTaskVo.setFlowStatus(TaskStatusEnum.WAITING.getStatus());
|
|
||||||
flowHisTaskVo.setUpdateTime(null);
|
List<User> associatedUsers = FlowEngine.userService()
|
||||||
flowHisTaskVo.setRunDuration(null);
|
.getByAssociateds(StreamUtils.toList(runningTasks, FlowTask::getId));
|
||||||
List<UserDTO> allUser = flwTaskService.currentTaskAllUser(flowHisTaskVo.getId());
|
Map<Long, List<User>> taskUserMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated);
|
||||||
if (CollUtil.isNotEmpty(allUser)) {
|
|
||||||
String join = StreamUtils.join(allUser, e -> String.valueOf(e.getUserId()));
|
for (FlowHisTaskVo vo : runningTaskVos) {
|
||||||
flowHisTaskVo.setApprover(join);
|
vo.setFlowStatus(TaskStatusEnum.WAITING.getStatus());
|
||||||
}
|
vo.setUpdateTime(null);
|
||||||
if (BusinessStatusEnum.isDraftOrCancelOrBack(flowInstance.getFlowStatus())) {
|
vo.setRunDuration(null);
|
||||||
flowHisTaskVo.setApprover(LoginHelper.getUserIdStr());
|
|
||||||
flowHisTaskVo.setApproveName(LoginHelper.getLoginUser().getNickname());
|
List<User> users = taskUserMap.get(vo.getId());
|
||||||
|
if (CollUtil.isNotEmpty(users)) {
|
||||||
|
vo.setApprover(StreamUtils.join(users, User::getProcessedBy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
list.addAll(flowHisTaskVos);
|
|
||||||
}
|
}
|
||||||
//历史任务
|
|
||||||
LambdaQueryWrapper<FlowHisTask> wrapper = Wrappers.lambdaQuery();
|
// 再组装历史任务(已处理任务)
|
||||||
wrapper.eq(FlowHisTask::getInstanceId, instanceId)
|
List<FlowHisTaskVo> hisTaskVos = new ArrayList<>();
|
||||||
.eq(FlowHisTask::getNodeType, NodeType.BETWEEN.getKey())
|
List<FlowHisTask> hisTasks = flowHisTaskMapper.selectList(
|
||||||
.orderByDesc(FlowHisTask::getCreateTime, FlowHisTask::getUpdateTime);
|
new LambdaQueryWrapper<FlowHisTask>()
|
||||||
List<FlowHisTask> flowHisTasks = flowHisTaskMapper.selectList(wrapper);
|
.eq(FlowHisTask::getInstanceId, instanceId)
|
||||||
if (CollUtil.isNotEmpty(flowHisTasks)) {
|
.eq(FlowHisTask::getNodeType, NodeType.BETWEEN.getKey())
|
||||||
list.addAll(BeanUtil.copyToList(flowHisTasks, FlowHisTaskVo.class));
|
.orderByDesc(FlowHisTask::getUpdateTime)
|
||||||
|
);
|
||||||
|
if (CollUtil.isNotEmpty(hisTasks)) {
|
||||||
|
hisTaskVos = BeanUtil.copyToList(hisTasks, FlowHisTaskVo.class);
|
||||||
}
|
}
|
||||||
return Map.of("list", list, "instanceId", instanceId);
|
|
||||||
|
// 结果列表,待审批任务在前,历史任务在后
|
||||||
|
List<FlowHisTaskVo> combinedList = new ArrayList<>();
|
||||||
|
combinedList.addAll(runningTaskVos);
|
||||||
|
combinedList.addAll(hisTaskVos);
|
||||||
|
|
||||||
|
return Map.of("list", combinedList, "instanceId", instanceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -361,6 +428,34 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
|||||||
return Map.of("variableList", variableList, "variable", flowInstance.getVariable());
|
return Map.of("variableList", variableList, "variable", flowInstance.getVariable());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置流程变量
|
||||||
|
*
|
||||||
|
* @param bo 参数
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateVariable(FlowVariableBo bo) {
|
||||||
|
FlowInstance flowInstance = flowInstanceMapper.selectById(bo.getInstanceId());
|
||||||
|
if (flowInstance == null) {
|
||||||
|
throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Map<String, Object> variableMap = new HashMap<>(Optional.ofNullable(flowInstance.getVariableMap()).orElse(Collections.emptyMap()));
|
||||||
|
if (!variableMap.containsKey(bo.getKey())) {
|
||||||
|
log.error("变量不存在: {}", bo.getKey());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
variableMap.put(bo.getKey(), bo.getValue());
|
||||||
|
flowInstance.setVariable(FlowEngine.jsonConvert.objToStr(variableMap));
|
||||||
|
flowInstanceMapper.updateById(flowInstance);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("设置流程变量失败: {}", e.getMessage(), e);
|
||||||
|
throw new ServiceException(e.getMessage());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置流程变量
|
* 设置流程变量
|
||||||
*
|
*
|
||||||
@ -395,31 +490,6 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 按任务id查询实例
|
|
||||||
*
|
|
||||||
* @param taskIdList 任务id
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<FlowInstance> selectByTaskIdList(List<Long> taskIdList) {
|
|
||||||
if (CollUtil.isEmpty(taskIdList)) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
Set<Long> instanceIds = new HashSet<>();
|
|
||||||
List<FlowTask> flowTaskList = flwTaskService.selectByIdList(taskIdList);
|
|
||||||
for (FlowTask flowTask : flowTaskList) {
|
|
||||||
instanceIds.add(flowTask.getInstanceId());
|
|
||||||
}
|
|
||||||
List<FlowHisTask> flowHisTaskList = flwTaskService.selectHisTaskByIdList(taskIdList);
|
|
||||||
for (FlowHisTask flowHisTask : flowHisTaskList) {
|
|
||||||
instanceIds.add(flowHisTask.getInstanceId());
|
|
||||||
}
|
|
||||||
if (!instanceIds.isEmpty()) {
|
|
||||||
return this.selectInstListByIdList(new ArrayList<>(instanceIds));
|
|
||||||
}
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 作废流程
|
* 作废流程
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,26 +1,31 @@
|
|||||||
package org.dromara.workflow.service.impl;
|
package org.dromara.workflow.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.common.core.domain.dto.DictTypeDTO;
|
import org.dromara.common.core.domain.dto.DictTypeDTO;
|
||||||
import org.dromara.common.core.service.DictService;
|
import org.dromara.common.core.service.DictService;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.json.utils.JsonUtils;
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
|
import org.dromara.warm.flow.core.FlowEngine;
|
||||||
|
import org.dromara.warm.flow.core.utils.CollUtil;
|
||||||
|
import org.dromara.warm.flow.core.utils.ExpressionUtil;
|
||||||
import org.dromara.warm.flow.ui.service.NodeExtService;
|
import org.dromara.warm.flow.ui.service.NodeExtService;
|
||||||
import org.dromara.warm.flow.ui.vo.NodeExt;
|
import org.dromara.warm.flow.ui.vo.NodeExt;
|
||||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
import org.dromara.workflow.common.enums.ButtonPermissionEnum;
|
import org.dromara.workflow.common.enums.ButtonPermissionEnum;
|
||||||
|
import org.dromara.workflow.common.enums.CopySettingEnum;
|
||||||
import org.dromara.workflow.common.enums.NodeExtEnum;
|
import org.dromara.workflow.common.enums.NodeExtEnum;
|
||||||
|
import org.dromara.workflow.common.enums.VariablesEnum;
|
||||||
import org.dromara.workflow.domain.vo.ButtonPermissionVo;
|
import org.dromara.workflow.domain.vo.ButtonPermissionVo;
|
||||||
|
import org.dromara.workflow.domain.vo.NodeExtVo;
|
||||||
import org.dromara.workflow.service.IFlwNodeExtService;
|
import org.dromara.workflow.service.IFlwNodeExtService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程设计器-节点扩展属性
|
* 流程设计器-节点扩展属性
|
||||||
@ -36,14 +41,35 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
|||||||
/**
|
/**
|
||||||
* 存储不同 dictType 对应的配置信息
|
* 存储不同 dictType 对应的配置信息
|
||||||
*/
|
*/
|
||||||
private static final Map<String, ButtonPermission> CHILD_NODE_MAP = new HashMap<>();
|
private static final Map<String, Map<String, Object>> CHILD_NODE_MAP;
|
||||||
|
|
||||||
record ButtonPermission(String label, Integer type, Boolean must, Boolean multiple) {
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
CHILD_NODE_MAP.put(ButtonPermissionEnum.class.getSimpleName(),
|
CHILD_NODE_MAP = Map.of(
|
||||||
new ButtonPermission("权限按钮", 4, false, true));
|
CopySettingEnum.class.getSimpleName(),
|
||||||
|
Map.of(
|
||||||
|
"label", "抄送对象",
|
||||||
|
"type", 5,
|
||||||
|
"must", false,
|
||||||
|
"multiple", false,
|
||||||
|
"desc", "设置该节点的抄送办理人"
|
||||||
|
),
|
||||||
|
VariablesEnum.class.getSimpleName(),
|
||||||
|
Map.of(
|
||||||
|
"label", "自定义参数",
|
||||||
|
"type", 2,
|
||||||
|
"must", false,
|
||||||
|
"multiple", false,
|
||||||
|
"desc", "节点执行时可设置自定义参数,多个参数以逗号分隔,如:key1=value1,key2=value2"
|
||||||
|
),
|
||||||
|
ButtonPermissionEnum.class.getSimpleName(),
|
||||||
|
Map.of(
|
||||||
|
"label", "权限按钮",
|
||||||
|
"type", 4,
|
||||||
|
"must", false,
|
||||||
|
"multiple", true,
|
||||||
|
"desc", "控制该节点的按钮权限"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final DictService dictService;
|
private final DictService dictService;
|
||||||
@ -56,6 +82,9 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
|||||||
@Override
|
@Override
|
||||||
public List<NodeExt> getNodeExt() {
|
public List<NodeExt> getNodeExt() {
|
||||||
List<NodeExt> nodeExtList = new ArrayList<>();
|
List<NodeExt> nodeExtList = new ArrayList<>();
|
||||||
|
// 构建基础设置页面
|
||||||
|
nodeExtList.add(buildNodeExt("wf_basic_tab", "基础设置", 1,
|
||||||
|
List.of(CopySettingEnum.class, VariablesEnum.class)));
|
||||||
// 构建按钮权限页面
|
// 构建按钮权限页面
|
||||||
nodeExtList.add(buildNodeExt("wf_button_tab", "权限", 2,
|
nodeExtList.add(buildNodeExt("wf_button_tab", "权限", 2,
|
||||||
List.of(ButtonPermissionEnum.class)));
|
List.of(ButtonPermissionEnum.class)));
|
||||||
@ -105,9 +134,20 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String simpleName = enumClass.getSimpleName();
|
String simpleName = enumClass.getSimpleName();
|
||||||
NodeExt.ChildNode childNode = buildChildNodeMap(simpleName);
|
NodeExt.ChildNode childNode = new NodeExt.ChildNode();
|
||||||
|
Map<String, Object> map = CHILD_NODE_MAP.get(simpleName);
|
||||||
// 编码,此json中唯
|
// 编码,此json中唯
|
||||||
childNode.setCode(simpleName);
|
childNode.setCode(simpleName);
|
||||||
|
// label名称
|
||||||
|
childNode.setLabel(Convert.toStr(map.get("label")));
|
||||||
|
// 1:输入框 2:文本域 3:下拉框 4:选择框 5:用户选择器
|
||||||
|
childNode.setType(Convert.toInt(map.get("type"), 1));
|
||||||
|
// 是否必填
|
||||||
|
childNode.setMust(Convert.toBool(map.get("must"), false));
|
||||||
|
// 是否多选
|
||||||
|
childNode.setMultiple(Convert.toBool(map.get("multiple"), true));
|
||||||
|
// 描述
|
||||||
|
childNode.setDesc(Convert.toStr(map.get("desc"), null));
|
||||||
// 字典,下拉框和复选框时用到
|
// 字典,下拉框和复选框时用到
|
||||||
childNode.setDict(Arrays.stream(enumClass.getEnumConstants())
|
childNode.setDict(Arrays.stream(enumClass.getEnumConstants())
|
||||||
.map(NodeExtEnum.class::cast)
|
.map(NodeExtEnum.class::cast)
|
||||||
@ -128,12 +168,18 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
|||||||
if (ObjectUtil.isNull(dictTypeDTO)) {
|
if (ObjectUtil.isNull(dictTypeDTO)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
NodeExt.ChildNode childNode = buildChildNodeMap(dictType);
|
NodeExt.ChildNode childNode = new NodeExt.ChildNode();
|
||||||
// 编码,此json中唯一
|
// 编码,此json中唯一
|
||||||
childNode.setCode(dictType);
|
childNode.setCode(dictType);
|
||||||
// label名称
|
// label名称
|
||||||
childNode.setLabel(dictTypeDTO.getDictName());
|
childNode.setLabel(dictTypeDTO.getDictName());
|
||||||
// 描述
|
// 1:输入框 2:文本域 3:下拉框 4:选择框 5:用户选择器
|
||||||
|
childNode.setType(3);
|
||||||
|
// 是否必填
|
||||||
|
childNode.setMust(false);
|
||||||
|
// 是否多选
|
||||||
|
childNode.setMultiple(true);
|
||||||
|
// 描述 (可根据描述参数解析更多配置,如type,must,multiple等)
|
||||||
childNode.setDesc(dictTypeDTO.getRemark());
|
childNode.setDesc(dictTypeDTO.getRemark());
|
||||||
// 字典,下拉框和复选框时用到
|
// 字典,下拉框和复选框时用到
|
||||||
childNode.setDict(dictService.getDictData(dictType)
|
childNode.setDict(dictService.getDictData(dictType)
|
||||||
@ -144,100 +190,165 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 CHILD_NODE_MAP 中的配置信息,构建一个基本的 ChildNode 对象
|
* 解析扩展属性 JSON 并构建 Node 扩展属性对象
|
||||||
* 该方法用于设置 ChildNode 的常规属性,例如 label、type、是否必填、是否多选等
|
* <p>
|
||||||
|
* 根据传入的 JSON 字符串,将扩展属性分为三类:
|
||||||
|
* 1. ButtonPermissionEnum:解析为按钮权限列表,标记每个按钮是否勾选
|
||||||
|
* 2. CopySettingEnum:解析为抄送对象 ID 集合
|
||||||
|
* 3. VariablesEnum:解析为自定义参数 Map
|
||||||
*
|
*
|
||||||
* @param key CHILD_NODE_MAP 的 key
|
* <p>示例 JSON:
|
||||||
* @return 返回构建好的 ChildNode 对象
|
* [
|
||||||
*/
|
* {"code": "ButtonPermissionEnum", "value": "back,termination"},
|
||||||
private NodeExt.ChildNode buildChildNodeMap(String key) {
|
* {"code": "CopySettingEnum", "value": "1,3,4,#{@spelRuleComponent.selectDeptLeaderById(#deptId", "#roleId)}"},
|
||||||
NodeExt.ChildNode childNode = new NodeExt.ChildNode();
|
* {"code": "VariablesEnum", "value": "key1=value1,key2=value2"}
|
||||||
ButtonPermission bp = CHILD_NODE_MAP.get(key);
|
* ]
|
||||||
if (bp == null) {
|
|
||||||
childNode.setType(1);
|
|
||||||
childNode.setMust(false);
|
|
||||||
childNode.setMultiple(true);
|
|
||||||
return childNode;
|
|
||||||
}
|
|
||||||
// label名称
|
|
||||||
childNode.setLabel(bp.label());
|
|
||||||
// 1:输入框 2:输入框 3:下拉框 4:选择框
|
|
||||||
childNode.setType(bp.type());
|
|
||||||
// 是否必填
|
|
||||||
childNode.setMust(bp.must());
|
|
||||||
// 是否多选
|
|
||||||
childNode.setMultiple(bp.multiple());
|
|
||||||
return childNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从扩展属性构建按钮权限列表:根据 ext 中记录的权限值,标记每个按钮是否勾选
|
|
||||||
*
|
*
|
||||||
* @param ext 扩展属性 JSON 字符串
|
* @param ext 扩展属性 JSON 字符串
|
||||||
* @return 按钮权限 VO 列表
|
* @param variable 流程变量
|
||||||
|
* @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<ButtonPermissionVo> buildButtonPermissionsFromExt(String ext) {
|
public NodeExtVo parseNodeExt(String ext, Map<String, Object> variable) {
|
||||||
// 解析 ext 为 Map<code, Set<value>>,用于标记权限
|
NodeExtVo nodeExtVo = new NodeExtVo();
|
||||||
Map<String, Set<String>> permissionMap = JsonUtils.parseArray(ext, ButtonPermissionVo.class)
|
|
||||||
.stream()
|
|
||||||
.collect(Collectors.toMap(
|
|
||||||
ButtonPermissionVo::getCode,
|
|
||||||
item -> StringUtils.splitList(item.getValue()).stream()
|
|
||||||
.map(String::trim)
|
|
||||||
.filter(StrUtil::isNotBlank)
|
|
||||||
.collect(Collectors.toSet()),
|
|
||||||
(a, b) -> b,
|
|
||||||
HashMap::new
|
|
||||||
));
|
|
||||||
|
|
||||||
// 构建按钮权限列表,标记哪些按钮在 permissionMap 中出现(表示已勾选)
|
// 解析 JSON 为 Dict 列表
|
||||||
return buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class));
|
List<Dict> nodeExtMap = JsonUtils.parseArrayMap(ext);
|
||||||
|
if (ObjectUtil.isEmpty(nodeExtMap)) {
|
||||||
|
return nodeExtVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Dict nodeExt : nodeExtMap) {
|
||||||
|
String code = nodeExt.getStr("code");
|
||||||
|
String value = nodeExt.getStr("value");
|
||||||
|
|
||||||
|
if (ButtonPermissionEnum.class.getSimpleName().equals(code)) {
|
||||||
|
// 解析按钮权限
|
||||||
|
// 将 value 拆分为 Set<String>,便于精确匹配
|
||||||
|
Set<String> buttonSet = StringUtils.str2Set(value, StringUtils.SEPARATOR);
|
||||||
|
|
||||||
|
// 获取按钮字典配置
|
||||||
|
NodeExt.ChildNode childNode = buildChildNode(ButtonPermissionEnum.class);
|
||||||
|
|
||||||
|
// 构建 ButtonPermissionVo 列表
|
||||||
|
List<ButtonPermissionVo> buttonList = Optional.ofNullable(childNode)
|
||||||
|
.map(NodeExt.ChildNode::getDict)
|
||||||
|
.orElse(List.of())
|
||||||
|
.stream()
|
||||||
|
.map(dict -> new ButtonPermissionVo(dict.getValue(), buttonSet.contains(dict.getValue())))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
nodeExtVo.setButtonPermissions(buttonList);
|
||||||
|
|
||||||
|
} else if (CopySettingEnum.class.getSimpleName().equals(code)) {
|
||||||
|
List<String> permissions = spelSmartSplit(value).stream()
|
||||||
|
.map(s -> {
|
||||||
|
List<String> result = ExpressionUtil.evalVariable(s, variable);
|
||||||
|
if (CollUtil.isNotEmpty(result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return Collections.singletonList(s);
|
||||||
|
}).filter(Objects::nonNull)
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
List<String> copySettings = FlowEngine.permissionHandler().convertPermissions(permissions);
|
||||||
|
// 解析抄送对象 ID 集合
|
||||||
|
nodeExtVo.setCopySettings(new HashSet<>(copySettings));
|
||||||
|
|
||||||
|
} else if (VariablesEnum.class.getSimpleName().equals(code)) {
|
||||||
|
// 解析自定义参数
|
||||||
|
// 将 key=value 字符串拆分为 Map
|
||||||
|
Map<String, String> variables = Arrays.stream(StringUtils.split(value, StringUtils.SEPARATOR))
|
||||||
|
.map(s -> StringUtils.split(s, "="))
|
||||||
|
.filter(arr -> arr.length == 2)
|
||||||
|
.collect(Collectors.toMap(arr -> arr[0], arr -> arr[1]));
|
||||||
|
|
||||||
|
nodeExtVo.setVariables(variables);
|
||||||
|
} else {
|
||||||
|
// 未知扩展类型,记录日志
|
||||||
|
log.warn("未知扩展类型:code={}, value={}", code, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeExtVo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将权限映射与按钮权限来源(枚举类或字典类型)进行匹配,生成权限视图列表
|
* 按逗号分割字符串,但保留 #{...} 表达式和字符串常量中的逗号
|
||||||
* <p>
|
|
||||||
* 使用说明:
|
|
||||||
* - sources 支持传入多个来源类型,支持 NodeExtEnum 枚举类 或 字典类型字符串(dictType)
|
|
||||||
* - 若需要扩展更多按钮权限,只需在 sources 中新增对应的枚举类或字典类型
|
|
||||||
* <p>
|
|
||||||
* 示例:
|
|
||||||
* buildPermissionsFromSources(permissionMap, List.of(ButtonPermissionEnum.class, "custom_button_dict"));
|
|
||||||
*
|
|
||||||
* @param permissionMap 权限映射
|
|
||||||
* @param sources 枚举类或字典类型列表
|
|
||||||
* @return 按钮权限视图对象列表
|
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked cast")
|
private static List<String> spelSmartSplit(String str) {
|
||||||
private List<ButtonPermissionVo> buildPermissionsFromSources(Map<String, Set<String>> permissionMap, List<Object> sources) {
|
List<String> result = new ArrayList<>();
|
||||||
return sources.stream()
|
if (str == null || str.trim().isEmpty()) {
|
||||||
.flatMap(source -> {
|
return result;
|
||||||
if (source instanceof Class<?> clazz && NodeExtEnum.class.isAssignableFrom(clazz)) {
|
}
|
||||||
Set<String> selectedSet = permissionMap.getOrDefault(clazz.getSimpleName(), Collections.emptySet());
|
|
||||||
return extractDictItems(this.buildChildNode((Class<? extends NodeExtEnum>) clazz), selectedSet).stream();
|
StringBuilder token = new StringBuilder();
|
||||||
} else if (source instanceof String dictType) {
|
// #{...} 的嵌套深度
|
||||||
Set<String> selectedSet = permissionMap.getOrDefault(dictType, Collections.emptySet());
|
int depth = 0;
|
||||||
return extractDictItems(this.buildChildNode(dictType), selectedSet).stream();
|
// 是否在字符串常量中(" 或 ')
|
||||||
|
boolean inString = false;
|
||||||
|
// 当前字符串引号类型
|
||||||
|
char stringQuote = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < str.length(); i++) {
|
||||||
|
char c = str.charAt(i);
|
||||||
|
|
||||||
|
// 检测进入 SpEL 表达式 #{...}
|
||||||
|
if (!inString && c == '#' && depth == 0 && checkNext(str, i, '{')) {
|
||||||
|
depth++;
|
||||||
|
token.append("#{");
|
||||||
|
// 跳过 {
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在表达式中遇到 { 或 } 改变嵌套深度
|
||||||
|
if (!inString && depth > 0) {
|
||||||
|
if (c == '{') {
|
||||||
|
depth++;
|
||||||
|
} else if (c == '}') {
|
||||||
|
depth--;
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
token.append(c);
|
||||||
}).toList();
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测字符串开始/结束
|
||||||
|
if (depth > 0 && (c == '"' || c == '\'')) {
|
||||||
|
if (!inString) {
|
||||||
|
inString = true;
|
||||||
|
stringQuote = c;
|
||||||
|
} else if (stringQuote == c) {
|
||||||
|
inString = false;
|
||||||
|
}
|
||||||
|
token.append(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 外层逗号才分割
|
||||||
|
if (c == ',' && depth == 0 && !inString) {
|
||||||
|
String part = token.toString().trim();
|
||||||
|
if (!part.isEmpty()) {
|
||||||
|
result.add(part);
|
||||||
|
}
|
||||||
|
token.setLength(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
token.append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加最后一个
|
||||||
|
String part = token.toString().trim();
|
||||||
|
if (!part.isEmpty()) {
|
||||||
|
result.add(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static boolean checkNext(String str, int index, char expected) {
|
||||||
* 从节点子项中提取字典项,并构建按钮权限视图对象列表
|
return index + 1 < str.length() && str.charAt(index + 1) == expected;
|
||||||
*
|
|
||||||
* @param childNode 子节点
|
|
||||||
* @param selectedSet 已选中的值集
|
|
||||||
* @return 按钮权限视图对象列表
|
|
||||||
*/
|
|
||||||
private List<ButtonPermissionVo> extractDictItems(NodeExt.ChildNode childNode, Set<String> selectedSet) {
|
|
||||||
return Optional.ofNullable(childNode)
|
|
||||||
.map(NodeExt.ChildNode::getDict)
|
|
||||||
.orElse(List.of())
|
|
||||||
.stream()
|
|
||||||
.map(dict -> new ButtonPermissionVo(dict.getValue(), selectedSet.contains(dict.getValue())))
|
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,190 @@
|
|||||||
|
package org.dromara.workflow.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.core.constant.SystemConstants;
|
||||||
|
import org.dromara.common.core.domain.dto.TaskAssigneeDTO;
|
||||||
|
import org.dromara.common.core.domain.model.TaskAssigneeBody;
|
||||||
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
|
import org.dromara.workflow.domain.FlowSpel;
|
||||||
|
import org.dromara.workflow.domain.bo.FlowSpelBo;
|
||||||
|
import org.dromara.workflow.domain.vo.FlowSpelVo;
|
||||||
|
import org.dromara.workflow.mapper.FlwSpelMapper;
|
||||||
|
import org.dromara.workflow.service.IFlwSpelService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程spel达式定义Service业务层处理
|
||||||
|
*
|
||||||
|
* @author Michelle.Chung
|
||||||
|
* @date 2025-07-04
|
||||||
|
*/
|
||||||
|
@ConditionalOnEnable
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service
|
||||||
|
public class FlwSpelServiceImpl implements IFlwSpelService {
|
||||||
|
|
||||||
|
private final FlwSpelMapper baseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询流程spel达式定义
|
||||||
|
*
|
||||||
|
* @param id 主键
|
||||||
|
* @return 流程spel达式定义
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FlowSpelVo queryById(Long id){
|
||||||
|
return baseMapper.selectVoById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询流程spel达式定义列表
|
||||||
|
*
|
||||||
|
* @param bo 查询条件
|
||||||
|
* @param pageQuery 分页参数
|
||||||
|
* @return 流程spel达式定义分页列表
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TableDataInfo<FlowSpelVo> queryPageList(FlowSpelBo bo, PageQuery pageQuery) {
|
||||||
|
LambdaQueryWrapper<FlowSpel> lqw = buildQueryWrapper(bo);
|
||||||
|
Page<FlowSpelVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||||
|
return TableDataInfo.build(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询符合条件的流程spel达式定义列表
|
||||||
|
*
|
||||||
|
* @param bo 查询条件
|
||||||
|
* @return 流程spel达式定义列表
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<FlowSpelVo> queryList(FlowSpelBo bo) {
|
||||||
|
LambdaQueryWrapper<FlowSpel> lqw = buildQueryWrapper(bo);
|
||||||
|
return baseMapper.selectVoList(lqw);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LambdaQueryWrapper<FlowSpel> buildQueryWrapper(FlowSpelBo bo) {
|
||||||
|
Map<String, Object> params = bo.getParams();
|
||||||
|
LambdaQueryWrapper<FlowSpel> lqw = Wrappers.lambdaQuery();
|
||||||
|
lqw.orderByAsc(FlowSpel::getId);
|
||||||
|
lqw.like(StringUtils.isNotBlank(bo.getComponentName()), FlowSpel::getComponentName, bo.getComponentName());
|
||||||
|
lqw.like(StringUtils.isNotBlank(bo.getMethodName()), FlowSpel::getMethodName, bo.getMethodName());
|
||||||
|
lqw.eq(StringUtils.isNotBlank(bo.getMethodParams()), FlowSpel::getMethodParams, bo.getMethodParams());
|
||||||
|
lqw.eq(StringUtils.isNotBlank(bo.getViewSpel()), FlowSpel::getViewSpel, bo.getViewSpel());
|
||||||
|
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), FlowSpel::getStatus, bo.getStatus());
|
||||||
|
lqw.like(StringUtils.isNotBlank(bo.getRemark()), FlowSpel::getRemark, bo.getRemark());
|
||||||
|
return lqw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增流程spel达式定义
|
||||||
|
*
|
||||||
|
* @param bo 流程spel达式定义
|
||||||
|
* @return 是否新增成功
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Boolean insertByBo(FlowSpelBo bo) {
|
||||||
|
FlowSpel add = MapstructUtils.convert(bo, FlowSpel.class);
|
||||||
|
validEntityBeforeSave(add);
|
||||||
|
boolean flag = baseMapper.insert(add) > 0;
|
||||||
|
if (flag) {
|
||||||
|
bo.setId(add.getId());
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改流程spel达式定义
|
||||||
|
*
|
||||||
|
* @param bo 流程spel达式定义
|
||||||
|
* @return 是否修改成功
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Boolean updateByBo(FlowSpelBo bo) {
|
||||||
|
FlowSpel update = MapstructUtils.convert(bo, FlowSpel.class);
|
||||||
|
validEntityBeforeSave(update);
|
||||||
|
return baseMapper.updateById(update) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存前的数据校验
|
||||||
|
*/
|
||||||
|
private void validEntityBeforeSave(FlowSpel entity){
|
||||||
|
//TODO 做一些数据校验,如唯一约束
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验并批量删除流程spel达式定义信息
|
||||||
|
*
|
||||||
|
* @param ids 待删除的主键集合
|
||||||
|
* @param isValid 是否进行有效性校验
|
||||||
|
* @return 是否删除成功
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||||
|
if(isValid){
|
||||||
|
//TODO 做一些业务上的校验,判断是否需要校验
|
||||||
|
}
|
||||||
|
return baseMapper.deleteByIds(ids) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询spel并返回任务指派的列表,支持分页
|
||||||
|
*
|
||||||
|
* @param taskQuery 查询条件
|
||||||
|
* @return 办理人
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TaskAssigneeDTO selectSpelByTaskAssigneeList(TaskAssigneeBody taskQuery) {
|
||||||
|
PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum());
|
||||||
|
FlowSpelBo bo = new FlowSpelBo();
|
||||||
|
bo.setViewSpel(taskQuery.getHandlerCode());
|
||||||
|
bo.setRemark(taskQuery.getHandlerName());
|
||||||
|
bo.setStatus(SystemConstants.NORMAL);
|
||||||
|
Map<String, Object> params = bo.getParams();
|
||||||
|
params.put("beginTime", taskQuery.getBeginTime());
|
||||||
|
params.put("endTime", taskQuery.getEndTime());
|
||||||
|
TableDataInfo<FlowSpelVo> page = this.queryPageList(bo, pageQuery);
|
||||||
|
// 使用封装的字段映射方法进行转换
|
||||||
|
List<TaskAssigneeDTO.TaskHandler> handlers = TaskAssigneeDTO.convertToHandlerList(page.getRows(),
|
||||||
|
FlowSpelVo::getViewSpel, item -> "", FlowSpelVo::getRemark, item -> "null", FlowSpelVo::getCreateTime);
|
||||||
|
return new TaskAssigneeDTO(page.getTotal(), handlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据视图 SpEL 表达式列表,查询对应的备注信息
|
||||||
|
*
|
||||||
|
* @param viewSpels SpEL 表达式列表
|
||||||
|
* @return 映射表:key 为 SpEL 表达式,value 为对应备注;若为空则返回空 Map
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Map<String, String> selectRemarksBySpels(List<String> viewSpels) {
|
||||||
|
if (CollUtil.isEmpty(viewSpels)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
List<FlowSpel> list = baseMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<FlowSpel>()
|
||||||
|
.select(FlowSpel::getViewSpel, FlowSpel::getRemark)
|
||||||
|
.in(FlowSpel::getViewSpel, viewSpels)
|
||||||
|
);
|
||||||
|
return StreamUtils.toMap(list, FlowSpel::getViewSpel, x ->
|
||||||
|
StringUtils.isEmpty(x.getRemark()) ? "" : x.getRemark()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.lang.Pair;
|
import cn.hutool.core.lang.Pair;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -12,10 +13,9 @@ import org.dromara.common.core.domain.dto.TaskAssigneeDTO;
|
|||||||
import org.dromara.common.core.domain.dto.UserDTO;
|
import org.dromara.common.core.domain.dto.UserDTO;
|
||||||
import org.dromara.common.core.domain.model.TaskAssigneeBody;
|
import org.dromara.common.core.domain.model.TaskAssigneeBody;
|
||||||
import org.dromara.common.core.enums.FormatsType;
|
import org.dromara.common.core.enums.FormatsType;
|
||||||
import org.dromara.common.core.service.DeptService;
|
import org.dromara.common.core.service.*;
|
||||||
import org.dromara.common.core.service.TaskAssigneeService;
|
|
||||||
import org.dromara.common.core.service.UserService;
|
|
||||||
import org.dromara.common.core.utils.DateUtils;
|
import org.dromara.common.core.utils.DateUtils;
|
||||||
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.warm.flow.ui.dto.HandlerFunDto;
|
import org.dromara.warm.flow.ui.dto.HandlerFunDto;
|
||||||
import org.dromara.warm.flow.ui.dto.HandlerQuery;
|
import org.dromara.warm.flow.ui.dto.HandlerQuery;
|
||||||
@ -25,10 +25,12 @@ import org.dromara.warm.flow.ui.vo.HandlerFeedBackVo;
|
|||||||
import org.dromara.warm.flow.ui.vo.HandlerSelectVo;
|
import org.dromara.warm.flow.ui.vo.HandlerSelectVo;
|
||||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
import org.dromara.workflow.common.enums.TaskAssigneeEnum;
|
import org.dromara.workflow.common.enums.TaskAssigneeEnum;
|
||||||
|
import org.dromara.workflow.service.IFlwSpelService;
|
||||||
import org.dromara.workflow.service.IFlwTaskAssigneeService;
|
import org.dromara.workflow.service.IFlwTaskAssigneeService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程设计器-获取办理人权限设置列表
|
* 流程设计器-获取办理人权限设置列表
|
||||||
@ -45,6 +47,9 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
|
|||||||
private final TaskAssigneeService taskAssigneeService;
|
private final TaskAssigneeService taskAssigneeService;
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
private final DeptService deptService;
|
private final DeptService deptService;
|
||||||
|
private final RoleService roleService;
|
||||||
|
private final PostService postService;
|
||||||
|
private final IFlwSpelService spelService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取办理人权限设置列表tabs页签
|
* 获取办理人权限设置列表tabs页签
|
||||||
@ -88,10 +93,10 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
// 解析并归类 ID,同时记录原始顺序和对应解析结果
|
// 解析并归类 ID,同时记录原始顺序和对应解析结果
|
||||||
Map<TaskAssigneeEnum, List<Long>> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class);
|
Map<TaskAssigneeEnum, List<String>> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class);
|
||||||
Map<String, Pair<TaskAssigneeEnum, Long>> parsedMap = new LinkedHashMap<>();
|
Map<String, Pair<TaskAssigneeEnum, String>> parsedMap = new LinkedHashMap<>();
|
||||||
for (String storageId : storageIds) {
|
for (String storageId : storageIds) {
|
||||||
Pair<TaskAssigneeEnum, Long> parsed = this.parseStorageId(storageId);
|
Pair<TaskAssigneeEnum, String> parsed = this.parseStorageId(storageId);
|
||||||
parsedMap.put(storageId, parsed);
|
parsedMap.put(storageId, parsed);
|
||||||
if (parsed != null) {
|
if (parsed != null) {
|
||||||
typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue());
|
typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue());
|
||||||
@ -99,14 +104,13 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 查询所有类型对应的 ID 名称映射
|
// 查询所有类型对应的 ID 名称映射
|
||||||
Map<TaskAssigneeEnum, Map<Long, String>> nameMap = new EnumMap<>(TaskAssigneeEnum.class);
|
Map<TaskAssigneeEnum, Map<String, String>> nameMap = new EnumMap<>(TaskAssigneeEnum.class);
|
||||||
typeIdMap.forEach((type, ids) -> nameMap.put(type, this.getNamesByType(type, ids)));
|
typeIdMap.forEach((type, ids) -> nameMap.put(type, this.getNamesByType(type, ids)));
|
||||||
|
|
||||||
// 组装返回结果,保持原始顺序
|
// 组装返回结果,保持原始顺序
|
||||||
return parsedMap.entrySet().stream()
|
return parsedMap.entrySet().stream()
|
||||||
.map(entry -> {
|
.map(entry -> {
|
||||||
String storageId = entry.getKey();
|
String storageId = entry.getKey();
|
||||||
Pair<TaskAssigneeEnum, Long> parsed = entry.getValue();
|
Pair<TaskAssigneeEnum, String> parsed = entry.getValue();
|
||||||
String handlerName = (parsed == null) ? null
|
String handlerName = (parsed == null) ? null
|
||||||
: nameMap.getOrDefault(parsed.getKey(), Collections.emptyMap())
|
: nameMap.getOrDefault(parsed.getKey(), Collections.emptyMap())
|
||||||
.get(parsed.getValue());
|
.get(parsed.getValue());
|
||||||
@ -123,6 +127,7 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
|
|||||||
case ROLE -> taskAssigneeService.selectRolesByTaskAssigneeList(taskQuery);
|
case ROLE -> taskAssigneeService.selectRolesByTaskAssigneeList(taskQuery);
|
||||||
case DEPT -> taskAssigneeService.selectDeptsByTaskAssigneeList(taskQuery);
|
case DEPT -> taskAssigneeService.selectDeptsByTaskAssigneeList(taskQuery);
|
||||||
case POST -> taskAssigneeService.selectPostsByTaskAssigneeList(taskQuery);
|
case POST -> taskAssigneeService.selectPostsByTaskAssigneeList(taskQuery);
|
||||||
|
case SPEL -> spelService.selectSpelByTaskAssigneeList(taskQuery);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,20 +135,37 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
|
|||||||
* 根据任务办理类型获取部门数据
|
* 根据任务办理类型获取部门数据
|
||||||
*/
|
*/
|
||||||
private List<DeptDTO> fetchDeptData(TaskAssigneeEnum type) {
|
private List<DeptDTO> fetchDeptData(TaskAssigneeEnum type) {
|
||||||
if (type == TaskAssigneeEnum.USER || type == TaskAssigneeEnum.DEPT || type == TaskAssigneeEnum.POST) {
|
if (type.needsDeptService()) {
|
||||||
return deptService.selectDeptsByList();
|
return deptService.selectDeptsByList();
|
||||||
}
|
}
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取权限分组名称
|
||||||
|
*
|
||||||
|
* @param type 任务分配人枚举
|
||||||
|
* @param groupName 权限分组
|
||||||
|
* @return 权限分组名称
|
||||||
|
*/
|
||||||
|
private String getGroupName(TaskAssigneeEnum type, String groupName) {
|
||||||
|
if (StringUtils.isEmpty(groupName)) {
|
||||||
|
return DEFAULT_GROUP_NAME;
|
||||||
|
}
|
||||||
|
if (type.needsDeptService()) {
|
||||||
|
return deptService.selectDeptNameByIds(groupName);
|
||||||
|
}
|
||||||
|
return DEFAULT_GROUP_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建部门树状结构
|
* 构建部门树状结构
|
||||||
*/
|
*/
|
||||||
private TreeFunDto<DeptDTO> buildDeptTree(List<DeptDTO> depts) {
|
private TreeFunDto<DeptDTO> buildDeptTree(List<DeptDTO> depts) {
|
||||||
return new TreeFunDto<>(depts)
|
return new TreeFunDto<>(depts)
|
||||||
.setId(dept -> String.valueOf(dept.getDeptId()))
|
.setId(dept -> Convert.toStr(dept.getDeptId()))
|
||||||
.setName(DeptDTO::getDeptName)
|
.setName(DeptDTO::getDeptName)
|
||||||
.setParentId(dept -> String.valueOf(dept.getParentId()));
|
.setParentId(dept -> Convert.toStr(dept.getParentId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -154,10 +176,7 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
|
|||||||
.setStorageId(assignee -> type.getCode() + assignee.getStorageId())
|
.setStorageId(assignee -> type.getCode() + assignee.getStorageId())
|
||||||
.setHandlerCode(assignee -> StringUtils.blankToDefault(assignee.getHandlerCode(), "无"))
|
.setHandlerCode(assignee -> StringUtils.blankToDefault(assignee.getHandlerCode(), "无"))
|
||||||
.setHandlerName(assignee -> StringUtils.blankToDefault(assignee.getHandlerName(), "无"))
|
.setHandlerName(assignee -> StringUtils.blankToDefault(assignee.getHandlerName(), "无"))
|
||||||
.setGroupName(assignee -> StringUtils.defaultIfBlank(
|
.setGroupName(assignee -> this.getGroupName(type, assignee.getGroupName()))
|
||||||
Optional.ofNullable(assignee.getGroupName())
|
|
||||||
.map(deptService::selectDeptNameByIds)
|
|
||||||
.orElse(DEFAULT_GROUP_NAME), DEFAULT_GROUP_NAME))
|
|
||||||
.setCreateTime(assignee -> DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, assignee.getCreateTime()));
|
.setCreateTime(assignee -> DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, assignee.getCreateTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,9 +193,9 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
|
|||||||
if (StringUtils.isEmpty(storageIds)) {
|
if (StringUtils.isEmpty(storageIds)) {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
Map<TaskAssigneeEnum, List<Long>> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class);
|
Map<TaskAssigneeEnum, List<String>> typeIdMap = new EnumMap<>(TaskAssigneeEnum.class);
|
||||||
for (String storageId : storageIds.split(StringUtils.SEPARATOR)) {
|
for (String storageId : storageIds.split(StringUtils.SEPARATOR)) {
|
||||||
Pair<TaskAssigneeEnum, Long> parsed = this.parseStorageId(storageId);
|
Pair<TaskAssigneeEnum, String> parsed = this.parseStorageId(storageId);
|
||||||
if (parsed != null) {
|
if (parsed != null) {
|
||||||
typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue());
|
typeIdMap.computeIfAbsent(parsed.getKey(), k -> new ArrayList<>()).add(parsed.getValue());
|
||||||
}
|
}
|
||||||
@ -197,12 +216,17 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
|
|||||||
* 如果类型为部门(DEPT),则通过部门ID列表查询;
|
* 如果类型为部门(DEPT),则通过部门ID列表查询;
|
||||||
* 如果类型为岗位(POST)或无法识别的类型,则返回空列表
|
* 如果类型为岗位(POST)或无法识别的类型,则返回空列表
|
||||||
*/
|
*/
|
||||||
private List<UserDTO> getUsersByType(TaskAssigneeEnum type, List<Long> ids,Long projectId) {
|
private List<UserDTO> getUsersByType(TaskAssigneeEnum type, List<String> ids,Long projectId) {
|
||||||
|
if (type == TaskAssigneeEnum.SPEL) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
List<Long> longIds = StreamUtils.toList(ids, Convert::toLong);
|
||||||
return switch (type) {
|
return switch (type) {
|
||||||
case USER -> userService.selectListByIds(ids);
|
case USER -> userService.selectListByIds(longIds);
|
||||||
case ROLE -> userService.selectUsersByRoleIds(ids,projectId);
|
case ROLE -> userService.selectUsersByRoleIds(longIds,projectId);
|
||||||
case DEPT -> userService.selectUsersByDeptIds(ids);
|
case DEPT -> userService.selectUsersByDeptIds(longIds);
|
||||||
case POST -> userService.selectUsersByPostIds(ids);
|
case POST -> userService.selectUsersByPostIds(longIds);
|
||||||
|
default -> new ArrayList<>();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,13 +237,28 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
|
|||||||
* @param ids ID 列表(如用户ID、角色ID等)
|
* @param ids ID 列表(如用户ID、角色ID等)
|
||||||
* @return 返回 Map,其中 key 为 ID,value 为对应的名称
|
* @return 返回 Map,其中 key 为 ID,value 为对应的名称
|
||||||
*/
|
*/
|
||||||
private Map<Long, String> getNamesByType(TaskAssigneeEnum type, List<Long> ids) {
|
private Map<String, String> getNamesByType(TaskAssigneeEnum type, List<String> ids) {
|
||||||
return switch (type) {
|
if (type == TaskAssigneeEnum.SPEL) {
|
||||||
case USER -> userService.selectUserNamesByIds(ids);
|
return spelService.selectRemarksBySpels(ids);
|
||||||
case ROLE -> userService.selectRoleNamesByIds(ids);
|
}
|
||||||
case DEPT -> userService.selectDeptNamesByIds(ids);
|
|
||||||
case POST -> userService.selectPostNamesByIds(ids);
|
List<Long> longIds = StreamUtils.toList(ids, Convert::toLong);
|
||||||
|
Map<Long, String> rawMap = switch (type) {
|
||||||
|
case USER -> userService.selectUserNamesByIds(longIds);
|
||||||
|
case ROLE -> userService.selectRoleNamesByIds(longIds);
|
||||||
|
case DEPT -> userService.selectDeptNamesByIds(longIds);
|
||||||
|
case POST -> userService.selectPostNamesByIds(longIds);
|
||||||
|
default -> Collections.emptyMap();
|
||||||
};
|
};
|
||||||
|
if (MapUtil.isEmpty(rawMap)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
return rawMap.entrySet()
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
e -> Convert.toStr(e.getKey()),
|
||||||
|
Map.Entry::getValue
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -228,22 +267,20 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
|
|||||||
* @param storageId 例如 "user:123" 或 "456"
|
* @param storageId 例如 "user:123" 或 "456"
|
||||||
* @return Pair(TaskAssigneeEnum, Long),如果格式非法返回 null
|
* @return Pair(TaskAssigneeEnum, Long),如果格式非法返回 null
|
||||||
*/
|
*/
|
||||||
private Pair<TaskAssigneeEnum, Long> parseStorageId(String storageId) {
|
private Pair<TaskAssigneeEnum, String> parseStorageId(String storageId) {
|
||||||
if (StringUtils.isBlank(storageId)) {
|
if (StringUtils.isBlank(storageId)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// 跳过以 $ 或 # 开头的字符串
|
if (TaskAssigneeEnum.isSpelExpression(storageId)) {
|
||||||
if (StringUtils.startsWith(storageId, "$") || StringUtils.startsWith(storageId, "#")) {
|
return Pair.of(TaskAssigneeEnum.SPEL, storageId);
|
||||||
log.debug("跳过 storageId 解析,检测到内置变量表达式:{}", storageId);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
String[] parts = storageId.split(StrUtil.COLON, 2);
|
String[] parts = storageId.split(StrUtil.COLON, 2);
|
||||||
if (parts.length < 2) {
|
if (parts.length < 2) {
|
||||||
return Pair.of(TaskAssigneeEnum.USER, Convert.toLong(parts[0]));
|
return Pair.of(TaskAssigneeEnum.USER, parts[0]);
|
||||||
} else {
|
} else {
|
||||||
TaskAssigneeEnum type = TaskAssigneeEnum.fromCode(parts[0] + StrUtil.COLON);
|
TaskAssigneeEnum type = TaskAssigneeEnum.fromCode(parts[0] + StrUtil.COLON);
|
||||||
return Pair.of(type, Convert.toLong(parts[1]));
|
return Pair.of(type, parts[1]);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("解析 storageId 失败,格式非法:{},错误信息:{}", storageId, e.getMessage());
|
log.warn("解析 storageId 失败,格式非法:{},错误信息:{}", storageId, e.getMessage());
|
||||||
|
|||||||
@ -3,8 +3,8 @@ package org.dromara.workflow.service.impl;
|
|||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
|
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
|
||||||
@ -22,17 +22,16 @@ import org.dromara.common.core.utils.StringUtils;
|
|||||||
import org.dromara.common.core.utils.ValidatorUtils;
|
import org.dromara.common.core.utils.ValidatorUtils;
|
||||||
import org.dromara.common.core.validate.AddGroup;
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
import org.dromara.common.core.validate.EditGroup;
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
import org.dromara.common.sse.dto.SeeMessageContentDto;
|
|
||||||
import org.dromara.common.sse.dto.SseMessageDto;
|
|
||||||
import org.dromara.common.sse.utils.SseMessageUtils;
|
|
||||||
import org.dromara.warm.flow.core.FlowEngine;
|
import org.dromara.warm.flow.core.FlowEngine;
|
||||||
import org.dromara.warm.flow.core.dto.FlowParams;
|
import org.dromara.warm.flow.core.dto.FlowParams;
|
||||||
import org.dromara.warm.flow.core.entity.*;
|
import org.dromara.warm.flow.core.entity.*;
|
||||||
import org.dromara.warm.flow.core.enums.NodeType;
|
import org.dromara.warm.flow.core.enums.NodeType;
|
||||||
import org.dromara.warm.flow.core.enums.SkipType;
|
import org.dromara.warm.flow.core.enums.SkipType;
|
||||||
|
import org.dromara.warm.flow.core.enums.UserType;
|
||||||
import org.dromara.warm.flow.core.service.*;
|
import org.dromara.warm.flow.core.service.*;
|
||||||
import org.dromara.warm.flow.core.utils.ExpressionUtil;
|
import org.dromara.warm.flow.core.utils.ExpressionUtil;
|
||||||
import org.dromara.warm.flow.core.utils.MapUtil;
|
import org.dromara.warm.flow.core.utils.MapUtil;
|
||||||
@ -42,10 +41,14 @@ import org.dromara.workflow.common.ConditionalOnEnable;
|
|||||||
import org.dromara.workflow.common.constant.FlowConstant;
|
import org.dromara.workflow.common.constant.FlowConstant;
|
||||||
import org.dromara.workflow.common.enums.TaskAssigneeType;
|
import org.dromara.workflow.common.enums.TaskAssigneeType;
|
||||||
import org.dromara.workflow.common.enums.TaskStatusEnum;
|
import org.dromara.workflow.common.enums.TaskStatusEnum;
|
||||||
|
import org.dromara.workflow.domain.FlowInstanceBizExt;
|
||||||
import org.dromara.workflow.domain.bo.*;
|
import org.dromara.workflow.domain.bo.*;
|
||||||
|
import org.dromara.workflow.domain.vo.FlowCopyVo;
|
||||||
import org.dromara.workflow.domain.vo.FlowHisTaskVo;
|
import org.dromara.workflow.domain.vo.FlowHisTaskVo;
|
||||||
import org.dromara.workflow.domain.vo.FlowTaskVo;
|
import org.dromara.workflow.domain.vo.FlowTaskVo;
|
||||||
|
import org.dromara.workflow.domain.vo.NodeExtVo;
|
||||||
import org.dromara.workflow.mapper.FlwCategoryMapper;
|
import org.dromara.workflow.mapper.FlwCategoryMapper;
|
||||||
|
import org.dromara.workflow.mapper.FlwInstanceBizExtMapper;
|
||||||
import org.dromara.workflow.mapper.FlwTaskMapper;
|
import org.dromara.workflow.mapper.FlwTaskMapper;
|
||||||
import org.dromara.workflow.service.IFlwCommonService;
|
import org.dromara.workflow.service.IFlwCommonService;
|
||||||
import org.dromara.workflow.service.IFlwNodeExtService;
|
import org.dromara.workflow.service.IFlwNodeExtService;
|
||||||
@ -56,7 +59,6 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static org.dromara.workflow.common.constant.FlowConstant.*;
|
import static org.dromara.workflow.common.constant.FlowConstant.*;
|
||||||
|
|
||||||
@ -87,6 +89,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
private final IFlwTaskAssigneeService flwTaskAssigneeService;
|
private final IFlwTaskAssigneeService flwTaskAssigneeService;
|
||||||
private final IFlwCommonService flwCommonService;
|
private final IFlwCommonService flwCommonService;
|
||||||
private final IFlwNodeExtService flwNodeExtService;
|
private final IFlwNodeExtService flwNodeExtService;
|
||||||
|
private final FlwInstanceBizExtMapper flwInstanceBizExtMapper;
|
||||||
private final FlowDefinitionMapper flowDefinitionMapper;
|
private final FlowDefinitionMapper flowDefinitionMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,15 +104,23 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
if (StringUtils.isBlank(businessId)) {
|
if (StringUtils.isBlank(businessId)) {
|
||||||
throw new ServiceException("启动工作流时必须包含业务ID");
|
throw new ServiceException("启动工作流时必须包含业务ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启动流程实例(提交申请)
|
// 启动流程实例(提交申请)
|
||||||
Map<String, Object> variables = startProcessBo.getVariables();
|
Map<String, Object> variables = startProcessBo.getVariables();
|
||||||
// 流程发起人
|
// 流程发起人
|
||||||
variables.put(INITIATOR, LoginHelper.getUserIdStr());
|
variables.put(INITIATOR, LoginHelper.getUserIdStr());
|
||||||
|
// 发起人部门id
|
||||||
|
variables.put(INITIATOR_DEPT_ID, LoginHelper.getDeptId());
|
||||||
// 业务id
|
// 业务id
|
||||||
variables.put(BUSINESS_ID, businessId);
|
variables.put(BUSINESS_ID, businessId);
|
||||||
|
FlowInstanceBizExt bizExt = startProcessBo.getBizExt();
|
||||||
|
|
||||||
|
// 获取已有流程实例
|
||||||
FlowInstance flowInstance = flowInstanceMapper.selectOne(new LambdaQueryWrapper<>(FlowInstance.class)
|
FlowInstance flowInstance = flowInstanceMapper.selectOne(new LambdaQueryWrapper<>(FlowInstance.class)
|
||||||
.eq(FlowInstance::getBusinessId, businessId));
|
.eq(FlowInstance::getBusinessId, businessId));
|
||||||
|
|
||||||
if (ObjectUtil.isNotNull(flowInstance)) {
|
if (ObjectUtil.isNotNull(flowInstance)) {
|
||||||
|
// 已存在流程
|
||||||
BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus());
|
BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus());
|
||||||
List<Task> taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId()));
|
List<Task> taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId()));
|
||||||
taskService.mergeVariable(flowInstance, variables);
|
taskService.mergeVariable(flowInstance, variables);
|
||||||
@ -117,9 +128,19 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
StartProcessReturnDTO dto = new StartProcessReturnDTO();
|
StartProcessReturnDTO dto = new StartProcessReturnDTO();
|
||||||
dto.setProcessInstanceId(taskList.get(0).getInstanceId());
|
dto.setProcessInstanceId(taskList.get(0).getInstanceId());
|
||||||
dto.setTaskId(taskList.get(0).getId());
|
dto.setTaskId(taskList.get(0).getId());
|
||||||
|
// 保存流程实例业务信息
|
||||||
|
this.buildFlowInstanceBizExt(flowInstance, bizExt);
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 将流程定义内的扩展参数设置到变量中
|
||||||
|
Definition definition = FlowEngine.defService().getPublishByFlowCode(startProcessBo.getFlowCode());
|
||||||
|
Dict dict = JsonUtils.parseMap(definition.getExt());
|
||||||
|
boolean autoPass = !ObjectUtil.isNull(dict) && dict.getBool(FlowConstant.AUTO_PASS);
|
||||||
|
variables.put(FlowConstant.AUTO_PASS, autoPass);
|
||||||
|
variables.put(FlowConstant.BUSINESS_CODE, this.generateBusinessCode(bizExt));
|
||||||
FlowParams flowParams = FlowParams.build()
|
FlowParams flowParams = FlowParams.build()
|
||||||
|
.handler(startProcessBo.getHandler())
|
||||||
.flowCode(startProcessBo.getFlowCode())
|
.flowCode(startProcessBo.getFlowCode())
|
||||||
.variable(startProcessBo.getVariables())
|
.variable(startProcessBo.getVariables())
|
||||||
.flowStatus(BusinessStatusEnum.DRAFT.getStatus());
|
.flowStatus(BusinessStatusEnum.DRAFT.getStatus());
|
||||||
@ -129,6 +150,8 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ServiceException(e.getMessage());
|
throw new ServiceException(e.getMessage());
|
||||||
}
|
}
|
||||||
|
// 保存流程实例业务信息
|
||||||
|
this.buildFlowInstanceBizExt(instance, bizExt);
|
||||||
// 申请人执行流程
|
// 申请人执行流程
|
||||||
List<Task> taskList = taskService.list(new FlowTask().setInstanceId(instance.getId()));
|
List<Task> taskList = taskService.list(new FlowTask().setInstanceId(instance.getId()));
|
||||||
if (taskList.size() > 1) {
|
if (taskList.size() > 1) {
|
||||||
@ -140,6 +163,31 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成业务编号,如果已有则直接返回已有值
|
||||||
|
*/
|
||||||
|
private String generateBusinessCode(FlowInstanceBizExt bizExt) {
|
||||||
|
if (StringUtils.isBlank(bizExt.getBusinessCode())) {
|
||||||
|
// TODO: 按照自己业务规则生成编号
|
||||||
|
String businessCode = Convert.toStr(System.currentTimeMillis());
|
||||||
|
bizExt.setBusinessCode(businessCode);
|
||||||
|
return businessCode;
|
||||||
|
}
|
||||||
|
return bizExt.getBusinessCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建流程实例业务信息
|
||||||
|
*
|
||||||
|
* @param instance 流程实例
|
||||||
|
* @param bizExt 流程业务扩展信息
|
||||||
|
*/
|
||||||
|
private void buildFlowInstanceBizExt(Instance instance, FlowInstanceBizExt bizExt) {
|
||||||
|
bizExt.setInstanceId(instance.getId());
|
||||||
|
bizExt.setBusinessId(instance.getBusinessId());
|
||||||
|
flwInstanceBizExtMapper.saveOrUpdateByInstanceId(bizExt);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 办理任务
|
* 办理任务
|
||||||
*
|
*
|
||||||
@ -156,11 +204,12 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
// 获取抄送人
|
// 获取抄送人
|
||||||
List<FlowCopyBo> flowCopyList = completeTaskBo.getFlowCopyList();
|
List<FlowCopyBo> flowCopyList = completeTaskBo.getFlowCopyList();
|
||||||
// 设置抄送人
|
// 设置抄送人
|
||||||
completeTaskBo.getVariables().put(FlowConstant.FLOW_COPY_LIST, flowCopyList);
|
Map<String, Object> variables = completeTaskBo.getVariables();
|
||||||
|
variables.put(FlowConstant.FLOW_COPY_LIST, flowCopyList);
|
||||||
// 消息类型
|
// 消息类型
|
||||||
completeTaskBo.getVariables().put(FlowConstant.MESSAGE_TYPE, messageType);
|
variables.put(FlowConstant.MESSAGE_TYPE, messageType);
|
||||||
// 消息通知
|
// 消息通知
|
||||||
completeTaskBo.getVariables().put(FlowConstant.MESSAGE_NOTICE, notice);
|
variables.put(FlowConstant.MESSAGE_NOTICE, notice);
|
||||||
|
|
||||||
|
|
||||||
FlowTask flowTask = flowTaskMapper.selectById(taskId);
|
FlowTask flowTask = flowTaskMapper.selectById(taskId);
|
||||||
@ -170,23 +219,24 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
Instance ins = insService.getById(flowTask.getInstanceId());
|
Instance ins = insService.getById(flowTask.getInstanceId());
|
||||||
// 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听
|
// 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听
|
||||||
if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) {
|
if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) {
|
||||||
completeTaskBo.getVariables().put(FlowConstant.SUBMIT, true);
|
variables.put(FlowConstant.SUBMIT, true);
|
||||||
}
|
}
|
||||||
// 设置弹窗处理人
|
// 设置弹窗处理人
|
||||||
Map<String, Object> assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), ins.getVariableMap());
|
Map<String, Object> assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), ins.getVariableMap());
|
||||||
if (CollUtil.isNotEmpty(assigneeMap)) {
|
if (CollUtil.isNotEmpty(assigneeMap)) {
|
||||||
completeTaskBo.getVariables().putAll(assigneeMap);
|
variables.putAll(assigneeMap);
|
||||||
}
|
}
|
||||||
// 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息
|
// 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息
|
||||||
FlowParams flowParams = FlowParams.build()
|
FlowParams flowParams = FlowParams.build()
|
||||||
.variable(completeTaskBo.getVariables())
|
.handler(completeTaskBo.getHandler())
|
||||||
|
.variable(variables)
|
||||||
.skipType(SkipType.PASS.getKey())
|
.skipType(SkipType.PASS.getKey())
|
||||||
.message(completeTaskBo.getMessage())
|
.message(completeTaskBo.getMessage())
|
||||||
.flowStatus(BusinessStatusEnum.WAITING.getStatus())
|
.flowStatus(BusinessStatusEnum.WAITING.getStatus())
|
||||||
.hisStatus(TaskStatusEnum.PASS.getStatus())
|
.hisStatus(TaskStatusEnum.PASS.getStatus())
|
||||||
.hisTaskExt(completeTaskBo.getFileId());
|
.hisTaskExt(completeTaskBo.getFileId());
|
||||||
// 执行任务跳转,并根据返回的处理人设置下一步处理人
|
Boolean autoPass = Convert.toBool(variables.getOrDefault(AUTO_PASS, false));
|
||||||
taskService.skip(taskId, flowParams);
|
skipTask(taskId, flowParams, flowTask.getInstanceId(), autoPass);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
@ -194,6 +244,43 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程办理
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @param flowParams 参数
|
||||||
|
* @param instanceId 实例ID
|
||||||
|
* @param autoPass 自动审批
|
||||||
|
*/
|
||||||
|
private void skipTask(Long taskId, FlowParams flowParams, Long instanceId, Boolean autoPass) {
|
||||||
|
// 执行任务跳转,并根据返回的处理人设置下一步处理人
|
||||||
|
taskService.skip(taskId, flowParams);
|
||||||
|
List<FlowTask> flowTaskList = selectByInstId(instanceId);
|
||||||
|
if (CollUtil.isEmpty(flowTaskList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<User> userList = FlowEngine.userService()
|
||||||
|
.getByAssociateds(StreamUtils.toList(flowTaskList, FlowTask::getId));
|
||||||
|
if (CollUtil.isEmpty(userList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (FlowTask task : flowTaskList) {
|
||||||
|
if (!task.getId().equals(taskId) && autoPass) {
|
||||||
|
List<User> users = StreamUtils.filter(userList, e -> ObjectUtil.equals(task.getId(), e.getAssociated()) && ObjectUtil.equal(e.getProcessedBy(), LoginHelper.getUserIdStr()));
|
||||||
|
if (CollUtil.isEmpty(users)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
flowParams.
|
||||||
|
message("流程引擎自动审批!").
|
||||||
|
variable(Map.of(
|
||||||
|
FlowConstant.SUBMIT, false,
|
||||||
|
FlowConstant.FLOW_COPY_LIST, Collections.emptyList(),
|
||||||
|
FlowConstant.MESSAGE_NOTICE, StringUtils.EMPTY));
|
||||||
|
skipTask(task.getId(), flowParams, instanceId, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置弹窗处理人
|
* 设置弹窗处理人
|
||||||
*
|
*
|
||||||
@ -216,7 +303,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
List<String> variableUserIds = Arrays.asList(userIds.split(StringUtils.SEPARATOR));
|
List<String> variableUserIds = Arrays.asList(userIds.split(StringUtils.SEPARATOR));
|
||||||
hashSet.addAll(popUserIds);
|
hashSet.addAll(popUserIds);
|
||||||
hashSet.addAll(variableUserIds);
|
hashSet.addAll(variableUserIds);
|
||||||
map.put(entry.getKey(), String.join(StringUtils.SEPARATOR, hashSet));
|
map.put(entry.getKey(), StringUtils.joinComma(hashSet));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
map.put(entry.getKey(), entry.getValue());
|
map.put(entry.getKey(), entry.getValue());
|
||||||
@ -237,7 +324,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 添加抄送人记录
|
// 添加抄送人记录
|
||||||
FlowHisTask flowHisTask = flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getTaskId, task.getId())).get(0);
|
FlowHisTask flowHisTask = flowHisTaskMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<>(FlowHisTask.class)
|
||||||
|
.eq(FlowHisTask::getTaskId, task.getId())).get(0);
|
||||||
FlowNode flowNode = new FlowNode();
|
FlowNode flowNode = new FlowNode();
|
||||||
flowNode.setNodeCode(flowHisTask.getTargetNodeCode());
|
flowNode.setNodeCode(flowHisTask.getTargetNodeCode());
|
||||||
flowNode.setNodeName(flowHisTask.getTargetNodeName());
|
flowNode.setNodeName(flowHisTask.getTargetNodeName());
|
||||||
@ -254,14 +343,11 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
hisTask.setCreateTime(updateTime);
|
hisTask.setCreateTime(updateTime);
|
||||||
hisTask.setUpdateTime(updateTime);
|
hisTask.setUpdateTime(updateTime);
|
||||||
hisTaskService.save(hisTask);
|
hisTaskService.save(hisTask);
|
||||||
List<User> userList = flowCopyList.stream()
|
List<User> userList = StreamUtils.toList(flowCopyList, x ->
|
||||||
.map(flowCopy -> {
|
new FlowUser()
|
||||||
FlowUser flowUser = new FlowUser();
|
.setType(TaskAssigneeType.COPY.getCode())
|
||||||
flowUser.setType(TaskAssigneeType.COPY.getCode());
|
.setProcessedBy(Convert.toStr(x.getUserId()))
|
||||||
flowUser.setProcessedBy(String.valueOf(flowCopy.getUserId()));
|
.setAssociated(taskId));
|
||||||
flowUser.setAssociated(taskId);
|
|
||||||
return flowUser;
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
// 批量保存抄送人员
|
// 批量保存抄送人员
|
||||||
FlowEngine.userService().saveBatch(userList);
|
FlowEngine.userService().saveBatch(userList);
|
||||||
}
|
}
|
||||||
@ -275,6 +361,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
@Override
|
@Override
|
||||||
public TableDataInfo<FlowTaskVo> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
public TableDataInfo<FlowTaskVo> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||||
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
||||||
|
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
|
||||||
|
queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr());
|
||||||
|
queryWrapper.in("t.flow_status", BusinessStatusEnum.WAITING.getStatus());
|
||||||
List<Long> definitionIds = new ArrayList<>();
|
List<Long> definitionIds = new ArrayList<>();
|
||||||
if (!"0".equals(flowTaskBo.getProjectId())){
|
if (!"0".equals(flowTaskBo.getProjectId())){
|
||||||
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>()
|
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>()
|
||||||
@ -289,13 +378,28 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
|
Page<FlowTaskVo> page = flwTaskMapper.getListRunTask(pageQuery.build(), queryWrapper);
|
||||||
queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr());
|
this.wrapAssigneeInfo(page.getRecords());
|
||||||
queryWrapper.in("t.flow_status", BusinessStatusEnum.WAITING.getStatus());
|
|
||||||
Page<FlowTaskVo> page = this.getFlowTaskDefinitionIdsVoPage(pageQuery,definitionIds, queryWrapper);
|
|
||||||
return TableDataInfo.build(page);
|
return TableDataInfo.build(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Page<FlowTaskVo> getFlowTaskDefinitionIdsVoPage(PageQuery pageQuery, List<Long> definitionIds, QueryWrapper<FlowTaskBo> queryWrapper) {
|
||||||
|
Page<FlowTaskVo> page = flwTaskMapper.getListRunTaskDefinitionIds(pageQuery.build(),definitionIds, queryWrapper);
|
||||||
|
List<FlowTaskVo> records = page.getRecords();
|
||||||
|
if (CollUtil.isNotEmpty(records)) {
|
||||||
|
List<Long> taskIds = StreamUtils.toList(records, FlowTaskVo::getId);
|
||||||
|
List<UserDTO> userList = currentTaskAllUser(taskIds);
|
||||||
|
records.forEach(t -> {
|
||||||
|
if (CollUtil.isNotEmpty(userList)) {
|
||||||
|
t.setAssigneeIds(StreamUtils.join(userList, e -> String.valueOf(e.getUserId())));
|
||||||
|
t.setAssigneeNames(StreamUtils.join(userList, UserDTO::getNickName));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询当前用户的已办任务
|
* 查询当前用户的已办任务
|
||||||
*
|
*
|
||||||
@ -305,24 +409,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
@Override
|
@Override
|
||||||
public TableDataInfo<FlowHisTaskVo> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
public TableDataInfo<FlowHisTaskVo> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||||
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
||||||
List<Long> definitionIds = new ArrayList<>();
|
|
||||||
if (!"0".equals(flowTaskBo.getProjectId())){
|
|
||||||
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>()
|
|
||||||
.select(FlowDefinition::getId)
|
|
||||||
.like(FlowDefinition::getFlowCode, flowTaskBo.getProjectId()));
|
|
||||||
if (flowDefinitions != null && !flowDefinitions.isEmpty()) {
|
|
||||||
flowDefinitions.forEach(flowDefinition -> {
|
|
||||||
definitionIds.add(flowDefinition.getId());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (definitionIds.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
|
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
|
||||||
queryWrapper.in("t.approver", LoginHelper.getUserIdStr());
|
queryWrapper.in("t.approver", LoginHelper.getUserIdStr());
|
||||||
queryWrapper.orderByDesc("t.create_time").orderByDesc("t.update_time");
|
Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper);
|
||||||
Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishDefinitionIdsTask(pageQuery.build(),definitionIds, queryWrapper);
|
|
||||||
return TableDataInfo.build(page);
|
return TableDataInfo.build(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,41 +425,27 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
public TableDataInfo<FlowTaskVo> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
public TableDataInfo<FlowTaskVo> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||||
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
||||||
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
|
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
|
||||||
Page<FlowTaskVo> page = getFlowTaskVoPage(pageQuery, queryWrapper);
|
Page<FlowTaskVo> page = flwTaskMapper.getListRunTask(pageQuery.build(), queryWrapper);
|
||||||
|
this.wrapAssigneeInfo(page.getRecords());
|
||||||
return TableDataInfo.build(page);
|
return TableDataInfo.build(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Page<FlowTaskVo> getFlowTaskVoPage(PageQuery pageQuery, QueryWrapper<FlowTaskBo> queryWrapper) {
|
/**
|
||||||
Page<FlowTaskVo> page = flwTaskMapper.getListRunTask(pageQuery.build(), queryWrapper);
|
* 为流程任务列表封装处理人 ID(assigneeIds)
|
||||||
List<FlowTaskVo> records = page.getRecords();
|
*
|
||||||
if (CollUtil.isNotEmpty(records)) {
|
* @param taskList 流程任务列表
|
||||||
List<Long> taskIds = StreamUtils.toList(records, FlowTaskVo::getId);
|
*/
|
||||||
Map<Long, List<UserDTO>> listMap = currentTaskAllUser(taskIds);
|
private void wrapAssigneeInfo(List<FlowTaskVo> taskList) {
|
||||||
records.forEach(t -> {
|
if (CollUtil.isEmpty(taskList)) {
|
||||||
List<UserDTO> userList = listMap.getOrDefault(t.getId(), Collections.emptyList());
|
return;
|
||||||
if (CollUtil.isNotEmpty(userList)) {
|
|
||||||
t.setAssigneeIds(StreamUtils.join(userList, e -> String.valueOf(e.getUserId())));
|
|
||||||
t.setAssigneeNames(StreamUtils.join(userList, UserDTO::getNickName));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return page;
|
List<User> associatedUsers = FlowEngine.userService().getByAssociateds(StreamUtils.toList(taskList, FlowTaskVo::getId));
|
||||||
}
|
Map<Long, List<User>> taskUserMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated);
|
||||||
private Page<FlowTaskVo> getFlowTaskDefinitionIdsVoPage(PageQuery pageQuery, List<Long> definitionIds, QueryWrapper<FlowTaskBo> queryWrapper) {
|
// 组装用户数据回任务列表
|
||||||
Page<FlowTaskVo> page = flwTaskMapper.getListRunTaskDefinitionIds(pageQuery.build(),definitionIds, queryWrapper);
|
for (FlowTaskVo task : taskList) {
|
||||||
List<FlowTaskVo> records = page.getRecords();
|
List<User> users = taskUserMap.get(task.getId());
|
||||||
if (CollUtil.isNotEmpty(records)) {
|
task.setAssigneeIds(StreamUtils.join(users, User::getProcessedBy));
|
||||||
List<Long> taskIds = StreamUtils.toList(records, FlowTaskVo::getId);
|
|
||||||
Map<Long, List<UserDTO>> listMap = currentTaskAllUser(taskIds);
|
|
||||||
records.forEach(t -> {
|
|
||||||
List<UserDTO> userList = listMap.getOrDefault(t.getId(), Collections.emptyList());
|
|
||||||
if (CollUtil.isNotEmpty(userList)) {
|
|
||||||
t.setAssigneeIds(StreamUtils.join(userList, e -> String.valueOf(e.getUserId())));
|
|
||||||
t.setAssigneeNames(StreamUtils.join(userList, UserDTO::getNickName));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return page;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -395,23 +470,8 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
@Override
|
@Override
|
||||||
public TableDataInfo<FlowTaskVo> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
public TableDataInfo<FlowTaskVo> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
|
||||||
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
||||||
List<Long> definitionIds = new ArrayList<>();
|
|
||||||
if (!"0".equals(flowTaskBo.getProjectId())){
|
|
||||||
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>()
|
|
||||||
.select(FlowDefinition::getId)
|
|
||||||
.like(FlowDefinition::getFlowCode, flowTaskBo.getProjectId()));
|
|
||||||
if (flowDefinitions != null && !flowDefinitions.isEmpty()) {
|
|
||||||
flowDefinitions.forEach(flowDefinition -> {
|
|
||||||
definitionIds.add(flowDefinition.getId());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (definitionIds.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queryWrapper.eq(StringUtils.isNotBlank(flowTaskBo.getIsRead()),"t.is_read", flowTaskBo.getIsRead());
|
|
||||||
queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr());
|
queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr());
|
||||||
Page<FlowTaskVo> page = flwTaskMapper.getTaskCopyDefinitionIdsByPage(pageQuery.build(),definitionIds, queryWrapper);
|
Page<FlowTaskVo> page = flwTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper);
|
||||||
return TableDataInfo.build(page);
|
return TableDataInfo.build(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +485,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory()));
|
List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory()));
|
||||||
wrapper.in("t.category", StreamUtils.toList(categoryIds, Convert::toStr));
|
wrapper.in("t.category", StreamUtils.toList(categoryIds, Convert::toStr));
|
||||||
}
|
}
|
||||||
wrapper.orderByDesc("t.create_time");
|
wrapper.orderByDesc("t.create_time").orderByDesc("t.update_time");
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,9 +513,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
|
|
||||||
Map<String, Object> variable = new HashMap<>();
|
Map<String, Object> variable = new HashMap<>();
|
||||||
// 消息类型
|
// 消息类型
|
||||||
variable.put("messageType", messageType);
|
variable.put(FlowConstant.MESSAGE_TYPE, messageType);
|
||||||
// 消息通知
|
// 消息通知
|
||||||
variable.put("notice", notice);
|
variable.put(FlowConstant.MESSAGE_NOTICE, notice);
|
||||||
|
|
||||||
FlowParams flowParams = FlowParams.build()
|
FlowParams flowParams = FlowParams.build()
|
||||||
.nodeCode(bo.getNodeCode())
|
.nodeCode(bo.getNodeCode())
|
||||||
@ -476,22 +536,28 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
/**
|
/**
|
||||||
* 获取可驳回的前置节点
|
* 获取可驳回的前置节点
|
||||||
*
|
*
|
||||||
* @param definitionId 流程定义id
|
* @param taskId 任务id
|
||||||
* @param nowNodeCode 当前节点
|
* @param nowNodeCode 当前节点
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<Node> getBackTaskNode(Long definitionId, String nowNodeCode) {
|
public List<Node> getBackTaskNode(Long taskId, String nowNodeCode) {
|
||||||
List<Node> nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), definitionId);
|
FlowTask task = flowTaskMapper.selectById(taskId);
|
||||||
|
List<Node> nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), task.getDefinitionId());
|
||||||
if (!CollUtil.isNotEmpty(nodeCodes)) {
|
if (!CollUtil.isNotEmpty(nodeCodes)) {
|
||||||
return nodeCodes;
|
return nodeCodes;
|
||||||
}
|
}
|
||||||
|
List<User> userList = FlowEngine.userService()
|
||||||
|
.getByAssociateds(Collections.singletonList(task.getId()), UserType.DEPUTE.getKey());
|
||||||
|
if (CollUtil.isNotEmpty(userList)) {
|
||||||
|
return nodeCodes;
|
||||||
|
}
|
||||||
//判断是否配置了固定驳回节点
|
//判断是否配置了固定驳回节点
|
||||||
Node node = nodeCodes.get(0);
|
Node node = nodeCodes.get(0);
|
||||||
if (StringUtils.isNotBlank(node.getAnyNodeSkip())) {
|
if (StringUtils.isNotBlank(node.getAnyNodeSkip())) {
|
||||||
return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), definitionId);
|
return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), task.getDefinitionId());
|
||||||
}
|
}
|
||||||
//获取可驳回的前置节点
|
//获取可驳回的前置节点
|
||||||
List<Node> nodes = nodeService.previousNodeList(definitionId, nowNodeCode);
|
List<Node> nodes = nodeService.previousNodeList(task.getDefinitionId(), nowNodeCode);
|
||||||
if (CollUtil.isNotEmpty(nodes)) {
|
if (CollUtil.isNotEmpty(nodes)) {
|
||||||
return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType()));
|
return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType()));
|
||||||
}
|
}
|
||||||
@ -535,8 +601,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<FlowTask> selectByIdList(List<Long> taskIdList) {
|
public List<FlowTask> selectByIdList(List<Long> taskIdList) {
|
||||||
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
|
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class).in(FlowTask::getId, taskIdList));
|
||||||
.in(FlowTask::getId, taskIdList));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -562,8 +627,24 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
if (ObjectUtil.isNull(flowNode)) {
|
if (ObjectUtil.isNull(flowNode)) {
|
||||||
throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在");
|
throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在");
|
||||||
}
|
}
|
||||||
|
NodeExtVo nodeExtVo = flwNodeExtService.parseNodeExt(flowNode.getExt(), instance.getVariableMap());
|
||||||
//设置按钮权限
|
//设置按钮权限
|
||||||
flowTaskVo.setButtonList(flwNodeExtService.buildButtonPermissionsFromExt(flowNode.getExt()));
|
if (CollUtil.isNotEmpty(nodeExtVo.getButtonPermissions())) {
|
||||||
|
flowTaskVo.setButtonList(nodeExtVo.getButtonPermissions());
|
||||||
|
} else {
|
||||||
|
flowTaskVo.setButtonList(new ArrayList<>());
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(nodeExtVo.getCopySettings())) {
|
||||||
|
List<FlowCopyVo> list = StreamUtils.toList(nodeExtVo.getCopySettings(), x -> new FlowCopyVo(Convert.toLong(x)));
|
||||||
|
flowTaskVo.setCopyList(list);
|
||||||
|
} else {
|
||||||
|
flowTaskVo.setCopyList(new ArrayList<>());
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(nodeExtVo.getVariables())) {
|
||||||
|
flowTaskVo.setVarList(nodeExtVo.getVariables());
|
||||||
|
} else {
|
||||||
|
flowTaskVo.setVarList(new HashMap<>());
|
||||||
|
}
|
||||||
flowTaskVo.setNodeRatio(flowNode.getNodeRatio());
|
flowTaskVo.setNodeRatio(flowNode.getNodeRatio());
|
||||||
flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId())));
|
flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId())));
|
||||||
return flowTaskVo;
|
return flowTaskVo;
|
||||||
@ -588,39 +669,24 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
// 只获取中间节点
|
// 只获取中间节点
|
||||||
nextFlowNodes = StreamUtils.filter(nextFlowNodes, node -> NodeType.BETWEEN.getKey().equals(node.getNodeType()));
|
nextFlowNodes = StreamUtils.filter(nextFlowNodes, node -> NodeType.BETWEEN.getKey().equals(node.getNodeType()));
|
||||||
if (CollUtil.isNotEmpty(nextNodeList)) {
|
if (CollUtil.isNotEmpty(nextNodeList)) {
|
||||||
// 构建以下节点数据
|
//构建以下节点数据
|
||||||
List<Task> buildNextTaskList = StreamUtils.toList(nextNodeList, node -> taskService.addTask(node, instance, definition, FlowParams.build()));
|
List<Task> buildNextTaskList = StreamUtils.toList(nextNodeList, node -> taskService.addTask(node, instance, definition, FlowParams.build()));
|
||||||
// 办理人变量替换
|
//办理人变量替换
|
||||||
ExpressionUtil.evalVariable(buildNextTaskList,
|
ExpressionUtil.evalVariable(buildNextTaskList, FlowParams.build().variable(mergeVariable));
|
||||||
FlowParams.build()
|
|
||||||
.variable(mergeVariable)
|
|
||||||
);
|
|
||||||
for (FlowNode flowNode : nextFlowNodes) {
|
for (FlowNode flowNode : nextFlowNodes) {
|
||||||
buildNextTaskList.stream().filter(t -> t.getNodeCode().equals(flowNode.getNodeCode())).findFirst().ifPresent(t -> {
|
StreamUtils.findFirst(buildNextTaskList, t -> t.getNodeCode().equals(flowNode.getNodeCode()))
|
||||||
if (CollUtil.isNotEmpty(t.getPermissionList())) {
|
.ifPresent(first -> {
|
||||||
List<UserDTO> users = flwTaskAssigneeService.fetchUsersByStorageIds(String.join(StringUtils.SEPARATOR, t.getPermissionList()),null);
|
List<UserDTO> users;
|
||||||
if (CollUtil.isNotEmpty(users)) {
|
if (CollUtil.isNotEmpty(first.getPermissionList())
|
||||||
flowNode.setPermissionFlag(StreamUtils.join(users, e -> String.valueOf(e.getUserId())));
|
&& CollUtil.isNotEmpty(users = flwTaskAssigneeService.fetchUsersByStorageIds(StringUtils.joinComma(first.getPermissionList()),null))) {
|
||||||
|
flowNode.setPermissionFlag(StreamUtils.join(users, e -> Convert.toStr(e.getUserId())));
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nextFlowNodes;
|
return nextFlowNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 按照任务id查询任务
|
|
||||||
*
|
|
||||||
* @param taskIdList 任务id
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<FlowHisTask> selectHisTaskByIdList(List<Long> taskIdList) {
|
|
||||||
return flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class)
|
|
||||||
.in(FlowHisTask::getId, taskIdList));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按照任务id查询任务
|
* 按照任务id查询任务
|
||||||
*
|
*
|
||||||
@ -629,19 +695,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public FlowHisTask selectHisTaskById(Long taskId) {
|
public FlowHisTask selectHisTaskById(Long taskId) {
|
||||||
return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class)
|
return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getId, taskId));
|
||||||
.eq(FlowHisTask::getId, taskId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 按照实例id查询任务
|
|
||||||
*
|
|
||||||
* @param instanceIdList 流程实例id
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<FlowTask> selectByInstIdList(List<Long> instanceIdList) {
|
|
||||||
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
|
|
||||||
.in(FlowTask::getInstanceId, instanceIdList));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -651,8 +705,29 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<FlowTask> selectByInstId(Long instanceId) {
|
public List<FlowTask> selectByInstId(Long instanceId) {
|
||||||
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
|
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class).eq(FlowTask::getInstanceId, instanceId));
|
||||||
.eq(FlowTask::getInstanceId, instanceId));
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按照实例id查询任务
|
||||||
|
*
|
||||||
|
* @param instanceIds 流程实例id
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<FlowTask> selectByInstIds(List<Long> instanceIds) {
|
||||||
|
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class).in(FlowTask::getInstanceId, instanceIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断流程是否已结束(即该流程实例下是否还有未完成的任务)
|
||||||
|
*
|
||||||
|
* @param instanceId 流程实例ID
|
||||||
|
* @return true 表示任务已全部结束;false 表示仍有任务存在
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isTaskEnd(Long instanceId) {
|
||||||
|
boolean exists = flowTaskMapper.exists(new LambdaQueryWrapper<FlowTask>().eq(FlowTask::getInstanceId, instanceId));
|
||||||
|
return !exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -664,8 +739,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public boolean taskOperation(TaskOperationBo bo, String taskOperation) {
|
public boolean taskOperation(TaskOperationBo bo, String taskOperation) {
|
||||||
FlowParams flowParams = FlowParams.build()
|
FlowParams flowParams = FlowParams.build().message(bo.getMessage());
|
||||||
.message(bo.getMessage());
|
|
||||||
if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
|
if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
|
||||||
flowParams.ignore(true);
|
flowParams.ignore(true);
|
||||||
}
|
}
|
||||||
@ -693,7 +767,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
Long taskId = bo.getTaskId();
|
Long taskId = bo.getTaskId();
|
||||||
Task task = taskService.getById(taskId);
|
Task task = taskService.getById(taskId);
|
||||||
FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId());
|
FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId());
|
||||||
if ("addSignature".equals(taskOperation) || "reductionSignature".equals(taskOperation)) {
|
if (ADD_SIGNATURE.equals(taskOperation) || REDUCTION_SIGNATURE.equals(taskOperation)) {
|
||||||
if (flowNode.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) {
|
if (flowNode.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) {
|
||||||
throw new ServiceException(task.getNodeName() + "不是会签节点!");
|
throw new ServiceException(task.getNodeName() + "不是会签节点!");
|
||||||
}
|
}
|
||||||
@ -744,15 +818,11 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
// 批量删除现有任务的办理人记录
|
// 批量删除现有任务的办理人记录
|
||||||
if (CollUtil.isNotEmpty(flowTasks)) {
|
if (CollUtil.isNotEmpty(flowTasks)) {
|
||||||
FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId));
|
FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId));
|
||||||
List<User> userList = flowTasks.stream()
|
List<User> userList = StreamUtils.toList(flowTasks, flowTask ->
|
||||||
.map(flowTask -> {
|
new FlowUser()
|
||||||
FlowUser flowUser = new FlowUser();
|
.setType(TaskAssigneeType.APPROVER.getCode())
|
||||||
flowUser.setType(TaskAssigneeType.APPROVER.getCode());
|
.setProcessedBy(userId)
|
||||||
flowUser.setProcessedBy(userId);
|
.setAssociated(flowTask.getId()));
|
||||||
flowUser.setAssociated(flowTask.getId());
|
|
||||||
return flowUser;
|
|
||||||
})
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
if (CollUtil.isNotEmpty(userList)) {
|
if (CollUtil.isNotEmpty(userList)) {
|
||||||
FlowEngine.userService().saveBatch(userList);
|
FlowEngine.userService().saveBatch(userList);
|
||||||
}
|
}
|
||||||
@ -764,36 +834,15 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取任务所有办理人
|
|
||||||
*
|
|
||||||
* @param taskIdList 任务id
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Map<Long, List<UserDTO>> currentTaskAllUser(List<Long> taskIdList) {
|
|
||||||
Map<Long, List<UserDTO>> map = new HashMap<>();
|
|
||||||
// 获取与当前任务关联的用户列表
|
|
||||||
List<User> associatedUsers = FlowEngine.userService().getByAssociateds(taskIdList);
|
|
||||||
Map<Long, List<User>> listMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated);
|
|
||||||
for (Map.Entry<Long, List<User>> entry : listMap.entrySet()) {
|
|
||||||
List<User> value = entry.getValue();
|
|
||||||
if (CollUtil.isNotEmpty(value)) {
|
|
||||||
List<UserDTO> userDtoList = userService.selectListByIds(StreamUtils.toList(value, e -> Convert.toLong(e.getProcessedBy())));
|
|
||||||
map.put(entry.getKey(), userDtoList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前任务的所有办理人
|
* 获取当前任务的所有办理人
|
||||||
*
|
*
|
||||||
* @param taskId 任务id
|
* @param taskIds 任务id
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<UserDTO> currentTaskAllUser(Long taskId) {
|
public List<UserDTO> currentTaskAllUser(List<Long> taskIds) {
|
||||||
// 获取与当前任务关联的用户列表
|
// 获取与当前任务关联的用户列表
|
||||||
List<User> userList = FlowEngine.userService().getByAssociateds(Collections.singletonList(taskId));
|
List<User> userList = FlowEngine.userService().getByAssociateds(taskIds);
|
||||||
if (CollUtil.isEmpty(userList)) {
|
if (CollUtil.isEmpty(userList)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
@ -813,17 +862,28 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
|||||||
.eq(FlowNode::getDefinitionId, definitionId));
|
.eq(FlowNode::getDefinitionId, definitionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 催办任务
|
||||||
|
*
|
||||||
|
* @param bo 参数
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void copyRead(Long flowUserId) {
|
public boolean urgeTask(FlowUrgeTaskBo bo) {
|
||||||
Long userId = LoginHelper.getUserId();
|
try {
|
||||||
flwTaskMapper.copyRead(flowUserId);
|
if (CollUtil.isEmpty(bo.getTaskIdList())) {
|
||||||
SseMessageDto dto = new SseMessageDto();
|
return false;
|
||||||
SeeMessageContentDto contentDto = new SeeMessageContentDto();
|
}
|
||||||
contentDto.setType("count");
|
List<UserDTO> userList = this.currentTaskAllUser(bo.getTaskIdList());
|
||||||
contentDto.setContent("统计");
|
if (CollUtil.isEmpty(userList)) {
|
||||||
dto.setMessage(JSONUtil.toJsonStr(contentDto));
|
return false;
|
||||||
dto.setIsRecord(false);
|
}
|
||||||
dto.setUserIds(Collections.singletonList(userId));
|
List<String> messageType = bo.getMessageType();
|
||||||
SseMessageUtils.publishMessage(dto);
|
String message = bo.getMessage();
|
||||||
|
flwCommonService.sendMessage(messageType, message, "单据审批提醒", userList);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
throw new ServiceException(e.getMessage());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,15 +4,18 @@ import cn.hutool.core.convert.Convert;
|
|||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.common.core.domain.event.ProcessTaskEvent;
|
import org.dromara.common.core.domain.dto.StartProcessDTO;
|
||||||
import org.dromara.common.core.domain.event.ProcessDeleteEvent;
|
import org.dromara.common.core.domain.event.ProcessDeleteEvent;
|
||||||
import org.dromara.common.core.domain.event.ProcessEvent;
|
import org.dromara.common.core.domain.event.ProcessEvent;
|
||||||
|
import org.dromara.common.core.domain.event.ProcessTaskEvent;
|
||||||
import org.dromara.common.core.enums.BusinessStatusEnum;
|
import org.dromara.common.core.enums.BusinessStatusEnum;
|
||||||
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.core.service.WorkflowService;
|
import org.dromara.common.core.service.WorkflowService;
|
||||||
import org.dromara.common.core.utils.MapstructUtils;
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
@ -20,6 +23,7 @@ import org.dromara.common.mybatis.core.domain.BaseEntity;
|
|||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
|
import org.dromara.workflow.common.constant.FlowConstant;
|
||||||
import org.dromara.workflow.domain.TestLeave;
|
import org.dromara.workflow.domain.TestLeave;
|
||||||
import org.dromara.workflow.domain.bo.TestLeaveBo;
|
import org.dromara.workflow.domain.bo.TestLeaveBo;
|
||||||
import org.dromara.workflow.domain.vo.TestLeaveVo;
|
import org.dromara.workflow.domain.vo.TestLeaveVo;
|
||||||
@ -104,6 +108,7 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
|
|||||||
long day = DateUtil.betweenDay(bo.getStartDate(), bo.getEndDate(), true);
|
long day = DateUtil.betweenDay(bo.getStartDate(), bo.getEndDate(), true);
|
||||||
// 截止日期也算一天
|
// 截止日期也算一天
|
||||||
bo.setLeaveDays((int) day + 1);
|
bo.setLeaveDays((int) day + 1);
|
||||||
|
bo.setApplyCode(System.currentTimeMillis() + StrUtil.EMPTY);
|
||||||
TestLeave add = MapstructUtils.convert(bo, TestLeave.class);
|
TestLeave add = MapstructUtils.convert(bo, TestLeave.class);
|
||||||
if (StringUtils.isBlank(add.getStatus())) {
|
if (StringUtils.isBlank(add.getStatus())) {
|
||||||
add.setStatus(BusinessStatusEnum.DRAFT.getStatus());
|
add.setStatus(BusinessStatusEnum.DRAFT.getStatus());
|
||||||
@ -115,6 +120,37 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
|
|||||||
return MapstructUtils.convert(add, TestLeaveVo.class);
|
return MapstructUtils.convert(add, TestLeaveVo.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public TestLeaveVo submitAndFlowStart(TestLeaveBo bo) {
|
||||||
|
long day = DateUtil.betweenDay(bo.getStartDate(), bo.getEndDate(), true);
|
||||||
|
// 截止日期也算一天
|
||||||
|
bo.setLeaveDays((int) day + 1);
|
||||||
|
if (ObjectUtil.isNull(bo.getId())) {
|
||||||
|
bo.setApplyCode(System.currentTimeMillis() + StrUtil.EMPTY);
|
||||||
|
}
|
||||||
|
TestLeave leave = MapstructUtils.convert(bo, TestLeave.class);
|
||||||
|
boolean flag = baseMapper.insertOrUpdate(leave);
|
||||||
|
if (flag) {
|
||||||
|
bo.setId(leave.getId());
|
||||||
|
// 后端发起需要忽略权限
|
||||||
|
bo.getParams().put("ignore", true);
|
||||||
|
|
||||||
|
StartProcessDTO startProcess = new StartProcessDTO();
|
||||||
|
startProcess.setBusinessId(leave.getId().toString());
|
||||||
|
startProcess.setFlowCode(StringUtils.isEmpty(bo.getFlowCode()) ? "leave1" : bo.getFlowCode());
|
||||||
|
startProcess.setVariables(bo.getParams());
|
||||||
|
// 后端发起 如果没有登录用户 比如定时任务 可以手动设置一个处理人id
|
||||||
|
// startProcess.setHandler("0");
|
||||||
|
|
||||||
|
boolean flag1 = workflowService.startCompleteTask(startProcess);
|
||||||
|
if (!flag1) {
|
||||||
|
throw new ServiceException("流程发起异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MapstructUtils.convert(leave, TestLeaveVo.class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改请假
|
* 修改请假
|
||||||
*/
|
*/
|
||||||
@ -136,7 +172,7 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
|
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成等)
|
||||||
* 正常使用只需#processEvent.flowCode=='leave1'
|
* 正常使用只需#processEvent.flowCode=='leave1'
|
||||||
* 示例为了方便则使用startsWith匹配了全部示例key
|
* 示例为了方便则使用startsWith匹配了全部示例key
|
||||||
*
|
*
|
||||||
@ -158,13 +194,17 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
|
|||||||
String message = Convert.toStr(params.get("message"));
|
String message = Convert.toStr(params.get("message"));
|
||||||
}
|
}
|
||||||
if (processEvent.getSubmit()) {
|
if (processEvent.getSubmit()) {
|
||||||
|
if (StringUtils.isBlank(testLeave.getApplyCode())) {
|
||||||
|
String businessCode = MapUtil.getStr(params, FlowConstant.BUSINESS_CODE, StrUtil.EMPTY);
|
||||||
|
testLeave.setApplyCode(businessCode);
|
||||||
|
}
|
||||||
testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
|
testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
|
||||||
}
|
}
|
||||||
baseMapper.updateById(testLeave);
|
baseMapper.updateById(testLeave);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行任务创建监听
|
* 执行任务创建监听(也代表上一条任务完成事件)
|
||||||
* 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断
|
* 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断
|
||||||
* 在方法中判断流程节点key
|
* 在方法中判断流程节点key
|
||||||
* if ("xxx".equals(processTaskEvent.getNodeCode())) {
|
* if ("xxx".equals(processTaskEvent.getNodeCode())) {
|
||||||
|
|||||||
@ -6,17 +6,22 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.dromara.common.core.domain.dto.CompleteTaskDTO;
|
import org.dromara.common.core.domain.dto.CompleteTaskDTO;
|
||||||
import org.dromara.common.core.domain.dto.StartProcessDTO;
|
import org.dromara.common.core.domain.dto.StartProcessDTO;
|
||||||
import org.dromara.common.core.domain.dto.StartProcessReturnDTO;
|
import org.dromara.common.core.domain.dto.StartProcessReturnDTO;
|
||||||
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.core.service.WorkflowService;
|
import org.dromara.common.core.service.WorkflowService;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.warm.flow.orm.entity.FlowInstance;
|
import org.dromara.warm.flow.orm.entity.FlowInstance;
|
||||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||||
|
import org.dromara.workflow.common.enums.MessageTypeEnum;
|
||||||
|
import org.dromara.workflow.domain.FlowInstanceBizExt;
|
||||||
import org.dromara.workflow.domain.bo.CompleteTaskBo;
|
import org.dromara.workflow.domain.bo.CompleteTaskBo;
|
||||||
import org.dromara.workflow.domain.bo.StartProcessBo;
|
import org.dromara.workflow.domain.bo.StartProcessBo;
|
||||||
import org.dromara.workflow.service.IFlwDefinitionService;
|
import org.dromara.workflow.service.IFlwDefinitionService;
|
||||||
import org.dromara.workflow.service.IFlwInstanceService;
|
import org.dromara.workflow.service.IFlwInstanceService;
|
||||||
import org.dromara.workflow.service.IFlwTaskService;
|
import org.dromara.workflow.service.IFlwTaskService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -148,4 +153,36 @@ public class WorkflowServiceImpl implements WorkflowService {
|
|||||||
return flwTaskService.completeTask(completeTask);
|
return flwTaskService.completeTask(completeTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动流程并办理第一个任务
|
||||||
|
*
|
||||||
|
* @param startProcess 参数
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean startCompleteTask(StartProcessDTO startProcess) {
|
||||||
|
try {
|
||||||
|
StartProcessBo processBo = new StartProcessBo();
|
||||||
|
processBo.setBusinessId(startProcess.getBusinessId());
|
||||||
|
processBo.setFlowCode(startProcess.getFlowCode());
|
||||||
|
processBo.setVariables(startProcess.getVariables());
|
||||||
|
processBo.setHandler(startProcess.getHandler());
|
||||||
|
processBo.setBizExt(BeanUtil.toBean(startProcess.getBizExt(), FlowInstanceBizExt.class));
|
||||||
|
|
||||||
|
StartProcessReturnDTO result = flwTaskService.startWorkFlow(processBo);
|
||||||
|
CompleteTaskBo taskBo = new CompleteTaskBo();
|
||||||
|
taskBo.setTaskId(result.getTaskId());
|
||||||
|
taskBo.setMessageType(Collections.singletonList(MessageTypeEnum.SYSTEM_MESSAGE.getCode()));
|
||||||
|
taskBo.setVariables(startProcess.getVariables());
|
||||||
|
taskBo.setHandler(startProcess.getHandler());
|
||||||
|
|
||||||
|
boolean flag = flwTaskService.completeTask(taskBo);
|
||||||
|
if (!flag) {
|
||||||
|
throw new ServiceException("流程发起异常");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ServiceException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="org.dromara.workflow.mapper.FlwInstanceBizExtMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@ -28,11 +28,13 @@
|
|||||||
fd.form_custom,
|
fd.form_custom,
|
||||||
fd.form_path,
|
fd.form_path,
|
||||||
fd.category,
|
fd.category,
|
||||||
bp.project_name
|
bp.project_name,
|
||||||
|
biz.business_code,
|
||||||
|
biz.business_title
|
||||||
from flow_instance fi
|
from flow_instance fi
|
||||||
left join flow_definition fd on fi.definition_id = fd.id
|
left join flow_definition fd on fi.definition_id = fd.id
|
||||||
left join bus_project bp on bp.id = SUBSTRING_INDEX(fd.flow_code, '_', 1)
|
left join flow_instance_biz_ext biz on biz.instance_id = fi.id
|
||||||
${ew.getCustomSqlSegment}
|
left join bus_project bp on bp.id = SUBSTRING_INDEX(fd.flow_code, '_', 1)
|
||||||
|
${ew.getCustomSqlSegment}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="org.dromara.workflow.mapper.FlwSpelMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@ -10,37 +10,40 @@
|
|||||||
|
|
||||||
<select id="getListRunTask" resultMap="FlowTaskResult">
|
<select id="getListRunTask" resultMap="FlowTaskResult">
|
||||||
select * from (
|
select * from (
|
||||||
select distinct
|
select distinct
|
||||||
t.id,
|
t.id,
|
||||||
t.node_code,
|
t.node_code,
|
||||||
t.node_name,
|
t.node_name,
|
||||||
t.node_type,
|
t.node_type,
|
||||||
t.definition_id,
|
t.definition_id,
|
||||||
t.instance_id,
|
t.instance_id,
|
||||||
t.create_time,
|
t.create_time,
|
||||||
t.update_time,
|
t.update_time,
|
||||||
t.tenant_id,
|
t.tenant_id,
|
||||||
i.business_id,
|
i.business_id,
|
||||||
i.flow_status,
|
i.flow_status,
|
||||||
i.create_by,
|
i.create_by,
|
||||||
d.flow_name,
|
d.flow_name,
|
||||||
d.flow_code,
|
d.flow_code,
|
||||||
d.form_custom,
|
d.form_custom,
|
||||||
d.category,
|
d.category,
|
||||||
COALESCE(t.form_path, d.form_path) as form_path,
|
COALESCE(t.form_path, d.form_path) as form_path,
|
||||||
d.version,
|
d.version,
|
||||||
uu.processed_by,
|
uu.processed_by,
|
||||||
uu.type
|
uu.type,
|
||||||
from flow_task t
|
biz.business_code,
|
||||||
left join flow_user uu on uu.associated = t.id
|
biz.business_title
|
||||||
left join flow_definition d on t.definition_id = d.id
|
from flow_task t
|
||||||
left join flow_instance i on t.instance_id = i.id
|
left join flow_user uu on uu.associated = t.id
|
||||||
where t.node_type = 1
|
left join flow_definition d on t.definition_id = d.id
|
||||||
and t.del_flag = '0'
|
left join flow_instance i on t.instance_id = i.id
|
||||||
and uu.del_flag = '0'
|
left join flow_instance_biz_ext biz on biz.instance_id = i.id
|
||||||
and uu.type in ('1','2','3')
|
where t.node_type = 1
|
||||||
) t
|
and t.del_flag = '0'
|
||||||
${ew.getCustomSqlSegment}
|
and uu.del_flag = '0'
|
||||||
|
and uu.type in ('1','2','3')
|
||||||
|
) t
|
||||||
|
${ew.getCustomSqlSegment}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 不分页版-->
|
<!-- 不分页版-->
|
||||||
@ -132,72 +135,78 @@
|
|||||||
|
|
||||||
<select id="getListFinishTask" resultMap="FlowHisTaskResult">
|
<select id="getListFinishTask" resultMap="FlowHisTaskResult">
|
||||||
select * from (
|
select * from (
|
||||||
select
|
select
|
||||||
a.id,
|
a.id,
|
||||||
a.node_code,
|
a.node_code,
|
||||||
a.node_name,
|
a.node_name,
|
||||||
a.cooperate_type,
|
a.cooperate_type,
|
||||||
a.approver,
|
a.approver,
|
||||||
a.collaborator,
|
a.collaborator,
|
||||||
a.node_type,
|
a.node_type,
|
||||||
a.target_node_code,
|
a.target_node_code,
|
||||||
a.target_node_name,
|
a.target_node_name,
|
||||||
a.definition_id,
|
a.definition_id,
|
||||||
a.instance_id,
|
a.instance_id,
|
||||||
a.flow_status flow_task_status,
|
a.flow_status flow_task_status,
|
||||||
a.message,
|
a.message,
|
||||||
a.ext,
|
a.ext,
|
||||||
a.create_time,
|
a.create_time,
|
||||||
a.update_time,
|
a.update_time,
|
||||||
a.tenant_id,
|
a.tenant_id,
|
||||||
a.form_custom,
|
a.form_custom,
|
||||||
a.form_path,
|
a.form_path,
|
||||||
b.flow_status,
|
b.flow_status,
|
||||||
b.business_id,
|
b.business_id,
|
||||||
b.create_by,
|
b.create_by,
|
||||||
c.flow_name,
|
c.flow_name,
|
||||||
c.flow_code,
|
c.flow_code,
|
||||||
c.category,
|
c.category,
|
||||||
c.version
|
c.version,
|
||||||
from flow_his_task a
|
biz.business_code,
|
||||||
left join flow_instance b on a.instance_id = b.id
|
biz.business_title
|
||||||
left join flow_definition c on a.definition_id = c.id
|
from flow_his_task a
|
||||||
where a.del_flag ='0'
|
left join flow_instance b on a.instance_id = b.id
|
||||||
and b.del_flag = '0'
|
left join flow_definition c on a.definition_id = c.id
|
||||||
and c.del_flag = '0'
|
left join flow_instance_biz_ext biz on biz.instance_id = b.id
|
||||||
and a.node_type in ('1','3','4')
|
where a.del_flag ='0'
|
||||||
) t
|
and b.del_flag = '0'
|
||||||
${ew.getCustomSqlSegment}
|
and c.del_flag = '0'
|
||||||
|
and a.node_type in ('1','3','4')
|
||||||
|
) t
|
||||||
|
${ew.getCustomSqlSegment}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="getTaskCopyByPage" resultMap="FlowTaskResult">
|
<select id="getTaskCopyByPage" resultMap="FlowTaskResult">
|
||||||
select * from (
|
select * from (
|
||||||
select
|
select
|
||||||
b.id,
|
b.id,
|
||||||
b.update_time,
|
b.update_time,
|
||||||
c.business_id,
|
c.business_id,
|
||||||
c.flow_status,
|
c.flow_status,
|
||||||
c.create_by,
|
c.create_by,
|
||||||
a.processed_by,
|
a.processed_by,
|
||||||
a.create_time,
|
a.create_time,
|
||||||
b.form_custom,
|
b.form_custom,
|
||||||
b.form_path,
|
b.form_path,
|
||||||
b.node_name,
|
b.node_name,
|
||||||
b.node_code,
|
b.node_code,
|
||||||
d.flow_name,
|
d.flow_name,
|
||||||
d.flow_code,
|
d.flow_code,
|
||||||
d.category,
|
d.category,
|
||||||
d.version
|
d.version,
|
||||||
from flow_user a
|
biz.business_code,
|
||||||
left join flow_his_task b on a.associated = b.task_id
|
biz.business_title
|
||||||
left join flow_instance c on b.instance_id = c.id
|
from flow_user a
|
||||||
left join flow_definition d on c.definition_id=d.id
|
left join flow_his_task b on a.associated = b.task_id
|
||||||
where a.type = '4'
|
left join flow_instance c on b.instance_id = c.id
|
||||||
and a.del_flag = '0'
|
left join flow_definition d on c.definition_id=d.id
|
||||||
and b.del_flag = '0'
|
left join flow_instance_biz_ext biz on biz.instance_id = c.id
|
||||||
and d.del_flag = '0'
|
where a.type = '4'
|
||||||
) t
|
and a.del_flag = '0'
|
||||||
${ew.getCustomSqlSegment}
|
and b.del_flag = '0'
|
||||||
|
and d.del_flag = '0'
|
||||||
|
) t
|
||||||
|
${ew.getCustomSqlSegment}
|
||||||
</select>
|
</select>
|
||||||
<select id="getListFinishDefinitionIdsTask" resultType="org.dromara.workflow.domain.vo.FlowHisTaskVo">
|
<select id="getListFinishDefinitionIdsTask" resultType="org.dromara.workflow.domain.vo.FlowHisTaskVo">
|
||||||
select * from (
|
select * from (
|
||||||
|
|||||||
93
xinnengyuan/script/sql/flowUpdate.sql
Normal file
93
xinnengyuan/script/sql/flowUpdate.sql
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
alter table flow_definition
|
||||||
|
add model_value varchar(40) default 'CLASSICS' null comment '设计器模型(CLASSICS经典模型 MIMIC仿钉钉模型)' after flow_code;
|
||||||
|
|
||||||
|
alter table flow_definition
|
||||||
|
add create_by varchar(64) default '' null comment '创建人' after create_time;
|
||||||
|
|
||||||
|
alter table flow_definition
|
||||||
|
add update_by varchar(64) default '' null comment '更新人' after update_time;
|
||||||
|
|
||||||
|
alter table flow_node
|
||||||
|
add create_by varchar(64) default '' null comment '创建人' after create_time;
|
||||||
|
|
||||||
|
alter table flow_node
|
||||||
|
add update_by varchar(64) default '' null comment '更新人' after update_time;
|
||||||
|
|
||||||
|
alter table flow_skip
|
||||||
|
add create_by varchar(64) default '' null comment '创建人' after create_time;
|
||||||
|
|
||||||
|
alter table flow_skip
|
||||||
|
add update_by varchar(64) default '' null comment '更新人' after update_time;
|
||||||
|
|
||||||
|
alter table flow_instance
|
||||||
|
add update_by varchar(64) default '' null comment '更新人' after update_time;
|
||||||
|
|
||||||
|
alter table flow_task
|
||||||
|
add create_by varchar(64) default '' null comment '创建人' after create_time;
|
||||||
|
|
||||||
|
alter table flow_task
|
||||||
|
add update_by varchar(64) default '' null comment '更新人' after update_time;
|
||||||
|
|
||||||
|
|
||||||
|
alter table flow_his_task
|
||||||
|
modify collaborator varchar(500) null comment '协作人';
|
||||||
|
|
||||||
|
alter table flow_user
|
||||||
|
add update_by varchar(64) default '' null comment '更新人' after update_time;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE flow_spel (
|
||||||
|
id bigint(20) NOT NULL COMMENT '主键id',
|
||||||
|
component_name varchar(255) DEFAULT NULL COMMENT '组件名称',
|
||||||
|
method_name varchar(255) DEFAULT NULL COMMENT '方法名',
|
||||||
|
method_params varchar(255) DEFAULT NULL COMMENT '参数',
|
||||||
|
view_spel varchar(255) DEFAULT NULL COMMENT '预览spel表达式',
|
||||||
|
remark varchar(255) DEFAULT NULL COMMENT '备注',
|
||||||
|
status char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||||
|
del_flag char(1) DEFAULT '0' COMMENT '删除标志',
|
||||||
|
create_dept bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||||
|
create_by bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||||
|
create_time datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
update_by bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||||
|
update_time datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
) ENGINE = InnoDB COMMENT='流程spel表达式定义表';
|
||||||
|
|
||||||
|
INSERT INTO flow_spel VALUES (1, 'spelRuleComponent', 'selectDeptLeaderById', 'initiatorDeptId', '#{@spelRuleComponent.selectDeptLeaderById(#initiatorDeptId)}', '根据部门id获取部门负责人', '0', '0', 103, 1, sysdate(), 1, sysdate());
|
||||||
|
INSERT INTO flow_spel VALUES (2, NULL, NULL, 'initiator', '${initiator}', '流程发起人', '0', '0', 103, 1, sysdate(), 1, sysdate());
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 流程实例业务扩展表
|
||||||
|
-- ----------------------------
|
||||||
|
|
||||||
|
create table flow_instance_biz_ext (
|
||||||
|
id bigint not null comment '主键id',
|
||||||
|
tenant_id varchar(20) default '000000' null comment '租户编号',
|
||||||
|
create_dept bigint null comment '创建部门',
|
||||||
|
create_by bigint null comment '创建者',
|
||||||
|
create_time datetime null comment '创建时间',
|
||||||
|
update_by bigint null comment '更新者',
|
||||||
|
update_time datetime null comment '更新时间',
|
||||||
|
business_code varchar(255) null comment '业务编码',
|
||||||
|
business_title varchar(1000) null comment '业务标题',
|
||||||
|
del_flag char default '0' null comment '删除标志(0代表存在 1代表删除)',
|
||||||
|
instance_id bigint null comment '流程实例Id',
|
||||||
|
business_id varchar(255) null comment '业务Id',
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
) ENGINE = InnoDB COMMENT '流程实例业务扩展表';
|
||||||
|
|
||||||
|
|
||||||
|
alter table test_leave
|
||||||
|
add apply_code varchar(50) null comment '申请编号' after tenant_id;
|
||||||
|
|
||||||
|
|
||||||
|
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache,
|
||||||
|
menu_type, visible, status, perms, icon, create_dept, create_by, create_time,
|
||||||
|
update_by, update_time, remark)
|
||||||
|
VALUES
|
||||||
|
('11802', '流程达式定义查询', '11801', 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:query', '#', 103, 1, sysdate(), NULL, NULL, ''),
|
||||||
|
('11803', '流程达式定义新增', '11801', 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:add', '#', 103, 1, sysdate(), NULL, NULL, ''),
|
||||||
|
('11804', '流程达式定义修改', '11801', 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:edit', '#', 103, 1, sysdate(), NULL, NULL, ''),
|
||||||
|
('11805', '流程达式定义删除', '11801', 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:remove', '#', 103, 1, sysdate(), NULL, NULL, ''),
|
||||||
|
('11806', '流程达式定义导出', '11801', 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:export', '#', 103, 1, sysdate(), NULL, NULL, '');
|
||||||
Reference in New Issue
Block a user