Merge remote-tracking branch 'origin/main'

This commit is contained in:
MDSMO
2025-08-28 15:10:14 +08:00
35 changed files with 358 additions and 156 deletions

View File

@@ -30,6 +30,10 @@ public interface DmsDormitoryMapper extends MPJBaseMapper<DmsDormitory> {
@Select("select * from view_dorm_info")
public List<Map<String, Object>> listDormInfo();
public List<DmsDormitory> listViewDormInfoByIds(@Param("ids") List<Long> ids);
public DmsDormitory getDormitoryById(@Param("id") Long id);
public DomInfo getDormHas(Long id);
public List<DomInfo> countRecordConfirmStatus();

View File

@@ -278,7 +278,9 @@ public class IDmsDormitoryDeptServiceImpl extends ServiceImpl<DmsDormitoryDeptMa
TransactionStatus status = transactionManager.getTransaction(def);
try{
Long dmId = param.get(0).getDormitoryId();
DmsDormitory dm = _dmMapper.selectById(dmId);
// DmsDormitory dm = _dmMapper.selectById(dmId);
DmsDormitory dm = _dmMapper.getDormitoryById(dmId);
if(dm == null){
throw new Exception("该宿舍不存在,请重新输入");
}
@@ -328,9 +330,9 @@ public class IDmsDormitoryDeptServiceImpl extends ServiceImpl<DmsDormitoryDeptMa
TransactionStatus status = transactionManager.getTransaction(def);
try{
QueryWrapper<DmsDormitory> dmQuery = new QueryWrapper<>();
dmQuery.in("id",dto.getDormIds());
List<DmsDormitory> dmList = _dmMapper.selectList(dmQuery);
// QueryWrapper<DmsDormitory> dmQuery = new QueryWrapper<>();
// dmQuery.in("id",dto.getDormIds());
List<DmsDormitory> dmList = _dmMapper.listViewDormInfoByIds(dto.getDormIds());
List<String> isExistXydm = new ArrayList<>();
@@ -415,7 +417,6 @@ public class IDmsDormitoryDeptServiceImpl extends ServiceImpl<DmsDormitoryDeptMa
@Override
public TableDataInfo getDormitory(SelectDormDto dto) {
DmsSearch param = new DmsSearch();
if (dto.getFloorId() != null) {

View File

@@ -615,4 +615,29 @@
where a.id = #{id}
</select>
<select id="listViewDormInfoByIds" parameterType="List" resultType="DmsDormitory">
select a.*,
case b.occupancy
when b.occupancy is not null then b.occupancy
else 0
end
as occupancy from view_dorm_info as a
left join view_dorm_stu_count as b on a.id = b.dormitory_id
where a.id in
<foreach item="item" collection="ids" open="(" separator="," close=")">
#{item}
</foreach>
</select>
<select id="getDormitoryById" parameterType="Long" resultType="DmsDormitory">
select a.*,
case b.occupancy
when b.occupancy is not null then b.occupancy
else 0
end
as occupancy from view_dorm_info as a
left join view_dorm_stu_count as b on a.id = b.dormitory_id
where a.id = #{id}
</select>
</mapper>

View File

@@ -37,6 +37,7 @@
where a2.apply_status != 1
) as t1
<where>
t1.apply_status = 1 or t1.apply_status = 2 or t1.apply_status = 3
<if test="stuNo != null and stuNo != ''">and t1.stu_no = #{stuNo}</if>
<if test="roomId != null ">and t1.room_id = #{roomId}</if>
<if test="startDate != null ">and t1.start_date = #{startDate}</if>

View File

@@ -113,14 +113,14 @@ public class WeChatMentalAlertController extends BaseController {
"学生姓名:%s\n" +
"学号:%s\n" +
"问题描述:%s\n" +
"AI建议%s\n" +
"心理问题评级:%s",
"心理问题评级%s\n"+
"复制链接登陆学工系统PC端查看更多" +
"zhxg.gxsdxy.cn/srs/#/aitutor/chatwarning",
teacherName,
teacher.getUserName(),
request.getUserName(),
request.getUserId(),
request.getStudentQuestion(),
request.getAiAnswer(),
request.getRating()
);
}

View File

@@ -94,7 +94,6 @@ public class CphGoodApplyController extends BaseController {
Object total = ajaxResult.get("data");
Page page = (Page) total;
list.add("rwgl-" + page.getTotal());
String username = new String();
return AjaxResult.success(list);
}

View File

@@ -162,15 +162,16 @@ public class SrsOrderController extends BaseController
stuReg.setRegStatus("1");
_stuRegService.updateSrsStuReg(stuReg);
srsStuTodoService.confirmTask(getUsername(),"ZXJF");
String classCode = stuReg.getBJDM();
QueryWrapper<SrsClass> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("class_code",classCode);
SrsClass srsClass = srcClassMapper.selectOne(queryWrapper);
Long teacherId = srsClass.getTeacherId();
CphTeacher cphTeacher = cphTeacherMapper.selectCphTeacherByTeacherId(teacherId);
String employeeId = cphTeacher.getEmployeeId();
// 自动分配宿舍
srsDormitoryStudentService.assignDormitoryByTeacher(employeeId);
// 分配宿舍逻辑
// String classCode = stuReg.getBJDM();
// QueryWrapper<SrsClass> queryWrapper = new QueryWrapper<>();
// queryWrapper.eq("class_code",classCode);
// SrsClass srsClass = srcClassMapper.selectOne(queryWrapper);
// Long teacherId = srsClass.getTeacherId();
// CphTeacher cphTeacher = cphTeacherMapper.selectCphTeacherByTeacherId(teacherId);
// String employeeId = cphTeacher.getEmployeeId();
// // 自动分配宿舍
// srsDormitoryStudentService.assignDormitoryByTeacher(employeeId);
return AjaxResult.success("已缴费");
}else {

View File

@@ -21,7 +21,7 @@ srs:
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080 正式8085 测试8088
port: 8088
port: 8085
servlet:
# 应用的访问路径
context-path: /
@@ -62,8 +62,8 @@ spring:
# 国际化资源文件路径
basename: i18n/messages
profiles:
# active: druid #正式环境
active: dev #测试环境
active: druid #正式环境
# active: dev #测试环境
# 文件上传
servlet:
multipart:
@@ -79,15 +79,15 @@ spring:
# redis 配置
redis:
# 地址
# host: localhost #正式环境redis
host: 47.112.118.149 #测试开发地址
host: localhost #正式环境redis
# host: 47.112.118.149 #测试开发地址
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# 密码SSSS
password: Houpuyfb #测试开发密码
# password: #正式环境密码
# password: Houpuyfb #测试开发密码
password: #正式环境密码
# 连接超时时间
timeout: 10s
lettuce:

View File

@@ -1,6 +1,5 @@
package com.srs.comprehensive.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.srs.comprehensive.domain.CphClasstwo;
import com.srs.comprehensive.domain.Vo.CphScoreVo;
import com.srs.comprehensive.domain.Vo.StuIdNo;
@@ -12,7 +11,7 @@ import java.util.List;
/**
* 第二课堂Mapper接口
*
*
* @author zhy
* @date 2023-07-03
*/
@@ -29,7 +28,7 @@ public interface CphClasstwoMapper extends EasyBaseMapper<CphClasstwo>
/**
* 查询第二课堂
*
*
* @param id 第二课堂主键
* @return 第二课堂
*/
@@ -37,7 +36,7 @@ public interface CphClasstwoMapper extends EasyBaseMapper<CphClasstwo>
/**
* 查询第二课堂列表
*
*
* @param cphClasstwo 第二课堂
* @return 第二课堂集合
*/
@@ -57,7 +56,7 @@ public interface CphClasstwoMapper extends EasyBaseMapper<CphClasstwo>
/**
* 新增第二课堂
*
*
* @param cphClasstwo 第二课堂
* @return 结果
*/
@@ -65,7 +64,7 @@ public interface CphClasstwoMapper extends EasyBaseMapper<CphClasstwo>
/**
* 修改第二课堂
*
*
* @param cphClasstwo 第二课堂
* @return 结果
*/
@@ -73,7 +72,7 @@ public interface CphClasstwoMapper extends EasyBaseMapper<CphClasstwo>
/**
* 删除第二课堂
*
*
* @param id 第二课堂主键
* @return 结果
*/
@@ -81,7 +80,7 @@ public interface CphClasstwoMapper extends EasyBaseMapper<CphClasstwo>
/**
* 批量删除第二课堂
*
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/

View File

@@ -1,8 +1,6 @@
package com.srs.comprehensive.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.srs.comprehensive.domain.CphStuScoreMiddle;
import com.srs.comprehensive.domain.Dto.CphStuScoreMiddleDto;
import com.srs.framework.mybatisplusMapper.EasyBaseMapper;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Mapper;

View File

@@ -1,13 +1,10 @@
package com.srs.comprehensive.mapper;
import com.srs.common.core.domain.entity.SysDept;
import java.util.List;
import java.util.Map;
import com.srs.comprehensive.domain.CphTeacher;
import com.srs.comprehensive.domain.Dto.CphExport;
import com.srs.comprehensive.domain.SrsClass;
import com.srs.comprehensive.domain.SrsGrade;
import com.srs.comprehensive.domain.SrsMajors;
import com.srs.comprehensive.domain.Vo.*;

View File

@@ -10,7 +10,7 @@ import org.apache.ibatis.annotations.Param;
/**
* 【加分记录】Mapper接口
*
*
* @author srs
* @date 2023-06-20
*/
@@ -24,7 +24,7 @@ public interface SrsAddRecordMapper extends EasyBaseMapper<SrsAddRecord>
/**
* 查询【请填写功能名称】
*
*
* @param id 【请填写功能名称】主键
* @return 【请填写功能名称】
*/
@@ -32,7 +32,7 @@ public interface SrsAddRecordMapper extends EasyBaseMapper<SrsAddRecord>
/**
* 查询【请填写功能名称】列表
*
*
* @param srsAddRecord 【请填写功能名称】
* @return 【请填写功能名称】集合
*/
@@ -40,7 +40,7 @@ public interface SrsAddRecordMapper extends EasyBaseMapper<SrsAddRecord>
/**
* 新增【请填写功能名称】
*
*
* @param srsAddRecord 【请填写功能名称】
* @return 结果
*/
@@ -50,7 +50,7 @@ public interface SrsAddRecordMapper extends EasyBaseMapper<SrsAddRecord>
/**
* 修改【请填写功能名称】
*
*
* @param srsAddRecord 【请填写功能名称】
* @return 结果
*/
@@ -58,7 +58,7 @@ public interface SrsAddRecordMapper extends EasyBaseMapper<SrsAddRecord>
/**
* 删除【请填写功能名称】
*
*
* @param id 【请填写功能名称】主键
* @return 结果
*/
@@ -66,7 +66,7 @@ public interface SrsAddRecordMapper extends EasyBaseMapper<SrsAddRecord>
/**
* 批量删除【请填写功能名称】
*
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/

View File

@@ -7,7 +7,6 @@ import com.srs.comprehensive.domain.Vo.CphSearch;
import com.srs.framework.mybatisplusMapper.EasyBaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;

View File

@@ -2,7 +2,6 @@ package com.srs.comprehensive.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.srs.comprehensive.domain.SrsGrade;
import com.srs.framework.mybatisplusMapper.EasyBaseMapper;
import org.apache.ibatis.annotations.Mapper;

View File

@@ -2,7 +2,6 @@ package com.srs.comprehensive.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.srs.comprehensive.domain.SrsMajors;
import com.srs.framework.mybatisplusMapper.EasyBaseMapper;
import org.apache.ibatis.annotations.Mapper;

View File

@@ -1,13 +1,10 @@
package com.srs.comprehensive.mapper;
import java.util.List;
import java.util.Set;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.srs.comprehensive.domain.SrsSportTest;
import com.srs.comprehensive.domain.SumSportTest;
import com.srs.comprehensive.domain.Vo.CphScoreVo;
import com.srs.comprehensive.domain.Vo.SrsSportTestStudent;
import com.srs.comprehensive.domain.Vo.StuIdNo;
import com.srs.framework.mybatisplusMapper.EasyBaseMapper;
import org.apache.ibatis.annotations.Mapper;
@@ -15,7 +12,7 @@ import org.apache.ibatis.annotations.Param;
/**
* 体能测试Mapper接口
*
*
* @author srs
* @date 2023-06-28
*/
@@ -39,7 +36,7 @@ public interface SrsSportTestMapper extends EasyBaseMapper<SrsSportTest>
/**
* 查询体能测试
*
*
* @param id 体能测试主键
* @return 体能测试
*/
@@ -53,7 +50,7 @@ public interface SrsSportTestMapper extends EasyBaseMapper<SrsSportTest>
/**
* 查询体能测试列表
*
*
* @param srsSportTest 体能测试
* @return 体能测试集合
*/
@@ -63,7 +60,7 @@ public interface SrsSportTestMapper extends EasyBaseMapper<SrsSportTest>
/**
* 新增体能测试
*
*
* @param srsSportTest 体能测试
* @return 结果
*/
@@ -71,7 +68,7 @@ public interface SrsSportTestMapper extends EasyBaseMapper<SrsSportTest>
/**
* 修改体能测试
*
*
* @param srsSportTest 体能测试
* @return 结果
*/
@@ -79,7 +76,7 @@ public interface SrsSportTestMapper extends EasyBaseMapper<SrsSportTest>
/**
* 删除体能测试
*
*
* @param id 体能测试主键
* @return 结果
*/
@@ -87,7 +84,7 @@ public interface SrsSportTestMapper extends EasyBaseMapper<SrsSportTest>
/**
* 批量删除体能测试
*
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/

View File

@@ -772,9 +772,10 @@
-- 邵政文-(宿舍管理-住宿费用-辅导员确认待办)
union
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 and a.apply_status = 1
from view_dms_record as a
left join dms_new_record as b on a.stu_year_id = b.id
left join view_stu_info as d on a.stu_no = d.stu_no
where d.t_no = #{tNo} and a.apply_status = 1
</select>

View File

@@ -66,6 +66,6 @@ public class LeaveApproveListener implements ExecutionListener {
log.info("审核成功");
//推送消息
//todo 推送消息,推送给辅导员,目的要拿到辅导员工号
}
}

View File

@@ -1,55 +1,106 @@
package com.srs.flowable.listener.disciplinary;
import com.srs.common.utils.SecurityUtils;
import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
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.stereotype.Component;
import java.util.List;
/**
* 执行监听器:在“学生教育管理科审批归档”节点开始时, 知无涯
* 向负责归档的角色发送企业微信通知。
* “学生教育管理科审批归档”节点做准备 知无涯
* <p>
* 它的职责包括:
* 1. 主动清理上一个节点残留的变量。
* 2. 查询“学生教育管理科归档”组的成员。
* 3. 向所有成员发送企业微信通知。
* 4. 为所有成员创建内部消息。
* </p>
*/
@Component
@Component("archivingNotifyListener") // 明确指定Bean名称
@Slf4j
public class ArchivingNotifyListener implements ExecutionListener {
@Override
public void notify(DelegateExecution delegateExecution) {
log.info("流程实例 [{}]: 已进入学生教育管理科审批归档节点,准备发送通知。", delegateExecution.getProcessInstanceId());
public void notify(DelegateExecution execution) {
log.info("流程实例 [{}]: 触发 ArchivingNotifyListener (一体化),为'学生教育管理科审批归档'节点发送所有通知...", execution.getProcessInstanceId());
// --- 步骤 1: 主动清理上一个节点残留的流程变量 ---
if (execution.hasVariable("approval")) {
execution.removeVariable("approval");
log.info("已清理上一个节点残留的 'approval' 变量。");
}
if (execution.hasVariable("userList")) {
execution.removeVariable("userList");
log.info("已清理上一个节点残留的 'userList' 变量。");
}
try {
DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class);
ICphMsgService cphMsgService = SpringUtils.getBean(ICphMsgService.class);
WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
// 1. 【核心】定义负责归档的角色的 role_key。
// --- 步骤 2: 查询“学生教育管理科归档”组的成员 ---
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);
log.warn("根据角色Key '{}' 未找到任何归档人员,无法发送任何通知。", ARCHIVING_ROLE_KEY);
return;
}
// 3. 批量查询 userName 并发送通知
// --- 步骤 3: 发送企业微信通知 (批量) ---
List<String> userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList);
if (!userNameList.isEmpty()) {
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("已成功向归档角色 ({}) 发送通知。接收人: {}", ARCHIVING_ROLE_KEY, toUser);
String weChatMessage = "您有一条新的学生违纪归档任务待处理,<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>。";
weChatUtil.sendTextMessage(toUser, weChatMessage);
log.info("已成功向归档角色 ({}) 发送企业微信通知。", ARCHIVING_ROLE_KEY);
} else {
log.warn("角色 '{}' 中找到了 {} 个用户,但无人配置企业微信账号,未发送任何通知。", ARCHIVING_ROLE_KEY, userIdList.size());
}
// --- 步骤 4: 创建内部消息 (逐条) ---
FlowElement nextElement = getNextFlowElement(execution);
String taskName = (nextElement != null && nextElement.getName() != null) ? nextElement.getName() : "学生教育管理科审批归档";
String activityId = (nextElement != null) ? nextElement.getId() : "Activity_1agoizv"; // 节点的ID作为备用
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 internalMessageContent = messageText + link + hiddenIdentifier;
Long senderId = SecurityUtils.getUserId() != null ? SecurityUtils.getUserId() : 1L;
for (Long receiverId : userIdList) {
CphMsg cphMsg = new CphMsg();
cphMsg.setReceiver(receiverId);
cphMsg.setSender(senderId);
cphMsg.setContent(internalMessageContent);
cphMsgService.insertCphMsg(cphMsg);
log.info("已成功为'学生教育管理科归档'成员 (userId:{}) 创建内部消息。", receiverId);
}
} catch (Exception e) {
log.error("向归档角色发送企业微信通知时出现异常。流程将继续。错误详情: {}", e.getMessage(), e);
log.error("在 ArchivingNotifyListener 中发送通知时出现异常。错误详情: {}", e.getMessage(), e);
}
}
/**
* 安全地获取线上监听器的下一个目标节点
*/
private FlowElement getNextFlowElement(DelegateExecution execution) {
if (execution.getCurrentFlowElement() instanceof SequenceFlow) {
return ((SequenceFlow) execution.getCurrentFlowElement()).getTargetFlowElement();
}
return null;
}
}

