|
|
|
@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; |
|
|
|
|
import cn.hutool.core.util.StrUtil; |
|
|
|
|
import com.alibaba.fastjson.JSONArray; |
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; |
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils; |
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|
|
|
|
import com.deepoove.poi.XWPFTemplate; |
|
|
|
|
import com.deepoove.poi.config.Configure; |
|
|
|
@ -12,24 +11,27 @@ import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy; |
|
|
|
|
import com.deepoove.poi.xwpf.NiceXWPFDocument; |
|
|
|
|
import digital.laboratory.platform.common.core.util.R; |
|
|
|
|
import digital.laboratory.platform.common.oss.service.OssFile; |
|
|
|
|
import digital.laboratory.platform.inspection.enums.BusinessType; |
|
|
|
|
import digital.laboratory.platform.inspection.enums.TestRecordFileUrl; |
|
|
|
|
import digital.laboratory.platform.inspection.dto.HairSewageDataDto; |
|
|
|
|
import digital.laboratory.platform.inspection.dto.NPSCaseTestDataDto; |
|
|
|
|
import digital.laboratory.platform.inspection.constant.BusinessType; |
|
|
|
|
import digital.laboratory.platform.inspection.constant.TestRecordFileUrl; |
|
|
|
|
import digital.laboratory.platform.inspection.entity.TestRecordInstrument; |
|
|
|
|
import digital.laboratory.platform.inspection.entity.TestRecordReagent; |
|
|
|
|
import digital.laboratory.platform.inspection.entity.TestRecordSampleData; |
|
|
|
|
import digital.laboratory.platform.inspection.entity.TestRecordSampleDataExpand; |
|
|
|
|
import digital.laboratory.platform.inspection.service.*; |
|
|
|
|
import digital.laboratory.platform.inspection.vo.TestRecordSampleDataVO; |
|
|
|
|
import digital.laboratory.platform.inspetion.api.entity.EntrustInfo; |
|
|
|
|
import digital.laboratory.platform.inspetion.api.entity.SampleInfo; |
|
|
|
|
import digital.laboratory.platform.inspetion.api.entity.TargetObject; |
|
|
|
|
import digital.laboratory.platform.inspetion.api.entity.TestRecord; |
|
|
|
|
import digital.laboratory.platform.sys.enums.entrust.EntrustBiologyType; |
|
|
|
|
import org.apache.commons.io.output.ByteArrayOutputStream; |
|
|
|
|
import org.springframework.beans.BeanUtils; |
|
|
|
|
import org.springframework.stereotype.Service; |
|
|
|
|
|
|
|
|
|
import javax.annotation.Resource; |
|
|
|
|
import java.io.ByteArrayInputStream; |
|
|
|
|
import java.util.*; |
|
|
|
|
import java.util.function.Function; |
|
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -62,45 +64,51 @@ public class InspectRecordServiceImpl implements InspectRecordService { |
|
|
|
|
@Resource |
|
|
|
|
private SampleInfoService sampleInfoService; |
|
|
|
|
|
|
|
|
|
@Resource |
|
|
|
|
private TestRecordSampledataExpandService testRecordSampledataExpandService; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 生成检验记录-贵阳禁毒 |
|
|
|
|
* |
|
|
|
|
* @param entrustId 委托id |
|
|
|
|
* @param entrustId 委托id |
|
|
|
|
* @param materialType 标注当前委托的检材是尿液还是毛发 |
|
|
|
|
* @return |
|
|
|
|
* @throws Exception |
|
|
|
|
*/ |
|
|
|
|
@Override |
|
|
|
|
public R inspectionRecord(String entrustId, String materialType) throws Exception { |
|
|
|
|
public R buildInspectionRecord(String entrustId, String materialType) throws Exception { |
|
|
|
|
EntrustInfo entrustInfo = entrustInfoService.getById(entrustId); |
|
|
|
|
if (entrustInfo == null) { |
|
|
|
|
return R.ok(false, "委托信息不存在!"); |
|
|
|
|
} |
|
|
|
|
String type = entrustInfo.getBusinessType(); |
|
|
|
|
if (type.equals(BusinessType.BOINT_CASE.getBusinessType())) { |
|
|
|
|
// Map<String, Object> map = this.invivoRecord(entrustInfo);
|
|
|
|
|
return R.ok(this.createInVivoFile(entrustInfo, materialType), "生成成功!"); |
|
|
|
|
if (entrustInfo.getBusinessType().equals(BusinessType.BOINT_CASE.getBusinessType())) { |
|
|
|
|
return R.ok(this.buildInVivoDocFile(entrustInfo, materialType), "生成成功!"); |
|
|
|
|
} |
|
|
|
|
return R.ok(this.generateCommonDrugInpectRecord(entrustId)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 生成生物样本检验记录数据map |
|
|
|
|
* @param entrustInfo 委托实体信息 |
|
|
|
|
* |
|
|
|
|
* @param entrustInfo 委托实体信息 |
|
|
|
|
* @param materialType 检材类型 |
|
|
|
|
* @return |
|
|
|
|
* @throws Exception |
|
|
|
|
*/ |
|
|
|
|
public Map<String, Object> invivoRecord(EntrustInfo entrustInfo, String materialType) throws Exception { |
|
|
|
|
public Map<String, Object> buildInVivoRecordData(EntrustInfo entrustInfo, String materialType) throws Exception { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取检验记录信息
|
|
|
|
|
TestRecord testRecord = testRecordService.getTestRecordByBusinessId(entrustInfo.getId()); |
|
|
|
|
|
|
|
|
|
if (testRecord == null) { |
|
|
|
|
throw new Exception("未找到检验记录信息"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 生成基础数据
|
|
|
|
|
HashMap<String, Object> data = buildCommonInspectRecordDocMap(entrustInfo, testRecord, materialType); |
|
|
|
|
|
|
|
|
|
// 获取仪器设备数据
|
|
|
|
|
// 获取仪器设备数据(批量查询,减少数据库压力)
|
|
|
|
|
List<String> deviceIdList = testRecord.getDeviceIdList(); |
|
|
|
|
List<TestRecordInstrument> instruments = CollectionUtils.isEmpty(deviceIdList) |
|
|
|
|
? Collections.emptyList() |
|
|
|
@ -109,84 +117,119 @@ public class InspectRecordServiceImpl implements InspectRecordService { |
|
|
|
|
|
|
|
|
|
data.put("instrumentName", CollectionUtils.isEmpty(instruments) |
|
|
|
|
? "未找到仪器设备数据!" |
|
|
|
|
: instruments.stream() |
|
|
|
|
.map(TestRecordInstrument::getInstrumentName) |
|
|
|
|
.collect(Collectors.joining("\n")) |
|
|
|
|
); |
|
|
|
|
: instruments.stream().map(TestRecordInstrument::getInstrumentName) |
|
|
|
|
.collect(Collectors.joining("\n"))); |
|
|
|
|
|
|
|
|
|
// 获取样品检测数据
|
|
|
|
|
List<HairSewageDataDto> hairDataDtos = (List<HairSewageDataDto>) testRecordSampleDataService |
|
|
|
|
.getSampleTestDataByBusiness(entrustInfo.getId()); |
|
|
|
|
// 获取样品数据
|
|
|
|
|
List<TestRecordSampleData> dataList = testRecordSampleDataService.list( |
|
|
|
|
Wrappers.<TestRecordSampleData>lambdaQuery().eq(TestRecordSampleData::getTestId, testRecord.getId())); |
|
|
|
|
|
|
|
|
|
if (CollectionUtils.isEmpty(hairDataDtos)) { |
|
|
|
|
if (CollectionUtils.isEmpty(dataList)) { |
|
|
|
|
data.put("dataDtos", Collections.emptyList()); |
|
|
|
|
data.put("sampleSize", 0); |
|
|
|
|
data.put("vo", testRecord); |
|
|
|
|
return data; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 处理检测数据
|
|
|
|
|
Map<String, List<HairSewageDataDto>> dataMap = hairDataDtos.stream() |
|
|
|
|
.collect(Collectors.groupingBy(HairSewageDataDto::getCompoundName)); |
|
|
|
|
// 批量查询所有样品扩展数据,避免多次查询数据库
|
|
|
|
|
Map<String, List<TestRecordSampleDataExpand>> dataExpandMap = testRecordSampledataExpandService.list( |
|
|
|
|
Wrappers.<TestRecordSampleDataExpand>lambdaQuery() |
|
|
|
|
.in(TestRecordSampleDataExpand::getTestDataId, dataList.stream().map(TestRecordSampleData::getId).collect(Collectors.toList())) |
|
|
|
|
).stream().collect(Collectors.groupingBy(TestRecordSampleDataExpand::getTestDataId)); |
|
|
|
|
|
|
|
|
|
// 根据化合物名称分组
|
|
|
|
|
Map<String, List<TestRecordSampleData>> dataMap = dataList.stream() |
|
|
|
|
.collect(Collectors.groupingBy(TestRecordSampleData::getCompoundName)); |
|
|
|
|
|
|
|
|
|
List<HairSewageDataDto> dataDtos = new ArrayList<>(); |
|
|
|
|
List<TestRecordSampleDataVO> dataDtos = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
// 遍历化合物组
|
|
|
|
|
for (Map.Entry<String, List<TestRecordSampleData>> entry : dataMap.entrySet()) { |
|
|
|
|
String compoundName = entry.getKey(); |
|
|
|
|
List<TestRecordSampleData> list = entry.getValue(); |
|
|
|
|
|
|
|
|
|
dataMap.forEach((compoundName, list) -> { |
|
|
|
|
// 添加空白数据
|
|
|
|
|
HairSewageDataDto blankDto = new HairSewageDataDto(); |
|
|
|
|
blankDto.setSampleName("空白"); |
|
|
|
|
blankDto.setCompoundName(compoundName); |
|
|
|
|
blankDto.setTmpTargetRtTime("/"); |
|
|
|
|
blankDto.setTmpRtTimeError("/"); |
|
|
|
|
blankDto.setRtTimeWithinError("否"); |
|
|
|
|
blankDto.setTmpIonAbundanceRatio("/"); |
|
|
|
|
blankDto.setWhetherCheckOut("否"); |
|
|
|
|
dataDtos.add(blankDto); |
|
|
|
|
|
|
|
|
|
// 处理样品数据
|
|
|
|
|
list.removeIf(item -> { |
|
|
|
|
if (StringUtils.equals(item.getSampleType(), "STD")) { |
|
|
|
|
item.setSampleName("空白添加"); |
|
|
|
|
item.setWhetherCheckOut("是"); |
|
|
|
|
dataDtos.add(item); |
|
|
|
|
return true; |
|
|
|
|
} else if (StringUtils.equals(item.getSampleType(), "QC")) { |
|
|
|
|
return true; |
|
|
|
|
TestRecordSampleDataVO blankVo = new TestRecordSampleDataVO(); |
|
|
|
|
blankVo.setName("空白"); |
|
|
|
|
blankVo.setCompoundName(compoundName); |
|
|
|
|
dataDtos.add(blankVo); |
|
|
|
|
|
|
|
|
|
// 根据样品类型分组
|
|
|
|
|
Map<String, List<TestRecordSampleData>> map = list.stream() |
|
|
|
|
.collect(Collectors.groupingBy(TestRecordSampleData::getSampleType)); |
|
|
|
|
|
|
|
|
|
// 处理标准样品(STD)
|
|
|
|
|
if (map.containsKey("STD")) { |
|
|
|
|
TestRecordSampleData std = map.get("STD").get(0); |
|
|
|
|
TestRecordSampleDataVO stdVo = new TestRecordSampleDataVO(); |
|
|
|
|
BeanUtils.copyProperties(std, stdVo); |
|
|
|
|
stdVo.setName("空白添加"); |
|
|
|
|
stdVo.setIsDetected(1); |
|
|
|
|
|
|
|
|
|
List<TestRecordSampleDataExpand> expandList = dataExpandMap.get(std.getId()); |
|
|
|
|
if (expandList != null) { |
|
|
|
|
for (TestRecordSampleDataExpand expand : expandList) { |
|
|
|
|
if (!expand.getBasePeak()) { |
|
|
|
|
stdVo.setIonAbundanceRatio(expand.getIonAbundanceRatio()); |
|
|
|
|
stdVo.setIonAbundanceRatioError(expand.getIonAbundanceRatioError()); |
|
|
|
|
stdVo.setIonAbundanceRatioWithinError(expand.getIonAbundanceRatioWithinError()); |
|
|
|
|
break; // 只取第一个符合条件的扩展数据
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
}); |
|
|
|
|
dataDtos.add(stdVo); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 排序
|
|
|
|
|
list.sort(this.getSortBySampleNo("inVivo")); |
|
|
|
|
// 处理检材样品(Analyte)
|
|
|
|
|
if (map.containsKey("Analyte")) { |
|
|
|
|
List<TestRecordSampleData> analyte = map.get("Analyte"); |
|
|
|
|
analyte.sort(testRecordSampleDataService.getSortBySampleNo()); |
|
|
|
|
|
|
|
|
|
List<TestRecordSampleDataVO> dataVOS = new ArrayList<>(); |
|
|
|
|
for (int i = 0; i < analyte.size(); i++) { |
|
|
|
|
TestRecordSampleData item = analyte.get(i); |
|
|
|
|
TestRecordSampleDataVO vo = new TestRecordSampleDataVO(); |
|
|
|
|
BeanUtils.copyProperties(item, vo); |
|
|
|
|
|
|
|
|
|
List<TestRecordSampleDataExpand> expandList = dataExpandMap.get(item.getId()); |
|
|
|
|
if (expandList != null) { |
|
|
|
|
for (TestRecordSampleDataExpand expand : expandList) { |
|
|
|
|
if (!expand.getBasePeak()) { |
|
|
|
|
vo.setIonAbundanceRatio(expand.getIonAbundanceRatio()); |
|
|
|
|
vo.setIonAbundanceRatioError(expand.getIonAbundanceRatioError()); |
|
|
|
|
vo.setIonAbundanceRatioWithinError(expand.getIonAbundanceRatioWithinError()); |
|
|
|
|
break; // 只取第一个符合条件的扩展数据
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 重新命名样品
|
|
|
|
|
if (list.size() == 1) { |
|
|
|
|
list.get(0).setSampleName("检材样品"); |
|
|
|
|
} else { |
|
|
|
|
for (int i = 0; i < list.size(); i++) { |
|
|
|
|
list.get(i).setSampleName((i + 1) + "号检材样品"); |
|
|
|
|
// 重新命名样品
|
|
|
|
|
vo.setName((analyte.size() == 1) ? "检材样品" : (i + 1) + "号检材样品"); |
|
|
|
|
dataVOS.add(vo); |
|
|
|
|
} |
|
|
|
|
dataDtos.addAll(dataVOS); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
dataDtos.addAll(list); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// 返回处理后的数据
|
|
|
|
|
data.put("dataDtos", dataDtos); |
|
|
|
|
data.put("sampleSize", dataDtos.size()); |
|
|
|
|
data.put("inspectOpinion", this.buildInspectOpinion(dataList)); |
|
|
|
|
return data; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 根据委托信息和样本类型生成生物样本检验记录文件。 |
|
|
|
|
* |
|
|
|
|
* @param entrustInfo 委托信息对象 |
|
|
|
|
* @param entrustInfo 委托信息对象 |
|
|
|
|
* @param materialType 样本类型(如"毛发"、"尿液"等) |
|
|
|
|
* @return 生成的生物样本检验记录文件的路径 |
|
|
|
|
* @throws Exception 如果文件生成过程中出现错误,抛出异常 |
|
|
|
|
*/ |
|
|
|
|
public String createInVivoFile(EntrustInfo entrustInfo, String materialType) throws Exception { |
|
|
|
|
public String buildInVivoDocFile(EntrustInfo entrustInfo, String materialType) throws Exception { |
|
|
|
|
// 获取文件数据map
|
|
|
|
|
Map<String, Object> data = this.invivoRecord(entrustInfo, materialType); |
|
|
|
|
Map<String, Object> data = this.buildInVivoRecordData(entrustInfo, materialType); |
|
|
|
|
// 调用模板生成检验记录
|
|
|
|
|
String templatePath = ""; |
|
|
|
|
if (materialType.equals("毛发")) { |
|
|
|
@ -203,10 +246,10 @@ public class InspectRecordServiceImpl implements InspectRecordService { |
|
|
|
|
/** |
|
|
|
|
* 根据委托信息、模板路径、配置和数据构建文档文件并上传到OSS |
|
|
|
|
* |
|
|
|
|
* @param entrustId 委托id |
|
|
|
|
* @param entrustId 委托id |
|
|
|
|
* @param templatePath 模板文件路径 |
|
|
|
|
* @param config 配置信息 |
|
|
|
|
* @param data 要填充到模板中的数据 |
|
|
|
|
* @param config 配置信息 |
|
|
|
|
* @param data 要填充到模板中的数据 |
|
|
|
|
* @return 上传后的文件路径 |
|
|
|
|
* @throws Exception 可能抛出的异常 |
|
|
|
|
*/ |
|
|
|
@ -238,44 +281,6 @@ public class InspectRecordServiceImpl implements InspectRecordService { |
|
|
|
|
return path; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public Comparator getSortBySampleNo(String type) { |
|
|
|
|
|
|
|
|
|
if (type.equals("inVivo")) { |
|
|
|
|
Comparator<HairSewageDataDto> comparator = Comparator.comparing( |
|
|
|
|
HairSewageDataDto::getSampleNo, |
|
|
|
|
(a, b) -> { |
|
|
|
|
String[] partsA = a.split("-"); |
|
|
|
|
String[] partsB = b.split("-"); |
|
|
|
|
|
|
|
|
|
// 逐部分比较数值
|
|
|
|
|
for (int i = 0; i < 3; i++) { |
|
|
|
|
int numA = Integer.parseInt(partsA[i]); |
|
|
|
|
int numB = Integer.parseInt(partsB[i]); |
|
|
|
|
if (numA != numB) return Integer.compare(numA, numB); |
|
|
|
|
} |
|
|
|
|
return 0; // 所有部分相同
|
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
return comparator; |
|
|
|
|
} else { |
|
|
|
|
Comparator<NPSCaseTestDataDto> comparator = Comparator.comparing( |
|
|
|
|
NPSCaseTestDataDto::getSampleNo, |
|
|
|
|
(a, b) -> { |
|
|
|
|
String[] partsA = a.split("-"); |
|
|
|
|
String[] partsB = b.split("-"); |
|
|
|
|
|
|
|
|
|
// 逐部分比较数值
|
|
|
|
|
for (int i = 0; i < 3; i++) { |
|
|
|
|
int numA = Integer.parseInt(partsA[i]); |
|
|
|
|
int numB = Integer.parseInt(partsB[i]); |
|
|
|
|
if (numA != numB) return Integer.compare(numA, numB); |
|
|
|
|
} |
|
|
|
|
return 0; // 所有部分相同
|
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
return comparator; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 生成常规毒品的检验记录(贵阳禁毒) |
|
|
|
@ -330,6 +335,8 @@ public class InspectRecordServiceImpl implements InspectRecordService { |
|
|
|
|
data.put("inspectMonth", testRecord.getTestStartDate().getMonthValue()); |
|
|
|
|
data.put("inspectDay", testRecord.getTestStartDate().getDayOfMonth()); |
|
|
|
|
|
|
|
|
|
data.put("acceptNo", entrustInfo.getAcceptNo()); |
|
|
|
|
|
|
|
|
|
// 检材性状描述和检验要求成分
|
|
|
|
|
List<SampleInfo> sampleInfoList = getSampleInfosByMaterialType(entrustInfo, materialType); |
|
|
|
|
String materialCharacterDesc = buildMaterialCharacterDesc(sampleInfoList); |
|
|
|
@ -384,7 +391,7 @@ public class InspectRecordServiceImpl implements InspectRecordService { |
|
|
|
|
/** |
|
|
|
|
* 根据委托信息和检材类型获取检材信息列表 |
|
|
|
|
* |
|
|
|
|
* @param entrustInfo 委托信息对象 |
|
|
|
|
* @param entrustInfo 委托信息对象 |
|
|
|
|
* @param materialType 检材类型, 毛发或尿液 |
|
|
|
|
* @return 检材信息列表 |
|
|
|
|
*/ |
|
|
|
@ -449,4 +456,127 @@ public class InspectRecordServiceImpl implements InspectRecordService { |
|
|
|
|
return String.join(";", descriptions) + "。"; // 用分号连接不同类型的描述
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public String buildInspectOpinion(List<TestRecordSampleData> dataList) { |
|
|
|
|
// 1. 检查输入的dataList是否为空,如果为空直接返回当前数据。
|
|
|
|
|
if (dataList == null || dataList.isEmpty()) { |
|
|
|
|
return ""; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 2. 初始化数据结构,用于分类和记录检出与未检出的物质
|
|
|
|
|
// - detectedMap 用来存储检出物质的样本信息,key为样本编号,value为检出的物质列表
|
|
|
|
|
// - notDetectedMap 用来存储未检出物质的样本信息,key为样本编号,value为未检出的物质列表
|
|
|
|
|
// - allCompoundNames 用来存储所有物质名称的集合,方便后续处理
|
|
|
|
|
Map<String, List<String>> detectedMap = new LinkedHashMap<>(); |
|
|
|
|
Map<String, List<String>> notDetectedMap = new LinkedHashMap<>(); |
|
|
|
|
Set<String> allCompoundNames = new HashSet<>(); |
|
|
|
|
|
|
|
|
|
// 3. 遍历dataList,按每个样本的检出状态(是否检出)对物质进行分类
|
|
|
|
|
for (TestRecordSampleData record : dataList) { |
|
|
|
|
String sampleNo = record.getSampleNo(); // 获取样本编号
|
|
|
|
|
String compoundName = record.getCompoundName(); // 获取化合物名称
|
|
|
|
|
allCompoundNames.add(compoundName); // 将化合物名称添加到所有化合物名称集合中
|
|
|
|
|
|
|
|
|
|
// 根据isDetected值将物质添加到相应的Map中
|
|
|
|
|
if (record.getIsDetected() == 1) { |
|
|
|
|
detectedMap.computeIfAbsent(sampleNo, k -> new ArrayList<>()).add(compoundName); // 如果检出,将物质加入到检测的Map中
|
|
|
|
|
} else { |
|
|
|
|
notDetectedMap.computeIfAbsent(sampleNo, k -> new ArrayList<>()).add(compoundName); // 如果未检出,将物质加入到未检测的Map中
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 4. 定义一个lambda函数,提取样本编号中的流水号(例如:"S001" -> "1号")
|
|
|
|
|
// 目的是生成以“号”结尾的样本编号格式。
|
|
|
|
|
Function<String, String> extractSampleNumber = sampleNo -> sampleNo.substring(sampleNo.lastIndexOf('-') + 1) + "号"; |
|
|
|
|
|
|
|
|
|
// 5. 处理“检出”数据
|
|
|
|
|
// 先根据样本编号分组相同的检出物质,之后生成相应的语句描述
|
|
|
|
|
List<String> detectedSentences = new ArrayList<>(); // 存储“检出”物质的描述
|
|
|
|
|
Map<Set<String>, List<String>> groupedDetectedSamples = new LinkedHashMap<>(); // 用来存储按物质分组的样本编号
|
|
|
|
|
|
|
|
|
|
// 遍历检测到的物质,将相同物质的样本编号进行分组
|
|
|
|
|
for (Map.Entry<String, List<String>> entry : detectedMap.entrySet()) { |
|
|
|
|
Set<String> compoundSet = new HashSet<>(entry.getValue()); // 去重,保证每个物质只记录一次
|
|
|
|
|
groupedDetectedSamples.computeIfAbsent(compoundSet, k -> new ArrayList<>()).add(extractSampleNumber.apply(entry.getKey())); // 根据物质的组合来分组样本编号
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 遍历每个分组,生成对应的描述
|
|
|
|
|
for (Map.Entry<Set<String>, List<String>> entry : groupedDetectedSamples.entrySet()) { |
|
|
|
|
String sampleNumbers = String.join("、", entry.getValue()); // 将所有样本编号合并为字符串
|
|
|
|
|
String compounds = String.join("、", entry.getKey()); // 将所有检出的物质合并为字符串
|
|
|
|
|
|
|
|
|
|
// 如果多个样本检出相同的物质,描述中使用“均检出”,否则使用“检出”
|
|
|
|
|
if (entry.getValue().size() > 1) { |
|
|
|
|
detectedSentences.add(String.format("从%s检材样品中均检出%s成分", sampleNumbers, compounds)); // 多个样本检出
|
|
|
|
|
} else { |
|
|
|
|
detectedSentences.add(String.format("从%s检材样品中检出%s成分", sampleNumbers, compounds)); // 单个样本检出
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 6. 处理“未检出”数据
|
|
|
|
|
// 先根据未检出的物质及样本编号进行分组,然后生成相应的描述
|
|
|
|
|
List<String> notDetectedSentences = new ArrayList<>(); // 存储“未检出”物质的描述
|
|
|
|
|
Map<Set<String>, List<String>> groupedNotDetectedSamples = new LinkedHashMap<>(); // 用来存储按物质分组的样本编号
|
|
|
|
|
|
|
|
|
|
// 遍历未检出的物质,找到未检出的样本并将其分组
|
|
|
|
|
for (Map.Entry<String, List<String>> entry : notDetectedMap.entrySet()) { |
|
|
|
|
String sampleNo = entry.getKey(); // 获取样本编号
|
|
|
|
|
if (detectedMap.containsKey(sampleNo)) { |
|
|
|
|
continue; // 如果该样本已经出现在检出组中,跳过,不再处理
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Set<String> compoundSet = new HashSet<>(entry.getValue()); // 获取未检出的物质,去重
|
|
|
|
|
groupedNotDetectedSamples.computeIfAbsent(compoundSet, k -> new ArrayList<>()).add(extractSampleNumber.apply(sampleNo)); // 将未检出的物质分组
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 遍历每个未检出物质的分组,生成描述
|
|
|
|
|
for (Map.Entry<Set<String>, List<String>> entry : groupedNotDetectedSamples.entrySet()) { |
|
|
|
|
String sampleNumbers = String.join("、", entry.getValue()); // 将未检出的样本编号合并为字符串
|
|
|
|
|
String compounds = String.join("、", entry.getKey()); // 将未检出的物质合并为字符串
|
|
|
|
|
|
|
|
|
|
// 如果多个样本未检出相同的物质,描述中使用“均未检出”,否则使用“未检出”
|
|
|
|
|
if (entry.getValue().size() > 1) { |
|
|
|
|
notDetectedSentences.add(String.format("从%s检材样品中均未检出%s成分", sampleNumbers, compounds)); // 多个样本未检出
|
|
|
|
|
} else { |
|
|
|
|
notDetectedSentences.add(String.format("从%s检材样品中未检出%s成分", sampleNumbers, compounds)); // 单个样本未检出
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 7. 将“检出”和“未检出”描述合并到最终结果中
|
|
|
|
|
List<String> finalSentences = new ArrayList<>(detectedSentences); // 先将检出物质的描述加入
|
|
|
|
|
finalSentences.addAll(notDetectedSentences); // 将未检出的描述添加到末尾
|
|
|
|
|
|
|
|
|
|
// 8. 将最终的描述字符串添加到结果数据Map中,字段名为"detectionStr"返回结果
|
|
|
|
|
return String.join(";", finalSentences); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) { |
|
|
|
|
List<TestRecordSampleData> list = Arrays.asList( |
|
|
|
|
new TestRecordSampleData("1", "Sample1", "2025-1-1", "T1", "10", "5", "羟考酮", "0.5", 1.2, 5.5, 5.0, 0, "Analyte", "{}", "{}", 1, "Oxycodone"), |
|
|
|
|
new TestRecordSampleData("2", "Sample1", "2025-1-1", "T1", "10", "4", "海洛因", "0.4", 1.1, 5.4, 5.0, 0, "Analyte", "{}", "{}", 1, "Heroin"), |
|
|
|
|
new TestRecordSampleData("3", "Sample1", "2025-1-1", "T1", "10", "3", "四氢大麻酚", "0.6", 1.3, 5.6, 5.0, 0, "Analyte", "{}", "{}", 1, "THC"), |
|
|
|
|
|
|
|
|
|
new TestRecordSampleData("4", "Sample2", "2025-1-2", "T2", "10", "5", "羟考酮", "0.5", 1.2, 5.5, 5.0, 0, "Analyte", "{}", "{}", 1, "Oxycodone"), |
|
|
|
|
new TestRecordSampleData("5", "Sample2", "2025-1-2", "T2", "10", "4", "海洛因", "0.4", 1.1, 5.4, 5.0, 1, "Analyte", "{}", "{}", 1, "Heroin"), |
|
|
|
|
new TestRecordSampleData("6", "Sample2", "2025-1-2", "T2", "10", "3", "四氢大麻酚", "0.6", 1.3, 5.6, 5.0, 0, "Analyte", "{}", "{}", 1, "THC"), |
|
|
|
|
|
|
|
|
|
new TestRecordSampleData("7", "Sample3", "2025-1-3", "T3", "10", "5", "羟考酮", "0.5", 1.2, 5.5, 5.0, 1, "Analyte", "{}", "{}", 1, "Oxycodone"), |
|
|
|
|
new TestRecordSampleData("8", "Sample3", "2025-1-3", "T3", "10", "4", "海洛因", "0.4", 1.1, 5.4, 5.0, 0, "Analyte", "{}", "{}", 1, "Heroin"), |
|
|
|
|
new TestRecordSampleData("9", "Sample3", "2025-1-3", "T3", "10", "3", "四氢大麻酚", "0.6", 1.3, 5.6, 5.0, 1, "Analyte", "{}", "{}", 1, "THC"), |
|
|
|
|
|
|
|
|
|
new TestRecordSampleData("10", "Sample4", "2025-1-4", "T4", "10", "5", "羟考酮", "0.5", 1.2, 5.5, 5.0, 0, "Analyte", "{}", "{}", 1, "Oxycodone"), |
|
|
|
|
new TestRecordSampleData("11", "Sample4", "2025-1-4", "T4", "10", "4", "海洛因", "0.4", 1.1, 5.4, 5.0, 0, "Analyte", "{}", "{}", 1, "Heroin"), |
|
|
|
|
new TestRecordSampleData("12", "Sample4", "2025-1-4", "T4", "10", "3", "四氢大麻酚", "0.6", 1.3, 5.6, 5.0, 0, "Analyte", "{}", "{}", 1, "THC"), |
|
|
|
|
|
|
|
|
|
new TestRecordSampleData("10", "Sample4", "2025-1-5", "T4", "10", "5", "羟考酮", "0.5", 1.2, 5.5, 5.0, 0, "Analyte", "{}", "{}", 1, "Oxycodone"), |
|
|
|
|
new TestRecordSampleData("11", "Sample4", "2025-1-5", "T4", "10", "4", "海洛因", "0.4", 1.1, 5.4, 5.0, 1, "Analyte", "{}", "{}", 1, "Heroin"), |
|
|
|
|
new TestRecordSampleData("12", "Sample4", "2025-1-5", "T4", "10", "3", "四氢大麻酚", "0.6", 1.3, 5.6, 5.0, 0, "Analyte", "{}", "{}", 1, "THC"), |
|
|
|
|
|
|
|
|
|
new TestRecordSampleData("10", "Sample4", "2025-1-6", "T4", "10", "5", "羟考酮", "0.5", 1.2, 5.5, 5.0, 1, "Analyte", "{}", "{}", 1, "Oxycodone"), |
|
|
|
|
new TestRecordSampleData("11", "Sample4", "2025-1-6", "T4", "10", "4", "海洛因", "0.4", 1.1, 5.4, 5.0, 0, "Analyte", "{}", "{}", 1, "Heroin"), |
|
|
|
|
new TestRecordSampleData("12", "Sample4", "2025-1-6", "T4", "10", "3", "四氢大麻酚", "0.6", 1.3, 5.6, 5.0, 0, "Analyte", "{}", "{}", 1, "THC")); |
|
|
|
|
|
|
|
|
|
String detectionStr = new InspectRecordServiceImpl().buildInspectOpinion(list); |
|
|
|
|
System.out.println(detectionStr); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|