外宿申请-工作流监听器

This commit is contained in:
2025-12-08 17:28:03 +08:00
parent 13afaa08b4
commit c6abc87555
16 changed files with 1806 additions and 4 deletions

View File

@@ -3,6 +3,7 @@ package com.srs.routine.service;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.IService;
import com.srs.dormitory.domain.DmsOutsideAccommodationApply;
import com.srs.routine.domain.RtEnlistmentReserve;
/**
@@ -67,4 +68,21 @@ public interface IRtEnlistmentReserveService extends IService<RtEnlistmentReserv
* @return 结果
*/
int deleteRtEnlistmentReserveById(Long id);
/**
* 新增外宿申请
*
* @param dmsOutsideAccommodationApply 外宿申请
* @return 结果
*/
DmsOutsideAccommodationApply insertDmsOutsideAccommodationApply(DmsOutsideAccommodationApply dmsOutsideAccommodationApply);
/**
* 修改外宿申请
*
* @param dmsOutsideAccommodationApply 外宿申请
* @return 结果
*/
int updateDmsOutsideAccommodationApply(DmsOutsideAccommodationApply dmsOutsideAccommodationApply);
}

View File

@@ -10,6 +10,8 @@ import com.srs.common.doman.vo.TeacherVo;
import com.srs.common.exception.ServiceException;
import com.srs.common.utils.DateUtils;
import com.srs.common.utils.SecurityUtils;
import com.srs.dormitory.domain.DmsOutsideAccommodationApply;
import com.srs.dormitory.mapper.DmsOutsideAccommodationApplyMapper;
import com.srs.flowable.service.IFlowDefinitionService;
import lombok.extern.slf4j.Slf4j;
import com.srs.routine.mapper.RtStuLeaveApplicationMapper;
@@ -36,8 +38,8 @@ public class RtEnlistmentReserveServiceImpl extends ServiceImpl<RtEnlistmentRese
@Autowired
private RtEnlistmentReserveMapper rtEnlistmentReserveMapper;
// @Autowired
// private RtStuLeaveApplicationMapper rtStuLeaveApplicationMapper;
@Autowired
private DmsOutsideAccommodationApplyMapper dmsOutsideAccommodationApplyMapper; // 外宿申请
@Autowired
IFlowDefinitionService flowDefinitionService;
@@ -49,7 +51,7 @@ public class RtEnlistmentReserveServiceImpl extends ServiceImpl<RtEnlistmentRese
IdentityService identityService;
// 新增:注入RuntimeService(之前缺失)
// 注入RuntimeService
@Autowired
private RuntimeService runtimeService;
@@ -177,6 +179,7 @@ public class RtEnlistmentReserveServiceImpl extends ServiceImpl<RtEnlistmentRese
.processInstanceId(processInstanceId)
.taskAssignee(studentUserId) // 学生作为任务负责人
.active() // 仅查询活跃任务
.taskName("学生申请")
.list();
if (!studentTaskList.isEmpty()) {
@@ -381,4 +384,232 @@ public class RtEnlistmentReserveServiceImpl extends ServiceImpl<RtEnlistmentRese
public int deleteRtEnlistmentReserveById(Long id) {
return rtEnlistmentReserveMapper.deleteRtEnlistmentReserveById(id);
}
/**
* 新增外宿申请
*
* @param dmsOutsideAccommodationApply 外宿申请
* @return 结果
*/
@Override
public DmsOutsideAccommodationApply insertDmsOutsideAccommodationApply(DmsOutsideAccommodationApply dmsOutsideAccommodationApply) {
// 新增之前先查询申请记录是否存在,如果存在就不能新增重复的数据
DmsOutsideAccommodationApply outsideAccommodationApply = dmsOutsideAccommodationApplyMapper.getAccommodationByStuNameAndStuNo(dmsOutsideAccommodationApply.getStudentName(), dmsOutsideAccommodationApply.getStudentNo());
if (outsideAccommodationApply != null) {
throw new ServiceException("您已经申请过了,请勿重新申请!", 400);
}
dmsOutsideAccommodationApply.setCreateTime(DateUtils.getNowDate());
dmsOutsideAccommodationApply.setCreateBy(SecurityUtils.getUsername());
dmsOutsideAccommodationApply.setStartDate(DateUtils.getNowDate());
// 先插入申请表数据,获取自增 ID数据库自动为 applyStatus 赋值 0 若未传值)
int insertCount = dmsOutsideAccommodationApplyMapper.insertDmsOutsideAccommodationApply(dmsOutsideAccommodationApply);
if (insertCount <= 0) {
throw new ServiceException("申请表插入失败", 500);
}
Long applyId = dmsOutsideAccommodationApply.getId();
if (applyId == null) {
throw new ServiceException("申请表 ID 生成失败,无法继续操作", 500);
}
// 仅当 applyStatus = 1 时启动流程1=提交申请,进入审批)
// 注意:若前端未传 applyStatus数据库默认 0不会触发流程
if (1 == dmsOutsideAccommodationApply.getStatus()) {
// 绑定当前学生 ID提交人即学生本人确保流程变量准确
dmsOutsideAccommodationApply.setStudentId(SecurityUtils.getUserId());
// 启动流程(此时 applyId 已存在,可正常传递)
ProcessResultDto processResultDto = startOutsideAccommodationProcess(dmsOutsideAccommodationApply);
// 同步更新流程实例 ID + 申请状态为“审批中”2形成业务闭环
if (processResultDto != null && StringUtils.isNotBlank(processResultDto.getProcessInstanceId())) {
DmsOutsideAccommodationApply updateEntity = new DmsOutsideAccommodationApply();
updateEntity.setId(applyId);
updateEntity.setProcessInstanceId(processResultDto.getProcessInstanceId());
updateEntity.setDeployId(processResultDto.getDeploymentId());
/*updateEntity.setApplyStatus(1L); // 审批中状态(根据实际枚举调整)*/
dmsOutsideAccommodationApplyMapper.updateDmsOutsideAccommodationApply(updateEntity);
System.out.println("申请表[" + applyId + "]已启动流程实例ID" + processResultDto.getProcessInstanceId() + ",状态更新为审批中");
} else {
throw new ServiceException("流程启动失败,请重试", 500);
}
} else {
// 若 applyStatus 为 0数据库默认或其他值仅保存表单不启动流程
String statusDesc = dmsOutsideAccommodationApply.getStatus() == 0 ? "草稿" : "待辅导员审批";
System.out.println("申请表[" + applyId + "]状态为" + dmsOutsideAccommodationApply.getStatus() + "" + statusDesc + "),暂不启动流程");
}
return dmsOutsideAccommodationApply;
}
/**
* 修改外宿申请
*
* @param dmsOutsideAccommodationApply 外宿申请
* @return 结果
*/
@Override
public int updateDmsOutsideAccommodationApply(DmsOutsideAccommodationApply dmsOutsideAccommodationApply) {
if (dmsOutsideAccommodationApply.getId() == null) {
throw new ServiceException("申请表ID不能为空无法更新", 500);
}
dmsOutsideAccommodationApply.setUpdateTime(DateUtils.getNowDate());
dmsOutsideAccommodationApply.setUpdateBy(SecurityUtils.getUsername());
// 查询当前申请表的已有状态(判断流程是否已启动)
DmsOutsideAccommodationApply existing = dmsOutsideAccommodationApplyMapper.selectDmsOutsideAccommodationApplyById(dmsOutsideAccommodationApply.getId());
if (existing == null) {
throw new ServiceException("未查询到申请表数据,无法更新", 500);
}
// 判断流程是否已启动(存在 processInstanceId 即为已启动)
boolean isProcessStarted = StringUtils.isNotBlank(existing.getProcessInstanceId());
if (isProcessStarted) {
// 流程已启动:如果节点回到学生申请,则学生申请自动完成
System.out.println("申请表[" + dmsOutsideAccommodationApply.getId() + "]流程已启动实例ID" + existing.getProcessInstanceId() + "),仅更新数据");
// ========== 核心新增逻辑:仅当任务是「学生申请」节点时,学生自动完成待办任务 ==========
String processInstanceId = existing.getProcessInstanceId();
Long studentId = SecurityUtils.getUserId(); // 获取当前操作的学生ID
String studentUserId = studentId.toString(); // 转换为Flowable的Assignee字符串类型
// 1. 查询学生当前的待办任务流程实例ID+学生ID作为负责人增加任务名称/任务定义Key过滤仅匹配「学生申请」节点
List<Task> studentTaskList = taskService.createTaskQuery()
.processInstanceId(processInstanceId)
.taskAssignee(studentUserId) // 学生作为任务负责人
.active() // 仅查询活跃任务
.taskName("学生申请")
.list();
if (!studentTaskList.isEmpty()) {
for (Task studentTask : studentTaskList) {
// 补充完成任务的流程变量(如审批意见、结果,根据你的流程需求设置)
Map<String, Object> completeVariables = new HashMap<>();
completeVariables.put("approvalResult", "AGREE"); // 学生提交(默认同意)
completeVariables.put("approvalOpinion", "学生自动提交申请,等待辅导员审批");
completeVariables.put("operator", "student"); // 操作人类型
// 添加任务分配的备注(便于流程追溯)
taskService.addComment(
studentTask.getId(),
processInstanceId,
"自动分配负责人",
"学生已经重新修改提交申请"
);
// 2. 学生自动完成待办任务
taskService.complete(studentTask.getId(), completeVariables);
System.out.println("学生[" + studentUserId + "]已自动完成待办任务任务ID" + studentTask.getId());
}
// 3. 分配下一节点(辅导员)的待办任务负责人【不再复用监听器,独立实现】
assignCounselorTask(processInstanceId, existing.getId(), existing.getStudentNo());
} else {
System.out.println("流程实例[" + processInstanceId + "]中未查询到学生[" + studentUserId + "]的待办任务,无需自动完成");
}
// 同步更新流程变量(将业务表状态同步到流程中)
runtimeService.setVariable(processInstanceId, "applyStatus", dmsOutsideAccommodationApply.getStatus());
// 注意:若需更新流程相关变量,需调用 Flowable 的 runtimeService.setVariables(),此处仅更新业务表
return dmsOutsideAccommodationApplyMapper.updateDmsOutsideAccommodationApply(dmsOutsideAccommodationApply);
} else {
// 流程未启动:仅当 applyStatus=1 时启动流程,否则仅更新数据
Long applyStatus = dmsOutsideAccommodationApply.getStatus();
if (1L == applyStatus) {
// 绑定当前学生ID启动流程
dmsOutsideAccommodationApply.setStudentId(SecurityUtils.getUserId());
ProcessResultDto processResultDto = startOutsideAccommodationProcess(dmsOutsideAccommodationApply);
if (processResultDto == null || StringUtils.isBlank(processResultDto.getProcessInstanceId())) {
throw new ServiceException("流程启动失败,请重试", 500);
}
// 关联流程实例ID更新为“审批中”状态
dmsOutsideAccommodationApply.setProcessInstanceId(processResultDto.getProcessInstanceId());
dmsOutsideAccommodationApply.setDeployId(processResultDto.getDeploymentId());
dmsOutsideAccommodationApply.setStatus(1L); // 审批中
System.out.println("申请表[" + dmsOutsideAccommodationApply.getId() + "]启动流程成功实例ID" + processResultDto.getProcessInstanceId());
} else {
// 非提交状态:仅更新基础数据(如草稿修改)
String statusDesc = applyStatus == null ? "未指定状态" : (applyStatus == 0 ? "草稿" : "其他状态");
System.out.println("申请表[" + dmsOutsideAccommodationApply.getId() + "]状态为" + statusDesc + ",流程未启动,仅更新数据");
}
// 执行数据库更新含流程实例ID绑定或基础数据更新
return dmsOutsideAccommodationApplyMapper.updateDmsOutsideAccommodationApply(dmsOutsideAccommodationApply);
}
}
/**
* 开启外宿申请工作流
*
* @param dmsOutsideAccommodationApply
*/
private ProcessResultDto startOutsideAccommodationProcess(DmsOutsideAccommodationApply
dmsOutsideAccommodationApply) {
Map<String, Object> variables = new HashMap<>();
// 1. 传递关键变量(申请编号+主键ID用于任务匹配
String applyNo = dmsOutsideAccommodationApply.getApplyNo(); // 申请编号如RY2024001
Long enlistmentId = dmsOutsideAccommodationApply.getId(); // 申请表主键ID
variables.put("applyNo", applyNo);
variables.put("accommodationId", enlistmentId); // 新增:用于任务匹配的主键变量
variables.put("stuId", dmsOutsideAccommodationApply.getStudentId());
// 2. 查询辅导员信息
TeacherVo counselorInfo = dmsOutsideAccommodationApplyMapper.getCounselorInfo(dmsOutsideAccommodationApply.getStudentNo());
if (counselorInfo == null) {
throw new ServiceException("该学生暂无辅导员", 500);
}
variables.put("approval", counselorInfo.getUserId()); // 下一节点:辅导员
variables.put("deptId", counselorInfo.getDeptId());
// 3. 启动流程
AjaxResult ajaxResult = flowDefinitionService.startProcessInstanceById("flow_dre1txpk:11:1375008", variables);
String code = ajaxResult.get("code").toString();
if (!"200".equals(code)) {
throw new ServiceException("流程启动失败,错误码:" + code, 500);
}
ProcessResultDto dto = (ProcessResultDto) ajaxResult.get("data");
System.out.println("流程启动成功实例ID" + dto.getProcessInstanceId());
// 4. 学生自动完成自己的待办任务
identityService.setAuthenticatedUserId(SecurityUtils.getUserId().toString());
// 精准查询当前流程中属于学生的待办任务
List<Task> tasks = taskService.createTaskQuery()
.processInstanceId(dto.getProcessInstanceId())
.taskAssignee(SecurityUtils.getUserId().toString())
.active()
.list();
if (tasks.isEmpty()) {
throw new ServiceException("未查询到学生的待办任务,请检查流程设计", 500);
}
// 5. 完成任务匹配主键ID避免错误
variables.put("approved", true); // 学生提交确认
for (Task task : tasks) {
// 安全获取变量先判断是否为null再转换类型
Object varValue = taskService.getVariable(task.getId(), "accommodationId");
if (varValue == null) {
continue;
}
// 转换为Long类型与主键ID匹配
Long taskEnlistmentId;
try {
taskEnlistmentId = Long.parseLong(varValue.toString());
} catch (NumberFormatException e) {
continue; // 类型不匹配,跳过
}
// 匹配当前申请表的主键ID
if (taskEnlistmentId.equals(enlistmentId)) {
taskService.complete(task.getId(), variables);
System.out.println("学生已完成待办任务任务ID" + task.getId());
break; // 完成后退出循环,避免重复处理
}
}
// 6. 推送消息给辅导员(待办提醒)
// todo: 企业微信推送逻辑
return dto;
}
}