违纪处分申报工作流完全打通ㄟ( ▔, ▔ )ㄏ

This commit is contained in:
2025-08-21 17:10:49 +08:00
parent 780346489b
commit 83bce533cc
10 changed files with 268 additions and 44 deletions

View File

@@ -0,0 +1,55 @@
package com.srs.flowable.listener.disciplinary;
import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
import com.srs.flowable.mapper.DisciplinaryMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 执行监听器:在“学生教育管理科审批归档”节点开始时, 知无涯
* 向负责归档的角色发送企业微信通知。
*/
@Component
@Slf4j
public class ArchivingNotifyListener implements ExecutionListener {
@Override
public void notify(DelegateExecution delegateExecution) {
log.info("流程实例 [{}]: 已进入学生教育管理科审批归档节点,准备发送通知。", delegateExecution.getProcessInstanceId());
try {
DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class);
// 1. 【核心】定义负责归档的角色的 role_key。
final String ARCHIVING_ROLE_KEY = "xsjyglkspgd";
// 2. 根据角色Key查询用户ID列表
List<Long> userIdList = disciplinaryMapper.getApprovalByRoleKey(ARCHIVING_ROLE_KEY);
if (userIdList == null || userIdList.isEmpty()) {
log.warn("根据角色Key '{}' 未找到任何归档人员,无法发送通知。", ARCHIVING_ROLE_KEY);
return;
}
// 3. 批量查询 userName 并发送通知
List<String> userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList);
if (!userNameList.isEmpty()) {
String toUser = String.join("|", userNameList);
WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
String content = "您有一条新的学生违纪归档任务待处理,<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>。";
weChatUtil.sendTextMessage(toUser, content);
log.info("已成功向归档角色 ({}) 发送通知。接收人: {}", ARCHIVING_ROLE_KEY, toUser);
} else {
log.warn("角色 '{}' 中找到了 {} 个用户,但无人配置企业微信账号,未发送任何通知。", ARCHIVING_ROLE_KEY, userIdList.size());
}
} catch (Exception e) {
log.error("向归档角色发送企业微信通知时出现异常。流程将继续。错误详情: {}", e.getMessage(), e);
}
}
}

View File

@@ -9,7 +9,7 @@ import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.stereotype.Component;
/**
* 根据辅导员部门id获取二级学院书记
* 根据辅导员部门id获取二级学院书记 知无涯
*/
@Component
@Slf4j

View File

