package com.emergencyrepair.business.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.emergencyrepair.business.dto.Requests; import com.emergencyrepair.business.entity.Acceptance; import com.emergencyrepair.business.entity.CompletionInfo; import com.emergencyrepair.business.entity.Contractor; import com.emergencyrepair.business.entity.Fault; import com.emergencyrepair.business.entity.TeamMajor; import com.emergencyrepair.business.entity.WorkOrder; import com.emergencyrepair.business.mapper.AcceptanceMapper; import com.emergencyrepair.business.mapper.CompletionInfoMapper; import com.emergencyrepair.business.mapper.ContractorMapper; import com.emergencyrepair.business.mapper.FaultMapper; import com.emergencyrepair.business.mapper.TeamMajorMapper; import com.emergencyrepair.business.mapper.WorkOrderMapper; import com.emergencyrepair.common.BusinessException; import com.emergencyrepair.common.StatusConstants; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class BusinessService { private static final DateTimeFormatter FAULT_DATE_FORMAT = DateTimeFormatter.ofPattern("yyMMdd"); private static final String FAULT_CODE_PREFIX = "\u6f5c1\u57fa-"; private static final Object FAULT_CODE_LOCK = new Object(); private final FaultMapper faultMapper; private final TeamMajorMapper teamMajorMapper; private final WorkOrderMapper workOrderMapper; private final ContractorMapper contractorMapper; private final CompletionInfoMapper completionInfoMapper; private final AcceptanceMapper acceptanceMapper; private final ObjectMapper objectMapper; public List listFaults(String status, String keyword) { return listFaults(status, keyword, null, null, null, null, null, null, null, null, null); } public List listFaults(String status, String keyword, String xNo, String teamMajor, String engineeringMajor, String reportUnit, String owner, LocalDate reportDateStart, LocalDate reportDateEnd, String contractorName, String faultNature) { return faultMapper.selectList(faultQuery(status, keyword, xNo, teamMajor, engineeringMajor, reportUnit, owner, reportDateStart, reportDateEnd, contractorName, faultNature)); } public Page pageFaults(String status, String keyword, String xNo, String teamMajor, String engineeringMajor, String reportUnit, String owner, LocalDate reportDateStart, LocalDate reportDateEnd, String contractorName, String faultNature, long current, long size) { long safeCurrent = Math.max(current, 1L); long safeSize = Math.min(Math.max(size, 1L), 200L); return faultMapper.selectPage(new Page<>(safeCurrent, safeSize), faultQuery(status, keyword, xNo, teamMajor, engineeringMajor, reportUnit, owner, reportDateStart, reportDateEnd, contractorName, faultNature)); } private LambdaQueryWrapper faultQuery(String status, String keyword) { return faultQuery(status, keyword, null, null, null, null, null, null, null, null, null); } private LambdaQueryWrapper faultQuery(String status, String keyword, String xNo, String teamMajor, String engineeringMajor, String reportUnit, String owner, LocalDate reportDateStart, LocalDate reportDateEnd, String contractorName, String faultNature) { LambdaQueryWrapper query = Wrappers.lambdaQuery(); if (StringUtils.hasText(status)) { query.in(Fault::getTaskStatus, Arrays.asList(status.split(","))); } if (StringUtils.hasText(keyword)) { query.and(wrapper -> wrapper .like(Fault::getFaultCode, keyword) .or().like(Fault::getEquipmentName, keyword) .or().like(Fault::getEngineeringNameDesc, keyword)); } if (StringUtils.hasText(xNo)) { query.eq(Fault::getXNo, xNo.trim()); } if (StringUtils.hasText(teamMajor)) { query.eq(Fault::getTeamMajor, teamMajor); } if (StringUtils.hasText(engineeringMajor)) { query.eq(Fault::getEngineeringMajor, engineeringMajor); } if (StringUtils.hasText(reportUnit)) { query.like(Fault::getReportUnit, reportUnit.trim()); } if (StringUtils.hasText(owner)) { query.like(Fault::getOwner, owner.trim()); } if (reportDateStart != null) { query.ge(Fault::getReportDate, reportDateStart); } if (reportDateEnd != null) { query.le(Fault::getReportDate, reportDateEnd); } if (StringUtils.hasText(contractorName)) { query.like(Fault::getContractorNames, contractorName.trim()); } if (StringUtils.hasText(faultNature)) { query.eq(Fault::getFaultNature, faultNature); } query.orderByDesc(Fault::getReportDate).orderByDesc(Fault::getCreateTime); return query; } @Transactional public Fault saveFault(Fault fault) { if (fault == null) { throw new BusinessException("故障信息不能为空"); } LocalDateTime now = LocalDateTime.now(); normalizeEquipmentIds(fault); normalizeParentSystemSeparators(fault); fault.setUpdateTime(now); if (fault.getId() == null) { if (fault.getReportDate() == null) { fault.setReportDate(LocalDate.now()); } synchronized (FAULT_CODE_LOCK) { fault.setFaultCode(generateFaultCode(fault)); fault.setTaskStatus(StatusConstants.Task.UNREPORTED); fault.setCreateTime(now); faultMapper.insert(fault); } } else { Fault existing = requireFault(fault.getId()); if (!canEdit(existing)) { throw new BusinessException("当前任务状态不允许修改"); } // The fault code is generated once on create and never edited afterwards. fault.setFaultCode(existing.getFaultCode()); if (!StringUtils.hasText(fault.getTaskStatus())) { fault.setTaskStatus(existing.getTaskStatus()); } faultMapper.updateById(fault); } return faultMapper.selectById(fault.getId()); } /** * Builds the fault code as: prefix + three digit X number + "/" + team major category * + "-" + report date (yyMMdd) + "-" + three digit sequence. * The sequence restarts at 001 for each X number + team major + report date. */ private String generateFaultCode(Fault fault) { String xNo = normalizeXNo(fault.getXNo()); if (xNo == null) { throw new BusinessException("请选择X号,格式为3位数字"); } if (!StringUtils.hasText(fault.getTeamMajor())) { throw new BusinessException("请选择T队专业"); } TeamMajor teamMajor = teamMajorMapper.selectOne(Wrappers.lambdaQuery() .eq(TeamMajor::getName, fault.getTeamMajor().trim()) .last("LIMIT 1")); if (teamMajor == null) { throw new BusinessException("T队专业未配置,请先在系统管理 > T队专业配置中维护:" + fault.getTeamMajor()); } String category = teamMajor.getCategory() == null ? "" : teamMajor.getCategory().trim().toUpperCase(); if (!"A".equals(category) && !"B".equals(category)) { throw new BusinessException("T队专业分类只能为A或B:" + fault.getTeamMajor()); } String prefix = FAULT_CODE_PREFIX + xNo + "/" + category + "-" + fault.getReportDate().format(FAULT_DATE_FORMAT) + "-"; int next = 1; for (Fault item : faultMapper.selectList(Wrappers.lambdaQuery() .likeRight(Fault::getFaultCode, prefix))) { next = Math.max(next, parseFaultSequence(item.getFaultCode(), prefix) + 1); } return prefix + String.format("%03d", next); } private int parseFaultSequence(String faultCode, String prefix) { if (faultCode == null || !faultCode.startsWith(prefix)) { return 0; } String suffix = faultCode.substring(prefix.length()); if (suffix.length() < 3) { return 0; } try { return Integer.parseInt(suffix.substring(0, 3)); } catch (NumberFormatException ex) { return 0; } } private String normalizeXNo(String xNo) { if (!StringUtils.hasText(xNo)) { return null; } String digits = xNo.replaceAll("[^0-9]", ""); if (digits.isEmpty()) { return null; } if (digits.length() > 3) { digits = digits.substring(digits.length() - 3); } StringBuilder builder = new StringBuilder(); for (int i = digits.length(); i < 3; i++) { builder.append('0'); } return builder.append(digits).toString(); } @Transactional public void deleteFault(Long id) { Fault fault = requireFault(id); if (!StatusConstants.Task.UNREPORTED.equals(fault.getTaskStatus()) && !StatusConstants.Task.RETURNED.equals(fault.getTaskStatus())) { throw new BusinessException("仅未上报或上级打回的故障可以删除"); } faultMapper.deleteById(id); } @Transactional public void cancelFaults(Requests.CancelRequest request) { if (request.getIds() == null || request.getIds().isEmpty()) { throw new BusinessException("请选择故障"); } if (!StringUtils.hasText(request.getReason())) { throw new BusinessException("请填写销项理由"); } String cancelledBy = StringUtils.hasText(request.getCancelledBy()) ? request.getCancelledBy().trim() : "XCB助理"; for (Long id : request.getIds()) { Fault fault = requireFault(id); if (!StatusConstants.Task.REPORTED_XCB.equals(fault.getTaskStatus()) && !StatusConstants.Task.RETURNED.equals(fault.getTaskStatus())) { throw new BusinessException("故障 " + fault.getFaultCode() + " 当前状态不允许销项"); } fault.setCancelReason(request.getReason().trim()); fault.setCancelledBy(cancelledBy); fault.setCancelTime(LocalDateTime.now()); fault.setTaskStatus(StatusConstants.Task.CANCELLED); fault.setUpdateTime(LocalDateTime.now()); faultMapper.updateById(fault); } } @Transactional public void reportFaults(List ids) { for (Long id : ids) { Fault fault = requireFault(id); if (!StatusConstants.Task.UNREPORTED.equals(fault.getTaskStatus())) { throw new BusinessException("故障 " + fault.getFaultCode() + " 不是未上报状态"); } fault.setTaskStatus(StatusConstants.Task.REPORTED_XCB); fault.setUpdateTime(LocalDateTime.now()); faultMapper.updateById(fault); } } @Transactional public void xcbReview(Requests.ReviewRequest request) { if (request.getIds() == null || request.getIds().isEmpty()) { throw new BusinessException("请选择故障"); } if (request.getContractorIds() == null || request.getContractorIds().isEmpty()) { throw new BusinessException("至少分配一个承修单位"); } List contractors = contractorMapper.selectBatchIds(request.getContractorIds()); Map contractorMap = contractors.stream() .collect(Collectors.toMap(Contractor::getId, Function.identity())); String contractorIds = request.getContractorIds().stream() .map(String::valueOf) .collect(Collectors.joining(",")); String contractorNames = request.getContractorIds().stream() .map(contractorMap::get) .filter(item -> item != null) .map(Contractor::getName) .collect(Collectors.joining("、")); int index = 0; for (Long id : request.getIds()) { Fault fault = requireFault(id); if (!StatusConstants.Task.REPORTED_XCB.equals(fault.getTaskStatus()) && !StatusConstants.Task.RETURNED.equals(fault.getTaskStatus())) { throw new BusinessException("故障 " + fault.getFaultCode() + " 当前状态不允许XCB助理审核"); } index++; fault.setContractorIds(contractorIds); fault.setContractorNames(contractorNames); fault.setTrackingTeam(request.getTrackingTeam()); fault.setRequestedFinishDate(request.getRequestedFinishDate()); fault.setEngineeringNo(buildEngineeringNo(fault, index)); fault.setTaskStatus(StatusConstants.Task.XCB_REVIEWED); fault.setXcbReviewTime(LocalDateTime.now()); fault.setUpdateTime(LocalDateTime.now()); faultMapper.updateById(fault); } } @Transactional public void approve(Requests.ApprovalRequest request) { if (request.getIds() == null || request.getIds().isEmpty()) { throw new BusinessException("请选择故障"); } boolean pass = "PASS".equalsIgnoreCase(request.getResult()) || "通过".equals(request.getResult()); for (Long id : request.getIds()) { Fault fault = requireFault(id); LocalDateTime now = LocalDateTime.now(); switch (request.getStage()) { case "CMB": requireStatus(fault, StatusConstants.Task.XCB_REVIEWED, "CMB领导审批"); fault.setCmbOpinion(request.getOpinion()); fault.setCmbResult(pass ? "通过" : "不通过"); fault.setCmbTime(now); fault.setTaskStatus(pass ? StatusConstants.Task.CMB_APPROVED : StatusConstants.Task.RETURNED); break; case "JCC_ASSISTANT": requireStatus(fault, StatusConstants.Task.CMB_APPROVED, "JCC助理审批"); fault.setJccAssistantOpinion(request.getOpinion()); fault.setJccAssistantResult(pass ? "通过" : "不通过"); fault.setJccAssistantTime(now); fault.setTaskStatus(pass ? StatusConstants.Task.JCC_ASSISTANT_APPROVED : StatusConstants.Task.RETURNED); break; case "JCC_DIRECTOR": requireStatus(fault, StatusConstants.Task.JCC_ASSISTANT_APPROVED, "JCC处长审批"); fault.setJccDirectorOpinion(request.getOpinion()); fault.setJccDirectorResult(pass ? "通过" : "不通过"); fault.setJccDirectorTime(now); fault.setTaskStatus(pass ? StatusConstants.Task.JCC_DIRECTOR_APPROVED : StatusConstants.Task.RETURNED); break; default: throw new BusinessException("未知审批环节"); } fault.setUpdateTime(now); faultMapper.updateById(fault); } } @Transactional public List dispatch(Requests.DispatchRequest request) { if (request.getFaultIds() == null || request.getFaultIds().isEmpty()) { throw new BusinessException("请选择未派单故障"); } List created = new ArrayList<>(); for (Long faultId : request.getFaultIds()) { Fault fault = requireFault(faultId); if (!StatusConstants.Task.JCC_DIRECTOR_APPROVED.equals(fault.getTaskStatus())) { throw new BusinessException("故障 " + fault.getFaultCode() + " 未完成审批,不能派单"); } List contractorIds = parseIds(fault.getContractorIds()); if (contractorIds.isEmpty()) { throw new BusinessException("故障 " + fault.getFaultCode() + " 未分配承修单位"); } long exists = workOrderMapper.selectCount(Wrappers.lambdaQuery() .eq(WorkOrder::getFaultId, fault.getId())); if (exists > 0) { throw new BusinessException("故障 " + fault.getFaultCode() + " 已经派单"); } List contractors = contractorMapper.selectBatchIds(contractorIds); Map contractorMap = contractors.stream() .collect(Collectors.toMap(Contractor::getId, Function.identity())); int sequence = 1; for (Long contractorId : contractorIds) { Contractor contractor = contractorMap.get(contractorId); if (contractor == null) { continue; } WorkOrder workOrder = workOrderFromFault(fault); workOrder.setWorkOrderNo(fault.getFaultCode() + "/" + String.format("%02d", sequence++)); workOrder.setContractorId(contractor.getId()); workOrder.setContractorName(contractor.getName()); workOrder.setCompletionStatus(StatusConstants.Completion.UNFINISHED); workOrder.setDispatchTime(LocalDateTime.now()); workOrder.setCreateTime(LocalDateTime.now()); workOrder.setUpdateTime(LocalDateTime.now()); workOrderMapper.insert(workOrder); created.add(workOrder); } fault.setTaskStatus(StatusConstants.Task.DISPATCHED); fault.setDispatchTime(LocalDateTime.now()); fault.setUpdateTime(LocalDateTime.now()); faultMapper.updateById(fault); } return created; } public List listWorkOrders(String status, String keyword) { LambdaQueryWrapper query = Wrappers.lambdaQuery(); if (StringUtils.hasText(status)) { query.in(WorkOrder::getCompletionStatus, Arrays.asList(status.split(","))); } if (StringUtils.hasText(keyword)) { query.and(wrapper -> wrapper .like(WorkOrder::getWorkOrderNo, keyword) .or().like(WorkOrder::getFaultCode, keyword) .or().like(WorkOrder::getEquipmentName, keyword) .or().like(WorkOrder::getContractorName, keyword)); } query.orderByDesc(WorkOrder::getDispatchTime).orderByAsc(WorkOrder::getWorkOrderNo); return workOrderMapper.selectList(query); } public WorkOrder getWorkOrder(Long id) { return workOrderMapper.selectById(id); } @Transactional public void updateCompletionStatus(Requests.StatusRequest request) { WorkOrder workOrder = requireWorkOrder(request.getId()); if (StatusConstants.Completion.COMPLETED.equals(workOrder.getCompletionStatus())) { throw new BusinessException("已完工派工单不能退回普通完工状态"); } if (!Arrays.asList( StatusConstants.Completion.UNFINISHED, StatusConstants.Completion.WAIT_PARTS, StatusConstants.Completion.WAIT_TEST).contains(request.getStatus())) { throw new BusinessException("完工状态不合法"); } workOrder.setCompletionStatus(request.getStatus()); workOrder.setUpdateTime(LocalDateTime.now()); workOrderMapper.updateById(workOrder); } @Transactional public void scoreWorkOrder(Requests.ScoreRequest request) { WorkOrder workOrder = requireWorkOrder(request.getId()); if (request.getScore() == null || request.getScore() < 1 || request.getScore() > 5) { throw new BusinessException("修后质量评分必须在1至5之间"); } workOrder.setScore(request.getScore()); workOrder.setQualityOpinion(request.getOpinion()); workOrder.setUpdateTime(LocalDateTime.now()); workOrderMapper.updateById(workOrder); } @Transactional public CompletionInfo submitCompletion(Requests.CompletionRequest request) { WorkOrder workOrder = requireWorkOrder(request.getWorkOrderId()); if (StatusConstants.Completion.COMPLETED.equals(workOrder.getCompletionStatus())) { throw new BusinessException("该派工单已完工上报,不能重复提交"); } LocalDateTime now = LocalDateTime.now(); workOrder.setCompletionStatus(StatusConstants.Completion.COMPLETED); workOrder.setUpdateTime(now); workOrderMapper.updateById(workOrder); CompletionInfo info = completionInfoMapper.selectOne(Wrappers.lambdaQuery() .eq(CompletionInfo::getWorkOrderId, workOrder.getId()).last("LIMIT 1")); if (info == null) { info = new CompletionInfo(); info.setWorkOrderId(workOrder.getId()); info.setCreateTime(now); } info.setWorkOrderNo(workOrder.getWorkOrderNo()); info.setXNo(workOrder.getXNo()); info.setContractorName(workOrder.getContractorName()); info.setEngineeringNo(request.getEngineeringNo()); info.setStartDate(request.getStartDate()); info.setFinishDate(request.getFinishDate()); info.setContractorPerson(request.getContractorPerson()); info.setTInternalConstruction(request.getTInternalConstruction()); info.setRelatedProject(request.getRelatedProject()); info.setDurationDays(request.getDurationDays()); info.setPersonCount(request.getPersonCount()); info.setAcceptanceMode(request.getAcceptanceMode()); info.setQualityInfo(request.getQualityInfo()); info.setReasonAnalysis(request.getReasonAnalysis()); info.setFaultDescription(request.getFaultDescription()); info.setItemName(request.getItemName()); info.setSolution(joinSolutions(request)); try { info.setSolutionsJson(objectMapper.writeValueAsString(request.getSolutions())); info.setConsumablesJson(objectMapper.writeValueAsString(request.getMaterials())); info.setConsumableCount(materialQuantity(request.getMaterials())); } catch (Exception exception) { info.setSolutionsJson("[]"); info.setConsumablesJson("[]"); } info.setSubmitTime(now); info.setUpdateTime(now); if (info.getId() == null) { completionInfoMapper.insert(info); } else { completionInfoMapper.updateById(info); } Acceptance acceptance = acceptanceMapper.selectOne(Wrappers.lambdaQuery() .eq(Acceptance::getWorkOrderId, workOrder.getId()).last("LIMIT 1")); if (acceptance == null) { acceptance = new Acceptance(); acceptance.setWorkOrderId(workOrder.getId()); acceptance.setWorkOrderNo(workOrder.getWorkOrderNo()); acceptance.setXNo(workOrder.getXNo()); acceptance.setContractorName(workOrder.getContractorName()); acceptance.setStage("APPLICATION"); acceptance.setStatus(StatusConstants.Acceptance.APPLICATION_PENDING); acceptance.setApplyTime(now); acceptance.setCreateTime(now); acceptance.setUpdateTime(now); acceptanceMapper.insert(acceptance); } return info; } public List listAcceptances(String stage) { LambdaQueryWrapper query = Wrappers.lambdaQuery(); if (StringUtils.hasText(stage)) { switch (stage) { case "APPLICATION": query.in(Acceptance::getStatus, StatusConstants.Acceptance.APPLICATION_PENDING, StatusConstants.Acceptance.RETURNED_APPLICATION); break; case "INSPECTOR": query.in(Acceptance::getStatus, StatusConstants.Acceptance.QUALITY_INSPECTOR_PENDING, StatusConstants.Acceptance.RETURNED_INSPECTOR); break; case "LEADER": query.eq(Acceptance::getStatus, StatusConstants.Acceptance.QUALITY_LEADER_PENDING); break; case "PRINT": query.eq(Acceptance::getStatus, StatusConstants.Acceptance.PRINT_PENDING); break; case "RATING": query.eq(Acceptance::getStatus, StatusConstants.Acceptance.RATING_PENDING); break; case "COMPLETED": query.eq(Acceptance::getStatus, StatusConstants.Acceptance.COMPLETED); break; default: break; } } query.orderByDesc(Acceptance::getUpdateTime); return acceptanceMapper.selectList(query); } public Map acceptanceDetail(Long id) { Acceptance acceptance = acceptanceMapper.selectById(id); if (acceptance == null) { throw new BusinessException("验收记录不存在"); } WorkOrder workOrder = requireWorkOrder(acceptance.getWorkOrderId()); CompletionInfo completion = completionInfoMapper.selectOne(Wrappers.lambdaQuery() .eq(CompletionInfo::getWorkOrderId, workOrder.getId()).last("LIMIT 1")); Map data = new LinkedHashMap<>(); data.put("acceptance", acceptance); data.put("workOrder", workOrder); data.put("completion", completion); return data; } @Transactional public void acceptanceAction(Requests.AcceptanceActionRequest request) { Acceptance acceptance = acceptanceMapper.selectById(request.getId()); if (acceptance == null) { throw new BusinessException("验收记录不存在"); } WorkOrder workOrder = requireWorkOrder(acceptance.getWorkOrderId()); if (!StatusConstants.Completion.COMPLETED.equals(workOrder.getCompletionStatus())) { throw new BusinessException("只有完工状态的派工单才能进入验收流程"); } LocalDateTime now = LocalDateTime.now(); String action = request.getAction(); if ("SUBMIT".equalsIgnoreCase(action)) { requireAcceptance(acceptance, StatusConstants.Acceptance.APPLICATION_PENDING, StatusConstants.Acceptance.RETURNED_APPLICATION); acceptance.setStage("QUALITY_INSPECTOR"); acceptance.setStatus(StatusConstants.Acceptance.QUALITY_INSPECTOR_PENDING); acceptance.setApplyTime(now); acceptance.setApplyRemark(request.getOpinion()); } else if ("PASS".equalsIgnoreCase(action)) { if (StatusConstants.Acceptance.QUALITY_INSPECTOR_PENDING.equals(acceptance.getStatus()) || StatusConstants.Acceptance.RETURNED_INSPECTOR.equals(acceptance.getStatus())) { acceptance.setInspectorResult("通过"); acceptance.setInspectorOpinion(request.getOpinion()); acceptance.setInspectorTime(now); acceptance.setStage("QUALITY_LEADER"); acceptance.setStatus(StatusConstants.Acceptance.QUALITY_LEADER_PENDING); } else if (StatusConstants.Acceptance.QUALITY_LEADER_PENDING.equals(acceptance.getStatus())) { acceptance.setLeaderResult("通过"); acceptance.setLeaderOpinion(request.getOpinion()); acceptance.setLeaderTime(now); acceptance.setStage("PRINT"); acceptance.setStatus(StatusConstants.Acceptance.PRINT_PENDING); } else { throw new BusinessException("当前验收状态不允许通过"); } } else if ("REJECT".equalsIgnoreCase(action)) { if (StatusConstants.Acceptance.QUALITY_INSPECTOR_PENDING.equals(acceptance.getStatus())) { acceptance.setInspectorResult("打回"); acceptance.setInspectorOpinion(request.getOpinion()); acceptance.setInspectorTime(now); acceptance.setStage("APPLICATION"); acceptance.setStatus(StatusConstants.Acceptance.RETURNED_APPLICATION); } else if (StatusConstants.Acceptance.QUALITY_LEADER_PENDING.equals(acceptance.getStatus())) { acceptance.setLeaderResult("打回"); acceptance.setLeaderOpinion(request.getOpinion()); acceptance.setLeaderTime(now); acceptance.setStage("QUALITY_INSPECTOR"); acceptance.setStatus(StatusConstants.Acceptance.RETURNED_INSPECTOR); } else { throw new BusinessException("当前验收状态不允许打回"); } } else if ("PRINT".equalsIgnoreCase(action)) { requireAcceptance(acceptance, StatusConstants.Acceptance.PRINT_PENDING); acceptance.setPrintTime(now); acceptance.setStage("RATING"); acceptance.setStatus(StatusConstants.Acceptance.RATING_PENDING); } else if ("RATING".equalsIgnoreCase(action)) { requireAcceptance(acceptance, StatusConstants.Acceptance.RATING_PENDING); if (!StringUtils.hasText(request.getRating())) { throw new BusinessException("请选择修后质量评级"); } acceptance.setRating(request.getRating()); acceptance.setRatingRemark(request.getRatingRemark()); acceptance.setRatingTime(now); acceptance.setStage("COMPLETED"); acceptance.setStatus(StatusConstants.Acceptance.COMPLETED); } else { throw new BusinessException("未知验收动作"); } acceptance.setUpdateTime(now); acceptanceMapper.updateById(acceptance); } /** * The 处理解决情况 field is a repeatable list; the legacy SOLUTION column keeps a joined copy. */ private String joinSolutions(Requests.CompletionRequest request) { List items = request.getSolutions(); if (items == null || items.isEmpty()) { return request.getSolution(); } String joined = items.stream() .filter(item -> item != null && StringUtils.hasText(item.getContent())) .map(item -> item.getContent().trim()) .collect(Collectors.joining("\uFF1B")); return joined.length() > 2000 ? joined.substring(0, 2000) : joined; } private int materialQuantity(List materials) { if (materials == null || materials.isEmpty()) { return 0; } return materials.stream() .filter(item -> item != null && item.getQuantity() != null) .mapToInt(Requests.MaterialItem::getQuantity) .sum(); } private Fault requireFault(Long id) { Fault fault = faultMapper.selectById(id); if (fault == null) { throw new BusinessException("故障不存在"); } return fault; } private WorkOrder requireWorkOrder(Long id) { WorkOrder workOrder = workOrderMapper.selectById(id); if (workOrder == null) { throw new BusinessException("派工单不存在"); } return workOrder; } private void requireStatus(Fault fault, String status, String action) { if (!status.equals(fault.getTaskStatus())) { throw new BusinessException("故障 " + fault.getFaultCode() + " 当前状态不能执行" + action); } } private void requireAcceptance(Acceptance acceptance, String... statuses) { if (!Arrays.asList(statuses).contains(acceptance.getStatus())) { throw new BusinessException("当前验收状态不允许该操作"); } } private boolean canEdit(Fault fault) { return StatusConstants.Task.UNREPORTED.equals(fault.getTaskStatus()) || StatusConstants.Task.REPORTED_XCB.equals(fault.getTaskStatus()) || StatusConstants.Task.RETURNED.equals(fault.getTaskStatus()); } private void normalizeParentSystemSeparators(Fault fault) { if (StringUtils.hasText(fault.getParentSystem())) { fault.setParentSystem(fault.getParentSystem().replace(";", "、").replace(";", "、")); } } private void normalizeEquipmentIds(Fault fault) { Set ids = new LinkedHashSet<>(parseIds(fault.getEquipmentIds())); if (fault.getEquipmentId() != null) { ids.add(fault.getEquipmentId()); } if (ids.isEmpty()) { throw new BusinessException("请选择装备名称"); } List normalized = new ArrayList<>(ids); fault.setEquipmentIds(normalized.stream().map(String::valueOf).collect(Collectors.joining(","))); fault.setEquipmentId(normalized.get(0)); } private List parseIds(String text) { if (!StringUtils.hasText(text)) { return Collections.emptyList(); } return Arrays.stream(text.split(",")) .filter(StringUtils::hasText) .map(Long::valueOf) .collect(Collectors.toList()); } private WorkOrder workOrderFromFault(Fault fault) { WorkOrder workOrder = new WorkOrder(); workOrder.setFaultId(fault.getId()); workOrder.setFaultCode(fault.getFaultCode()); workOrder.setXNo(fault.getXNo()); workOrder.setEquipmentName(fault.getEquipmentName()); workOrder.setEngineeringMajor(fault.getEngineeringMajor()); workOrder.setTeamMajor(fault.getTeamMajor()); workOrder.setParentSystem(fault.getParentSystem()); workOrder.setReportUnit(fault.getReportUnit()); workOrder.setReportDate(fault.getReportDate()); workOrder.setReviewTime(fault.getXcbReviewTime()); workOrder.setOwner(fault.getOwner()); workOrder.setRequestedFinishDate(fault.getRequestedFinishDate()); workOrder.setEngineeringNameDesc(fault.getEngineeringNameDesc()); workOrder.setRepairRequirement(fault.getRepairRequirement()); workOrder.setFaultImpact(fault.getFaultImpact()); workOrder.setFaultNature(fault.getFaultNature()); workOrder.setIsSelfRepair(fault.getIsSelfRepair()); workOrder.setIsHRelated(fault.getIsHRelated()); workOrder.setIsMonitorItem(fault.getIsMonitorItem()); workOrder.setMonitorItem(fault.getMonitorItem()); workOrder.setMonitorValue(fault.getMonitorValue()); workOrder.setRemark(fault.getRemark()); return workOrder; } private String buildEngineeringNo(Fault fault, int index) { String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd")); return "LX-" + fault.getXNo() + "-" + date + "-" + String.format("%03d", index); } }