update
This commit is contained in:
@@ -110,7 +110,7 @@ public class EntrustInfoServiceImpl extends ServiceImpl<EntrustInfoMapper, Entru
|
||||
.eq(StringUtils.isNotBlank(entrustInfo.getId()), EntrustInfo::getId, entrustInfo.getId())
|
||||
.like(StringUtils.isNotBlank(entrustInfo.getCaseName()), EntrustInfo::getCaseName, entrustInfo.getCaseName())
|
||||
.eq(entrustInfo.getStatus() != null, EntrustInfo::getStatus, status)
|
||||
.orderByDesc(EntrustInfo::getCreateTime));
|
||||
.last("ORDER BY CAST(SUBSTRING_INDEX(accept_no,'-',1) AS UNSIGNED)DESC,CAST(SUBSTRING_INDEX(accept_no,'-',-1) AS UNSIGNED) DESC"));
|
||||
List<EntrustInfo> records = ret.getRecords();
|
||||
for (EntrustInfo info : records) {
|
||||
List<AssignmentInfo> list = assignmentInfoService.list(Wrappers.<AssignmentInfo>lambdaQuery().eq(AssignmentInfo::getBusinessId, info.getId()));
|
||||
|
||||
@@ -128,22 +128,32 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
System.out.println(String.format("转换为 PDF 结束"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建体内检验记录数据
|
||||
*
|
||||
* @param entrustInfo 委托信息对象
|
||||
* @param materialType 材料类型(如血液、尿液等)
|
||||
* @return 包含体内检验记录的Map数据
|
||||
* @throws Exception 如果未找到检验记录,则抛出异常
|
||||
*/
|
||||
public Map<String, Object> buildInVivoRecordData(EntrustInfo entrustInfo, String materialType) throws Exception {
|
||||
|
||||
// 获取检验记录信息
|
||||
// 1️⃣ 获取当前委托业务对应的检验记录信息
|
||||
TestRecord testRecord = testRecordService.getTestRecordByBusinessId(entrustInfo.getId());
|
||||
|
||||
// 2️⃣ 如果找不到对应的检验记录,则抛出异常
|
||||
if (testRecord == null) {
|
||||
throw new Exception("未找到检验记录信息");
|
||||
}
|
||||
|
||||
// 生成基础数据
|
||||
// 3️⃣ 生成基础数据,构建通用的检验记录文档数据
|
||||
HashMap<String, Object> data = buildCommonInspectRecordDocMap(entrustInfo, testRecord, materialType);
|
||||
|
||||
// 获取样品数据
|
||||
// 4️⃣ 查询该检验记录下的所有样品数据
|
||||
List<TestRecordSampleData> dataList = testRecordSampleDataService.list(
|
||||
Wrappers.<TestRecordSampleData>lambdaQuery().eq(TestRecordSampleData::getTestId, testRecord.getId()));
|
||||
|
||||
// 5️⃣ 如果没有样品数据,则直接返回空数据
|
||||
if (CollectionUtils.isEmpty(dataList)) {
|
||||
data.put("dataDtos", Collections.emptyList());
|
||||
data.put("sampleSize", 0);
|
||||
@@ -151,41 +161,48 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
return data;
|
||||
}
|
||||
|
||||
// 批量查询所有样品扩展数据,避免多次查询数据库
|
||||
// 6️⃣ 批量查询所有样品的扩展数据,避免多次查询数据库,提高效率
|
||||
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));
|
||||
|
||||
// 根据化合物名称分组
|
||||
// 7️⃣ 按化合物名称进行分组,确保同一化合物的数据在一起处理
|
||||
Map<String, List<TestRecordSampleData>> dataMap = dataList.stream()
|
||||
.collect(Collectors.groupingBy(TestRecordSampleData::getCompoundCnName));
|
||||
|
||||
// 8️⃣ 获取标准品列表,并按照其中的化合物顺序进行排序
|
||||
String referenceMaterialName = (String) data.get("referenceMaterialName");
|
||||
List<String> collect = Arrays.stream(referenceMaterialName.split("\n")) // 按换行拆分
|
||||
.map(line -> line.replaceFirst("^\u3000\u3000\u2611 ", "") // 去掉前缀 " ✔ "
|
||||
.replaceFirst("^\u2611 ", "")) // 去掉前缀 "✔ "
|
||||
.collect(Collectors.toList()); // 转换为列表
|
||||
|
||||
// 9️⃣ 用于存储最终的检验数据
|
||||
List<TestRecordSampleDataDocDTO> dataDtos = new ArrayList<>();
|
||||
|
||||
// 遍历化合物组
|
||||
for (Map.Entry<String, List<TestRecordSampleData>> entry : dataMap.entrySet()) {
|
||||
String compoundName = entry.getKey();
|
||||
List<TestRecordSampleData> list = entry.getValue();
|
||||
// 🔟 遍历化合物列表,按照标准品顺序构建数据
|
||||
for (String compoundName : collect) {
|
||||
List<TestRecordSampleData> list = dataMap.get(compoundName);
|
||||
|
||||
// 添加空白数据
|
||||
// 10.1️⃣ 先添加一个空白样品数据
|
||||
TestRecordSampleDataDocDTO blankVo = new TestRecordSampleDataDocDTO();
|
||||
blankVo.setName("空白" + materialType);
|
||||
blankVo.setCompoundName(compoundName);
|
||||
blankVo.setPTargetRtTime("/"); // 设置空值为"/"
|
||||
blankVo.setPRtTimeError("/"); // 设置空值为"/"
|
||||
blankVo.setPRtTimeWithinError("否"); // 默认"否"
|
||||
blankVo.setPIonAbundanceRatio("/"); // 设置空值为"/"
|
||||
blankVo.setPIonAbundanceRatioError("/"); // 设置空值为"/"
|
||||
blankVo.setPIonAbundanceRatioWithinError("否"); // 默认"否"
|
||||
blankVo.setPIsDetected("否"); // 默认"否"
|
||||
blankVo.setPTargetRtTime("/");
|
||||
blankVo.setPRtTimeError("/");
|
||||
blankVo.setPRtTimeWithinError("否");
|
||||
blankVo.setPIonAbundanceRatio("/");
|
||||
blankVo.setPIonAbundanceRatioError("/");
|
||||
blankVo.setPIonAbundanceRatioWithinError("否");
|
||||
blankVo.setPIsDetected("否");
|
||||
dataDtos.add(blankVo);
|
||||
|
||||
// 根据样品类型分组
|
||||
// 10.2️⃣ 按样品类型(STD:标准样品,Analyte:检材样品)分组
|
||||
Map<String, List<TestRecordSampleData>> map = list.stream()
|
||||
.collect(Collectors.groupingBy(TestRecordSampleData::getSampleType));
|
||||
|
||||
// 处理标准样品(STD)
|
||||
// 11️⃣ 处理标准样品(STD)
|
||||
if (map.containsKey("STD")) {
|
||||
TestRecordSampleData std = map.get("STD").get(0);
|
||||
TestRecordSampleDataDocDTO stdVo = new TestRecordSampleDataDocDTO();
|
||||
@@ -196,22 +213,22 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
for (TestRecordSampleDataExpand expand : expandList) {
|
||||
if (!expand.getBasePeak()) {
|
||||
stdVo.setPIonAbundanceRatio(expand.getIonAbundanceRatio() != null ? expand.getIonAbundanceRatio().setScale(2, RoundingMode.HALF_UP).toString() : "/");
|
||||
stdVo.setPIonAbundanceRatioError("/"); // 设置空值为"/"
|
||||
stdVo.setPIonAbundanceRatioWithinError("/"); // 设置空值为"/"
|
||||
stdVo.setPIonAbundanceRatioError("/");
|
||||
stdVo.setPIonAbundanceRatioWithinError("/");
|
||||
break; // 只取第一个符合条件的扩展数据
|
||||
}
|
||||
}
|
||||
}
|
||||
stdVo.setName("空白" + materialType + "加标");
|
||||
stdVo.setPTargetRtTime(std.getTargetRtTime() != null ? String.format("%.2f", std.getTargetRtTime()) : "/");
|
||||
stdVo.setPRtTimeError("/"); // 设置空值为"/"
|
||||
stdVo.setPRtTimeWithinError("/"); // 设置空值为"/"
|
||||
stdVo.setPIsDetected("是"); // 默认"是"
|
||||
stdVo.setPRtTimeError("/");
|
||||
stdVo.setPRtTimeWithinError("/");
|
||||
stdVo.setPIsDetected("是");
|
||||
stdVo.setCompoundName(compoundName);
|
||||
dataDtos.add(stdVo);
|
||||
}
|
||||
|
||||
// 处理检材样品(Analyte)
|
||||
// 12️⃣ 处理检材样品(Analyte)
|
||||
if (map.containsKey("Analyte")) {
|
||||
List<TestRecordSampleData> analyte = map.get("Analyte");
|
||||
analyte.sort(testRecordSampleDataService.getSortBySampleNo());
|
||||
@@ -227,24 +244,7 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
vo.setPRtTimeWithinError(item.getRtTimeWithinError() != null ? item.getRtTimeWithinError().toString() : "/");
|
||||
vo.setPIsDetected(item.getIsDetected() != null && item.getIsDetected() == 1 ? "是" : "否");
|
||||
|
||||
List<TestRecordSampleDataExpand> expandList = dataExpandMap.get(item.getId());
|
||||
if (expandList != null) {
|
||||
for (TestRecordSampleDataExpand expand : expandList) {
|
||||
if (!expand.getBasePeak()) {
|
||||
vo.setPIonAbundanceRatio(expand.getIonAbundanceRatio() != null ? expand.getIonAbundanceRatio().setScale(2, RoundingMode.HALF_UP).toString() : "/");
|
||||
vo.setPIonAbundanceRatioError(expand.getIonAbundanceRatioError() != null ? expand.getIonAbundanceRatioError().setScale(2, RoundingMode.HALF_UP).toString() : "/");
|
||||
vo.setPIonAbundanceRatioWithinError(expand.getIonAbundanceRatioWithinError() != null ? expand.getIonAbundanceRatioWithinError() : "/");
|
||||
break; // 只取第一个符合条件的扩展数据
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重新命名样品
|
||||
vo.setName((dataList
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(TestRecordSampleData::getSampleNo))
|
||||
.keySet()
|
||||
.size() == 1) ? "检材样品" : (i + 1) + "号检材样品");
|
||||
vo.setName((dataList.stream().collect(Collectors.groupingBy(TestRecordSampleData::getSampleNo)).keySet().size() == 1) ? "检材样品" : (i + 1) + "号检材样品");
|
||||
vo.setCompoundName(compoundName);
|
||||
dataVOS.add(vo);
|
||||
}
|
||||
@@ -252,28 +252,25 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
}
|
||||
}
|
||||
|
||||
// 加入图谱序号值
|
||||
// 13️⃣ 为所有数据项添加序号
|
||||
int indexNum = 1;
|
||||
for (int i = 0; i < dataDtos.size(); i++) {
|
||||
dataDtos.get(i).setIndexNum(String.valueOf(indexNum++));
|
||||
for (TestRecordSampleDataDocDTO dto : dataDtos) {
|
||||
dto.setIndexNum(String.valueOf(indexNum++));
|
||||
}
|
||||
|
||||
this.buildIonPairAndCE(data, testRecordReagentService
|
||||
.list(Wrappers.<TestRecordReagent>lambdaQuery()
|
||||
// 14️⃣ 构建离子对和CE值数据
|
||||
this.buildIonPairAndCE(data, testRecordReagentService.list(
|
||||
Wrappers.<TestRecordReagent>lambdaQuery()
|
||||
.in(TestRecordReagent::getId, testRecord.getReagentConsumablesList())
|
||||
.eq(TestRecordReagent::getCategory, "标准物质"))
|
||||
.stream()
|
||||
.map(item -> item.getId())
|
||||
.collect(Collectors.toList()));
|
||||
.stream().map(TestRecordReagent::getId).collect(Collectors.toList()));
|
||||
|
||||
// 返回处理后的数据
|
||||
// 15️⃣ 返回最终处理的数据
|
||||
data.put("dataDtos", dataDtos);
|
||||
data.put("type", "inVivo");
|
||||
data.put("inspectOpinion", this.buildInspectOpinion(testRecordSampleDataService
|
||||
.lambdaQuery()
|
||||
data.put("type", materialType);
|
||||
data.put("inspectOpinion", this.buildInspectOpinion(testRecordSampleDataService.lambdaQuery()
|
||||
.eq(TestRecordSampleData::getTestId, testRecord.getId())
|
||||
.eq(TestRecordSampleData::getSampleType, "Analyte")
|
||||
.list()));
|
||||
.eq(TestRecordSampleData::getSampleType, "Analyte").list()));
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -425,116 +422,163 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
// 9️⃣ 返回处理后的数据
|
||||
data.put("dataDtos", dataDtos);
|
||||
data.put("sampleSize", dataDtos.size());
|
||||
data.put("type", "inVitro");
|
||||
|
||||
try {
|
||||
Map<Integer, List<TestRecordSampleData>> isDetectedMap = testRecordSampleDataService
|
||||
.lambdaQuery()
|
||||
.eq(TestRecordSampleData::getTestId, testRecord.getId())
|
||||
.eq(TestRecordSampleData::getSampleType, "Analyte")
|
||||
.list()
|
||||
.stream()
|
||||
.filter(Objects::nonNull) // 避免空值
|
||||
.collect(Collectors.groupingBy(TestRecordSampleData::getIsDetected));
|
||||
|
||||
List<String> isDetectedStrs = new ArrayList<>();
|
||||
List<String> notDetectedStrs = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<Integer, List<TestRecordSampleData>> entry : isDetectedMap.entrySet()) {
|
||||
if (entry.getKey() != null && entry.getValue() != null && !entry.getValue().isEmpty()) {
|
||||
List<TestRecordSampleData> value = entry.getValue();
|
||||
Map<String, List<TestRecordSampleData>> map = value.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(item -> item.getCompoundName() != null && item.getSampleNo() != null)
|
||||
.collect(Collectors.groupingBy(TestRecordSampleData::getCompoundCnName));
|
||||
|
||||
for (Map.Entry<String, List<TestRecordSampleData>> listEntry : map.entrySet()) {
|
||||
if (listEntry.getKey() != null && listEntry.getValue() != null && !listEntry.getValue().isEmpty()) {
|
||||
List<TestRecordSampleData> entryValue = listEntry.getValue();
|
||||
entryValue.sort(testRecordSampleDataService.getSortBySampleNo());
|
||||
|
||||
String collect = entryValue.stream()
|
||||
.map(item -> {
|
||||
String[] parts = item.getSampleNo().split("-");
|
||||
return (parts.length > 2) ? parts[2] + "号" : item.getSampleNo(); // 预防数组越界
|
||||
})
|
||||
.collect(Collectors.joining("、"));
|
||||
|
||||
String description;
|
||||
if (entry.getKey() == 1) {
|
||||
description = "☑ " + collect + "样品空白对照无干扰,在相同条件下进行测定时,样品溶液中目标物与浓度相近的标准工作溶液中的目标物相比,色谱峰保留时间一致、质谱特征离子一致,各离子丰度比相对偏差符合规定范围,判定样品中检出" + listEntry.getKey() + "。";
|
||||
isDetectedStrs.add(description);
|
||||
} else {
|
||||
description = "☑ " + collect + "样品空白对照无干扰,样品溶液中未检出符合阳性结果评价要求的色谱峰,标准溶液空白无干扰,判定样品中为未检出" + listEntry.getKey() + "。";
|
||||
notDetectedStrs.add(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDetectedStrs.isEmpty()) {
|
||||
data.put("isDetectedStrs", "阳性结果:" + "\n" + isDetectedStrs.stream()
|
||||
.map(item -> "\u3000\u3000" + item)
|
||||
.collect(Collectors.joining("\n")));
|
||||
}
|
||||
if (!notDetectedStrs.isEmpty()) {
|
||||
data.put("notDetectedStrs", "阴性结果:" + "\n" + notDetectedStrs.stream()
|
||||
.map(item -> "\u3000\u3000" + item)
|
||||
.collect(Collectors.joining("\n")));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
// 1️⃣0 添加检测结果与分析结果判定
|
||||
List<TestRecordSampleData> sampleDataList = testRecordSampleDataService
|
||||
.lambdaQuery()
|
||||
.eq(TestRecordSampleData::getTestId, testRecord.getId())
|
||||
.eq(TestRecordSampleData::getSampleType, "Analyte")
|
||||
.list();
|
||||
|
||||
// 添加非空校验,防止传入 `null` 进入 `buildInspectOpinion`
|
||||
data.put("type", "常规毒品");
|
||||
data.put("inspectOpinion", sampleDataList.size() > 0 ? this.buildInspectOpinion(sampleDataList) : "");
|
||||
this.processDetectionResults(data, testRecord);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 📌 处理检测结果并格式化
|
||||
*
|
||||
* @param data 存储检测结果的 Map
|
||||
* @param testRecord 当前检测记录
|
||||
*/
|
||||
public void processDetectionResults(Map<String, Object> data, TestRecord testRecord) {
|
||||
// 查询所有 "Analyte" 类型的样本数据
|
||||
List<TestRecordSampleData> analyteDataList = testRecordSampleDataService
|
||||
.lambdaQuery()
|
||||
.eq(TestRecordSampleData::getTestId, testRecord.getId())
|
||||
.eq(TestRecordSampleData::getSampleType, "Analyte")
|
||||
.list();
|
||||
|
||||
if (analyteDataList.isEmpty()) {
|
||||
return; // 如果没有数据,直接返回
|
||||
}
|
||||
|
||||
// 按 `isDetected` 分组,1 为检出,0 为未检出
|
||||
Map<Integer, List<TestRecordSampleData>> isDetectedMap = analyteDataList.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.groupingBy(TestRecordSampleData::getIsDetected));
|
||||
|
||||
List<String> isDetectedStr = new ArrayList<>();
|
||||
List<String> notDetectedStr = new ArrayList<>();
|
||||
|
||||
// 遍历检测结果,生成描述
|
||||
for (Map.Entry<Integer, List<TestRecordSampleData>> entry : isDetectedMap.entrySet()) {
|
||||
List<TestRecordSampleData> samples = entry.getValue();
|
||||
if (samples == null || samples.isEmpty()) {
|
||||
continue; // 如果样本数据为空,跳过
|
||||
}
|
||||
|
||||
// 按化合物名称分组样本
|
||||
Map<String, List<TestRecordSampleData>> compoundSampleMap = samples.stream()
|
||||
.filter(sample -> sample.getCompoundCnName() != null && sample.getSampleNo() != null)
|
||||
.collect(Collectors.groupingBy(TestRecordSampleData::getCompoundCnName));
|
||||
|
||||
for (Map.Entry<String, List<TestRecordSampleData>> compoundEntry : compoundSampleMap.entrySet()) {
|
||||
String compoundName = compoundEntry.getKey();
|
||||
List<TestRecordSampleData> compoundSamples = compoundEntry.getValue();
|
||||
|
||||
if (compoundSamples == null || compoundSamples.isEmpty()) {
|
||||
continue; // 如果化合物名称或样本为空,跳过
|
||||
}
|
||||
|
||||
// 按 `sampleNo` 排序样本
|
||||
compoundSamples.sort(testRecordSampleDataService.getSortBySampleNo());
|
||||
|
||||
// 拼接样本编号
|
||||
String sampleNos = compoundSamples.stream()
|
||||
.map(sample -> {
|
||||
String[] parts = sample.getSampleNo().split("-");
|
||||
return (parts.length > 2) ? parts[2] + "号" : sample.getSampleNo(); // 防止数组越界
|
||||
})
|
||||
.collect(Collectors.joining("、"));
|
||||
|
||||
// 生成描述
|
||||
String description;
|
||||
if (entry.getKey() == 1) {
|
||||
description = String.format(
|
||||
"☑ %s样品空白对照无干扰,在相同条件下进行测定时,样品溶液中目标物与浓度相近的标准工作溶液中的目标物相比," +
|
||||
"色谱峰保留时间一致、质谱特征离子一致,各离子丰度比相对偏差符合规定范围,判定样品中检出%s。",
|
||||
sampleNos, compoundName);
|
||||
isDetectedStr.add(description);
|
||||
} else {
|
||||
description = String.format(
|
||||
"☑ %s样品空白对照无干扰,样品溶液中未检出符合阳性结果评价要求的色谱峰,标准溶液空白无干扰,判定样品中未检出%s。",
|
||||
sampleNos, compoundName);
|
||||
notDetectedStr.add(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 将阳性结果和阴性结果放入数据 Map 中
|
||||
if (!isDetectedStr.isEmpty()) {
|
||||
data.put("isDetectedStrs", "阳性结果:" + "\n" + isDetectedStr.stream()
|
||||
.map(item -> " " + item) // 使用全角空格缩进
|
||||
.collect(Collectors.joining("\n")));
|
||||
}
|
||||
if (!notDetectedStr.isEmpty()) {
|
||||
data.put("notDetectedStrs", "阴性结果:" + "\n" + notDetectedStr.stream()
|
||||
.map(item -> " " + item) // 使用全角空格缩进
|
||||
.collect(Collectors.joining("\n")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 📌 构建离子对和碰撞能量信息,并存入数据 Map
|
||||
*
|
||||
* @param data 存储结果的 Map
|
||||
* @param reagentIdList 试剂 ID 列表
|
||||
*/
|
||||
public void buildIonPairAndCE(Map<String, Object> data, List<String> reagentIdList) {
|
||||
List<IonPairAndCEVO> ionPairAndCEVOS = new ArrayList<>();
|
||||
|
||||
// 遍历 reagentIdList
|
||||
// 🔄 遍历 reagentIdList 获取试剂信息
|
||||
for (String id : reagentIdList) {
|
||||
TestRecordReagentVO vo = testRecordReagentService.getVOById(id);
|
||||
if (vo == null) {
|
||||
continue; // 如果 vo 为空,跳过当前循环
|
||||
continue; // ⏭️ 如果 vo 为空,跳过当前循环
|
||||
}
|
||||
|
||||
Drug drug = vo.getDrug();
|
||||
if (drug == null) {
|
||||
continue; // 如果 drug 为空,跳过当前循环
|
||||
continue; // ⏭️ 如果 drug 为空,跳过当前循环
|
||||
}
|
||||
|
||||
// 添加 ionPairAndCEVO1 和 ionPairAndCEVO2
|
||||
// 📌 创建主产物离子信息并添加到列表
|
||||
ionPairAndCEVOS.add(createIonPairAndCEVO(drug.getName(), drug.getMainProductIon(),
|
||||
drug.getMainDeclusteringPotential(), drug.getMainCollisionEnergy()));
|
||||
|
||||
// 📌 创建次产物离子信息并添加到列表
|
||||
ionPairAndCEVOS.add(createIonPairAndCEVO(drug.getName(), drug.getMinorProductIon(),
|
||||
drug.getMinorDeclusteringPotential(), drug.getMinorCollisionEnergy()));
|
||||
}
|
||||
|
||||
// 将结果放入数据 map 中
|
||||
// 📌 将结果放入数据 map 中,供后续使用
|
||||
data.put("ionPairAndCEVOS", ionPairAndCEVOS);
|
||||
data.put("ionPairAndCEVOSize", ionPairAndCEVOS.size() / 2);
|
||||
}
|
||||
|
||||
|
||||
// 创建 IonPairAndCEVO 对象的辅助方法
|
||||
|
||||
/**
|
||||
* 📌 创建 IonPairAndCEVO 对象并初始化属性
|
||||
*
|
||||
* @param compoundName 化合物名称
|
||||
* @param productIon 产物离子
|
||||
* @param declusteringPotential 去簇电位(DP)
|
||||
* @param collisionEnergy 碰撞能量(CE)
|
||||
* @return 初始化后的 IonPairAndCEVO 对象
|
||||
*/
|
||||
private IonPairAndCEVO createIonPairAndCEVO(String compoundName, String productIon,
|
||||
Integer declusteringPotential, Integer collisionEnergy) {
|
||||
IonPairAndCEVO ionPairAndCEVO = new IonPairAndCEVO();
|
||||
ionPairAndCEVO.setCompoundName(compoundName);
|
||||
ionPairAndCEVO.setProductIon(productIon);
|
||||
ionPairAndCEVO.setDeclusteringPotential(declusteringPotential);
|
||||
ionPairAndCEVO.setCollisionEnergy(collisionEnergy);
|
||||
return ionPairAndCEVO;
|
||||
ionPairAndCEVO.setCompoundName(compoundName); // 设置化合物名称
|
||||
ionPairAndCEVO.setProductIon(productIon); // 设置产物离子
|
||||
ionPairAndCEVO.setDeclusteringPotential(declusteringPotential); // 设置去簇电位(DP)
|
||||
ionPairAndCEVO.setCollisionEnergy(collisionEnergy); // 设置碰撞能量(CE)
|
||||
return ionPairAndCEVO; // 返回创建的对象
|
||||
}
|
||||
|
||||
|
||||
@@ -556,7 +600,6 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
} else {
|
||||
templatePath = "/template" + "/贵阳生物样本尿液检验记录模板.docx";
|
||||
}
|
||||
System.out.println(data);
|
||||
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
|
||||
Configure config = Configure.builder().
|
||||
bind("dataDtos", policy)
|
||||
@@ -565,106 +608,134 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据委托信息、模板路径、配置和数据构建文档文件并上传到OSS
|
||||
* 📄 构建 Word 文档并上传至 OSS
|
||||
*
|
||||
* @param entrustId 委托id
|
||||
* @param entrustId 委托 ID
|
||||
* @param templatePath 模板文件路径
|
||||
* @param config 配置信息
|
||||
* @param data 要填充到模板中的数据
|
||||
* @return 上传后的文件路径
|
||||
* @param config 配置对象
|
||||
* @param data 数据映射
|
||||
* @return 上传到 OSS 的文件路径
|
||||
* @throws Exception 可能抛出的异常
|
||||
*/
|
||||
private String buildDocFileAndUploadToOss(String entrustId, String templatePath, Configure config, Map<String, Object> data) throws Exception {
|
||||
// 📌 读取模板文件
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ossFile.fileGet(templatePath, bos);
|
||||
byte[] templateArray = bos.toByteArray();
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(templateArray);
|
||||
bos.close();
|
||||
|
||||
try (ByteArrayInputStream bis = new ByteArrayInputStream(templateArray);
|
||||
ByteArrayOutputStream fosWord = new ByteArrayOutputStream()) {
|
||||
|
||||
// 📌 渲染模板数据
|
||||
XWPFTemplate template = XWPFTemplate.compile(bis, config).render(data);
|
||||
NiceXWPFDocument document = template.getXWPFDocument();
|
||||
List<XWPFTable> tables = document.getTables();
|
||||
|
||||
// 📌 读取数据类型并安全处理
|
||||
String type = (String) data.getOrDefault("type", ""); // 避免空指针
|
||||
XWPFTable table = tables.get(tables.size() - 1); // 获取最后一个表格
|
||||
|
||||
if ("常规毒品".equals(type)) {
|
||||
mergeRegularDrugTable(table);
|
||||
} else if ("尿液".equals(type) || "毛发".equals(type)) {
|
||||
mergeNonRegularDrugTable(table);
|
||||
mergeAdditionalTable(type, tables);
|
||||
}
|
||||
|
||||
String type = (String) data.get("type");
|
||||
// 📌 写入文档流
|
||||
template.write(fosWord);
|
||||
template.close();
|
||||
document.close();
|
||||
|
||||
if (StringUtils.isNotBlank(type) && type.equals("inVitro")) {
|
||||
int startRow = 1; // 从第二行开始(表头是第一行,索引从0开始)
|
||||
// **处理合并单元格**
|
||||
int mergeStep = 4; // 每4行合并一次
|
||||
int[] mergeColumns = {0, 1, 2, 3, 4, 9}; // 合并的列:第1、2、3、4、5、10列,索引分别是 0, 1, 2, 3, 4, 9
|
||||
// 📌 构建文件存储路径
|
||||
ByteArrayInputStream fisWord = new ByteArrayInputStream(fosWord.toByteArray());
|
||||
String path = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + entrustId + "/" + "贵阳生物样本检验记录.docx";
|
||||
ossFile.fileSave(path, fisWord);
|
||||
|
||||
return path; // 📌 返回 OSS 文件路径
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 📌 合并常规毒品检验记录检测数据部分表格的单元格
|
||||
*/
|
||||
private void mergeRegularDrugTable(XWPFTable table) {
|
||||
int startRow = 1; // 🔹 从第二行开始(索引从0开始)
|
||||
int mergeStep = 4; // 🔹 每 4 行合并一次
|
||||
int[] mergeColumns = {0, 1, 2, 3, 4, 9}; // 🔹 需要合并的列
|
||||
|
||||
// 遍历表格数据行
|
||||
for (int rowIndex = startRow; rowIndex < table.getNumberOfRows(); rowIndex += mergeStep) {
|
||||
int endRow = Math.min(rowIndex + mergeStep - 1, table.getNumberOfRows() - 1); // 计算合并的终止行,防止越界
|
||||
int endRow = Math.min(rowIndex + mergeStep - 1, table.getNumberOfRows() - 1); // 防止越界
|
||||
for (int col : mergeColumns) {
|
||||
TableTools.mergeCellsVertically(table, col, rowIndex, endRow);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// **处理合并单元格**
|
||||
int startRow = 1; // 从第二行开始(表头是第一行,索引从0开始)
|
||||
}
|
||||
|
||||
/**
|
||||
* 📌 合并生物样本检验记录检测数据部分表格的单元格
|
||||
*/
|
||||
private void mergeNonRegularDrugTable(XWPFTable table) {
|
||||
int startRow = 1;
|
||||
String currentCompoundName = null;
|
||||
int mergeStartRow = -1;
|
||||
|
||||
for (int rowIndex = startRow; rowIndex < table.getNumberOfRows(); rowIndex++) {
|
||||
XWPFTableRow row = table.getRow(rowIndex);
|
||||
XWPFTableCell cell = row.getCell(1); // 获取第二列的单元格(索引1)
|
||||
XWPFTableCell cell = row.getCell(1); // 🔹 第二列(索引1)
|
||||
String compoundName = cell.getText().trim();
|
||||
|
||||
if (currentCompoundName == null || !currentCompoundName.equals(compoundName)) {
|
||||
// 如果当前化合物名称与上一行不同,则结束之前的合并
|
||||
if (!compoundName.equals(currentCompoundName)) {
|
||||
if (mergeStartRow >= 0 && rowIndex > mergeStartRow + 1) {
|
||||
TableTools.mergeCellsVertically(table, 1, mergeStartRow, rowIndex - 1); // 合并第二列(列索引1)
|
||||
TableTools.mergeCellsVertically(table, 1, mergeStartRow, rowIndex - 1);
|
||||
}
|
||||
currentCompoundName = compoundName;
|
||||
mergeStartRow = rowIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理最后一组合并(循环结束后可能残留未合并的区域)
|
||||
// 📌 处理最后一组合并
|
||||
if (mergeStartRow >= 0 && mergeStartRow < table.getNumberOfRows() - 1) {
|
||||
TableTools.mergeCellsVertically(table, 1, mergeStartRow, table.getNumberOfRows() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("总共的表格数量:" + tables.size());
|
||||
XWPFTable xwpfTable = tables.get(2);
|
||||
/**
|
||||
* 📌 处理毛发或尿液表格目标物定性离子对、碰撞能量 (CE)等参数表格的合并逻辑
|
||||
* 📌 因为毛发和尿液的配置表格数量不同,因此下标不同
|
||||
*/
|
||||
private void mergeAdditionalTable(String type, List<XWPFTable> tables) {
|
||||
if (!"毛发".equals(type) && !"尿液".equals(type)) {
|
||||
return; // 如果不是毛发或尿液类型,则不处理
|
||||
}
|
||||
|
||||
int tableIndex = "毛发".equals(type) ? 2 : 1;
|
||||
if (tables.size() <= tableIndex) {
|
||||
return; // 避免索引越界
|
||||
}
|
||||
|
||||
XWPFTable xwpfTable = tables.get(tableIndex);
|
||||
List<XWPFTableRow> rows = xwpfTable.getRows();
|
||||
|
||||
// 跳过第一行(表头),从第二行开始处理
|
||||
for (int i = 1; i < rows.size() - 1; i++) { // 注意:i 从 1 开始
|
||||
for (int i = 1; i < rows.size() - 1; i++) { // 🔹 从第二行开始
|
||||
XWPFTableRow currentRow = rows.get(i);
|
||||
XWPFTableRow nextRow = rows.get(i + 1);
|
||||
|
||||
// 获取当前行和下一行的化合物名称
|
||||
String currentCompoundName = currentRow.getCell(0).getText().trim();
|
||||
String nextCompoundName = nextRow.getCell(0).getText().trim();
|
||||
|
||||
// 如果当前行和下一行的化合物名称相同,则合并它们的第一列
|
||||
if (currentCompoundName.equals(nextCompoundName)) {
|
||||
// 合并单元格
|
||||
currentRow.getCell(0).getCTTc().addNewTcPr().addNewVMerge().setVal(org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge.RESTART);
|
||||
nextRow.getCell(0).getCTTc().addNewTcPr().addNewVMerge().setVal(org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge.CONTINUE);
|
||||
// 📌 合并单元格
|
||||
currentRow.getCell(0).getCTTc().addNewTcPr().addNewVMerge()
|
||||
.setVal(org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge.RESTART);
|
||||
nextRow.getCell(0).getCTTc().addNewTcPr().addNewVMerge()
|
||||
.setVal(org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge.CONTINUE);
|
||||
|
||||
// 删除下一行的第一个单元格的内容(可选)
|
||||
// 📌 清空被合并行的内容
|
||||
nextRow.getCell(0).setText("");
|
||||
}
|
||||
}
|
||||
|
||||
bis.close();
|
||||
ByteArrayOutputStream fosWord = new ByteArrayOutputStream();
|
||||
template.write(fosWord);
|
||||
template.close();
|
||||
ByteArrayInputStream fisWord = new ByteArrayInputStream(fosWord.toByteArray());
|
||||
fosWord.close();
|
||||
document.close();
|
||||
|
||||
String path = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + entrustId + "/" + "贵阳生物样本检验记录.docx";
|
||||
ossFile.fileSave(path, fisWord);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
@@ -769,22 +840,23 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
.in(TestRecordReagent::getId, testRecord.getReagentConsumablesList())
|
||||
.eq(TestRecordReagent::getCategory, "标准物质"));
|
||||
|
||||
|
||||
if (references == null || references.isEmpty()) {
|
||||
data.put("referenceMaterialName", "未找到标准物质数据!");
|
||||
} else {
|
||||
|
||||
String referenceMaterialName = "";
|
||||
if (references.size() == 1) {
|
||||
referenceMaterialName = "\u2611" + " " + references.get(0).getReagentConsumableName();
|
||||
} else {
|
||||
TestRecordReagent firstReagent = references.get(0);
|
||||
String firstStr = "\u2611" + " " + references.get(0).getReagentConsumableName() + "\n";
|
||||
references.remove(references.get(0));
|
||||
referenceMaterialName = firstStr + references.stream()
|
||||
.map(reagent -> "\u3000\u3000\u2611" + " " + reagent.getReagentConsumableName())
|
||||
.collect(Collectors.joining("\n"));
|
||||
references.add(0, firstReagent);
|
||||
}
|
||||
data.put("referenceMaterialName", referenceMaterialName);
|
||||
|
||||
data.put("materialIngredient", references.stream()
|
||||
.map(reagent -> reagent.getReagentConsumableName())
|
||||
.collect(Collectors.joining("、")));
|
||||
@@ -896,10 +968,29 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
*/
|
||||
private int extractTailNumber(String orderNo) {
|
||||
String[] parts = orderNo.split("-");
|
||||
if (parts.length > 0) {
|
||||
return Integer.parseInt(parts[parts.length - 1]); // 取最后一段
|
||||
return (parts.length > 0) ? Integer.parseInt(parts[parts.length - 1]) : 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
/**
|
||||
* 对样品编号进行排序
|
||||
*
|
||||
* @param sampleNumbers 样品编号列表,例如 ["3号", "1号", "2号"]
|
||||
* @return 排序后的样品编号列表,例如 ["1号", "2号", "3号"]
|
||||
*/
|
||||
private List<String> sortSampleNumbers(List<String> sampleNumbers) {
|
||||
return sampleNumbers.stream()
|
||||
.sorted(Comparator.comparingInt(this::extractNumber))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 从样品编号中提取数值部分
|
||||
*
|
||||
* @param sampleNumber 样品编号,例如 "12号"
|
||||
* @return 提取出的数字,例如 12
|
||||
*/
|
||||
private int extractNumber(String sampleNumber) {
|
||||
return sampleNumber.matches("\\d+号") ? Integer.parseInt(sampleNumber.replace("号", "")) : Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -907,48 +998,74 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
* - 单个编号:返回 "1号"
|
||||
* - 连续编号:返回 "1号至3号"
|
||||
*
|
||||
* @param start 起始编号
|
||||
* @param end 结束编号
|
||||
* @return 格式化的编号字符串(如果 start == end,返回单号)
|
||||
* @param sortedSampleNumbers 已排序的样品编号列表
|
||||
* @return 格式化的编号字符串
|
||||
*/
|
||||
private String formatRange(int start, int end) {
|
||||
return (start == end) ? start + "号" : start + "号至" + end + "号";
|
||||
}
|
||||
|
||||
|
||||
private String formatSampleNumbers(List<String> sampleNumbers) {
|
||||
List<Integer> numbers = sampleNumbers.stream()
|
||||
private String formatSampleNumbers(List<String> sortedSampleNumbers) {
|
||||
List<Integer> numbers = sortedSampleNumbers.stream()
|
||||
.map(s -> s.replace("号", "")) // 移除"号"字
|
||||
.map(Integer::parseInt) // 转换为整数
|
||||
.sorted() // 排序
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (numbers.size() > 1 && numbers.get(numbers.size() - 1) - numbers.get(0) == numbers.size() - 1) {
|
||||
return numbers.get(0) + "至" + numbers.get(numbers.size() - 1) + "号";
|
||||
List<String> formattedList = new ArrayList<>();
|
||||
int start = numbers.get(0), prev = start;
|
||||
|
||||
for (int i = 1; i < numbers.size(); i++) {
|
||||
int current = numbers.get(i);
|
||||
if (current != prev + 1) {
|
||||
formattedList.add(formatRange(start, prev));
|
||||
start = current;
|
||||
}
|
||||
prev = current;
|
||||
}
|
||||
formattedList.add(formatRange(start, prev));
|
||||
|
||||
return String.join("、", formattedList);
|
||||
}
|
||||
|
||||
return String.join("、", sampleNumbers);
|
||||
/**
|
||||
* 生成编号范围的字符串
|
||||
*
|
||||
* @param start 起始编号
|
||||
* @param end 结束编号
|
||||
* @return 生成的范围字符串,例如 "1号至3号" 或 "5号"
|
||||
*/
|
||||
private String formatRange(int start, int end) {
|
||||
return (start == end) ? start + "号" : start + "号至" + end + "号";
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建检测意见,根据样品的检出与未检出情况,生成描述性文本。
|
||||
*
|
||||
* @param dataList 检测记录数据列表,每个对象包含样品编号、化合物名称及是否检出标识
|
||||
* @return 格式化的检测意见字符串
|
||||
*/
|
||||
public String buildInspectOpinion(List<TestRecordSampleData> dataList) {
|
||||
// 1. **处理空数据情况**
|
||||
if (dataList == null || dataList.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
Map<String, List<String>> detectedMap = new LinkedHashMap<>();
|
||||
Map<String, List<String>> notDetectedMap = new LinkedHashMap<>();
|
||||
Set<String> allCompoundNames = new HashSet<>();
|
||||
// 2. **定义存储结构**
|
||||
Map<String, List<String>> detectedMap = new LinkedHashMap<>(); // 记录检出化合物的样品编号映射(样品编号 -> 该样品检出的化合物列表)
|
||||
Map<String, List<String>> notDetectedMap = new LinkedHashMap<>(); // 记录未检出化合物的样品编号映射(样品编号 -> 该样品未检出的化合物列表)
|
||||
Set<String> allCompoundNames = new HashSet<>(); // 存储所有涉及的化合物名称(用于后续分析)
|
||||
|
||||
// 3. **遍历数据列表,整理样品的检出与未检出情况**
|
||||
for (TestRecordSampleData record : dataList) {
|
||||
String sampleNo = record.getSampleNo();
|
||||
String compoundName = record.getCompoundCnName();
|
||||
String sampleNo = record.getSampleNo(); // 样品编号
|
||||
String compoundName = record.getCompoundCnName(); // 化合物名称
|
||||
|
||||
// **跳过无效数据**
|
||||
if (sampleNo == null || compoundName == null || sampleNo.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// **记录化合物名称**
|
||||
allCompoundNames.add(compoundName);
|
||||
|
||||
// **分类存储检出与未检出数据**
|
||||
if (record.getIsDetected() != null && record.getIsDetected() == 1) {
|
||||
detectedMap.computeIfAbsent(sampleNo, k -> new ArrayList<>()).add(compoundName);
|
||||
} else {
|
||||
@@ -956,56 +1073,70 @@ public class InspectRecordServiceImpl implements InspectRecordService {
|
||||
}
|
||||
}
|
||||
|
||||
// 4. **定义样品编号格式化方法**
|
||||
// 目标是将形如 "A12"、"B34" 这样的样品编号转换成 "12号"、"34号"
|
||||
Function<String, String> extractSampleNumber = sampleNo -> sampleNo.matches(".*\\d+")
|
||||
? sampleNo.replaceAll(".*?(\\d+)$", "$1号")
|
||||
? sampleNo.replaceAll(".*?(\\d+)$", "$1号") // 只提取最后的数字并添加 "号"
|
||||
: sampleNo;
|
||||
|
||||
// 5. **构建检出化合物的描述**
|
||||
List<String> detectedSentences = new ArrayList<>();
|
||||
Map<Set<String>, List<String>> groupedDetectedSamples = new LinkedHashMap<>();
|
||||
Map<Set<String>, List<String>> groupedDetectedSamples = new LinkedHashMap<>(); // 用于按相同化合物组合分组样品
|
||||
|
||||
// **分组整理检出样品**
|
||||
for (Map.Entry<String, List<String>> entry : detectedMap.entrySet()) {
|
||||
Set<String> compoundSet = new HashSet<>(entry.getValue());
|
||||
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 = formatSampleNumbers(entry.getValue()); // 这里也应用连续编号格式化
|
||||
String compounds = String.join("、", entry.getKey());
|
||||
List<String> sortedSampleNumbers = sortSampleNumbers(entry.getValue()); // 对样品编号排序
|
||||
String sampleNumbers = formatSampleNumbers(sortedSampleNumbers); // 处理编号连续情况
|
||||
String compounds = String.join("、", entry.getKey()); // 多个化合物用 "、" 连接
|
||||
|
||||
if (entry.getValue().size() > 1) {
|
||||
if (sortedSampleNumbers.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<>();
|
||||
Map<Set<String>, List<String>> groupedNotDetectedSamples = new LinkedHashMap<>(); // 用于按相同化合物组合分组未检出样品
|
||||
|
||||
// **分组整理未检出样品**
|
||||
for (Map.Entry<String, List<String>> entry : notDetectedMap.entrySet()) {
|
||||
String sampleNo = entry.getKey();
|
||||
Set<String> compoundSet = new HashSet<>(entry.getValue());
|
||||
|
||||
// 只有当该样品编号未出现在 detectedMap(即没有检出任何化合物)时,才记录未检出的情况
|
||||
if (!detectedMap.containsKey(sampleNo)) {
|
||||
groupedNotDetectedSamples.computeIfAbsent(compoundSet, k -> new ArrayList<>()).add(extractSampleNumber.apply(sampleNo));
|
||||
}
|
||||
}
|
||||
|
||||
// **遍历分组后的数据,生成描述文本**
|
||||
for (Map.Entry<Set<String>, List<String>> entry : groupedNotDetectedSamples.entrySet()) {
|
||||
String sampleNumbers = formatSampleNumbers(entry.getValue()); // 这里也应用连续编号格式化
|
||||
String compounds = String.join("、", entry.getKey());
|
||||
List<String> sortedSampleNumbers = sortSampleNumbers(entry.getValue()); // 对样品编号排序
|
||||
String sampleNumbers = formatSampleNumbers(sortedSampleNumbers); // 处理编号连续情况
|
||||
String compounds = String.join("、", entry.getKey()); // 多个化合物用 "、" 连接
|
||||
|
||||
if (entry.getValue().size() > 1) {
|
||||
if (sortedSampleNumbers.size() > 1) {
|
||||
notDetectedSentences.add(String.format("从%s检材样品中均未检出%s成分", sampleNumbers, compounds));
|
||||
} else {
|
||||
notDetectedSentences.add(String.format("从%s检材样品中未检出%s成分", sampleNumbers, compounds));
|
||||
}
|
||||
}
|
||||
|
||||
List<String> finalSentences = new ArrayList<>(detectedSentences);
|
||||
finalSentences.addAll(notDetectedSentences);
|
||||
// 7. **最终结果合并**
|
||||
List<String> finalSentences = new ArrayList<>(detectedSentences); // 先添加检出的描述
|
||||
finalSentences.addAll(notDetectedSentences); // 再添加未检出的描述
|
||||
|
||||
// 使用 ";" 连接所有描述,并返回最终的检测意见字符串
|
||||
return String.join(";", finalSentences);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user