View File

@@ -13,7 +13,7 @@ import java.util.Collections;
import java.util.List;
/**
* 【通用线上监听器】为即将到来的任务创建内部“我的消息”记录。 知无涯
* 为即将到来的任务创建内部“我的消息”记录。 知无涯
* <p>
* 该监听器被设计为在SequenceFlow的'take'事件上触发。
* 它会智能地从流程变量中读取单个接收人(变量名: approval)或多个接收人(变量名: userList)

View File

@@ -13,7 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 【线上专用监听器】在流程结果返回给发起人时,
* 在流程结果返回给发起人时, 知无涯
* 负责发送企业微信和内部消息两种通知。
*/
@Component("initiatorNotificationListener") // 使用一个全新的、明确的Bean名称

View File

@@ -13,7 +13,7 @@ import javax.annotation.PostConstruct;
import java.util.List;
/**
* 【任务监听器】在任务完成后,删除内部消息。
* 【任务监听器】在任务完成后,删除内部消息。 知无涯
* <p>
* 该监听器被设计为在UserTask的'complete'事件上触发。
* 它通过解析消息内容中的隐藏HTML标识来找到与当前已完成任务关联的消息

View File

@@ -14,7 +14,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
/**
* 【多实例专用线上监听器】为即将到来的多实例任务创建内部消息。
* 为即将到来的多实例任务创建内部消息。 知无涯
* <p>
* 它只从流程变量 `userList` 中读取接收人列表。
* </p>

View File

@@ -1,55 +1,104 @@
package com.srs.flowable.listener.disciplinary;
import com.srs.common.utils.SecurityUtils;
import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
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.stereotype.Component;
import java.util.List;
/**
* 执行监听器:在“校领导审批”节点开始时,向校领导发送企业微信通知。 知无涯
* (简化版:因为流程能到达此节点,即表示前序节点已全票通过)
* “校领导审批”节点做准备 知无涯
* <p>
* 它的职责包括:
* 1. 主动清理上一个节点残留的变量。
* 2. 查询校领导组成员。
* 3. 向所有成员发送企业微信通知。
* 4. 为所有成员创建内部消息。
* </p>
*/
@Component
@Component("schoolLeaderApprovalListener")
@Slf4j
public class SchoolLeaderApprovalListener implements ExecutionListener {
@Override
public void notify(DelegateExecution delegateExecution) {
log.info("流程实例 [{}]: 已进入校领导审批节点,准备发送通知。", delegateExecution.getProcessInstanceId());
public void notify(DelegateExecution execution) {
log.info("流程实例 [{}]: 触发 SchoolLeaderApprovalListener (一体化),为'校领导审批'节点发送所有通知...", execution.getProcessInstanceId());
// --- 步骤 1: 主动清理上一个节点残留的流程变量 ---
if (execution.hasVariable("approval")) {
execution.removeVariable("approval");
log.info("已清理上一个节点残留的 'approval' 变量。");
}
if (execution.hasVariable("userList")) {
execution.removeVariable("userList");
log.info("已清理上一个节点残留的 'userList' 变量。");
}
try {
DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class);
ICphMsgService cphMsgService = SpringUtils.getBean(ICphMsgService.class);
WeChatUtil weChatUtil = SpringUtils.getBean(WeChatUtil.class);
// 1. 【核心】定义“校领导”这个角色的 role_key
// --- 步骤 2: 查询校领导组成员 ---
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);
log.warn("根据角色Key '{}' 未找到任何校领导用户,无法发送任何通知。", LEADER_ROLE_KEY);
return;
}
// 3. 批量查询 userName 并发送通知
// --- 步骤 3: 发送企业微信通知 (批量) ---
List<String> userNameList = disciplinaryMapper.getUserNamesByUserIdList(userIdList);
if (!userNameList.isEmpty()) {
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>。";
String weChatMessage = "校领导您有一条新的学生违纪审批任务待处理,<a href='http://zhxg.gxsdxy.cn/web/#/pages/Approval/index'>请点击前往处理</a>。";
weChatUtil.sendTextMessage(toUser, weChatMessage);
log.info("已成功向校领导 (角色: {}) 发送企业微信通知。", LEADER_ROLE_KEY);
}
weChatUtil.sendTextMessage(toUser, content);
log.info("已成功向校领导 (角色: {}) 发送通知。接收人: {}", LEADER_ROLE_KEY, toUser);
} else {
log.warn("角色 '{}' 中找到了 {} 个用户,但无人配置企业微信账号,未发送任何通知。", LEADER_ROLE_KEY, userIdList.size());
// --- 步骤 4: (关键) 创建内部消息 (逐条) ---
FlowElement nextElement = getNextFlowElement(execution);
String taskName = (nextElement != null && nextElement.getName() != null) ? nextElement.getName() : "校领导审批";
String activityId = (nextElement != null) ? nextElement.getId() : "Activity_0ftj9eo";
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 internalMessageContent = messageText + link + hiddenIdentifier;
Long senderId = SecurityUtils.getUserId() != null ? SecurityUtils.getUserId() : 1L;
for (Long receiverId : userIdList) {
CphMsg cphMsg = new CphMsg();
cphMsg.setReceiver(receiverId);
cphMsg.setSender(senderId);
cphMsg.setContent(internalMessageContent);
cphMsgService.insertCphMsg(cphMsg);
log.info("已成功为校领导 (userId:{}) 创建内部消息。", receiverId);
}
} catch (Exception e) {
log.error("向校领导发送企业微信通知时出现异常。流程将继续。错误详情: {}", e.getMessage(), e);
log.error("在 SchoolLeaderApprovalListener 中发送通知时出现异常。错误详情: {}", e.getMessage(), e);
}
}
/**
* 安全地获取线上监听器的下一个目标节点
*/
private FlowElement getNextFlowElement(DelegateExecution execution) {
if (execution.getCurrentFlowElement() instanceof SequenceFlow) {
return ((SequenceFlow) execution.getCurrentFlowElement()).getTargetFlowElement();
}
return null;
}
}

