feat(dms): 添加故障报修工单服务备份实现,使用startCompleteTask(从hwbm的新版本plus框架中直接复制,未经过测试!)

- 实现了完整的故障报修工单业务逻辑,包括查询、新增、审批、维修等核心功能
- 集成了工作流服务,支持工单的流程化审批和状态推进
- 添加了设备信息、零部件更换记录、文件附件等关联数据处理
- 实现了PDA端兼容的工单创建和状态管理功能
- 添加了故障实例活动跟踪和维修过程记录功能
- 集成了远程文件服务,支持工单相关的图片上传和管理
master
zangch@mesnac.com 2 months ago
parent 2b4a234ab2
commit 6391a4902d

@ -0,0 +1,917 @@
package org.dromara.dms.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.constant.DmsConstants;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.uuid.Seq;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.dms.domain.*;
import org.dromara.dms.domain.bo.DmsBillsFaultInstanceBo;
import org.dromara.dms.domain.bo.DmsBillsFaultInstanceScanBo;
import org.dromara.dms.domain.bo.DmsFaultInstanceActivityBo;
import org.dromara.dms.domain.bo.DmsInstanceFileBo;
import org.dromara.dms.domain.mobile.DeviceBeen;
import org.dromara.dms.domain.vo.DmsBillsFaultInstanceVo;
import org.dromara.dms.domain.vo.DmsFaultComponentsPartsVo;
import org.dromara.dms.domain.vo.DmsFaultInstanceActivityVo;
import org.dromara.dms.domain.vo.DmsInstanceFileVo;
import org.dromara.dms.mapper.DmsBillsFaultInstanceMapper;
import org.dromara.dms.mapper.DmsFaultComponentsPartsMapper;
import org.dromara.dms.mapper.DmsFaultInstanceActivityMapper;
import org.dromara.dms.mapper.DmsInstanceFileMapper;
import org.dromara.dms.service.IDmsBillsFaultInstanceService;
import org.dromara.dms.service.IDmsFaultInstanceActivityService;
import org.dromara.dms.service.IDmsInstanceFileService;
import org.dromara.resource.api.RemoteFileService;
import org.dromara.resource.api.domain.RemoteFile;
import org.dromara.workflow.api.RemoteWorkflowService;
import org.dromara.workflow.api.domain.RemoteCompleteTask;
import org.dromara.workflow.api.domain.RemoteStartProcess;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.util.*;
/**
* Service
* startCompleteTask
*
* @author zch
* @date 2025-04-07
*/
@RequiredArgsConstructor
@Service
@Slf4j
public class DmsBillsFaultInstanceServiceImplBackup implements IDmsBillsFaultInstanceService {
private final DmsBillsFaultInstanceMapper baseMapper;
private final DmsInstanceFileMapper dmsInstanceFileMapper;
private final IDmsInstanceFileService DmsInstanceFileService;
@DubboReference(timeout = 30000, retries = 2)
private final RemoteWorkflowService remoteWorkflowService;
private final DmsFaultInstanceActivityMapper dmsFaultInstanceActivityMapper;
private final IDmsFaultInstanceActivityService dmsFaultInstanceActivityService;
@DubboReference(timeout = 15000, retries = 1)
private final RemoteFileService remoteFileService;
private final DmsFaultComponentsPartsMapper dmsFaultComponentsPartsMapper;
/**
*
*
*
* @param repairInstanceId
* @return
*/
@Override
public DmsBillsFaultInstanceVo queryById(Long repairInstanceId){
DmsBillsFaultInstanceVo vo = baseMapper.selectVoById(repairInstanceId);
if (vo != null) {
// 查询维修零件列表不使用分页避免SQL Server OFFSET语法问题
List<DmsFaultComponentsParts> partsList = dmsFaultComponentsPartsMapper.selectList(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<DmsFaultComponentsParts>()
.eq(DmsFaultComponentsParts::getRepairInstanceId, repairInstanceId)
);
vo.setParts(partsList);
}
return vo;
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<DmsBillsFaultInstanceVo> queryPageList(DmsBillsFaultInstanceBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<DmsBillsFaultInstance> lqw = buildQueryWrapper(bo);
Page<DmsBillsFaultInstanceVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @return
*/
@Override
public List<DmsBillsFaultInstanceVo> queryList(DmsBillsFaultInstanceBo bo) {
MPJLambdaWrapper<DmsBillsFaultInstance> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
@Override
public Long count(DmsBillsFaultInstanceBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<DmsBillsFaultInstance> lqw = JoinWrappers.lambda(DmsBillsFaultInstance.class)
.eq(bo.getRepairInstanceId() != null, DmsBillsFaultInstance::getRepairInstanceId, bo.getRepairInstanceId())
.eq(StringUtils.isNotBlank(bo.getBillsFaultCode()), DmsBillsFaultInstance::getBillsFaultCode, bo.getBillsFaultCode())
.eq(StringUtils.isNotBlank(bo.getInstanceType()), DmsBillsFaultInstance::getInstanceType, bo.getInstanceType())
.eq(StringUtils.isNotBlank(bo.getFaultSourceType()), DmsBillsFaultInstance::getFaultSourceType, bo.getFaultSourceType())
.eq(bo.getFaultSourceId() != null, DmsBillsFaultInstance::getFaultSourceId, bo.getFaultSourceId())
.eq(bo.getWfDefinitionId() != null, DmsBillsFaultInstance::getWfDefinitionId, bo.getWfDefinitionId())
.eq(bo.getMachineId() != null, DmsBillsFaultInstance::getMachineId, bo.getMachineId())
.eq(StringUtils.isNotBlank(bo.getApplyUser()), DmsBillsFaultInstance::getApplyUser, bo.getApplyUser())
.eq(bo.getApplyTime() != null, DmsBillsFaultInstance::getApplyTime, bo.getApplyTime())
.eq(bo.getRealBeginTime() != null, DmsBillsFaultInstance::getRealBeginTime, bo.getRealBeginTime())
.eq(bo.getRealEndTime() != null, DmsBillsFaultInstance::getRealEndTime, bo.getRealEndTime())
.eq(bo.getRequireEndTime() != null, DmsBillsFaultInstance::getRequireEndTime, bo.getRequireEndTime())
.eq(StringUtils.isNotBlank(bo.getBillsStatus()), DmsBillsFaultInstance::getBillsStatus, bo.getBillsStatus())
.eq(StringUtils.isNotBlank(bo.getApproveStatus()), DmsBillsFaultInstance::getApproveStatus, bo.getApproveStatus())
.eq(StringUtils.isNotBlank(bo.getRepairConfirm()), DmsBillsFaultInstance::getRepairConfirm, bo.getRepairConfirm())
.eq(StringUtils.isNotBlank(bo.getConfirmUser()), DmsBillsFaultInstance::getConfirmUser, bo.getConfirmUser())
.eq(StringUtils.isNotBlank(bo.getActiveFlag()), DmsBillsFaultInstance::getActiveFlag, bo.getActiveFlag());
return baseMapper.selectCount(lqw);
}
private MPJLambdaWrapper<DmsBillsFaultInstance> buildQueryWrapper(DmsBillsFaultInstanceBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<DmsBillsFaultInstance> lqw = JoinWrappers.lambda(DmsBillsFaultInstance.class)
.selectAll(DmsBillsFaultInstance.class)
//关联查询设备信息
.select(DmsBaseMachineInfo::getMachineName)
.select(DmsBaseMachineInfo::getMachineCode)
.select(DmsBaseMachineInfo::getMachineLocation)
.select(DmsBaseMachineInfo::getMachineSpec)
.leftJoin(DmsBaseMachineInfo.class, DmsBaseMachineInfo::getMachineId, DmsBaseShutReason::getMachineId)
//FIXME:关联查询设备信息
.select(DeviceBeen::getDeviceId)
.select(DeviceBeen::getDeviceCode)
.select(DeviceBeen::getDeviceName)
.select(DeviceBeen::getDeviceLocation)
.select(DeviceBeen::getDeviceTypeId)
.select(DeviceBeen::getDeviceSpec)
.select(DeviceBeen::getDeviceStatus)
.leftJoin(DeviceBeen.class, DeviceBeen::getDeviceId, DmsBillsFaultInstance::getMachineId)
//关联查询故障报修工单活动信息
//关联查询零部件更换记录
.select(DmsFaultComponentsParts::getPartName)
.select(DmsFaultComponentsParts::getPartSpecifications)
.select(DmsFaultComponentsParts::getAmount)
.leftJoin(DmsFaultComponentsParts.class, DmsFaultComponentsParts::getRepairInstanceId, DmsBillsFaultInstance::getRepairInstanceId)
.select(DmsInstanceFile::getFilePath)
.leftJoin(DmsInstanceFile.class, DmsInstanceFile::getTargetId, DmsBillsFaultInstance::getRepairInstanceId)
.eq(bo.getRepairInstanceId() != null, DmsBillsFaultInstance::getRepairInstanceId, bo.getRepairInstanceId())
.eq(StringUtils.isNotBlank(bo.getBillsFaultCode()), DmsBillsFaultInstance::getBillsFaultCode, bo.getBillsFaultCode())
.eq(StringUtils.isNotBlank(bo.getInstanceType()), DmsBillsFaultInstance::getInstanceType, bo.getInstanceType())
.eq(StringUtils.isNotBlank(bo.getFaultSourceType()), DmsBillsFaultInstance::getFaultSourceType, bo.getFaultSourceType())
.eq(bo.getFaultSourceId() != null, DmsBillsFaultInstance::getFaultSourceId, bo.getFaultSourceId())
.eq(bo.getWfDefinitionId() != null, DmsBillsFaultInstance::getWfDefinitionId, bo.getWfDefinitionId())
.eq(bo.getMachineId() != null, DmsBillsFaultInstance::getMachineId, bo.getMachineId())
.eq(StringUtils.isNotBlank(bo.getApplyUser()), DmsBillsFaultInstance::getApplyUser, bo.getApplyUser())
.eq(bo.getApplyTime() != null, DmsBillsFaultInstance::getApplyTime, bo.getApplyTime())
.eq(bo.getRealBeginTime() != null, DmsBillsFaultInstance::getRealBeginTime, bo.getRealBeginTime())
.eq(bo.getRealEndTime() != null, DmsBillsFaultInstance::getRealEndTime, bo.getRealEndTime())
.eq(bo.getRequireEndTime() != null, DmsBillsFaultInstance::getRequireEndTime, bo.getRequireEndTime())
.eq(StringUtils.isNotBlank(bo.getBillsStatus()), DmsBillsFaultInstance::getBillsStatus, bo.getBillsStatus())
.eq(StringUtils.isNotBlank(bo.getApproveStatus()), DmsBillsFaultInstance::getApproveStatus, bo.getApproveStatus())
.eq(StringUtils.isNotBlank(bo.getRepairConfirm()), DmsBillsFaultInstance::getRepairConfirm, bo.getRepairConfirm())
.eq(StringUtils.isNotBlank(bo.getConfirmUser()), DmsBillsFaultInstance::getConfirmUser, bo.getConfirmUser())
.eq(StringUtils.isNotBlank(bo.getActiveFlag()), DmsBillsFaultInstance::getActiveFlag, bo.getActiveFlag())
.orderByDesc(DmsBillsFaultInstance::getCreateTime);
return lqw;
}
/**
*
*
* @param bo
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public Boolean insertByBo(DmsBillsFaultInstanceBo bo) {
bo.setMachineId((long) bo.getDeviceId());
// 【关键修复】处理PDA端outsrcId到outsourcingId的转换
if (bo.getOutsrcId() != null && bo.getOutsrcId() > 0) {
bo.setOutsourcingId(Long.valueOf(bo.getOutsrcId()));
}
DmsBillsFaultInstance add = MapstructUtils.convert(bo, DmsBillsFaultInstance.class);
validEntityBeforeSave(add);
// 获取当前日期时间
Date curretnDate = new Date();
add.setApplyTime(curretnDate);
add.setApplyUser(LoginHelper.getUsername());
add.setBillsFaultCode(Seq.getId(Seq.dmsBillsFaultInstanceSeqType, Seq.dmsBillsFaultInstanceSeqCode));
// 设置报修状态为待维修
add.setBillsStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_TO_REPAIR);
// 设置审批状态为待审批按照PDA标准
add.setApproveStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_APPROVE_STATUS_PENDING);
// 设置实例类型为手动录入
add.setInstanceType(DmsConstants.DMS_BILLS_FAULT_INSTANCE_TYPE_MAUAL);
// 【修复】工单创建时确认状态应该为null不设置任何值
add.setRepairConfirm(null);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setRepairInstanceId(add.getRepairInstanceId());
}
// 【方案三】工作流相关:使用 startCompleteTask 一次性完成启动+推进
RemoteStartProcess remoteStartProcess = new RemoteStartProcess();
remoteStartProcess.setFlowCode(DmsConstants.DMS_BILLS_FAULT_INSTANCE_WF_CODE);
remoteStartProcess.setBusinessId(add.getRepairInstanceId().toString());
// 设置流程变量(后端发起必须忽略权限检查)
Map<String, Object> variables = new HashMap<>();
variables.put("businessId", add.getRepairInstanceId().toString());
variables.put("initiator", LoginHelper.getUsername());
variables.put("ignore", true); // 后端发起必须忽略权限
remoteStartProcess.setVariables(variables);
// 调用 startCompleteTask 一次完成启动+推进(内部使用独立事务,避免死锁)
boolean workflowResult = remoteWorkflowService.startCompleteTask(remoteStartProcess);
if (!workflowResult) {
throw new ServiceException("工作流启动失败");
}
// 获取流程实例ID用于后续关联
Long processInstanceId = remoteWorkflowService.getInstanceIdByBusinessId(add.getRepairInstanceId().toString());
// 更新工单的工作流实例ID
add.setWfDefinitionId(processInstanceId);
baseMapper.updateById(add);
log.info("工作流启动并推进成功repairInstanceId: {}, processInstanceId: {}",
add.getRepairInstanceId(), processInstanceId);
// 【重要修改】创建故障实例活动对象 - 只有PDA创建工单时才生成
DmsFaultInstanceActivity dmsFaultInstanceActivity = new DmsFaultInstanceActivity();
// 设置维修实例ID
dmsFaultInstanceActivity.setRepairInstanceId(add.getRepairInstanceId());
// 设置流程活动ID
dmsFaultInstanceActivity.setWfNodeId(processInstanceId);
// 设置故障类型
dmsFaultInstanceActivity.setFaultType(add.getFaultType());
// 设置故障描述
dmsFaultInstanceActivity.setFaultDescription(add.getFaultDescription());
// 设置设计操作
dmsFaultInstanceActivity.setDesignOperations(add.getDesignOperations());
// 设置设备ID
dmsFaultInstanceActivity.setMachineId(add.getMachineId());
// 设置维修类型
dmsFaultInstanceActivity.setRepairType(add.getRepairType());
// 【关键修复】如果外部资源ID不为空则设置外部资源ID
if (bo.getOutsourcingId() != null) {
dmsFaultInstanceActivity.setOutsourcingId(bo.getOutsourcingId());
}
// 设置处理状态为待审批
dmsFaultInstanceActivity.setProcessHandleStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_ACTIVITY_HANDLE_STATUS_TO_PICK);
// 设置流程步骤顺序
dmsFaultInstanceActivity.setProcessStepOrder(1l);
// 插入故障实例活动记录
dmsFaultInstanceActivityMapper.insert(dmsFaultInstanceActivity);
//存储图片
// 获取文件URL列表
List<String> fileUrls = bo.getFileUrls();
// 批量插入实例文件记录
batchInsertInstanceFiles(fileUrls, dmsFaultInstanceActivity.getInstanceActivityId());
return flag;
}
/**
*
*
* @param repairInstanceId ID
* @param approveStatus 2-3-
* @param message
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public Boolean approveWorkOrder(Long repairInstanceId, String approveStatus, String message) {
// 查询工单信息
DmsBillsFaultInstance workOrder = baseMapper.selectById(repairInstanceId);
if (workOrder == null) {
throw new ServiceException("工单不存在");
}
// 检查当前状态是否可以审批(必须是待审批状态)
if (!DmsConstants.DMS_BILLS_FAULT_INSTANCE_APPROVE_STATUS_PENDING.equals(workOrder.getApproveStatus())) {
throw new ServiceException("工单当前状态不允许审批");
}
// 更新审批状态和工单状态
workOrder.setApproveStatus(approveStatus);
if (DmsConstants.DMS_BILLS_FAULT_INSTANCE_APPROVE_STATUS_APPROVED.equals(approveStatus)) {
// 审批通过:保持待维修状态
workOrder.setBillsStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_TO_REPAIR);
} else if (DmsConstants.DMS_BILLS_FAULT_INSTANCE_APPROVE_STATUS_REJECTED.equals(approveStatus)) {
// 审批拒绝:设置为维修完成状态(终止工单)
workOrder.setBillsStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_FINISH);
}
// 先更新工单状态,确保业务数据一致性
boolean updateResult = baseMapper.updateById(workOrder) > 0;
if (!updateResult) {
throw new ServiceException("工单状态更新失败");
}
// 业务状态更新成功后,再推进工作流
if (workOrder.getWfDefinitionId() != null) {
try {
// 获取当前任务ID
Long currentTaskId = remoteWorkflowService.getCurrentTaskIdByInstanceId(workOrder.getWfDefinitionId());
if (currentTaskId != null) {
RemoteCompleteTask remoteCompleteTask = new RemoteCompleteTask();
remoteCompleteTask.setTaskId(currentTaskId);
remoteCompleteTask.setMessage(message != null ? message : "审批完成");
// 设置消息类型
List<String> messageTypes = new ArrayList<>();
messageTypes.add("1"); // 站内信
remoteCompleteTask.setMessageType(messageTypes);
// 设置消息通知内容
if (DmsConstants.DMS_BILLS_FAULT_INSTANCE_APPROVE_STATUS_APPROVED.equals(approveStatus)) {
remoteCompleteTask.setNotice("故障报修工单审批通过,请及时处理,工单编号:" + workOrder.getBillsFaultCode());
} else {
remoteCompleteTask.setNotice("故障报修工单审批被拒绝,工单编号:" + workOrder.getBillsFaultCode());
}
// 设置工作流变量 - approveStatus用于互斥网关判断
Map<String, Object> variables = new HashMap<>();
variables.put("approveStatus", approveStatus);
variables.put("businessId", repairInstanceId.toString());
remoteCompleteTask.setVariables(variables);
// 推进工作流
boolean workflowResult = remoteWorkflowService.completeTask(remoteCompleteTask);
if (!workflowResult) {
log.warn("工作流推进失败但业务状态已更新成功repairInstanceId: {}, approveStatus: {}",
repairInstanceId, approveStatus);
// 工作流推进失败不影响业务操作的成功
} else {
log.info("审批工单成功repairInstanceId: {}, approveStatus: {}", repairInstanceId, approveStatus);
}
} else {
log.warn("未找到当前活跃任务跳过工作流推进repairInstanceId: {}", repairInstanceId);
}
} catch (Exception e) {
log.error("工作流推进异常repairInstanceId: {}, approveStatus: {}", repairInstanceId, approveStatus, e);
// 工作流推进失败不影响业务操作的成功,但需要记录日志
}
}
return updateResult;
}
/**
*
*
* @param dmsFaultInstanceActivity
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public int startRepair(DmsFaultInstanceActivityBo dmsFaultInstanceActivity) {
// 根据维修实例ID查询故障实例信息
DmsBillsFaultInstance dmsBillsFaultInstance = baseMapper.selectById(dmsFaultInstanceActivity.getRepairInstanceId());
if (dmsBillsFaultInstance == null) {
throw new ServiceException("工单不存在");
}
// 检查审批状态按照PDA标准只有状态为"2"审批成功才可以开始维修)
if (!DmsConstants.DMS_BILLS_FAULT_INSTANCE_APPROVE_STATUS_APPROVED.equals(dmsBillsFaultInstance.getApproveStatus())) {
throw new ServiceException("工单未审批通过,无法开始维修");
}
// 检查工单状态
String dmsBillsStatus = dmsBillsFaultInstance.getBillsStatus();
if (!dmsBillsStatus.equals(DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_TO_REPAIR)) {
throw new ServiceException("工单状态不允许开始维修");
}
// 获取当前日期和登录用户名
Date currentDate = new Date();
String userName = LoginHelper.getLoginUser() == null ? LoginHelper.getUsername() : LoginHelper.getLoginUser().getNickname();
// 设置工单状态为维修中
dmsBillsFaultInstance.setBillsStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_REPAIRING);
// 设置实际开始时间
dmsBillsFaultInstance.setRealBeginTime(currentDate);
// 推进工作流
if (dmsBillsFaultInstance.getWfDefinitionId() != null) {
Long currentTaskId = remoteWorkflowService.getCurrentTaskIdByInstanceId(dmsBillsFaultInstance.getWfDefinitionId());
if (currentTaskId != null) {
RemoteCompleteTask remoteCompleteTask = new RemoteCompleteTask();
remoteCompleteTask.setTaskId(currentTaskId);
remoteCompleteTask.setMessage("开始维修");
List<String> messageTypes = new ArrayList<>();
messageTypes.add("1"); // 站内信
remoteCompleteTask.setMessageType(messageTypes);
remoteCompleteTask.setNotice("故障报修工单已开始维修,工单编号:" + dmsBillsFaultInstance.getBillsFaultCode());
boolean b = remoteWorkflowService.completeTask(remoteCompleteTask);
if (!b) {
throw new ServiceException("工作流推进失败");
}
}
}
// 更新工单状态
baseMapper.updateById(dmsBillsFaultInstance);
// 设置维修实例活动记录
dmsFaultInstanceActivity.setRepairInstanceId(dmsBillsFaultInstance.getRepairInstanceId());
dmsFaultInstanceActivity.setMachineId(dmsBillsFaultInstance.getMachineId());
dmsFaultInstanceActivity.setProcessHandleStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_ACTIVITY_HANDLE_STATUS_EXECUTING);
dmsFaultInstanceActivity.setProcessStepOrder(2L);
dmsFaultInstanceActivity.setStartTime(currentDate);
dmsFaultInstanceActivity.setHandleUserId(LoginHelper.getUserId());
dmsFaultInstanceActivity.setHandleBy(userName);
dmsFaultInstanceActivity.setHandleTime(currentDate);
// 【调试日志】打印传入的活动ID以确认问题根源
log.info("调用startRepair时从控制器传入的instanceActivityId为: {}", dmsFaultInstanceActivity.getInstanceActivityId());
// 【关键修复】在插入新的活动记录前必须将ID设置为空。
// 这是因为传入的dmsFaultInstanceActivity对象可能包含了由PDA端getBillsFaultInstance4Repair接口返回的
// 第一个活动节点process_step_order=1的ID。如果不清空MyBatis会尝试使用这个旧ID插入新记录
// 如果instance_activity_id不是主键或唯一键就会导致数据重复如果是则会抛出主键冲突异常。
dmsFaultInstanceActivity.setInstanceActivityId(null);
// 插入新的故障实例活动记录
boolean result = dmsFaultInstanceActivityService.insertByBo(dmsFaultInstanceActivity);
return result ? 1 : 0;
}
/**
*
*
* @param dmsFaultInstanceActivity
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public int completeRepair(DmsFaultInstanceActivityBo dmsFaultInstanceActivity, List<MultipartFile> files) {
// 更新 dms_fault_instance_activity 表
DmsFaultInstanceActivity activity = new DmsFaultInstanceActivity();
activity.setInstanceActivityId(dmsFaultInstanceActivity.getInstanceActivityId());
activity.setProcessHandleStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_ACTIVITY_HANDLE_STATUS_FINISH);
activity.setEndTime(new Date());
activity.setRepairer(LoginHelper.getLoginUser() == null ? LoginHelper.getUsername() : LoginHelper.getLoginUser().getNickname());
dmsFaultInstanceActivityMapper.updateById(activity);
// 批量保存处理的零部件
List<DmsFaultComponentsParts> parts = dmsFaultInstanceActivity.getParts();
if (parts != null && !parts.isEmpty()) {
parts.forEach(part -> {
part.setRepairInstanceId(dmsFaultInstanceActivity.getRepairInstanceId());
dmsFaultComponentsPartsMapper.insert(part);
});
}
// 处理文件上传
if (files != null && !files.isEmpty()) {
List<DmsInstanceFile> fileList = new ArrayList<>();
for (MultipartFile file : files) {
try {
RemoteFile remoteFile = remoteFileService.upload(file.getName(), file.getOriginalFilename(), file.getContentType(), file.getBytes());
DmsInstanceFile instanceFile = new DmsInstanceFile();
instanceFile.setTargetId(dmsFaultInstanceActivity.getInstanceActivityId());
instanceFile.setFilePath(remoteFile.getUrl());
instanceFile.setTargetType("1"); // 维修完成图片
fileList.add(instanceFile);
dmsInstanceFileMapper.insert(instanceFile);
} catch (Exception e) {
throw new ServiceException("文件上传失败");
}
}
}
// 更新 dms_bills_fault_instance 表
DmsBillsFaultInstance instance = baseMapper.selectById(dmsFaultInstanceActivity.getRepairInstanceId());
if (instance == null) {
throw new ServiceException("工单不存在: " + dmsFaultInstanceActivity.getRepairInstanceId());
}
instance.setBillsStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_FINISH);
instance.setRealEndTime(new Date());
instance.setRepairConfirm("0"); // 设置为待确认状态
baseMapper.updateById(instance);
// 推进工作流
if (instance.getWfDefinitionId() != null) {
Long currentTaskId = remoteWorkflowService.getCurrentTaskIdByInstanceId(instance.getWfDefinitionId());
if (currentTaskId != null) {
RemoteCompleteTask remoteCompleteTask = new RemoteCompleteTask();
remoteCompleteTask.setTaskId(currentTaskId);
remoteCompleteTask.setMessage("完成维修");
List<String> messageTypes = new ArrayList<>();
messageTypes.add("1"); // 站内信
remoteCompleteTask.setMessageType(messageTypes);
remoteCompleteTask.setNotice("故障报修工单维修完成,待主管确认,工单编号:" + instance.getBillsFaultCode());
boolean b = remoteWorkflowService.completeTask(remoteCompleteTask);
if (!b) {
throw new ServiceException("工作流推进失败");
}
}
}
return 1;
}
/**
*
*
* @param repairInstanceId ID
* @param confirmResult 1-2-
* @param confirmUser
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public Boolean confirmRepairResult(Long repairInstanceId, String confirmResult, String confirmUser) {
// 查询工单信息
DmsBillsFaultInstance workOrder = baseMapper.selectById(repairInstanceId);
if (workOrder == null) {
throw new ServiceException("工单不存在");
}
// 检查当前状态是否可以确认
if (!DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_FINISH.equals(workOrder.getBillsStatus())) {
throw new ServiceException("工单尚未完成维修,无法确认");
}
if (!"0".equals(workOrder.getRepairConfirm())) {
throw new ServiceException("工单已经确认过了");
}
// 根据确认结果设置不同的业务状态
if ("1".equals(confirmResult)) {
// 确认通过:完成工单
workOrder.setRepairConfirm(confirmResult);
workOrder.setConfirmUser(confirmUser != null ? confirmUser : LoginHelper.getUsername());
workOrder.setConfirmTime(new Date());
} else {
// 确认不通过:返回到维修环节,重置相关状态
workOrder.setRepairConfirm(confirmResult);
workOrder.setConfirmUser(confirmUser != null ? confirmUser : LoginHelper.getUsername());
workOrder.setConfirmTime(new Date());
// 重置工单状态为待维修,让维修人员重新维修
workOrder.setBillsStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_TO_REPAIR);
// 清空实际结束时间,因为需要重新维修
workOrder.setRealEndTime(null);
}
// 推进工作流:业务状态和工作流分支变量分离处理
if (workOrder.getWfDefinitionId() != null) {
Long currentTaskId = remoteWorkflowService.getCurrentTaskIdByInstanceId(workOrder.getWfDefinitionId());
if (currentTaskId != null) {
RemoteCompleteTask remoteCompleteTask = new RemoteCompleteTask();
remoteCompleteTask.setTaskId(currentTaskId);
// 设置工作流变量 - 用于互斥网关判断分支走向
Map<String, Object> variables = new HashMap<>();
if ("1".equals(confirmResult)) {
// 确认通过:工作流分支变量=0走确认通过分支结束流程
remoteCompleteTask.setMessage("主管确认通过,工单完成");
variables.put("repairConfirm", "0");
} else {
// 确认不通过:工作流分支变量=1走确认不通过分支返回维修环节
remoteCompleteTask.setMessage("主管确认不通过,返回维修环节");
variables.put("repairConfirm", "1");
}
variables.put("businessId", repairInstanceId.toString());
remoteCompleteTask.setVariables(variables);
List<String> messageTypes = new ArrayList<>();
messageTypes.add("1"); // 站内信
remoteCompleteTask.setMessageType(messageTypes);
// 设置消息通知内容
if ("1".equals(confirmResult)) {
remoteCompleteTask.setNotice("故障报修工单已完成,工单编号:" + workOrder.getBillsFaultCode());
} else {
remoteCompleteTask.setNotice("故障报修工单确认不通过,需重新维修,工单编号:" + workOrder.getBillsFaultCode());
}
boolean workflowResult = remoteWorkflowService.completeTask(remoteCompleteTask);
if (!workflowResult) {
log.warn("工作流推进失败但业务状态已更新成功repairInstanceId: {}, confirmResult: {}",
repairInstanceId, confirmResult);
} else {
log.info("主管确认完成工作流推进成功repairInstanceId: {}, confirmResult: {}",
repairInstanceId, confirmResult);
}
}
}
return baseMapper.updateById(workOrder) > 0;
}
/**
*
*
* @param bo
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(DmsBillsFaultInstanceBo bo) {
DmsBillsFaultInstance update = MapstructUtils.convert(bo, DmsBillsFaultInstance.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
*
*/
private void validEntityBeforeSave(DmsBillsFaultInstance entity){
//TODO 做一些数据校验,如唯一约束
}
/**
*
*
* @param ids
* @param isValid
* @return
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* ID
* @param repairInstanceId ID
* @param wfDefinitionId ID
* @return truefalse
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateWfDefinitionIdById(Long repairInstanceId, Long wfDefinitionId) {
if(StringUtils.isNull(repairInstanceId)){
throw new ServiceException("参数为空");
}
DmsBillsFaultInstance entity = baseMapper.selectById(repairInstanceId);
if (entity == null) {
throw new ServiceException("记录不存在");
}
entity.setWfDefinitionId(wfDefinitionId);
entity.setRealBeginTime(new Date());
return baseMapper.updateById(entity) > 0;
}
@Override
public DmsFaultInstanceActivity selectFaults(Long repairInstanceId) {
List<DmsFaultInstanceActivityVo> list = baseMapper.selectFaults(repairInstanceId);
List<DmsFaultComponentsPartsVo> parts = baseMapper.selectParts(repairInstanceId);
DmsFaultInstanceActivity activity = new DmsFaultInstanceActivity();
BeanUtils.copyProperties(list.get(0),activity);
// activity.setCheckedFault(list.get(0).getCheckedFault());
activity.setParts(parts);
return activity;
}
/**
*
*
* @param repairInstanceId
* @return
*/
@Override
public DmsBillsFaultInstanceVo selectDmsBillsFaultInstanceByRepairInstanceId(Long repairInstanceId) {
try {
// 根据repairInstanceId查询故障实例及其关联的设备和第一条活动记录
DmsBillsFaultInstanceVo dmsBillsFaultInstance = baseMapper.selectFaultInstanceJoinFirstAndDeviceById(repairInstanceId);
if (dmsBillsFaultInstance == null) {
throw new ServiceException("工单不存在repairInstanceId: " + repairInstanceId);
}
// 【调试日志】输出查询结果确认outsourcingId是否正确获取
log.info("查询工单详情repairInstanceId: {}, outsourcingId: {}, instanceActivityId: {}",
repairInstanceId, dmsBillsFaultInstance.getOutsourcingId(), dmsBillsFaultInstance.getInstanceActivityId());
// 【关键修复】查询零部件信息确保PDA端兼容性
List<DmsFaultComponentsPartsVo> partsVoList = baseMapper.selectParts(repairInstanceId);
if (partsVoList == null) {
partsVoList = new ArrayList<>(); // 确保不为null
}
// 转换为实体对象并设置到工单中
List<DmsFaultComponentsParts> partsList = MapstructUtils.convert(partsVoList, DmsFaultComponentsParts.class);
dmsBillsFaultInstance.setParts(partsList);
// 创建实例文件查询对象
DmsInstanceFileBo queryInstanceFile = new DmsInstanceFileBo();
// 设置目标类型为故障实例活动
queryInstanceFile.setTargetType(DmsConstants.DMS_INSTANCE_FILE_TARGET_TYPE_FAULT_INSTANCE_ACTIVITY);
// 设置目标ID为故障实例的活动ID
queryInstanceFile.setTargetId(dmsBillsFaultInstance.getInstanceActivityId());
// 查询实例文件列表
List<DmsInstanceFileVo> dmsInstanceFiles = DmsInstanceFileService.queryList(queryInstanceFile);
// 遍历实例文件列表FIXME
for (DmsInstanceFileVo dmsInstanceFile : dmsInstanceFiles){
// 获取文件路径
String filePath = dmsInstanceFile.getFilePath();
// 如果文件路径不包含"9005"
if(!filePath.contains("9005")){
// 如果文件路径包含"https",将其替换为"http"
if(filePath.contains("https")){
filePath.replaceFirst("https","http");
}
// 找到"/statics"的索引位置
int index= filePath.indexOf("/statics");
// 修改文件路径为新的地址
filePath = "http://118.25.106.99:9005"+filePath.substring(index);
// 设置新的URL和文件路径
dmsInstanceFile.setFilePath(filePath);
}else{
// 如果文件路径包含"9005"直接设置URL为文件路径
dmsInstanceFile.setFilePath(dmsInstanceFile.getFilePath());
}
}
List<DmsInstanceFile> InstanceFiles = MapstructUtils.convert(dmsInstanceFiles, DmsInstanceFile.class);
// 将修改后的实例文件列表设置到故障实例中
dmsBillsFaultInstance.setDmsInstanceFiles(InstanceFiles);
// 返回故障实例对象
return dmsBillsFaultInstance;
} catch (Exception e) {
log.error("查询工单详情异常repairInstanceId: {}", repairInstanceId, e);
// 如果是查询返回多条记录的异常,尝试备用查询方案
if (e.getMessage() != null && e.getMessage().contains("Expected one result")) {
log.warn("检测到查询返回多条记录异常尝试备用查询方案repairInstanceId: {}", repairInstanceId);
// 备用方案:查询工单基本信息和最新的活动记录
DmsBillsFaultInstanceVo workOrder = baseMapper.selectVoById(repairInstanceId);
if (workOrder != null) {
// 查询最新的活动记录
MPJLambdaWrapper<DmsFaultInstanceActivity> wrapper = JoinWrappers.lambda(DmsFaultInstanceActivity.class)
.eq(DmsFaultInstanceActivity::getRepairInstanceId, repairInstanceId)
.orderByDesc(DmsFaultInstanceActivity::getProcessStepOrder)
.orderByDesc(DmsFaultInstanceActivity::getInstanceActivityId)
.last("LIMIT 1");
DmsFaultInstanceActivity latestActivity = dmsFaultInstanceActivityMapper.selectOne(wrapper);
if (latestActivity != null) {
// 设置活动相关信息
workOrder.setInstanceActivityId(latestActivity.getInstanceActivityId());
workOrder.setFaultType(latestActivity.getFaultType());
workOrder.setFaultDescription(latestActivity.getFaultDescription());
workOrder.setDesignOperations(latestActivity.getDesignOperations());
workOrder.setRepairType(latestActivity.getRepairType());
workOrder.setOutsourcingId(latestActivity.getOutsourcingId());
workOrder.setProcessHandleResolution(latestActivity.getProcessHandleResolution());
}
log.info("备用查询方案成功repairInstanceId: {}, instanceActivityId: {}",
repairInstanceId, workOrder.getInstanceActivityId());
return workOrder;
}
}
throw new ServiceException("查询工单详情失败:" + e.getMessage());
}
}
public void batchInsertInstanceFiles(List<String> fileUrls, Long instanceActivityId) {
// 判断文件URL列表是否不为空且非空
if (fileUrls != null && !fileUrls.isEmpty()) {
// 创建一个DmsInstanceFile对象的列表
List<DmsInstanceFile> dmsInstanceFiles = new ArrayList<>();
// 遍历文件URL列表
for (String fileUrl : fileUrls) {
// 创建一个新的DmsInstanceFile对象
DmsInstanceFile dmsInstanceFile = new DmsInstanceFile();
// 设置目标ID为实例活动ID
dmsInstanceFile.setTargetId(instanceActivityId);
// 设置目标类型为故障实例活动
dmsInstanceFile.setTargetType(DmsConstants.DMS_INSTANCE_FILE_TARGET_TYPE_FAULT_INSTANCE_ACTIVITY);
// 设置文件路径为当前URL
dmsInstanceFile.setFilePath(fileUrl);
// 将DmsInstanceFile对象添加到列表中
dmsInstanceFiles.add(dmsInstanceFile);
}
// 批量插入DmsInstanceFile对象到数据库
dmsInstanceFileMapper.batchDmsInstanceFile(dmsInstanceFiles);
}
}
/**
*
*
* @param dmsFaultInstanceActivity
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public int updateDmsFaultInstanceActivity(DmsFaultInstanceActivityBo dmsFaultInstanceActivity) {
// 获取文件URL列表
List<String> fileUrls = dmsFaultInstanceActivity.getFileUrls();
// 获取实例ID
Long activityId = dmsFaultInstanceActivity.getInstanceActivityId();
// 根据实例ID查询对应的维修实例ID
Long repairInstanceId = dmsFaultInstanceActivityMapper.selectRepairInstanceId(activityId);
// 创建新的DmsBillsFaultInstance对象
DmsBillsFaultInstance dmsBillsFaultInstance = new DmsBillsFaultInstance();
// 设置外包ID
dmsBillsFaultInstance.setOutsourcingId(dmsFaultInstanceActivity.getOutsourcingId());
// 设置故障来源类型
dmsBillsFaultInstance.setFaultSourceType(dmsFaultInstanceActivity.getFaultSourceType());
// 设置故障类型
dmsBillsFaultInstance.setFaultType(dmsFaultInstanceActivity.getFaultType());
// 设置维修工单ID主键
dmsBillsFaultInstance.setRepairInstanceId(repairInstanceId);
validEntityBeforeSave(dmsBillsFaultInstance);
// 根据ID更新DmsBillsFaultInstance记录
int i = baseMapper.updateById(dmsBillsFaultInstance);
// 根据目标ID删除dms_instance_file表记录
int rows = dmsFaultInstanceActivityMapper.deleteByTargetId(activityId);
// 批量插入实例文件
batchInsertInstanceFiles(fileUrls,activityId);
// 根据ID更新记录并返回影响行数
DmsFaultInstanceActivity faultInstanceActivity = MapstructUtils.convert(dmsFaultInstanceActivity, DmsFaultInstanceActivity.class);
return dmsFaultInstanceActivityMapper.updateById(faultInstanceActivity);
}
/**
*
*
* @param dmsBillsFaultInstanceScanVo
*/
@Override
public Long scanDevice4Repair(DmsBillsFaultInstanceScanBo dmsBillsFaultInstanceScan) {
Long count = baseMapper.selectCountByRepairInstanceIdAndDeviceCode(
dmsBillsFaultInstanceScan.getRepairInstanceId(), dmsBillsFaultInstanceScan.getDeviceCode());
if (count <= 0) {
throw new ServiceException("扫描验证失败");
}else {
return count;
}
}
public void batchInsertInstanceAfterFiles(List<String> fileUrls, Long instanceActivityId) {
// 判断文件URL列表是否不为空且非空集合
if (fileUrls != null && !fileUrls.isEmpty()) {
// 创建一个DmsInstanceFile对象的列表用于存储文件信息
List<DmsInstanceFile> dmsInstanceFiles = new ArrayList<>();
// 遍历文件URL列表
for (String fileUrl : fileUrls) {
// 创建一个新的DmsInstanceFile对象
DmsInstanceFile dmsInstanceFile = new DmsInstanceFile();
// 设置目标ID为传入的实例活动ID
dmsInstanceFile.setTargetId(instanceActivityId);
// 设置目标类型为"2",表示关联类型为维修后
dmsInstanceFile.setTargetType("2");//关联类型(1维修前2维修后)
// 设置文件路径为当前遍历到的文件URL
dmsInstanceFile.setFilePath(fileUrl);
// 将DmsInstanceFile对象添加到列表中
dmsInstanceFiles.add(dmsInstanceFile);
}
// 调用数据映射器批量插入文件信息
dmsInstanceFileMapper.batchDmsInstanceFile(dmsInstanceFiles);
}
}
}
Loading…
Cancel
Save