| | |
| | | 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.emergencyrepair.common.audit.CurrentUserContext; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.jdbc.core.JdbcTemplate; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.StringUtils; |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | | import java.util.Collection; |
| | | import java.util.Objects; |
| | | 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(); |
| | | @Value("${fault-code.prefix:\u6f5c1\u57fa-}") |
| | | private String faultCodePrefix; |
| | | private final FaultMapper faultMapper; |
| | | private final JdbcTemplate jdbcTemplate; |
| | | private final TeamMajorMapper teamMajorMapper; |
| | | private final WorkOrderMapper workOrderMapper; |
| | | private final ContractorMapper contractorMapper; |
| | | private final CompletionInfoMapper completionInfoMapper; |
| | | private final AcceptanceMapper acceptanceMapper; |
| | | private final ObjectMapper objectMapper; |
| | |
| | | private String generateFaultCode(Fault fault) { |
| | | String xNo = normalizeXNo(fault.getXNo()); |
| | | if (xNo == null) { |
| | | throw new BusinessException("请选择X号,格式为3位数字"); |
| | | throw new BusinessException("请选择rk_X号,格式为3位数字"); |
| | | } |
| | | if (!StringUtils.hasText(fault.getTeamMajor())) { |
| | | throw new BusinessException("请选择T队专业"); |
| | | throw new BusinessException("请选择rk_T队专业"); |
| | | } |
| | | TeamMajor teamMajor = teamMajorMapper.selectOne(Wrappers.<TeamMajor>lambdaQuery() |
| | | .eq(TeamMajor::getName, fault.getTeamMajor().trim()) |
| | | .last("LIMIT 1")); |
| | | if (teamMajor == null) { |
| | | throw new BusinessException("T队专业未配置,请先在系统管理 > T队专业配置中维护:" + fault.getTeamMajor()); |
| | | throw new BusinessException("rk_T队专业未配置,请先在系统管理 > rk_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()); |
| | | throw new BusinessException("rk_T队专业分类只能为A或B:" + fault.getTeamMajor()); |
| | | } |
| | | String prefix = FAULT_CODE_PREFIX + xNo + "/" + category + "-" + fault.getReportDate().format(FAULT_DATE_FORMAT) + "-"; |
| | | String prefix = faultCodePrefix + xNo + "/" + category + "-" + fault.getReportDate().format(FAULT_DATE_FORMAT) + "-"; |
| | | int next = 1; |
| | | for (Fault item : faultMapper.selectList(Wrappers.<Fault>lambdaQuery() |
| | | .likeRight(Fault::getFaultCode, prefix))) { |
| | | next = Math.max(next, parseFaultSequence(item.getFaultCode(), prefix) + 1); |
| | | // Include logically deleted rows so a generated code never collides with |
| | | // the unique index on FAULT_CODE. |
| | | List<String> existingCodes = jdbcTemplate.query( |
| | | "SELECT FAULT_CODE FROM LX.T_FAULT WHERE FAULT_CODE LIKE ?", |
| | | new Object[]{prefix + "%"}, (rs, rowNum) -> rs.getString(1)); |
| | | for (String existingCode : existingCodes) { |
| | | next = Math.max(next, parseFaultSequence(existingCode, prefix) + 1); |
| | | } |
| | | return prefix + String.format("%03d", next); |
| | | } |
| | |
| | | throw new BusinessException("请填写销项理由"); |
| | | } |
| | | String cancelledBy = StringUtils.hasText(request.getCancelledBy()) |
| | | ? request.getCancelledBy().trim() : "XCB助理"; |
| | | ? request.getCancelledBy().trim() : "rk_XCB助理"; |
| | | for (Long id : request.getIds()) { |
| | | Fault fault = requireFault(id); |
| | | if (!StatusConstants.Task.REPORTED_XCB.equals(fault.getTaskStatus()) |
| | |
| | | if (request.getContractorIds() == null || request.getContractorIds().isEmpty()) { |
| | | throw new BusinessException("至少分配一个承修单位"); |
| | | } |
| | | List<Contractor> contractors = contractorMapper.selectBatchIds(request.getContractorIds()); |
| | | Map<Long, Contractor> contractorMap = contractors.stream() |
| | | .collect(Collectors.toMap(Contractor::getId, Function.identity())); |
| | | Map<Long, String> contractorMap = contractorNamesByIds(request.getContractorIds()); |
| | | if (contractorMap.isEmpty()) { |
| | | throw new BusinessException("承修单位不存在或未在部门表中配置"); |
| | | } |
| | | 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) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.joining("、")); |
| | | |
| | | int index = 0; |
| | |
| | | Fault fault = requireFault(id); |
| | | if (!StatusConstants.Task.REPORTED_XCB.equals(fault.getTaskStatus()) |
| | | && !StatusConstants.Task.RETURNED.equals(fault.getTaskStatus())) { |
| | | throw new BusinessException("故障 " + fault.getFaultCode() + " 当前状态不允许XCB助理审核"); |
| | | throw new BusinessException("故障 " + fault.getFaultCode() + " 当前状态不允许rk_XCB助理审核"); |
| | | } |
| | | index++; |
| | | fault.setContractorIds(contractorIds); |
| | |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | switch (request.getStage()) { |
| | | case "CMB": |
| | | requireStatus(fault, StatusConstants.Task.XCB_REVIEWED, "CMB领导审批"); |
| | | requireStatus(fault, StatusConstants.Task.XCB_REVIEWED, "rk_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助理审批"); |
| | | requireStatus(fault, StatusConstants.Task.CMB_APPROVED, "rk_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处长审批"); |
| | | requireStatus(fault, StatusConstants.Task.JCC_ASSISTANT_APPROVED, "rk_JCC处长审批"); |
| | | fault.setJccDirectorOpinion(request.getOpinion()); |
| | | fault.setJccDirectorResult(pass ? "通过" : "不通过"); |
| | | fault.setJccDirectorTime(now); |
| | |
| | | if (exists > 0) { |
| | | throw new BusinessException("故障 " + fault.getFaultCode() + " 已经派单"); |
| | | } |
| | | List<Contractor> contractors = contractorMapper.selectBatchIds(contractorIds); |
| | | Map<Long, Contractor> contractorMap = contractors.stream() |
| | | .collect(Collectors.toMap(Contractor::getId, Function.identity())); |
| | | Map<Long, String> contractorMap = contractorNamesByIds(contractorIds); |
| | | int sequence = 1; |
| | | for (Long contractorId : contractorIds) { |
| | | Contractor contractor = contractorMap.get(contractorId); |
| | | if (contractor == null) { |
| | | String contractorName = contractorMap.get(contractorId); |
| | | if (contractorName == null) { |
| | | continue; |
| | | } |
| | | WorkOrder workOrder = workOrderFromFault(fault); |
| | | workOrder.setWorkOrderNo(fault.getFaultCode() + "/" + String.format("%02d", sequence++)); |
| | | workOrder.setContractorId(contractor.getId()); |
| | | workOrder.setContractorName(contractor.getName()); |
| | | workOrder.setContractorId(contractorId); |
| | | workOrder.setContractorName(contractorName); |
| | | workOrder.setCompletionStatus(StatusConstants.Completion.UNFINISHED); |
| | | workOrder.setDispatchTime(LocalDateTime.now()); |
| | | workOrder.setCreateTime(LocalDateTime.now()); |
| | |
| | | return created; |
| | | } |
| | | |
| | | public List<WorkOrder> listWorkOrders(String status, String keyword) { |
| | | public List<WorkOrder> listWorkOrders(String status, String keyword, boolean completionReportable) { |
| | | LambdaQueryWrapper<WorkOrder> query = Wrappers.lambdaQuery(); |
| | | if (StringUtils.hasText(status)) { |
| | | if (completionReportable) { |
| | | query.eq(WorkOrder::getCompletionStatus, StatusConstants.Completion.COMPLETED) |
| | | .notInSql(WorkOrder::getId, "SELECT WORK_ORDER_ID FROM LX.T_COMPLETION_INFO WHERE DEL_FLAG = 0 OR DEL_FLAG IS NULL"); |
| | | List<String> unitNames = currentUserContractorNames(); |
| | | if (unitNames != null) { |
| | | if (unitNames.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | query.in(WorkOrder::getContractorName, unitNames); |
| | | } |
| | | } else if (StringUtils.hasText(status)) { |
| | | query.in(WorkOrder::getCompletionStatus, Arrays.asList(status.split(","))); |
| | | } |
| | | if (StringUtils.hasText(keyword)) { |
| | |
| | | return workOrderMapper.selectList(query); |
| | | } |
| | | |
| | | /** |
| | | * Returns null when the current user sees every unit (system administrator). |
| | | * Otherwise returns the contractor names matching the logged-in user's department. |
| | | */ |
| | | private List<String> currentUserContractorNames() { |
| | | String username = CurrentUserContext.get(); |
| | | if (!StringUtils.hasText(username) || "admin".equalsIgnoreCase(username)) { |
| | | return null; |
| | | } |
| | | List<Map<String, Object>> rows = jdbcTemplate.query( |
| | | "SELECT d.DEPT_NAME, d.DEPT_TYPE FROM CSICZB_ZB.SYS_USER u " |
| | | + "LEFT JOIN CSICZB_ZB.SYS_DEPT d ON d.DEPT_ID = u.DEPT_ID " |
| | | + "WHERE u.USER_NAME = ? AND (u.DEL_FLAG = '0' OR u.DEL_FLAG IS NULL)", |
| | | new Object[]{username}, (rs, rowNum) -> { |
| | | Map<String, Object> row = new LinkedHashMap<>(); |
| | | row.put("deptName", rs.getString("DEPT_NAME")); |
| | | row.put("deptType", rs.getString("DEPT_TYPE")); |
| | | return row; |
| | | }); |
| | | if (rows.isEmpty() || !StringUtils.hasText((String) rows.get(0).get("deptName"))) { |
| | | return Collections.emptyList(); |
| | | } |
| | | Map<String, Object> dept = rows.get(0); |
| | | if (!"cj".equalsIgnoreCase(String.valueOf(dept.get("deptType")))) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return Collections.singletonList(((String) dept.get("deptName")).trim()); |
| | | } |
| | | |
| | | private Map<Long, String> contractorNamesByIds(Collection<Long> ids) { |
| | | Map<Long, String> result = new LinkedHashMap<>(); |
| | | if (ids == null || ids.isEmpty()) { |
| | | return result; |
| | | } |
| | | String placeholders = ids.stream().map(item -> "?").collect(Collectors.joining(",")); |
| | | List<Object> args = new ArrayList<>(ids); |
| | | return jdbcTemplate.query( |
| | | "SELECT DEPT_ID, DEPT_NAME FROM CSICZB_ZB.SYS_DEPT " |
| | | + "WHERE DEPT_TYPE = 'cj' AND (DEL_FLAG = '0' OR DEL_FLAG IS NULL) " |
| | | + "AND DEPT_ID IN (" + placeholders + ")", |
| | | args.toArray(), rs -> { |
| | | while (rs.next()) { |
| | | result.put(rs.getLong("DEPT_ID"), rs.getString("DEPT_NAME")); |
| | | } |
| | | return result; |
| | | }); |
| | | } |
| | | |
| | | 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())) { |
| | | if (StatusConstants.Completion.COMPLETED.equals(workOrder.getCompletionStatus()) |
| | | && !StatusConstants.Completion.COMPLETED.equals(request.getStatus())) { |
| | | throw new BusinessException("已完工派工单不能退回普通完工状态"); |
| | | } |
| | | if (!Arrays.asList( |
| | | StatusConstants.Completion.UNFINISHED, |
| | | StatusConstants.Completion.WAIT_PARTS, |
| | | StatusConstants.Completion.WAIT_TEST).contains(request.getStatus())) { |
| | | StatusConstants.Completion.WAIT_TEST, |
| | | StatusConstants.Completion.COMPLETED).contains(request.getStatus())) { |
| | | throw new BusinessException("完工状态不合法"); |
| | | } |
| | | workOrder.setCompletionStatus(request.getStatus()); |
| | |
| | | @Transactional |
| | | public CompletionInfo submitCompletion(Requests.CompletionRequest request) { |
| | | WorkOrder workOrder = requireWorkOrder(request.getWorkOrderId()); |
| | | if (StatusConstants.Completion.COMPLETED.equals(workOrder.getCompletionStatus())) { |
| | | CompletionInfo info = completionInfoMapper.selectOne(Wrappers.<CompletionInfo>lambdaQuery() |
| | | .eq(CompletionInfo::getWorkOrderId, workOrder.getId()).last("LIMIT 1")); |
| | | if (info != null) { |
| | | throw new BusinessException("该派工单已完工上报,不能重复提交"); |
| | | } |
| | | 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.<CompletionInfo>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()); |
| | |
| | | ids.add(fault.getEquipmentId()); |
| | | } |
| | | if (ids.isEmpty()) { |
| | | throw new BusinessException("请选择装备名称"); |
| | | throw new BusinessException("请选择设备名称"); |
| | | } |
| | | List<Long> normalized = new ArrayList<>(ids); |
| | | fault.setEquipmentIds(normalized.stream().map(String::valueOf).collect(Collectors.joining(","))); |