View File

@@ -1,59 +1,137 @@
package com.srs.flowable.listener.disciplinary;
import com.srs.common.utils.SecurityUtils;
import com.srs.common.utils.WeChatUtil;
import com.srs.common.utils.spring.SpringUtils;
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;
import org.springframework.util.StringUtils;
import org.springframework.util.Assert;
import javax.annotation.PostConstruct;
/**
* 流程结束监听器。
* 在流程的最终节点,向当事学生发送处理结果的通知。 知无涯
* 为“学生接收”节点做准备并发送所有通知。 知无涯
* <p>
* 它的核心职责是:
* 1. 从流程变量 'stuId' 中获取学生ID。
* 2. 将学生ID设置到 'approval' 流程变量中供下一个UserTask分配办理人。
* 3. 向该学生发送企业微信通知。
* 4. 为该学生创建内部消息,并确保任务名正确。
* </p>
*/
@Component
@Component("stuInfoListener") // 保持Bean名称不变
@Slf4j
public class StuInfoListener implements ExecutionListener {
@Autowired
private DisciplinaryMapper disciplinaryMapper;
@Autowired
private ICphMsgService cphMsgService;
@Autowired(required = false)
private WeChatUtil weChatUtil;
@PostConstruct
public void checkDependencies() {
Assert.notNull(disciplinaryMapper, "DisciplinaryMapper in StuInfoListener is not injected!");
Assert.notNull(cphMsgService, "ICphMsgService in StuInfoListener is not injected!");
}
@Override
public void notify(DelegateExecution delegateExecution) {
// 1. 从流程变量中获取学生ID
Object stuIdObj = delegateExecution.getVariable("stuId");
public void notify(DelegateExecution execution) {
log.info("流程实例 [{}]: 触发 StuInfoListener (一体化版),为'学生接收'节点准备数据并发送通知...", execution.getProcessInstanceId());
// 安全检查确保stuId存在且类型正确
if (!(stuIdObj instanceof Long)) {
log.error("流程实例 [{}] 在结束时未能获取到有效的 'stuId' 变量,无法发送最终通知。", delegateExecution.getProcessInstanceId());
return;
// --- 步骤 1: 安全地获取学生ID ---
Object stuIdObj = execution.getVariable("stuId");
if (stuIdObj == null) {
throw new IllegalStateException("核心流程变量 'stuId' 未找到。");
}
Long stuId = (Long) stuIdObj;
log.info("流程实例 [{}] 即将结束准备向学生ID: {} 发送最终通知。", delegateExecution.getProcessInstanceId(), stuId);
// 2. 向该学生发送企业微信通知
Long stuId;
try {
DisciplinaryMapper disciplinaryMapper = SpringUtils.getBean(DisciplinaryMapper.class);
stuId = Long.parseLong(stuIdObj.toString());
} catch (NumberFormatException e) {
throw new IllegalStateException("流程变量 'stuId' 类型错误。");
}
// 根据学生ID查询其对应的企业微信账号(userName)
String userName = disciplinaryMapper.getUserNameByUserId(stuId);
// --- 步骤 2: (核心) 设置下一个任务的办理人 ---
execution.setVariable("approval", stuId);
log.info("已成功将下一个任务的办理人('approval')设置为学生ID: {}", stuId);
// 检查是否找到了对应的企业微信账号
if (!StringUtils.hasText(userName)) {
log.warn("流程实例 [{}]: 根据学生ID '{}' 未找到对应的企业微信账号,无法发送最终通知。", delegateExecution.getProcessInstanceId(), stuId);
return; // 中止发送逻辑
// --- 步骤 3: (可选) 发送企业微信通知 ---
sendWeChatNotification(stuId);
// --- 步骤 4: (关键新增) 创建内部消息,并确保任务名正确 ---
createInternalMessage(stuId, execution);
}
/**
* 发送企业微信通知的私有方法
*/
private void sendWeChatNotification(Long stuId) {
if (weChatUtil != null) {
try {
String studentUserName = disciplinaryMapper.getUserNameByUserId(stuId);
if (studentUserName != null && !studentUserName.isEmpty()) {
String content = "同学你好,关于你的一项违纪处分申请已有最终结果,请登录系统在'我的待办'中查看并确认。";
weChatUtil.sendTextMessage(studentUserName, content);
log.info("已成功向学生 (ID:{}) 发送企业微信通知。", stuId);
} else {
log.warn("未找到学生 (ID:{}) 对应的企业微信账号,未发送通知。", stuId);
}
} catch (Exception e) {
log.error("向学生 (ID:{}) 发送企业微信时发生异常: {}", stuId, e.getMessage(), e);
}
// 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);
}
}
/**
* 创建内部消息的私有方法
*/
private void createInternalMessage(Long receiverId, DelegateExecution execution) {
try {
FlowElement nextElement = getNextFlowElement(execution);
// String taskName = (nextElement != null && nextElement.getName() != null) ? nextElement.getName() : "结果确认";
// String activityId = (nextElement != null) ? nextElement.getId() : "Activity_0iy3ij6"; // 备用ID
String taskName = "学生接收";
String activityId = "Activity_0iy3ij6"; // 备用ID
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 internalMessageContent = messageText + link + hiddenIdentifier;
Long senderId = SecurityUtils.getUserId() != null ? SecurityUtils.getUserId() : 1L;
CphMsg cphMsg = new CphMsg();
cphMsg.setReceiver(receiverId);
cphMsg.setSender(senderId);
cphMsg.setContent(internalMessageContent);
cphMsgService.insertCphMsg(cphMsg);
log.info("已成功为学生 (ID:{}) 创建内部消息。", receiverId);
} catch (Exception e) {
log.error("为学生 (ID:{}) 创建内部消息时发生异常: {}", receiverId, e.getMessage(), e);
}
}
/**
* 安全地获取线上监听器的下一个目标节点
*/
private FlowElement getNextFlowElement(DelegateExecution execution) {
if (execution.getCurrentFlowElement() instanceof SequenceFlow) {
return ((SequenceFlow) execution.getCurrentFlowElement()).getTargetFlowElement();
}
return null;
}
}

View File

@@ -10,7 +10,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
/**
* 【线上监听器-升级版】为“学生教育管理科审核”节点做准备。
* 为“学生教育管理科审核”节点做准备。 知无涯
* 1. 向该候选组的所有成员发送企业微信通知。
* 2. 将该组的所有成员ID列表存入 'userList' 流程变量,供下游监听器(GenericMessageListener)使用。
*/

View File

@@ -14,7 +14,7 @@ import org.springframework.util.CollectionUtils;
import java.util.List;
/**
* 【生产者线上监听器】为“学院违纪处理委员会”多实例任务准备数据。
* 为“学院违纪处理委员会”多实例任务准备数据。 知无涯
* 1. 设置 'userList' 变量供多实例节点本身消费。
* 2. 设置 'nextTaskNameForMessage' 变量供下游消息监听器消费。
* 3. 发送企业微信通知。
@@ -76,4 +76,4 @@ public class XYWJCLWYHListener implements ExecutionListener {
}
return null;
}
}
}

View File

@@ -78,4 +78,4 @@
</dependencies>
</project>
</project>

View File

@@ -1,6 +1,7 @@
package com.srs.framework.mybatisplusMapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
public interface EasyBaseMapper<T> extends BaseMapper<T> {
@@ -11,4 +12,4 @@ public interface EasyBaseMapper<T> extends BaseMapper<T> {
* @return 影响行数
*/
Integer insertBatchSomeColumn(List<T> entityList);
}
}

View File

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

View File

@@ -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:12:765004", variables);
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_d46199lc:18:832592", variables);
String code = ajaxResult.get("code").toString();
if (code.equals("200")) {

View File

@@ -184,7 +184,7 @@ public class RtStuDisqualificationServiceImpl extends ServiceImpl<RtStuDisqualif
// todo 企业微信推送消息
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_8mod6d6a:6:477589", variables);
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_8mod6d6a:17:915004", variables);
String code = ajaxResult.get("code").toString();
if (code.equals("200")) {

View File

@@ -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:13:835109", variables);
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_vxuubvdh:14:915008", variables);
String code = ajaxResult.get("code").toString();
if (code.equals("200")) {

View File

@@ -4,12 +4,11 @@ import java.util.List;
import com.srs.framework.mybatisplusMapper.EasyBaseMapper;
import com.srs.stureg.domain.SrsMsgQueue;
import com.srs.stureg.domain.SrsStuReg;
import org.apache.ibatis.annotations.Mapper;
/**
* 短信队列Mapper接口
*
*
* @author srs
* @date 2023-07-24
*/
@@ -18,7 +17,7 @@ public interface SrsMsgQueueMapper extends EasyBaseMapper<SrsMsgQueue>
{
/**
* 查询短信队列
*
*
* @param id 短信队列主键
* @return 短信队列
*/
@@ -26,7 +25,7 @@ public interface SrsMsgQueueMapper extends EasyBaseMapper<SrsMsgQueue>
/**
* 查询短信队列列表
*
*
* @param srsMsgQueue 短信队列
* @return 短信队列集合
*/
@@ -34,7 +33,7 @@ public interface SrsMsgQueueMapper extends EasyBaseMapper<SrsMsgQueue>
/**
* 新增短信队列
*
*
* @param srsMsgQueue 短信队列
* @return 结果
*/
@@ -42,7 +41,7 @@ public interface SrsMsgQueueMapper extends EasyBaseMapper<SrsMsgQueue>
/**
* 修改短信队列
*
*
* @param srsMsgQueue 短信队列
* @return 结果
*/
@@ -50,7 +49,7 @@ public interface SrsMsgQueueMapper extends EasyBaseMapper<SrsMsgQueue>
/**
* 删除短信队列
*
*
* @param id 短信队列主键
* @return 结果
*/
@@ -58,7 +57,7 @@ public interface SrsMsgQueueMapper extends EasyBaseMapper<SrsMsgQueue>
/**
* 批量删除短信队列
*
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/

View File

@@ -407,10 +407,14 @@ public class SrsStuRegServiceImpl extends ServiceImpl<SrsStuRegMapper, SrsStuReg
public int updateSrsStuReg(SrsStuReg srsStuReg) {
// SrsClass sc=srsClassService.selectSrsClassByClassId(srsStuReg.getClassId());
SrsClass sc=srsClassService.selectSrsClassByClassCode(srsStuReg.getBJDM());
srsStuReg.setClassName(sc.getClassName());
srsStuReg.setBJ(sc.getClassName());
srsStuReg.setBJDM(sc.getClassCode());
if(srsStuReg.getBJDM()!=null||srsStuReg.getBJDM()!=""){
SrsClass sc=srsClassService.selectSrsClassByClassCode(srsStuReg.getBJDM());
if(sc!=null){
srsStuReg.setClassName(sc.getClassName());
srsStuReg.setBJ(sc.getClassName());
srsStuReg.setBJDM(sc.getClassCode());
}
}
srsStuReg.setUpdateTime(DateUtils.getNowDate());
return srsStuRegMapper.updateSrsStuReg(srsStuReg);
}