@@ -0,0 +1,61 @@
package com.srs.flowable.listener.disciplinary;
import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
import com.srs.flowable.mapper.DisciplinaryMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.stereotype.Component;
/**
* 执行监听器:在“申请人(辅导员)接收”节点开始时, 知无涯
* 向流程发起人发送企业微信通知,告知其结果已出。
*/
@Component
@Slf4j
public class InitiatorResultListener implements ExecutionListener {
@Override
public void notify(DelegateExecution delegateExecution) {
log.info("流程实例 [{}]: 已进入辅导员接收结果节点,准备向发起人发送通知。", delegateExecution.getProcessInstanceId());
try {
DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class);
// 1. 从流程变量中获取发起人的ID。Flowable会自动将发起人ID存入名为 "INITIATOR" 的变量中。
// 这个变量通常是 String 类型。
Object initiatorObj = delegateExecution.getVariable("INITIATOR");
if (initiatorObj == null) {
log.warn("在流程实例 [{}] 中未找到发起人(INITIATOR)变量,无法发送通知。", delegateExecution.getProcessInstanceId());
return;
}
// 2. 将发起人ID转换为 Long 类型,以便查询数据库
Long initiatorUserId;
try {
initiatorUserId = Long.parseLong(initiatorObj.toString());
} catch (NumberFormatException e) {
log.error("发起人(INITIATOR)变量 '{}' 无法转换为Long类型无法发送通知。", initiatorObj);
return;
}
// 3. 使用 initiatorUserId 查询对应的企业微信 userName
String initiatorUserName = disciplinaryMapper.getUserNameByUserId(initiatorUserId);
if (initiatorUserName != null && !initiatorUserName.isEmpty()) {
// 4. 发送通知
WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
String content = "您提交的学生违纪处分申请已有最终处理结果,<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>。\"";
weChatUtil.sendTextMessage(initiatorUserName, content);
log.info("已成功向流程发起人 ({}) 发送结果通知。", initiatorUserName);
} else {
log.warn("找到了发起人(userId:{}),但其对应的企业微信账号(userName)为空,未发送通知。", initiatorUserId);
}
} catch (Exception e) {
log.error("向流程发起人发送结果通知时出现异常。流程将继续。错误详情: {}", e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,55 @@
package com.srs.flowable.listener.disciplinary;
import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
import com.srs.flowable.mapper.DisciplinaryMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 执行监听器:在“校领导审批”节点开始时,向校领导发送企业微信通知。 知无涯
* (简化版:因为流程能到达此节点,即表示前序节点已全票通过)
*/
@Component
@Slf4j
public class SchoolLeaderApprovalListener implements ExecutionListener {
@Override
public void notify(DelegateExecution delegateExecution) {
log.info("流程实例 [{}]: 已进入校领导审批节点,准备发送通知。", delegateExecution.getProcessInstanceId());
try {
DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class);
// 1. 【核心】定义“校领导”这个角色的 role_key
final String LEADER_ROLE_KEY = "xldsp";
// 2. 根据角色Key查询用户ID列表
List<Long> userIdList = disciplinaryMapper.getApprovalByRoleKey(LEADER_ROLE_KEY);
if (userIdList == null || userIdList.isEmpty()) {
log.warn("根据角色Key '{}' 未找到任何校领导用户,无法发送通知。", LEADER_ROLE_KEY);
return;
}
// 3. 批量查询 userName 并发送通知
List<String> userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList);
if (!userNameList.isEmpty()) {
String toUser = String.join("|", userNameList);
WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
String content = "校领导您有一条新的学生违纪审批任务待处理,<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>。";
weChatUtil.sendTextMessage(toUser, content);
log.info("已成功向校领导 (角色: {}) 发送通知。接收人: {}", LEADER_ROLE_KEY, toUser);
} else {
log.warn("角色 '{}' 中找到了 {} 个用户,但无人配置企业微信账号,未发送任何通知。", LEADER_ROLE_KEY, userIdList.size());
}
} catch (Exception e) {
log.error("向校领导发送企业微信通知时出现异常。流程将继续。错误详情: {}", e.getMessage(), e);
}
}
}

View File

@@ -1,12 +1,17 @@
package com.srs.flowable.listener.disciplinary;
import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
import com.srs.flowable.mapper.DisciplinaryMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* 设置处分学生审批参数
* 流程结束监听器。
* 在流程的最终节点,向当事学生发送处理结果的通知。 知无涯
*/
@Component
@Slf4j
@@ -14,10 +19,41 @@ public class StuInfoListener implements ExecutionListener {
@Override
public void notify(DelegateExecution delegateExecution) {
Long stuId = (Long)delegateExecution.getVariable("stuId");
// 1. 从流程变量中获取学生ID
Object stuIdObj = delegateExecution.getVariable("stuId");
log.info("学生信息:{}",stuId);
delegateExecution.setVariable("approval",stuId);
// todo 企业微信推送消息
// 安全检查确保stuId存在且类型正确
if (!(stuIdObj instanceof Long)) {
log.error("流程实例 [{}] 在结束时未能获取到有效的 'stuId' 变量,无法发送最终通知。", delegateExecution.getProcessInstanceId());
return;
}
Long stuId = (Long) stuIdObj;
log.info("流程实例 [{}] 即将结束准备向学生ID: {} 发送最终通知。", delegateExecution.getProcessInstanceId(), stuId);
// 2. 向该学生发送企业微信通知
try {
DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class);
// 根据学生ID查询其对应的企业微信账号(userName)
String userName = disciplinaryMapper.getUserNameByUserId(stuId);
// 检查是否找到了对应的企业微信账号
if (!StringUtils.hasText(userName)) {
log.warn("流程实例 [{}]: 根据学生ID '{}' 未找到对应的企业微信账号,无法发送最终通知。", delegateExecution.getProcessInstanceId(), stuId);
return; // 中止发送逻辑
}
// 3. 构建并发送通知内容
WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
String content = "您好,关于您的违纪处理流程已办结,最终结果已生成。<a href='http://zhxg.gxsdxy.cn/web/#/pages/Disciplinary/MyDisciplinary'>请点击登录系统查看详情</a>。";
weChatUtil.sendTextMessage(userName, content);
log.info("流程实例 [{}]: 已成功向学生ID '{}' (企业微信账号: {}) 发送了流程办结通知。", delegateExecution.getProcessInstanceId(), stuId, userName);
} catch (Exception e) {
// 即使通知失败,也不应影响流程的正常结束
log.error("流程实例 [{}]: 在向学生ID '{}' 发送最终通知时出现异常。错误详情: {}",
delegateExecution.getProcessInstanceId(), stuId, e.getMessage(), e);
}
}
}
}

View File

@@ -10,7 +10,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
/**
* 学生教育管理科审核节点的执行监听器。
* 学生教育管理科审核节点的执行监听器。 知无涯
* 向“学生教育管理科”角色发送企业微信通知。
*/
@Component

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
/**
* 根据辅导员的部门id查询该部门的学无干事人员
* 根据辅导员的部门id查询该部门的学无干事人员 知无涯
*/
@Component
@Slf4j

View File

