Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -4,11 +4,14 @@ import com.srs.common.core.controller.BaseController;
|
||||
import com.srs.common.core.domain.AjaxResult;
|
||||
import com.srs.common.core.domain.entity.SysUser;
|
||||
import com.srs.common.core.domain.model.LoginUser;
|
||||
import com.srs.common.core.page.TableDataInfo;
|
||||
import com.srs.common.utils.WeChatUtil;
|
||||
import com.srs.framework.web.service.TokenService;
|
||||
import com.srs.system.domain.StudentMentalRating;
|
||||
import com.srs.system.domain.vo.StudentMentalRatingVo;
|
||||
import com.srs.system.mapper.StudentMentalRatingMapper;
|
||||
import com.srs.system.mapper.SysUserMapper;
|
||||
import com.srs.system.service.ISysPostService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -38,6 +41,9 @@ public class WeChatMentalAlertController extends BaseController {
|
||||
private TokenService tokenService;
|
||||
@Autowired
|
||||
private StudentMentalRatingMapper studentMentalRatingMapper;
|
||||
//岗位
|
||||
@Autowired
|
||||
private ISysPostService sysPostService;
|
||||
|
||||
/**
|
||||
* 处理心理预警通知请求
|
||||
@@ -134,11 +140,27 @@ public class WeChatMentalAlertController extends BaseController {
|
||||
/**
|
||||
* 获取全部学生心理评级记录
|
||||
*/
|
||||
/**
|
||||
* 获取全部学生心理评级记录(支持条件查询和分页)
|
||||
*/
|
||||
@GetMapping("/rating/all")
|
||||
public AjaxResult allRatings() {
|
||||
return AjaxResult.success(studentMentalRatingMapper.selectAll());
|
||||
}
|
||||
public TableDataInfo allRatings(StudentMentalRatingVo queryVo) {
|
||||
// 获取当前登录用户信息
|
||||
String teacherId = getUsername();
|
||||
Long userId = getUserId();
|
||||
// 判断是否为学工
|
||||
boolean isJwc = RoleBool.isJwc(userId, sysPostService);
|
||||
|
||||
startPage();
|
||||
|
||||
if (isJwc) {
|
||||
return getDataTable(studentMentalRatingMapper.selectLatestAllWithConditions(
|
||||
queryVo.getStuNo(), queryVo.getStuName()));
|
||||
} else {
|
||||
return getDataTable(studentMentalRatingMapper.selectLatestByTeacherIdWithConditions(
|
||||
teacherId, queryVo.getStuNo(), queryVo.getStuName()));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 根据学号获取全部记录
|
||||
*/
|
||||
|
||||
@@ -528,18 +528,6 @@
|
||||
select concat('zsg-',count(a.id)) as `all`
|
||||
from knzz_zsg_apply as a
|
||||
where a.apply_status = 3
|
||||
# 宁博-辅导员管理--成果绩效----待办 (第3步:科室复核 和 第4步:学工处长终审)
|
||||
union
|
||||
select concat('cg-',count(a.check_id)) as `all`
|
||||
from sys_teacher_achievementcheck as a
|
||||
left join sys_user as b on a.teacher_id = b.user_name
|
||||
where a.check_status in (3, 4)
|
||||
-- 陈冠元 辅导员业绩考核-科室复核待办-学工处长审核待办
|
||||
union
|
||||
select concat('yj-',count(a.id)) as `all`
|
||||
from sys_teacher_kpi_filling as a
|
||||
left join sys_user as b on a.job_number = b.user_name
|
||||
where a.role_audit in (3, 4)
|
||||
</select>
|
||||
|
||||
<select id="countStuUnDo" resultType="String" parameterType="String">
|
||||
@@ -786,7 +774,7 @@
|
||||
select concat('zsfy-',count(a.id)) as `all`
|
||||
from dms_new_record as a
|
||||
left join view_dms_record as d on a.stu_no = d.stu_no
|
||||
where d.employee_id = #{tNo} and a.apply_status = 6
|
||||
where d.employee_id = #{tNo} and a.apply_status = 6 and a.apply_status = 1
|
||||
</select>
|
||||
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<!-- 班级信息 -->
|
||||
<select id="selectDeptByDeptCodes" parameterType="String" resultType="com.srs.comprehensive.domain.SrsClass">
|
||||
SELECT DISTINCT v.class_id,v.class_name
|
||||
FROM srs_dev.view_stu_info v
|
||||
FROM view_stu_info v
|
||||
JOIN srs_class c ON v.teacher_id = c.teacher_id
|
||||
WHERE v.t_no = #{userName}
|
||||
</select>
|
||||
|
||||
@@ -26,29 +26,34 @@ public class EJXYSJListener implements ExecutionListener {
|
||||
if (userId!=null){
|
||||
delegateExecution.setVariable("approval", userId);
|
||||
// todo 企业微信推送消息
|
||||
// --- 企业微信推送消息模块 ---
|
||||
/**
|
||||
* 庞世斌
|
||||
*/
|
||||
try {
|
||||
// 步骤 2: 【关键】使用 userId 查询对应的企业微信账号 (userName)
|
||||
// 步骤 2: 使用 userId 查询对应的企业微信账号 (userName)
|
||||
String userName = disciplinaryMapper.getUserNameByUserId(userId);
|
||||
|
||||
// 步骤 3: 检查 userName 是否存在
|
||||
// 步骤 3: 检查是否成功获取到 userName
|
||||
if (userName != null && !userName.isEmpty()) {
|
||||
WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
|
||||
|
||||
// 构造包含超链接的消息内容
|
||||
String content = "您有一条新的学生违纪审批任务待处理,<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>。";
|
||||
String content = "您有一条新的学生违纪审批任务待处理," +
|
||||
"<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>";
|
||||
|
||||
// 步骤 4: 【关键】使用 userName 作为接收人发送消息
|
||||
// 步骤 4: 使用 userName 作为接收人发送消息
|
||||
weChatUtil.sendTextMessage(userName, content);
|
||||
log.info("已成功向二级学院书记(userName:{})发送企业微信审批通知。", userName);
|
||||
log.info("已成功向学务干事(userName:{})发送企业微信审批通知。", userName);
|
||||
|
||||
} else {
|
||||
// 如果找不到userName,记录警告日志,但流程继续
|
||||
log.warn("找到了二级学院书记审批人(userId:{}),但其对应的企业微信账号(userName)为空,无法发送通知。", userId);
|
||||
log.warn("找到了审批人(userId:{}),但其对应的企业微信账号(userName)为空,无法发送通知。", userId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 保证即使通知失败,流程也能继续
|
||||
log.error("向二级学院书记(userId:{})发送企业微信通知时出现异常。流程将继续。错误详情: {}", userId, e.getMessage(), e);
|
||||
// 捕获所有异常,仅记录日志,确保主流程不受影响
|
||||
log.error("向学务干事(userId:{})发送企业微信通知时出现异常,但流程将继续。错误详情: {}", userId, e.getMessage(), e);
|
||||
}
|
||||
|
||||
}else{
|
||||
throw new RuntimeException("该二级学院书记审批人未配置");
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 【通用线上监听器】为即将到来的任务创建内部“我的消息”记录。 知无涯1
|
||||
* 【通用线上监听器】为即将到来的任务创建内部“我的消息”记录。 知无涯
|
||||
* <p>
|
||||
* 该监听器被设计为在SequenceFlow的'take'事件上触发。
|
||||
* 它会智能地从流程变量中读取单个接收人(变量名: approval)或多个接收人(变量名: userList),
|
||||
@@ -44,7 +44,7 @@ public class GenericMessageListener implements ExecutionListener {
|
||||
String taskName = execution.getCurrentFlowElement() != null ? execution.getCurrentFlowElement().getName() : "新";
|
||||
|
||||
// --- 关键改动:构建带有隐藏标识的消息内容 ---
|
||||
String messageText = "您有一条新的【" + taskName + "】待办任务需要处理,";
|
||||
String messageText = "您有一条新的【" + taskName + "】待办任务需要处理";
|
||||
// 我们嵌入一个隐藏的span,它包含了流程实例ID和活动ID作为唯一标识
|
||||
String hiddenIdentifier = String.format("<span id='flow-identifier' data-proc-inst-id='%s' data-activity-id='%s' style='display:none;'></span>",
|
||||
execution.getProcessInstanceId(),
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.srs.flowable.listener.disciplinary;
|
||||
import com.srs.common.utils.SecurityUtils;
|
||||
import com.srs.common.utils.WeChatUtil;
|
||||
import com.srs.comprehensive.domain.CphMsg;
|
||||
import com.srs.comprehensive.service.ICphMsgService;
|
||||
import com.srs.flowable.mapper.DisciplinaryMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.SequenceFlow;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.delegate.ExecutionListener;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 【线上专用监听器】在流程结果返回给发起人时,
|
||||
* 负责发送企业微信和内部消息两种通知。
|
||||
*/
|
||||
@Component("initiatorNotificationListener") // 使用一个全新的、明确的Bean名称
|
||||
@Slf4j
|
||||
public class InitiatorNotificationListener implements ExecutionListener {
|
||||
|
||||
@Autowired
|
||||
private DisciplinaryMapper disciplinaryMapper;
|
||||
|
||||
@Autowired
|
||||
private ICphMsgService cphMsgService;
|
||||
|
||||
@Autowired(required = false) // 允许WeChatUtil为null,增加灵活性
|
||||
private WeChatUtil weChatUtil;
|
||||
|
||||
@Override
|
||||
public void notify(DelegateExecution execution) {
|
||||
log.info("流程实例 [{}]: 触发 InitiatorNotificationListener,准备向发起人发送整合通知...", execution.getProcessInstanceId());
|
||||
|
||||
// --- 1. 获取核心数据:发起人ID ---
|
||||
Object initiatorObj = execution.getVariable("INITIATOR");
|
||||
if (initiatorObj == null) {
|
||||
log.error("在流程实例 [{}] 中未找到发起人(INITIATOR)变量,无法发送任何通知。", execution.getProcessInstanceId());
|
||||
return;
|
||||
}
|
||||
|
||||
Long initiatorUserId;
|
||||
try {
|
||||
initiatorUserId = Long.parseLong(initiatorObj.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("发起人(INITIATOR)变量 '{}' 无法转换为Long类型。", initiatorObj, e);
|
||||
return;
|
||||
}
|
||||
|
||||
// --- 2. 准备通知内容 (解决taskName为空的问题) ---
|
||||
String nextTaskName = getNextTaskName(execution);
|
||||
String weChatMessage = "您提交的学生违纪处分申请已有最终处理结果,<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>。";
|
||||
String internalMessageText = "您有一条新的【" + nextTaskName + "】待办任务需要处理。";
|
||||
String hiddenIdentifier = String.format("<span id='flow-identifier' data-proc-inst-id='%s' data-activity-id='%s' style='display:none;'></span>",
|
||||
execution.getProcessInstanceId(),
|
||||
((SequenceFlow) execution.getCurrentFlowElement()).getTargetRef());
|
||||
String internalMessageContent = internalMessageText + "<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>。" + hiddenIdentifier;
|
||||
|
||||
// --- 3. 发送企业微信通知 ---
|
||||
sendWeChatNotification(initiatorUserId, weChatMessage);
|
||||
|
||||
// --- 4. 创建内部消息 ---
|
||||
createInternalMessage(initiatorUserId, internalMessageContent, execution);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信通知
|
||||
*/
|
||||
private void sendWeChatNotification(Long userId, String content) {
|
||||
if (weChatUtil == null) { // 防御性编程
|
||||
log.warn("WeChatUtil未配置,跳过发送企业微信。");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String userName = disciplinaryMapper.getUserNameByUserId(userId);
|
||||
if (userName != null && !userName.isEmpty()) {
|
||||
weChatUtil.sendTextMessage(userName, content);
|
||||
log.info("已成功向流程发起人 (userId:{}) 发送企业微信通知。", userId);
|
||||
} else {
|
||||
log.warn("找到了发起人(userId:{}),但其企微账号为空,未发送企微通知。", userId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("向流程发起人发送企业微信通知时异常: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建内部消息
|
||||
*/
|
||||
private void createInternalMessage(Long receiverId, String content, DelegateExecution execution) {
|
||||
try {
|
||||
CphMsg cphMsg = new CphMsg();
|
||||
cphMsg.setReceiver(receiverId);
|
||||
cphMsg.setContent(content);
|
||||
// 安全地获取发送人,提供默认值
|
||||
cphMsg.setSender(SecurityUtils.getUserId() != null ? SecurityUtils.getUserId() : 1L);
|
||||
|
||||
cphMsgService.insertCphMsg(cphMsg);
|
||||
log.info("已成功为流程发起人 (userId:{}) 创建内部消息。", receiverId);
|
||||
} catch (Exception e) {
|
||||
log.error("为流程发起人创建内部消息时异常: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地获取线上监听器下一个目标节点的名称
|
||||
*/
|
||||
private String getNextTaskName(DelegateExecution execution) {
|
||||
try {
|
||||
SequenceFlow sequenceFlow = (SequenceFlow) execution.getCurrentFlowElement();
|
||||
FlowElement targetElement = sequenceFlow.getTargetFlowElement();
|
||||
if (targetElement != null) {
|
||||
return targetElement.getName();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("获取下一个任务名称时出错: {}", e.getMessage());
|
||||
}
|
||||
return "结果接收";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.srs.flowable.listener.disciplinary;
|
||||
|
||||
import com.srs.common.utils.SecurityUtils;
|
||||
import com.srs.comprehensive.domain.CphMsg;
|
||||
import com.srs.comprehensive.service.ICphMsgService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.SequenceFlow;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 【多实例专用线上监听器】为即将到来的多实例任务创建内部消息。
|
||||
* <p>
|
||||
* 它只从流程变量 `userList` 中读取接收人列表。
|
||||
* </p>
|
||||
*/
|
||||
@Component("multiInstanceMessageListener") // 定义一个全新的Bean名称
|
||||
@Slf4j
|
||||
public class MultiInstanceMessageListener implements ExecutionListener {
|
||||
|
||||
@Autowired
|
||||
private ICphMsgService cphMsgService;
|
||||
|
||||
@Override
|
||||
public void notify(DelegateExecution execution) {
|
||||
log.info("流程实例 [{}]: 触发多实例专用消息监听器 (MultiInstanceMessageListener)...", execution.getProcessInstanceId());
|
||||
|
||||
// --- 步骤 1: 只从 'userList' 变量获取接收人 ---
|
||||
Object userListObj = execution.getVariable("userList");
|
||||
if (!(userListObj instanceof List) || ((List<?>) userListObj).isEmpty()) {
|
||||
log.warn("流程实例 [{}]: 未能从 'userList' 变量中找到有效的接收人列表,跳过消息创建。", execution.getProcessInstanceId());
|
||||
return;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Long> receiverIdList = (List<Long>) userListObj;
|
||||
|
||||
// --- 步骤 2: (已修正) 精确获取下一个目标节点的名称和ID ---
|
||||
FlowElement nextElement = getNextFlowElement(execution);
|
||||
String taskName = (nextElement != null && nextElement.getName() != null) ? nextElement.getName() : "新的待办";
|
||||
String activityId = (nextElement != null) ? nextElement.getId() : "unknownActivity";
|
||||
|
||||
// --- 步骤 3: 准备消息内容 ---
|
||||
String messageText = "您有一条新的【" + taskName + "】待办任务需要处理。";
|
||||
String link = "<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>。";
|
||||
String hiddenIdentifier = String.format("<span id='flow-identifier' data-proc-inst-id='%s' data-activity-id='%s' style='display:none;'></span>",
|
||||
execution.getProcessInstanceId(),
|
||||
activityId);
|
||||
String finalContent = messageText + link + hiddenIdentifier;
|
||||
|
||||
Long senderId = getSenderId();
|
||||
|
||||
// --- 步骤 4: 批量创建消息 ---
|
||||
for (Long receiverId : receiverIdList) {
|
||||
try {
|
||||
CphMsg cphMsg = new CphMsg();
|
||||
cphMsg.setReceiver(receiverId);
|
||||
cphMsg.setSender(senderId);
|
||||
cphMsg.setContent(finalContent);
|
||||
cphMsgService.insertCphMsg(cphMsg);
|
||||
log.info("已成功为用户 [{}] 创建多实例任务的内部消息 (关联 Activity ID: {})。", receiverId, activityId);
|
||||
} catch (Exception e) {
|
||||
log.error("为用户 [{}] 创建多实例任务内部消息时发生异常: {}", receiverId, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地获取线上监听器的下一个目标节点
|
||||
*/
|
||||
private FlowElement getNextFlowElement(DelegateExecution execution) {
|
||||
if (execution.getCurrentFlowElement() instanceof SequenceFlow) {
|
||||
return ((SequenceFlow) execution.getCurrentFlowElement()).getTargetFlowElement();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地获取当前操作的发送人ID。
|
||||
*/
|
||||
private Long getSenderId() {
|
||||
try {
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
return userId != null ? userId : 1L;
|
||||
} catch (Exception e) {
|
||||
log.warn("在监听器中获取发送人ID时发生异常,使用默认系统管理员ID(1L)。");
|
||||
return 1L;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,22 @@ 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;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class XGLDSHListener implements ExecutionListener {
|
||||
|
||||
|
||||
@Autowired
|
||||
private WeChatUtil weChatUtil;
|
||||
|
||||
@Override
|
||||
public void notify(DelegateExecution delegateExecution) {
|
||||
DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class);
|
||||
@@ -38,14 +47,14 @@ public class XGLDSHListener implements ExecutionListener {
|
||||
|
||||
// 步骤 3: 发送企业微信通知
|
||||
weChatUtil.sendTextMessage(toUser, content);
|
||||
// log.info("已成功向角色 '{}' 的成员发送企业微信审批通知。接收人: {}", TARGET_ROLE_KEY, toUser);
|
||||
log.info("已成功向角色 '{}' 的成员发送企业微信审批通知。接收人: {}", TARGET_ROLE_KEY, toUser);
|
||||
|
||||
} else {
|
||||
// log.warn("角色 '{}' 下找到 {} 个用户,但无对应的企业微信账号,无法发送通知。", TARGET_ROLE_KEY, userIdList.size());
|
||||
log.warn("角色 '{}' 下找到 {} 个用户,但无对应的企业微信账号,无法发送通知。", TARGET_ROLE_KEY, userIdList.size());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
// log.error("向角色 '{}' 发送企业微信通知时出现异常,但流程将继续。错误详情: {}", TARGET_ROLE_KEY, e.getMessage(), e);
|
||||
log.error("向角色 '{}' 发送企业微信通知时出现异常,但流程将继续。错误详情: {}", TARGET_ROLE_KEY, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,11 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生教育管理科审核节点的执行监听器。 知无涯
|
||||
* 向“学生教育管理科”角色发送企业微信通知。
|
||||
* 【线上监听器-升级版】为“学生教育管理科审核”节点做准备。
|
||||
* 1. 向该候选组的所有成员发送企业微信通知。
|
||||
* 2. 将该组的所有成员ID列表存入 'userList' 流程变量,供下游监听器(GenericMessageListener)使用。
|
||||
*/
|
||||
@Component
|
||||
@Component("xsjyglkListener")
|
||||
@Slf4j
|
||||
public class XSJYGLKListener implements ExecutionListener {
|
||||
|
||||
@@ -21,39 +22,51 @@ public class XSJYGLKListener implements ExecutionListener {
|
||||
public void notify(DelegateExecution delegateExecution) {
|
||||
DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class);
|
||||
|
||||
// 1. 【核心】定义“学生教育管理科”xsjyglksh
|
||||
// 1. 【核心】定义“学生教育管理科”角色Key
|
||||
final String TARGET_ROLE_KEY = "xsjyglksh";
|
||||
log.info("流程实例 [{}]: 准备向角色 '{}' 发送通知。", delegateExecution.getProcessInstanceId(), TARGET_ROLE_KEY);
|
||||
log.info("流程实例 [{}]: 触发XSJYGLKListener, 准备向角色 '{}' 发送通知并设置流程变量。", delegateExecution.getProcessInstanceId(), TARGET_ROLE_KEY);
|
||||
|
||||
// 2. 根据这个固定的角色Key,查询该角色的所有成员ID(即使只有一个)。
|
||||
// 2. 根据角色Key,查询该角色的所有成员ID。
|
||||
// 这个查询结果既用于发送企微,也用于设置流程变量。
|
||||
List<Long> userIdList = disciplinaryMapper.getApprovalByRoleKey(TARGET_ROLE_KEY);
|
||||
|
||||
// 3. 检查是否找到了成员。
|
||||
if (userIdList == null || userIdList.isEmpty()) {
|
||||
log.error("根据角色Key '{}' 未找到任何用户,无法发送通知。", TARGET_ROLE_KEY);
|
||||
return; // 中止执行,不抛出异常以免中断流程
|
||||
log.error("根据角色Key '{}' 未找到任何用户,无法发送通知和设置变量。", TARGET_ROLE_KEY);
|
||||
return; // 中止执行
|
||||
}
|
||||
|
||||
// 4. 发送企业微信通知。
|
||||
// (我们的批量发送逻辑即使只有一个用户也能完美处理)
|
||||
// --- 关键新增逻辑:开始 ---
|
||||
// 4. 将查询到的用户ID列表存入流程变量 'userList'。
|
||||
// 这是为下游的 GenericMessageListener 准备的标准“产品”。
|
||||
delegateExecution.setVariable("userList", userIdList);
|
||||
log.info("已将角色 '{}' 的 {} 位成员ID存入 'userList' 流程变量,供下游监听器使用。", TARGET_ROLE_KEY, userIdList.size());
|
||||
// --- 关键新增逻辑:结束 ---
|
||||
|
||||
// 5. (原有逻辑) 发送企业微信通知。
|
||||
sendWeChatNotification(userIdList, disciplinaryMapper, TARGET_ROLE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装的发送企业微信的私有方法,保持主方法 notify 的整洁。
|
||||
*/
|
||||
private void sendWeChatNotification(List<Long> userIdList, DisciplinaryMapper disciplinaryMapper, String roleKey) {
|
||||
try {
|
||||
// 批量查询userName (即使只有一个ID,这个方法也能正常工作)
|
||||
List<String> userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList);
|
||||
|
||||
if (!userNameList.isEmpty()) {
|
||||
// 将列表拼接成 "username1|username2|..." 的格式
|
||||
if (userNameList != null && !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("已成功向角色 '{}' 的成员发送通知。接收人: {}", TARGET_ROLE_KEY, toUser);
|
||||
log.info("已成功向角色 '{}' 的成员发送企业微信通知。接收人: {}", roleKey, toUser);
|
||||
} else {
|
||||
log.warn("角色 '{}' 中找到了 {} 个用户,但无人配置企业微信账号,未发送任何通知。", TARGET_ROLE_KEY, userIdList.size());
|
||||
log.warn("角色 '{}' 中找到了 {} 个用户,但无人配置企业微信账号,未发送任何通知。", roleKey, userIdList.size());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("向角色 '{}' 发送企业微信通知时出现异常。流程将继续。错误详情: {}", TARGET_ROLE_KEY, e.getMessage(), e);
|
||||
log.error("向角色 '{}' 发送企业微信通知时出现异常。流程将继续。错误详情: {}", roleKey, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,24 +3,26 @@ package com.srs.flowable.listener.disciplinary;
|
||||
import com.srs.common.utils.WeChatUtil;
|
||||
import com.srs.flowable.mapper.DisciplinaryMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.SequenceFlow;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.delegate.ExecutionListener;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 【线上监听器】为“学院违纪处理委员会”多实例任务准备数据并发送通知 知无涯
|
||||
* 【生产者线上监听器】为“学院违纪处理委员会”多实例任务准备数据。
|
||||
* 1. 设置 'userList' 变量供多实例节点本身消费。
|
||||
* 2. 设置 'nextTaskNameForMessage' 变量供下游消息监听器消费。
|
||||
* 3. 发送企业微信通知。
|
||||
*/
|
||||
@MapperScan("com.srs.flowable.mapper")
|
||||
@Component("xywjclwyhListener")
|
||||
@Slf4j
|
||||
public class XYWJCLWYHListener implements ExecutionListener {
|
||||
|
||||
// 推荐:使用依赖注入,而不是SpringUtils
|
||||
@Autowired
|
||||
private DisciplinaryMapper disciplinaryMapper;
|
||||
|
||||
@@ -29,46 +31,49 @@ public class XYWJCLWYHListener implements ExecutionListener {
|
||||
|
||||
@Override
|
||||
public void notify(DelegateExecution execution) {
|
||||
log.info("流程实例 [{}]: 在进入'学院违纪处理委员会'节点前,开始准备审批数据...", execution.getProcessInstanceId());
|
||||
|
||||
// 步骤 1: 单一数据库查询,获取所有需要的审批人信息 (ID和企微账号)
|
||||
// List<DisciplinaryMapper.UserInfo> userInfos = disciplinaryMapper.getUserInfoByRoleKey("xywjclwyh");
|
||||
// 注意:如果您不方便修改Mapper,这里可以保持原来的两次查询,逻辑依然正确。
|
||||
// 我们先用原始的两次查询来演示,更具普适性。
|
||||
log.info("流程实例 [{}]: 触发 XYWJCLWYHListener,为'委员会'节点准备数据...", execution.getProcessInstanceId());
|
||||
|
||||
List<Long> userIdList = disciplinaryMapper.getApprovalByRoleKey("xywjclwyh");
|
||||
|
||||
if (userIdList == null || userIdList.isEmpty()) {
|
||||
if (CollectionUtils.isEmpty(userIdList)) {
|
||||
log.error("角色 'xywjclwyh' 未配置或未找到任何有效用户,流程无法继续。");
|
||||
throw new RuntimeException("学院违纪处理委员会审批人员未设置");
|
||||
}
|
||||
|
||||
// 步骤 2: 设置多实例任务需要的流程变量 (这是“线上”为“节点”准备的核心数据)
|
||||
// 步骤 1: 设置 'userList' 变量,供多实例UserTask节点消费
|
||||
execution.setVariable("userList", userIdList);
|
||||
log.info("流程实例 [{}]: 已成功设置'userList'变量,包含 {} 个审批人。", execution.getProcessInstanceId(), userIdList.size());
|
||||
log.info("已将'委员会'的 {} 位成员ID存入 'userList' 流程变量。", userIdList.size());
|
||||
|
||||
// 步骤 2: 主动获取并设置下一个节点的名称,供 GenericMessageListener 消费
|
||||
FlowElement nextElement = getNextFlowElement(execution);
|
||||
if (nextElement != null) {
|
||||
execution.setVariable("nextTaskNameForMessage", nextElement.getName());
|
||||
log.info("已将下一个任务的名称 '{}' 存入流程变量 'nextTaskNameForMessage'。", nextElement.getName());
|
||||
}
|
||||
|
||||
// 步骤 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);
|
||||
if (CollectionUtils.isEmpty(userNameList)) {
|
||||
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);
|
||||
log.info("流程实例 [{}]: 已成功向'委员会'发送企微通知。", processInstanceId);
|
||||
} catch (Exception e) {
|
||||
log.error("流程实例 [{}]: 发送企微通知时出现异常,但不影响主流程。错误: {}", processInstanceId, e.getMessage(), e);
|
||||
log.error("流程实例 [{}]: 发送企微通知时出现异常: {}", processInstanceId, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private FlowElement getNextFlowElement(DelegateExecution execution) {
|
||||
if (execution.getCurrentFlowElement() instanceof SequenceFlow) {
|
||||
return ((SequenceFlow) execution.getCurrentFlowElement()).getTargetFlowElement();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.srs.flowable.listener.relieve;
|
||||
|
||||
import com.srs.common.utils.WeChatUtil;
|
||||
import com.srs.common.utils.spring.SpringUtils;
|
||||
import com.srs.flowable.mapper.RelieveMapper;
|
||||
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 StuReceiveListener implements ExecutionListener {
|
||||
|
||||
@Override
|
||||
public void notify(DelegateExecution delegateExecution) {
|
||||
RelieveMapper relieveMapper = (RelieveMapper) SpringUtils.getBean("relieveMapper");
|
||||
|
||||
try {
|
||||
// 从流程变量中获取学生 userId(之前在发给辅导员时已经存入)
|
||||
Long stuUserId = Long.valueOf(delegateExecution.getVariable("stuUserId").toString());
|
||||
|
||||
// 使用 userId 查询对应的企业微信账号
|
||||
String stuUserName = relieveMapper.getUserNameByUserId(stuUserId);
|
||||
|
||||
if (stuUserName != null && !stuUserName.isEmpty()) {
|
||||
WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
|
||||
|
||||
// 根据流程结果拼接不同的提示信息
|
||||
String approveResult = delegateExecution.getVariable("approveResult") != null
|
||||
? delegateExecution.getVariable("approveResult").toString()
|
||||
: "审批已完成";
|
||||
|
||||
String content = "您的违纪处理流程有新的进展:" +
|
||||
approveResult + "," +
|
||||
"<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>点此查看详情</a>";
|
||||
|
||||
// 发送企业微信消息
|
||||
weChatUtil.sendTextMessage(stuUserName, content);
|
||||
log.info("✅ 已成功向学生(userName:{})发送企业微信审批通知。", stuUserName);
|
||||
|
||||
} else {
|
||||
log.warn("⚠ 找到了学生(stuUserId:{}), 但其对应的企业微信账号为空,无法发送通知。", stuUserId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Long stuUserId = Long.valueOf(delegateExecution.getVariable("stuUserId").toString());
|
||||
log.error("❌ 向学生(stuUserId:{})发送企业微信通知时出现异常,但流程将继续。错误详情:", stuUserId, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,7 +265,7 @@ public class RtStuDisciplinaryApplicationServiceImpl extends ServiceImpl<RtStuDi
|
||||
|
||||
// todo 企业微信推送消息
|
||||
|
||||
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_n27gxm4k:22:720004", variables);
|
||||
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_n27gxm4k:27:795072", variables);
|
||||
String code = ajaxResult.get("code").toString();
|
||||
if (code.equals("200")) {
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ public class RtStuDisciplinaryRelieveServiceImpl extends ServiceImpl<RtStuDiscip
|
||||
variables.put("penaltyType", rtStuDisciplinaryRelieve.getPenaltyType());
|
||||
variables.put("stuUserId", SecurityUtils.getUserId());
|
||||
|
||||
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_d46199lc:7:260004", variables);
|
||||
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_d46199lc:12:765004", variables);
|
||||
String code = ajaxResult.get("code").toString();
|
||||
if (code.equals("200")) {
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ public class RtStuQuitSchoolServiceImpl extends ServiceImpl<RtStuQuitSchoolMappe
|
||||
variables.put("approval", SecurityUtils.getUserId());
|
||||
variables.put("deptId", SecurityUtils.getDeptId());
|
||||
|
||||
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_vxuubvdh:5:347504", variables);
|
||||
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_vxuubvdh:13:835109", variables);
|
||||
String code = ajaxResult.get("code").toString();
|
||||
if (code.equals("200")) {
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.srs.system.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.srs.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -11,7 +12,6 @@ import java.util.Date;
|
||||
public class StudentMentalRating extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
private String studentId;
|
||||
private String rating;
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.srs.system.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author 宁博
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class StudentMentalRatingVo {
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String stuNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String stuName;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 心理评级
|
||||
*/
|
||||
private String rating;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createdTime;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.srs.system.mapper;
|
||||
|
||||
import com.srs.system.domain.StudentMentalRating;
|
||||
import com.srs.system.domain.vo.StudentMentalRatingVo;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDate;
|
||||
@@ -23,11 +24,29 @@ public interface StudentMentalRatingMapper {
|
||||
*/
|
||||
int updateRatingByStudentId(StudentMentalRating record);
|
||||
|
||||
/** 全部记录 */
|
||||
List<StudentMentalRating> selectAll();
|
||||
/**
|
||||
* 查询辅导员负责的每个学生的最新心理评级记录(带条件查询)
|
||||
* @param teacherId 教师ID
|
||||
* @param stuNo 学号
|
||||
* @param stuName 学生姓名
|
||||
* @return 学生心理评级列表
|
||||
*/
|
||||
List<StudentMentalRatingVo> selectLatestByTeacherIdWithConditions(@Param("teacherId") String teacherId,
|
||||
@Param("stuNo") String stuNo,
|
||||
@Param("stuName") String stuName);
|
||||
|
||||
/**
|
||||
* 查询所有学生的最新心理评级记录(带条件查询)
|
||||
* @param stuNo 学号
|
||||
* @param stuName 学生姓名
|
||||
* @return 学生心理评级列表
|
||||
*/
|
||||
List<StudentMentalRatingVo> selectLatestAllWithConditions(@Param("stuNo") String stuNo,
|
||||
@Param("stuName") String stuName);
|
||||
|
||||
|
||||
/** 单学号全部记录 */
|
||||
List<StudentMentalRating> selectByStuNo(@Param("stuNo") String stuNo);
|
||||
List<StudentMentalRatingVo> selectByStuNo(@Param("stuNo") String stuNo);
|
||||
|
||||
/**
|
||||
* 查询今天的心理评级记录 陈冠元
|
||||
|
||||
@@ -21,25 +21,76 @@
|
||||
WHERE student_id = #{studentId}
|
||||
</update>
|
||||
|
||||
<!-- 心理查询全部:知无涯 -->
|
||||
<select id="selectAll" resultType="com.srs.system.domain.StudentMentalRating">
|
||||
SELECT id,
|
||||
student_id AS studentId,
|
||||
rating,
|
||||
created_time AS createdTime,
|
||||
updated_time AS updatedTime
|
||||
|
||||
<!-- 查询辅导员负责的每个学生的最新心理评级记录(带条件查询) -->
|
||||
<select id="selectLatestByTeacherIdWithConditions" resultType="com.srs.system.domain.vo.StudentMentalRatingVo">
|
||||
SELECT
|
||||
a.stu_no,
|
||||
a.stu_name,
|
||||
a.class_name,
|
||||
smr.rating,
|
||||
smr.created_time
|
||||
FROM view_stu_info a
|
||||
LEFT JOIN student_mental_rating smr ON a.stu_no = smr.student_id
|
||||
INNER JOIN (
|
||||
SELECT student_id, MAX(created_time) as max_time
|
||||
FROM student_mental_rating
|
||||
ORDER BY created_time DESC
|
||||
WHERE rating IS NOT NULL
|
||||
GROUP BY student_id
|
||||
) latest ON smr.student_id = latest.student_id AND smr.created_time = latest.max_time
|
||||
WHERE a.t_no = #{teacherId}
|
||||
AND smr.rating IS NOT NULL
|
||||
AND smr.student_id IS NOT NULL
|
||||
<if test="stuNo != null and stuNo != ''">
|
||||
AND a.stu_no = #{stuNo}
|
||||
</if>
|
||||
<if test="stuName != null and stuName != ''">
|
||||
AND a.stu_name LIKE CONCAT('%', #{stuName}, '%')
|
||||
</if>
|
||||
ORDER BY smr.created_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据学号查询心理:知无涯 -->
|
||||
<select id="selectByStuNo" resultType="com.srs.system.domain.StudentMentalRating">
|
||||
SELECT id,
|
||||
student_id AS studentId,
|
||||
rating,
|
||||
created_time AS createdTime,
|
||||
updated_time AS updatedTime
|
||||
<!-- 查询所有学生的最新心理评级记录(带条件查询) -->
|
||||
<select id="selectLatestAllWithConditions" resultType="com.srs.system.domain.vo.StudentMentalRatingVo">
|
||||
SELECT
|
||||
a.stu_no,
|
||||
a.stu_name,
|
||||
a.class_name,
|
||||
smr.rating,
|
||||
smr.created_time
|
||||
FROM view_stu_info a
|
||||
LEFT JOIN student_mental_rating smr ON a.stu_no = smr.student_id
|
||||
INNER JOIN (
|
||||
SELECT student_id, MAX(created_time) as max_time
|
||||
FROM student_mental_rating
|
||||
WHERE rating IS NOT NULL
|
||||
GROUP BY student_id
|
||||
) latest ON smr.student_id = latest.student_id AND smr.created_time = latest.max_time
|
||||
WHERE smr.rating IS NOT NULL
|
||||
AND smr.student_id IS NOT NULL
|
||||
<if test="stuNo != null and stuNo != ''">
|
||||
AND a.stu_no = #{stuNo}
|
||||
</if>
|
||||
<if test="stuName != null and stuName != ''">
|
||||
AND a.stu_name LIKE CONCAT('%', #{stuName}, '%')
|
||||
</if>
|
||||
ORDER BY smr.created_time DESC
|
||||
</select>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 根据学号查询心理:知无涯 -->
|
||||
<select id="selectByStuNo" parameterType="string" resultType="com.srs.system.domain.vo.StudentMentalRatingVo">
|
||||
SELECT
|
||||
a.stu_no,
|
||||
a.stu_name,
|
||||
a.class_name,
|
||||
smr.rating,
|
||||
smr.created_time
|
||||
FROM view_stu_info a
|
||||
LEFT JOIN student_mental_rating smr ON a.stu_no = smr.student_id
|
||||
WHERE student_id = #{stuNo}
|
||||
ORDER BY created_time DESC
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user