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_weishengwu)。 * *

输入:lims_huanjing_jiance_baogao.f_id;子项来自 * lims_huanjing_jiance_baogao_zixiang.f_foreign_id。 */ @Component public class HuanjingWeishengwuRenderer implements PrintTemplateRenderer { public static final String TEMPLATE_ID = "huanjing_weishengwu"; private static final String DEFAULT_COMPANY_NAME = "华道(上海)生物医药有限公司"; private static final String DEFAULT_DOC_NUMBER = "SOP-MBC-A020-TO-R01-02"; private static final String DEFAULT_REVIEW_CYCLE = "3年"; private static final String DEFAULT_METHOD_TEXT = "SOP-MBC-A020-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 render(String baogaoId, LimsPrintTemplateEntity tpl) { if (baogaoId == null || baogaoId.isEmpty()) { throw new DataException("缺少环境监测报告 id"); } Map baogao = getBaogaoMap(baogaoId); if (baogao.isEmpty()) { throw new DataException("环境监测报告不存在或已删除: " + baogaoId); } Map cfg = parseConfig(tpl); List> items = buildItems(baogaoId); Map userNames = fetchUserNames(baogao); Map 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 getBaogaoMap(String baogaoId) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("f_id", baogaoId); wrapper.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); List> rows = baogaoMapper.selectMaps(wrapper); return rows.isEmpty() ? Collections.emptyMap() : new LinkedHashMap<>(rows.get(0)); } private List> buildItems(String baogaoId) { QueryWrapper 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> items = new ArrayList<>(); for (Map row : zixiangMapper.selectMaps(wrapper)) { Map 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 buildHeader(Map row) { Map 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 baogao, Map cfg) { String biaozhunIdOrCode = asString(getAny(baogao, "biaozhun_guiding")); Map 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 findBiaozhun(String biaozhunIdOrCode) { if (biaozhunIdOrCode == null || biaozhunIdOrCode.isEmpty()) { return Collections.emptyMap(); } QueryWrapper byGuiding = new QueryWrapper<>(); byGuiding.eq("biaozhun_guiding", biaozhunIdOrCode); byGuiding.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); List> rows = biaozhunMapper.selectMaps(byGuiding); if (!rows.isEmpty()) { return new LinkedHashMap<>(rows.get(0)); } QueryWrapper 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 byId = new QueryWrapper<>(); byId.eq("f_id", yijuIdOrText); byId.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); List rows = yijuMapper.selectList(byId); if (!rows.isEmpty() && rows.get(0).getJianceYiju() != null) { return rows.get(0).getJianceYiju(); } QueryWrapper 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 wrapper = new QueryWrapper<>(); wrapper.eq("f_id", quyuId); wrapper.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); List list = quyuMapper.selectList(wrapper); if (list.isEmpty() || list.get(0).getJianceQuyu() == null) { return quyuId; } return list.get(0).getJianceQuyu(); } @SuppressWarnings("unchecked") private List> buildStandardRows(Map cfg) { Object rows = cfg.get("standard_rows"); if (rows instanceof List) { return (List>) rows; } List> result = new ArrayList<>(); result.add(standardRow("A", "<1", "<1")); result.add(standardRow("C", "25", "25")); result.add(standardRow("D", "50", "50")); return result; } private Map standardRow(String level, String staticLimit, String dynamicLimit) { Map row = new LinkedHashMap<>(); row.put("level", level); row.put("static_limit", staticLimit); row.put("dynamic_limit", dynamicLimit); return row; } private Map buildSignatures(Map row, Map userNames) { Map 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 makeSignature(String userId, String date, Map userNames) { Map 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 fetchUserNames(Map row) { List 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 idToRealName = new HashMap<>(); List 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 parseConfig(LimsPrintTemplateEntity tpl) { String json = tpl.getConfig(); if (json == null || json.isEmpty()) { return Collections.emptyMap(); } try { return objectMapper.readValue(json, new TypeReference>() {}); } catch (Exception e) { throw new DataException("打印模板 config JSON 解析失败: " + e.getMessage()); } } private static Object getAny(Map 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 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; } }