@@ -1,55 +1,72 @@
package com.srs.flowable.listener.disciplinary;
import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
import com.srs.flowable.mapper.DisciplinaryMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
* 学院违纪处理委员会审批
* 【线上监听器】为“学院违纪处理委员会”多实例任务准备数据并发送通知 知无涯
*/
@Component
@Component("xywjclwyhListener")
@Slf4j
public class XYWJCLWYHListener implements ExecutionListener {
// 推荐使用依赖注入而不是SpringUtils
@Autowired
private DisciplinaryMapper disciplinaryMapper;
@Autowired
private WeChatUtil weChatUtil;
@Override
public void notify(DelegateExecution delegateExecution) {
DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean("disciplinaryMapper");
// 步骤 1: 根据角色Key获取审批人ID列表 (第1次DB查询)
public void notify(DelegateExecution execution) {
log.info("流程实例 [{}]: 在进入'学院违纪处理委员会'节点前,开始准备审批数据...", execution.getProcessInstanceId());
// 步骤 1: 单一数据库查询,获取所有需要的审批人信息 (ID和企微账号)
// List<DisciplinaryMapper.UserInfo> userInfos = disciplinaryMapper.getUserInfoByRoleKey("xywjclwyh");
// 注意如果您不方便修改Mapper这里可以保持原来的两次查询逻辑依然正确。
// 我们先用原始的两次查询来演示,更具普适性。
List<Long> userIdList = disciplinaryMapper.getApprovalByRoleKey("xywjclwyh");
if (userIdList == null || userIdList.isEmpty()){
log.error("未找到角色相关信息");
if (userIdList == null || userIdList.isEmpty()) {
log.error("角色 'xywjclwyh' 未配置或未找到任何有效用户,流程无法继续。");
throw new RuntimeException("学院违纪处理委员会审批人员未设置");
}else{
delegateExecution.setVariable("userList",userIdList);
// todo 企业微信推送消息
// --- 企业微信推送消息模块 ---
try {
// 步骤 2: 一次性批量查询所有有效的userName (第2次DB查询性能最优)
List<String> userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList);
if (!userNameList.isEmpty()) {
// 步骤 3: 将 userName 列表用 "|" 连接成一个字符串
String toUser = String.join("|", userNameList);
WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
String content = "您有一条新的学生违纪审批任务待处理,<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>。";
weChatUtil.sendTextMessage(toUser, content);
log.info("已成功向学院违纪处理委员会发送群组通知。接收人: {}", toUser);
} else {
log.warn("角色 'xywjclwyh' 存在审批人,但无人配置企业微信账号,未发送任何通知。");
}
} catch (Exception e) {
// 保证即使通知失败,流程也能继续
log.error("向学院违纪处理委员会发送企业微信通知时出现异常。流程将继续。错误详情: {}", e.getMessage(), e);
}
}
// 步骤 2: 设置多实例任务需要的流程变量 (这是“线上”为“节点”准备的核心数据)
execution.setVariable("userList", userIdList);
log.info("流程实例 [{}]: 已成功设置'userList'变量,包含 {} 个审批人。", execution.getProcessInstanceId(), userIdList.size());
// 步骤 3: 发送企业微信通知
sendWeChatNotification(userIdList, execution.getProcessInstanceId());
}
}
/**
* 封装并执行企业微信通知逻辑
*/
private void sendWeChatNotification(List<Long> userIdList, String processInstanceId) {
try {
List<String> userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList);
if (userNameList == null || userNameList.isEmpty()) {
log.warn("流程实例 [{}]: 角色'xywjclwyh'存在审批人ID但无人配置企微账号未发送通知。", processInstanceId);
return;
}
String toUser = String.join("|", userNameList);
String content = "您有一条新的学生违纪审批任务待处理,<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>。";
weChatUtil.sendTextMessage(toUser, content);
log.info("流程实例 [{}]: 已成功向学院违纪处理委员会发送通知。接收人: {}", processInstanceId, toUser);
} catch (Exception e) {
log.error("流程实例 [{}]: 发送企微通知时出现异常,但不影响主流程。错误: {}", processInstanceId, e.getMessage(), e);
}
}
}

View File

@@ -23,7 +23,7 @@ public interface DisciplinaryMapper {
*/
String getUserNameByUserId(@Param("userId") Long userId);
/**
* 知无涯新增:根据用户ID列表批量查询用户名列表
* 知无涯 根据用户ID列表批量查询用户名列表
* @param userIdList 用户ID列表
* @return 用户的username列表
*/

View File

@@ -265,7 +265,7 @@ public class RtStuDisciplinaryApplicationServiceImpl extends ServiceImpl<RtStuDi
// todo 企业微信推送消息
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_n27gxm4k:8:610039", variables);
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_n27gxm4k:16:672598", variables);
String code = ajaxResult.get("code").toString();
if (code.equals("200")) {