package jnpf.limsService.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import jnpf.base.ActionResult; import jnpf.base.ActionResultCode; import jnpf.flowable.TaskApi; import jnpf.flowable.model.task.FlowModel; import jnpf.limsEntity.JianyanJielun; import jnpf.limsEntity.LimsAdDiaochabiaoEntity; import jnpf.limsEntity.LimsJianyanResultItem; import jnpf.limsEntity.LimsJianyanXiangEntity; import jnpf.limsEntity.LimsOosOotDiaochabiaoEntity; import jnpf.limsEntity.YichangDiaochaLeixing; import jnpf.limsEntity.ZhiliangBiaozhunGuanliZixiangEntity; import jnpf.limsService.LimsAdDiaochabiaoService; import jnpf.limsService.LimsFlowTemplateResolver; import jnpf.limsService.LimsOosOotDiaochabiaoService; import jnpf.limsService.LimsYichangDiaochaService; import jnpf.limsService.ZhiliangBiaozhunGuanliZixiangService; import jnpf.util.UserProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; @Service public class LimsYichangDiaochaServiceImpl implements LimsYichangDiaochaService { @Autowired private ZhiliangBiaozhunGuanliZixiangService zhiliangBiaozhunGuanliZixiangService; @Autowired private LimsAdDiaochabiaoService limsAdDiaochabiaoService; @Autowired private LimsOosOotDiaochabiaoService limsOosOotDiaochabiaoService; @Autowired private LimsFlowTemplateResolver limsFlowTemplateResolver; @Autowired private TaskApi taskApi; @Override public void createIfNeeded(LimsJianyanXiangEntity row, LimsJianyanResultItem item) { if (row == null || item == null) { return; } YichangDiaochaLeixing t = YichangDiaochaLeixing.fromCode(item.getYichangDiaochaLeixing()); if (t == null || !t.isInvestigation()) { return; } // 确定性反查:lims_jianyan_xiang.f_foreign_id = zixiang.f_id(= 表单检验项目id); // zixiang.f_foreign_id = guanli.f_id(= 表单质量标准)。f_foreign_id 创建后稳定、报告流程不覆盖。 String jianyanXiangmuId = row.getForeignId(); String zhiliangBiaozhunId = null; if (jianyanXiangmuId != null && !jianyanXiangmuId.isEmpty()) { ZhiliangBiaozhunGuanliZixiangEntity zixiang = zhiliangBiaozhunGuanliZixiangService.getById(jianyanXiangmuId); if (zixiang != null) { zhiliangBiaozhunId = zixiang.getForeignId(); } } if (t == YichangDiaochaLeixing.AD) { launchAd(row, item, jianyanXiangmuId, zhiliangBiaozhunId, t); } else { // OOS / OOT:同一张表 + 同一模板,diaocha_fenlei 用枚举 code(oos/oot) launchOosOot(row, item, jianyanXiangmuId, zhiliangBiaozhunId, t); } } private void launchAd(LimsJianyanXiangEntity row, LimsJianyanResultItem item, String jianyanXiangmuId, String zhiliangBiaozhunId, YichangDiaochaLeixing t) { // 判重:自然键 = qingyan_liushuihao + jianyan_xiangmu_id;已存在则跳过,防重复发起 QueryWrapper dup = new QueryWrapper<>(); dup.eq("qingyan_liushuihao", row.getJianyanLiushuihao()); dup.eq("jianyan_xiangmu_id", jianyanXiangmuId); dup.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); if (limsAdDiaochabiaoService.count(dup) > 0) { return; } Date now = new Date(); Map formData = baseFormData(row, jianyanXiangmuId, zhiliangBiaozhunId, now); formData.put("ad_diaocha_bianhao", nextBianhao("AD", now, true)); // 异常描述:AD 表单发起阶段必填,用检验结果数据拼一句客观描述,调查员可再改 formData.put("yichang_miaoshu", describeAnomaly(row, item)); launch(t, formData, row.getJianyanLiushuihao()); } private void launchOosOot(LimsJianyanXiangEntity row, LimsJianyanResultItem item, String jianyanXiangmuId, String zhiliangBiaozhunId, YichangDiaochaLeixing t) { String fenlei = t.getCode(); // oos / oot // 判重:自然键 = qingyan_liushuihao + jianyan_xiangmu_id + diaocha_fenlei QueryWrapper dup = new QueryWrapper<>(); dup.eq("qingyan_liushuihao", row.getJianyanLiushuihao()); dup.eq("jianyan_xiangmu_id", jianyanXiangmuId); dup.eq("diaocha_fenlei", fenlei); dup.and(w -> w.isNull("f_delete_mark").or().ne("f_delete_mark", 1)); if (limsOosOotDiaochabiaoService.count(dup) > 0) { return; } Date now = new Date(); Map formData = baseFormData(row, jianyanXiangmuId, zhiliangBiaozhunId, now); formData.put("diaocha_fenlei", fenlei); formData.put("diaocha_bianhao", nextBianhao(fenlei.toUpperCase(), now, false)); // 检验描述:OOS/OOT 表单发起阶段必填,同 AD 异常描述 formData.put("jianyan_miaoshu", describeAnomaly(row, item)); launch(t, formData, row.getJianyanLiushuihao()); } /** 公共表单字段(key = 物理列名,AD/OOS/OOT 同源)。日期用 yyyy-MM-dd 字符串(与库内现有数据一致)。 */ private Map baseFormData(LimsJianyanXiangEntity row, String jianyanXiangmuId, String zhiliangBiaozhunId, Date now) { String today = new SimpleDateFormat("yyyy-MM-dd").format(now); String currentUserId = UserProvider.getUser().getUserId(); Map m = new LinkedHashMap<>(); m.put("yangpin_leixing", row.getBizType()); m.put("yangpin_mingcheng", row.getChanpinMingcheng()); m.put("yangpin_id", row.getChanpinId()); m.put("pihao", row.getPihao()); m.put("qingyan_liushuihao", row.getJianyanLiushuihao()); m.put("zhiliang_biaozhun", zhiliangBiaozhunId); m.put("jianyan_xiangmu", row.getJianyanXiangmuMingcheng()); m.put("jianyan_xiangmu_id", jianyanXiangmuId); m.put("faxian_riqi", today); m.put("jianyan_ren", currentUserId); m.put("jianyan_riqi", today); m.put("qingyandan_id", row.getQingyandanId()); return m; } /** * 异常描述 / 检验描述(表单发起阶段必填):用 检验项目 + 本次检验结果 + 标准规定 + 检验结论 * 拼一句客观描述,调查员可在表单里再修改。结果/结论取自本次录入 item,标准/项目取自检验项 row。 */ private String describeAnomaly(LimsJianyanXiangEntity row, LimsJianyanResultItem item) { String xiangmu = safe(row.getJianyanXiangmuMingcheng()); String jieguo = safe(item.getJianyanJieguo()); String biaozhun = safe(row.getBiaozhunGuiding()); String jielun = jielunLabel(item.getJianyanJielun()); return "检验项目【" + xiangmu + "】检验结果【" + jieguo + "】,标准规定【" + biaozhun + "】,检验结论【" + jielun + "】。"; } private static String safe(String s) { return s == null ? "" : s; } /** 检验结论 code → 中文 label;空 / 未知 code 不抛异常(返回原值或空) */ private static String jielunLabel(String code) { if (code == null || code.isEmpty()) { return ""; } try { return JianyanJielun.fromCode(code).getLabel(); } catch (Exception e) { return code; } } /** 解析 templateId → 以当前登录用户名义 launchFlow → 校验返回;失败抛异常(交 submit 收集为发起失败)。 */ private void launch(YichangDiaochaLeixing t, Map formData, String liushuihao) { String enCode = t.getFlowTemplateEnCode(); String templateId = limsFlowTemplateResolver.resolveTemplateId(enCode); if (templateId == null || templateId.isEmpty()) { throw new RuntimeException("未找到流程模板(enCode=" + enCode + "),无法发起 " + t.getCode() + " 调查流程"); } FlowModel model = new FlowModel(); model.setTemplateId(templateId); model.setUserIds(Collections.singletonList(UserProvider.getUser().getUserId())); model.setFormDataList(Collections.singletonList(formData)); // hasPermission 默认 false:两模板 visibleType=1 全局可发起,不做发起权限过滤 ActionResult result = taskApi.launchFlow(model); // 成功判定用平台常量 ActionResultCode.SUCCESS(与 VisualdevModelDataController 发起后判定一致); // 不能硬编码 "200"——launchFlow 成功返回的 code 是 SUCCESS 码、msg 为"提交成功,请耐心等待",并非 "200"。 if (result == null || !ActionResultCode.SUCCESS.getCode().equals(result.getCode())) { throw new RuntimeException("发起 " + t.getCode() + " 调查流程失败(流水号=" + liushuihao + "):" + (result == null ? "无返回" : result.getMsg())); } } /** * 生成"前缀+yyyyMMdd+3位日内流水"编号;流水 = 当天该前缀已有行数 + 1。 * isAd=true 查 lims_ad_diaochabiao.ad_diaocha_bianhao,否则查 lims_oos_oot_diaochabiao.diaocha_bianhao。 * LIMS 单据量低,并发碰撞可忽略;真正的重复由判重自然键拦截。 */ private String nextBianhao(String prefix, Date now, boolean isAd) { String head = prefix + new SimpleDateFormat("yyyy").format(now); long seq; if (isAd) { QueryWrapper w = new QueryWrapper<>(); w.likeRight("ad_diaocha_bianhao", head); seq = limsAdDiaochabiaoService.count(w) + 1; } else { QueryWrapper w = new QueryWrapper<>(); w.likeRight("diaocha_bianhao", head); seq = limsOosOotDiaochabiaoService.count(w) + 1; } return String.format("%s%04d", head, seq); } }