Merge remote-tracking branch 'origin/master'

master
wanghao 1 week ago
commit 49ab37e589

@ -111,4 +111,5 @@ public interface RemoteWorkflowService {
* @return IDnull
*/
Long getCurrentTaskIdByInstanceId(Long instanceId);
}

@ -15,6 +15,11 @@ public class DmsConstants {
public static final String DMS_BILLS_FAULT_INSTANCE_STATUS_REPAIRING = "1";//维修中
public static final String DMS_BILLS_FAULT_INSTANCE_STATUS_FINISH = "2";//维修完成
/**故障报修工单审批状态按照PDA标准在PDA实体类DeviceRepair中*/
public static final String DMS_BILLS_FAULT_INSTANCE_APPROVE_STATUS_PENDING = "1";//待审批
public static final String DMS_BILLS_FAULT_INSTANCE_APPROVE_STATUS_APPROVED = "2";//审批成功
public static final String DMS_BILLS_FAULT_INSTANCE_APPROVE_STATUS_REJECTED = "3";//审批失败
/**故障报修工单实例状态*/
public static final String DMS_BILLS_FAULT_INSTANCE_ACTIVITY_HANDLE_STATUS_FINISH = "0";//已结束
public static final String DMS_BILLS_FAULT_INSTANCE_ACTIVITY_HANDLE_STATUS_EXECUTING = "1";//执行中

@ -14,6 +14,7 @@ import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
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.common.web.core.BaseController;
import org.dromara.dms.domain.bo.DmsBillsFaultInstanceBo;
import org.dromara.dms.domain.vo.DmsBillsFaultInstanceVo;
@ -67,7 +68,7 @@ public class DmsBillsFaultInstanceController extends BaseController {
@GetMapping("/{repairInstanceId}")
public R<DmsBillsFaultInstanceVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long repairInstanceId) {
return R.ok(dmsBillsFaultInstanceService.queryById(repairInstanceId));
return R.ok(dmsBillsFaultInstanceService.selectDmsBillsFaultInstanceByRepairInstanceId(repairInstanceId));
}
/**
@ -128,6 +129,37 @@ public class DmsBillsFaultInstanceController extends BaseController {
return toAjax(dmsBillsFaultInstanceService.updateWfDefinitionIdById(repairInstanceId, wfDefinitionId));
}
/**
*
*
* @param repairInstanceId ID
* @param approveStatus 2-3-
* @param message
*/
//@SaCheckPermission("dms:dmsBillsFaultInstance:approve")
@Log(title = "故障报修工单审批", businessType = BusinessType.UPDATE)
@PostMapping("/approve")
public R<Void> approve(@RequestParam Long repairInstanceId,
@RequestParam String approveStatus,
@RequestParam(required = false) String message) {
return toAjax(dmsBillsFaultInstanceService.approveWorkOrder(repairInstanceId, approveStatus, message));
}
/**
*
*
* @param repairInstanceId ID
* @param confirmResult 1-
*/
//@SaCheckPermission("dms:dmsBillsFaultInstance:confirm")
@Log(title = "故障报修工单确认", businessType = BusinessType.UPDATE)
@PostMapping("/confirm")
public R<Void> confirm(@RequestParam Long repairInstanceId,
@RequestParam String confirmResult) {
String confirmUser = LoginHelper.getUsername();
return toAjax(dmsBillsFaultInstanceService.confirmRepairResult(repairInstanceId, confirmResult, confirmUser));
}
// @PostMapping("faultRecordExport")
// public void faultRecordExport(DmsBillsFaultInstance dmsBillsFaultInstance, HttpServletResponse response) throws Exception {
// Map<String, Object> beanParams = new HashMap<>();

@ -3,6 +3,7 @@ package org.dromara.dms.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.DeserializationFeature;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
@ -97,6 +98,13 @@ public class DmsMobileController extends BaseController {
mobileInstance.setDeviceLocation(voInstance.getMachineLocation());
mobileInstance.setDeviceSpec(voInstance.getMachineSpec());
// 设置审批状态字段确保PDA端能获取到审批信息
mobileInstance.setApproveStatus(voInstance.getApproveStatus());
// 【修复】设置设备编码标签字段用于PDA端验证扫描设备编码
// 该字段用于PDA端startRepair方法中验证扫描的设备编码与工单中的设备编码是否一致
mobileInstance.setDeviceCodeTag(voInstance.getMachineCode());
// ID字段类型转换 - Long到String并处理字段映射差异
if (voInstance.getRepairInstanceId() != null) {
mobileInstance.setRepairInstanceId(String.valueOf(voInstance.getRepairInstanceId()));
@ -114,6 +122,45 @@ public class DmsMobileController extends BaseController {
mobileInstance.setMachineId(String.valueOf(voInstance.getMachineId()));
mobileInstance.setDeviceId(String.valueOf(voInstance.getMachineId()));
}
// 【关键修复】处理外协单位ID转换Long outsourcingId -> int outsrcId
if (voInstance.getOutsourcingId() != null) {
try {
mobileInstance.setOutsrcId(Math.toIntExact(voInstance.getOutsourcingId()));
} catch (ArithmeticException e) {
log.warn("外协单位ID转换失败值过大: {}", voInstance.getOutsourcingId());
mobileInstance.setOutsrcId(0); // 设置为0作为默认值
}
} else {
mobileInstance.setOutsrcId(0); // 当outsourcingId为null时明确设置为0
}
// 【关键修复】处理维修类型转换String repairType -> int repairType 并设置radioState
int repairTypeInt = 1; // 默认为内部维修
if (voInstance.getRepairType() != null) {
try {
repairTypeInt = Integer.parseInt(voInstance.getRepairType());
} catch (NumberFormatException e) {
log.warn("维修类型转换失败,无效值: {}, 使用默认值1", voInstance.getRepairType());
repairTypeInt = 1; // 默认为内部维修
}
}
mobileInstance.setRepairType(String.valueOf(repairTypeInt));
// 【关键修复】根据维修类型设置单选按钮状态模拟PDA端的repairTypeSelect逻辑
if (repairTypeInt == 1) {
// 内部维修
mobileInstance.setRadioState1(true);
mobileInstance.setRadioState2(false);
} else if (repairTypeInt == 2) {
// 委外维修
mobileInstance.setRadioState1(false);
mobileInstance.setRadioState2(true);
} else {
// 未知类型,默认为内部维修
mobileInstance.setRadioState1(true);
mobileInstance.setRadioState2(false);
}
}
/**
@ -159,7 +206,6 @@ public class DmsMobileController extends BaseController {
dictList.add(dict);
}
}
return AjaxResult.success(dictList);
}
@ -238,7 +284,7 @@ public class DmsMobileController extends BaseController {
DeviceBeen deviceBeen = MapstructUtils.convert(dmsBaseDeviceLedger, DeviceBeen.class);
// 手动处理字段映射差异machineId -> deviceId确保类型安全转换
if (dmsBaseDeviceLedger.getMachineId() != null) {
deviceBeen.setDeviceId(dmsBaseDeviceLedger.getMachineId().intValue());
deviceBeen.setDeviceId(dmsBaseDeviceLedger.getMachineId());
}
return AjaxResult.success(deviceBeen);
}
@ -410,10 +456,24 @@ public class DmsMobileController extends BaseController {
public AjaxResult getBillsFaultInstance4Repair(@PathVariable("repairInstanceId") Long repairInstanceId) {
// DmsBillsFaultInstanceVo billsFaultInstance = dmsBillsFaultInstanceService.queryById(repairInstanceId);
DmsBillsFaultInstanceVo billsFaultInstance = dmsBillsFaultInstanceService.selectDmsBillsFaultInstanceByRepairInstanceId(repairInstanceId);
// 【调试日志】输出查询结果
log.info("PDA获取工单详情repairInstanceId: {}, outsourcingId: {}",
repairInstanceId, billsFaultInstance.getOutsourcingId());
// 使用MapstructUtils进行高性能对象转换避免时间字段序列化问题
DmsBillsFaultInstanceMobile mobileInstance = MapstructUtils.convert(billsFaultInstance, DmsBillsFaultInstanceMobile.class);
billsFaultInstance.setDeviceCode(mobileInstance.getMachineCode());
billsFaultInstance.setDeviceId(Integer.parseInt(mobileInstance.getMachineId()));
billsFaultInstance.setDeviceName(mobileInstance.getMachineName());
billsFaultInstance.setDeviceLocation(mobileInstance.getMachineLocation());
billsFaultInstance.setDeviceSpec(mobileInstance.getMachineSpec());
// 手动格式化时间字段确保PDA客户端兼容性
formatTimeFields(mobileInstance, billsFaultInstance);
// 【调试日志】输出转换后的结果
log.info("PDA转换后结果outsrcId: {}", mobileInstance.getOutsrcId());
return AjaxResult.success(mobileInstance);
}
@ -441,9 +501,38 @@ public class DmsMobileController extends BaseController {
@Log(title = "故障报修工单", businessType = BusinessType.START)
@PostMapping("/startRepair")
@RepeatSubmit
public AjaxResult startRepair(@RequestBody DmsFaultInstanceActivityBo dmsFaultInstanceActivity) {
public AjaxResult startRepair(@RequestBody String json) {
try {
// 预处理 "amount" 字段
String processedJson = preprocessAmountFields(json);
// 手动反序列化
ObjectMapper objectMapper = new ObjectMapper();
// 【修复】 忽略未知字段,增强兼容性
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
DmsFaultInstanceActivityBo dmsFaultInstanceActivity = objectMapper.readValue(processedJson, DmsFaultInstanceActivityBo.class);
int i = dmsBillsFaultInstanceService.startRepair(dmsFaultInstanceActivity);
return AjaxResult.success(i);
} catch (ServiceException e) {
log.error("开始维修失败:{}", e.getMessage());
return AjaxResult.error(e.getMessage());
} catch (Exception e) {
log.error("数据处理失败:{}", e.getMessage());
return AjaxResult.error("数据处理失败:" + e.getMessage());
}
}
/**
* JSONamount
* "1.0""1"
*/
private String preprocessAmountFields(String json) {
if (json == null) {
return null;
}
// 将 "amount":"1.0" 转换成 "amount":1
return json.replaceAll("\"amount\"\\s*:\\s*\"?([0-9]+)\\.0+\"?", "\"amount\":$1");
}
/**
@ -455,18 +544,29 @@ public class DmsMobileController extends BaseController {
@RepeatSubmit
public AjaxResult completeRepair(DmsFaultInstanceActivityBo dmsFaultInstanceActivity,
@RequestParam(value = "files", required = false) List<MultipartFile> files) throws JsonProcessingException {
dmsFaultInstanceActivity.setRepairConfirm("2");
try {
// 注意这里不再设置repairConfirm因为在Service层会自动设置为0待确认
dmsFaultInstanceActivity.setConfirmTime(new Date());
String parts1 = dmsFaultInstanceActivity.getParts1();
ObjectMapper objectMapper = new ObjectMapper();
List<DmsFaultComponentsParts> parts2 = objectMapper.readValue(parts1, new TypeReference<List<DmsFaultComponentsParts>>() {
// 忽略未知字段,增强兼容性
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 由于PDA端传递的parts1是一个JSON字符串这里需要特殊处理
if (parts1 != null && !parts1.isEmpty()) {
// 预处理 "amount" 字段
String processedPartsJson = preprocessAmountFields(parts1);
List<DmsFaultComponentsParts> parts2 = objectMapper.readValue(processedPartsJson, new TypeReference<List<DmsFaultComponentsParts>>() {
});
dmsFaultInstanceActivity.setParts(parts2);
List<String> fileUrls = handleFileUploads(files);
dmsFaultInstanceActivity.setFileUrls(fileUrls);
//FIXME:关于工作流相关的本页代码以及调用方法都需测试完善修改
int i = dmsBillsFaultInstanceService.completeRepair(dmsFaultInstanceActivity);
}
int i = dmsBillsFaultInstanceService.completeRepair(dmsFaultInstanceActivity, files);
return AjaxResult.success(i);
} catch (ServiceException e) {
log.error("完成维修失败:{}", e.getMessage());
return AjaxResult.error(e.getMessage());
}
}
@ -490,13 +590,13 @@ public class DmsMobileController extends BaseController {
DmsInspectInstanceDetailMobile detailMobile = MapstructUtils.convert(detailVo, DmsInspectInstanceDetailMobile.class);
// 手动处理字段映射差异machineId -> deviceId
if (detailVo.getMachineId() != null) {
detailMobile.setDeviceId(detailVo.getMachineId().intValue());
detailMobile.setDeviceId(detailVo.getMachineId());
}
detailMobileList.add(detailMobile);
}
mobileInstance.setDmsInspectInstanceDetailList(detailMobileList);
}
//mobileInstance.setCreateTime(newestInspectInstance.getCreateTime());
return AjaxResult.success(mobileInstance);
}
@ -527,7 +627,7 @@ public class DmsMobileController extends BaseController {
// 手动处理字段映射差异machineId -> deviceId
if (dmsInspectInstanceDetailVo.getMachineId() != null) {
dmsInspectInstanceDetailMobile.setDeviceId(dmsInspectInstanceDetailVo.getMachineId().intValue());
dmsInspectInstanceDetailMobile.setDeviceId(dmsInspectInstanceDetailVo.getMachineId());
}
// 【方案对比实现】处理项目列表:使用流和类型过滤 vs 强制转换
@ -625,6 +725,7 @@ public class DmsMobileController extends BaseController {
*/
@Log(title = "点巡检工单明细", businessType = BusinessType.INSERT)
@PostMapping("/saveInspectInstanceDetail")
@RepeatSubmit
public AjaxResult saveInspectInstanceDetail(@RequestBody DmsInspectInstanceDetailBo dmsInspectInstanceDetail) {
return AjaxResult.success(dmsBillsInspectInstanceService.updateDmsInspectInstanceDetail(dmsInspectInstanceDetail));
}
@ -689,7 +790,6 @@ public class DmsMobileController extends BaseController {
DmsBillsMaintDetail result = dmsBillsMaintInstanceService.startMaint(dmsBillsMaintDetail);
// 转换为Mobile对象确保与PDA端兼容
MaintainDetail maintainDetail = MapstructUtils.convert(result, MaintainDetail.class);
// 手动处理字段映射差异machineId -> deviceId
if (result.getMachineId() != null) {
maintainDetail.setDeviceId(result.getMachineId());
@ -706,7 +806,6 @@ public class DmsMobileController extends BaseController {
maintainDetail.setMaintProtocol(result.getMaintProtocol());
maintainDetail.setMaintOperationDescription(result.getMaintOperationDescription());
maintainDetail.setOperationDescription(result.getOperationDescription());
// 处理嵌套对象的字段映射dmsBillsMaintDetailProjectList
if (result.getDmsBillsMaintDetailProjectList() != null) {
List<MaintainProject> maintainProjectList = new ArrayList<>();
@ -730,7 +829,6 @@ public class DmsMobileController extends BaseController {
}
maintainDetail.setDmsBillsMaintDetailProjectList(maintainProjectList);
}
return AjaxResult.success(maintainDetail);
}
@ -771,29 +869,88 @@ public class DmsMobileController extends BaseController {
// @RepeatSubmit
public AjaxResult getNewestLubeInstance(DmsBillsLubeInstanceBo dmsBillsLubeInstance) {
DmsBillsLubeInstanceVo newestLubeInstance = dmsBillsLubeInstanceService.getNewestBillsLubeInstance(dmsBillsLubeInstance);
// 使用MapstructUtils进行高性能对象转换避免时间字段序列化问题
DmsBillsLubeInstanceMobile mobileInstance = MapstructUtils.convert(newestLubeInstance, DmsBillsLubeInstanceMobile.class);
// 【PDA适配】如果查询结果为空直接返回
if (newestLubeInstance == null) {
return AjaxResult.success(null);
}
// 【关键修复】使用手动转换而不是MapstructUtils避免序列化问题
DmsBillsLubeInstanceMobile mobileInstance = new DmsBillsLubeInstanceMobile();
// 手动设置基本字段
mobileInstance.setLubeInstanceId(newestLubeInstance.getLubeInstanceId());
mobileInstance.setPlanLubeId(newestLubeInstance.getPlanLubeId());
mobileInstance.setBillsLubeCode(newestLubeInstance.getBillsLubeCode());
mobileInstance.setLubeGroup(newestLubeInstance.getLubeGroup());
mobileInstance.setLubeSupervisor(newestLubeInstance.getLubeSupervisor());
mobileInstance.setRemark(newestLubeInstance.getRemark());
// 【类型转换】处理状态字段的类型转换String -> Long
if (newestLubeInstance.getLubeLevel() != null) {
try {
mobileInstance.setLubeLevel(Long.valueOf(newestLubeInstance.getLubeLevel()));
} catch (NumberFormatException e) {
log.warn("润滑级别转换失败: {}", newestLubeInstance.getLubeLevel());
mobileInstance.setLubeLevel(null);
}
}
if (newestLubeInstance.getLubeStatus() != null) {
try {
mobileInstance.setLubeStatus(Long.valueOf(newestLubeInstance.getLubeStatus()));
} catch (NumberFormatException e) {
log.warn("润滑状态转换失败: {}", newestLubeInstance.getLubeStatus());
mobileInstance.setLubeStatus(null);
}
}
// 处理嵌套对象的字段映射dmsBillsLubeDetailList
if (newestLubeInstance.getDmsBillsLubeDetailList() != null) {
List<LubricationDetail> lubricationDetailList = new ArrayList<>();
for (var detailVo : newestLubeInstance.getDmsBillsLubeDetailList()) {
LubricationDetail lubricationDetail = MapstructUtils.convert(detailVo, LubricationDetail.class);
LubricationDetail lubricationDetail = new LubricationDetail();
// 手动设置字段,确保类型匹配
lubricationDetail.setBillsLubeDetailId(detailVo.getBillsLubeDetailId());
lubricationDetail.setLubeInstanceId(detailVo.getLubeInstanceId());
lubricationDetail.setLubeStationId(detailVo.getLubeStationId());
lubricationDetail.setLubeStandardId(detailVo.getLubeStandardId());
lubricationDetail.setOperationDescription(detailVo.getOperationDescription());
// 手动处理字段映射差异machineId -> deviceId
if (detailVo.getMachineId() != null) {
lubricationDetail.setDeviceId(detailVo.getMachineId());
}
// 处理其他字段映射machineCode -> deviceCode, machineName -> deviceName
lubricationDetail.setDeviceCode(detailVo.getMachineCode());
lubricationDetail.setDeviceName(detailVo.getMachineName());
lubricationDetail.setTypeName(detailVo.getDeviceTypeName());
// 【关键修复】确保润滑部位和润滑标准字段正确映射
lubricationDetail.setLubeStationName(detailVo.getLubeStationName());
lubricationDetail.setLubeProtocol(detailVo.getLubeProtocol());
lubricationDetail.setLubeOperationDescription(detailVo.getLubeOperationDescription());
lubricationDetail.setLubeStandardCode(detailVo.getLubeStandardCode());
// 【类型转换】处理维护状态字段的类型转换String -> Long
if (detailVo.getMaintStatus() != null) {
try {
lubricationDetail.setMaintStatus(Long.valueOf(detailVo.getMaintStatus()));
} catch (NumberFormatException e) {
log.warn("润滑明细维护状态转换失败: {}", detailVo.getMaintStatus());
lubricationDetail.setMaintStatus(null);
}
} else {
lubricationDetail.setMaintStatus(null);
}
lubricationDetailList.add(lubricationDetail);
}
mobileInstance.setDmsBillsLubeDetailList(lubricationDetailList);
}
// 注意润滑Mobile类中的时间字段已被注释无需格式化
// 如果将来启用时间字段,请添加相应的格式化方法
// 【PDA兼容性】直接返回标准的AjaxResult让Spring Boot自动序列化为JSON
return AjaxResult.success(mobileInstance);
}
@ -821,5 +978,4 @@ public class DmsMobileController extends BaseController {
return AjaxResult.success(i);
}
}

@ -14,9 +14,9 @@ import java.io.Serial;
* @date 2025-04-07
*/
@Data
@EqualsAndHashCode(callSuper = true)
@EqualsAndHashCode
@TableName("dms_fault_components_parts")
public class DmsFaultComponentsParts extends TenantEntity {
public class DmsFaultComponentsParts {
@Serial
private static final long serialVersionUID = 1L;

@ -30,7 +30,7 @@ public class DmsFaultInstanceActivity extends TenantEntity {
/**
* ID
*/
@TableId(value = "instance_activity_id", type = IdType.AUTO)
@TableId(value = "instance_activity_id",type = IdType.ASSIGN_ID)
private Long instanceActivityId;
/**

@ -1,5 +1,6 @@
package org.dromara.dms.domain.bo;
import com.baomidou.mybatisplus.annotation.TableField;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@ -8,6 +9,8 @@ import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.dms.domain.DmsBillsFaultInstance;
import org.dromara.dms.domain.DmsFaultComponentsParts;
import org.dromara.dms.domain.DmsInstanceFile;
import java.util.Date;
import java.util.List;
@ -121,6 +124,10 @@ public class DmsBillsFaultInstanceBo extends BaseEntity {
*/
private Long outsourcingId;
/**
* IDPDAintoutsourcingId
*/
private Integer outsrcId;
/**
* ID machine_id
@ -158,4 +165,81 @@ public class DmsBillsFaultInstanceBo extends BaseEntity {
* String int
*/
private int deviceStatus;//DeviceBeen映射
private String machineCode;//JOIN
private String machineName;//JOIN
private String machineLocation;//JOIN
private String machineSpec;//JOIN
private String imgUrl;//JOIN
private Long instanceActivityId;//JOIN
private String faultType;//JOIN
private String faultDescription;//JOIN
private String designOperations;//JOIN
private String repairType;//JOIN
/**
* dms_base_outsourcing_infooutsourcing_id;12212
*/
private String processHandleResolution;//JOIN
// private List<SysFile> sysFiles;
private List<DmsInstanceFile> dmsInstanceFiles;//JOIN
private List<DmsInstanceFile> dmsInstanceFiles1;//JOIN
private String checkedFault;//JOIN
private String repairContent;//JOIN
private String protectedMethod;//JOIN
private String repairer;//JOIN
private Date confirmTime;//JOIN
private Long componentsPartsId;//JOIN
private List<DmsFaultComponentsParts> parts;//JOIN
/**
*
*/
private String filePath;//join
/**
*
*/
private String partName;//JOIN
/**
*
*/
private String partSpecifications;//JOIN
/**
*
*/
private Long amount;//JOIN
}

@ -10,6 +10,7 @@ import org.dromara.dms.domain.vo.DmsBillsInspectInstanceVo;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@ -128,5 +129,6 @@ public class DmsBillsInspectInstanceMobile implements Serializable {
private String inspectStatusStr;
private Date CreateTime;
}

@ -13,6 +13,7 @@ import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import java.util.Date;
/**

@ -2,6 +2,8 @@ package org.dromara.dms.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
@ -10,6 +12,7 @@ import org.dromara.dms.domain.DmsBillsMaintDetailProject;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@ -73,4 +76,29 @@ public class DmsBillsMaintDetailProjectVo implements Serializable {
/** 保养工单明细项目信息;检查每个项目的点巡检结果详情信息 */
/* private List<DmsBillsMaintDetailProject> dmsBillsMaintDetailProjectList;*/
/**
*
*/
private Long createDept;
/**
*
*/
private Long createBy;
/**
*
*/
private Date createTime;
/**
*
*/
private Long updateBy;
/**
*
*/
private Date updateTime;
}

@ -235,11 +235,13 @@ public class RemoteInspectInstanceServiceImpl implements RemoteInspectInstanceSe
// 推进工作流状态
RemoteCompleteTask completeTask = new RemoteCompleteTask();
completeTask.setTaskId(taskId);
completeTask.setMessage("检查工单启动,自动推进");
completeTask.setMessage("系统自动创建检查工单,请及时处理");
// 设置消息类型为非null的List
List<String> messageTypes = new ArrayList<>();
messageTypes.add("system"); // 系统消息
messageTypes.add("1"); // 站内信
completeTask.setMessageType(messageTypes);
// 设置消息通知内容
completeTask.setNotice("您有新的检查工单需要处理,工单编号:" + businessId);
// 【关键修复】在调用工作流推进前再次确认租户上下文
log.info("检查工作流推进前当前租户ID: {}", TenantHelper.getTenantId());
@ -248,7 +250,7 @@ public class RemoteInspectInstanceServiceImpl implements RemoteInspectInstanceSe
RpcContext.getContext().setAttachment("tenantId", currentTenantId);
// 【关键】调用工作流推进
boolean completeResult = remoteWorkflowService.completeTaskIgnoreAuth(taskId, "检查工单启动,自动推进");
boolean completeResult = remoteWorkflowService.completeTask(completeTask);
if (completeResult) {
log.info("检查工单 {} 工作流推进成功", businessId);
} else {

@ -254,11 +254,13 @@ public class RemoteLubeInstanceServiceImpl implements RemoteLubeInstanceService
// 2. 推进工作流状态
RemoteCompleteTask completeTask = new RemoteCompleteTask();
completeTask.setTaskId(taskId);
completeTask.setMessage("润滑工单启动,自动推进");
completeTask.setMessage("系统自动创建润滑工单,请及时处理");
// 设置消息类型为非null的List
List<String> messageTypes = new ArrayList<>();
messageTypes.add("system"); // 系统消息
messageTypes.add("1"); // 站内信
completeTask.setMessageType(messageTypes);
// 设置消息通知内容
completeTask.setNotice("您有新的润滑工单需要处理,工单编号:" + businessId);
// 【关键修复】在调用工作流推进前再次确认租户上下文
log.info("工作流推进前当前租户ID: {}", TenantHelper.getTenantId());

@ -257,11 +257,13 @@ public class RemoteMaintInstanceServiceImpl implements RemoteMaintInstanceServic
// 2. 推进工作流状态
RemoteCompleteTask completeTask = new RemoteCompleteTask();
completeTask.setTaskId(taskId);
completeTask.setMessage("保养工单启动,自动推进");
completeTask.setMessage("系统自动创建保养工单,请及时处理");
// 设置消息类型为非null的List
List<String> messageTypes = new ArrayList<>();
messageTypes.add("system"); // 系统消息
messageTypes.add("1"); // 站内信
completeTask.setMessageType(messageTypes);
// 设置消息通知内容
completeTask.setNotice("您有新的保养工单需要处理,工单编号:" + businessId);
// 【关键修复】在调用工作流推进前再次确认租户上下文
log.info("保养工作流推进前当前租户ID: {}", TenantHelper.getTenantId());

@ -4,6 +4,8 @@ import org.dromara.dms.domain.DmsBillsMaintDetailProject;
import org.dromara.dms.domain.vo.DmsBillsMaintDetailProjectVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* ;Mapper
*
@ -12,4 +14,12 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
*/
public interface DmsBillsMaintDetailProjectMapper extends BaseMapperPlus<DmsBillsMaintDetailProject, DmsBillsMaintDetailProjectVo> {
/**
*
*
* @param dmsBillsMaintDetailProject
* @return
*/
List<DmsBillsMaintDetailProjectVo> selectDmsBillsMaintDetailProjectWithProjectName(DmsBillsMaintDetailProject dmsBillsMaintDetailProject);
}

@ -11,6 +11,7 @@ import org.dromara.dms.domain.vo.DmsBillsFaultInstanceVo;
import java.util.Collection;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
/**
* Service
@ -109,7 +110,7 @@ public interface IDmsBillsFaultInstanceService {
* @param dmsFaultInstanceActivity
* @return
*/
public int completeRepair(DmsFaultInstanceActivityBo dmsFaultInstanceActivity);
public int completeRepair(DmsFaultInstanceActivityBo dmsFaultInstanceActivity, List<MultipartFile> files);
/**
* ID
@ -117,5 +118,25 @@ public interface IDmsBillsFaultInstanceService {
* @param wfDefinitionId ID
* @return truefalse
*/
public Boolean updateWfDefinitionIdById(Long repairInstanceId, Long wfDefinitionId);
Boolean updateWfDefinitionIdById(Long repairInstanceId, Long wfDefinitionId);
/**
*
*
* @param repairInstanceId ID
* @param approveStatus 2-3-
* @param message
* @return
*/
Boolean approveWorkOrder(Long repairInstanceId, String approveStatus, String message);
/**
*
*
* @param repairInstanceId ID
* @param confirmResult 1-
* @param confirmUser
* @return
*/
Boolean confirmRepairResult(Long repairInstanceId, String confirmResult, String confirmUser);
}

@ -46,6 +46,8 @@ import cn.dev33.satoken.stp.StpUtil;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import org.springframework.web.multipart.MultipartFile;
import org.dromara.dms.mapper.DmsFaultComponentsPartsMapper;
/**
* Service
@ -65,7 +67,7 @@ public class DmsBillsFaultInstanceServiceImpl implements IDmsBillsFaultInstanceS
private final IDmsInstanceFileService DmsInstanceFileService;
@DubboReference(timeout = 15000, retries = 1)
@DubboReference(timeout = 30000, retries = 2)
private final RemoteWorkflowService remoteWorkflowService;
private final DmsFaultInstanceActivityMapper dmsFaultInstanceActivityMapper;
@ -75,6 +77,8 @@ public class DmsBillsFaultInstanceServiceImpl implements IDmsBillsFaultInstanceS
@DubboReference(timeout = 15000, retries = 1)
private final RemoteFileService remoteFileService;
private final DmsFaultComponentsPartsMapper dmsFaultComponentsPartsMapper;
/**
*
*
@ -176,6 +180,12 @@ public class DmsBillsFaultInstanceServiceImpl implements IDmsBillsFaultInstanceS
@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);
// 获取当前日期时间
@ -185,20 +195,28 @@ public class DmsBillsFaultInstanceServiceImpl implements IDmsBillsFaultInstanceS
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());
}
//FIXME:工作流相关
//工作流相关:自动启动工作流
RemoteStartProcess remoteStartProcess = new RemoteStartProcess();
remoteStartProcess.setFlowCode(DmsConstants.DMS_BILLS_FAULT_INSTANCE_WF_CODE);
remoteStartProcess.setBusinessId(add.getRepairInstanceId().toString());
RemoteStartProcessReturn remoteStartProcessReturn = remoteWorkflowService.startWorkFlow(remoteStartProcess);
Long taskId = remoteStartProcessReturn.getTaskId();
Long processInstanceId = remoteStartProcessReturn.getProcessInstanceId();
// // 更新工作流实例ID
// add.setWfDefinitionId(processInstanceId);
// ** 异步线程上下文传递【核心问题】 **
// 在主线程中,用户的登录信息(Token)是存放在一个叫 ThreadLocal 的"线程口袋"里的。
@ -214,15 +232,38 @@ public class DmsBillsFaultInstanceServiceImpl implements IDmsBillsFaultInstanceS
try {
// 3. 【设置上下文】: 在子线程任务开始时,立刻用 StpUtil.setTokenValue() 把传递过来的Token放进子线程自己的"口袋"。
StpUtil.setTokenValue(tokenValue);
// 4. 【执行业务】: 现在子线程就像登录过一样可以带着Token去调用其他需要权限的服务了。
updateWorkFlow(add, taskId);
// 4. 【延迟执行】: 稍微延迟,确保主事务完全提交
Thread.sleep(100);
// 5. 【重试机制】: 最多重试3次每次间隔递增
int maxRetries = 3;
for (int i = 0; i < maxRetries; i++) {
try {
// 执行业务现在子线程就像登录过一样可以带着Token去调用其他需要权限的服务了
updateWorkFlow(add, taskId, processInstanceId);
log.info("异步工作流推进成功repairInstanceId: {}, 重试次数: {}", add.getRepairInstanceId(), i);
break; // 成功则退出重试循环
} catch (Exception retryException) {
log.warn("异步工作流推进失败repairInstanceId: {}, 重试次数: {}/{}, 错误: {}",
add.getRepairInstanceId(), i + 1, maxRetries, retryException.getMessage());
if (i == maxRetries - 1) {
// 最后一次重试失败,记录错误
log.error("异步工作流推进最终失败repairInstanceId: {}, 请手动处理", add.getRepairInstanceId(), retryException);
// TODO: 可以考虑记录到失败表,后续补偿处理
} else {
// 等待后重试,递增延迟时间
Thread.sleep((i + 1) * 1000);
}
}
}
} catch (Exception e) {
// 简单记录错误,不影响主流程
System.err.println("异步更新工作流失败repairInstanceId: " + add.getRepairInstanceId() + ", 错误: " + e.getMessage());
// 可以考虑记录到失败表,后续补偿处理
log.error("异步更新工作流异常repairInstanceId: {}", add.getRepairInstanceId(), e);
}
}));
// 创建故障实例活动对象
// 【重要修改】创建故障实例活动对象 - 只有PDA创建工单时才生成
DmsFaultInstanceActivity dmsFaultInstanceActivity = new DmsFaultInstanceActivity();
// 设置维修实例ID
dmsFaultInstanceActivity.setRepairInstanceId(add.getRepairInstanceId());
@ -238,11 +279,11 @@ public class DmsBillsFaultInstanceServiceImpl implements IDmsBillsFaultInstanceS
dmsFaultInstanceActivity.setMachineId(add.getMachineId());
// 设置维修类型
dmsFaultInstanceActivity.setRepairType(add.getRepairType());
// 如果外部资源ID不为空则设置外部资源ID
if (add.getOutsourcingId() != null) {
dmsFaultInstanceActivity.setOutsourcingId(add.getOutsourcingId());
// 【关键修复】如果外部资源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);
@ -250,35 +291,405 @@ public class DmsBillsFaultInstanceServiceImpl implements IDmsBillsFaultInstanceS
dmsFaultInstanceActivityMapper.insert(dmsFaultInstanceActivity);
//存储图片
// 获取文件URL列表
List<String> fileUrls = add.getFileUrls();
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 dmsBillsFaultInstance
* @param dmsBillsFaultInstance
* @param taskId ID
* @param processInstanceId ID
* @return
*/
private Boolean updateWorkFlow(DmsBillsFaultInstance dmsBillsFaultInstance, Long taskId){
dmsBillsFaultInstance.setWfDefinitionId(taskId);
private Boolean updateWorkFlow(DmsBillsFaultInstance dmsBillsFaultInstance, Long taskId, Long processInstanceId){
try {
// 1. 首先更新工单的工作流实例ID确保关联关系建立
dmsBillsFaultInstance.setWfDefinitionId(processInstanceId);
boolean updateResult = baseMapper.updateById(dmsBillsFaultInstance) > 0;
RemoteCompleteTask remoteCompleteTask = new RemoteCompleteTask();
// 必填字段
remoteCompleteTask.setTaskId(taskId);
remoteCompleteTask.setMessage("自动推进");
// 关键设置messageType为非null的List解决原始错误
List<String> messageTypes = new ArrayList<>();
messageTypes.add("system"); // 系统消息
remoteCompleteTask.setMessageType(messageTypes);
boolean b = remoteWorkflowService.completeTask(remoteCompleteTask);
if (!b) {
if (!updateResult) {
log.error("更新工单工作流实例ID失败repairInstanceId: {}, processInstanceId: {}",
dmsBillsFaultInstance.getRepairInstanceId(), processInstanceId);
return false;
}
log.info("成功更新工单工作流实例IDrepairInstanceId: {}, processInstanceId: {}",
dmsBillsFaultInstance.getRepairInstanceId(), processInstanceId);
// 2. 然后推进工作流(工单创建后自动推进到审批节点)
RemoteCompleteTask remoteCompleteTask = new RemoteCompleteTask();
remoteCompleteTask.setTaskId(taskId);
remoteCompleteTask.setMessage("工单创建完成,自动推进到审批节点");
// 设置消息类型
List<String> messageTypes = new ArrayList<>();
messageTypes.add("1"); // 站内信
remoteCompleteTask.setMessageType(messageTypes);
// 设置消息通知内容
remoteCompleteTask.setNotice("您有新的故障报修工单需要审批,工单编号:" + dmsBillsFaultInstance.getBillsFaultCode());
// 设置工作流变量(如果需要)
Map<String, Object> variables = new HashMap<>();
variables.put("businessId", dmsBillsFaultInstance.getRepairInstanceId().toString());
variables.put("initiator", LoginHelper.getUsername());
remoteCompleteTask.setVariables(variables);
boolean completeResult = remoteWorkflowService.completeTask(remoteCompleteTask);
if (!completeResult) {
log.error("工作流推进失败repairInstanceId: {}, taskId: {}",
dmsBillsFaultInstance.getRepairInstanceId(), taskId);
return false;
}
log.info("工作流推进成功repairInstanceId: {}, taskId: {}",
dmsBillsFaultInstance.getRepairInstanceId(), taskId);
return true;
} catch (Exception e) {
log.error("更新工作流异常repairInstanceId: {}, taskId: {}, processInstanceId: {}",
dmsBillsFaultInstance.getRepairInstanceId(), taskId, processInstanceId, e);
return false;
}else {
return baseMapper.updateById(dmsBillsFaultInstance) > 0;
}
}
@ -361,8 +772,27 @@ public class DmsBillsFaultInstanceServiceImpl implements IDmsBillsFaultInstanceS
*/
@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();
// 设置目标类型为故障实例活动
@ -399,6 +829,44 @@ public class DmsBillsFaultInstanceServiceImpl implements IDmsBillsFaultInstanceS
// 返回故障实例对象
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());
}
}
@ -481,201 +949,6 @@ public class DmsBillsFaultInstanceServiceImpl implements IDmsBillsFaultInstanceS
}
}
/**
*
*
* @param dmsFaultInstanceActivity
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public int startRepair(DmsFaultInstanceActivityBo dmsFaultInstanceActivity) {
// 定义一个布尔变量b用于存储更新结果
Boolean b = false;
// 根据维修实例ID查询故障实例信息
DmsBillsFaultInstance dmsBillsFaultInstance = baseMapper
.selectFaultInstanceJoinFirstById(dmsFaultInstanceActivity.getRepairInstanceId());//join 第一步activity
// 获取工单状态
String dmsBillsStatus = dmsBillsFaultInstance.getBillsStatus();
// 如果工单状态为已完成,抛出异常
if (dmsBillsStatus.equals(DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_FINISH)) {//维修完成
throw new ServiceException("已经维修完成");
}
// 获取当前日期和登录用户名
Date currentDate = new Date();
String userName = LoginHelper.getLoginUser()==null ? LoginHelper.getUsername() :LoginHelper.getLoginUser().getNickname();
// 如果工单状态为待维修
if (dmsBillsStatus.equals(DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_TO_REPAIR)) {//待维修
// 设置工单状态为维修中
dmsBillsFaultInstance.setBillsStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_REPAIRING);
// 设置实际开始时间
dmsBillsFaultInstance.setRealBeginTime(currentDate);
//启动工作流
Long taskId = getOrCreateTaskId(dmsBillsFaultInstance);
// ** 异步线程上下文传递【核心问题】 **
// 在主线程中,用户的登录信息(Token)是存放在一个叫 ThreadLocal 的"线程口袋"里的。
// 当我们使用 CompletableFuture.runAsync() 开启一个异步线程(子线程)时,
// 这个"口袋"里的东西默认是不会被带到子线程去的。
//
// ** 【解决方案】 **
// 1. 【捕获Token】: 在主线程里,我们先用 StpUtil.getTokenValue() 把Token拿出来存好。
final String tokenValue = StpUtil.getTokenValue();
// 2. 【传递与恢复】: 使用 TtlRunnable (TransmittableThreadLocal Runnable) 包装我们的异步任务。
// 它就像一个特殊的"接力棒",能在线程切换时把主线程"口袋"里的东西包括Token传递给子线程。
CompletableFuture.runAsync(TtlRunnable.get(() -> {
try {
// 3. 【设置上下文】: 在子线程任务开始时,立刻用 StpUtil.setTokenValue() 把传递过来的Token放进子线程自己的"口袋"。
StpUtil.setTokenValue(tokenValue);
// 4. 【执行业务】: 现在子线程就像登录过一样可以带着Token去调用其他需要权限的服务了。
updateWorkFlow(dmsBillsFaultInstance, taskId);
} catch (Exception e) {
// 简单记录错误,不影响主流程
System.err.println("异步更新工作流失败repairInstanceId: " + dmsBillsFaultInstance.getRepairInstanceId() + ", 错误: " + e.getMessage());
// 可以考虑记录到失败表,后续补偿处理
}
}));
// 设置维修实例ID
dmsFaultInstanceActivity.setRepairInstanceId(dmsBillsFaultInstance.getRepairInstanceId());
// FIXME: 工作流相关代码(暂时注释掉)
// dmsFaultInstanceActivity.setProcessActivityId(WfConstants.WF_BILLS_FAULT_INSTANCE_PROCESS_ACTIVITY_SECOND_ID);
// 设置机器ID
dmsFaultInstanceActivity.setMachineId(dmsBillsFaultInstance.getMachineId());
// 设置处理状态为执行中
dmsFaultInstanceActivity.setProcessHandleStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_ACTIVITY_HANDLE_STATUS_EXECUTING);
// 设置步骤顺序
dmsFaultInstanceActivity.setProcessStepOrder(2L);
// 设置开始时间
dmsFaultInstanceActivity.setStartTime(currentDate);
// 设置处理用户ID
dmsFaultInstanceActivity.setHandleUserId(LoginHelper.getUserId());
// 设置处理人名称
dmsFaultInstanceActivity.setHandleBy(userName);
// 设置处理时间
dmsFaultInstanceActivity.setHandleTime(currentDate);
// 插入新的故障实例活动记录
b = dmsFaultInstanceActivityService.insertByBo(dmsFaultInstanceActivity);
// 创建第一个实例活动对象并设置其属性
DmsFaultInstanceActivityBo firstInstanceActivity = new DmsFaultInstanceActivityBo();
firstInstanceActivity.setInstanceActivityId(dmsBillsFaultInstance.getInstanceActivityId());
// 设置处理状态为已完成
firstInstanceActivity.setProcessHandleStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_ACTIVITY_HANDLE_STATUS_FINISH);
// 设置结束时间
firstInstanceActivity.setEndTime(currentDate);
// FIXME: 需重新梳理代码dmsFaultInstanceActivityService
// 更新第一个实例活动记录
dmsFaultInstanceActivityService.updateByBo(firstInstanceActivity);
} else {// 如果工单状态为维修中
// 更新故障实例活动记录
b = dmsFaultInstanceActivityService.updateByBo(dmsFaultInstanceActivity);
}
// 返回结果1表示成功
return b ? 1 : 0;
}
// startRepair方法内提取的获取或创建taskId的方法
private Long getOrCreateTaskId(DmsBillsFaultInstance dmsBillsFaultInstance) {
Long taskId = dmsBillsFaultInstance.getWfDefinitionId();
if (StringUtils.isNull(taskId)) {
// 启动工作流
RemoteStartProcess startProcess = new RemoteStartProcess();
startProcess.setFlowCode(DmsConstants.DMS_BILLS_FAULT_INSTANCE_WF_CODE);
String businessId = dmsBillsFaultInstance.getRepairInstanceId().toString();
startProcess.setBusinessId(businessId);
RemoteStartProcessReturn remoteStartProcessReturn = remoteWorkflowService.startWorkFlow(startProcess);
taskId = remoteStartProcessReturn.getTaskId();
if (StringUtils.isNull(taskId)) {
throw new ServiceException("流程启动失败");
}
}
return taskId;
}
/**
*
*
* @param dmsFaultInstanceActivity
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public int completeRepair(DmsFaultInstanceActivityBo dmsFaultInstanceActivity) {
// 批量插入实例的附件文件信息
batchInsertInstanceAfterFiles(dmsFaultInstanceActivity.getFileUrls(),dmsFaultInstanceActivity.getInstanceActivityId());
// 获取需要插入的备件列表
List<DmsFaultComponentsParts> parts = dmsFaultInstanceActivity.getParts();
// 如果备件列表不为空则设置每个备件的故障ID并插入数据库
if (!CollectionUtils.isEmpty(parts)){
for (DmsFaultComponentsParts part : parts) {
part.setFaultId(dmsFaultInstanceActivity.getRepairInstanceId());
}
dmsFaultInstanceActivityMapper.insertParts(parts);
}
// 根据维修实例ID查询对应的工单实例
DmsBillsFaultInstanceVo dmsBillsFaultInstance = this.
queryById(dmsFaultInstanceActivity.getRepairInstanceId());
// 获取当前工单的状态
String dmsBillsStatus = dmsBillsFaultInstance.getBillsStatus();
// 如果状态为已完成,抛出异常提示已经维修完成
if (dmsBillsStatus.equals(DmsConstants.DMS_BILLS_FAULT_INSTANCE_STATUS_FINISH)) {//维修完成
throw new ServiceException("已经维修完成");
}
// 如果状态为待维修,抛出异常提示请先开始维修
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_FINISH);
dmsBillsFaultInstance.setRealEndTime(currentDate);
// 将工单实例转换为数据库实体对象并更新数据库
DmsBillsFaultInstance faultInstance = MapstructUtils.convert(dmsBillsFaultInstance, DmsBillsFaultInstance.class);
if(StringUtils.isNull(dmsBillsFaultInstance.getWfDefinitionId())){
throw new ServiceException("流程未启动");
}else{
//FIXME:完成第一步,待测试待完善
RemoteCompleteTask remoteCompleteTask = new RemoteCompleteTask();
remoteCompleteTask.setTaskId(dmsBillsFaultInstance.getWfDefinitionId());
remoteCompleteTask.setMessage("同意");
remoteWorkflowService.completeTask(remoteCompleteTask);
baseMapper.updateById(faultInstance);
// 设置工单活动状态为已完成,并记录结束时间和维修人员
dmsFaultInstanceActivity.setProcessHandleStatus(DmsConstants.DMS_BILLS_FAULT_INSTANCE_ACTIVITY_HANDLE_STATUS_FINISH);
dmsFaultInstanceActivity.setEndTime(currentDate);
dmsFaultInstanceActivity.setRepairer(userName);
// 将工单活动实例转换为数据库实体对象并更新数据库
DmsFaultInstanceActivity faultInstanceActivity = MapstructUtils.convert(dmsFaultInstanceActivity, DmsFaultInstanceActivity.class);
int i = dmsFaultInstanceActivityMapper.updateById(faultInstanceActivity);
// 返回更新操作影响的行数
return i;
}
}
public void batchInsertInstanceAfterFiles(List<String> fileUrls, Long instanceActivityId) {
// 判断文件URL列表是否不为空且非空集合
if (fileUrls != null && !fileUrls.isEmpty()) {

@ -24,7 +24,7 @@ import org.dromara.workflow.api.RemoteWorkflowService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import io.seata.spring.annotation.GlobalTransactional;
import java.math.BigDecimal;
import java.util.*;
@ -232,7 +232,7 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
if (currentActiveTaskId != null) {
// 【关键】设置消息类型为非null的List避免原始错误
List<String> messageTypes = new ArrayList<>();
messageTypes.add("system"); // 系统消息
messageTypes.add("1"); // 系统消息
// 【工作流推进】完成当前活跃任务
boolean taskCompleted = remoteWorkflowService.completeTaskIgnoreAuth(currentActiveTaskId, "巡检工单完成,自动推进");
@ -330,11 +330,13 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
/**
*
*
*
* @param dmsBillsInspectInstanceScan
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public DmsInspectInstanceDetailVo scanInspectInstanceDetail(DmsBillsInspectInstanceScanBo dmsBillsInspectInstanceScan) {
// 根据检查实例ID和设备编码查询检查工单详细信息
DmsInspectInstanceDetailVo dmsInspectInstanceDetail = dmsInspectInstanceDetailMapper.selectDmsInspectInstanceDetailByUI(dmsBillsInspectInstanceScan.getInspectInstanceId(),
@ -343,6 +345,131 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
if (dmsInspectInstanceDetail == null) {
throw new ServiceException("无此设备的检查工单");
}
// 【参考开始保养】查询巡检工单实例信息
DmsBillsInspectInstance inspectInstance = baseMapper.selectById(dmsBillsInspectInstanceScan.getInspectInstanceId());
if (inspectInstance == null) {
throw new ServiceException("巡检工单不存在");
}
// 【参考开始保养】获取当前巡检状态
String inspectStatus = inspectInstance.getInspectStatus() == null ?
DmsConstants.DMS_BILLS_INSPECT_INSTANCE_INSPECT_STATUS_TO_INSPECT : inspectInstance.getInspectStatus();
// 【参考开始保养】如果巡检状态为已完成,抛出异常
if (inspectStatus.equals(DmsConstants.DMS_BILLS_INSPECT_INSTANCE_INSPECT_STATUS_FINISH)) {
throw new ServiceException("已经巡检完成");
}
// 获取当前日期时间
Date currentDate = new Date();
// 【参考开始保养】如果巡检状态为待巡检,进行工作流启动处理
if (inspectStatus.equals(DmsConstants.DMS_BILLS_INSPECT_INSTANCE_INSPECT_STATUS_TO_INSPECT)) {
// 设置巡检状态为巡检中
inspectInstance.setInspectStatus(DmsConstants.DMS_BILLS_INSPECT_INSTANCE_INSPECT_STATUS_INSPECTING);
// 设置实际开始巡检时间为当前时间
inspectInstance.setRealBeginTime(currentDate);
// 【参考开始保养】检查工作流是否已经启动
DmsBillsInspectInstance latestInstance = baseMapper.selectById(inspectInstance.getInspectInstanceId());
if (latestInstance != null && latestInstance.getWfDefinitionId() == null) {
// 【参考开始保养】工作流未启动,需要启动
try {
// 创建远程启动流程对象
org.dromara.workflow.api.domain.RemoteStartProcess startProcess = new org.dromara.workflow.api.domain.RemoteStartProcess();
// 设置流程代码(需要根据实际的巡检工作流代码设置)
startProcess.setFlowCode(DmsConstants.DMS_BILLS_INSPECT_INSTANCE_WF_CODE);
// 获取业务ID巡检实例ID
String businessId = inspectInstance.getInspectInstanceId().toString();
startProcess.setBusinessId(businessId);
// 启动工作流程
org.dromara.workflow.api.domain.RemoteStartProcessReturn remoteStartProcessReturn = remoteWorkflowService.startWorkFlow(startProcess);
// 获取流程实例ID和任务ID
Long processInstanceId = remoteStartProcessReturn.getProcessInstanceId();
Long taskId = remoteStartProcessReturn.getTaskId();
if (processInstanceId == null) {
throw new ServiceException("巡检工作流启动失败");
} else {
// 存储流程实例ID
inspectInstance.setWfDefinitionId(processInstanceId);
// 【参考开始保养】异步推进工作流
if (taskId != null) {
// 自动推进工作流
org.dromara.workflow.api.domain.RemoteCompleteTask remoteCompleteTask = new org.dromara.workflow.api.domain.RemoteCompleteTask();
remoteCompleteTask.setTaskId(taskId);
remoteCompleteTask.setMessage("巡检开始,自动推进");
// 设置消息类型为非null的List
List<String> messageTypes = new ArrayList<>();
messageTypes.add("1"); // 站内信
remoteCompleteTask.setMessageType(messageTypes);
boolean taskCompleted = remoteWorkflowService.completeTask(remoteCompleteTask);
if (!taskCompleted) {
log.error("巡检工作流推进失败任务ID: {}", taskId);
} else {
log.info("巡检工单 {} 工作流推进成功", inspectInstance.getInspectInstanceId());
}
}
}
} catch (Exception e) {
// 【参考开始保养】捕获工作流启动异常
if (e.getMessage() != null && e.getMessage().contains("该单据已提交过申请")) {
log.warn("巡检工单 {} 工作流已存在,跳过启动: {}", inspectInstance.getInspectInstanceId(), e.getMessage());
// 重新查询获取工作流ID
DmsBillsInspectInstance updatedInstance = baseMapper.selectById(inspectInstance.getInspectInstanceId());
if (updatedInstance != null && updatedInstance.getWfDefinitionId() != null) {
inspectInstance.setWfDefinitionId(updatedInstance.getWfDefinitionId());
}
} else {
log.error("巡检工单 {} 工作流启动失败: {}", inspectInstance.getInspectInstanceId(), e.getMessage());
throw new ServiceException("巡检工作流启动失败: " + e.getMessage());
}
}
} else if (latestInstance != null && latestInstance.getWfDefinitionId() != null) {
// 【参考开始保养】工作流已启动,推进当前活跃任务
Long processInstanceId = latestInstance.getWfDefinitionId();
inspectInstance.setWfDefinitionId(processInstanceId);
log.info("巡检工单 {} 工作流已启动流程实例ID: {},查询当前活跃任务",
inspectInstance.getInspectInstanceId(), processInstanceId);
// 根据流程实例ID获取当前活跃任务ID
Long currentActiveTaskId = remoteWorkflowService.getCurrentTaskIdByInstanceId(processInstanceId);
if (currentActiveTaskId != null) {
log.info("巡检工单 {} 找到当前活跃任务ID: {}",
inspectInstance.getInspectInstanceId(), currentActiveTaskId);
// 直接推进工作流
org.dromara.workflow.api.domain.RemoteCompleteTask remoteCompleteTask = new org.dromara.workflow.api.domain.RemoteCompleteTask();
remoteCompleteTask.setTaskId(currentActiveTaskId);
remoteCompleteTask.setMessage("巡检开始,推进工作流");
// 设置消息类型为非null的List
List<String> messageTypes = new ArrayList<>();
messageTypes.add("1"); // 站内信
remoteCompleteTask.setMessageType(messageTypes);
boolean taskCompleted = remoteWorkflowService.completeTask(remoteCompleteTask);
if (!taskCompleted) {
log.error("巡检工作流推进失败任务ID: {}", currentActiveTaskId);
} else {
log.info("巡检工单 {} 工作流推进成功", inspectInstance.getInspectInstanceId());
}
} else {
log.warn("巡检工单 {} 无法获取当前活跃任务,流程可能已完成", inspectInstance.getInspectInstanceId());
}
}
// 更新巡检实例信息
baseMapper.updateById(inspectInstance);
}
// 获取设备ID
Long deviceId = dmsInspectInstanceDetail.getMachineId();
// 创建查询检查实例详细项目的参数对象
@ -360,30 +487,18 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
// 将查询结果设置到检查工单详情对象中
dmsInspectInstanceDetail.setDmsInspectInstanceDetailProjectList(dmsInspectInstanceDetailProjects);
// 更新检查工单的开始时间
DmsBillsInspectInstanceBo dmsBillsInspectInstance = new DmsBillsInspectInstanceBo();
// 设置检查实例ID
dmsBillsInspectInstance.setInspectInstanceId(dmsBillsInspectInstanceScan.getInspectInstanceId());
// 设置实际开始时间为当前时间
dmsBillsInspectInstance.setRealBeginTime(new Date());
// dmsBillsInspectInstance.setInspectStatus("2");
// FIXME: 梳理流程,完善更新方法
// int i = dmsBillsInspectInstanceMapper.updateDmsBillsInspectInstance(dmsBillsInspectInstance);
// 使用BO更新检查实例信息
this.updateByBo(dmsBillsInspectInstance);
// 返回检查实例详情对象
return dmsInspectInstanceDetail;
}
/**
*
*
*
* @param dmsInspectInstanceDetail
* @return
*/
@GlobalTransactional(rollbackFor = Exception.class)
private DmsInspectInstanceDetailBo handleDmsInspectInstanceDetailProject(DmsInspectInstanceDetailBo dmsInspectInstanceDetail) {
// 【初始化状态】默认设置为完成状态和通过状态
String instanceDetailStatus = DmsConstants.DMS_INSPECT_INSTANCE_DETAIL_STATUS_FINISH;
@ -451,6 +566,72 @@ public class DmsBillsInspectInstanceServiceImpl implements IDmsBillsInspectInsta
toUpdatedList.add(inspectInstanceDetailProject);
}
// 【参考完成保养】如果当前明细已完成,检查是否需要完成整个巡检工单
if (instanceDetailStatus.equals(DmsConstants.DMS_INSPECT_INSTANCE_DETAIL_STATUS_FINISH)) {
Long inspectInstanceId = dmsInspectInstanceDetail.getInspectInstanceId();
// 【参考完成保养】查询所有明细的完成情况
try {
// 查询同一巡检工单下的所有明细
DmsInspectInstanceDetailBo queryDetail = new DmsInspectInstanceDetailBo();
queryDetail.setInspectInstanceId(inspectInstanceId);
// 这里需要查询所有明细的状态,判断是否全部完成
// 注意:需要排除当前正在处理的明细
List<DmsInspectInstanceDetailVo> allDetails = dmsInspectInstanceDetailMapper.selectDmsInspectInstanceDetailJoinList(queryDetail);
// 统计未完成的明细数量(排除当前处理的明细)
long incompleteCount = allDetails.stream()
.filter(detail -> !detail.getInstanceDetailId().equals(dmsInspectInstanceDetail.getInstanceDetailId()))
.filter(detail -> detail.getInstanceDetailStatus() == null
|| !detail.getInstanceDetailStatus().equals(DmsConstants.DMS_INSPECT_INSTANCE_DETAIL_STATUS_FINISH))
.count();
// 【参考完成保养】如果所有明细都已完成,完成工作流
if (incompleteCount == 0) {
log.info("巡检工单 {} 所有明细已完成,开始完成工作流", inspectInstanceId);
// 【参考完成保养】完成巡检工作流
String businessId = inspectInstanceId.toString();
Long currentActiveTaskId = remoteWorkflowService.getCurrentActiveTaskId(businessId);
if (currentActiveTaskId != null) {
org.dromara.workflow.api.domain.RemoteCompleteTask remoteCompleteTask = new org.dromara.workflow.api.domain.RemoteCompleteTask();
remoteCompleteTask.setTaskId(currentActiveTaskId);
remoteCompleteTask.setMessage("巡检工单完成,自动推进");
// 设置消息类型为非null的List
List<String> messageTypes = new ArrayList<>();
messageTypes.add("1"); // 站内信
remoteCompleteTask.setMessageType(messageTypes);
// 完成工作流任务
boolean taskCompleted = remoteWorkflowService.completeTask(remoteCompleteTask);
if (!taskCompleted) {
log.error("巡检工作流完成失败当前活跃任务ID: {}", currentActiveTaskId);
} else {
log.info("巡检工单 {} 工作流完成成功任务ID: {}", inspectInstanceId, currentActiveTaskId);
// 【参考完成保养】更新巡检工单主表状态为已完成
DmsBillsInspectInstance inspectInstance = baseMapper.selectById(inspectInstanceId);
if (inspectInstance != null) {
inspectInstance.setInspectStatus(DmsConstants.DMS_BILLS_INSPECT_INSTANCE_INSPECT_STATUS_FINISH);
inspectInstance.setRealEndTime(new Date());
baseMapper.updateById(inspectInstance);
log.info("巡检工单 {} 状态已更新为完成", inspectInstanceId);
}
}
} else {
log.warn("巡检工单 {} 无法获取当前活跃任务ID工作流可能已完成或异常", inspectInstanceId);
}
} else {
log.info("巡检工单 {} 还有 {} 个明细未完成,暂不完成工作流", inspectInstanceId, incompleteCount);
}
} catch (Exception e) {
log.error("检查巡检工单完成状态时发生异常: {}", e.getMessage(), e);
// 不影响主流程,继续执行
}
}
// 【设置返回结果】设置处理后的状态和项目列表
returnInspectInstanceDetail.setInspectStatus(inspectStatus);
returnInspectInstanceDetail.setInstanceDetailStatus(instanceDetailStatus);

@ -65,6 +65,25 @@ public class DmsBillsMaintDetailProjectServiceImpl implements IDmsBillsMaintDeta
*/
@Override
public List<DmsBillsMaintDetailProjectVo> queryList(DmsBillsMaintDetailProjectBo bo) {
// 【修复保养项目名称为空问题】优先使用关联查询方法获取完整项目信息
if (bo.getBillsMaintDetailId() != null) {
// 转换为实体对象用于查询
DmsBillsMaintDetailProject queryEntity = MapstructUtils.convert(bo, DmsBillsMaintDetailProject.class);
queryEntity.setBillsMaintDetailId(bo.getBillsMaintDetailId());
queryEntity.setMaintDetailProjectId(bo.getMaintDetailProjectId());
queryEntity.setMaintProjectId(bo.getMaintProjectId());
queryEntity.setMaintProjectStatus(bo.getMaintProjectStatus());
// 使用关联查询方法,确保获取到项目名称
List<DmsBillsMaintDetailProjectVo> result = baseMapper.selectDmsBillsMaintDetailProjectWithProjectName(queryEntity);
// 如果关联查询有结果,直接返回
if (result != null && !result.isEmpty()) {
return result;
}
}
// 降级到默认查询方法
MPJLambdaWrapper<DmsBillsMaintDetailProject> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
@ -132,6 +151,6 @@ public class DmsBillsMaintDetailProjectServiceImpl implements IDmsBillsMaintDeta
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
return baseMapper.deleteBatchIds(ids) > 0;
}
}

@ -17,6 +17,7 @@ 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.DmsBillsMaintDetailBo;
import org.dromara.dms.domain.bo.DmsBillsMaintDetailProjectBo;
@ -385,6 +386,7 @@ public class DmsBillsMaintInstanceServiceImpl implements IDmsBillsMaintInstanceS
}
}
} else if (latestInstance != null) {
// 【关键修复】工作流已启动根据流程实例ID查询当前活跃任务
// 使用最新查询到的工作流ID
Long processInstanceId = latestInstance.getWfDefinitionId();
@ -429,13 +431,15 @@ public class DmsBillsMaintInstanceServiceImpl implements IDmsBillsMaintInstanceS
// 更新保养明细信息
dmsBillsMaintDetailMapper.updateById(dmsBillsMaintDetail);
// 更新保养工单信息
baseMapper.updateById(dmsBillsMaintInstance);
}
else {//保养中
// 更新人不为空,则设置更新人为当前用户,更新时间为当前时间
dmsBillsMaintDetail.setUpdateBy(LoginHelper.getUserId());
dmsBillsMaintDetail.setUpdateTime(currentDate);
dmsBillsMaintDetailMapper.updateById(dmsBillsMaintDetail);
}
// else {//保养中
// // 更新人不为空,则设置更新人为当前用户,更新时间为当前时间
// dmsBillsMaintDetail.setUpdateBy(userName);
// dmsBillsMaintDetail.setUpdateTime(currentDate);
// dmsBillsMaintDetailMapper.updateDmsBillsMaintDetail(dmsBillsMaintDetail);
// }
// 创建查询保养明细项目的对象
DmsBillsMaintDetailProjectBo queryBillsMaintDetailProject = new DmsBillsMaintDetailProjectBo();
@ -500,7 +504,7 @@ public class DmsBillsMaintInstanceServiceImpl implements IDmsBillsMaintInstanceS
if (!b){
return false;
}else{
// 更新保养实例信息
// 更新保养工单信息
int i = baseMapper.updateById(dmsBillsMaintInstance);
return i > 0;
}
@ -517,6 +521,9 @@ public class DmsBillsMaintInstanceServiceImpl implements IDmsBillsMaintInstanceS
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public int completeMaint(DmsBillsMaintDetail dmsBillsMaintDetail) {
if(!dmsBillsMaintDetail.getMaintStatus().equals(DmsConstants.DMS_BILLS_MAINT_INSTANCE_STATUS_MAINTING)){
throw new ServiceException("非保养中状态,不能完成保养");
}
// 获取保养工单明细中的项目列表
List<DmsBillsMaintDetailProjectVo> dmsBillsMaintDetailProjects = dmsBillsMaintDetail.getDmsBillsMaintDetailProjectList();
// 获取保养实例ID

@ -78,7 +78,8 @@ public class DmsFaultComponentsPartsServiceImpl implements IDmsFaultComponentsPa
.like(StringUtils.isNotBlank(bo.getPartName()), DmsFaultComponentsParts::getPartName, bo.getPartName())
.eq(StringUtils.isNotBlank(bo.getPartSpecifications()), DmsFaultComponentsParts::getPartSpecifications, bo.getPartSpecifications())
.eq(bo.getAmount() != null, DmsFaultComponentsParts::getAmount, bo.getAmount())
.orderByDesc(DmsFaultComponentsParts::getCreateTime);
//.orderByDesc(DmsFaultComponentsParts::getCreateTime)
;
return lqw;
}

