wsm-修改xispeak督办计划流程
This commit is contained in:
@@ -31,5 +31,10 @@ public class XiSpeakConfig {
|
||||
private String implDeptCollectionUsedKey;
|
||||
/** 对应sdw-role-id*/
|
||||
private String sdwRoleId;
|
||||
/** 对应business-key*/
|
||||
private String businessKey;
|
||||
/** 对应impl-dept-key-underscore-key*/
|
||||
private String implDeptKeyUnderscoreKey;
|
||||
private String deptWorkerKey;
|
||||
}
|
||||
}
|
||||
|
||||
+46
-2
@@ -6,6 +6,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.util.StringUtils;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.jeecg.common.constant.SymbolConstant;
|
||||
import org.jeecg.common.system.api.ISysBaseAPI;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -83,8 +85,12 @@ public class XiSpeakFlow {
|
||||
} else {
|
||||
data = JSONObject.parseObject(JSONObject.toJSONString(jsonData));
|
||||
}
|
||||
log.info("needSdwApproval结果为{}", data.getInteger(codeName));
|
||||
return data == null ? 0 : data.getInteger(codeName);
|
||||
int finalResult = Optional.ofNullable(data)
|
||||
.map(d -> d.getInteger(codeName))
|
||||
.orElse(0);
|
||||
|
||||
log.info("needSdwApproval结果为{}", finalResult);
|
||||
return finalResult;
|
||||
} catch (Exception e) {
|
||||
log.warn("getJsondata parse failed, codeName={}, jsonData={}", codeName, jsonData, e);
|
||||
return 0;
|
||||
@@ -154,4 +160,42 @@ public class XiSpeakFlow {
|
||||
|
||||
return resultList.size();
|
||||
}
|
||||
|
||||
public List<String> getDeptWorkerList(DelegateExecution execution) {
|
||||
String variableName = xiSpeakConfig.getXiSpeak().getDeptWorkerKey();
|
||||
if (execution == null || org.apache.commons.lang.StringUtils.isBlank(variableName)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. 优先尝试从当前 Execution 的局部作用域获取
|
||||
// 在多实例(会签)中,每个分支特有的变量(如 item 变量)通常存储在这里
|
||||
Object value = execution.getVariableLocal(variableName);
|
||||
|
||||
// 2. 如果局部没有,直接使用 getVariable 获取
|
||||
// 该方法会自动向上追溯:当前 Execution -> 父 Execution -> 流程实例(Global)
|
||||
if (value == null) {
|
||||
value = execution.getVariable(variableName);
|
||||
}
|
||||
|
||||
// 3. 结果处理
|
||||
if (value != null) {
|
||||
return splitUsernames(value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("getSonProcessVariable 失败, executionId={}, variableName={}",
|
||||
execution.getId(), variableName, e);
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
private List<String> splitUsernames(Object value) {
|
||||
if (value == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Arrays.stream(String.valueOf(value).split(SymbolConstant.COMMA))
|
||||
.map(String::trim)
|
||||
.filter(org.apache.commons.lang.StringUtils::isNotBlank)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
package org.jeecg.xispeak.listener;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
import org.jeecg.modules.bg.xispeak.entity.BgXiSpeak;
|
||||
import org.jeecg.modules.bg.xispeak.entity.DeptApproveDetail;
|
||||
import org.jeecg.modules.bg.xispeak.service.IBgXiSpeakService;
|
||||
import org.jeecg.modules.extbpm.process.common.expression.FlowNodeExpression;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.delegate.ExecutionListener;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.modules.extbpm.process.common.WorkFlowGlobals;
|
||||
import org.jeecg.modules.tasktask.entity.TaskTask;
|
||||
import org.jeecg.modules.tasktask.service.ITaskTaskService;
|
||||
import org.jeecg.xispeak.XiSpeakConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component("AfterImplDeptLeaderApproveListener")
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
public class AfterImplDeptLeaderApproveListener implements TaskListener {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final FlowNodeExpression flowNodeExpression;
|
||||
private final RuntimeService runtimeService;
|
||||
private final XiSpeakConfig xiSpeakConfig;
|
||||
private final ITaskTaskService taskTaskService;
|
||||
private final IBgXiSpeakService bgXiSpeakService;
|
||||
|
||||
// @Override
|
||||
// @Transactional(rollbackFor = Exception.class)
|
||||
// public void notify(DelegateTask delegateTask) {
|
||||
//
|
||||
// // 1. 获取审批人
|
||||
// String currentAssignee = delegateTask.getAssignee();
|
||||
// if (StringUtils.isEmpty(currentAssignee)) {
|
||||
// // 使用你给出的正确获取方式:扫描 Execution 树获取局部变量
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 2. 获取业务主键:通常业务 ID 是全局变量,可以直接 getVariable
|
||||
// Object rawTaskTaskId = delegateTask.getVariable(xiSpeakConfig.getXiSpeak().getBusinessKey());
|
||||
//
|
||||
// if (StringUtils.isEmpty(currentAssignee) || rawTaskTaskId == null) {
|
||||
// log.warn("无法获取有效的审批人或业务ID,ExecutionId: {}, TaskId: {}",
|
||||
// delegateTask.getExecutionId(), delegateTask.getId());
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 3. 获取业务实体
|
||||
// BgXiSpeak xiSpeak = bgXiSpeakService.getById(rawTaskTaskId.toString());
|
||||
// if (xiSpeak == null) return;
|
||||
//
|
||||
// // 4. 处理数据结构
|
||||
// Map<String, DeptApproveDetail> deptApproveDetailMap = Optional.ofNullable(xiSpeak.getApproveInfo())
|
||||
// .orElse(new HashMap<>());
|
||||
//
|
||||
// // 5. 获取实施部门 ID:同样使用全路径搜索,确保在嵌套会签中能精准定位局部变量
|
||||
// String implDeptKey = xiSpeakConfig.getXiSpeak().getImplDeptCollectionUsedKey();
|
||||
// String rawDeptVar = delegateTask.getVariable(implDeptKey).toString();
|
||||
//
|
||||
// if (StringUtils.isBlank(rawDeptVar)) {
|
||||
// throw new RuntimeException("流程数据异常:未找到实施部门ID变量: " + implDeptKey);
|
||||
// }
|
||||
//
|
||||
// // 清洗字符串(处理 [id1, id2] 格式)
|
||||
// String cleanDeptId = rawDeptVar.replace("[", "").replace("]", "").trim();
|
||||
//
|
||||
// // computeIfAbsent 的特性:如果 key 存在,返回 value;如果不存在,运行 lambda 并存入再返回。
|
||||
// DeptApproveDetail detail = deptApproveDetailMap.computeIfAbsent(cleanDeptId, k -> new DeptApproveDetail());
|
||||
//
|
||||
// // 2. 只有当 approverName 为空时(即该对象是刚新建的,或者之前没存过审批人),才进行赋值
|
||||
// if (StringUtils.isBlank(detail.getApproverName())) {
|
||||
// detail.setApproverName(currentAssignee);
|
||||
//
|
||||
// // 3. 只有发生了赋值,才执行数据库更新(可选,为了性能)
|
||||
// xiSpeak.setApproveInfo(deptApproveDetailMap);
|
||||
// bgXiSpeakService.updateById(xiSpeak);
|
||||
// log.info("部门 {} 首次审批,已记录审批人: {}", cleanDeptId, currentAssignee);
|
||||
// } else {
|
||||
// log.info("部门 {} 已存在审批记录: {},跳过本次回写", cleanDeptId, detail.getApproverName());
|
||||
// }
|
||||
// }
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void notify(DelegateTask delegateTask) {
|
||||
// 1. 获取基础数据
|
||||
String currentAssignee = delegateTask.getAssignee();
|
||||
Object rawTaskTaskId = delegateTask.getVariable(xiSpeakConfig.getXiSpeak().getBusinessKey());
|
||||
String implDeptKey = xiSpeakConfig.getXiSpeak().getImplDeptCollectionUsedKey();
|
||||
String rawDeptVar = delegateTask.getVariable(implDeptKey).toString();
|
||||
String cleanDeptId = rawDeptVar.replace("[", "").replace("]", "").trim();
|
||||
|
||||
// 2. 【核心】使用行锁查询,确保拿到的是数据库此刻最真实、最新的数据
|
||||
// 同时也让其他并发的审批线程在这里“排队”等待
|
||||
BgXiSpeak xiSpeak = bgXiSpeakService.getByIdForUpdate(rawTaskTaskId.toString());
|
||||
if (xiSpeak == null) return;
|
||||
|
||||
// 3. 操作 Map
|
||||
Map<String, DeptApproveDetail> map = xiSpeak.getApproveInfo();
|
||||
if (map == null) map = new HashMap<>();
|
||||
|
||||
// 4. 获取或创建详情对象
|
||||
// 使用你定义的 POJO
|
||||
DeptApproveDetail detail = map.getOrDefault(cleanDeptId, new DeptApproveDetail());
|
||||
|
||||
// 只有没审批过才记录(防止重复触发覆盖已有数据)
|
||||
if (StringUtils.isBlank(detail.getApproverName())) {
|
||||
detail.setDeptId(cleanDeptId);
|
||||
detail.setApproverName(currentAssignee);
|
||||
// 这里可以根据需要设置其他字段,比如 detail.setApproverId(...)
|
||||
|
||||
map.put(cleanDeptId, detail);
|
||||
xiSpeak.setApproveInfo(map);
|
||||
|
||||
// 5. 写回数据库
|
||||
// 因为有了 FOR UPDATE,这里的更新绝对是基于最新数据的增量合并
|
||||
bgXiSpeakService.updateById(xiSpeak);
|
||||
}
|
||||
}
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
package org.jeecg.xispeak.listener;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
import org.jeecg.modules.bg.xispeak.entity.BgXiSpeak;
|
||||
import org.jeecg.modules.bg.xispeak.entity.DeptApproveDetail;
|
||||
import org.jeecg.modules.bg.xispeak.service.IBgXiSpeakService;
|
||||
import org.jeecg.modules.extbpm.process.common.expression.FlowNodeExpression;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.delegate.ExecutionListener;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.modules.extbpm.process.common.WorkFlowGlobals;
|
||||
import org.jeecg.modules.tasktask.entity.TaskTask;
|
||||
import org.jeecg.modules.tasktask.service.ITaskTaskService;
|
||||
import org.jeecg.xispeak.XiSpeakConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@Slf4j
|
||||
@Component("AfterImplWorkerApproveListener")
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
public class AfterImplWorkerApproveListener implements TaskListener {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final XiSpeakConfig xiSpeakConfig;
|
||||
private final IBgXiSpeakService bgXiSpeakService;
|
||||
|
||||
// 引入 Jackson 的 ObjectMapper 用于处理类型转换失败的情况
|
||||
private final com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void notify(DelegateTask delegateTask) {
|
||||
String currentWorkerName = delegateTask.getAssignee();
|
||||
Object rawBusinessKey = delegateTask.getVariable(xiSpeakConfig.getXiSpeak().getBusinessKey());
|
||||
|
||||
if (StringUtils.isEmpty(currentWorkerName) || rawBusinessKey == null) {
|
||||
log.warn("无法获取有效的审批人或业务ID,略过处理");
|
||||
return;
|
||||
}
|
||||
|
||||
BgXiSpeak xiSpeak = bgXiSpeakService.getByIdForUpdate(rawBusinessKey.toString());
|
||||
if (xiSpeak == null) {
|
||||
log.error("业务数据不存在: {}", rawBusinessKey);
|
||||
return;
|
||||
}
|
||||
|
||||
String implDeptKey = xiSpeakConfig.getXiSpeak().getImplDeptCollectionUsedKey();
|
||||
Object rawDeptVar = delegateTask.getVariableLocal(implDeptKey);
|
||||
if (rawDeptVar == null) {
|
||||
rawDeptVar = delegateTask.getVariable(implDeptKey);
|
||||
}
|
||||
|
||||
if (rawDeptVar == null) {
|
||||
log.error("流程数据异常:未找到实施部门ID变量: {}", implDeptKey);
|
||||
return;
|
||||
}
|
||||
|
||||
String cleanDeptId = rawDeptVar.toString().replace("[", "").replace("]", "").trim();
|
||||
|
||||
// --- 修改开始:处理复杂的 Map 转换问题 ---
|
||||
|
||||
// 1. 获取原始 Map (这里使用通配符,避免直接强转报错)
|
||||
Map<String, Object> rawApproveMap = (Map) xiSpeak.getApproveInfo();
|
||||
if (rawApproveMap == null) {
|
||||
rawApproveMap = new HashMap<>();
|
||||
}
|
||||
|
||||
// 2. 获取该部门对应的详情,并进行安全类型检查
|
||||
Object rawDetail = rawApproveMap.get(cleanDeptId);
|
||||
DeptApproveDetail detail;
|
||||
|
||||
if (rawDetail == null) {
|
||||
// 情况 A: 部门记录不存在,新建
|
||||
detail = new DeptApproveDetail();
|
||||
detail.setDeptId(cleanDeptId);
|
||||
detail.setImplUserNameList(new ArrayList<>());
|
||||
rawApproveMap.put(cleanDeptId, detail);
|
||||
} else if (rawDetail instanceof DeptApproveDetail) {
|
||||
// 情况 B: 类型正确,直接使用
|
||||
detail = (DeptApproveDetail) rawDetail;
|
||||
} else {
|
||||
// 情况 C: 就是你遇到的报错点!类型是 LinkedHashMap,需要转换
|
||||
log.debug("检测到 LinkedHashMap 类型,执行手动转换...");
|
||||
detail = objectMapper.convertValue(rawDetail, DeptApproveDetail.class);
|
||||
// 转换后放回 Map,防止后续逻辑再次触发转换
|
||||
rawApproveMap.put(cleanDeptId, detail);
|
||||
}
|
||||
|
||||
// --- 修改结束 ---
|
||||
|
||||
// 5. 更新落实人列表
|
||||
List<String> workerList = detail.getImplUserNameList();
|
||||
if (workerList == null) {
|
||||
workerList = new ArrayList<>();
|
||||
}
|
||||
|
||||
if (!workerList.contains(currentWorkerName)) {
|
||||
workerList.add(currentWorkerName);
|
||||
detail.setImplUserNameList(workerList);
|
||||
|
||||
// 重新写回 Map 并保存
|
||||
// 声明:虽然 rawApproveMap 里的 Value 是 Object,但写回数据库时 TypeHandler 会处理它
|
||||
xiSpeak.setApproveInfo((Map) rawApproveMap);
|
||||
bgXiSpeakService.updateById(xiSpeak);
|
||||
log.info("部门 {} 经办人审批记录更新成功: {}", cleanDeptId, currentWorkerName);
|
||||
} else {
|
||||
log.info("部门 {} 经办人 {} 已在列表中,跳过更新", cleanDeptId, currentWorkerName);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.jeecg.modules.extbpm.listener.execution;
|
||||
package org.jeecg.xispeak.listener;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.modules.extbpm.process.common.expression.FlowNodeExpression;
|
||||
|
||||
@@ -5,5 +5,10 @@ flow-biz:
|
||||
need-sdw-approve-code: "needSdwApproval"
|
||||
json-data-key: "json_data"
|
||||
impl-dept-key: "implDept"
|
||||
impl-dept-key-underscore-key: "impl_dept"
|
||||
impl-dept-collection-used-key: "impl_dept_id"
|
||||
sdw-role-id: "2044676455280570370"
|
||||
business-key: "business_id"
|
||||
dept-worker-key: "subApproveUser"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user