Compare commits

..

6 Commits

Author SHA1 Message Date
疯狂的狮子Li 0498ba2e41 fix 修复 防止tenantId出现sql注入问题 2026-08-17 18:04:58 +08:00
疯狂的狮子Li c3a83c11d5 update 优化 兼容企业微信 大小写返回不一致的奇葩问题 2026-07-22 19:12:43 +08:00
疯狂的狮子Li c29ecbd847 update 优化 删除流程实例同时删除抄送内容 2026-07-20 11:48:08 +08:00
疯狂的狮子Li e49f02f89e update 优化 异常处理 2026-06-23 11:37:58 +08:00
疯狂的狮子Li 89f4b7007a update 优化 基于流程变量优化退回选择问题 2026-06-22 16:47:13 +08:00
疯狂的狮子Li 88d03d970d update 优化 工作流管理页接口增加权限标识符 避免越权 2026-06-22 16:26:14 +08:00
9 changed files with 169 additions and 19 deletions
@@ -53,10 +53,15 @@ public abstract class AbstractAuthWeChatEnterpriseRequest extends AuthDefaultReq
// 返回 OpenId 或其他,均代表非当前企业用户,不支持
// https://github.com/justauth/JustAuth/issues/227 修复bug
if (!object.containsKey("userid")) {
String userId = null;
if (object.containsKey("userid")) {
userId = object.getString("userid");
} else if (object.containsKey("UserId")) {
userId = object.getString("UserId");
}
if (userId == null) {
throw new AuthException(AuthResponseStatus.UNIDENTIFIED_PLATFORM, source);
}
String userId = object.getString("userid");
String userTicket = object.getString("user_ticket");
JSONObject userDetail = getUserDetail(authToken.getAccessToken(), userId, userTicket);
@@ -8,6 +8,7 @@ import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.NullValue;
import net.sf.jsqlparser.expression.StringValue;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.sql.SqlUtil;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.tenant.properties.TenantProperties;
@@ -32,7 +33,7 @@ public class PlusTenantLineHandler implements TenantLineHandler {
return new NullValue();
}
// 返回固定租户
return new StringValue(tenantId);
return new StringValue(SqlUtil.escapeOrderBySql(tenantId));
}
@Override
@@ -1,5 +1,6 @@
package org.dromara.workflow.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.dto.StartProcessReturnDTO;
@@ -91,6 +92,7 @@ public class FlwTaskController extends BaseController {
* @param flowTaskBo 参数
* @param pageQuery 分页
*/
@SaCheckPermission("workflow:task:list")
@GetMapping("/pageByAllTaskWait")
public TableDataInfo<FlowTaskVo> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
return flwTaskService.pageByAllTaskWait(flowTaskBo, pageQuery);
@@ -102,6 +104,7 @@ public class FlwTaskController extends BaseController {
* @param flowTaskBo 参数
* @param pageQuery 分页
*/
@SaCheckPermission("workflow:task:list")
@GetMapping("/pageByAllTaskFinish")
public TableDataInfo<FlowHisTaskVo> pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
return flwTaskService.pageByAllTaskFinish(flowTaskBo, pageQuery);
@@ -171,6 +174,7 @@ public class FlwTaskController extends BaseController {
*/
@Log(title = "任务管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@SaCheckPermission("workflow:task:edit")
@PutMapping("/updateAssignee/{userId}")
public R<Void> updateAssignee(@RequestBody List<Long> taskIdList, @PathVariable String userId) {
return toAjax(flwTaskService.updateAssignee(taskIdList, userId));
@@ -217,6 +221,7 @@ public class FlwTaskController extends BaseController {
*/
@PostMapping("/urgeTask")
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@SaCheckPermission("workflow:task:edit")
public R<Void> urgeTask(@RequestBody FlowUrgeTaskBo bo) {
return toAjax(flwTaskService.urgeTask(bo));
}
@@ -195,7 +195,10 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
}
// 发送事件
processDeleteHandler(flowInstances);
return insService.remove(StreamUtils.toList(flowInstances, FlowInstance::getId));
List<Long> instanceIds = StreamUtils.toList(flowInstances, FlowInstance::getId);
// 删除抄送任务关联的用户记录
deleteCopyTaskUsers(instanceIds);
return insService.remove(instanceIds);
}
/**
@@ -214,8 +217,11 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
}
// 发送事件
processDeleteHandler(flowInstances);
List<Long> validInstanceIds = StreamUtils.toList(flowInstances, FlowInstance::getId);
// 删除抄送任务关联的用户记录
deleteCopyTaskUsers(validInstanceIds);
// 删除实例
return insService.remove(instanceIds);
return insService.remove(validInstanceIds);
}
/**
@@ -234,16 +240,56 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
}
// 发送事件
processDeleteHandler(flowInstances);
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);
List<Long> validInstanceIds = StreamUtils.toList(flowInstances, FlowInstance::getId);
List<FlowTask> flowTaskList = flwTaskService.selectByInstIds(validInstanceIds);
List<Long> taskIds = new ArrayList<>(StreamUtils.toList(flowTaskList, FlowTask::getId));
taskIds.addAll(selectCopyTaskIds(validInstanceIds));
deleteTaskUsers(taskIds);
FlowEngine.taskService().deleteByInsIds(validInstanceIds);
FlowEngine.hisTaskService().deleteByInsIds(validInstanceIds);
FlowEngine.insService().removeByIds(validInstanceIds);
return true;
}
/**
* 查询流程实例下的抄送任务id
*
* @param instanceIds 流程实例id
* @return 抄送任务id
*/
private List<Long> selectCopyTaskIds(List<Long> instanceIds) {
if (CollUtil.isEmpty(instanceIds)) {
return Collections.emptyList();
}
List<FlowHisTask> copyTaskList = flowHisTaskMapper.selectList(
new LambdaQueryWrapper<>(FlowHisTask.class)
.select(FlowHisTask::getTaskId)
.eq(FlowHisTask::getFlowStatus, TaskStatusEnum.COPY.getStatus())
.in(FlowHisTask::getInstanceId, instanceIds)
);
return StreamUtils.toList(copyTaskList, FlowHisTask::getTaskId);
}
/**
* 删除抄送任务关联的用户记录
*
* @param instanceIds 流程实例id
*/
private void deleteCopyTaskUsers(List<Long> instanceIds) {
deleteTaskUsers(selectCopyTaskIds(instanceIds));
}
/**
* 删除任务关联的用户记录
*
* @param taskIds 任务id
*/
private void deleteTaskUsers(List<Long> taskIds) {
if (CollUtil.isNotEmpty(taskIds)) {
FlowEngine.userService().deleteByTaskIds(taskIds);
}
}
private void processDeleteHandler(List<FlowInstance> flowInstances) {
@@ -29,12 +29,15 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.utils.IdGeneratorUtil;
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.dto.FlowCombine;
import org.dromara.warm.flow.core.dto.FlowParams;
import org.dromara.warm.flow.core.entity.*;
import org.dromara.warm.flow.core.enums.CooperateType;
import org.dromara.warm.flow.core.enums.NodeType;
import org.dromara.warm.flow.core.enums.SkipType;
import org.dromara.warm.flow.core.enums.UserType;
import org.dromara.warm.flow.core.exception.FlowException;
import org.dromara.warm.flow.core.service.*;
import org.dromara.warm.flow.core.utils.ExpressionUtil;
import org.dromara.warm.flow.core.utils.MapUtil;
@@ -544,16 +547,30 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), task.getDefinitionId());
}
//获取可驳回的前置节点
List<Node> nodes = nodeService.previousNodeList(task.getDefinitionId(), nowNodeCode);
Long definitionId = task.getDefinitionId();
FlowCombine flowCombine = defService.getFlowCombineNoDef(definitionId);
Map<String, Node> nodeMap = getPreviousNodeMap(nowNodeCode, flowCombine);
List<HisTask> hisTaskList = hisTaskService.getByInsId(task.getInstanceId());
Map<String, Node> nodeMap = StreamUtils.toIdentityMap(nodes, Node::getNodeCode);
Set<String> reachableNodeCodes = new HashSet<>();
if (CollUtil.isNotEmpty(hisTaskList)) {
Instance instance = insService.getById(task.getInstanceId());
if (ObjectUtil.isNull(instance)) {
throw new ServiceException("流程实例不存在");
}
collectReachableNodeCodes(reachableNodeCodes, instance, flowCombine);
if (!reachableNodeCodes.contains(nowNodeCode)) {
reachableNodeCodes.clear();
}
}
Set<String> added = new HashSet<>();
List<Node> backNodeList = new ArrayList<>();
for (HisTask hisTask : hisTaskList) {
Node nodeValue = nodeMap.get(hisTask.getNodeCode());
if (nodeValue != null
&& NodeType.BETWEEN.getKey().equals(nodeValue.getNodeType())
&& (CollUtil.isEmpty(reachableNodeCodes) || reachableNodeCodes.contains(nodeValue.getNodeCode()))
&& added.add(nodeValue.getNodeCode())) {
backNodeList.add(nodeValue);
}
@@ -562,7 +579,78 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
Collections.reverse(backNodeList);
return backNodeList;
}
return nodes;
if (CollUtil.isNotEmpty(hisTaskList)) {
return Collections.emptyList();
}
return StreamUtils.filter(nodeMap.values(), e -> NodeType.BETWEEN.getKey().equals(e.getNodeType()));
}
private Map<String, Node> getPreviousNodeMap(String nodeCode, FlowCombine flowCombine) {
if (ObjectUtil.isNull(flowCombine) || CollUtil.isEmpty(flowCombine.getAllNodes()) || CollUtil.isEmpty(flowCombine.getAllSkips())) {
return Collections.emptyMap();
}
Map<String, Node> allNodeMap = StreamUtils.toIdentityMap(flowCombine.getAllNodes(), Node::getNodeCode);
Map<String, List<Skip>> previousSkipMap = new HashMap<>();
for (Skip skip : flowCombine.getAllSkips()) {
previousSkipMap.computeIfAbsent(skip.getNextNodeCode(), k -> new ArrayList<>()).add(skip);
}
Map<String, Node> previousNodeMap = new LinkedHashMap<>();
Set<String> visitedNodeCodes = new HashSet<>();
Deque<String> nodeQueue = new ArrayDeque<>();
visitedNodeCodes.add(nodeCode);
nodeQueue.add(nodeCode);
while (CollUtil.isNotEmpty(nodeQueue)) {
String currentNodeCode = nodeQueue.poll();
List<Skip> previousSkips = previousSkipMap.get(currentNodeCode);
if (CollUtil.isEmpty(previousSkips)) {
continue;
}
for (Skip previousSkip : previousSkips) {
String previousNodeCode = previousSkip.getNowNodeCode();
if (!visitedNodeCodes.add(previousNodeCode)) {
continue;
}
Node previousNode = allNodeMap.get(previousNodeCode);
if (ObjectUtil.isNull(previousNode)) {
continue;
}
previousNodeMap.put(previousNodeCode, previousNode);
nodeQueue.add(previousNodeCode);
}
}
return previousNodeMap;
}
private void collectReachableNodeCodes(Set<String> nodeCodes, Instance instance, FlowCombine flowCombine) {
if (ObjectUtil.isNull(flowCombine) || CollUtil.isEmpty(flowCombine.getAllNodes())) {
return;
}
Deque<Node> nodeQueue = new ArrayDeque<>();
flowCombine.getAllNodes().stream()
.filter(e -> NodeType.START.getKey().equals(e.getNodeType()))
.findFirst()
.ifPresent(nodeQueue::add);
while (CollUtil.isNotEmpty(nodeQueue)) {
Node currentNode = nodeQueue.poll();
if (ObjectUtil.isNull(currentNode) || !nodeCodes.add(currentNode.getNodeCode())) {
continue;
}
try {
List<Node> nextNodes = nodeService.getNextNodeList(currentNode, null, SkipType.PASS.getKey(),
instance.getVariableMap(), null, flowCombine);
if (CollUtil.isNotEmpty(nextNodes)) {
nodeQueue.addAll(nextNodes);
}
} catch (FlowException e) {
// 条件变量缺失时跳过当前分支,其他引擎异常继续抛出。
if (!StringUtils.containsAny(e.getMessage(), ExceptionCons.NULL_CONDITION_VALUE, ExceptionCons.NULL_SKIP_TYPE)) {
throw e;
}
}
}
}
/**
+2 -1
View File
@@ -478,7 +478,8 @@ INSERT INTO sys_menu VALUES ('11621', '流程实例', '11630', '1', 'processInst
INSERT INTO sys_menu VALUES ('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, SYSDATE, NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', 'workflow:instance:currentList', 'guide', 103, 1, SYSDATE, NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11630', '流程监控', '11616', '4', 'processMonitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, SYSDATE, NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, SYSDATE, NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', 'workflow:task:list', 'waiting', 103, 1, SYSDATE, NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11660', '待办任务修改', '11631', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:task:edit', '#', 103, 1, SYSDATE, NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11700', '流程设计', '11616', '5', 'design/index', 'workflow/processDefinition/design', '', '1', '1', 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, SYSDATE, NULL, NULL, '/workflow/processDefinition');
INSERT INTO sys_menu VALUES ('11701', '请假申请', '11616', '6', 'leaveEdit/index', 'workflow/leave/leaveEdit', '', '1', '1', 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, SYSDATE, NULL, NULL, '');
+2 -1
View File
@@ -456,7 +456,8 @@ INSERT INTO sys_menu VALUES ('11621', '流程实例', '11630', '1', 'processInst
INSERT INTO sys_menu VALUES ('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', 'workflow:instance:currentList', 'guide', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11630', '流程监控', '11616', '4', 'processMonitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', 'workflow:task:list', 'waiting', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11660', '待办任务修改', '11631', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:task:edit', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu VALUES ('11700', '流程设计', '11616', '5', 'design/index', 'workflow/processDefinition/design', '', '1', '1', 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, now(), NULL, NULL, '/workflow/processDefinition');
INSERT INTO sys_menu VALUES ('11701', '请假申请', '11616', '6', 'leaveEdit/index', 'workflow/leave/leaveEdit', '', '1', '1', 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, now(), NULL, NULL, '');
+2 -1
View File
@@ -269,7 +269,8 @@ insert into sys_menu values ('11622', '流程分类', '11616', '1', 'category',
INSERT INTO sys_menu VALUES ('11801', '流程表达式', '11616', '2', 'spel', 'workflow/spel/index', '', 1, 0, 'C', '0', '0', 'workflow:spel:list', 'input', 103, 1, sysdate(), 1, sysdate(), '流程达式定义菜单');
insert into sys_menu values ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', 'workflow:instance:currentList', 'guide', 103, 1, sysdate(), NULL, NULL, '');
insert into sys_menu values ('11630', '流程监控', '11616', '4', 'processMonitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, sysdate(), NULL, NULL, '');
insert into sys_menu values ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, sysdate(), NULL, NULL, '');
insert into sys_menu values ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', 'workflow:task:list', 'waiting', 103, 1, sysdate(), NULL, NULL, '');
insert into sys_menu values ('11660', '待办任务修改', '11631', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:task:edit', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu values ('11700', '流程设计', '11616', '5', 'design/index', 'workflow/processDefinition/design', '', 1, 1, 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), null, null, '/workflow/processDefinition');
insert into sys_menu values ('11701', '请假申请', '11616', '6', 'leaveEdit/index', 'workflow/leave/leaveEdit', '', 1, 1, 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), null, null, '');
-- 流程分类管理相关按钮
@@ -1581,7 +1581,9 @@ INSERT sys_menu VALUES (11629, N'我发起的', 11618, 1, N'myDocument', N'workf
GO
INSERT sys_menu VALUES (11630, N'流程监控', 11616, 4, N'processMonitor', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'monitor', 103, 1, GETDATE(), NULL, NULL, N'');
GO
INSERT sys_menu VALUES (11631, N'待办任务', 11630, 2, N'allTaskWaiting', N'workflow/task/allTaskWaiting', N'', 1, 1, N'C', N'0', N'0', N'', N'waiting', 103, 1, GETDATE(), NULL, NULL, N'');
INSERT sys_menu VALUES (11631, N'待办任务', 11630, 2, N'allTaskWaiting', N'workflow/task/allTaskWaiting', N'', 1, 1, N'C', N'0', N'0', N'workflow:task:list', N'waiting', 103, 1, GETDATE(), NULL, NULL, N'');
GO
INSERT sys_menu VALUES (11660, N'待办任务修改', 11631, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:task:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N'');
GO
INSERT sys_menu VALUES (11700, N'流程设计', 11616, 5, N'design/index', N'workflow/processDefinition/design', N'', 1, 1, N'C', N'1', N'0', N'workflow:leave:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N'/workflow/processDefinition');
GO