@@ -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 i nspectionRecord( String entrustId , String materialType ) throws Exception {
public R buildI nspectionRecord( 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 . getBusiness Type ( ) ) ) {
// 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 , material Type ) , " 生成成功! " ) ;
}
return R . ok ( this . generateCommonDrugInpectRecord ( entrustId ) ) ;
}
/**
* 生成生物样本检验记录数据map
* @param entrustInfo 委托实体信息
*
* @param entrustInfo 委托实体信息
* @param materialType 检材类型
* @return
* @throws Exception
*/
public Map < String , Object > inv ivoRecord( EntrustInfo entrustInfo , String materialType ) throws Exception {
public Map < String , Object > buildInV ivoRecordData ( 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 ( TestR ecordInstrument : : getInstrumentName )
. collect ( Collectors . joining ( " \ n " ) )
) ;
: instruments . stream ( ) . map ( TestRecordInstrument : : getInstrumentName )
. collect ( Coll ect ors . joining ( " \ n " ) ) ) ;
// 获取样品检测 数据
List < HairSewag eDataDto > hairDataDtos = ( List < HairSewageDataDto > ) testRecordSampleDataService
. getSampleTestDataByBusiness ( entrustInfo . getId ( ) ) ;
// 获取样品数据
List < TestRecordSampl eData> 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 > > dataExpand Map = testRecordSampledataExpandService . list (
Wrappers . < TestRecordSampleDataExpand > lambdaQuery ( )
. in ( TestRecordSampleDataExpand : : getTestDataId , dataList . stream ( ) . map ( TestRecordSampleData : : getId ) . collect ( Collectors . toList ( ) ) )
) . stream ( ) . collect ( Collectors . groupingBy ( TestRecordSampleDataExpand : : getTestDataId ) ) ;
List < HairSewageDataDto > dataDtos = new ArrayList < > ( ) ;
// 根据化合物名称分组
Map < String , List < TestRecordSampleData > > dataMap = dataList . stream ( )
. collect ( Collectors . groupingBy ( TestRecordSampleData : : getCompoundName ) ) ;
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 ) - > {
// 添加空白数据
HairSewag eDataDto blankDt o = new HairSewag eDataDto ( ) ;
blankDt o . setSample Name ( " 空白 " ) ;
blankDt o . setCompoundName ( compoundName ) ;
blank Dto. setTmpTargetRtTime ( " / " ) ;
blankDto . setTmpRtTimeError ( " / " ) ;
blankDto . setRtTimeWithinError ( " 否 " ) ;
blankDto . setTmpIonAbundanceRatio ( " / " ) ;
blankDto . setWhetherCheckOut ( " 否 " ) ;
dataDtos . add ( blankDto ) ;
TestRecordSampl eDataVO blankV o = new TestRecordSampl eDataVO ( ) ;
blankV o . setName ( " 空白 " ) ;
blankV o . setCompoundName ( compoundName ) ;
data Dtos . add ( blankVo ) ;
// 处理样品数据
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 ;
}
return false ;
} ) ;
// 排序
list . sort ( this . getSortBySampleNo ( " inVivo " ) ) ;
// 重新命名样品
if ( list . size ( ) = = 1 ) {
list . g et( 0 ) . s etSampleName ( " 检材样品 " ) ;
} else {
for ( int i = 0 ; i < list . size ( ) ; i + + ) {
list . get ( i ) . setSampleName ( ( i + 1 ) + " 号检材样品 " ) ;
// 根据样品类型分组
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 . s etIonAbundanceRatioWithinError ( expand . g etIonAbundanceRatioWithinError ( ) ) ;
break ; // 只取第一个符合条件的扩展数据
}
}
}
dataDtos . add ( stdVo ) ;
}
dataDtos . addAll ( list ) ;
} ) ;
// 处理检材样品( 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 ; // 只取第一个符合条件的扩展数据
}
}
}
// 重新命名样品
vo . setName ( ( analyte . size ( ) = = 1 ) ? " 检材样品 " : ( i + 1 ) + " 号检材样品 " ) ;
dataVOS . add ( vo ) ;
}
dataDtos . addAll ( dataVOS ) ;
}
}
// 返回处理后的数据
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 create InVivoFile( EntrustInfo entrustInfo , String materialType ) throws Exception {
public String build InVivoDoc File( EntrustInfo entrustInfo , String materialType ) throws Exception {
// 获取文件数据map
Map < String , Object > data = this . inv ivoRecord( entrustInfo , materialType ) ;
Map < String , Object > data = this . buildInV ivoRecordData ( 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 ) ;
}
}