From 56fe897d3e06bfa1e1105980d0044e6e67b2a484 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期五, 23 十月 2026 17:44:20 +0800
Subject: [PATCH] feat(report): 实现浏览器内报告DOCX编辑功能

---
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java |  163 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 157 insertions(+), 6 deletions(-)

diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
index 50d6ad8..797cc86 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
@@ -49,6 +49,7 @@
 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;
@@ -224,6 +225,10 @@
         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;
@@ -354,6 +359,9 @@
                         "妯℃澘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 + "鈥濈殑妫�娴嬪湴鐐�");
@@ -612,6 +620,16 @@
     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())) {
@@ -1027,6 +1045,10 @@
     //浜ゆ帴
     @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);
@@ -1211,6 +1233,23 @@
         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. 濮旀墭缂栧彿鍏ㄥ眬鍞竴锛屾彁浜ゅ鏍告椂鍐嶆鏍¢獙锛岄槻姝㈠苟鍙戞垨鍘嗗彶鏁版嵁缁曡繃鐢熸垚鏍¢獙銆�
@@ -1619,14 +1658,19 @@
             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);
@@ -1675,11 +1719,25 @@
         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"));
@@ -1738,6 +1796,24 @@
             insOrderMapper.update(null, Wrappers.<InsOrder>lambdaUpdate()
                     .eq(InsOrder::getId, orderId)
                     .set(InsOrder::getInsState, 5));
+
+            // 璐ㄩ噺鐩戞帶浠诲姟鍙繚鐣欏師濮嬭褰曪紝鍚庣画鐢辫川閲忕洃鎺ц瘎浠峰畬鎴愬綊妗c��
+            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())) {
@@ -1877,6 +1953,11 @@
      * 鍏煎淇涓婄嚎鍓嶅凡缁忎笅鍙戙�佷絾鍥犳病鏈� ins_product 鑰岀己灏戜换鍔$姸鎬佺殑鐩寸粦妯℃澘璁㈠崟銆�
      */
     private void ensureDirectTemplateOrderState(Integer orderId) {
+        InsOrder order = insOrderMapper.selectById(orderId);
+        // 鏈笅鍙戠殑鍗曡繕娌¤繘鍏ユ楠屼换鍔★紝鏌ョ湅鍘熷璁板綍涓嶈兘鎻愬墠鍒涘缓浠诲姟鐘舵�併��
+        if (order == null || order.getSendTime() == null) {
+            return;
+        }
         if (!isDirectTemplateOrder(orderId)) {
             return;
         }
@@ -1929,7 +2010,8 @@
         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) {
@@ -1973,7 +2055,12 @@
                 .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) {
@@ -2009,6 +2096,10 @@
      * @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*/
         //杩欓噷鐨刬nsSamples鏄鍗曚笅鐨勬墍鏈夋牱鍝佸寘鎷�("/")
         List<InsSample> insSamples = insSampleMapper.selectList(Wrappers.<InsSample>lambdaQuery().eq(InsSample::getInsOrderId, orderId));
@@ -3534,7 +3625,8 @@
                         .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);
@@ -3550,7 +3642,7 @@
         List<Map<String, String>> finalDeviceList = deviceList;
         String finalModelStr = modelStr;
 
-        // 鐩寸粦妯℃澘璁㈠崟娌℃湁 ins_product锛屾娴嬮」鐩�佸崟浣嶅拰缁撴灉鍧囦粠璁㈠崟妯℃澘蹇収涓幏鍙栥��
+        // 鐩寸粦妯℃澘璁㈠崟娌℃湁 ins_product锛屾娴嬮」鐩�佹爣鍑嗚姹傚�煎拰缁撴灉鍧囦粠璁㈠崟妯℃澘蹇収涓幏鍙栥��
         List<Map<String, String>> detectionResultRows = directTemplateOrder
                 ? buildTemplateDetectionResultRows(orderId)
                 : buildDetectionResultRows(samples);
@@ -3732,7 +3824,7 @@
     }
 
     /**
-     * 鏂扮増妫�娴嬫姤鍛婄殑缁撴灉琛ㄥ浐瀹氫负鍥涘垪锛氬簭鍙枫�佹娴嬮」鐩�佸崟浣嶃�佹娴嬬粨鏋溿��
+     * 鏂扮増妫�娴嬨�佹楠屾姤鍛婂叡鐢ㄧ粨鏋滄暟鎹紱鏍囧噯瑕佹眰鍊煎彇鑷師濮嬭褰曟ā鏉块厤缃��
      */
     private List<Map<String, String>> buildDetectionResultRows(List<SampleProductDto> samples) {
         List<Map<String, String>> rows = new ArrayList<>();
@@ -3741,6 +3833,7 @@
         }
 
         boolean multipleSamples = samples.size() > 1;
+        Map<Integer, String> requirementsByTemplate = new HashMap<>();
         int sequence = 1;
         for (SampleProductDto sample : samples) {
             if (CollectionUtils.isEmpty(sample.getInsProduct())) {
@@ -3761,8 +3854,15 @@
 
                 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);
@@ -3774,6 +3874,41 @@
     /**
      * 鏂拌仛鐩寸粦妯℃澘璁㈠崟锛氭ā鏉夸腑姣忎竴涓�滃鍑哄�尖�濇壒娉ㄩ兘瀵瑰簲鎶ュ憡涓殑涓�鏉℃娴嬮」鐩��
      */
+    @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()
@@ -3782,6 +3917,12 @@
         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());
@@ -3800,8 +3941,10 @@
                 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);
@@ -3977,6 +4120,14 @@
         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;

--
Gitblit v1.9.3