| | |
| | | import com.ruoyi.inspect.util.ReportSignaturePictureUtils; |
| | | import com.ruoyi.inspect.vo.InsOrderPlanTaskSwitchVo; |
| | | import com.ruoyi.inspect.vo.InsOrderPlanVO; |
| | | import com.ruoyi.inspect.vo.QualityMonitorRawContext; |
| | | import com.ruoyi.inspect.vo.InsSampleUserVO; |
| | | import com.ruoyi.performance.mapper.AuxiliaryOutputWorkingHoursMapper; |
| | | import com.ruoyi.performance.pojo.AuxiliaryOutputWorkingHours; |
| | |
| | | if (Objects.isNull(entity)) { |
| | | return false; |
| | | } |
| | | InsOrder claimOrder = insOrderMapper.selectById(entity.getInsSampleId()); |
| | | if (claimOrder != null && "QUALITY_MONITOR".equals(claimOrder.getTaskSource())) { |
| | | throw new ErrorException("质量监控任务由计划指定检测员,不能认领"); |
| | | } |
| | | Integer userId = SecurityUtils.getUserId().intValue(); |
| | | InsSampleUser insSampleUser = new InsSampleUser(entity.getInsSampleId().intValue(), userId, 0, entity.getSonLaboratory()); |
| | | return insSampleUserMapper.insert(insSampleUser) > 0; |
| | |
| | | "模板ID " + snapshot.getTemplateId()); |
| | | if (snapshot.getDetectionTime() == null) { |
| | | collect.add("请选择“" + templateName + "”的检测时间"); |
| | | } else if (snapshot.getDetectionEndTime() != null |
| | | && snapshot.getDetectionEndTime().isBefore(snapshot.getDetectionTime())) { |
| | | collect.add("“" + templateName + "”的检测结束日期不能早于开始日期"); |
| | | } |
| | | if (StringUtils.isBlank(snapshot.getDetectionPlace())) { |
| | | collect.add("请填写“" + templateName + "”的检测地点"); |
| | |
| | | public void saveTemplateContext(SaveTemplateContextDto dto) { |
| | | if (dto.getOrderId() == null || dto.getSampleId() == null || dto.getTemplateId() == null) { |
| | | throw new ErrorException("订单、样品和模板不能为空"); |
| | | } |
| | | InsOrder sourceOrder = insOrderMapper.selectById(dto.getOrderId()); |
| | | if (sourceOrder != null && "QUALITY_MONITOR".equals(sourceOrder.getTaskSource()) |
| | | && !Objects.equals(sourceOrder.getState(), 1)) { |
| | | throw new ErrorException("已取消的质量监控任务不能填写原始记录"); |
| | | } |
| | | if (sourceOrder != null && "QUALITY_MONITOR".equals(sourceOrder.getTaskSource()) |
| | | && !Objects.equals(SecurityUtils.getUserId().intValue(), |
| | | insOrderMapper.selectQualityMonitorInspectorId(dto.getOrderId()))) { |
| | | throw new ErrorException("只有计划指定的检测员可以填写质量监控原始记录"); |
| | | } |
| | | InsSample sample = insSampleMapper.selectById(dto.getSampleId()); |
| | | if (sample == null || !Objects.equals(sample.getInsOrderId(), dto.getOrderId())) { |
| | |
| | | //交接 |
| | | @Override |
| | | public int upPlanUser(Integer userId, Integer orderId, String sonLaboratory) { |
| | | InsOrder handoffOrder = insOrderMapper.selectById(orderId); |
| | | if (handoffOrder != null && "QUALITY_MONITOR".equals(handoffOrder.getTaskSource())) { |
| | | throw new ErrorException("质量监控任务检测员由计划指定,不能直接交接"); |
| | | } |
| | | InsSampleUser insSampleUser = new InsSampleUser(); |
| | | insSampleUser.setUserId(userId); |
| | | insSampleUser.setInsSampleId(orderId); |
| | |
| | | InsOrder order = insOrderMapper.selectOne(Wrappers.<InsOrder>lambdaQuery() |
| | | .eq(InsOrder::getId, orderId) |
| | | .last("FOR UPDATE")); |
| | | if (order == null) throw new ErrorException("检验任务不存在"); |
| | | if ("QUALITY_MONITOR".equals(order.getTaskSource()) && !Objects.equals(order.getState(), 1)) { |
| | | throw new ErrorException("已取消的质量监控任务不能提交"); |
| | | } |
| | | if ("QUALITY_MONITOR".equals(order.getTaskSource()) |
| | | && (verifyUser == null || userMapper.selectById(verifyUser) == null)) { |
| | | throw new ErrorException("请选择质量监控任务复核人"); |
| | | } |
| | | if ("QUALITY_MONITOR".equals(order.getTaskSource()) |
| | | && Objects.equals(verifyUser, insOrderMapper.selectQualityMonitorInspectorId(orderId))) { |
| | | throw new ErrorException("检测员不能复核自己的质量监控原始记录"); |
| | | } |
| | | if ("QUALITY_MONITOR".equals(order.getTaskSource()) |
| | | && !Objects.equals(SecurityUtils.getUserId().intValue(), |
| | | insOrderMapper.selectQualityMonitorInspectorId(orderId))) { |
| | | throw new ErrorException("只有计划指定的检测员可以提交质量监控任务"); |
| | | } |
| | | boolean isInspectionReport = Objects.equals(INSPECTION_REPORT, reportType); |
| | | registerInsResults = isInspectionReport && Boolean.TRUE.equals(registerInsResults); |
| | | // 1. 委托编号全局唯一,提交复核时再次校验,防止并发或历史数据绕过生成校验。 |
| | |
| | | refreshed.setInsOrderId(orderId); |
| | | refreshed.setTemplateId(templateId); |
| | | refreshed.setNumber(standardTemplate == null ? oldSnapshot.getNumber() : standardTemplate.getNumber()); |
| | | refreshed.setStandardRequirement(oldSnapshot == null |
| | | ? standardTemplate.getStandardRequirement() : oldSnapshot.getStandardRequirement()); |
| | | refreshed.setName(standardTemplate == null ? oldSnapshot.getName() : standardTemplate.getName()); |
| | | refreshed.setRemark(standardTemplate == null ? oldSnapshot.getRemark() : standardTemplate.getRemark()); |
| | | refreshed.setThing(standardTemplate == null ? oldSnapshot.getThing() : standardTemplate.getThing()); |
| | | refreshed.setRecordValues(templateRecordValuesMap.get(templateId)); |
| | | refreshed.setDeviceDefaultsInitialized(oldSnapshot == null ? 0 |
| | | : oldSnapshot.getDeviceDefaultsInitialized()); |
| | | refreshed.setTemperature(templateTemperatureMap.get(templateId)); |
| | | refreshed.setHumidity(templateHumidityMap.get(templateId)); |
| | | // 刷新模板结构时必须保留检验阶段填写的业务数据,避免进入复核后回显为空。 |
| | | refreshed.setDetectionTime(oldSnapshot == null ? null : oldSnapshot.getDetectionTime()); |
| | | refreshed.setDetectionEndTime(oldSnapshot == null ? null : oldSnapshot.getDetectionEndTime()); |
| | | refreshed.setDetectionPlace(oldSnapshot == null ? null : oldSnapshot.getDetectionPlace()); |
| | | refreshed.setInsResult(oldSnapshot == null ? null : oldSnapshot.getInsResult()); |
| | | Integer templateSort = templateSortMap.get(templateId); |
| | |
| | | if (orderId == null || laboratory == null || type == null) { |
| | | throw new ErrorException("复核参数不完整"); |
| | | } |
| | | InsOrder verifyOrder = insOrderMapper.selectById(orderId); |
| | | if (verifyOrder == null) throw new ErrorException("检验任务不存在"); |
| | | if ("QUALITY_MONITOR".equals(verifyOrder.getTaskSource()) && !Objects.equals(verifyOrder.getState(), 1)) { |
| | | throw new ErrorException("已取消的质量监控任务不能复核"); |
| | | } |
| | | ensureDirectTemplateOrderState(orderId); |
| | | InsOrderState currentState = insOrderStateMapper.selectOne(Wrappers.<InsOrderState>lambdaQuery() |
| | | .eq(InsOrderState::getInsOrderId, orderId) |
| | | .eq(InsOrderState::getLaboratory, laboratory) |
| | | .last("limit 1")); |
| | | if ("QUALITY_MONITOR".equals(verifyOrder.getTaskSource()) |
| | | && (currentState == null || currentState.getVerifyUser() == null |
| | | || !Objects.equals(SecurityUtils.getUserId().intValue(), currentState.getVerifyUser()))) { |
| | | throw new ErrorException("只有提交时指定的复核人可以复核质量监控任务"); |
| | | } |
| | | if ("QUALITY_MONITOR".equals(verifyOrder.getTaskSource()) && Objects.equals(type, 1) |
| | | && currentState != null && Objects.equals(currentState.getInsState(), 5)) { |
| | | return 1; |
| | | } |
| | | InsReport existingReport = insReportMapper.selectOne(Wrappers.<InsReport>lambdaQuery() |
| | | .eq(InsReport::getInsOrderId, orderId) |
| | | .last("limit 1")); |
| | |
| | | insOrderMapper.update(null, Wrappers.<InsOrder>lambdaUpdate() |
| | | .eq(InsOrder::getId, orderId) |
| | | .set(InsOrder::getInsState, 5)); |
| | | |
| | | // 质量监控任务只保留原始记录,后续由质量监控评价完成归档。 |
| | | if ("QUALITY_MONITOR".equals(order.getTaskSource())) { |
| | | Integer evaluatorId = insOrderMapper.selectQualityMonitorEvaluatorId(orderId); |
| | | if (evaluatorId != null) { |
| | | InformationNotification notice = new InformationNotification(); |
| | | notice.setCreateUser(insProductMapper.selectUserById(SecurityUtils.getUserId().intValue()).get("name")); |
| | | notice.setSenderId(SecurityUtils.getUserId().intValue()); |
| | | notice.setConsigneeId(evaluatorId); |
| | | notice.setMessageType("2"); |
| | | notice.setTheme("质量监控评价通知"); |
| | | notice.setContent("质量监控任务 " + order.getEntrustCode() + " 的原始记录已复核,请填写评价记录"); |
| | | notice.setViewStatus(false); |
| | | notice.setJumpPath(MenuJumpPathConstants.QUALITY_MONITOR); |
| | | informationNotificationService.addInformationNotification(notice); |
| | | } |
| | | return 1; |
| | | } |
| | | |
| | | // 检验人员提交复核时不生成报告;全部试验室复核通过后生成报告。 |
| | | if (report == null || StringUtils.isBlank(report.getUrl())) { |
| | |
| | | * 兼容修复上线前已经下发、但因没有 ins_product 而缺少任务状态的直绑模板订单。 |
| | | */ |
| | | private void ensureDirectTemplateOrderState(Integer orderId) { |
| | | InsOrder order = insOrderMapper.selectById(orderId); |
| | | // 未下发的单还没进入检验任务,查看原始记录不能提前创建任务状态。 |
| | | if (order == null || order.getSendTime() == null) { |
| | | return; |
| | | } |
| | | if (!isDirectTemplateOrder(orderId)) { |
| | | return; |
| | | } |
| | |
| | | if (Objects.equals(report.getIsRatify(), 1)) { |
| | | throw new ErrorException("已批准报告不能重新生成"); |
| | | } |
| | | if (StringUtils.isNotBlank(report.getUrlS())) { |
| | | // urlS 同时用于人工上传和审核页面保存的 Word;只有人工上传需要先手动切回系统报告。 |
| | | if (StringUtils.isNotBlank(report.getUrlS()) && !isBrowserEditedReportUrl(report.getUrlS())) { |
| | | throw new ErrorException("当前报告已手动上传,请先还原为系统报告后再重新生成"); |
| | | } |
| | | if (report.getInsOrderId() == null) { |
| | |
| | | .eq(InsReport::getId, reportId) |
| | | .set(InsReport::getWriteTime, report.getWriteTime()) |
| | | .set(InsReport::getIsPass, report.getIsPass()) |
| | | .set(InsReport::getUrlS, null) |
| | | .set(InsReport::getTempUrlPdf, "/word/" + tempPdfName)); |
| | | } |
| | | |
| | | private static boolean isBrowserEditedReportUrl(String url) { |
| | | return url != null && url.matches("(?i)^/word/(?:edited|reviewed)-[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}\\.docx$"); |
| | | } |
| | | |
| | | private Map<String, Object> buildExistingReportMarks(InsReport report) { |
| | |
| | | * @param orderId |
| | | */ |
| | | private void generateReport(Integer orderId, Integer reportType, Integer writeUserId) { |
| | | InsOrder sourceOrder = insOrderMapper.selectById(orderId); |
| | | if (sourceOrder != null && "QUALITY_MONITOR".equals(sourceOrder.getTaskSource())) { |
| | | throw new ErrorException("质量监控检验任务不生成报告"); |
| | | } |
| | | /*样品下的项目只要有一个项目不合格则检验结果为0,否则为1*/ |
| | | //这里的insSamples是订单下的所有样品包括("/") |
| | | List<InsSample> insSamples = insSampleMapper.selectList(Wrappers.<InsSample>lambdaQuery().eq(InsSample::getInsOrderId, orderId)); |
| | |
| | | .eq(InsOrderStandardTemplate::getInsOrderId, orderId) |
| | | .orderByAsc(InsOrderStandardTemplate::getSort, InsOrderStandardTemplate::getId)); |
| | | List<LocalDate> detectionDates = templateSnapshots.stream() |
| | | .map(InsOrderStandardTemplate::getDetectionTime) |
| | | .flatMap(snapshot -> java.util.stream.Stream.of( |
| | | snapshot.getDetectionTime(), snapshot.getDetectionEndTime())) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toList()); |
| | | String insTime = formatReportTestDate(detectionDates); |
| | |
| | | List<Map<String, String>> finalDeviceList = deviceList; |
| | | String finalModelStr = modelStr; |
| | | |
| | | // 直绑模板订单没有 ins_product,检测项目、单位和结果均从订单模板快照中获取。 |
| | | // 直绑模板订单没有 ins_product,检测项目、标准要求值和结果均从订单模板快照中获取。 |
| | | List<Map<String, String>> detectionResultRows = directTemplateOrder |
| | | ? buildTemplateDetectionResultRows(orderId) |
| | | : buildDetectionResultRows(samples); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 新版检测报告的结果表固定为四列:序号、检测项目、单位、检测结果。 |
| | | * 新版检测、检验报告共用结果数据;标准要求值取自原始记录模板配置。 |
| | | */ |
| | | private List<Map<String, String>> buildDetectionResultRows(List<SampleProductDto> samples) { |
| | | List<Map<String, String>> rows = new ArrayList<>(); |
| | |
| | | } |
| | | |
| | | boolean multipleSamples = samples.size() > 1; |
| | | Map<Integer, String> requirementsByTemplate = new HashMap<>(); |
| | | int sequence = 1; |
| | | for (SampleProductDto sample : samples) { |
| | | if (CollectionUtils.isEmpty(sample.getInsProduct())) { |
| | |
| | | |
| | | Map<String, String> row = new LinkedHashMap<>(); |
| | | row.put("seq", String.valueOf(sequence++)); |
| | | row.put("itemName", itemName); |
| | | row.put("itemName", formatReportItemWithUnit(itemName, product.getUnit())); |
| | | row.put("unit", defaultReportText(product.getUnit(), "/")); |
| | | String requirement = product.getTemplateId() == null ? null |
| | | : requirementsByTemplate.computeIfAbsent(product.getTemplateId(), templateId -> { |
| | | StandardTemplate sourceTemplate = standardTemplateService.getById(templateId); |
| | | return defaultReportText(sourceTemplate == null ? null |
| | | : sourceTemplate.getStandardRequirement(), "/"); |
| | | }); |
| | | row.put("standardRequirement", defaultReportText(requirement, "/")); |
| | | row.put("result", defaultReportText(product.getLastValue(), "/")); |
| | | row.put("inspectionConclusion", formatInspectionConclusion(product.getInsResult())); |
| | | rows.add(row); |
| | |
| | | /** |
| | | * 新聚直绑模板订单:模板中每一个“导出值”批注都对应报告中的一条检测项目。 |
| | | */ |
| | | @Override |
| | | public List<Map<String, String>> getQualityMonitorRawResults(Integer orderId) { |
| | | requireReviewedQualityMonitorOrder(orderId); |
| | | return buildTemplateDetectionResultRows(orderId); |
| | | } |
| | | |
| | | @Override |
| | | public QualityMonitorRawContext getQualityMonitorRawContext(Integer orderId) { |
| | | requireReviewedQualityMonitorOrder(orderId); |
| | | QualityMonitorRawContext context = new QualityMonitorRawContext(); |
| | | List<InsOrderStandardTemplate> snapshots = insOrderStandardTemplateService.list( |
| | | Wrappers.<InsOrderStandardTemplate>lambdaQuery() |
| | | .eq(InsOrderStandardTemplate::getInsOrderId, orderId) |
| | | .orderByAsc(InsOrderStandardTemplate::getSort, InsOrderStandardTemplate::getId)); |
| | | context.setDetectionDates(snapshots.stream().flatMap(snapshot -> java.util.stream.Stream.of( |
| | | snapshot.getDetectionTime(), snapshot.getDetectionEndTime())) |
| | | .filter(Objects::nonNull).distinct().sorted().collect(Collectors.toList())); |
| | | List<Integer> deviceIds = insOrderTemplateDeviceMapper.selectDeviceIdsByOrderId(orderId); |
| | | if (CollectionUtils.isNotEmpty(deviceIds)) { |
| | | context.setDevices(insOrderMapper.selectDeviceListByIds(new LinkedHashSet<>(deviceIds))); |
| | | } |
| | | return context; |
| | | } |
| | | |
| | | private void requireReviewedQualityMonitorOrder(Integer orderId) { |
| | | InsOrder order = insOrderMapper.selectById(orderId); |
| | | if (order == null || !"QUALITY_MONITOR".equals(order.getTaskSource()) |
| | | || !Objects.equals(order.getInsState(), 5)) { |
| | | throw new ErrorException("质控任务原始记录复核通过后才能读取检测数据"); |
| | | } |
| | | Long pendingCount = insOrderStateMapper.selectCount(Wrappers.<InsOrderState>lambdaQuery() |
| | | .eq(InsOrderState::getInsOrderId, orderId).ne(InsOrderState::getInsState, 5)); |
| | | if (pendingCount > 0) throw new ErrorException("质控任务仍有未复核的原始记录"); |
| | | } |
| | | |
| | | private List<Map<String, String>> buildTemplateDetectionResultRows(Integer orderId) { |
| | | List<InsOrderStandardTemplate> snapshots = insOrderStandardTemplateService.list( |
| | | Wrappers.<InsOrderStandardTemplate>lambdaQuery() |
| | |
| | | List<Map<String, String>> rows = new ArrayList<>(); |
| | | int sequence = 1; |
| | | for (InsOrderStandardTemplate snapshot : snapshots) { |
| | | String standardRequirement = snapshot.getStandardRequirement(); |
| | | // 兼容新增该字段前下单的旧记录;有快照时始终以订单保存的值为准。 |
| | | if (StringUtils.isBlank(standardRequirement) && snapshot.getTemplateId() != null) { |
| | | StandardTemplate sourceTemplate = standardTemplateService.getById(snapshot.getTemplateId()); |
| | | standardRequirement = sourceTemplate == null ? null : sourceTemplate.getStandardRequirement(); |
| | | } |
| | | List<TemplateExportCell> exportCells = getTemplateExportCells(snapshot.getThing()); |
| | | JSONObject recordValues = StrUtil.isBlank(snapshot.getRecordValues()) |
| | | ? new JSONObject() : JSON.parseObject(snapshot.getRecordValues()); |
| | |
| | | row.put("seq", String.valueOf(sequence++)); |
| | | String reportItemName = defaultReportText(itemName, |
| | | defaultReportText(snapshot.getName(), "模板ID " + snapshot.getTemplateId())); |
| | | row.put("itemName", formatExportItemName(reportItemName)); |
| | | row.put("itemName", formatReportItemWithUnit( |
| | | formatExportItemName(reportItemName), unit)); |
| | | row.put("unit", defaultReportText(unit, "/")); |
| | | row.put("standardRequirement", defaultReportText(standardRequirement, "/")); |
| | | row.put("result", result); |
| | | row.put("inspectionConclusion", formatInspectionConclusion(snapshot.getInsResult())); |
| | | rows.add(row); |
| | |
| | | return itemName.replaceAll("平均值\\s*[,,]?\\s*", ""); |
| | | } |
| | | |
| | | private static String formatReportItemWithUnit(String itemName, String unit) { |
| | | if (StringUtils.isBlank(unit) || "/".equals(unit.trim()) |
| | | || itemName.contains(unit.trim())) { |
| | | return itemName; |
| | | } |
| | | return itemName + "," + unit.trim(); |
| | | } |
| | | |
| | | private static String getMapText(Map<String, String> map, String... keys) { |
| | | if (map == null) { |
| | | return null; |