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.LimsJianyanXiangEntity; import jnpf.limsEntity.LimsPrintTemplateEntity; import jnpf.limsEntity.LimsQingyandanEntity; import jnpf.limsEntity.LimsWendingxingKaocaJihuaEntity; import jnpf.limsEntity.LimsWendingxingKaocaJihuaZhouqiEntity; import jnpf.limsMapper.LimsJianyanXiangMapper; import jnpf.limsMapper.LimsQingyandanMapper; import jnpf.limsMapper.LimsWendingxingKaocaJihuaMapper; import jnpf.limsMapper.LimsWendingxingKaocaJihuaZhouqiMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * 稳定性考察汇总模板渲染器(template_id = wendingxing_kaoca_huizong)。 */ @Component public class WendingxingKaocaHuizongRenderer implements PrintTemplateRenderer { public static final String TEMPLATE_ID = "wendingxing_kaoca_huizong"; private static final String EMPTY_RESULT = "/"; @Autowired private LimsWendingxingKaocaJihuaMapper jihuaMapper; @Autowired private LimsWendingxingKaocaJihuaZhouqiMapper zhouqiMapper; @Autowired private LimsQingyandanMapper qingyandanMapper; @Autowired private LimsJianyanXiangMapper jianyanXiangMapper; @Autowired private ObjectMapper objectMapper; @Override public String getTemplateId() { return TEMPLATE_ID; } @Override public Map render(String baogaoId, LimsPrintTemplateEntity tpl) { if (baogaoId == null || baogaoId.trim().isEmpty()) { throw new DataException("缺少稳定性考察计划 id"); } LimsWendingxingKaocaJihuaEntity jihua = selectJihua(baogaoId); if (jihua == null) { throw new DataException("稳定性考察计划不存在或已删除: " + baogaoId); } Map config = parseConfig(tpl); List cycles = selectCycles(baogaoId); Map> qingyandanByCycle = selectQingyandan(baogaoId, cycles); Map> itemsByQingyandan = selectItems(qingyandanByCycle); LinkedHashMap periodLabels = buildPeriodLabels(cycles, config.get("zhouqiDanwei")); Map data = new LinkedHashMap<>(); data.put("schemeName", jihua.getKaocaMingcheng()); data.put("periods", new ArrayList<>(periodLabels.values())); data.put("reports", buildReports(cycles, periodLabels, qingyandanByCycle, itemsByQingyandan)); return data; } private LimsWendingxingKaocaJihuaEntity selectJihua(String baogaoId) { QueryWrapper query = new QueryWrapper<>(); query.eq("f_id", baogaoId); query.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); return jihuaMapper.selectOne(query); } /** * * 根据计划 ID 查询周期列表数据 * * @param baogaoId * @return */ private List selectCycles(String baogaoId) { QueryWrapper query = new QueryWrapper<>(); query.eq("kaoca_jihua_id", baogaoId); query.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); query.and(w -> w.isNull("shifou_jixu_zhixing").or().ne("shifou_jixu_zhixing", "no")); query.orderByAsc("jiahua_anpai_riqi", "f_id"); return zhouqiMapper.selectList(query); } private Map> selectQingyandan( String baogaoId, List cycles) { if (cycles.isEmpty()) { return Collections.emptyMap(); } List cycleIds = cycles.stream() .map(LimsWendingxingKaocaJihuaZhouqiEntity::getId) .collect(Collectors.toList()); QueryWrapper query = new QueryWrapper<>(); query.eq("wendingxing_jilu_id", baogaoId); query.in("wendingxing_zhouqi_id", cycleIds); query.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); query.orderByAsc("f_id"); Map> result = new HashMap<>(); for (LimsQingyandanEntity row : qingyandanMapper.selectList(query)) { result.computeIfAbsent(row.getWendingxingZhouqiId(), key -> new ArrayList<>()).add(row); } return result; } private Map> selectItems( Map> qingyandanByCycle) { List qingyandanIds = qingyandanByCycle.values().stream() .flatMap(List::stream) .map(LimsQingyandanEntity::getId) .collect(Collectors.toList()); if (qingyandanIds.isEmpty()) { return Collections.emptyMap(); } QueryWrapper query = new QueryWrapper<>(); query.in("qingyandan_id", qingyandanIds); query.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); query.orderByAsc("f_id"); Map> result = new HashMap<>(); for (LimsJianyanXiangEntity row : jianyanXiangMapper.selectList(query)) { result.computeIfAbsent(row.getQingyandanId(), key -> new ArrayList<>()).add(row); } return result; } private LinkedHashMap buildPeriodLabels( List cycles, Object unitConfig) { LinkedHashMap result = new LinkedHashMap<>(); for (LimsWendingxingKaocaJihuaZhouqiEntity cycle : cycles) { String key = periodKey(cycle); result.putIfAbsent(key, formatNumber(cycle.getZhouqi()) + resolveUnit(cycle.getZhouqiDanwei(), unitConfig)); } return result; } private List> buildReports( List cycles, LinkedHashMap periodLabels, Map> qingyandanByCycle, Map> itemsByQingyandan) { LinkedHashMap> cyclesByBatch = new LinkedHashMap<>(); for (LimsWendingxingKaocaJihuaZhouqiEntity cycle : cycles) { cyclesByBatch.computeIfAbsent(valueOrEmpty(cycle.getPihao()), key -> new ArrayList<>()) .add(cycle); } List> reports = new ArrayList<>(); for (Map.Entry> batch : cyclesByBatch.entrySet()) { LinkedHashMap rows = new LinkedHashMap<>(); for (LimsWendingxingKaocaJihuaZhouqiEntity cycle : batch.getValue()) { String periodKey = periodKey(cycle); for (LimsQingyandanEntity qingyandan : qingyandanByCycle.getOrDefault(cycle.getId(), Collections.emptyList())) { for (LimsJianyanXiangEntity item : itemsByQingyandan.getOrDefault(qingyandan.getId(), Collections.emptyList())) { String rowKey = valueOrEmpty(item.getJianyanXiangmuMingcheng()) + "\u0000" + valueOrEmpty(item.getBiaozhunGuiding()); String standard = resultOrSlash(item.getBiaozhunGuiding()); String value = resultOrSlash(item.getJianyanJieguo()); if ("数值".equals(item.getShujuLeixing())) { value += item.getFenjianDanwei(); standard += item.getFenjianDanwei(); } String finalStandard = standard; ReportRow row = rows.computeIfAbsent(rowKey, key -> new ReportRow(item.getJianyanXiangmuMingcheng(), finalStandard)); if (!row.values.containsKey(periodKey) || EMPTY_RESULT.equals(row.values.get(periodKey))) { row.values.put(periodKey, value); } } } } List> reportRows = new ArrayList<>(); for (ReportRow source : rows.values()) { Map row = new LinkedHashMap<>(); row.put("item", source.item); row.put("standard", source.standard); List values = periodLabels.keySet().stream() .map(key -> source.values.getOrDefault(key, EMPTY_RESULT)) .collect(Collectors.toList()); row.put("values", values); reportRows.add(row); } Map report = new LinkedHashMap<>(); report.put("batchNo", batch.getKey()); report.put("rows", reportRows); reports.add(report); } return reports; } private Map parseConfig(LimsPrintTemplateEntity tpl) { if (tpl == null || tpl.getConfig() == null || tpl.getConfig().trim().isEmpty()) { return Collections.emptyMap(); } try { return objectMapper.readValue(tpl.getConfig(), new TypeReference>() { }); } catch (Exception e) { throw new DataException("打印模板 config JSON 解析失败: " + e.getMessage()); } } @SuppressWarnings("unchecked") private String resolveUnit(String code, Object config) { String source = valueOrEmpty(code); if (config instanceof Map) { Object configured = ((Map) config).get(source); return labelOf(configured, source); } if (config instanceof List) { for (Object entry : (List) config) { if (!(entry instanceof Map)) { continue; } Map option = (Map) entry; String value = firstString(option, "value", "id", "code", "enCode"); if (source.equals(value)) { return firstNonEmpty(firstString(option, "label", "name", "fullName", "text"), source); } } } return source; } @SuppressWarnings("unchecked") private String labelOf(Object configured, String fallback) { if (configured instanceof Map) { return firstNonEmpty(firstString((Map) configured, "label", "name", "fullName", "text", "value"), fallback); } return configured == null ? fallback : configured.toString(); } private String firstString(Map values, String... keys) { for (String key : keys) { Object value = values.get(key); if (value != null && !value.toString().trim().isEmpty()) { return value.toString(); } } return ""; } private String periodKey(LimsWendingxingKaocaJihuaZhouqiEntity cycle) { return formatNumber(cycle.getZhouqi()) + "\u0000" + valueOrEmpty(cycle.getZhouqiDanwei()); } private String formatNumber(BigDecimal value) { return value == null ? "" : value.stripTrailingZeros().toPlainString(); } private String resultOrSlash(String value) { return value == null || value.trim().isEmpty() ? EMPTY_RESULT : value; } private String firstNonEmpty(String value, String fallback) { return value == null || value.trim().isEmpty() ? fallback : value; } private String valueOrEmpty(String value) { return value == null ? "" : value; } private static final class ReportRow { private final String item; private final String standard; private final Map values = new HashMap<>(); private ReportRow(String item, String standard) { this.item = item; this.standard = standard; } } }