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.JianyanXiangmuGuanliEntity;
import jnpf.limsEntity.LimsJianyanXiangEntity;
import jnpf.limsEntity.LimsPrintTemplateEntity;
import jnpf.limsEntity.LimsQingyandanEntity;
import jnpf.limsMapper.JianyanXiangmuGuanliMapper;
import jnpf.limsService.LimsJianyanXiangService;
import jnpf.limsService.LimsQingyandanService;
import jnpf.permission.UserApi;
import jnpf.permission.entity.UserEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
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.Set;
import java.util.stream.Collectors;
/**
* "成品质量报告"模板渲染器(template_id = jianyan_baogao)。
*
*
输入:lims_qingyandan.f_id;报告数据与表头都在这张行上(baogao_* 列)。
* 输出包含表头、检测项分组(按 fenxi_leixing 聚合 lims_jianyan_xiang)、
* 签名区(报告人/复核人/QC 经理)、依据 / 结论 / 备注(来自模板 config)。
*/
@Component
public class JianyanBaogaoRenderer implements PrintTemplateRenderer {
public static final String TEMPLATE_ID = "jianyan_baogao";
@Autowired
private LimsQingyandanService qingyandanService;
@Autowired
private LimsJianyanXiangService jianyanXiangService;
@Autowired
private JianyanXiangmuGuanliMapper xiangmuGuanliMapper;
@Autowired
private UserApi usersApi;
@Autowired
private ObjectMapper objectMapper;
@Override
public String getTemplateId() {
return TEMPLATE_ID;
}
@Override
public Map render(String qingyandanId, LimsPrintTemplateEntity tpl) {
if (qingyandanId == null || qingyandanId.isEmpty()) {
throw new DataException("缺少请验单 id");
}
// 1. 请验单(报告数据 + 表头都在这一行上,必须存在 + 未软删)
LimsQingyandanEntity qingyandan = qingyandanService.getById(qingyandanId);
if (qingyandan == null
|| (qingyandan.getDeleteMark() != null && qingyandan.getDeleteMark() == 1)) {
throw new DataException("请验单不存在或已删除: " + qingyandanId);
}
// 2. 该流水号下未软删的所有 jianyan_xiang
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.eq("jianyan_liushuihao", qingyandan.getJianyanLiushuihao());
wrapper.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1));
wrapper.orderByAsc("f_id");
List rows = jianyanXiangService.list(wrapper);
// 3.1 排除 lims_jianyan_xiang.shifou_chuju_baogao = 'no' 的检验项。
// 仅显式 "no" 才会被剔除;NULL / 其它值按"出报告"处理(保守不误伤)。
// 该字段在 buildJianyanXiang / buildWaijianJianyanXiang 阶段就从 jiancexiang 快照过来,
// 渲染时不再回查 lims_qingyandan_jiancexiang。
rows = rows.stream()
.filter(r -> !"no".equalsIgnoreCase(r.getShifouChujuBaogao()))
.collect(Collectors.toList());
// 4. 解析模板 config
Map cfg = parseConfig(tpl);
Map labels = asMap(cfg.get("labels"));
// 5. 拼装返回结构(保持 LinkedHashMap 顺序便于阅读)
// 顶层 companyName / docNumber / reportBookNumber 命名与前端模板
// jianyan_baogao.html 内 templateData.* 的读取键一致,避免前端再做映射。
//
// docNumber 的真实业务语义是"产品质量标准文档编号 + 版次"(如
// STP-QAD-Z003-MP-R01-06),应跟随产品/产品标准维护。当前业务尚未
// 在主数据里建立该字段,**临时**用 jianyan_liushuihao(每次请验唯一)
// 占位,避免页头空白。等 lims_quality_manager 等主数据补齐 doc_number
// 后切回 cfg.doc_number 或新源即可(cfg.doc_number 字段保留不删)。
Map data = new LinkedHashMap<>();
data.put("template_id", tpl.getTemplateId());
data.put("template_name", tpl.getTemplateName());
data.put("companyName", asString(cfg.get("company_name")));
data.put("docNumber", asString(qingyandan.getJianyanLiushuihao()));
data.put("reportBookNumber", asString(qingyandan.getBaogaoBianhao()));
data.put("yiju", asString(cfg.get("yiju")));
data.put("header", buildHeader(qingyandan));
data.put("groups", buildGroups(rows));
data.put("jielun", asString(cfg.get("jielun")));
data.put("signatures", buildSignatures(qingyandan, labels));
data.put("beizhu", asString(cfg.get("beizhu")));
return data;
}
private Map buildHeader(LimsQingyandanEntity q) {
Map h = new LinkedHashMap<>();
h.put("chanpin_mingcheng", q.getChanpinMingcheng());
h.put("pihao", q.getPihao());
h.put("laiyuan_bianma", q.getLaiyuanBianma());
h.put("chanpin_bianma", q.getChanpinBianma());
h.put("guige", q.getGuige());
h.put("shengchan_riqi", q.getShengchanRiqi());
h.put("piliang", q.getPiliang());
h.put("piliang_danwei", q.getPiliangDanwei());
h.put("youxiaoqi", q.getYouxiaoqi());
return h;
}
/**
* 按"质量属性中文名"分组,组内按 jianyan_xiang 自然顺序(f_id 升序)。
*
* "质量属性"取自检验项目主数据 jianyan_xiangmu_guanli:
*
* - 用 lims_jianyan_xiang.jianyan_xiangmu_bianma 反查主数据,得到 self;
* - self.fenxi_leixing 为空 → 质量属性 = self.mingcheng(自身既是质量属性又是检验项目);
* - self.fenxi_leixing 不空 → 用其值再次反查主数据 bianma 得到 parent,
* 质量属性 = parent.mingcheng。
*
*
* 主数据缺失的容错:self 缺 → 用 lims_jianyan_xiang.jianyan_xiangmu_mingcheng 兜底;
* parent 缺 → 用 self.mingcheng 兜底;都没有就空字符串。
*
*
下发字段 key 仍叫 "fenxi_leixing",与历史前端模板兼容;其值的语义已变成
* "质量属性中文名"(不再是分类编码)。
*/
private List