@ -203,7 +203,7 @@ public class DmsPlanInspectServiceImpl implements IDmsPlanInspectService {
.setExecutorInfo("stanceInspect")//执行器名称
.setExecutorTimeout(30)//执行超时时间
.setBlockStrategy(JobBlockStrategyEnum.DISCARD)//阻塞策略:丢弃后续任务,避免重复执行
.setMaxRetryTimes(2)//最大重试次数
.setMaxRetryTimes(0)//最大重试次数
.setTriggerType(TriggerTypeEnum.CRON)//触发器类型cron
.setTriggerInterval(bo.getCronExpression())//间隔时长: cron表达式
.setRetryInterval(10)//重试间隔时长
@ -297,7 +297,7 @@ public class DmsPlanInspectServiceImpl implements IDmsPlanInspectService {
.setExecutorInfo("stanceInspect")//执行器名称
.setExecutorTimeout(30)//执行超时时间
.setBlockStrategy(JobBlockStrategyEnum.DISCARD)//阻塞策略:丢弃后续任务,避免重复执行
.setMaxRetryTimes(2)//最大重试次数
.setMaxRetryTimes(0)//最大重试次数
.setTriggerType(TriggerTypeEnum.CRON)//触发器类型cron
.setTriggerInterval(bo.getCronExpression())//间隔时长: cron表达式
.setRetryInterval(10)//重试间隔时长

@ -188,7 +188,7 @@ public class DmsPlanLubeServiceImpl implements IDmsPlanLubeService {
.setExecutorInfo("stanceLube")//执行器名称
.setExecutorTimeout(30)//执行超时时间
.setBlockStrategy(JobBlockStrategyEnum.DISCARD)//阻塞策略:丢弃后续任务,避免重复执行
.setMaxRetryTimes(2)//最大重试次数
.setMaxRetryTimes(0)//最大重试次数
.setTriggerType(TriggerTypeEnum.CRON)//触发器类型cron
.setTriggerInterval(bo.getCronExpression())//间隔时长: cron表达式
.setRetryInterval(10)//重试间隔时长
@ -251,7 +251,7 @@ public class DmsPlanLubeServiceImpl implements IDmsPlanLubeService {
.setExecutorInfo("stanceLube")//执行器名称
.setExecutorTimeout(30)//执行超时时间
.setBlockStrategy(JobBlockStrategyEnum.DISCARD)//阻塞策略:丢弃后续任务,避免重复执行
.setMaxRetryTimes(2)//最大重试次数
.setMaxRetryTimes(0)//最大重试次数
.setTriggerType(TriggerTypeEnum.CRON)//触发器类型cron
.setTriggerInterval(bo.getCronExpression())//间隔时长: cron表达式
.setRetryInterval(10)//重试间隔时长
@ -274,7 +274,7 @@ public class DmsPlanLubeServiceImpl implements IDmsPlanLubeService {
.setExecutorInfo("stanceLube")//执行器名称
.setExecutorTimeout(30)//执行超时时间
.setBlockStrategy(JobBlockStrategyEnum.DISCARD)//阻塞策略:丢弃后续任务,避免重复执行
.setMaxRetryTimes(2)//最大重试次数
.setMaxRetryTimes(0)//最大重试次数
.setTriggerType(TriggerTypeEnum.CRON)//触发器类型cron
.setTriggerInterval(bo.getCronExpression())//间隔时长: cron表达式
.setRetryInterval(10)//重试间隔时长

@ -214,7 +214,7 @@ public class DmsPlanMaintServiceImpl implements IDmsPlanMaintService {
.setExecutorInfo("stanceMaint")//执行器名称
.setExecutorTimeout(30)//执行超时时间
.setBlockStrategy(JobBlockStrategyEnum.DISCARD)//阻塞策略:丢弃后续任务,避免重复执行
.setMaxRetryTimes(2)//最大重试次数
.setMaxRetryTimes(0)//最大重试次数
.setTriggerType(TriggerTypeEnum.CRON)//触发器类型cron
.setTriggerInterval(bo.getCronExpression())//间隔时长: cron表达式
.setRetryInterval(10)//重试间隔时长
@ -303,7 +303,7 @@ public class DmsPlanMaintServiceImpl implements IDmsPlanMaintService {
.setExecutorInfo("stanceMaint")//执行器名称
.setExecutorTimeout(30)//执行超时时间
.setBlockStrategy(JobBlockStrategyEnum.DISCARD)//阻塞策略:丢弃后续任务,避免重复执行
.setMaxRetryTimes(2)//最大重试次数
.setMaxRetryTimes(0)//最大重试次数
.setTriggerType(TriggerTypeEnum.CRON)//触发器类型cron
.setTriggerInterval(bo.getCronExpression())//间隔时长: cron表达式
.setRetryInterval(10)//重试间隔时长
@ -323,7 +323,7 @@ public class DmsPlanMaintServiceImpl implements IDmsPlanMaintService {
.setExecutorInfo("stanceMaint")//执行器名称
.setExecutorTimeout(30)//执行超时时间
.setBlockStrategy(JobBlockStrategyEnum.DISCARD)//阻塞策略:丢弃后续任务,避免重复执行
.setMaxRetryTimes(2)//最大重试次数
.setMaxRetryTimes(0)//最大重试次数
.setTriggerType(TriggerTypeEnum.CRON)//触发器类型cron
.setTriggerInterval(bo.getCronExpression())//间隔时长: cron表达式
.setRetryInterval(10)//重试间隔时长

@ -129,15 +129,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
dfia.repair_content repair_content,
dfia.protected_method protected_method,
dfia.repairer repairer,
dfia.repair_confirm repair_confirm,
dbfi.repair_confirm repair_confirm,
dfia.confirm_time confirm_time,dfia.components_parts_id components_parts_id
from dms_bills_fault_instance dbfi
left join prod_base_machine_info dbdl on dbfi.machine_id=dbdl.machine_id
left join dms_fault_instance_activity dfia on (dbfi.repair_instance_id=dfia.repair_instance_id
and dfia.process_step_order = (
select max(process_step_order)
and dfia.instance_activity_id = (
select max(instance_activity_id)
from dms_fault_instance_activity dfia2
where dfia2.repair_instance_id = dbfi.repair_instance_id
and dfia2.process_step_order = (
select max(process_step_order)
from dms_fault_instance_activity dfia3
where dfia3.repair_instance_id = dbfi.repair_instance_id
)
))
where dbfi.repair_instance_id = #{repairInstanceId}
</select>
@ -222,7 +227,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectParts" resultType="org.dromara.dms.domain.vo.DmsFaultComponentsPartsVo"
parameterType="java.lang.Long">
SELECT x.* FROM dms_fault_compents_parts x where x.fault_id = #{repairInstanceId}
SELECT x.* FROM dms_fault_components_parts x where x.repair_instance_id = #{repairInstanceId}
</select>
<select id="selectDmsBillsFaultInstanceCompletedList" resultType="org.dromara.dms.domain.vo.DmsBillsFaultInstanceVo"

@ -45,6 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="lubeStationName" column="lube_station_name" />
<result property="lubeProtocol" column="lube_protocol" />
<result property="lubeOperationDescription" column="lube_operation_description" />
<result property="lubeStandardCode" column="lube_standard_code" />
</resultMap>

@ -4,4 +4,41 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.dms.mapper.DmsBillsMaintDetailProjectMapper">
<resultMap type="DmsBillsMaintDetailProjectVo" id="DmsBillsMaintDetailProjectResult">
<result property="maintDetailProjectId" column="maint_detail_project_id" />
<result property="billsMaintDetailId" column="bills_maint_detail_id" />
<result property="maintProjectId" column="maint_project_id" />
<result property="maintProjectName" column="maint_project_name" />
<result property="maintProjectDesc" column="maint_project_desc" />
<result property="maintProjectStatus" column="maint_project_status" />
<result property="remark" column="remark" />
<result property="createTime" column="create_time" />
</resultMap>
<sql id="selectDmsBillsMaintDetailProjectVo">
select
dbmdp.maint_detail_project_id,
dbmdp.bills_maint_detail_id,
dbmdp.maint_project_id,
COALESCE(dbmdp.maint_project_name, dbmp.maint_project_name) as maint_project_name,
COALESCE(dbmdp.maint_project_desc, dbmp.maint_project_desc) as maint_project_desc,
dbmdp.maint_project_status,
dbmdp.remark,
dbmdp.create_time
from
dms_bills_maint_detail_project dbmdp
left join dms_base_maint_project dbmp on dbmdp.maint_project_id = dbmp.maint_project_id
</sql>
<select id="selectDmsBillsMaintDetailProjectWithProjectName" parameterType="DmsBillsMaintDetailProject" resultMap="DmsBillsMaintDetailProjectResult">
<include refid="selectDmsBillsMaintDetailProjectVo"/>
<where>
<if test="maintDetailProjectId != null"> and dbmdp.maint_detail_project_id = #{maintDetailProjectId}</if>
<if test="billsMaintDetailId != null"> and dbmdp.bills_maint_detail_id = #{billsMaintDetailId}</if>
<if test="maintProjectId != null"> and dbmdp.maint_project_id = #{maintProjectId}</if>
<if test="maintProjectStatus != null and maintProjectStatus != ''"> and dbmdp.maint_project_status = #{maintProjectStatus}</if>
</where>
order by dbmdp.create_time desc
</select>
</mapper>

@ -61,7 +61,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete>
<insert id="insertParts" parameterType="java.util.List">
insert into dms_fault_compents_parts(fault_id,part_name,part_specifications,amount)
insert into dms_fault_components_parts(repair_instance_id,part_name,part_specifications,amount)
values
<foreach collection="list" item="item" index="index" open="" close="" separator=",">
(#{item.faultId},#{item.partName},#{item.partSpecifications},#{item.amount})

@ -30,9 +30,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select a.plan_inspect_id, a.plan_inspect_code, a.plan_inspect_name, a.inspect_type,
a.inspect_route_id, a.device_amount, a.plan_time, a.cycle_period,a.time_limit,a.job_id,
a.performer, a.remark, a.create_by, a.create_time, a.update_by, a.update_time,
b.cron_expression
-- '' as cron_expression
from dms_plan_inspect a
left join sys_job b on a.job_id = b.job_id
where a.plan_inspect_id = #{planInspectId}
</select>
@ -42,7 +41,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
a.inspect_route_id, a.device_amount, a.plan_time, a.cycle_period,a.time_limit,a.job_id,
a.performer, a.remark, a.create_by, a.create_time, a.update_by,
a.update_time
from dms_plan_inspect a left join sys_job b on a.job_id = b.job_id
from dms_plan_inspect a
where a.plan_inspect_code = #{planInspectCode}
</select>

@ -72,10 +72,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectPlanLubeJoinJobByPlanLubeId" parameterType="Long" resultMap="DmsPlanLubeResult">
select a.plan_lube_id, a.plan_lube_code, a.lube_level, a.lube_group, a.lube_supervisor, a.lube_time, a.time_limit, a.job_id, a.cycle_period, a.create_method, a.remark, a.create_by, a.create_time,
sj.cron_expression
select a.plan_lube_id, a.plan_lube_code, a.lube_level, a.lube_group, a.lube_supervisor, a.lube_time, a.time_limit, a.job_id,
a.cycle_period, a.create_method, a.remark,
a.create_by,
a.create_time,
-- '' as cron_expression
from dms_plan_lube a
left join hwmom-job.sys_job sj on a.job_id = sj.job_id
where a.plan_lube_id = #{planLubeId}
</select>
</mapper>

@ -0,0 +1,116 @@
package org.dromara.mes.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.mes.domain.vo.BaseToolingTypeVo;
import org.dromara.mes.domain.bo.BaseToolingTypeBo;
import org.dromara.mes.service.IBaseToolingTypeService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
*
* 访:/mes/toolingType
*
* @author Yinq
* @date 2025-07-03
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/toolingType")
public class BaseToolingTypeController extends BaseController {
private final IBaseToolingTypeService baseToolingTypeService;
/**
*
*/
@SaCheckPermission("mes:toolingType:list")
@GetMapping("/list")
public TableDataInfo<BaseToolingTypeVo> list(BaseToolingTypeBo bo, PageQuery pageQuery) {
return baseToolingTypeService.queryPageList(bo, pageQuery);
}
/**
*
*/
@SaCheckPermission("mes:toolingType:export")
@Log(title = "载具工装类型", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(BaseToolingTypeBo bo, HttpServletResponse response) {
List<BaseToolingTypeVo> list = baseToolingTypeService.queryList(bo);
ExcelUtil.exportExcel(list, "载具工装类型", BaseToolingTypeVo.class, response);
}
/**
*
*
* @param toolingTypeId
*/
@SaCheckPermission("mes:toolingType:query")
@GetMapping("/{toolingTypeId}")
public R<BaseToolingTypeVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long toolingTypeId) {
return R.ok(baseToolingTypeService.queryById(toolingTypeId));
}
/**
*
*/
@SaCheckPermission("mes:toolingType:add")
@Log(title = "载具工装类型", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody BaseToolingTypeBo bo) {
return toAjax(baseToolingTypeService.insertByBo(bo));
}
/**
*
*/
@SaCheckPermission("mes:toolingType:edit")
@Log(title = "载具工装类型", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody BaseToolingTypeBo bo) {
return toAjax(baseToolingTypeService.updateByBo(bo));
}
/**
*
*
* @param toolingTypeIds
*/
@SaCheckPermission("mes:toolingType:remove")
@Log(title = "载具工装类型", businessType = BusinessType.DELETE)
@DeleteMapping("/{toolingTypeIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] toolingTypeIds) {
return toAjax(baseToolingTypeService.deleteWithValidByIds(List.of(toolingTypeIds), true));
}
/**
*
*/
@GetMapping("/getBaseToolingTypeList")
public R<List<BaseToolingTypeVo>> getBaseToolingTypeList(BaseToolingTypeBo bo) {
List<BaseToolingTypeVo> list = baseToolingTypeService.queryList(bo);
return R.ok(list);
}
}

@ -67,6 +67,11 @@ public class BaseShiftInfo extends TenantEntity {
*/
private String activeFlag;
/**
* (2 3)
*/
private String classType;
/**
* 0 2
*/

@ -1,9 +1,6 @@
package org.dromara.mes.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
@ -41,11 +38,6 @@ public class BaseToolingInfo extends TenantEntity {
*/
private String toolingName;
/**
*
*/
private String toolingTypeCode;
/**
*
*/
@ -81,9 +73,21 @@ public class BaseToolingInfo extends TenantEntity {
*/
private String activeFlag;
/**
* ID
*/
private Long toolingTypeId;
/**
* 0 2
*/
@TableLogic
private String delFlag;
/**
*
*/
@TableField(exist = false)
private String toolingTypeName;
}

@ -0,0 +1,69 @@
package org.dromara.mes.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.util.List;
/**
* base_tooling_type
*
* @author Yinq
* @date 2025-07-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("base_tooling_type")
public class BaseToolingType extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId(value = "tooling_type_id", type = IdType.AUTO)
private Long toolingTypeId;
/**
*
*/
private String toolingTypeCode;
/**
*
*/
private String toolingTypeName;
/**
*
*/
private String toolingSpecCode;
/**
* 使/
*/
private Long standardLife;
/**
* (kg)
*/
private Long standardWeight;
/**
*
*/
private String remark;
/**
* 0 2
*/
@TableLogic
private String delFlag;
@TableField(exist = false)
private List<BaseToolingTypeRelation> typeRelationList;
}

@ -0,0 +1,56 @@
package org.dromara.mes.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* base_tooling_type_relation
*
* @author Yinq
* @date 2025-07-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("base_tooling_type_relation")
public class BaseToolingTypeRelation extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId(value = "relation_id", type = IdType.AUTO)
private Long relationId;
/**
* ID
*/
private Long toolingTypeId;
/**
* (1 2)
*/
private String relationInfoType;
/**
* ID
*/
private Long relationInfoId;
/**
* 0 2
*/
@TableLogic
private String delFlag;
/**
*
*/
@TableField(exist = false)
private String materialName;
}

@ -122,6 +122,11 @@ public class ProdBaseMachineInfo extends TenantEntity {
*/
private Long requestInterval;
/**
* (2 3)
*/
private String classType;
/**
* 0 2
*/
@ -144,4 +149,5 @@ public class ProdBaseMachineInfo extends TenantEntity {
*/
@TableField(exist = false)
private String deviceModeName;
}

@ -74,5 +74,9 @@ public class BaseShiftInfoBo extends BaseEntity {
/* @NotBlank(message = "激活标识1是 0否不能为空", groups = { AddGroup.class, EditGroup.class })*/
private String activeFlag;
/**
* (2 3)
*/
@NotBlank(message = "班制类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String classType;
}

@ -74,5 +74,14 @@ public class BaseToolingInfoBo extends BaseEntity {
*/
private String activeFlag;
/**
* ID
*/
private Long toolingTypeId;
/**
*
*/
private String toolingTypeName;
}

@ -0,0 +1,66 @@
package org.dromara.mes.domain.bo;
import org.dromara.mes.domain.BaseToolingType;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import org.dromara.mes.domain.BaseToolingTypeRelation;
import java.util.List;
/**
* base_tooling_type
*
* @author Yinq
* @date 2025-07-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = BaseToolingType.class, reverseConvertGenerate = false)
public class BaseToolingTypeBo extends BaseEntity {
/**
*
*/
private Long toolingTypeId;
/**
*
*/
@NotBlank(message = "工装类型编号不能为空", groups = { AddGroup.class, EditGroup.class })
private String toolingTypeCode;
/**
*
*/
@NotBlank(message = "工装类型名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String toolingTypeName;
/**
*
*/
private String toolingSpecCode;
/**
* 使/
*/
private Long standardLife;
/**
* (kg)
*/
private Long standardWeight;
/**
*
*/
private String remark;
private List<BaseToolingTypeRelation> typeRelationList;
private List<BaseToolingTypeRelation> processList;
}

@ -0,0 +1,47 @@
package org.dromara.mes.domain.bo;
import org.dromara.mes.domain.BaseToolingTypeRelation;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* base_tooling_type_relation
*
* @author Yinq
* @date 2025-07-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = BaseToolingTypeRelation.class, reverseConvertGenerate = false)
public class BaseToolingTypeRelationBo extends BaseEntity {
/**
*
*/
private Long relationId;
/**
* ID
*/
@NotNull(message = "工装类型ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long toolingTypeId;
/**
* (1 2)
*/
@NotBlank(message = "关联信息类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String relationInfoType;
/**
* ID
*/
@NotNull(message = "关联信息ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long relationInfoId;
}

@ -145,5 +145,11 @@ public class ProdBaseMachineInfoBo extends BaseEntity {
*/
private String instockType;
/**
* (2 3)
*/
@NotBlank(message = "班制类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String classType;
private List<ProdBaseMachineProcess> baseMachineProcessList;
}

@ -122,5 +122,10 @@ public class BaseShiftInfoVo implements Serializable {
@ExcelProperty(value = "更新时间")
private Date updateTime;
/**
* (2 3)
*/
@ExcelProperty(value = "班制类型(2两班 3三班)", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "mes_class_type")
private String classType;
}

@ -2,6 +2,7 @@ package org.dromara.mes.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableField;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
@ -53,13 +54,6 @@ public class BaseToolingInfoVo implements Serializable {
@ExcelProperty(value = "工装名称")
private String toolingName;
/**
*
*/
@ExcelProperty(value = "工装类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "tooling_type_code")
private String toolingTypeCode;
/**
*
*/
@ -133,5 +127,11 @@ public class BaseToolingInfoVo implements Serializable {
@ExcelProperty(value = "更新时间")
private Date updateTime;
/**
*
*/
@ExcelProperty(value = "工装类型名称")
private String toolingTypeName;
private Long toolingTypeId;
}

@ -0,0 +1,56 @@
package org.dromara.mes.domain.vo;
import org.dromara.mes.domain.BaseToolingTypeRelation;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* base_tooling_type_relation
*
* @author Yinq
* @date 2025-07-03
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = BaseToolingTypeRelation.class)
public class BaseToolingTypeRelationVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@ExcelProperty(value = "主键标识")
private Long relationId;
/**
* ID
*/
@ExcelProperty(value = "工装类型ID")
private Long toolingTypeId;
/**
* (1 2)
*/
@ExcelProperty(value = "关联信息类型(1物料 2工序)")
private String relationInfoType;
/**
* ID
*/
@ExcelProperty(value = "关联信息ID")
private Long relationInfoId;
}

@ -0,0 +1,76 @@
package org.dromara.mes.domain.vo;
import org.dromara.mes.domain.BaseToolingType;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.mes.domain.BaseToolingTypeRelation;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* base_tooling_type
*
* @author Yinq
* @date 2025-07-03
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = BaseToolingType.class)
public class BaseToolingTypeVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@ExcelProperty(value = "主键标识")
private Long toolingTypeId;
/**
*
*/
@ExcelProperty(value = "工装类型编号")
private String toolingTypeCode;
/**
*
*/
@ExcelProperty(value = "工装类型名称")
private String toolingTypeName;
/**
*
*/
@ExcelProperty(value = "工装类型规格")
private String toolingSpecCode;
/**
* 使/
*/
@ExcelProperty(value = "标准使用次数/秒")
private Long standardLife;
/**
* (kg)
*/
@ExcelProperty(value = "标准重量(kg)")
private Long standardWeight;
/**
*
*/
@ExcelProperty(value = "备注")
private String remark;
private List<BaseToolingTypeRelation> typeRelationList;
private List<BaseToolingTypeRelation> processList;
}

@ -197,6 +197,13 @@ public class ProdBaseMachineInfoVo implements Serializable {
@ExcelProperty(value = "设备模型名称")
private String deviceModeName;
/**
* (2 3)
*/
@ExcelProperty(value = "班制类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "mes_class_type")
private String classType;
/**
* 1 2
*/

@ -255,4 +255,9 @@ public class ProdPlanInfoVo implements Serializable {
@ExcelProperty(value = "班次名称")
private String shiftName;//
/**
*
*/
@ExcelProperty(value = "单位名称")
private String unitName;
}

@ -0,0 +1,15 @@
package org.dromara.mes.mapper;
import org.dromara.mes.domain.BaseToolingType;
import org.dromara.mes.domain.vo.BaseToolingTypeVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* Mapper
*
* @author Yinq
* @date 2025-07-03
*/
public interface BaseToolingTypeMapper extends BaseMapperPlus<BaseToolingType, BaseToolingTypeVo> {
}

@ -0,0 +1,15 @@
package org.dromara.mes.mapper;
import org.dromara.mes.domain.BaseToolingTypeRelation;
import org.dromara.mes.domain.vo.BaseToolingTypeRelationVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* Mapper
*
* @author Yinq
* @date 2025-07-03
*/
public interface BaseToolingTypeRelationMapper extends BaseMapperPlus<BaseToolingTypeRelation, BaseToolingTypeRelationVo> {
}

@ -0,0 +1,69 @@
package org.dromara.mes.service;
import org.dromara.mes.domain.BaseToolingTypeRelation;
import org.dromara.mes.domain.vo.BaseToolingTypeRelationVo;
import org.dromara.mes.domain.bo.BaseToolingTypeRelationBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* Service
*
* @author Yinq
* @date 2025-07-03
*/
public interface IBaseToolingTypeRelationService {
/**
*
*
* @param relationId
* @return
*/
BaseToolingTypeRelationVo queryById(Long relationId);
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
TableDataInfo<BaseToolingTypeRelationVo> queryPageList(BaseToolingTypeRelationBo bo, PageQuery pageQuery);
/**
*
*
* @param bo
* @return
*/
List<BaseToolingTypeRelationVo> queryList(BaseToolingTypeRelationBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean insertByBo(BaseToolingTypeRelationBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean updateByBo(BaseToolingTypeRelationBo bo);
/**
*
*
* @param ids
* @param isValid
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

@ -0,0 +1,69 @@
package org.dromara.mes.service;
import org.dromara.mes.domain.BaseToolingType;
import org.dromara.mes.domain.vo.BaseToolingTypeVo;
import org.dromara.mes.domain.bo.BaseToolingTypeBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* Service
*
* @author Yinq
* @date 2025-07-03
*/
public interface IBaseToolingTypeService {
/**
*
*
* @param toolingTypeId
* @return
*/
BaseToolingTypeVo queryById(Long toolingTypeId);
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
TableDataInfo<BaseToolingTypeVo> queryPageList(BaseToolingTypeBo bo, PageQuery pageQuery);
/**
*
*
* @param bo
* @return
*/
List<BaseToolingTypeVo> queryList(BaseToolingTypeBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean insertByBo(BaseToolingTypeBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean updateByBo(BaseToolingTypeBo bo);
/**
*
*
* @param ids
* @param isValid
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

@ -10,6 +10,7 @@ import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.mes.domain.BaseToolingType;
import org.springframework.stereotype.Service;
import org.dromara.mes.domain.bo.BaseToolingInfoBo;
import org.dromara.mes.domain.vo.BaseToolingInfoVo;
@ -74,10 +75,11 @@ public class BaseToolingInfoServiceImpl implements IBaseToolingInfoService {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<BaseToolingInfo> lqw = JoinWrappers.lambda(BaseToolingInfo.class)
.selectAll(BaseToolingInfo.class)
.select(BaseToolingType::getToolingTypeName)
.leftJoin(BaseToolingType.class, BaseToolingType::getToolingTypeId, BaseToolingType::getToolingTypeId)
.eq(bo.getToolingId() != null, BaseToolingInfo::getToolingId, bo.getToolingId())
.eq(StringUtils.isNotBlank(bo.getToolingCode()), BaseToolingInfo::getToolingCode, bo.getToolingCode())
.like(StringUtils.isNotBlank(bo.getToolingName()), BaseToolingInfo::getToolingName, bo.getToolingName())
.eq(StringUtils.isNotBlank(bo.getToolingTypeCode()), BaseToolingInfo::getToolingTypeCode, bo.getToolingTypeCode())
.eq(StringUtils.isNotBlank(bo.getToolingSpecCode()), BaseToolingInfo::getToolingSpecCode, bo.getToolingSpecCode())
.eq(StringUtils.isNotBlank(bo.getToolingBarcode()), BaseToolingInfo::getToolingBarcode, bo.getToolingBarcode())
.eq(StringUtils.isNotBlank(bo.getToolingRfidBarcode()), BaseToolingInfo::getToolingRfidBarcode, bo.getToolingRfidBarcode())

@ -0,0 +1,135 @@
package org.dromara.mes.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.mes.domain.bo.BaseToolingTypeRelationBo;
import org.dromara.mes.domain.vo.BaseToolingTypeRelationVo;
import org.dromara.mes.domain.BaseToolingTypeRelation;
import org.dromara.mes.mapper.BaseToolingTypeRelationMapper;
import org.dromara.mes.service.IBaseToolingTypeRelationService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* Service
*
* @author Yinq
* @date 2025-07-03
*/
@RequiredArgsConstructor
@Service
public class BaseToolingTypeRelationServiceImpl implements IBaseToolingTypeRelationService {
private final BaseToolingTypeRelationMapper baseMapper;
/**
*
*
* @param relationId
* @return
*/
@Override
public BaseToolingTypeRelationVo queryById(Long relationId){
return baseMapper.selectVoById(relationId);
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<BaseToolingTypeRelationVo> queryPageList(BaseToolingTypeRelationBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<BaseToolingTypeRelation> lqw = buildQueryWrapper(bo);
Page<BaseToolingTypeRelationVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @return
*/
@Override
public List<BaseToolingTypeRelationVo> queryList(BaseToolingTypeRelationBo bo) {
MPJLambdaWrapper<BaseToolingTypeRelation> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private MPJLambdaWrapper<BaseToolingTypeRelation> buildQueryWrapper(BaseToolingTypeRelationBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<BaseToolingTypeRelation> lqw = JoinWrappers.lambda(BaseToolingTypeRelation.class)
.selectAll(BaseToolingTypeRelation.class)
.eq(bo.getRelationId() != null, BaseToolingTypeRelation::getRelationId, bo.getRelationId())
.eq(bo.getToolingTypeId() != null, BaseToolingTypeRelation::getToolingTypeId, bo.getToolingTypeId())
.eq(StringUtils.isNotBlank(bo.getRelationInfoType()), BaseToolingTypeRelation::getRelationInfoType, bo.getRelationInfoType())
.eq(bo.getRelationInfoId() != null, BaseToolingTypeRelation::getRelationInfoId, bo.getRelationInfoId())
.orderByAsc(BaseToolingTypeRelation::getCreateTime);
return lqw;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean insertByBo(BaseToolingTypeRelationBo bo) {
BaseToolingTypeRelation add = MapstructUtils.convert(bo, BaseToolingTypeRelation.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setRelationId(add.getRelationId());
}
return flag;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean updateByBo(BaseToolingTypeRelationBo bo) {
BaseToolingTypeRelation update = MapstructUtils.convert(bo, BaseToolingTypeRelation.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
*
*/
private void validEntityBeforeSave(BaseToolingTypeRelation entity){
//TODO 做一些数据校验,如唯一约束
}
/**
*
*
* @param ids
* @param isValid
* @return
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -0,0 +1,235 @@
package org.dromara.mes.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.mes.domain.BaseMaterialInfo;
import org.dromara.mes.domain.BaseToolingTypeRelation;
import org.dromara.mes.domain.ProdBaseRouteMaterial;
import org.dromara.mes.mapper.BaseToolingTypeRelationMapper;
import org.springframework.stereotype.Service;
import org.dromara.mes.domain.bo.BaseToolingTypeBo;
import org.dromara.mes.domain.vo.BaseToolingTypeVo;
import org.dromara.mes.domain.BaseToolingType;
import org.dromara.mes.mapper.BaseToolingTypeMapper;
import org.dromara.mes.service.IBaseToolingTypeService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Service
*
* @author Yinq
* @date 2025-07-03
*/
@RequiredArgsConstructor
@Service
public class BaseToolingTypeServiceImpl implements IBaseToolingTypeService {
private final BaseToolingTypeMapper baseMapper;
private final BaseToolingTypeRelationMapper relationMapper;
/**
*
*
* @param toolingTypeId
* @return
*/
@Override
public BaseToolingTypeVo queryById(Long toolingTypeId){
BaseToolingTypeVo baseToolingTypeVo = baseMapper.selectVoById(toolingTypeId);
// 关联物料
MPJLambdaWrapper<BaseToolingTypeRelation> lqw = JoinWrappers.lambda(BaseToolingTypeRelation.class);
lqw.selectAll(BaseToolingTypeRelation.class)
.select(BaseMaterialInfo::getMaterialName)
.leftJoin(BaseMaterialInfo.class, BaseMaterialInfo::getMaterialId, BaseToolingTypeRelation::getRelationInfoId)
.eq(BaseToolingTypeRelation::getToolingTypeId, toolingTypeId)
.eq(BaseToolingTypeRelation::getRelationInfoType, "1");
List<BaseToolingTypeRelation> relationList = relationMapper.selectList(lqw);
baseToolingTypeVo.setTypeRelationList(relationList);
// 关联工序
MPJLambdaWrapper<BaseToolingTypeRelation> lqwProcess = JoinWrappers.lambda(BaseToolingTypeRelation.class);
lqwProcess.selectAll(BaseToolingTypeRelation.class)
.eq(BaseToolingTypeRelation::getToolingTypeId, toolingTypeId)
.eq(BaseToolingTypeRelation::getRelationInfoType, "2");
List<BaseToolingTypeRelation> relationProcessList = relationMapper.selectList(lqwProcess);
baseToolingTypeVo.setProcessList(relationProcessList);
return baseToolingTypeVo;
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<BaseToolingTypeVo> queryPageList(BaseToolingTypeBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<BaseToolingType> lqw = buildQueryWrapper(bo);
Page<BaseToolingTypeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @return
*/
@Override
public List<BaseToolingTypeVo> queryList(BaseToolingTypeBo bo) {
MPJLambdaWrapper<BaseToolingType> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private MPJLambdaWrapper<BaseToolingType> buildQueryWrapper(BaseToolingTypeBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<BaseToolingType> lqw = JoinWrappers.lambda(BaseToolingType.class)
.selectAll(BaseToolingType.class)
.eq(bo.getToolingTypeId() != null, BaseToolingType::getToolingTypeId, bo.getToolingTypeId())
.eq(StringUtils.isNotBlank(bo.getToolingTypeCode()), BaseToolingType::getToolingTypeCode, bo.getToolingTypeCode())
.like(StringUtils.isNotBlank(bo.getToolingTypeName()), BaseToolingType::getToolingTypeName, bo.getToolingTypeName())
.eq(StringUtils.isNotBlank(bo.getToolingSpecCode()), BaseToolingType::getToolingSpecCode, bo.getToolingSpecCode())
.eq(bo.getStandardLife() != null, BaseToolingType::getStandardLife, bo.getStandardLife())
.eq(bo.getStandardWeight() != null, BaseToolingType::getStandardWeight, bo.getStandardWeight())
.orderByAsc(BaseToolingType::getCreateTime);
return lqw;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean insertByBo(BaseToolingTypeBo bo) {
BaseToolingType add = MapstructUtils.convert(bo, BaseToolingType.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
assert add != null;
bo.setToolingTypeId(add.getToolingTypeId());
// 插入关联物料
List<BaseToolingTypeRelation> typeRelationList = bo.getTypeRelationList();
if (typeRelationList != null && !typeRelationList.isEmpty()) {
for (BaseToolingTypeRelation typeRelation : typeRelationList) {
typeRelation.setToolingTypeId(add.getToolingTypeId());
relationMapper.insert(typeRelation);
}
}
}
return flag;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean updateByBo(BaseToolingTypeBo bo) {
BaseToolingType update = MapstructUtils.convert(bo, BaseToolingType.class);
validEntityBeforeSave(update);
// 更新工艺路线关联物料
List<BaseToolingTypeRelation> typeRelationList = bo.getTypeRelationList();
MPJLambdaWrapper<BaseToolingTypeRelation> lqwMaterial = JoinWrappers.lambda(BaseToolingTypeRelation.class);
lqwMaterial.eq(BaseToolingTypeRelation::getToolingTypeId, bo.getToolingTypeId())
.eq(BaseToolingTypeRelation::getRelationInfoType, "1");
List<BaseToolingTypeRelation> dbTypeRelationList = relationMapper.selectList(lqwMaterial);
if (typeRelationList != null && !typeRelationList.isEmpty()) {
for (BaseToolingTypeRelation typeRelation : typeRelationList) {
typeRelation.setToolingTypeId(bo.getToolingTypeId());
if (typeRelation.getRelationId() == null) {
relationMapper.insert(typeRelation);
} else {
relationMapper.updateById(typeRelation);
}
}
Set<Long> existingIds = typeRelationList.stream()
.filter(m -> m.getRelationId() != null)
.map(BaseToolingTypeRelation::getRelationId)
.collect(Collectors.toSet());
List<BaseToolingTypeRelation> filteredIds = dbTypeRelationList.stream()
.filter(field -> !existingIds.contains(field.getRelationId()))
.toList();
for (BaseToolingTypeRelation typeRelation : filteredIds) {
relationMapper.deleteById(typeRelation.getRelationId());
}
} else if (dbTypeRelationList != null && !dbTypeRelationList.isEmpty()) {
// 如果前端传空,全部删除
for (BaseToolingTypeRelation typeRelation : dbTypeRelationList) {
relationMapper.deleteById(typeRelation.getRelationId());
}
}
// 更新关联工序
List<BaseToolingTypeRelation> typeProessList = bo.getProcessList();
MPJLambdaWrapper<BaseToolingTypeRelation> lqwMaterialProess = JoinWrappers.lambda(BaseToolingTypeRelation.class);
lqwMaterialProess.eq(BaseToolingTypeRelation::getToolingTypeId, bo.getToolingTypeId())
.eq(BaseToolingTypeRelation::getRelationInfoType, "2");
List<BaseToolingTypeRelation> dbTypeProessList = relationMapper.selectList(lqwMaterialProess);
if (typeProessList != null && !typeProessList.isEmpty()) {
for (BaseToolingTypeRelation typeRelation : typeProessList) {
typeRelation.setToolingTypeId(bo.getToolingTypeId());
if (typeRelation.getRelationId() == null) {
relationMapper.insert(typeRelation);
} else {
relationMapper.updateById(typeRelation);
}
}
Set<Long> existingIds = typeProessList.stream()
.filter(m -> m.getRelationId() != null)
.map(BaseToolingTypeRelation::getRelationId)
.collect(Collectors.toSet());
List<BaseToolingTypeRelation> filteredIds = dbTypeProessList.stream()
.filter(field -> !existingIds.contains(field.getRelationId()))
.toList();
for (BaseToolingTypeRelation typeRelation : filteredIds) {
relationMapper.deleteById(typeRelation.getRelationId());
}
} else if (dbTypeProessList != null && !dbTypeProessList.isEmpty()) {
// 如果前端传空,全部删除
for (BaseToolingTypeRelation typeRelation : dbTypeProessList) {
relationMapper.deleteById(typeRelation.getRelationId());
}
}
return baseMapper.updateById(update) > 0;
}
/**
*
*/
private void validEntityBeforeSave(BaseToolingType entity){
//TODO 做一些数据校验,如唯一约束
}
/**
*
*
* @param ids
* @param isValid
* @return
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -53,9 +53,6 @@ public class ProdPlanInfoServiceImpl implements IProdPlanInfoService {
private final Logger log = LoggerFactory.getLogger(ProdPlanInfoServiceImpl.class);
private static final String PLAN_ID_HEADER = "planId";
private final ProdPlanInfoMapper baseMapper;
private final DynamicBaseSqlMapper<ProdPlanInfo> dynamicBaseSqlMapper;

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.mes.mapper.BaseToolingTypeMapper">
</mapper>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.mes.mapper.BaseToolingTypeRelationMapper">
</mapper>

@ -64,6 +64,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="productionTime" column="production_time"/>
<result property="releaseName" column="release_name"/>
<result property="unitName" column="unit_name"/>
</resultMap>
@ -87,13 +88,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
end as release_name,
pbpi.process_name,
bsi.shift_name,
bcti.team_name
bcti.team_name,
bmui.unit_name
</if>
<if test="ew.getSqlSelect == null">
*
</if>
from ${tableName} t
left join base_material_info bmi on bmi.material_id = t.material_id
left join base_measurement_unit_info bmui on bmui.unit_id = bmi.material_unit_id
left join prod_material_bom pmb on pmb.material_bom_id = t.material_bom_id
left join base_material_info bomi on bomi.material_id = pmb.material_id
left join prod_base_process_info pbpi on pbpi.process_id = t.process_id

Loading…
Cancel
Save