From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master

---
 jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/print/HuanjingChenjiangjunRenderer.java |  426 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 426 insertions(+), 0 deletions(-)

diff --git a/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/print/HuanjingChenjiangjunRenderer.java b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/print/HuanjingChenjiangjunRenderer.java
new file mode 100644
index 0000000..873d9d7
--- /dev/null
+++ b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/print/HuanjingChenjiangjunRenderer.java
@@ -0,0 +1,426 @@
+package jnpf.limsService.print;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import jnpf.exception.DataException;
+import jnpf.limsEntity.LimsHuanjingJianceBaogaoEntity;
+import jnpf.limsEntity.LimsHuanjingJianceBaogaoZixiangEntity;
+import jnpf.limsEntity.LimsHuanjingJianceBiaozhunEntity;
+import jnpf.limsEntity.LimsHuanjingJianceYijuEntity;
+import jnpf.limsEntity.LimsHuanjingQuyuEntity;
+import jnpf.limsEntity.LimsPrintTemplateEntity;
+import jnpf.limsMapper.LimsHuanjingJianceBaogaoMapper;
+import jnpf.limsMapper.LimsHuanjingJianceBaogaoZixiangMapper;
+import jnpf.limsMapper.LimsHuanjingJianceBiaozhunMapper;
+import jnpf.limsMapper.LimsHuanjingJianceYijuMapper;
+import jnpf.limsMapper.LimsHuanjingQuyuMapper;
+import jnpf.permission.UserApi;
+import jnpf.permission.entity.UserEntity;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * "娌夐檷鑿屾娴嬫姤鍛�"妯℃澘娓叉煋鍣紙template_id = huanjing_chenjiangjun锛夈��
+ *
+ * <p>杈撳叆锛歭ims_huanjing_jiance_baogao.f_id锛涘瓙椤规潵鑷�
+ * lims_huanjing_jiance_baogao_zixiang.f_foreign_id銆�
+ */
+@Component
+public class HuanjingChenjiangjunRenderer implements PrintTemplateRenderer {
+
+    public static final String TEMPLATE_ID = "huanjing_chenjiangjun";
+
+    private static final String DEFAULT_COMPANY_NAME = "鍗庨亾锛堜笂娴凤級鐢熺墿鍖昏嵂鏈夐檺鍏徃";
+    private static final String DEFAULT_DOC_NUMBER = "SOP-MBC-A017-TO-R01-01";
+    private static final String DEFAULT_REVIEW_CYCLE = "3骞�";
+    private static final String DEFAULT_METHOD_TEXT = "SOP-MBC-A017-TO 銆婃矇闄嶈弻妫�娴嬫爣鍑嗘搷浣滆绋嬨��";
+
+    @Autowired
+    private LimsHuanjingJianceBaogaoMapper baogaoMapper;
+
+    @Autowired
+    private LimsHuanjingJianceBaogaoZixiangMapper zixiangMapper;
+
+    @Autowired
+    private LimsHuanjingJianceBiaozhunMapper biaozhunMapper;
+
+    @Autowired
+    private LimsHuanjingJianceYijuMapper yijuMapper;
+
+    @Autowired
+    private LimsHuanjingQuyuMapper quyuMapper;
+
+    @Autowired
+    private UserApi usersApi;
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Override
+    public String getTemplateId() {
+        return TEMPLATE_ID;
+    }
+
+    @Override
+    public Map<String, Object> render(String baogaoId, LimsPrintTemplateEntity tpl) {
+        if (baogaoId == null || baogaoId.isEmpty()) {
+            throw new DataException("缂哄皯鐜鐩戞祴鎶ュ憡 id");
+        }
+
+        Map<String, Object> baogao = getBaogaoMap(baogaoId);
+        if (baogao.isEmpty()) {
+            throw new DataException("鐜鐩戞祴鎶ュ憡涓嶅瓨鍦ㄦ垨宸插垹闄�: " + baogaoId);
+        }
+
+        Map<String, Object> cfg = parseConfig(tpl);
+        List<Map<String, Object>> items = buildItems(baogaoId);
+        Map<String, String> userNames = fetchUserNames(baogao);
+
+        Map<String, Object> data = new LinkedHashMap<>();
+        data.put("template_id", tpl.getTemplateId());
+        data.put("template_name", tpl.getTemplateName());
+        data.put("companyName", asString(cfg.get("company_name"), DEFAULT_COMPANY_NAME));
+        data.put("docNumber", asString(cfg.get("doc_number"), DEFAULT_DOC_NUMBER));
+        data.put("reviewCycle", asString(cfg.get("review_cycle"), DEFAULT_REVIEW_CYCLE));
+        data.put("distributionDepartment", asString(cfg.get("distribution_department")));
+        data.put("effectiveDate", formatDate(getAny(baogao, "fuhe_riqi")));
+        data.put("methodText", resolveMethodText(baogao, cfg));
+        data.put("header", buildHeader(baogao));
+        data.put("items", items);
+        data.put("standardRows", buildStandardRows(cfg));
+        data.put("jielun", normalizeConclusion(asString(getAny(baogao, "jielun"))));
+        data.put("signatures", buildSignatures(baogao, userNames));
+        data.put("beizhu", asString(getAny(baogao, "beizhu"), asString(cfg.get("beizhu"))));
+        return data;
+    }
+
+    private Map<String, Object> getBaogaoMap(String baogaoId) {
+        QueryWrapper<LimsHuanjingJianceBaogaoEntity> wrapper = new QueryWrapper<>();
+        wrapper.eq("f_id", baogaoId);
+        wrapper.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1));
+        List<Map<String, Object>> rows = baogaoMapper.selectMaps(wrapper);
+        return rows.isEmpty() ? Collections.emptyMap() : new LinkedHashMap<>(rows.get(0));
+    }
+
+    private List<Map<String, Object>> buildItems(String baogaoId) {
+        QueryWrapper<LimsHuanjingJianceBaogaoZixiangEntity> wrapper = new QueryWrapper<>();
+        wrapper.eq("f_foreign_id", baogaoId);
+        wrapper.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1));
+        wrapper.orderByAsc("weizhi_bianhao", "quyangdian_mingcheng", "f_id");
+
+        List<Map<String, Object>> items = new ArrayList<>();
+        for (Map<String, Object> row : zixiangMapper.selectMaps(wrapper)) {
+            Map<String, Object> item = new LinkedHashMap<>();
+            item.put("weizhi_bianhao", asString(getAny(row, "weizhi_bianhao")));
+            item.put("weizhi_mingcheng", asString(getAny(row, "weizhi_mingcheng")));
+            item.put("quyangdian_mingcheng", asString(getAny(row, "quyangdian_mingcheng")));
+            item.put("ceshi_jieguo", asString(getAny(row, "ceshi_jieguo")));
+            item.put("shifou_hege", normalizeYesNo(asString(getAny(row, "shifou_hege"))));
+            items.add(item);
+        }
+        return items;
+    }
+
+    private Map<String, Object> buildHeader(Map<String, Object> row) {
+        Map<String, Object> h = new LinkedHashMap<>();
+        String quyuId = asString(getAny(row, "jiance_quyu"));
+        h.put("jiance_quyu", quyuId);
+        h.put("jiance_quyu_name", resolveQuyuName(quyuId));
+        h.put("jiance_riqi", formatDate(getAny(row, "jiance_riqi")));
+        h.put("jiance_zhuangtai", asString(getAny(row, "jiance_zhuangtai")));
+        h.put("qizhi_shijian", asString(getAny(row, "qizhi_shijian")));
+        h.put("peiyangji_pihao", asString(getAny(row, "peiyangji_pihao")));
+        h.put("peiyangji_youxiaoqi", formatDate(getAny(row, "peiyangji_youxiaoqi")));
+        h.put("peiyang_shebei_biaohao", asString(getAny(row, "peiyang_shebei_biaohao")));
+        h.put("jiaozhun_youxiaoqi", formatDate(getAny(row, "jiaozhun_youxiaoqi")));
+        h.put("peiyang_kaishi_shijian", formatDate(getAny(row, "peiyang_kaishi_shijian")));
+        h.put("peiyang_jieshu_shijian", formatDate(getAny(row, "peiyang_jieshu_shijian")));
+        h.put("jiejing_jibie", formatLevel(asString(getAny(row, "jiejing_jibie"))));
+        h.put("biaozhun_guiding", asString(getAny(row, "biaozhun_guiding")));
+        h.put("moren_danwei", asString(getAny(row, "moren_danwei")));
+        h.put("beizhu", asString(getAny(row, "beizhu")));
+        return h;
+    }
+
+    private String resolveMethodText(Map<String, Object> baogao, Map<String, Object> cfg) {
+        String biaozhunIdOrCode = asString(getAny(baogao, "biaozhun_guiding"));
+        Map<String, Object> biaozhun = findBiaozhun(biaozhunIdOrCode);
+        if (biaozhun.isEmpty()) {
+            return asString(cfg.get("method_text"), DEFAULT_METHOD_TEXT);
+        }
+
+        String biaozhunGuiding = asString(getAny(biaozhun, "biaozhun_guiding"));
+        String yijuIdOrText = asString(getAny(biaozhun, "jiance_yiju"));
+        String jianceYiju = findJianceYiju(yijuIdOrText);
+
+        if (!biaozhunGuiding.isEmpty() && !jianceYiju.isEmpty()) {
+            return biaozhunGuiding + " " + jianceYiju;
+        }
+        if (!biaozhunGuiding.isEmpty()) {
+            return biaozhunGuiding;
+        }
+        if (!jianceYiju.isEmpty()) {
+            return jianceYiju;
+        }
+        return asString(cfg.get("method_text"), DEFAULT_METHOD_TEXT);
+    }
+
+    private Map<String, Object> findBiaozhun(String biaozhunIdOrCode) {
+        if (biaozhunIdOrCode == null || biaozhunIdOrCode.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        QueryWrapper<LimsHuanjingJianceBiaozhunEntity> byGuiding = new QueryWrapper<>();
+        byGuiding.eq("biaozhun_guiding", biaozhunIdOrCode);
+        byGuiding.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1));
+        List<Map<String, Object>> rows = biaozhunMapper.selectMaps(byGuiding);
+        if (!rows.isEmpty()) {
+            return new LinkedHashMap<>(rows.get(0));
+        }
+
+        QueryWrapper<LimsHuanjingJianceBiaozhunEntity> byId = new QueryWrapper<>();
+        byId.eq("f_id", biaozhunIdOrCode);
+        byId.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1));
+        rows = biaozhunMapper.selectMaps(byId);
+        return rows.isEmpty() ? Collections.emptyMap() : new LinkedHashMap<>(rows.get(0));
+    }
+
+    private String findJianceYiju(String yijuIdOrText) {
+        if (yijuIdOrText == null || yijuIdOrText.isEmpty()) {
+            return "";
+        }
+
+        QueryWrapper<LimsHuanjingJianceYijuEntity> byId = new QueryWrapper<>();
+        byId.eq("f_id", yijuIdOrText);
+        byId.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1));
+        List<LimsHuanjingJianceYijuEntity> rows = yijuMapper.selectList(byId);
+        if (!rows.isEmpty() && rows.get(0).getJianceYiju() != null) {
+            return rows.get(0).getJianceYiju();
+        }
+
+        QueryWrapper<LimsHuanjingJianceYijuEntity> byText = new QueryWrapper<>();
+        byText.eq("jiance_yiju", yijuIdOrText);
+        byText.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1));
+        rows = yijuMapper.selectList(byText);
+        if (rows.isEmpty() || rows.get(0).getJianceYiju() == null) {
+            return yijuIdOrText;
+        }
+        return rows.get(0).getJianceYiju();
+    }
+
+    private String resolveQuyuName(String quyuId) {
+        if (quyuId == null || quyuId.isEmpty()) {
+            return "";
+        }
+        QueryWrapper<LimsHuanjingQuyuEntity> wrapper = new QueryWrapper<>();
+        wrapper.eq("f_id", quyuId);
+        wrapper.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1));
+        List<LimsHuanjingQuyuEntity> list = quyuMapper.selectList(wrapper);
+        if (list.isEmpty() || list.get(0).getJianceQuyu() == null) {
+            return quyuId;
+        }
+        return list.get(0).getJianceQuyu();
+    }
+
+    @SuppressWarnings("unchecked")
+    private List<Map<String, Object>> buildStandardRows(Map<String, Object> cfg) {
+        Object rows = cfg.get("standard_rows");
+        if (rows instanceof List) {
+            return (List<Map<String, Object>>) rows;
+        }
+
+        List<Map<String, Object>> result = new ArrayList<>();
+        result.add(standardRow("A绾�", "<1", "<1"));
+        result.add(standardRow("B绾�", "3", "5"));
+        result.add(standardRow("C绾�", "10", "50"));
+        result.add(standardRow("D绾�", "50", "100"));
+        return result;
+    }
+
+    private Map<String, Object> standardRow(String level, String staticLimit, String dynamicLimit) {
+        Map<String, Object> row = new LinkedHashMap<>();
+        row.put("level", level);
+        row.put("static_limit", staticLimit);
+        row.put("dynamic_limit", dynamicLimit);
+        return row;
+    }
+
+    private Map<String, Object> buildSignatures(Map<String, Object> row, Map<String, String> userNames) {
+        Map<String, Object> sig = new LinkedHashMap<>();
+        sig.put("operator", makeSignature(
+                asString(getAny(row, "jiance_ren")),
+                formatDate(getAny(row, "jiance_riqi")),
+                userNames));
+        sig.put("recorder", makeSignature(
+                asString(getAny(row, "jiance_ren")),
+                formatDate(getAny(row, "jiance_riqi")),
+                userNames));
+        sig.put("reviewer", makeSignature(
+                asString(getAny(row, "fuhe_ren")),
+                formatDate(getAny(row, "fuhe_riqi")),
+                userNames));
+        return sig;
+    }
+
+    private Map<String, Object> makeSignature(String userId, String date, Map<String, String> userNames) {
+        Map<String, Object> m = new LinkedHashMap<>();
+        m.put("user_id", userId);
+        m.put("name", userId == null ? "" : asString(userNames.get(userId)));
+        m.put("date", date);
+        return m;
+    }
+
+    private Map<String, String> fetchUserNames(Map<String, Object> row) {
+        List<String> userIds = Arrays.asList(
+                        asString(getAny(row, "jiance_ren")),
+                        asString(getAny(row, "quyang_ren")),
+                        asString(getAny(row, "fuhe_ren")))
+                .stream()
+                .filter(s -> s != null && !s.isEmpty())
+                .distinct()
+                .collect(Collectors.toList());
+        if (userIds.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        Map<String, String> idToRealName = new HashMap<>();
+        List<UserEntity> users = usersApi.getUserName(userIds);
+        if (users != null) {
+            for (UserEntity u : users) {
+                if (u != null && u.getId() != null) {
+                    idToRealName.put(u.getId(), u.getRealName());
+                }
+            }
+        }
+        return idToRealName;
+    }
+
+    private Map<String, Object> parseConfig(LimsPrintTemplateEntity tpl) {
+        String json = tpl.getConfig();
+        if (json == null || json.isEmpty()) {
+            return Collections.emptyMap();
+        }
+        try {
+            return objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
+        } catch (Exception e) {
+            throw new DataException("鎵撳嵃妯℃澘 config JSON 瑙f瀽澶辫触: " + e.getMessage());
+        }
+    }
+
+    private static Object getAny(Map<String, Object> row, String key) {
+        if (row == null || row.isEmpty()) {
+            return null;
+        }
+        if (row.containsKey(key)) {
+            return row.get(key);
+        }
+        String lowerKey = normalizeKey(key);
+        for (Map.Entry<String, Object> e : row.entrySet()) {
+            if (e.getKey() != null && normalizeKey(e.getKey()).equals(lowerKey)) {
+                return e.getValue();
+            }
+        }
+        return null;
+    }
+
+    private static String normalizeKey(String key) {
+        return key == null ? "" : key.replace("_", "").toLowerCase();
+    }
+
+    private static String formatDate(Object value) {
+        return format(value, "yyyy-MM-dd");
+    }
+
+    private static String formatDateTime(Object value) {
+        return format(value, "yyyy-MM-dd");
+    }
+
+    private static String format(Object value, String pattern) {
+        if (value == null) {
+            return "";
+        }
+        if (value instanceof Date) {
+            return new SimpleDateFormat(pattern).format((Date) value);
+        }
+        String text = value.toString();
+        if ("yyyy-MM-dd".equals(pattern) && text.matches("^\\d{4}-\\d{2}-\\d{2}.*")) {
+            return text.substring(0, 10);
+        }
+        return text;
+    }
+
+    private static String formatLevel(String level) {
+        if (level == null || level.isEmpty()) {
+            return "";
+        }
+        String lower = level.toLowerCase();
+        if (Arrays.asList("a", "b", "c", "d").contains(lower)) {
+            return lower.toUpperCase() + "绾�";
+        }
+        return level;
+    }
+
+    private static String normalizeConclusion(String value) {
+        if ("compliant".equalsIgnoreCase(value)
+                || "qualified".equalsIgnoreCase(value)
+                || "fuheguiding".equalsIgnoreCase(value)
+                || "yes".equalsIgnoreCase(value)
+                || "鍚堟牸".equals(value)
+                || "绗﹀悎瑙勫畾".equals(value)) {
+            return "yes";
+        }
+        if ("non_compliant".equalsIgnoreCase(value)
+                || "uncompliant".equalsIgnoreCase(value)
+                || "unqualified".equalsIgnoreCase(value)
+                || "bufuheguiding".equalsIgnoreCase(value)
+                || "no".equalsIgnoreCase(value)
+                || "涓嶅悎鏍�".equals(value)
+                || "涓嶇鍚堣瀹�".equals(value)) {
+            return "no";
+        }
+        return value;
+    }
+
+    private static String normalizeYesNo(String value) {
+        if ("yes".equalsIgnoreCase(value)
+                || "true".equalsIgnoreCase(value)
+                || "1".equals(value)
+                || "鏄�".equals(value)
+                || "鍚堟牸".equals(value)) {
+            return "yes";
+        }
+        if ("no".equalsIgnoreCase(value)
+                || "false".equalsIgnoreCase(value)
+                || "0".equals(value)
+                || "鍚�".equals(value)
+                || "涓嶅悎鏍�".equals(value)) {
+            return "no";
+        }
+        return value;
+    }
+
+    private static String asString(Object v) {
+        if (v instanceof BigDecimal) {
+            return ((BigDecimal) v).stripTrailingZeros().toPlainString();
+        }
+        return v == null ? "" : v.toString();
+    }
+
+    private static String asString(Object v, String fallback) {
+        String s = asString(v);
+        return s.isEmpty() ? fallback : s;
+    }
+}

--
Gitblit v1.8.0