package com.smartor.service.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.ruoyi.common.utils.StringUtils; import com.smartor.common.SpecificArchiveConstants; import com.smartor.domain.PatArchive; import com.smartor.domain.PatChildArchiveDetail; import com.smartor.domain.PatMaternityArchiveDetail; import com.smartor.domain.PatMedOuthosp; import com.smartor.domain.PatSpecificArchiveGenerateConfig; import com.smartor.mapper.PatArchiveMapper; import com.smartor.service.IPatChildArchiveService; import com.smartor.service.IPatMaternityArchiveService; import com.smartor.service.IPatSpecificArchiveGenerateConfigService; import com.smartor.service.IPatSpecificArchiveGenerateService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; /** * 专科档案生成Service业务层处理。 * *

只处理丽水市妇幼保健院(orgid = 47226079133110211G1001)的门诊接诊完成记录, * 按 {@code pat_specific_archive_generate_config} 配置匹配科室和诊断后, * 生成对应类型的妇科档案或儿科档案。

*/ @Slf4j @Service public class PatSpecificArchiveGenerateServiceImpl implements IPatSpecificArchiveGenerateService { /** 部门分类:妇科 */ private static final String DEPT_CATEGORY_GYNECOLOGY = "1"; /** 部门分类:儿科 */ private static final String DEPT_CATEGORY_PEDIATRICS = "2"; /** 部门类型:科室 */ private static final String DEPT_TYPE_DEPARTMENT = "1"; /** 来源类型:门诊记录 */ private static final String SOURCE_TYPE_OUTHOSP = "1"; @Autowired private IPatSpecificArchiveGenerateConfigService patSpecificArchiveGenerateConfigService; @Autowired private IPatMaternityArchiveService patMaternityArchiveService; @Autowired private IPatChildArchiveService patChildArchiveService; @Autowired private PatArchiveMapper patArchiveMapper; @Override public int generateByOuthosp(PatMedOuthosp patMedOuthosp, PatArchive patArchive) { if (patMedOuthosp == null) { return 0; } // 仅丽水市妇幼保健院生效,避免影响其他机构 if (!SpecificArchiveConstants.LISHUI_MCH_ORG_ID.equals(patMedOuthosp.getOrgid())) { return 0; } if (StringUtils.isBlank(patMedOuthosp.getOuthospno())) { log.warn("生成专科档案跳过:门诊编号为空,serialnum={}", patMedOuthosp.getSerialnum()); return 0; } PatArchive targetArchive = resolvePatArchive(patMedOuthosp, patArchive); if (targetArchive == null && patMedOuthosp.getPatid() != null) { targetArchive = patArchiveMapper.selectPatArchiveByPatid(patMedOuthosp.getPatid()); } Long patid = targetArchive != null ? targetArchive.getId() : patMedOuthosp.getPatid(); if (patid == null) { log.warn("生成专科档案跳过:未找到患者档案,outhospno={},patno={}", patMedOuthosp.getOuthospno(), patMedOuthosp.getPatno()); return 0; } String campusid = StringUtils.isNotBlank(patMedOuthosp.getCampusid()) ? patMedOuthosp.getCampusid() : "1"; List configs = patSpecificArchiveGenerateConfigService.selectEffectiveConfigList(patMedOuthosp.getOrgid(), campusid); if (CollectionUtils.isEmpty(configs)) { log.debug("生成专科档案跳过:机构未配置档案生成规则,orgid={},campusid={}", patMedOuthosp.getOrgid(), campusid); return 0; } // 同一条门诊记录、同一部门分类、同一档案类型只生成一次 Set generatedKeys = new HashSet<>(); int generatedCount = 0; for (PatSpecificArchiveGenerateConfig config : configs) { if (!matchConfig(config, patMedOuthosp)) { continue; } String archiveType = config.getArchiveType(); String deptCategory = config.getDeptCategory(); if (StringUtils.isBlank(archiveType) || StringUtils.isBlank(deptCategory)) { log.warn("生成专科档案跳过:配置不完整,configId={},deptCategory={},archiveType={}", config.getId(), deptCategory, archiveType); continue; } String generatedKey = deptCategory + "|" + archiveType; if (!generatedKeys.add(generatedKey)) { continue; } try { if (DEPT_CATEGORY_GYNECOLOGY.equals(deptCategory)) { PatMaternityArchiveDetail detail = buildMaternityDetail(patMedOuthosp, targetArchive, config, campusid); patMaternityArchiveService.insertOrUpdateMaternityArchive(detail); generatedCount++; } else if (DEPT_CATEGORY_PEDIATRICS.equals(deptCategory)) { PatChildArchiveDetail detail = buildChildDetail(patMedOuthosp, targetArchive, config, campusid); patChildArchiveService.insertOrUpdateChildArchive(detail); generatedCount++; } else { log.warn("生成专科档案跳过:未知部门分类,configId={},deptCategory={}", config.getId(), deptCategory); } } catch (Exception e) { log.error("生成专科档案失败,configId={},outhospno={},deptCategory={},archiveType={}", config.getId(), patMedOuthosp.getOuthospno(), deptCategory, archiveType, e); } } return generatedCount; } /** * 判断门诊记录是否命中配置。 * *

部门条件与诊断条件为 OR 关系:任一条件命中即生成;两个集合都为空时配置无效。

*/ private boolean matchConfig(PatSpecificArchiveGenerateConfig config, PatMedOuthosp patMedOuthosp) { List deptCodes = parseCodes(config.getDeptCodes()); List icd10Codes = parseCodes(config.getIcd10Codes()); if (CollectionUtils.isEmpty(deptCodes) && CollectionUtils.isEmpty(icd10Codes)) { return false; } boolean deptMatched = false; if (CollectionUtils.isNotEmpty(deptCodes)) { // 门诊记录只有科室,没有病区;dept_type=2(病区)不参与门诊匹配 if (DEPT_TYPE_DEPARTMENT.equals(config.getDeptType())) { deptMatched = containsIgnoreCase(deptCodes, patMedOuthosp.getDeptcode()); } } boolean diagnosisMatched = false; if (CollectionUtils.isNotEmpty(icd10Codes)) { String icd10code = patMedOuthosp.getIcd10code(); String diagname = patMedOuthosp.getDiagname(); diagnosisMatched = icd10Codes.stream().anyMatch(code -> { if (equalsIgnoreCase(code, icd10code)) { return true; } // 部分 HIS 数据只有诊断名称没有诊断码,此时允许按诊断名称兜底匹配 return StringUtils.isBlank(icd10code) && equalsIgnoreCase(code, diagname); }); } return deptMatched || diagnosisMatched; } private PatMaternityArchiveDetail buildMaternityDetail(PatMedOuthosp patMedOuthosp, PatArchive patArchive, PatSpecificArchiveGenerateConfig config, String campusid) { PatMaternityArchiveDetail detail = new PatMaternityArchiveDetail(); detail.setArchiveType(config.getArchiveType()); detail.setSourceType(SOURCE_TYPE_OUTHOSP); fillCommonDetail(detail, patMedOuthosp, patArchive, campusid); if (patArchive != null) { detail.setAddress(patArchive.getPlaceOfResidence()); } return detail; } private PatChildArchiveDetail buildChildDetail(PatMedOuthosp patMedOuthosp, PatArchive patArchive, PatSpecificArchiveGenerateConfig config, String campusid) { PatChildArchiveDetail detail = new PatChildArchiveDetail(); detail.setArchiveType(config.getArchiveType()); detail.setSourceType(SOURCE_TYPE_OUTHOSP); fillCommonChildDetail(detail, patMedOuthosp, patArchive, campusid); detail.setParentPhone(patArchive != null ? firstNotBlank(patArchive.getTelcode(), patMedOuthosp.getTelcode()) : patMedOuthosp.getTelcode()); if (patArchive != null) { detail.setParentAddress(patArchive.getPlaceOfResidence()); } // 营养性疾病档案同步诊断信息,方便列表直接展示 if ("1".equals(config.getArchiveType())) { detail.setNutritionIcd10Code(patMedOuthosp.getIcd10code()); detail.setNutritionDiagName(patMedOuthosp.getDiagname()); } return detail; } private void fillCommonDetail(PatMaternityArchiveDetail detail, PatMedOuthosp patMedOuthosp, PatArchive patArchive, String campusid) { detail.setOuthospno(patMedOuthosp.getOuthospno()); detail.setSerialnum(patMedOuthosp.getSerialnum()); detail.setPatid(patArchive != null ? patArchive.getId() : patMedOuthosp.getPatid()); detail.setPatname(patArchive != null ? firstNotBlank(patArchive.getName(), patMedOuthosp.getPatname()) : patMedOuthosp.getPatname()); detail.setBirthdate(patArchive != null ? patArchive.getBirthdate() : null); detail.setIdcardno(patArchive != null ? firstNotBlank(patArchive.getIdcardno(), patMedOuthosp.getIdcardno()) : patMedOuthosp.getIdcardno()); detail.setPhone(patArchive != null ? firstNotBlank(patArchive.getTelcode(), patMedOuthosp.getTelcode()) : patMedOuthosp.getTelcode()); detail.setSex(patArchive != null && patArchive.getSex() != null ? patArchive.getSex() : patMedOuthosp.getSex()); detail.setDiagTime(patMedOuthosp.getAdmitdate()); detail.setArchiveTime(new Date()); detail.setDoctorCode(patMedOuthosp.getDrcode()); detail.setDoctorName(patMedOuthosp.getDrname()); detail.setManagementDoctorCode(patMedOuthosp.getDrcode()); detail.setManagementDoctorName(patMedOuthosp.getDrname()); detail.setFirstDoctorCode(patMedOuthosp.getDrcode()); detail.setFirstDoctorName(patMedOuthosp.getDrname()); detail.setDeptcode(patMedOuthosp.getDeptcode()); detail.setDeptname(patMedOuthosp.getDeptname()); detail.setIcd10code(patMedOuthosp.getIcd10code()); detail.setDiagname(patMedOuthosp.getDiagname()); detail.setRegisterUser(patMedOuthosp.getDrname()); detail.setOrgid(patMedOuthosp.getOrgid()); detail.setCampusid(campusid); detail.setDelFlag("0"); } private void fillCommonChildDetail(PatChildArchiveDetail detail, PatMedOuthosp patMedOuthosp, PatArchive patArchive, String campusid) { detail.setOuthospno(patMedOuthosp.getOuthospno()); detail.setSerialnum(patMedOuthosp.getSerialnum()); detail.setPatid(patArchive != null ? patArchive.getId() : patMedOuthosp.getPatid()); detail.setPatname(patArchive != null ? firstNotBlank(patArchive.getName(), patMedOuthosp.getPatname()) : patMedOuthosp.getPatname()); detail.setBirthdate(patArchive != null ? patArchive.getBirthdate() : null); detail.setIdcardno(patArchive != null ? firstNotBlank(patArchive.getIdcardno(), patMedOuthosp.getIdcardno()) : patMedOuthosp.getIdcardno()); detail.setPhone(patArchive != null ? firstNotBlank(patArchive.getTelcode(), patMedOuthosp.getTelcode()) : patMedOuthosp.getTelcode()); detail.setSex(patArchive != null && patArchive.getSex() != null ? patArchive.getSex() : patMedOuthosp.getSex()); detail.setDiagTime(patMedOuthosp.getAdmitdate()); detail.setArchiveTime(new Date()); detail.setDoctorCode(patMedOuthosp.getDrcode()); detail.setDoctorName(patMedOuthosp.getDrname()); detail.setManagementDoctorCode(patMedOuthosp.getDrcode()); detail.setManagementDoctorName(patMedOuthosp.getDrname()); detail.setDeptcode(patMedOuthosp.getDeptcode()); detail.setDeptname(patMedOuthosp.getDeptname()); detail.setIcd10code(patMedOuthosp.getIcd10code()); detail.setDiagname(patMedOuthosp.getDiagname()); detail.setRegisterUser(patMedOuthosp.getDrname()); detail.setOrgid(patMedOuthosp.getOrgid()); detail.setCampusid(campusid); detail.setDelFlag("0"); } private PatArchive resolvePatArchive(PatMedOuthosp patMedOuthosp, PatArchive patArchive) { if (patArchive != null && patArchive.getId() != null) { return patArchive; } PatArchive query = new PatArchive(); if (StringUtils.isNotBlank(patMedOuthosp.getPatno())) { query.setPatientno(patMedOuthosp.getPatno()); } else if (StringUtils.isNotBlank(patMedOuthosp.getIdcardno())) { query.setIdcardno(patMedOuthosp.getIdcardno()); } else { return null; } query.setOrgid(patMedOuthosp.getOrgid()); List archives = patArchiveMapper.selectPatArchiveList(query); return CollectionUtils.isNotEmpty(archives) ? archives.get(0) : null; } private List parseCodes(String raw) { if (StringUtils.isBlank(raw)) { return Collections.emptyList(); } String value = raw.trim(); try { JSONArray array = JSON.parseArray(value); if (array != null) { List result = new ArrayList<>(); for (Object item : array) { if (item != null && StringUtils.isNotBlank(String.valueOf(item))) { result.add(String.valueOf(item).trim()); } } return result; } } catch (Exception e) { log.warn("解析档案生成配置集合失败,按逗号分隔处理:{}", raw); } return Arrays.stream(value.split(",")) .map(String::trim) .filter(StringUtils::isNotBlank) .collect(Collectors.toList()); } private String firstNotBlank(String first, String second) { return StringUtils.isNotBlank(first) ? first : second; } private boolean containsIgnoreCase(List source, String target) { if (StringUtils.isBlank(target)) { return false; } return source.stream().anyMatch(item -> equalsIgnoreCase(item, target)); } private boolean equalsIgnoreCase(String first, String second) { return first != null && second != null && first.trim().equalsIgnoreCase(second.trim()); } }