diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/enlistmentReserve/ApprovalAssigneeListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/enlistmentReserve/ApprovalAssigneeListener.java
index c2ddf88..a32f56e 100644
--- a/srs-flowable/src/main/java/com/srs/flowable/listener/enlistmentReserve/ApprovalAssigneeListener.java
+++ b/srs-flowable/src/main/java/com/srs/flowable/listener/enlistmentReserve/ApprovalAssigneeListener.java
@@ -5,12 +5,15 @@ import com.srs.common.core.domain.entity.SysUser;
import com.srs.common.doman.vo.TeacherVo;
import com.srs.common.utils.SecurityUtils;
+import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
import com.srs.flowable.domain.EnlistmentReserve;
import com.srs.flowable.domain.EnlistmentReserveApproval;
import com.srs.flowable.mapper.EnlistmentReserveApprovalMapper;
import com.srs.flowable.mapper.EnlistmentReserveMapper;
+import com.srs.flowable.mapper.RelieveMapper;
import com.srs.system.service.ISysUserService;
+import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.engine.HistoryService;
@@ -28,9 +31,10 @@ import java.util.List;
/**
* 审批流程负责人自动流转监听器
- * 用于节点审批通过时,添加审批记录
+ * 用于节点审批通过时,添加审批记录 + 给学生发送企业微信通知
*/
@Component("approvalAssigneeListener") // Spring Bean名称,与BPMN表达式对应
+@Slf4j
public class ApprovalAssigneeListener implements ExecutionListener {
@Autowired
@@ -103,8 +107,89 @@ public class ApprovalAssigneeListener implements ExecutionListener {
// 改变申请表中的审核状态(审核通过)
enlistmentReserve.setApplyStatus(status);
rtEnlistmentReserveMapper.updateRtEnlistmentReserve(enlistmentReserve);
+ // ========== 给学生发送入伍保留学籍审批通知 ==========
+ sendStudentWeChatNotification(execution, enlistmentReserve, currentNodeName, approvalResult, approvalOpinion);
}
+ /**
+ * 给学生发送入伍保留学籍审批结果的企业微信通知
+ */
+ private void sendStudentWeChatNotification(DelegateExecution execution, EnlistmentReserve enlistmentReserve,
+ String currentNodeName, Long approvalResult, String approvalOpinion) {
+ try {
+ // 1. 获取需要的Mapper和工具类
+ RelieveMapper relieveMapper = (RelieveMapper) SpringUtils.getBean("relieveMapper");
+ WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
+
+ // 2. 获取学生基础信息
+ String studentNo = enlistmentReserve.getStudentNo();
+ String studentName = enlistmentReserve.getStudentName();
+
+ // 3. 获取学生userId(优先从流程变量取)
+ Long stuUserId = null;
+ if (execution.hasVariable("stuUserId")) {
+ stuUserId = Long.valueOf(execution.getVariable("stuUserId").toString());
+ } else {
+ // 兜底:通过申请表获取学生id
+ stuUserId = enlistmentReserve.getStudentId();
+ }
+
+ if (stuUserId == null) {
+ log.warn("⚠ 未找到学生(学号:{},姓名:{})对应的用户ID,无法发送通知", studentNo, studentName);
+ return;
+ }
+
+ // 4. 查询学生的企业微信账号
+ String stuUserName = relieveMapper.getUserNameByUserId(stuUserId);
+
+ if (stuUserName != null && !stuUserName.isEmpty()) {
+ // 5. 拼接审批结果描述
+ String approveResultDesc = getApprovalResultDesc(approvalResult, currentNodeName);
+
+ // 6. 构造通知内容
+ String content = String.format("您的入伍保留学籍申请有新的审批进展:%s(%s),%s,点此查看详情",
+ currentNodeName,
+ approveResultDesc,
+ (approvalOpinion != null && !approvalOpinion.isEmpty()) ? "审批意见:" + approvalOpinion : "");
+
+ // 7. 发送企业微信消息
+ weChatUtil.sendTextMessage(stuUserName, content);
+ log.info("✅ 已成功向学生(姓名:{},学号:{},userName:{})发送入伍保留学籍审批通知。审批节点:{},结果:{}",
+ studentName, studentNo, stuUserName, currentNodeName, approveResultDesc);
+
+ } else {
+ // 发送日志
+ log.warn("⚠ 找到了学生(学号:{},姓名:{},userId:{}),但其对应的企业微信账号为空,无法发送通知。",
+ studentNo, studentName, stuUserId);
+ }
+ } catch (Exception e) {
+ // 异常处理:记录日志+不影响主流程
+ String studentNo = enlistmentReserve.getStudentNo();
+ log.error("❌ 向学生(学号:{})发送入伍保留学籍审批通知时出现异常,但流程将继续。错误详情:", studentNo, e);
+ }
+ }
+
+ /**
+ * 转换审批结果为可读描述(适配入伍保留学籍审批状态)
+ */
+ private String getApprovalResultDesc(Long approvalResult, String currentNodeName) {
+ if (approvalResult == null) {
+ return "审批已处理";
+ }
+ // 匹配项目中实际的审批状态值(0=驳回/1=通过/2=审批中)
+ switch (approvalResult.intValue()) {
+ case 0:
+ return currentNodeName + "驳回";
+ case 1:
+ return currentNodeName + "通过";
+ case 2:
+ return "审批中";
+ default:
+ return "审批已完成";
+ }
+ }
+
+
/**
* 根据节点ID和流程定义ID,查询节点名称(兼容所有版本的核心方法)
*/
diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/enlistmentReserve/StartApprovalAssigneeListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/enlistmentReserve/StartApprovalAssigneeListener.java
index ae55c20..9ed55d4 100644
--- a/srs-flowable/src/main/java/com/srs/flowable/listener/enlistmentReserve/StartApprovalAssigneeListener.java
+++ b/srs-flowable/src/main/java/com/srs/flowable/listener/enlistmentReserve/StartApprovalAssigneeListener.java
@@ -4,13 +4,18 @@ import com.srs.common.core.domain.entity.SysUser;
import com.srs.common.doman.vo.TeacherVo;
+import com.srs.common.utils.DateUtils;
import com.srs.common.utils.SecurityUtils;
+import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
import com.srs.flowable.domain.EnlistmentReserve;
import com.srs.flowable.domain.EnlistmentReserveApproval;
+import com.srs.flowable.domain.NotificationManage;
import com.srs.flowable.mapper.EnlistmentReserveApprovalMapper;
import com.srs.flowable.mapper.EnlistmentReserveMapper;
+import com.srs.flowable.mapper.LeaveMapper;
import com.srs.system.service.ISysUserService;
+import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.engine.HistoryService;
@@ -31,6 +36,7 @@ import java.util.List;
* 用于节点审批之前时,更新下一个节点的负责人变量(approval)
*/
@Component("startApprovalAssigneeListener") // Spring Bean名称,与BPMN表达式对应
+@Slf4j
public class StartApprovalAssigneeListener implements ExecutionListener {
@Autowired
@@ -46,7 +52,7 @@ public class StartApprovalAssigneeListener implements ExecutionListener {
String currentActivityId = execution.getCurrentActivityId(); // 当前节点ID(兼容所有版本)
String processDefinitionId = execution.getProcessDefinitionId(); // 流程定义ID
- // 2. 根据节点ID查询节点名称(核心修正:通过流程定义获取名称)
+ // 2. 根据节点ID查询节点名称(通过流程定义获取名称)
String currentNodeName = getNodeNameByActivityId(processDefinitionId, currentActivityId);
if (currentNodeName == null) {
throw new RuntimeException("未找到节点ID=" + currentActivityId + "的名称");
@@ -61,6 +67,8 @@ public class StartApprovalAssigneeListener implements ExecutionListener {
if (nextAssigneeId != null) {
execution.setVariable("approval", nextAssigneeId);
execution.setVariable("currentNode", currentNodeName);
+ // ========== 发送通知逻辑 ==========
+ sendApprovalNotification(execution, currentNodeName, nextAssigneeId, enlistmentId);
}
}
@@ -174,4 +182,99 @@ public class StartApprovalAssigneeListener implements ExecutionListener {
throw new RuntimeException("未配置节点[" + currentNodeName + "]的当前负责人规则");
}
}
+
+ /**
+ * 发送审批通知(系统通知+企业微信通知)
+ */
+ private void sendApprovalNotification(DelegateExecution execution, String currentNodeName,
+ Long nextAssigneeId, Long enlistmentId) {
+ try {
+ // 获取需要的Mapper和工具类
+ EnlistmentReserveMapper enlistmentReserveMapper = (EnlistmentReserveMapper) SpringUtils.getBean(EnlistmentReserveMapper.class);
+ LeaveMapper leaveMapper = (LeaveMapper) SpringUtils.getBean("leaveMapper");
+ WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
+
+ // 1. 查询入伍保留学籍申请详情
+ EnlistmentReserve enlistmentReserve = enlistmentReserveMapper.selectRtEnlistmentReserveById(enlistmentId);
+ if (enlistmentReserve == null) {
+ log.warn("未找到入伍保留学籍申请记录,ID:{}", enlistmentId);
+ return;
+ }
+
+ // 2. 查询下一个审批人的信息(获取用户名/工号)
+ SysUser nextApprover = sysUserService.selectUserById(nextAssigneeId);
+ if (nextApprover == null) {
+ log.warn("未找到审批人信息,用户ID:{}", nextAssigneeId);
+ return;
+ }
+ String approverUserName = nextApprover.getUserName(); // 审批人工号/用户名
+ String approverName = nextApprover.getNickName(); // 审批人姓名
+
+ log.info("开始发送【入伍保留学籍审批】通知,审批节点:{},审批人:{}({})",
+ currentNodeName, approverName, approverUserName);
+
+ // 3. 处理系统通知(先删后加,避免重复通知)
+ NotificationManage notificationManage = new NotificationManage();
+ notificationManage.setContent(String.format("您有一条【入伍保留学籍审批】待处理(节点:%s)", currentNodeName));
+ notificationManage.setReceiver(nextAssigneeId); // 接收人:下一个审批人
+
+ // 3.1 查询是否已有相同通知,有则删除
+ NotificationManage existNotify = leaveMapper.selectCphMsgListForFlowable(notificationManage);
+ if (existNotify != null) {
+ int delRes = leaveMapper.deleteCphMsgById(existNotify.getId());
+ log.info("删除重复的系统通知,通知ID:{},删除结果:{}", existNotify.getId(), delRes);
+ }
+
+ // 3.2 添加新的系统通知
+ notificationManage.setSender(SecurityUtils.getUserId()); // 发送人:当前操作人
+ notificationManage.setCreateTime(DateUtils.getNowDate()); // 创建时间
+ int addRes = leaveMapper.insertCphMsg(notificationManage);
+ log.info("新增系统通知成功,接收人ID:{},添加结果:{}", nextAssigneeId, addRes);
+
+ // 4. 企业微信推送消息
+ if (approverUserName != null && !approverUserName.isEmpty()) {
+ // 构造带超链接的消息内容
+ String weChatContent = String.format(
+ "您有一条【入伍保留学籍审批】待处理(节点:%s),请点击前往处理",
+ currentNodeName
+ );
+
+ // 发送企业微信文本消息
+ weChatUtil.sendTextMessage(approverUserName, weChatContent);
+ log.info("企业微信通知发送成功,接收人工号:{},节点:{}", approverUserName, currentNodeName);
+ } else {
+ log.warn("审批人工号为空,无法发送企业微信通知,用户ID:{}", nextAssigneeId);
+ }
+
+ // ========== 删除当前审批人的待处理通知 ==========
+ // 4.1 获取当前审批人ID(当前操作人=已完成审批的人)
+ Long currentApproverId = SecurityUtils.getUserId();
+ if (currentApproverId == null) {
+ log.warn("当前审批人ID为空,无法删除其待处理通知");
+ return;
+ }
+
+ // 4.2 构造当前审批人的待处理通知查询条件
+ NotificationManage currentNotifyQuery = new NotificationManage();
+ // 内容匹配:当前节点的待处理通知(关键词+节点名称)
+ currentNotifyQuery.setContent(String.format("您有一条【入伍保留学籍审批】待处理(节点:%s)", currentNodeName));
+ currentNotifyQuery.setReceiver(currentApproverId); // 接收人=当前审批人
+
+ // 4.3 查询当前审批人的该节点待处理通知
+ NotificationManage currentExistNotify = leaveMapper.selectCphMsgListForFlowable(currentNotifyQuery);
+ if (currentExistNotify != null) {
+ // 4.4 删除该通知(清理已处理的待办)
+ int currentDelRes = leaveMapper.deleteCphMsgById(currentExistNotify.getId());
+ log.info("删除当前审批人({})的【{}】待处理通知,通知ID:{},删除结果:{}",
+ currentApproverId, currentNodeName, currentExistNotify.getId(), currentDelRes);
+ } else {
+ log.info("当前审批人({})无【{}】节点的待处理通知,无需删除", currentApproverId, currentNodeName);
+ }
+
+ } catch (Exception e) {
+ // 捕获所有异常,仅记录日志,不影响主流程
+ log.error("发送入伍保留学籍审批通知失败,节点:{},审批人ID:{},错误信息:{}",
+ currentNodeName, nextAssigneeId, e.getMessage(), e);
+ }
+ }
}
\ No newline at end of file
diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/outsideAccommodation/OutsideAccommodationEndListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/outsideAccommodation/OutsideAccommodationEndListener.java
index 2613247..7f7dbe3 100644
--- a/srs-flowable/src/main/java/com/srs/flowable/listener/outsideAccommodation/OutsideAccommodationEndListener.java
+++ b/srs-flowable/src/main/java/com/srs/flowable/listener/outsideAccommodation/OutsideAccommodationEndListener.java
@@ -2,12 +2,15 @@ package com.srs.flowable.listener.outsideAccommodation;
import com.srs.common.utils.SecurityUtils;
+import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
import com.srs.flowable.domain.DormitoryStudent;
import com.srs.flowable.domain.OutsideAccommodationApply;
import com.srs.flowable.domain.OutsideAccommodationApproval;
import com.srs.flowable.mapper.OutsideAccommodationApplyMapper;
import com.srs.flowable.mapper.OutsideAccommodationApprovalMapper;
+import com.srs.flowable.mapper.RelieveMapper;
+import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.engine.RepositoryService;
@@ -21,9 +24,10 @@ import java.util.Date;
/**
* 审批流程负责人自动流转监听器
- * 用于节点审批通过时,添加审批记录
+ * 用于节点审批通过时,添加审批记录 + 给学生发送企业微信通知
*/
@Component("OutsideAccommodationEndListener") // Spring Bean名称,与BPMN表达式对应
+@Slf4j
public class OutsideAccommodationEndListener implements ExecutionListener {
// 用于查询流程定义中的节点信息
@@ -36,7 +40,7 @@ public class OutsideAccommodationEndListener implements ExecutionListener {
String currentActivityId = execution.getCurrentActivityId(); // 当前节点ID(兼容所有版本)
String processDefinitionId = execution.getProcessDefinitionId(); // 流程定义ID
- // 2. 根据节点ID查询节点名称(核心修正:通过流程定义获取名称)
+ // 2. 根据节点ID查询节点名称(通过流程定义获取名称)
String currentNodeName = getNodeNameByActivityId(processDefinitionId, currentActivityId);
if (currentNodeName == null) {
throw new RuntimeException("未找到节点ID=" + currentActivityId + "的名称");
@@ -88,6 +92,84 @@ public class OutsideAccommodationEndListener implements ExecutionListener {
}
outsideAccommodationApply.setStatus(status);
outsideAccommodationApplyMapper.updateDmsOutsideAccommodationApply(outsideAccommodationApply);
+ // ========== 给学生发送企业微信通知 ==========
+ sendStudentWeChatNotification(execution, outsideAccommodationApply, currentNodeName, approvalResult, approvalOpinion);
+ }
+
+ /**
+ * 给学生发送外宿申请审批结果的企业微信通知
+ */
+ private void sendStudentWeChatNotification(DelegateExecution execution, OutsideAccommodationApply outsideAccommodationApply,
+ String currentNodeName, Long approvalResult, String approvalOpinion) {
+ try {
+ // 1. 获取需要的Mapper和工具类
+ RelieveMapper relieveMapper = (RelieveMapper) SpringUtils.getBean("relieveMapper");
+ WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
+
+ // 2. 获取学生学号和姓名(从外宿申请对象中获取)
+ String studentNo = outsideAccommodationApply.getStudentNo();
+ String studentName = outsideAccommodationApply.getStudentName();
+
+ // 3. 先尝试从流程变量获取学生userId
+ Long stuUserId = null;
+ if (execution.hasVariable("stuUserId")) {
+ stuUserId = Long.valueOf(execution.getVariable("stuUserId").toString());
+ } else {
+ // 补充逻辑:如果流程变量中没有stuUserId,通过申请表获取
+ stuUserId = outsideAccommodationApply.getStudentId();
+ }
+
+ if (stuUserId == null) {
+ log.warn("⚠ 未找到学生(学号:{},姓名:{})对应的用户ID,无法发送通知", studentNo, studentName);
+ return;
+ }
+
+ // 4. 使用userId查询对应的企业微信账号
+ String stuUserName = relieveMapper.getUserNameByUserId(stuUserId);
+
+ if (stuUserName != null && !stuUserName.isEmpty()) {
+ // 5. 拼接审批结果提示信息(适配外宿申请场景)
+ String approveResultDesc = getApprovalResultDesc(approvalResult, currentNodeName);
+
+ // 6. 拼接最终通知内容
+ String content = String.format("您的外宿申请有新的审批进展:%s(%s),%s,点此查看详情",
+ currentNodeName,
+ approveResultDesc,
+ (approvalOpinion != null && !approvalOpinion.isEmpty()) ? "审批意见:" + approvalOpinion : "");
+
+ // 7. 发送企业微信消息
+ weChatUtil.sendTextMessage(stuUserName, content);
+ log.info("✅ 已成功向学生(姓名:{},学号:{},userName:{})发送外宿申请审批通知。审批节点:{},结果:{}",
+ studentName, studentNo, stuUserName, currentNodeName, approveResultDesc);
+
+ } else {
+ log.warn("⚠ 找到了学生(学号:{},姓名:{},userId:{}),但其对应的企业微信账号为空,无法发送通知。",
+ studentNo, studentName, stuUserId);
+ }
+ } catch (Exception e) {
+ // 捕获所有异常,仅记录日志,不影响主流程
+ String studentNo = outsideAccommodationApply.getStudentNo();
+ log.error("❌ 向学生(学号:{})发送外宿申请审批通知时出现异常,但流程将继续。错误详情:", studentNo, e);
+ }
+ }
+
+ /**
+ * 转换审批结果为可读描述(适配外宿申请的审批状态)
+ */
+ private String getApprovalResultDesc(Long approvalResult, String currentNodeName) {
+ if (approvalResult == null) {
+ return "审批已处理";
+ }
+ switch (approvalResult.intValue()) {
+ case 0:
+ return currentNodeName + "驳回";
+ case 1:
+ return currentNodeName + "通过";
+ case 2:
+ return "审批中";
+ default:
+ return "审批已完成";
+ }
}
/**
diff --git a/srs-flowable/src/main/java/com/srs/flowable/listener/outsideAccommodation/OutsideAccommodationStartListener.java b/srs-flowable/src/main/java/com/srs/flowable/listener/outsideAccommodation/OutsideAccommodationStartListener.java
index 557c172..2aebd5b 100644
--- a/srs-flowable/src/main/java/com/srs/flowable/listener/outsideAccommodation/OutsideAccommodationStartListener.java
+++ b/srs-flowable/src/main/java/com/srs/flowable/listener/outsideAccommodation/OutsideAccommodationStartListener.java
@@ -2,13 +2,19 @@ package com.srs.flowable.listener.outsideAccommodation;
import com.srs.common.core.domain.entity.SysUser;
import com.srs.common.doman.vo.TeacherVo;
+import com.srs.common.utils.DateUtils;
+import com.srs.common.utils.SecurityUtils;
+import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
import com.srs.dormitory.domain.DmsOutsideAccommodationApply;
import com.srs.flowable.domain.EnlistmentReserve;
+import com.srs.flowable.domain.NotificationManage;
import com.srs.flowable.domain.OutsideAccommodationApply;
import com.srs.flowable.mapper.EnlistmentReserveMapper;
+import com.srs.flowable.mapper.LeaveMapper;
import com.srs.flowable.mapper.OutsideAccommodationApplyMapper;
import com.srs.system.service.ISysUserService;
+import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.engine.RepositoryService;
@@ -25,6 +31,7 @@ import java.util.List;
* 用于节点审批之前时,更新下一个节点的负责人变量(approval)
*/
@Component("OutsideAccommodationStartListener") // Spring Bean名称,与BPMN表达式对应
+@Slf4j
public class OutsideAccommodationStartListener implements ExecutionListener {
@Autowired
@@ -40,7 +47,7 @@ public class OutsideAccommodationStartListener implements ExecutionListener {
String currentActivityId = execution.getCurrentActivityId(); // 当前节点ID(兼容所有版本)
String processDefinitionId = execution.getProcessDefinitionId(); // 流程定义ID
- // 2. 根据节点ID查询节点名称(核心修正:通过流程定义获取名称)
+ // 2. 根据节点ID查询节点名称(通过流程定义获取名称)
String currentNodeName = getNodeNameByActivityId(processDefinitionId, currentActivityId);
if (currentNodeName == null) {
throw new RuntimeException("未找到节点ID=" + currentActivityId + "的名称");
@@ -55,6 +62,8 @@ public class OutsideAccommodationStartListener implements ExecutionListener {
if (nextAssigneeId != null) {
execution.setVariable("approval", nextAssigneeId);
execution.setVariable("currentNode", currentNodeName);
+ // ========== 外宿申请审批通知逻辑 ==========
+ sendOutsideAccommodationNotification(execution, currentNodeName, nextAssigneeId, accommodationId);
}
}
@@ -168,4 +177,98 @@ public class OutsideAccommodationStartListener implements ExecutionListener {
throw new RuntimeException("未配置节点[" + currentNodeName + "]的当前负责人规则");
}
}
+ /**
+ * 发送外宿申请审批通知(系统通知+企业微信通知)
+ */
+ private void sendOutsideAccommodationNotification(DelegateExecution execution, String currentNodeName,
+ Long nextAssigneeId, Long accommodationId) {
+ try {
+ // 获取需要的Mapper和工具类
+ OutsideAccommodationApplyMapper outsideAccommodationApplyMapper = SpringUtils.getBean(OutsideAccommodationApplyMapper.class);
+ LeaveMapper leaveMapper = (LeaveMapper) SpringUtils.getBean("leaveMapper");
+ WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
+
+ // 1. 查询外宿申请详情
+ com.srs.flowable.domain.OutsideAccommodationApply outsideAccommodationApply = outsideAccommodationApplyMapper.selectDmsOutsideAccommodationApplyById(accommodationId);
+ if (outsideAccommodationApply == null) {
+ log.warn("未找到外宿申请记录,ID:{}", accommodationId);
+ return;
+ }
+
+ // 2. 查询下一个审批人的信息(获取用户名/工号)
+ SysUser nextApprover = sysUserService.selectUserById(nextAssigneeId);
+ if (nextApprover == null) {
+ log.warn("未找到审批人信息,用户ID:{}", nextAssigneeId);
+ return;
+ }
+ String approverUserName = nextApprover.getUserName(); // 审批人工号/用户名
+ String approverName = nextApprover.getNickName(); // 审批人姓名
+
+ log.info("开始发送【外宿申请审批】通知,审批节点:{},审批人:{}({})",
+ currentNodeName, approverName, approverUserName);
+
+ // 3. 处理系统通知(先删后加,避免重复通知)
+ NotificationManage notificationManage = new NotificationManage();
+ notificationManage.setContent(String.format("您有一条【外宿申请审批】待处理(节点:%s)", currentNodeName));
+ notificationManage.setReceiver(nextAssigneeId); // 接收人:下一个审批人
+
+ // 3.1 查询是否已有相同通知,有则删除
+ NotificationManage existNotify = leaveMapper.selectCphMsgListForFlowable(notificationManage);
+ if (existNotify != null) {
+ int delRes = leaveMapper.deleteCphMsgById(existNotify.getId());
+ log.info("删除重复的系统通知,通知ID:{},删除结果:{}", existNotify.getId(), delRes);
+ }
+
+ // 3.2 添加新的系统通知
+ notificationManage.setSender(SecurityUtils.getUserId() != null ? SecurityUtils.getUserId() : 0L); // 发送人:当前操作人(兜底处理)
+ notificationManage.setCreateTime(DateUtils.getNowDate()); // 创建时间
+ int addRes = leaveMapper.insertCphMsg(notificationManage);
+ log.info("新增系统通知成功,接收人ID:{},添加结果:{}", nextAssigneeId, addRes);
+
+ // 4. 企业微信推送消息
+ if (approverUserName != null && !approverUserName.isEmpty()) {
+ // 构造带超链接的消息内容
+ String weChatContent = String.format(
+ "您有一条【外宿申请审批】待处理(节点:%s),请点击前往处理",
+ currentNodeName
+ );
+
+ // 发送企业微信文本消息
+ weChatUtil.sendTextMessage(approverUserName, weChatContent);
+ log.info("企业微信通知发送成功,接收人工号:{},节点:{}", approverUserName, currentNodeName);
+ } else {
+ log.warn("审批人工号为空,无法发送企业微信通知,用户ID:{}", nextAssigneeId);
+ }
+
+ // ========== 删除当前审批人的待处理通知 ==========
+ // 4.1 获取当前审批人ID(当前操作人=已完成审批的人)
+ Long currentApproverId = SecurityUtils.getUserId();
+ if (currentApproverId == null) {
+ log.warn("当前审批人ID为空,无法删除其待处理通知");
+ return;
+ }
+
+ // 4.2 构造当前审批人的待处理通知查询条件
+ NotificationManage currentNotifyQuery = new NotificationManage();
+ // 内容匹配:当前节点的待处理通知(关键词+节点名称)
+ currentNotifyQuery.setContent(String.format("您有一条【外宿申请审批】待处理(节点:%s)", currentNodeName));
+ currentNotifyQuery.setReceiver(currentApproverId); // 接收人=当前审批人
+
+ // 4.3 查询当前审批人的该节点待处理通知
+ NotificationManage currentExistNotify = leaveMapper.selectCphMsgListForFlowable(currentNotifyQuery);
+ if (currentExistNotify != null) {
+ // 4.4 删除该通知(清理已处理的待办)
+ int currentDelRes = leaveMapper.deleteCphMsgById(currentExistNotify.getId());
+ log.info("删除当前审批人({})的【{}】待处理通知,通知ID:{},删除结果:{}",
+ currentApproverId, currentNodeName, currentExistNotify.getId(), currentDelRes);
+ } else {
+ log.info("当前审批人({})无【{}】节点的待处理通知,无需删除", currentApproverId, currentNodeName);
+ }
+
+ } catch (Exception e) {
+ // 捕获所有异常,仅记录日志,不影响主流程
+ log.error("发送外宿申请审批通知失败,节点:{},审批人ID:{},错误信息:{}",
+ currentNodeName, nextAssigneeId, e.getMessage(), e);
+ }
+ }
}
\ No newline at end of file