diff --git a/dlp-drugtesting-api/pom.xml b/dlp-drugtesting-api/pom.xml new file mode 100644 index 0000000..f812515 --- /dev/null +++ b/dlp-drugtesting-api/pom.xml @@ -0,0 +1,47 @@ + + 4.0.0 + + digital.laboratory.platform + dlp-drugtesting + 2022.10.11-snapshots + + dlp-drugtesting-api + jar + dlp-drugtesting-api + + UTF-8 + + + + + + digital.laboratory.platform + dlp-common-swagger + 2022.10.11-snapshots + + + + digital.laboratory.platform + dlp-common-feign + 2022.10.11-snapshots + + + + digital.laboratory.platform + dlp-common-mybatis + 2022.10.11-snapshots + + + digital.laboratory.platform + dlp-admin-api + 2022.10.11-snapshots + + + junit + junit + 3.8.1 + test + + + diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/EntrustInfo.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/EntrustInfo.java new file mode 100644 index 0000000..79991e7 --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/EntrustInfo.java @@ -0,0 +1,59 @@ +package digital.laboratory.platform.inspetion.api.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/* + *@title EntrustInfo + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 14:58 + */ +@Data +@TableName(value = "b_entrustInfo", autoResultMap = true) +@ApiModel(value = "委托信息", description = "委托信息") +public class EntrustInfo extends BaseEntity { + private String id; + private String businessType;//业务类型 + private String caseName;//案件名称 + private String caseBrief;//案情简要 + private String entrustNo;//委托编号 + private String entrustDepartment;//委托单位 + private String identityDepartment;//鉴定单位 + private String acceptNo;//受理编号 + private LocalDateTime acceptDate;//受理日期 + private String deliver1Name;//送检人姓名 + private String deliver1Phone;//送检人电话 + private String deliver1Position;//送检人职务 + private String deliver1Cert;//证件类型 + private String deliver1No;//证件号码 + private String deliver2Name;//送检人姓名 + private String deliver2Phone;//送检人电话 + private String deliver2Position;//送检人职务 + private String deliver2Cert;//证件类型 + private String deliver2No;//证件号码 + private Integer source;//数据来源 + private String materialType;//检材类别(缴获物和生物样本) + private String entrustRequirement;//鉴定要求,从检材中的鉴定要求提取组合而成 eg:对检材中四氢大麻酚进行定性定量分析,对合成大麻素类物质进行定性分析。 + private Integer status;//0:未分配 1:已分配 2:实验中 3:鉴定完毕 + private String reportReceiveMode; // 文书领取方式 + private String postAddress; // 邮寄地址 + private String synEntrustId;//送检受理系统中的委托ID + @TableField(exist = false) + private String businessTypeName; + @TableField(exist = false) + private Boolean isDistribution;//是否被分配 + + @ApiModelProperty(value="检材数量") + @TableField(exist = false) + private Integer materialNum; + +} diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/IdentificationBookDTO.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/IdentificationBookDTO.java new file mode 100644 index 0000000..713119e --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/IdentificationBookDTO.java @@ -0,0 +1,190 @@ +package digital.laboratory.platform.inspetion.api.entity; + +import lombok.Data; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * @author xy + * @version 1.0 + * @title IdentificationBookDTO 提供给文书系统的数据格式 + * @description + * @create 2024/3/11 10:12 + */ +@Data +public class IdentificationBookDTO { + private EntrustInfo entrustInfo;//委托信息 + private List sampleInfoList;//对应的检材 + private String testMethod;//检验方法 + private String testProcessDes;//检验过程 + private String testResult;//检验结果 + private String testOptUser;//检验人 + private String testStartDate;//检验开始日期 + private String testFinishDate;//检验完成日期 + + // eg:1号检材中未检出四氢大麻酚,检出合成大麻素类物质MDMB-4en-PINACA; + // 2号检材中未检出四氢大麻酚,检出合成大麻素类物质MDMB-4en-PINACA。 + + private static String getNumberByMaterialNo(String materialNo){ + Pattern pattern = Pattern.compile("\\d+"); + + Matcher matcher = pattern.matcher(materialNo); + + while (matcher.find()) { + return matcher.group(0); + } + return ""; + } + public static void main(String[] args) { + List sampleList=new ArrayList<>(); + TestResult t1=new TestResult(); + t1.setMaterialNo("1号"); + t1.setCompoundName("化合物1"); + t1.setIsFind(1); + t1.setOrderNo(1); + TestResult t2=new TestResult(); + t2.setMaterialNo("1号"); + t2.setCompoundName("化合物2"); + t2.setIsFind(1); + t2.setOrderNo(1); + TestResult t3=new TestResult(); + t3.setMaterialNo("1号"); + t3.setCompoundName("化合物3"); + t3.setIsFind(0); + t3.setOrderNo(1); + sampleList.add(t1); + sampleList.add(t2); + sampleList.add(t3); + TestResult t4=new TestResult(); + t4.setMaterialNo("2号"); + t4.setCompoundName("化合物1"); + t4.setIsFind(0); + t4.setOrderNo(2); + TestResult t5=new TestResult(); + t5.setMaterialNo("2号"); + t5.setCompoundName("化合物2"); + t5.setIsFind(0); + t5.setOrderNo(2); + TestResult t6=new TestResult(); + t6.setMaterialNo("2号"); + t6.setCompoundName("化合物3"); + t6.setIsFind(1); + t6.setOrderNo(2); + sampleList.add(t4); + sampleList.add(t5); + sampleList.add(t6); + + TestResult t7=new TestResult(); + t7.setMaterialNo("3号"); + t7.setCompoundName("化合物1"); + t7.setIsFind(0); + t7.setOrderNo(3); + TestResult t8=new TestResult(); + t8.setMaterialNo("3号"); + t8.setCompoundName("化合物2"); + t8.setIsFind(0); + t8.setOrderNo(3); + TestResult t9=new TestResult(); + t9.setMaterialNo("3号"); + t9.setCompoundName("化合物3"); + t9.setIsFind(1); + t9.setOrderNo(3); + sampleList.add(t7); + sampleList.add(t8); + sampleList.add(t9); + + //按照检材编号先分组,这样的话,如果有n个检材,m个化合物,那么就会分成n组,每组中就m条数据 + Map> collectMap = sampleList.stream().collect(Collectors.groupingBy(m -> m.getMaterialNo())); + //我们把每组中的List 数据再次分组,分组按检出和未检出分,这样就会得到2个组,一个组是检出的,一个组是未检出的 + Map>> ret=new HashMap<>(); + collectMap.forEach((k,v)->{ + Map> tmp1Map= v.stream().collect(Collectors.groupingBy(m -> m.getIsFind())); + ret.put(k,tmp1Map); + }); + + //将3条合并为一条 + //将检出和未检出合并成一条,创建一个对象来存储 + List testResultDetailList=new ArrayList<>(); + ret.forEach((k,v)->{ + StringBuffer sb1=new StringBuffer(); + StringBuffer sb2=new StringBuffer(); + v.forEach((k1,v1)->{ + //这个map中只有2个值,第一个表示未检出的化合物,第2个表示检出的化合物 + if(k1==0){ + //未检出 + v1.forEach(item->{ + sb1.append(item.getCompoundName()).append(","); + }); + } + if(k1==1){ + //检出 + v1.forEach(item->{ + sb2.append(item.getCompoundName()).append(","); + }); + } + }); + if(sb1.length()>0){ + sb1.delete(sb1.length()-1,sb1.length());//删除最后一个 , + } + if(sb2.length()>0){ + sb2.delete(sb2.length()-1,sb2.length());//删除最后一个 , + } + // + TestResultDetail eg=new TestResultDetail(); + eg.setMaterialNo(k); + eg.setFindCompounds(sb2.toString()); + eg.setNoFindCompounds(sb1.toString()); + testResultDetailList.add(eg); + }); + testResultDetailList.forEach(item->{ + String str1=item.getMaterialNo()+"检材中检出了"+item.getFindCompounds(); + String str2=item.getMaterialNo()+"检材中未检出"+item.getNoFindCompounds(); + System.out.println(str1); + System.out.println(str2); + System.out.println("-----------------------------"); + }); + //现在对上面的数据进行从新分组,按检出+化合物的形式 + Map> temp2 = testResultDetailList.stream().collect( + Collectors.groupingBy(m -> m.getFindCompounds() + m.getNoFindCompounds())); + //这里需要排一个序,检材编号小的应该放在前面,大的放在后面,所以使用values中的值来给map进行排序 + List>> targetList=new ArrayList>>(temp2.entrySet()); + targetList.sort(new Comparator>>() { + @Override + public int compare(Map.Entry> mp1, Map.Entry> mp2) { + int materialNo1 = getMinMaterialNo(mp1.getValue()); + int materialNo2 = getMinMaterialNo(mp2.getValue()); + return materialNo1-materialNo2; + } + }); + targetList.forEach((target)->{ + + StringBuffer sbNo=new StringBuffer(); + + target.getValue().forEach(item->{ + sbNo.append(item.getMaterialNo()).append(","); + }); + if(sbNo.length()>0){ + sbNo.delete(sbNo.length()-1,sbNo.length());//删除最后一个 , + } + System.out.println(sbNo.toString()+"检材未检出"+target.getValue().get(0).getNoFindCompounds()+"--- 检出了"+target.getValue().get(0).getFindCompounds()); + }); + } + + //获取检材中最小的一个检材编号 + private static int getMinMaterialNo(List materialList){ + materialList.sort(new Comparator() { + @Override + public int compare(TestResultDetail t1, TestResultDetail t2) { + int mNo1= Integer.parseInt(getNumberByMaterialNo(t1.getMaterialNo())); + int mNo2= Integer.parseInt(getNumberByMaterialNo(t2.getMaterialNo())); + return mNo1-mNo2; + } + }); + return Integer.parseInt(getNumberByMaterialNo(materialList.get(0).getMaterialNo())); + } + + +} diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/MaterialDto.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/MaterialDto.java new file mode 100644 index 0000000..7ba8ee2 --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/MaterialDto.java @@ -0,0 +1,108 @@ +package digital.laboratory.platform.inspetion.api.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import digital.laboratory.platform.sys.entity.DrugLite; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.util.List; + + +/** + * 检材信息 + */ +@Data +@ApiModel(value = "检材信息:用户接受其他系统提供的检材信息") +public class MaterialDto extends BaseEntity { + + /** + * 检材id + */ + @ApiModelProperty(value = "检材id") + private String id; + + /** + * 检材编号 + */ + @ApiModelProperty(value = "检材编号") + private String imNo; + + @ApiModelProperty(value = "委托id") + private String entrustmentId; + + /** + * 检材名称 + */ + @ApiModelProperty(value = "检材名称") + private String name; + + /** + * 检材类别:继承所取物证的类别或从物证类别选择 + */ + @ApiModelProperty(value = "检材类别:继承所取物证的类别或从物证类别选择") + private String type; + + @ApiModelProperty(value = "检材颜色:继承所取物证颜色或手动填入") + private String color; + + /** + * 检材性状:继承所取物证性状或从物证性状类别选择 + */ + @ApiModelProperty(value = "检材性状:继承所取物证性状或从物证性状类别选择") + private String form; + + + /** + * 检材情况之承载物数量, 例如 5 颗, 3包 + */ + @ApiModelProperty(value = "检材情况之承载物数量, 例如 5 颗, 3包") + private Integer fundQuantity; + + /** + * 检材情况之承载物单位, 例如 5 颗, 3包 + */ + @ApiModelProperty(value = "检材情况之承载物单位, 例如 5 颗, 3包") + private String fundUnit; + + /** + * 检材数量, 例如 3.8 克 或 4.5毫升 + */ + @ApiModelProperty(value = "检材数量, 例如 3.8 克 或 4.5毫升") + private BigDecimal quantity; + + /** + * 计量单位, 例如 3.8 克 或 4.5毫升 + */ + @ApiModelProperty(value = "计量单位, 例如 3.8 克 或 4.5毫升") + private String unit; + + @ApiModelProperty(value = "检材受理编号") + private String acceptNo; + + /** + * 候选毒品列表(drug 对象的 json array) + */ + @ApiModelProperty(value = "候选毒品列表(drug 对象的 json array)") + private List candidateDrugs; + + private BigDecimal sample1Quantity; + + private String sampleName; + + private String sampleCode; + + private Integer orderNo; + + private BigDecimal sample1RepeatWeigh; + + private String formName; + + private Integer analysisOption;//分析项目,代替原来的定性分析,定量分析字段 1.定性分析 2.定量分析 3.定性定量分析 4.关联性判断 5。其他 + +} diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/SampleInfo.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/SampleInfo.java new file mode 100644 index 0000000..f7dfc43 --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/SampleInfo.java @@ -0,0 +1,47 @@ +package digital.laboratory.platform.inspetion.api.entity; +/* + *@title SampleInfo + *@description + *@author xy + *@version 1.0 + *@create 2023/12/13 11:00 + */ + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +import java.util.List; + +@Data +@TableName(value = "b_sampleInfo", autoResultMap = true) +@ApiModel(value = "样本信息", description = "样本信息") +public class SampleInfo extends BaseEntity { + private String id; + private String sampleName; + private String acceptNo; + private Double quality; //送检的时候送检质量 + private String unit;//单位 + private Double sampleQuality;//受理的时候的质量 + private String sampleQualityUnit;//受理的时候的质量单位 + private Integer source;//数据来源-手动录入或系统接口录入 + private String businessId;//业务ID + private Integer status; // 0 未分配 1已分配 + private String businessType;//委托检验鉴定、任务检验鉴定、筛查检验鉴定 + private String form;//检材性状 + private String color;//检材颜色 + Integer analysisOption;//定量分析字段 1.定性分析 2.定量分析 3.定性定量分析 4.关联性判断 5。其他 + Integer orderNo;//委托中检材的序号 + @TableField(typeHandler = FastjsonTypeHandler.class) + private List targetObject;//筛查物列表 + + //用来转换type类型的中文 + @TableField(exist = false) + private String businessTypeName; + + @TableField(exist = false) + private Boolean isDistribution;//是否被分配 +} diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TargetObject.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TargetObject.java new file mode 100644 index 0000000..0052ff6 --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TargetObject.java @@ -0,0 +1,78 @@ +package digital.laboratory.platform.inspetion.api.entity; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TargetObject { + /** + * ID + */ + @ApiModelProperty(value = "Id") + private String id; + + + /** + * 英文名 + */ + @ApiModelProperty(value = "英文名") + private String englishName; + + /** + * 毒品类型 + */ + @ApiModelProperty(value = "毒品类型") + private String drugType; + + /** + * 发布时间 + */ + @ApiModelProperty(value = "发布时间") + private String publishTime; + + /** + * 实行时间 + */ + @ApiModelProperty(value = "实行时间") + private String implementTime; + + /** + * 备注 + */ + @ApiModelProperty(value = "备注") + private String comments; + + @ApiModelProperty(value = "code") + private String code; + + /** + * 毒品名称 + */ + @ApiModelProperty(value = "毒品名称") + private String name; + + /** + * 别名 + */ + @ApiModelProperty(value = "别名") + private String alias; + + /** + * CAS号 + */ + @ApiModelProperty(value = "CAS号") + private String casCode; + + /** + * 来源 + */ + @ApiModelProperty(value = "来源") + + private String source; + + +} diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TestRecord.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TestRecord.java new file mode 100644 index 0000000..d863a23 --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TestRecord.java @@ -0,0 +1,96 @@ +package digital.laboratory.platform.inspetion.api.entity; + +import com.alibaba.fastjson.annotation.JSONField; +import com.alibaba.fastjson.annotation.JSONType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import com.fasterxml.jackson.annotation.JsonFormat; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDate; +import java.util.List; + +/* + *@title TestRecord + *@description 检验记录 + *@author xy + *@version 1.0 + *@create 2023/12/18 9:39 + */ +@Data +@TableName(value = "b_test_record", autoResultMap = true) +@ApiModel(value = "检验记录", description = "检验记录") +public class TestRecord extends BaseEntity { + @ApiModelProperty(value = "id") + private String id; + @ApiModelProperty(value = "待检验样本ID") + @TableField(typeHandler = FastjsonTypeHandler.class) + private List sampleTestList;//待检验样本ID + @ApiModelProperty(value = "使用到的设备ID") + @TableField(typeHandler = FastjsonTypeHandler.class) + private List deviceIdList;//使用到的设备ID + + @ApiModelProperty(value = "使用到的试剂耗材") + @TableField(typeHandler = FastjsonTypeHandler.class) + private List reagentConsumablesList;//使用到的试剂耗材 + + @ApiModelProperty(value = "使用到的标准溶液") + @TableField(typeHandler = FastjsonTypeHandler.class) + private List standardSolution;//使用到的标准溶液 + + @ApiModelProperty(value = "使用到的样本溶液") + @TableField(typeHandler = FastjsonTypeHandler.class) + private List sampleSolution;//使用到的样本溶液 + + @ApiModelProperty(value = "使用到的检验方法") + @TableField(typeHandler = FastjsonTypeHandler.class) + private List testMethodList;//使用到的检验方法 + @ApiModelProperty(value = "仪器设备使用条件") + @TableField(typeHandler = FastjsonTypeHandler.class) + private List deviceUseCondition;//仪器设备使用条件 + @ApiModelProperty(value = "检验人") + private String testUserId;//检验人 + + @ApiModelProperty(value = "检验编号") + private String testSerialNumber;//检验编号 + + @ApiModelProperty(value = "样本溶液处理过程") + private String sampleSolutionProcessing;//样本溶液处理过程 + + @ApiModelProperty(value = "标准溶液处理过程") + private String standardSolutionProcessing;//标准溶液处理过程 + + @ApiModelProperty(value = "检验过程描述") + private String testProcessDes;//检验过程描述 + + @ApiModelProperty(value = "模板名称") + private String templateName;//模板名称 + + @ApiModelProperty(value = + "创建实验:0\n" + + "正在上机:1\n" + + "结果分析:2\n" + + "提交审核:3\n" + + "提交审批:4\n" + + "实验完成:5\n" + + "出具文书:6") + private Integer status; + + @ApiModelProperty(value = "实验类型(业务类型)") + private String businessType; + + @ApiModelProperty(value = "实验图谱-存储图谱文件名,一般为pdf,格式为['p1.pdf,p2.pdf']") + private String testAtlas; + + @ApiModelProperty("实验开始时间") + @JsonFormat(pattern = "yyyy/MM/dd", timezone = "GMT+8") + private LocalDate testStartDate; + + @ApiModelProperty("实验结束时间") + @JsonFormat(pattern = "yyyy/MM/dd", timezone = "GMT+8") + private LocalDate testEndDate; +} diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TestResult.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TestResult.java new file mode 100644 index 0000000..857e5b5 --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TestResult.java @@ -0,0 +1,24 @@ +package digital.laboratory.platform.inspetion.api.entity; + +import lombok.Data; + +/** + * @author xy + * @version 1.0 + * @title TestResult + * @description + * @create 2024/3/13 18:02 + */ +@Data +public class TestResult { + private Integer orderNo;//检材序号 + private String materialNo;//检材名称 + private String compoundName;//化合物名称 + private Integer isFind;// 0 未检出 1 检出 + private String testId; + + //private String findCompounds;//检出的化合物列表 + //private String noFindCompounds;//未检出的化合物列表 + + +} diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TestResultDetail.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TestResultDetail.java new file mode 100644 index 0000000..0d35492 --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/entity/TestResultDetail.java @@ -0,0 +1,19 @@ +package digital.laboratory.platform.inspetion.api.entity; + +import lombok.Data; + +/** + * @author xy + * @version 1.0 + * @title TestResultDetail + * @description + * @create 2024/3/13 22:31 + */ +@Data +public class TestResultDetail { + private String materialNo; + private String findCompounds; + private String noFindCompounds; + private Integer isFind; + +} diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/feign/RemoteTestToIdentifyService.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/feign/RemoteTestToIdentifyService.java new file mode 100644 index 0000000..2e7f377 --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/feign/RemoteTestToIdentifyService.java @@ -0,0 +1,40 @@ +package digital.laboratory.platform.inspetion.api.feign; + +import digital.laboratory.platform.inspetion.api.entity.IdentificationBookDTO; +import digital.laboratory.platform.inspetion.api.feign.factory.RemoteTestToIdentifyServiceFallbackFactory; +import digital.laboratory.platform.common.core.constant.SecurityConstants; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import io.swagger.annotations.ApiOperation; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * @author xy + * @version 1.0 + * @title 检验系统对文书系统提供的接口 + * @description + * @create 2024/2/26 15:01 + */ +@FeignClient(contextId = "remoteTestToIdentifyService", value ="dlp-drugtesting-biz", + fallbackFactory = RemoteTestToIdentifyServiceFallbackFactory.class) +public interface RemoteTestToIdentifyService { + /** + * 提供读取实验数据的接口 + * @param businessId + * @return + */ + @GetMapping(value="/identifyBookData/getIdentifyBookDataByBusinessId", headers = SecurityConstants.HEADER_FROM_IN) + public R getIdentifyBookDataByBusinessId(@RequestParam("businessId") String businessId); + + @PostMapping(value="/identifyBookData/getTestFinishBusinessData", headers = SecurityConstants.HEADER_FROM_IN) + public R getTestFinishBusinessData(@RequestBody List synedIdList); + + @PostMapping("/testRecord/queryTestRecordInfoByBusinessId") + @ApiOperation("根据业务id获取实验信息") + public R> queryTestRecordInfoByBusinessId(@RequestBody List businessIds); + +} diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/feign/factory/RemoteTestToIdentifyServiceFallbackFactory.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/feign/factory/RemoteTestToIdentifyServiceFallbackFactory.java new file mode 100644 index 0000000..9e2cdd0 --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/feign/factory/RemoteTestToIdentifyServiceFallbackFactory.java @@ -0,0 +1,23 @@ +package digital.laboratory.platform.inspetion.api.feign.factory; + +import digital.laboratory.platform.inspetion.api.feign.RemoteTestToIdentifyService; +import digital.laboratory.platform.inspetion.api.feign.fallback.RemoteTestToIdentifyServiceFallbackImpl; +import org.springframework.cloud.openfeign.FallbackFactory; +import org.springframework.stereotype.Component; + +/** + * @author xy + * @version 1.0 + * @title RemoteFlowManagerServiceFallbackFactory + * @description + * @create 2024/1/17 18:07 + */ +@Component +public class RemoteTestToIdentifyServiceFallbackFactory implements FallbackFactory { + @Override + public RemoteTestToIdentifyService create(Throwable throwable) { + RemoteTestToIdentifyServiceFallbackImpl remoteFlowManagerServiceFallback=new RemoteTestToIdentifyServiceFallbackImpl(); + remoteFlowManagerServiceFallback.setCause(throwable); + return remoteFlowManagerServiceFallback; + } +} diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/feign/fallback/RemoteTestToIdentifyServiceFallbackImpl.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/feign/fallback/RemoteTestToIdentifyServiceFallbackImpl.java new file mode 100644 index 0000000..1f2728f --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/feign/fallback/RemoteTestToIdentifyServiceFallbackImpl.java @@ -0,0 +1,42 @@ +package digital.laboratory.platform.inspetion.api.feign.fallback; + +import digital.laboratory.platform.inspetion.api.entity.IdentificationBookDTO; +import digital.laboratory.platform.inspetion.api.feign.RemoteTestToIdentifyService; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +/** + * @author xy + * @version 1.0 + * @title RemoteTestToIdentifyServiceFallbackImpl + * @description + * @create 2024/1/17 18:07 + */ +@Slf4j +@Component +public class RemoteTestToIdentifyServiceFallbackImpl implements RemoteTestToIdentifyService { + @Setter + private Throwable cause; + + @Override + public R getIdentifyBookDataByBusinessId(String businessId) { + //log.error("feign 获取鉴定文书信息失败,请联系管理员:{}", identificationBookDTO.getCaseName(), cause); + return null; + } + + @Override + public R getTestFinishBusinessData(List synedIdList) { + return null; + } + + @Override + public R> queryTestRecordInfoByBusinessId(List businessIds) { + return null; + } +} diff --git a/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/vo/TestRecordVo.java b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/vo/TestRecordVo.java new file mode 100644 index 0000000..74f717a --- /dev/null +++ b/dlp-drugtesting-api/src/main/java/digital/laboratory/platform/inspetion/api/vo/TestRecordVo.java @@ -0,0 +1,19 @@ +package digital.laboratory.platform.inspetion.api.vo; + +import digital.laboratory.platform.inspetion.api.entity.TestRecord; +import lombok.Data; + +import java.util.List; + +@Data +public class TestRecordVo extends TestRecord { + + private String testUserName; + private List testMethodName; + + private String instrumentConditionUrl; + + private String instrumentConditionFileName; + + private String businessTypeName; +} diff --git a/dlp-drugtesting-api/src/test/java/digital/laboratory/platform/AppTest.java b/dlp-drugtesting-api/src/test/java/digital/laboratory/platform/AppTest.java new file mode 100644 index 0000000..6304505 --- /dev/null +++ b/dlp-drugtesting-api/src/test/java/digital/laboratory/platform/AppTest.java @@ -0,0 +1,38 @@ +package digital.laboratory.platform; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } +} diff --git a/dlp-drugtesting-biz/assets/image-20240417101824328.png b/dlp-drugtesting-biz/assets/image-20240417101824328.png new file mode 100644 index 0000000..f0ac1b8 Binary files /dev/null and b/dlp-drugtesting-biz/assets/image-20240417101824328.png differ diff --git a/dlp-drugtesting-biz/assets/image-20240417101958546.png b/dlp-drugtesting-biz/assets/image-20240417101958546.png new file mode 100644 index 0000000..c626aa4 Binary files /dev/null and b/dlp-drugtesting-biz/assets/image-20240417101958546.png differ diff --git a/dlp-drugtesting-biz/assets/image-20240417102214943.png b/dlp-drugtesting-biz/assets/image-20240417102214943.png new file mode 100644 index 0000000..8d29160 Binary files /dev/null and b/dlp-drugtesting-biz/assets/image-20240417102214943.png differ diff --git a/dlp-drugtesting-biz/pom.xml b/dlp-drugtesting-biz/pom.xml new file mode 100644 index 0000000..6609121 --- /dev/null +++ b/dlp-drugtesting-biz/pom.xml @@ -0,0 +1,269 @@ + + 4.0.0 + + digital.laboratory.platform + dlp-drugtesting + 2022.10.11-snapshots + + dlp-drugtesting-biz + jar + dlp-drugtesting-biz + + UTF-8 + 1.8 + 1.8 + 5.7.1 + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + 2021.1 + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + 2021.1 + + + + digital.laboratory.platform + dlp-common-swagger + + + + + + + + + digital.laboratory.platform + dlp-common-feign + 2022.10.11-snapshots + + + + digital.laboratory.platform + dlp-common-security + 2022.10.11-snapshots + + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.springframework.boot + spring-boot-starter-test + test + + + + digital.laboratory.platform + dlp-common-core + 2022.10.11-snapshots + + + + mysql + mysql-connector-java + 8.0.28 + + + + org.springframework.boot + spring-boot-starter-undertow + + + + digital.laboratory.platform + dlp-common-log + 2022.10.11-snapshots + + + + digital.laboratory.platform + dlp-common-seata + 2022.10.11-snapshots + + + + digital.laboratory.platform + dlp-admin-api + 2022.10.11-snapshots + + + digital.laboratory.platform + dlp-drugtesting-api + 2022.10.11-snapshots + + + digital.laboratory.platform + dlp-sewage-api + 2022.10.11-snapshots + + + digital.laboratory.platform + dlp-common-oss + 2022.10.11-snapshots + + + + commons-io + commons-io + 2.11.0 + + + + digital.laboratory.platform + dlp-upload-api + 2022.10.11-snapshots + + + + digital.laboratory.platform + dlp-basic-commonservice-api + 2022.10.11-snapshots + + + + + com.deepoove + poi-tl + 1.12.0 + + + + com.alibaba + easyexcel + 3.1.3 + + + org.apache.poi + poi + + + org.apache.poi + poi-ooxml + + + org.apache.poi + poi-ooxml-schemas + + + + + + digital.laboratory.platform + dlp-common-remote-word2pdf + 2022.10.11-snapshots + + + org.apache.poi + poi + 5.2.3 + + + + org.apache.poi + poi-ooxml + 5.2.3 + + + org.apache.poi + poi-ooxml-schemas + 4.1.2 + + + + org.apache.poi + poi-ooxml-full + 5.2.3 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + -Xlint:unchecked + + 3.8.1 + + + org.springframework.boot + spring-boot-maven-plugin + + + io.fabric8 + docker-maven-plugin + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.3.0 + + + timestamp-property + + timestamp-property + + + timestamp + yyyy-MM-dd HH:mm:ss + zh_CN + Asia/Shanghai + + + + + + + + maven-resources-plugin + 3.1.0 + + UTF-8 + + + xlsx + xls + docx + + + + + copy-resource-one + install + + copy-resources + + + ${basedir}/../../out + + + ${basedir}/target + + ${project.artifactId}.jar + + + + + + + + + + + + ${project.basedir}/src/main/resources + true + + + + diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/DlpDrugTestingApplication.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/DlpDrugTestingApplication.java new file mode 100644 index 0000000..fc7b48f --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/DlpDrugTestingApplication.java @@ -0,0 +1,23 @@ +package digital.laboratory.platform.inspection; + +import digital.laboratory.platform.common.feign.annotation.EnableDLPFeignClients; +import digital.laboratory.platform.common.security.annotation.EnableDLPResourceServer; +import digital.laboratory.platform.common.swagger.annotation.EnableDLPSwagger2; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; + +@Configuration +@EnableDLPSwagger2 +@EnableDLPFeignClients +@EnableDiscoveryClient +@EnableDLPResourceServer +@SpringBootApplication(scanBasePackages="digital.laboratory.platform") +public class DlpDrugTestingApplication { + + public static void main(String[] args) { + SpringApplication.run(DlpDrugTestingApplication.class, args); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/Interceptor/FeignOauth2RequestInterceptor.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/Interceptor/FeignOauth2RequestInterceptor.java new file mode 100644 index 0000000..1104923 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/Interceptor/FeignOauth2RequestInterceptor.java @@ -0,0 +1,37 @@ +package digital.laboratory.platform.inspection.Interceptor; + +import feign.RequestInterceptor; +import feign.RequestTemplate; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails; + +/** + * Feign 请求拦截器 + * Feign Client 向业务系统发出请求的时候, 把 Token 带上, 以用户自己的身份调用业务系统。 + * 目的是在业务系统中识别用户是谁, 允许或禁止用户进行对应的操作。 + */ + + +@Configuration +public class FeignOauth2RequestInterceptor implements RequestInterceptor { + + private final String AUTHORIZATION_HEADER = "Authorization"; + private final String BEARER_TOKEN_TYPE = "Bearer"; + + @Override + public void apply(RequestTemplate requestTemplate) { +System.out.println(String.format("dlp-entrustment, FeignOauth2RequestInterceptor()...")); + SecurityContext securityContext = SecurityContextHolder.getContext(); + Authentication authentication = securityContext.getAuthentication(); + if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) { + OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails(); +System.out.println(String.format("FeignOauth2RequestInterceptor() Authorization, token=%s", details.getTokenValue())); + requestTemplate.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, details.getTokenValue())); + } + + } +} + diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/BusinessType.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/BusinessType.java new file mode 100644 index 0000000..c252d2d --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/BusinessType.java @@ -0,0 +1,38 @@ +package digital.laboratory.platform.inspection.constant; + +import lombok.Getter; + +@Getter +public enum BusinessType { + NPS_CASE("10001", "缴获物检验"), + BOINT_CASE("10002", "生物样本案件"), + + + BOINT_JOB("20001", "毛发任务"), + SEWAGE_JOB("20002", "污水任务"), + SCREENING_EVENT("30001", "筛查事件"); + + BusinessType(String businessType, String businessTypeName) { + this.businessType = businessType; + this.businessTypeName = businessTypeName; + } + private final String businessType; + private final String businessTypeName; + + public static String getBusinessTypeName(String businessType) { + for (BusinessType type : values()) { + if (businessType.equals(type.businessType)) { + return type.businessTypeName; + } + } + throw new RuntimeException(String.format("没有获取到%s相关的Name", businessType)); + } + public static BusinessType getBusinessTypeByType(String businessType) { + for (BusinessType type : values()) { + if (businessType.equals(type.businessType)) { + return type; + } + } + throw new RuntimeException(String.format("没有获取到%s相关的Name", businessType)); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/CompoundMassKV.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/CompoundMassKV.java new file mode 100644 index 0000000..3ea8d4a --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/CompoundMassKV.java @@ -0,0 +1,45 @@ +package digital.laboratory.platform.inspection.constant; + +/** + * @author xy + * @version 1.0 + * @title compoundMassKV 化合物名称与Mass的对应关系 + * @description + * @create 2024/2/18 18:02 + */ + +public enum CompoundMassKV { + COMPOUND_ABFUBINACA("AB-FUBINACA", 109), + COMPOUND_2FA("2-FA", 44), + COMPOUND_3FA("3-FA", 44), + COMPOUND_4FA("4-FA", 44), + COMPOUND_Phentermine("Phentermine", 58), + COMPOUND_MPA("MPA", 58), + COMPOUND_2FMA("2-FMA", 58), + COMPOUND_3FMA("3-FMA", 58), + COMPOUND_4FMA("4-FMA", 58), + COMPOUND_HEROIN("Heroin", 327), + COMPOUND_MEDETOMIDINE("Medetomidine", 0), + ; + + private String name; + private int code; + CompoundMassKV(String _name , int _code) { + this.name=_name; + this.code=_code; + } + public int getCode() { + return code; + } + public String getCompoundName() { + return name; + } + public static int getCodeByName(String _name) { + for (CompoundMassKV enumObj : CompoundMassKV.values()) { + if (enumObj.getCompoundName().equals(_name)) { + return enumObj.code; + } + } + return -1; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/MaterialType.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/MaterialType.java new file mode 100644 index 0000000..102f0f3 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/MaterialType.java @@ -0,0 +1,15 @@ +package digital.laboratory.platform.inspection.constant; + +public enum MaterialType { + + BIOLOGICAL_SAMPLE("inVivo"),//生物样本 + SEIZURE("inVitro"),//缴获物 + OTHER("other");//其他 + private final String type; + MaterialType(String type) { + this.type = type; + } + public String getType() { + return type; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/NumberTransferHanZi.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/NumberTransferHanZi.java new file mode 100644 index 0000000..ceb78f0 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/NumberTransferHanZi.java @@ -0,0 +1,45 @@ +package digital.laboratory.platform.inspection.constant; + +import lombok.Getter; + +@Getter +public enum NumberTransferHanZi { + ZERO(0, "零"), + ONE(1, "一"), + + + TWO(2, "二"), + THREE(3, "三"), + FOUR(4, "四"), + FIVE(5, "五"), + SIX(6, "六"), + + + SEVEN(7, "七"), + EIGHT(8, "八"), + NINE(9, "九"), + TEN(10, "十"), + ELEVEN(11, "十一一"), + + + TWELVE(12, "十二"), + THIRTEEN(13, "十三"), + FOURTEEN(14, "十四"), + ; + + NumberTransferHanZi(int number, String hanZi) { + this.number = number; + this.hanZi = hanZi; + } + private final int number; + private final String hanZi; + + public static String getHanZiNameByNumber(int number) { + for (NumberTransferHanZi type : values()) { + if (number == type.number) { + return type.hanZi; + } + } + throw new RuntimeException(String.format("没有获取到%s相关的汉字", number)); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/SampleInjectorConstant.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/SampleInjectorConstant.java new file mode 100644 index 0000000..4efe032 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/SampleInjectorConstant.java @@ -0,0 +1,281 @@ +package digital.laboratory.platform.inspection.constant; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; + +/** 相关导出进样位置信息中excel 中对应的类型type +* date: 2024/2/19 15:30 +* @author: Chen +* @since JDK 1.8 +* Description: +*/ +public interface SampleInjectorConstant { + + // 进样类型 + String BLANK = "Blank"; + + String STANDARD = "Standard"; + + String QC = "QC"; + + String ANALYTE = "Analyte"; + + // 溶液名称 + String BLANK_NAME = "空白溶液"; + String STANDARD_NAME = "标准溶液"; + String QC_NAME = "质控溶液"; + + String MIX_STANDARD_NAME = "标准混合溶液"; + + String NORMAL_NAME = "样本溶液"; + + /**************************************************进样方盘的初始数据********************************************************************/ + JSONArray P_1 = JSON.parseArray("[" + + "{ name: 'A1', value: ['A', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1' }," + + "{ name: 'A2', value: ['A', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1' }," + + "{ name: 'A3', value: ['A', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1' }," + + "{ name: 'A4', value: ['A', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1' }," + + "{ name: 'A5', value: ['A', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1' }," + + "{ name: 'A6', value: ['A', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1' }," + + "{ name: 'A7', value: ['A', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1' }," + + "{ name: 'A8', value: ['A', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1' }," + + "{ name: 'A9', value: ['A', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1' }," + + + "{ name: 'B1', value: ['B', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'B2', value: ['B', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'B3', value: ['B', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'B4', value: ['B', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'B5', value: ['B', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'B6', value: ['B', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'B7', value: ['B', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'B8', value: ['B', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'B9', value: ['B', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + + "{ name: 'C1', value: ['C', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'C2', value: ['C', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'C3', value: ['C', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'C4', value: ['C', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'C5', value: ['C', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'C6', value: ['C', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'C7', value: ['C', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'C8', value: ['C', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'C9', value: ['C', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + + "{ name: 'D1', value: ['D', '1'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'D2', value: ['D', '2'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'D3', value: ['D', '3'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'D4', value: ['D', '4'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'D5', value: ['D', '5'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'D6', value: ['D', '6'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'D7', value: ['D', '7'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'D8', value: ['D', '8'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'D9', value: ['D', '9'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + + "{ name: 'E1', value: ['E', '1'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'E2', value: ['E', '2'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'E3', value: ['E', '3'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'E4', value: ['E', '4'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'E5', value: ['E', '5'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'E6', value: ['E', '6'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'E7', value: ['E', '7'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'E8', value: ['E', '8'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + "{ name: 'E9', value: ['E', '9'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-1'}," + + + "{ name: 'F1', value: ['F', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'F2', value: ['F', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'F3', value: ['F', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'F4', value: ['F', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'F5', value: ['F', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'F6', value: ['F', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'F7', value: ['F', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'F8', value: ['F', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "{ name: 'F9', value: ['F', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-1'}," + + "]"); + + JSONArray P_2 = JSON.parseArray("[" + + "{ name: 'A1', value: ['A', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2' }," + + "{ name: 'A2', value: ['A', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2' }," + + "{ name: 'A3', value: ['A', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2' }," + + "{ name: 'A4', value: ['A', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2' }," + + "{ name: 'A5', value: ['A', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2' }," + + "{ name: 'A6', value: ['A', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2' }," + + "{ name: 'A7', value: ['A', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2' }," + + "{ name: 'A8', value: ['A', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2' }," + + "{ name: 'A9', value: ['A', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2' }," + + + "{ name: 'B1', value: ['B', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'B2', value: ['B', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'B3', value: ['B', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'B4', value: ['B', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'B5', value: ['B', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'B6', value: ['B', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'B7', value: ['B', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'B8', value: ['B', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'B9', value: ['B', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + + "{ name: 'C1', value: ['C', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'C2', value: ['C', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'C3', value: ['C', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'C4', value: ['C', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'C5', value: ['C', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'C6', value: ['C', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'C7', value: ['C', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'C8', value: ['C', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'C9', value: ['C', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + + "{ name: 'D1', value: ['D', '1'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'D2', value: ['D', '2'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'D3', value: ['D', '3'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'D4', value: ['D', '4'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'D5', value: ['D', '5'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'D6', value: ['D', '6'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'D7', value: ['D', '7'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'D8', value: ['D', '8'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'D9', value: ['D', '9'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + + "{ name: 'E1', value: ['E', '1'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'E2', value: ['E', '2'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'E3', value: ['E', '3'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'E4', value: ['E', '4'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'E5', value: ['E', '5'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'E6', value: ['E', '6'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'E7', value: ['E', '7'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'E8', value: ['E', '8'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + "{ name: 'E9', value: ['E', '9'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-2'}," + + + "{ name: 'F1', value: ['F', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'F2', value: ['F', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'F3', value: ['F', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'F4', value: ['F', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'F5', value: ['F', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'F6', value: ['F', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'F7', value: ['F', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'F8', value: ['F', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "{ name: 'F9', value: ['F', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-2'}," + + "]"); + + JSONArray P_3 = JSON.parseArray("[" + + "{ name: 'A1', value: ['A', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3' }," + + "{ name: 'A2', value: ['A', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3' }," + + "{ name: 'A3', value: ['A', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3' }," + + "{ name: 'A4', value: ['A', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3' }," + + "{ name: 'A5', value: ['A', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3' }," + + "{ name: 'A6', value: ['A', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3' }," + + "{ name: 'A7', value: ['A', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3' }," + + "{ name: 'A8', value: ['A', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3' }," + + "{ name: 'A9', value: ['A', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3' }," + + + "{ name: 'B1', value: ['B', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'B2', value: ['B', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'B3', value: ['B', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'B4', value: ['B', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'B5', value: ['B', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'B6', value: ['B', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'B7', value: ['B', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'B8', value: ['B', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'B9', value: ['B', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + + "{ name: 'C1', value: ['C', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'C2', value: ['C', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'C3', value: ['C', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'C4', value: ['C', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'C5', value: ['C', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'C6', value: ['C', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'C7', value: ['C', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'C8', value: ['C', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'C9', value: ['C', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + + "{ name: 'D1', value: ['D', '1'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'D2', value: ['D', '2'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'D3', value: ['D', '3'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'D4', value: ['D', '4'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'D5', value: ['D', '5'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'D6', value: ['D', '6'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'D7', value: ['D', '7'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'D8', value: ['D', '8'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'D9', value: ['D', '9'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + + "{ name: 'E1', value: ['E', '1'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'E2', value: ['E', '2'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'E3', value: ['E', '3'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'E4', value: ['E', '4'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'E5', value: ['E', '5'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'E6', value: ['E', '6'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'E7', value: ['E', '7'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'E8', value: ['E', '8'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + "{ name: 'E9', value: ['E', '9'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-3'}," + + + "{ name: 'F1', value: ['F', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'F2', value: ['F', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'F3', value: ['F', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'F4', value: ['F', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'F5', value: ['F', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'F6', value: ['F', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'F7', value: ['F', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'F8', value: ['F', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "{ name: 'F9', value: ['F', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-3'}," + + "]"); + + JSONArray P_4 = JSONArray.parseArray("[" + + "{ name: 'A1', value: ['A', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4' }," + + "{ name: 'A2', value: ['A', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4' }," + + "{ name: 'A3', value: ['A', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4' }," + + "{ name: 'A4', value: ['A', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4' }," + + "{ name: 'A5', value: ['A', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4' }," + + "{ name: 'A6', value: ['A', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4' }," + + "{ name: 'A7', value: ['A', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4' }," + + "{ name: 'A8', value: ['A', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4' }," + + "{ name: 'A9', value: ['A', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4' }," + + + "{ name: 'B1', value: ['B', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'B2', value: ['B', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'B3', value: ['B', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'B4', value: ['B', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'B5', value: ['B', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'B6', value: ['B', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'B7', value: ['B', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'B8', value: ['B', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'B9', value: ['B', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + + "{ name: 'C1', value: ['C', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'C2', value: ['C', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'C3', value: ['C', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'C4', value: ['C', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'C5', value: ['C', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'C6', value: ['C', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'C7', value: ['C', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'C8', value: ['C', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'C9', value: ['C', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + + "{ name: 'D1', value: ['D', '1'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'D2', value: ['D', '2'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'D3', value: ['D', '3'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'D4', value: ['D', '4'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'D5', value: ['D', '5'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'D6', value: ['D', '6'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'D7', value: ['D', '7'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'D8', value: ['D', '8'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'D9', value: ['D', '9'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + + "{ name: 'E1', value: ['E', '1'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'E2', value: ['E', '2'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'E3', value: ['E', '3'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'E4', value: ['E', '4'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'E5', value: ['E', '5'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'E6', value: ['E', '6'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'E7', value: ['E', '7'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'E8', value: ['E', '8'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + "{ name: 'E9', value: ['E', '9'], active: false,injectorCount: 1,sampleNo: \"\" ,frameNumber:'P-4'}," + + + "{ name: 'F1', value: ['F', '1'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'F2', value: ['F', '2'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'F3', value: ['F', '3'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'F4', value: ['F', '4'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'F5', value: ['F', '5'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'F6', value: ['F', '6'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'F7', value: ['F', '7'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'F8', value: ['F', '8'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "{ name: 'F9', value: ['F', '9'], active: false,injectorCount: 1,sampleNo: \"\",frameNumber:'P-4'}," + + "]"); + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/SewageCompoundNameTransform.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/SewageCompoundNameTransform.java new file mode 100644 index 0000000..ade99e3 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/SewageCompoundNameTransform.java @@ -0,0 +1,62 @@ +package digital.laboratory.platform.inspection.constant; + +import lombok.Getter; + +/** + * 转换化合物名称和大数据平台上传的名称一致 + */ +@Getter +public enum SewageCompoundNameTransform { + + Methamphetamine("MA,AM","冰毒"), // 甲基苯丙胺、苯丙胺(甲基苯丙胺代谢物) + + Heroin("Mor,O6", "海洛因"), // 吗啡(海洛因二级代谢产物)、O6-单乙酰吗啡(海洛因一级代谢产物) + + Codeine("Cod","可待因"), // 可待因 + + Cocaine("Coc,BZE", "可卡因"), // 可卡因、苯甲酰爱康宁(可卡因代谢物) + + MDMA("MDMA,MDA","摇头丸"), // 3,4-亚甲基二氧甲基苯丙胺(摇头丸MDMA)、3,4-亚甲基二氧基苯丙胺(摇头丸代谢物) + + Ketamine("Keta,NK","氯胺酮"), // 氯胺酮、去甲氯胺酮(氯胺酮代谢物) + + Fentanyl("Fen", "芬太尼"), + + ; + + private String targetName; + private String describe; + + SewageCompoundNameTransform(String targetName, String describe) { + this.targetName = targetName; + this.describe = describe; + } + + /** + * 根据sourceName 获取转换的大数据平台化合物名称,如果没有,则返回原始值 + * @param sourceName + * @return + */ + public static String transferName(String sourceName) { + for (SewageCompoundNameTransform enumObj : SewageCompoundNameTransform.values()) { + if (enumObj.getTargetName().contains(sourceName)) { + return enumObj.describe; + } + } + return null; + } + + /** + * 根据sourceName 获取枚举 + * @param sourceName + * @return + */ + public static SewageCompoundNameTransform getEnumBySourceName(String sourceName) { + for (SewageCompoundNameTransform enumObj : SewageCompoundNameTransform.values()) { + if (enumObj.getTargetName().equals(sourceName)) { + return enumObj; + } + } + return null; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/SewageReportColumn.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/SewageReportColumn.java new file mode 100644 index 0000000..c4b311a --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/SewageReportColumn.java @@ -0,0 +1,72 @@ +package digital.laboratory.platform.inspection.constant; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +public enum SewageReportColumn { + COLUMN_1("样品编号", "red", ""), + COLUMN_2("污水处理厂名称", "red", ""), + COLUMN_3("所在地(省)", "red", ""), + COLUMN_4("所在地(市)", "red", ""), + COLUMN_5("所在地(区/县)", "", ""), + COLUMN_6("采样时间", "", ""), + COLUMN_7("污水厂服务人口(万人)", "", ""), + COLUMN_8("生活污水占比", "", ""), + COLUMN_9("流量(万立方米/天)", "", ""), + COLUMN_10("人均日吸烟(支)", "", ""), + COLUMN_11("可替宁排泄量(mg/千人天)", "", ""), + COLUMN_12("测算人口(千人)", "", ""), + COLUMN_13("可替宁(ng/L)", "red", ""), + COLUMN_14("可待因(ng/L)", "red", ""), + COLUMN_15("MDA(ng/L)", "red", ""), + COLUMN_16("MDMA(ng/L)", "red", ""), + COLUMN_17("可卡因(ng/L)", "red", ""), + COLUMN_18("苯甲酰爱康宁(ng/L)", "red", ""), + COLUMN_19("吗啡(ng/L)", "red", ""), + COLUMN_20("O6-单乙酰吗啡(ng/L)", "red", ""), + COLUMN_21("甲基苯丙胺(ng/L)", "red", "red"), + COLUMN_22("苯丙胺(ng/L)", "red", ""), + COLUMN_23("氯胺酮(ng/L)", "red", "red"), + COLUMN_24("去甲氯胺酮(ng/L)", "red", ""), + COLUMN_25("四氢大麻酸(ng/L)", "red", ""), + COLUMN_26("", "", ""), + COLUMN_27("吗啡负荷量(mg/千人﹒天)", "", ""), + COLUMN_28("可待因负荷量(mg/千人﹒天)", "", ""), + COLUMN_29("可待因转化为吗啡负荷量(mg/千人﹒天)", "", ""), + COLUMN_30("医用吗啡负荷量(mg/千人﹒天)", "", ""), + COLUMN_31("MA/AM", "red", "red"), + COLUMN_32("K/NK", "red", "red"), + COLUMN_33("", "", ""), + COLUMN_34("人均消耗量(mg/千人﹒天)", "", "pink"), + COLUMN_35("Heroin", "", ""), + COLUMN_36("MA", "", ""), + COLUMN_37("K", "", ""), + COLUMN_38("MDMA", "", ""), + COLUMN_39("COC", "", ""), + COLUMN_40("THC", "", ""), + COLUMN_41("", "", ""), + COLUMN_42("", "", ""), + COLUMN_43("总消耗量", "", "pink"), + COLUMN_44("Heroin", "", ""), + COLUMN_45("MA", "", ""), + COLUMN_46("K", "", ""), + COLUMN_47("MDMA", "", ""), + COLUMN_48("COC", "", ""), + COLUMN_49("THC", "", ""); + private final String columnName; + private final String fontColor; + private final String backgroundColor; + + public String getColumnName() { + return columnName; + } + + public String getFontColor() { + return fontColor; + } + + public String getBackgroundColor() { + return backgroundColor; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/StdSolutionNum.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/StdSolutionNum.java new file mode 100644 index 0000000..98526d5 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/StdSolutionNum.java @@ -0,0 +1,18 @@ +package digital.laboratory.platform.inspection.constant; + +public enum StdSolutionNum { + SIMPLE_SOLUTION("Sin"), + MIXED_SOLUTION("Mix"), + BLANK_SOLUTION("BLK"), + QC_SOLUTION("QC"), + BLANK_SAMPLE_SOLUTION("BLS"); + private final String prefix; + + StdSolutionNum(String prefix) { + this.prefix = prefix; + } + + public String getPrefix() { + return prefix; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TaskTestDataStatus.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TaskTestDataStatus.java new file mode 100644 index 0000000..f5eb536 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TaskTestDataStatus.java @@ -0,0 +1,52 @@ +package digital.laboratory.platform.inspection.constant; + +import lombok.Getter; + +/** + * 任务审核状态 + */ +@Getter +public enum TaskTestDataStatus { + + REJECT(-1, "审核审批不通过"), + WAIT_REVIEW(0, "待审核"), + REVIEWED(1, "已审核"), + APPROVED(2, "已审批"), + UPLOADED(3, "已上传") + ; + private int code; + private String message; + + TaskTestDataStatus(int code, String message) { + this.code = code; + this.message = message; + } + + /** + * 根据code 值获取状态名称 + * @param code + * @return + */ + public static String getStatusNameByCode(int code) { + for (TaskTestDataStatus status : values()) { + if (code == status.getCode()) { + return status.getMessage(); + } + } + throw new RuntimeException(String.format("没有获取到code 为 %s相关的状态名", code)); + } + + /*** + * 根据code 获取enum + * @param code + * @return + */ + public static TaskTestDataStatus getEnumByCode(int code) { + for (TaskTestDataStatus status : values()) { + if (code == status.getCode()) { + return status; + } + } + throw new RuntimeException(String.format("没有获取到code 为 %s相关的枚举", code)); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestDataFileStructConstant.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestDataFileStructConstant.java new file mode 100644 index 0000000..9e2aa4c --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestDataFileStructConstant.java @@ -0,0 +1,17 @@ +package digital.laboratory.platform.inspection.constant; + +import java.util.Arrays; +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title TestDataFileStructConstant + * @description + * @create 2024/1/9 14:40 + */ + +public class TestDataFileStructConstant { + public static List TEST_DATA_FILE_NPS_STRUCT= Arrays.asList("Header","File Information", + "Sample Information","Original Files","File Description","MS Quantitative Results"); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestDataType.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestDataType.java new file mode 100644 index 0000000..48468e7 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestDataType.java @@ -0,0 +1,50 @@ +package digital.laboratory.platform.inspection.constant; + +/** + * @author xy + * @version 1.0 + * @title TestDataType 检验数据的格式类型枚举 + * @description + * @create 2024/1/9 10:23 + */ + +public enum TestDataType { + //这三种是沃特斯的数据文件的格式类型 + WaterS_QuantifyCompoundSummaryReport(10001,"WATERS Quantify Compound Summary Report"), + WaterS_QuantifySampleSummaryReport(10002, "WATERS Quantify Sample Summary Report"), + WaterS_TabSeparator(10003, "WATERS 液相色谱导出的 tab 分隔数据文件"), + //这三种是岛津的数据文件的格式 + Shimadzu_Common_File(20000, "岛津通用格式"), + Shimadzu_MCPeakTable(20001, "岛津 定性峰表 SHIMADZU MC Peak Table"), + Shimadzu_MSQuantitativeResults(20002, "岛津 组分定量结果 SHIMADZU MS Quantitative Results"), + //这2种是安捷伦的数据文件格式 + Angient_TSV(30001, "ANGIENT TSV"), + Angient_CSV(30002, "ANGIENT CSV"); + private int eCode; + private String description; + TestDataType(int _code,String _description){ + this.description=_description; + this.eCode=_code; + } + + public int getECode() { + return eCode; + } + + public String getDescription() { + return description; + } + /** + * 根据code 获取对应的描述 + * @param _code + * @return + */ + public static String getDescriptionByCode(int _code) { + for (TestDataType enumObj : TestDataType.values()) { + if (enumObj.getECode() == _code) { + return enumObj.description; + } + } + return "未知数据格式"; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestRecordArgumentType.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestRecordArgumentType.java new file mode 100644 index 0000000..65da7d2 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestRecordArgumentType.java @@ -0,0 +1,30 @@ +package digital.laboratory.platform.inspection.constant; + +import lombok.Getter; + +@Getter +public enum TestRecordArgumentType { + + TEST_RECORD_ARGUMENT_INSTRUMENT("testRecordInstrument"),//实验仪器 + TEST_RECORD_ARGUMENT_INSTRUMENT_CONDITION("testRecordInstrumentCondition"),//实验仪器条件 + TEST_RECORD_ARGUMENT_METHOD("testRecordMethod"),//实验方法 + TEST_RECORD_ARGUMENT_REAGENT("testRecordReagent"),//实验试剂耗材、标准物质 + TEST_RECORD_ARGUMENT_SAMPLE_DATA("testRecordSampleData"),//实验样本 + TEST_RECORD_ARGUMENT_SAMPLE_SOLUTION("testRecordSampleSolution"),//实验样本溶液 + TEST_RECORD_ARGUMENT_STANDARD_SOLUTION("testRecordStandardSolution");//实验标准溶液 + + private final String type; + + TestRecordArgumentType(String type) { + this.type = type; + } + + public static String getType(String type) { + for (TestRecordArgumentType constans : values()) { + if (constans.getType().equals(type)) { + return constans.getType(); + } + } + return ""; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestRecordFileUrl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestRecordFileUrl.java new file mode 100644 index 0000000..0e1ddb4 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestRecordFileUrl.java @@ -0,0 +1,26 @@ +package digital.laboratory.platform.inspection.constant; + +import lombok.Getter; + +@Getter +public enum TestRecordFileUrl { + + TEMPORARY_PATH("C:\\tmp\\upload\\"), + TEST_RECORD_BIOLOGICAL_SAMPLE_TEMPLATE("template/生物样本检验记录模板.docx"), + TEST_RECORD_BIOLOGICAL_SAMPLE_INSTRUMENT_CONDITION_TEMPLATE("template/生物样本仪器条件模板.docx"), + TEST_RECORD_SEIZURE_TEMPLATE("template/缴获物检验记录模板.docx"), + TEST_RECORD_SEIZURE_INSTRUMENT_CONDITION_TEMPLATE("template/缴获物仪器条件模板.docx"), + TEST_RECORD_CATALOGUE("document" + "/" + "testRecord"), + TEST_TEMPLATE_CATALOGUE("document" + "/" + "testTemplate"), + TEST_ATLAS_PATH("testRecord/testAtlas/") + ; + private final String fileUrl; + + TestRecordFileUrl(String fileUrl) { + this.fileUrl = fileUrl; + } + + public String getFileUrl() { + return fileUrl; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestRecordSampleDataConstant.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestRecordSampleDataConstant.java new file mode 100644 index 0000000..abc190d --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/constant/TestRecordSampleDataConstant.java @@ -0,0 +1,62 @@ +package digital.laboratory.platform.inspection.constant; + +/** + * 关于计算检验数据中的相对误差、离子丰度比相对误差的一些常量数据 + */ +public interface TestRecordSampleDataConstant { + // 毛发案件 + double HAIR_CASE_POSITIVE_RT_ERROR = 2.5; // 保留时间相对误差(正负2.5%) + + + double HAIR_CASE_NEGATIVE_RT_ERROR = -2.5; // 保留时间相对误差(正负2.5%) - + + double HAIR_CASE_ION_ABUNDANCE_RATIO_1 = 0.5; // 离子丰度比 中的比较值1 50% + + double HAIR_CASE_ION_ABUNDANCE_RATIO_2 = 0.2; // 离子丰度比 中的比较值2 20% + + double HAIR_CASE_ION_ABUNDANCE_RATIO_3 = 0.1; // 离子丰度比 中的比较值3 10% + + double HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_1 = 20d; // 离子丰度比 > 50% 的最大允许偏差范围(正负20%) + + + double HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_1 = -20d; // 离子丰度比 > 50% 的最大允许偏差范围(正负20%) - + + double HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_2 = 25d; // 20% < 离子丰度比 < 50% 的最大允许偏差范围(正负25%) + + + double HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_2 = -25d; // 20% < 离子丰度比 < 50% 的最大允许偏差范围(正负25%) - + + double HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_3 = 30d; // 10% < 离子丰度比 < 20% 的最大允许偏差范围(正负30%) + + + double HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_3 = -30d; // 10% < 离子丰度比 < 20% 的最大允许偏差范围(正负30%) - + + double HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_4 = 50d; // 离子丰度比 < 10% 的最大允许偏差范围(正负50%) + + + double HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_4 = -50d; // 离子丰度比 < 10% 的最大允许偏差范围(正负50%) - + + + /**********************************************关于溶液类型的常量值*******************************************************************/ + + String SAMPLE_TYPE_QC = "QC"; // 质控样品 + + String SAMPLE_TYPE_ANALYTE = "Analyte"; // 检材样本 + + String SAMPLE_TYPE_STD = "STD"; // 标准物质 + + /******************************************管理 判断是否符合 的常量****************************************************/ + String IS = "是"; + + String NO = "否"; + + /************************************************ 检出 或 未检出 常量属性 *****************************************************************/ + String CHECK_OUT = "检出"; + + String NOT_CHECK_OUT = "未检出"; + + /***********************************************组装数据时常用的自定义健**********************************************************/ + String LABEL = "label"; // 对应的中午 + + String PROP = "prop"; // 对应的英文值名称 + + /**************************************************化合物基峰的字典类型值******************************************************************/ + + String COMPOUND_BASIC_PEAK = "compound_basic_peak"; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/AssignmentInfoController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/AssignmentInfoController.java new file mode 100644 index 0000000..5f0483e --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/AssignmentInfoController.java @@ -0,0 +1,148 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.lang.Assert; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.inspection.dto.AssignmentInfoDto; +import digital.laboratory.platform.inspection.entity.AssignmentInfo; +import digital.laboratory.platform.inspection.entity.TaskInfo; +import digital.laboratory.platform.inspection.service.AssignmentInfoService; +import digital.laboratory.platform.inspection.service.TaskInfoService; +import digital.laboratory.platform.inspection.vo.AssignmentInfoVo; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.security.Principal; +import java.util.List; + +/* + *@title TaskInfoController + *@description + *@author xy + *@version 1.0 + *@create 2023/12/8 11:24 + */ +@RestController +@RequestMapping("/assignmentInfo") +@Api(tags = "05-分配信息管理", description = "分配信息管理") +public class AssignmentInfoController { + @Resource + private AssignmentInfoService assignmentInfoService; + + //添加接口 + @PostMapping("/addAssignmentInfo") + @ApiOperation(value = "添加分配信息", notes = "添加分配信息") + public R addAssignmentInfo(@RequestBody List assignmentInfoDtoList, HttpServletRequest httpServletRequest) { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + assignmentInfoDtoList.forEach(item -> { + item.setAssignUser(dlpUser.getId()); + item.setAssignUserName(dlpUser.getName()); + }); + + List assignmentInfoList = null; + try { + assignmentInfoList = assignmentInfoService.addAssignmentInfo(assignmentInfoDtoList); + } catch (RuntimeException e) { + e.printStackTrace(); + return R.failed(e.getMessage()); + } + + if (assignmentInfoList != null) { + return R.ok(assignmentInfoList, "添加成功"); + } else { + return R.failed("false", "添加失败"); + } + } + + //修改接口 + @PostMapping("/cancelAssignmentInfo") + @ApiOperation(value = "撤销分配信息", notes = "") + public R cancelAssignmentInfo(@RequestBody List assignmentInfoList) { + boolean ret = assignmentInfoService.cancelAssignmentInfo(assignmentInfoList); + if (ret) { + return R.ok(ret, "撤销成功"); + } else { + return R.failed("false", "撤销失败"); + } + } + + //删除数据 + @GetMapping("/deleteAssignmentInfo") + @ApiOperation(value = "删除分配信息", notes = "") + public R deleteAssignmentInfo(String id) { + Assert.notBlank(id, "参数id不能为空"); + boolean ret = assignmentInfoService.deleteAssignmentInfo(id); + if (ret) { + return R.ok("true", "删除成功"); + } else { + return R.failed("false", "删除成功"); + } + } + + //显示列表分页 + @GetMapping("/getAssignmentInfoPageList") + @ApiOperation(value = "获取分页数据", notes = "opCode 0:分配者查询已分配记录 1:接收者查询下发给自己的任务;") + public R getTaskPageList(Page page, AssignmentInfoDto assignmentInfoDto, HttpServletRequest httpServletRequest) { + //opCode 0:分配者查询已分配记录 1:接收者查询下发给自己的任务; + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + if (assignmentInfoDto.getOpCode() == 0) { + assignmentInfoDto.setAssignUser(dlpUser.getId()); + } else { + assignmentInfoDto.setTestUser(dlpUser.getId()); + } + return R.ok(assignmentInfoService.getAssignmentInfoPageList(page, assignmentInfoDto), "获取数据成功"); + } + + //显示列表 + @GetMapping("/getAssignmentInfoList") + @ApiOperation(value = "获取列表", notes = "opCode 0:分配者查询已分配记录 1:接收者查询下发给自己的任务;") + public R getAssignmentInfoList(AssignmentInfoDto assignmentInfoDto, HttpServletRequest httpServletRequest) { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + if (assignmentInfoDto.getOpCode() == 0) { + assignmentInfoDto.setAssignUser(dlpUser.getId()); + } else { + assignmentInfoDto.setTestUser(dlpUser.getId()); + } + return R.ok(assignmentInfoService.getAssignmentInfoList(assignmentInfoDto), "获取数据成功"); + } + + /** + * 根据业务ID批量撤销分配信息 + * + * @param bussinessIdList + * @return + */ + @PostMapping("/cancelByBusiness") + @ApiOperation(value = "根据业务ID批量撤销分配信息", notes = "根据业务ID批量撤销分配信息") + public R cancelByBusiness(@RequestBody List bussinessIdList) { + boolean ret = assignmentInfoService.cancelByBusiness(bussinessIdList); + if (ret) { + return R.ok(ret, "撤销成功"); + } else { + return R.failed("false", "撤销失败"); + } + } + + /** + * 查询已分配的类别为委托的任务列表 + * + * @param page + * @param keywords 查询参数 + * @return + */ + @GetMapping("/getCancelEntrustPage") + @ApiOperation(value = "查询已分配的类别为委托的任务列表", notes = "查询已分配的类别为委托的任务列表") + public R> getAssignedEntrustPage(Page page, String keywords) { + return R.ok(assignmentInfoService.getAssignedEntrustPage(page, keywords), "查询成功!"); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/EntrustInfoController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/EntrustInfoController.java new file mode 100644 index 0000000..9df5edc --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/EntrustInfoController.java @@ -0,0 +1,132 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.lang.Assert; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.oss.service.OssFile; +import digital.laboratory.platform.inspection.constant.BusinessType; +import digital.laboratory.platform.inspection.constant.TestRecordFileUrl; +import digital.laboratory.platform.inspection.dto.EntrustInfoDto; +import digital.laboratory.platform.inspetion.api.entity.EntrustInfo; +import digital.laboratory.platform.inspection.service.EntrustInfoService; +import digital.laboratory.platform.inspection.service.TestRecordService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/* + *@title EntrustInfoController + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +@RestController +@RequestMapping("/entrustInfo") +@Api(tags = "01-委托基本信息管理", description = "委托基本信息管理") +public class EntrustInfoController { + @Resource + private EntrustInfoService entrustInfoService; + + @Resource + private TestRecordService testRecordService; + + @Resource + private OssFile ossFile; + + //添加接口 + @PostMapping("/addEntrustInfo") + @ApiOperation(value = "添加委托基本信息", notes = "添加委托基本信息,同时也作为其他系统调用的外部接口") + public R addEntrustInfo(@RequestBody EntrustInfoDto entrustInfo) { + EntrustInfo ret = entrustInfoService.addEntrustInfo(entrustInfo); + if (ret != null) { + return R.ok(ret, "添加成功"); + } else { + return R.failed("false", "添加失败"); + } + + } + + //修改接口 + @PostMapping("/updateEntrustInfo") + @ApiOperation(value = "修改委托基本信息", notes = "") + public R updateEntrustInfo(@RequestBody EntrustInfo entrustInfo) { + EntrustInfo ret = entrustInfoService.updateEntrustInfo(entrustInfo); + if (ret != null) { + return R.ok(ret, "修改成功"); + } else { + return R.failed("false", "修改失败"); + } + } + + //删除数据 + @DeleteMapping("/deleteEntrustInfo") + @ApiOperation(value = "删除委托基本信息", notes = "") + public R deleteEntrustInfo(String id) { + Assert.notBlank(id, "参数id不能为空"); + boolean ret = entrustInfoService.deleteEntrustInfo(id); + if (ret) { + return R.ok("true", "删除成功"); + } else { + return R.failed("false", "删除成功"); + } + } + + //显示列表分页 + @GetMapping("/getEntrustPageList") + @ApiOperation(value = "获取分页数据", notes = "") + public R> getEntrustPageList(Page page, Integer status, EntrustInfo entrustInfo, String keywords) { + if (entrustInfo == null) { + entrustInfo = new EntrustInfo(); + } + return R.ok(entrustInfoService.getEntrustPageList(page, status, entrustInfo, keywords), "获取数据成功"); + } + + //显示列表 + @GetMapping("/getEntrustList") + @ApiOperation(value = "获取列表", notes = "") + public R getEntrustList(EntrustInfo entrustInfo) { + if (entrustInfo == null) { + entrustInfo = new EntrustInfo(); + } + return R.ok(entrustInfoService.getEntrustList(entrustInfo), "获取数据成功"); + } + + //检查是否有重复编号 + @GetMapping("/checkRepeatNo") + @ApiOperation(value = "检查是否有重复编号", notes = "检查是否有重复编号") + public R checkRepeatNo(String acceptNo, String id) { + return R.ok(entrustInfoService.checkRepeatNo(acceptNo, id)); + } + + @GetMapping("/createInspectionRecord") + @ApiOperation(value = "生成检验记录", notes = "参数 :businessId、businessType:10001 或 10002") + public R getPrintData(String businessId, String businessType) throws Exception { + String fileName = ""; + if (businessType.equals(BusinessType.BOINT_CASE.getBusinessType())) { + fileName = "生物样本检验记录.docx"; + } else { + fileName = "缴获物检验记录.docx"; + } + //判断是否生成了检验记录 + List fileNameList = ossFile.fileList(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + businessId); + boolean isCreate = fileNameList.contains(fileName); + //如果生成了 就直接返回word地址 + if (isCreate) { + return R.ok(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + businessId + "/" + fileName, "创建成功!"); + } + //如果没有生成,那么现在创建检验记录 + boolean ret = testRecordService.createInspectionRecord(businessId); + if (ret) { + return R.ok(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + businessId + "/" + fileName, "创建成功!"); + + } else { + return R.failed("创建失败!"); + } + } +} + diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/IdentifyBookController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/IdentifyBookController.java new file mode 100644 index 0000000..86e1fdf --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/IdentifyBookController.java @@ -0,0 +1,36 @@ +package digital.laboratory.platform.inspection.controller; + +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.service.IdentifyBookDataService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title 鉴定文书数据接口,主要为文书系统提供接口 + * @description + * @create 2024/3/13 11:01 + */ +@RestController +@RequestMapping("/identifyBookData") +@Api(tags = "16-鉴定报告数据提供服务接口", description = "鉴定报告数据提供服务接口") +public class IdentifyBookController { + @Resource + private IdentifyBookDataService identifyBookDataService; + //对文书系统提供获取实验数据 + @GetMapping("/getIdentifyBookDataByBusinessId") + @ApiOperation(value = "获取检验数据") + public R getIdentifyBookDataByBusinessId(String businessId){ + return identifyBookDataService.getIdentifyBookDataByBusinessId(businessId); + } + @PostMapping("/getTestFinishBusinessData") + @ApiOperation(value = "获取待制作文书列表") + public R getTestFinishBusinessData(@RequestBody List synedIdList){ + return identifyBookDataService.getTestFinishBusinessData(synedIdList); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/SampleInfoController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/SampleInfoController.java new file mode 100644 index 0000000..7be4026 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/SampleInfoController.java @@ -0,0 +1,105 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.lang.Assert; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import digital.laboratory.platform.inspection.service.SampleInfoService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.security.Principal; + +/* + *@title TaskInfoController + *@description + *@author xy + *@version 1.0 + *@create 2023/12/8 11:24 + */ +@RestController +@RequestMapping("/sampleInfo") +@Api(tags = "04-样本基本信息管理", description = "样本基本信息管理") +public class SampleInfoController { + @Resource + private SampleInfoService sampleInfoService; + + //添加接口 + @PostMapping("/addSampleInfo") + @ApiOperation(value = "添加样本基本信息", notes = "添加样本基本信息,同时也作为其他系统调用的外部接口") + public R addSampleInfo(@RequestBody SampleInfo sampleInfo) { + SampleInfo ret = sampleInfoService.addSampleInfo(sampleInfo); + if (ret != null) { + return R.ok(ret, "添加成功"); + } else { + return R.failed("false", "添加失败"); + } + + } + + //修改接口 + @PostMapping("/updateSampleInfo") + @ApiOperation(value = "修改任务基本信息", notes = "") + public R updateSampleInfo(@RequestBody SampleInfo sampleInfo) { + SampleInfo ret = sampleInfoService.updateSampleInfo(sampleInfo); + if (ret != null) { + return R.ok(ret, "添加成功"); + } else { + return R.failed("false", "添加失败"); + } + } + + //删除数据 + @DeleteMapping("/deleteSampleInfo") + @ApiOperation(value = "删除样本基本信息", notes = "") + public R deleteSampleInfo(String id) { + Assert.notBlank(id, "参数id不能为空"); + boolean ret = sampleInfoService.deleteSampleInfo(id); + if (ret) { + return R.ok("true", "删除成功"); + } else { + return R.failed("false", "删除成功"); + } + } + + //显示列表分页 + @GetMapping("/getSampleInfoPageList") + @ApiOperation(value = "获取分页数据", notes = "") + public R getSampleInfoPageList(Page page, SampleInfo sampleInfo) { + return R.ok(sampleInfoService.getSampleInfoPageList(page, sampleInfo), "获取数据成功"); + } + + //显示列表 + @GetMapping("/getSampleInfoList") + @ApiOperation(value = "获取列表", notes = "") + public R getSampleInfoList(SampleInfo sampleInfo) { + return R.ok(sampleInfoService.getSampleInfoList(sampleInfo), "获取数据成功"); + } + + @GetMapping("/getPageForTestRecord") + @ApiOperation(value = "在实验阶段获取该用户获得分配的检材列表", notes = "在实验阶段获取该用户获得分配的检材列表") + public R getPageForTestRecord(Page page, String testId, String keywords, HttpServletRequest httpServletRequest) { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + return R.ok(sampleInfoService.getPageForTestRecord(page, dlpUser, testId,keywords), "获取数据成功"); + } + + + @PutMapping("/useSample") + @ApiOperation(value = "在实验阶段使用检材或取消使用检材", notes = "在实验阶段使用检材或取消使用检材") + public R useTestRecordSample(@RequestBody TestRecordArgumentDto argumentDto) { + return sampleInfoService.useTestRecordSample(argumentDto) ? R.ok("操作成功!") : R.failed("操作失败!"); + } + + @GetMapping("/checkRepeatNo") + @ApiOperation(value = "检查是否有重复编号", notes = "检查是否有重复编号") + public R checkRepeatNo(String acceptNo,String id) { + return sampleInfoService.checkRepeatNo(acceptNo,id) ? R.ok(true,"操作成功!") : R.failed(false,"操作失败!"); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/SampleInjectorController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/SampleInjectorController.java new file mode 100644 index 0000000..f3f0742 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/SampleInjectorController.java @@ -0,0 +1,120 @@ +package digital.laboratory.platform.inspection.controller; + +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.dto.ResetSampleInjectorDTO; +import digital.laboratory.platform.inspection.entity.SampleInjector; +import digital.laboratory.platform.inspection.service.SampleInjectorService; +import digital.laboratory.platform.inspection.vo.TestRecordSolutionVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.List; + +@RestController +@RequestMapping("/sampleInjector") +@Api(tags = "14-进样器信息相关接口管理", description = "14-进样器信息相关接口管理") +public class SampleInjectorController { + + @Resource + private SampleInjectorService sampleInjectorService; + + @GetMapping + @ApiOperation(value = "根据实验id获取进样信息", notes = "根据实验id获取进样信息") + @ApiImplicitParam(name = "testId", value = "实验id", required = true) + public R getByTestId(@RequestParam("testId") String testId) { + SampleInjector one = null; + try { + one = sampleInjectorService.getByTestId(testId); + } catch (Exception e) { + e.printStackTrace(); + return R.failed("进样信息查询失败!"); + } + return R.ok(one); + } + + @GetMapping("/materialList") + @ApiOperation(value = "检材列表", notes = "检材列表") + @ApiImplicitParams({ + @ApiImplicitParam(name = "testId", value = "实验id", required = true), + @ApiImplicitParam(name = "key", value = "查询数据字段, 仅支持编号查询", required = false) + }) + public R> queryMaterialList(@RequestParam("testId") String testId, + @RequestParam(value = "key", required = false) String key) { + List resultList = null; + try { + resultList = sampleInjectorService.queryMaterialList(testId, key); + } catch (Exception e) { + e.printStackTrace(); + return R.failed("查询列表失败!"); + } + return R.ok(resultList); + } + + @PostMapping("/saveSampleInjector") + @ApiOperation(value = "保存进样信息", notes = "保存进样信息,进样位置信息使用json存储,直方图(方盘有4个json数组,外层是个大数组): [\n" + + " [{ sampleNo: '', injectorCount: '', name: 'A1', value: ['A', '1'], active: false, frameNumber: '' },\n" + + " { sampleNo: '', injectorCount: '', name: 'A2', value: ['A', '2'], active: false, frameNumber: '' }]," + + " [{ sampleNo: '', injectorCount: '', name: 'A1', value: ['A', '1'], active: false, frameNumber: '' },\\n\" +\n" + + " { sampleNo: '', injectorCount: '', name: 'A2', value: ['A', '2'], active: false, frameNumber: '' }]],\n" + + " 圆盘:[\n" + + " {\n" + + " \"sampleNo\": ''," + + " \"injectorCount\": ''," + + " \"frameNumber\": ''," + + " \"index\": 1,\n" + + " \"active\": false,\n" + + " \"title\": 1\n" + + " },\n" + + " {\n" + + " \"sampleNo\": ''," + + " \"injectorCount\": ''," + + " \"frameNumber\": ''," + + " \"index\": 2,\n" + + " \"active\": false,\n" + + " \"title\": 6\n" + + " }]; sampleNo 溶液编号、injectorCount 进样次数、frameNumber 架号") + public R saveSampleInjector(@Valid @RequestBody SampleInjector sampleInjector) { + SampleInjector resultInfo = null; + try { + resultInfo = sampleInjectorService.saveSampleInjector(sampleInjector); + } catch (Exception e) { + e.printStackTrace(); + if (e instanceof RuntimeException) { + return R.failed(e.getMessage()); + } + return R.failed("保存失败!"); + } + return R.ok(resultInfo); + } + + @PutMapping("/reset") + @ApiOperation(value = "重置进样信息", notes = "重置进样信息") + public R reset(@Valid @RequestBody ResetSampleInjectorDTO dto) { + SampleInjector resultInfo = null; + try { + resultInfo = sampleInjectorService.reset(dto); + } catch (Exception e) { + e.printStackTrace(); + return R.failed("重置失败!"); + } + return R.ok(resultInfo); + } + + @GetMapping("/export") + @ApiOperation(value = "进样信息导出", notes = "根据实验id查询对应的进样信息导出") + @ApiImplicitParam(name = "id", value = "进样信息的id", required = true) + public void exportSampleInjectorInfoToExcel(@RequestParam("id") String id, HttpServletResponse response) { + try { + sampleInjectorService.exportSampleInjectorInfoToExcel(id, response); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/ScreenInfoController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/ScreenInfoController.java new file mode 100644 index 0000000..9104acf --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/ScreenInfoController.java @@ -0,0 +1,76 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.lang.Assert; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.entity.ScreenInfo; +import digital.laboratory.platform.inspection.entity.TaskInfo; +import digital.laboratory.platform.inspection.service.ScreenInfoService; +import digital.laboratory.platform.inspection.service.TaskInfoService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/* + *@title TaskInfoController + *@description + *@author xy + *@version 1.0 + *@create 2023/12/8 11:24 + */ +@RestController +@RequestMapping("/screenInfo") +@Api(tags = "03-筛查基本信息管理", description = "筛查基本信息管理") +public class ScreenInfoController { + @Resource + private ScreenInfoService screenInfoService; + //添加接口 + @PostMapping("/addScreenInfo") + @ApiOperation(value = "添加筛查基本信息",notes = "添加筛查基本信息,同时也作为其他系统调用的外部接口") + public R addScreenInfo(@RequestBody ScreenInfo screenInfo){ + ScreenInfo ret=screenInfoService.addScreenInfo(screenInfo); + if(ret!=null){ + return R.ok(ret,"添加成功"); + }else { + return R.failed("false","添加失败"); + } + + } + //修改接口 + @PostMapping("/updateScreenInfo") + @ApiOperation(value = "修改筛查基本信息",notes = "") + public R updateScreenInfo(@RequestBody ScreenInfo screenInfo){ + ScreenInfo ret=screenInfoService.updateScreenInfo(screenInfo); + if(ret!=null){ + return R.ok(ret,"添加成功"); + }else { + return R.failed("false","添加失败"); + } + } + //删除数据 + @DeleteMapping("/deleteScreenInfo") + @ApiOperation(value = "删除筛查基本信息",notes = "") + public R deleteScreenInfo(String id){ + Assert.notBlank(id,"参数id不能为空"); + boolean ret=screenInfoService.deleteScreenInfo(id); + if(ret){ + return R.ok("true","删除成功"); + }else { + return R.failed("false","删除成功"); + } + } + //显示列表分页 + @GetMapping("/getScreenPageList") + @ApiOperation(value = "获取分页数据",notes = "") + public R getScreenPageList(Page page,ScreenInfo screenInfo,String keywords){ + return R.ok(screenInfoService.getScreenPageList(page,screenInfo,keywords),"获取数据成功"); + } + //显示列表 + @GetMapping("/getScreenList") + @ApiOperation(value = "获取列表",notes = "") + public R getScreenList(ScreenInfo screenInfo,String keywords){ + return R.ok(screenInfoService.getScreenList(screenInfo,keywords),"获取数据成功"); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/SewageDrugInspectReportController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/SewageDrugInspectReportController.java new file mode 100644 index 0000000..4ba9ae8 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/SewageDrugInspectReportController.java @@ -0,0 +1,64 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.lang.Assert; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.dto.ExportSewageAnalystReportsDTO; +import digital.laboratory.platform.inspection.dto.SewageDataDto; +import digital.laboratory.platform.inspection.dto.TaskInfoDto; +import digital.laboratory.platform.inspection.entity.TaskInfo; +import digital.laboratory.platform.inspection.entity.TestRecordSampleData; +import digital.laboratory.platform.inspection.service.SewageDrugInspectReportService; +import digital.laboratory.platform.inspection.service.TaskInfoService; +import digital.laboratory.platform.inspection.service.TestRecordSampleDataService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.List; + +/** + *@title TaskInfoController + *@description + *@author xy + *@version 1.0 + *@create 2023/12/8 11:24 + */ +@RestController +@RequestMapping("/sewageReport") +@Api(tags = "17-污水专项检测毒品分析报告", description = "污水专项检测毒品分析报告") +public class SewageDrugInspectReportController { + @Resource + private SewageDrugInspectReportService sewageDrugInspectReportService; + + @Resource + private TestRecordSampleDataService testRecordSampleDataService; + + @ApiOperation(value = "导出污水专项检测毒品分析报告") + @PostMapping("/exportSewageAnalystReports") + public R exportSewageAnalystReports(@RequestBody ExportSewageAnalystReportsDTO dto){ + try { + String reportWord = sewageDrugInspectReportService.generateSewageDrugInspectReportWord(dto); + return R.ok(reportWord); + } catch (Exception e) { + e.printStackTrace(); + } + return R.failed(); + } +// +// @ApiOperation(value = "更新数据") +// @PostMapping("/updateData") +// public R updateData(){ +// boolean update = testRecordSampleDataService +// .update(Wrappers.lambdaUpdate() +// .eq(TestRecordSampleData::getTestId, "BC4234B2FF08F7E8CE1ED881DB374EA8") +// .eq(TestRecordSampleData::getSampleConcentration, 0) +// .set(TestRecordSampleData::getSampleConcentration, 2.123)); +// return R.ok(update); +// } + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TaskInfoController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TaskInfoController.java new file mode 100644 index 0000000..c8c8414 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TaskInfoController.java @@ -0,0 +1,101 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.lang.Assert; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.dto.ExportSewageAnalystReportsDTO; +import digital.laboratory.platform.inspection.dto.SewageDataDto; +import digital.laboratory.platform.inspection.dto.TaskInfoDto; +import digital.laboratory.platform.inspection.entity.TaskInfo; +import digital.laboratory.platform.inspection.service.TaskInfoService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.io.IOException; +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title TaskInfoController + * @description + * @create 2023/12/8 11:24 + */ +@RestController +@RequestMapping("/taskInfo") +@Api(tags = "02-任务基本信息管理", description = "任务基本信息管理") +public class TaskInfoController { + @Resource + private TaskInfoService taskInfoService; + + //添加接口 + @PostMapping("/addTaskInfo") + @ApiOperation(value = "添加任务基本信息", notes = "添加任务基本信息,同时也作为其他系统调用的外部接口") + public R addTaskInfo(@RequestBody TaskInfoDto taskInfo) { + TaskInfo ret = taskInfoService.addTaskInfo(taskInfo); + if (ret != null) { + return R.ok(ret, "添加成功"); + } else { + return R.failed("false", "添加失败"); + } + + } + + //修改接口 + @PostMapping("/updateTaskInfo") + @ApiOperation(value = "修改任务基本信息", notes = "") + public R updateTaskInfo(@RequestBody TaskInfo taskInfo) { + TaskInfo ret = taskInfoService.updateTaskInfo(taskInfo); + if (ret != null) { + return R.ok(ret, "添加成功"); + } else { + return R.failed("false", "添加失败"); + } + } + + //删除数据 + @GetMapping("/deleteTaskInfo") + @ApiOperation(value = "删除任务基本信息", notes = "") + public R deleteTaskInfo(String id) { + Assert.notBlank(id, "参数id不能为空"); + boolean ret = taskInfoService.deleteTaskInfo(id); + if (ret) { + return R.ok("true", "删除成功"); + } else { + return R.failed("false", "删除成功"); + } + } + + //显示列表分页 + @GetMapping("/getTaskPageList") + @ApiOperation(value = "获取分页数据", notes = "") + public R getTaskPageList(Page page, TaskInfo taskInfo, String keywords) { + return R.ok(taskInfoService.getTaskPageList(page, taskInfo, keywords), "获取数据成功"); + } + + //显示列表 + @GetMapping("/getTaskList") + @ApiOperation(value = "获取列表", notes = "") + public R getTaskList(TaskInfo taskInfo, String keywords) { + return R.ok(taskInfoService.getTaskList(taskInfo, keywords), "获取数据成功"); + } + + @PostMapping("/create/sewageReport") + @ApiOperation(value = "导出污水消费量计算Excel,参数:dailySmokingPerCapita为人均日吸烟量(支)") + public R createSewageReport(String taskId, Double dailySmokingPerCapita) throws IOException { + List sewageReportData = taskInfoService.createSewageReportData(taskId, dailySmokingPerCapita); + String filePath = taskInfoService.createSewageReportExcel(sewageReportData, taskId); + return R.ok(filePath, "生成成功!"); + } + + @PostMapping("/exportSewageAnalystReports") + @ApiOperation(value = "导出污水专项检测毒品分析报告", notes = "按月份导出") + public R exportSewageAnalystReports(@RequestBody ExportSewageAnalystReportsDTO dto) { + return taskInfoService.exportSewageAnalystReports(dto); + } + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordController.java new file mode 100644 index 0000000..48534e5 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordController.java @@ -0,0 +1,215 @@ +package digital.laboratory.platform.inspection.controller; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.amazonaws.services.s3.model.AmazonS3Exception; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.annotation.JsonFormat; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.common.oss.service.OssFile; +import digital.laboratory.platform.inspection.dto.DeleteTestAtlasDTO; +import digital.laboratory.platform.inspection.dto.TestRecordDto; +import digital.laboratory.platform.inspetion.api.entity.TestRecord; +import digital.laboratory.platform.inspection.service.TestRecordService; +import digital.laboratory.platform.inspection.vo.ProcedureVo; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.activation.MimetypesFileTypeMap; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.security.Principal; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + * @author xy + * @version 1.0 + * @title TestRecordController + * @description 检验记录控制器 + * @create 2023/12/19 11:50 + */ +@RestController +@RequestMapping("/testRecord") +@Api(tags = "06-检验记录管理", description = "检验记录管理") +public class TestRecordController { + + @Resource + private TestRecordService testRecordService; + + @Resource + private OssFile ossFile; + + /** + * 创建实验记录 + */ + @PostMapping("/createTestInstance") + @ApiOperation(value = "创建实验", notes = "创建实验") + public R createTestInstance(@RequestBody TestRecordDto testRecord, HttpServletRequest httpServletRequest) throws Exception { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + TestRecord testInstance = testRecordService.createTestInstance(testRecord, dlpUser); + return testInstance != null ? R.ok(testInstance, "创建成功!") : R.failed("创建失败!"); + } + + @PutMapping("/updateTestInstance") + @ApiOperation(value = "修改实验", notes = "修改实验") + public R updateTestInstance(@RequestBody TestRecord testRecord) { + TestRecord testInstance = testRecordService.updateTestInstance(testRecord); + return testInstance != null ? R.ok(testInstance, "修改成功!") : R.failed("修改失败!"); + } + + @GetMapping("/getById") + @ApiOperation(value = "通过实验Id查询实验信息", notes = "通过实验Id查询实验信息") + public R getTestRecord(String id, HttpServletRequest httpServletRequest) { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + return R.ok(testRecordService.getTestRecord(id, dlpUser), "查询成功!"); + } + + @GetMapping("/getByIdTest") + @ApiOperation(value = "通过实验Id查询实验信息", notes = "通过实验Id查询实验信息") + public R getByIdTest(String id, HttpServletRequest httpServletRequest) { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + return R.ok(testRecordService.getById(id), "查询成功!"); + } + + @GetMapping("/getPage") + @ApiOperation(value = "分页查询实验信息", notes = "分页查询实验信息") + public R> getTestRecordPageList(Page page, HttpServletRequest httpServletRequest, + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") LocalDateTime startTime, + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") LocalDateTime endTime, + String businessType) { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + return R.ok(testRecordService.getTestRecordPageList(page, dlpUser, startTime, endTime, businessType), "查询成功!"); + } + + @GetMapping("/getList") + @ApiOperation(value = "列表查询实验信息", notes = "列表查询实验信息") + public R> getTestRecordList(HttpServletRequest httpServletRequest) { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + return R.ok(testRecordService.getTestRecordList(dlpUser), "查询成功!"); + } + + @PutMapping("/useTemplate") + @ApiOperation(value = "使用模板", notes = "使用模板") + public R useTemplate(String testId, String templateId) throws Exception { + return R.ok(testRecordService.useTemplate(testId, templateId), "使用成功!"); + } + + @GetMapping("/getProcedure") + @ApiOperation(value = "获取步骤是否完成的参数") + public R getProcedure(String testId) { + return R.ok(testRecordService.getProcedure(testId), "数据获取成功!"); + } + + + @GetMapping("/solutionPage") + @ApiOperation(value = "分页查询实验中所有溶液编号") + public R getResultSolutionPage(Page page, String testId) { + return R.ok(testRecordService.getResultSolutionPage(page, testId), "数据获取成功!"); + } + + @DeleteMapping + @ApiOperation(value = "通过实验ID删除这个实验") + public R delTestRecord(String testId) { + return testRecordService.delTestRecord(testId) ? R.ok("删除成功!") : R.failed(" 删除失败!"); + } + + @PostMapping("/uploadTestAtlas") + @ApiOperation(value = "上传该实验的实验图谱") + @ApiImplicitParams({ + @ApiImplicitParam(name = "testId", value = "实验id", required = true) + }) + public R uploadTestAtlas(@RequestParam("testId") String testId, @RequestPart("file") MultipartFile file) { + // ? R.ok("上传实验图谱成功!") : R.failed("上传实验图谱删除失败!") + try { + return testRecordService.uploadTestAtlas(testId, file); + } catch (Exception e) { + e.printStackTrace(); + return R.failed("系统出错,请联系管理员!"); + } + } + + @GetMapping("/getTestAtlasList") + @ApiOperation(value = "获取图谱列表") + @ApiImplicitParam(name = "testId", value = "该实验图谱关联的实验id") + public R getTestAtlasList(@RequestParam("testId") String testId) { + return testRecordService.getTestAtlasList(testId); + } + + @GetMapping("/getTestAtlasListByBusinessId") + @ApiOperation(value = "根据业务id获取图谱列表") + @ApiImplicitParam(name = "businessId", value = "该实验图谱关联的实验id") + public R getTestAtlasListByBusinessId(@RequestParam("businessId") String businessId) { + try { + return testRecordService.getTestAtlasListByBusinessId(businessId); + } catch (Exception e) { + e.printStackTrace(); + return R.failed("系统出错,请联系管理员!"); + } + } + + @DeleteMapping("/deleteTestAtlas") + @ApiOperation(value = "删除图谱,支持批量删除") + public R deleteTestAtlas(@RequestBody @Valid DeleteTestAtlasDTO dto) { + try { + return testRecordService.deleteTestAtlas(dto); + } catch (Exception e) { + e.printStackTrace(); + return R.failed(e.getMessage()); + } + } + + @GetMapping("/getTestAtlasByFileId") + @ApiOperation(value = "根据实验id和文件id获取图片") + @ApiImplicitParam(name = "testId", value = "该实验图谱关联的实验id") + public void getTestAtlasByFileId(@RequestParam("testId") String testId, + @RequestParam("fileId") String fileId, + HttpServletResponse httpServletResponse) throws IOException { + try { + TestRecord testRecord = testRecordService.getById(testId); + JSONArray jsonArray = JSONArray.parseArray(testRecord.getTestAtlas()); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + if (object.getString("fileId").equals(fileId)) { + ossFile.fileGet(object.getString("path"), httpServletResponse.getOutputStream()); + httpServletResponse.setContentType(new MimetypesFileTypeMap().getContentType(object.getString("fileName"))); + break; + } + } + }catch (AmazonS3Exception s3e) { + httpServletResponse.sendError(s3e.getStatusCode(), s3e.toString()); + } catch (Exception e) { + httpServletResponse.sendError(501, e.toString()); + } +// return R.ok(ossFile.fileList(TestRecordFileUrl.TEST_ATLAS_PATH.getFileUrl()+testId)); + } + + @PostMapping("/queryTestRecordInfoByBusinessId") + @ApiOperation("根据业务id获取实验信息") + public R> queryTestRecordInfoByBusinessId(@RequestBody List businessIds) { + try { + return testRecordService.queryTestRecordInfoByBusinessId(businessIds); + } catch (Exception e) { + e.printStackTrace(); + return R.failed(e.getMessage()); + } + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordInstrumentConditionController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordInstrumentConditionController.java new file mode 100644 index 0000000..aab9cf1 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordInstrumentConditionController.java @@ -0,0 +1,82 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.util.StrUtil; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.constant.TestRecordFileUrl; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TestRecordInstrumentCondition; +import digital.laboratory.platform.inspection.service.TestRecordInstrumentConditionService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +@RestController +@RequestMapping("/testRecord_instrumentCondition") +@Api(tags = "12-检验记录-仪器的使用条件", description = "检验记录-仪器的使用条件") +public class TestRecordInstrumentConditionController { + + @Resource + private TestRecordInstrumentConditionService testRecordInstrumentConditionService; + + + @ApiOperation(value = "添加实验仪器条件", notes = "添加实验仪器条件") + @PostMapping("/addInstrumentCondition") + public R addInstrumentCondition(@RequestBody TestRecordInstrumentCondition testRecordInstrumentCondition) { + TestRecordInstrumentCondition instrumentCondition = testRecordInstrumentConditionService.addInstrumentCondition(testRecordInstrumentCondition); + return instrumentCondition != null ? R.ok(instrumentCondition, "添加成功!") : R.failed("添加失败!"); + } + + @ApiOperation(value = "选择不同的模板类型,为实验创建仪器条件模板", notes = "type 1:(生物样本模板),-1 :(缴获物样本模板)") + @PostMapping("/createWord") + public R createConditionWordByTest(String testId) throws Exception { + boolean ret = testRecordInstrumentConditionService.createConditionWordByTest(testId); + return ret ? R.ok(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + "仪器条件.docx", "创建成功!") : R.failed("创建失败!"); + } + + @ApiOperation(value = "选择不同的模板类型,为模板创建仪器条件模板", notes = "type 1:(生物样本模板),-1 :(缴获物样本模板)") + @PostMapping("/createWordTem") + public R createConditionWordByTemplate(String templateId) throws Exception { + boolean ret = testRecordInstrumentConditionService.createConditionWordByTemplate(templateId); + return ret ? R.ok(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + templateId + "/" + "仪器条件.docx", "创建成功!") : R.failed("创建失败!"); + } + + @ApiOperation(value = "修改实验仪器条件", notes = "修改实验仪器条件") + @PostMapping("/updateInstrumentCondition") + public R updateInstrumentCondition(@RequestBody TestRecordInstrumentCondition testRecordInstrumentCondition) { + TestRecordInstrumentCondition instrumentCondition = testRecordInstrumentConditionService.updateInstrumentCondition(testRecordInstrumentCondition); + return instrumentCondition != null ? R.ok(instrumentCondition, "修改成功!") : R.failed("修改失败!"); + } + + @ApiOperation(value = "删除实验仪器条件", notes = "删除实验仪器条件") + @DeleteMapping("/delInstrumentCondition") + public R delInstrumentCondition(String id) { + return testRecordInstrumentConditionService.delInstrumentCondition(id) ? R.ok("删除成功!") : R.failed("删除失败!"); + } + + @ApiOperation(value = "通过ID查询仪器条件") + @GetMapping("/getConditionById") + public R getInstrumentConditionById(String testId) { + return R.ok(testRecordInstrumentConditionService.getInstrumentConditionByTestId(testId)); + } + + + @ApiOperation(value = "为模板添加或移除仪器条件", notes = "为模板添加或移除仪器条件") + @PutMapping("/useConditionToTemplate") + public R useInstrumentConditionToTemplate(@RequestBody TestRecordArgumentDto argumentDto) { + return testRecordInstrumentConditionService.useInstrumentConditionToTemplate(argumentDto) ? R.ok("添加成功!") : R.failed("添加失败!"); + } + + @PutMapping("/merge") + public R mergeFileByBiologicalSample(String testId) throws Exception { + return testRecordInstrumentConditionService.mergeFile(testId) ? R.ok("合并成功!") : R.failed("合并失败!"); + } + + @GetMapping("/generatedOrNot") + @ApiOperation(value = "判断是否创建了仪器条件模板", notes = "判断是否创建了仪器条件模板") + public R generatedOrNot(String testId) { + String filePath = testRecordInstrumentConditionService.generatedOrNot(testId); + return StrUtil.isNotBlank(filePath) ? R.ok(filePath) : R.failed("没有创建好仪器条件模板!"); + } +} \ No newline at end of file diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordInstrumentController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordInstrumentController.java new file mode 100644 index 0000000..2e55294 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordInstrumentController.java @@ -0,0 +1,98 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.lang.Assert; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TaskInfo; +import digital.laboratory.platform.inspection.entity.TestRecordInstrument; +import digital.laboratory.platform.inspection.service.TestRecordInstrumentService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + * @author xy + * @version 1.0 + * @title TestRecordInstrumentController + * @description 实验中使用到的仪器设备 + * @create 2023/12/19 11:48 + */ +@RestController +@RequestMapping("/testRecord_instrument") +@Api(tags = "07-检验记录-使用仪器管理", description = "检验记录-使用仪器管理") +public class TestRecordInstrumentController { + @Resource + private TestRecordInstrumentService testRecordInstrumentService; + + //添加 + @PostMapping("/addInstrument") + @ApiOperation(value = "添加设备仪器", notes = "添加设备仪器") + public R addInstrument(@RequestBody TestRecordInstrument testRecordInstrument) { + TestRecordInstrument ret = testRecordInstrumentService.addTestRecordInstrument(testRecordInstrument); + if (ret != null) { + return R.ok(ret, "添加实验仪器设备成功"); + } else { + return R.failed("false", "添加实验仪器设备失败"); + } + } + + //修改接口 + @PostMapping("/updateInstrument") + @ApiOperation(value = "修改实验设备仪器", notes = "") + public R updateInstrument(@RequestBody TestRecordInstrument testRecordInstrument) { + TestRecordInstrument ret = testRecordInstrumentService.updateTestRecordInstrument(testRecordInstrument); + if (ret != null) { + return R.ok(ret, "添加成功"); + } else { + return R.failed("false", "添加失败"); + } + } + + //删除数据 + @DeleteMapping("/deleteInstrument") + @ApiOperation(value = "删除实验设备仪器信息", notes = "") + public R deleteInstrument(String id) { + Assert.notBlank(id, "参数id不能为空"); + boolean ret = testRecordInstrumentService.deleteTestRecordInstrument(id); + if (ret) { + return R.ok("true", "删除成功"); + } else { + return R.failed("false", "删除成功"); + } + } + + //显示列表分页 + @GetMapping("/getInstrumentPageList") + @ApiOperation(value = "获取实验中仪器设备分页数据", notes = "") + public R getInstrumentPageList(Page page, String testId, String keywords, Integer opCode) { + return R.ok(testRecordInstrumentService.getTestRecordInstrumentPageList(page, testId,keywords,opCode), "获取数据成功"); + } + + @GetMapping("/getInstrumentToTemplatePage") + @ApiOperation(value = "获取模板中仪器设备分页数据", notes = "") + public R getTemplateInstrumentPageList(Page page, String templateId, String keywords, Integer opCode) { + return R.ok(testRecordInstrumentService.getTemplateInstrumentPageList(page, templateId,keywords,opCode), "获取数据成功"); + } + + //显示列表 + @GetMapping("/getInstrumentList") + @ApiOperation(value = "获取列表", notes = "") + public R getInstrumentList(TestRecordInstrument testRecordInstrument) { + return R.ok(testRecordInstrumentService.getTestRecordInstrumentList(testRecordInstrument), "获取数据成功"); + } + + @PutMapping("/useInstrument") + @ApiOperation(value = "添加或移除实验过程中使用的仪器设备", notes = "添加或移除实验过程中使用的仪器设备") + public R useTestRecordInstrument(@RequestBody TestRecordArgumentDto testRecordArgumentDto) { + return testRecordInstrumentService.useTestRecordInstrument(testRecordArgumentDto) ? R.ok("添加成功!") : R.failed("添加失败!"); + } + + @PutMapping("/useInstrumentToTemplate") + @ApiOperation(value = "添加或移除模板中使用的仪器设备", notes = "添加或移除模板中使用的仪器设备") + public R useTemplateInstrument(@RequestBody TestRecordArgumentDto testRecordArgumentDto) { + return testRecordInstrumentService.useTemplateInstrument(testRecordArgumentDto) ? R.ok("添加成功!") : R.failed("添加失败!"); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordMethodController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordMethodController.java new file mode 100644 index 0000000..ae00144 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordMethodController.java @@ -0,0 +1,91 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.lang.Assert; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TestRecordMethod; +import digital.laboratory.platform.inspection.service.TestRecordMethodService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + * @author xy + * @version 1.0 + * @title TestRecordMethodController + * @description + * @create 2023/12/19 15:25 + */ +@RestController +@RequestMapping("/testRecord_method") +@Api(tags = "08-检验记录-使用方法管理", description = "检验记录-使用方法管理") +public class TestRecordMethodController { + @Resource + private TestRecordMethodService testRecordMethodService; + + //添加 + @PostMapping("/addMethod") + @ApiOperation(value = "添加实验使用方法", notes = "添加设备仪器") + public R addMethod(@RequestBody TestRecordMethod testRecordMethod) { + TestRecordMethod ret = testRecordMethodService.addTestRecordMethod(testRecordMethod); + if (ret != null) { + return R.ok(ret, "添加实验方法成功"); + } else { + return R.failed("false", "添加实验方法失败"); + } + } + + //修改接口 + @PostMapping("/updateMethod") + @ApiOperation(value = "修改实验使用方法", notes = "") + public R updateMethod(@RequestBody TestRecordMethod testRecordMethod) { + TestRecordMethod ret = testRecordMethodService.updateTestRecordMethod(testRecordMethod); + if (ret != null) { + return R.ok(ret, "添加成功"); + } else { + return R.failed("false", "添加失败"); + } + } + + //删除数据 + @DeleteMapping("/deleteMethod") + @ApiOperation(value = "删除实验使用方法", notes = "") + public R deleteMethod(String id) { + Assert.notBlank(id, "参数id不能为空"); + boolean ret = testRecordMethodService.deleteTestRecordMethod(id); + if (ret) { + return R.ok("true", "删除成功"); + } else { + return R.failed("false", "删除成功"); + } + } + + //显示列表分页 + @GetMapping("/getMethodPageList") + @ApiOperation(value = "获取分页数据", notes = "") + public R getMethodPageList(Page page, TestRecordMethod testRecordMethod) { + return R.ok(testRecordMethodService.getTestRecordMethodPageList(page, testRecordMethod), "获取数据成功"); + } + + //显示列表 + @GetMapping("/getMethodList") + @ApiOperation(value = "获取列表", notes = "") + public R getMethodList(TestRecordMethod testRecordMethod) { + return R.ok(testRecordMethodService.getTestRecordMethodList(testRecordMethod), "获取数据成功"); + } + + @PutMapping("/useMethod") + @ApiOperation(value = "使用方法、取消使用方法", notes = "testRecordId:实验ID、methodId:方法ID、opCode:1使用,-1取消使用") + public R useTestRecordMethod(@RequestBody TestRecordArgumentDto argumentDto) { + return testRecordMethodService.useTestRecordMethod(argumentDto) ? R.ok("操作成功!") : R.failed("操作失败!"); + } + + @PutMapping("/useMethodToTemplate") + @ApiOperation(value = "针对模板使用方法、取消使用方法", notes = "templateId:模板ID、methodId:方法ID、opCode:1使用,-1取消使用") + public R useTemplateMethod(@RequestBody TestRecordArgumentDto argumentDto) { + return testRecordMethodService.useTemplateMethod(argumentDto) ? R.ok("操作成功!") : R.failed("操作失败!"); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordReagentController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordReagentController.java new file mode 100644 index 0000000..2e564d9 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordReagentController.java @@ -0,0 +1,99 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.lang.Assert; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TestRecordMethod; +import digital.laboratory.platform.inspection.entity.TestRecordReagent; +import digital.laboratory.platform.inspection.service.TestRecordMethodService; +import digital.laboratory.platform.inspection.service.TestRecordReagentService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + * @author xy + * @version 1.0 + * @title TestRecordReagent + * @description 实验用到的试剂耗材,标准物质 + * @create 2023/12/20 10:07 + */ +@RestController +@RequestMapping("/testRecord_reagent") +@Api(tags = "09-检验记录-使用的试剂耗材,标准物质管理", description = "检验记录-使用的试剂耗材,标准物质管理") +public class TestRecordReagentController { + @Resource + private TestRecordReagentService testRecordReagentService; + + //添加 + @PostMapping("/addReagent") + @ApiOperation(value = "添加实验使用的试剂耗材、标准物质", notes = "添加实验使用的试剂耗材、标准物质") + public R addReagent(@RequestBody TestRecordReagent testRecordReagent) { + TestRecordReagent ret = testRecordReagentService.addTestRecordReagent(testRecordReagent); + if (ret != null) { + return R.ok(ret, "添加数据成功"); + } else { + return R.failed("false", "添加数据失败"); + } + } + + //修改接口 + @PutMapping("/updateReagent") + @ApiOperation(value = "修改实验使用试剂耗材、标准物质", notes = "") + public R updateReagent(@RequestBody TestRecordReagent testRecordReagent) { + TestRecordReagent ret = testRecordReagentService.updateTestRecordReagent(testRecordReagent); + if (ret != null) { + return R.ok(ret, "添加成功"); + } else { + return R.failed("false", "添加失败"); + } + } + + //删除数据 + @DeleteMapping("/deleteReagent") + @ApiOperation(value = "删除实验使用试剂耗材、标准物质", notes = "") + public R deleteReagent(String id) { + Assert.notBlank(id, "参数id不能为空"); + boolean ret = testRecordReagentService.deleteTestRecordReagent(id); + if (ret) { + return R.ok("true", "删除成功"); + } else { + return R.failed("false", "删除成功"); + } + } + + //显示列表分页 + @GetMapping("/getReagentPageList") + @ApiOperation(value = "获取实验中试剂耗材分页数据", notes = "参数:" + "\n" + "1.testId:实验ID" + "\n" + "2.keywords:查询参数" + "\n" + "3.category:试剂耗材类别(传入试剂耗材/标准物质二选一即可)" + "\n" + "4.opCode:传入1或-1(1是查询所有(去重),-1是查询这个实验下的所有)") + public R getReagentPageList(Page page, String testId, String keywords, String category, Integer opCode) { + return R.ok(testRecordReagentService.getTestRecordReagentPageList(page, testId, keywords, category, opCode), "获取数据成功"); + } + + //显示列表 + @GetMapping("/getReagentList") + @ApiOperation(value = "获取实验中试剂耗材列表数据", notes = "获取实验中试剂耗材列表数据") + public R getReagentList(String testId, String category) { + return R.ok(testRecordReagentService.getTestRecordReagentList(testId, category), "获取数据成功"); + } + + @PutMapping("/useReagent") + @ApiOperation(value = "添加或移除实验过程中的试剂耗材", notes = "testRecordId:实验ID、reagentId:试剂耗材ID、opCode:1使用,-1取消使用") + public R useTestRecordReagent(@RequestBody TestRecordArgumentDto testRecordArgumentDto) { + return testRecordReagentService.useTestRecordReagent(testRecordArgumentDto) ? R.ok("添加成功!") : R.failed("添加失败!"); + } + + @PutMapping("/useReagentToTemplate") + @ApiOperation(value = "添加或移除模板中的试剂耗材", notes = "testRecordId:实验ID、reagentId:试剂耗材ID、opCode:1使用,-1取消使用") + public R useTestTemplateReagent(@RequestBody TestRecordArgumentDto testRecordArgumentDto) { + return testRecordReagentService.useTestTemplateReagent(testRecordArgumentDto) ? R.ok("添加成功!") : R.failed("添加失败!"); + } + + @GetMapping("/getReagentToTemplatePage") + @ApiOperation(value = "获取模板中试剂耗材分页数据", notes = "参数:" + "\n" + "1.templateId:模板ID" + "\n" + "2.keywords:查询参数" + "\n" + "3.category:试剂耗材类别(传入试剂耗材/标准物质二选一即可)" + "\n" + "4.opCode:传入1或-1(1是查询所有(去重),-1是查询这个模板下的所有)") + public R getReagentToTemplatePageList(Page page, String templateId, String keywords, String category, Integer opCode) { + return R.ok(testRecordReagentService.getTestTemplateReagentPageList(page, templateId, keywords, category, opCode), "获取数据成功"); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordSampleDataController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordSampleDataController.java new file mode 100644 index 0000000..a58d8b7 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordSampleDataController.java @@ -0,0 +1,302 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.inspection.constant.BusinessType; +import digital.laboratory.platform.inspection.dto.*; +import digital.laboratory.platform.inspection.entity.TestRecordSampleData; +import digital.laboratory.platform.inspection.service.TestRecordSampleDataService; +import digital.laboratory.platform.inspection.utils.TestDataFileUtil; +import digital.laboratory.platform.inspection.utils.datafile.hair.HairSewageCompoundData; +import digital.laboratory.platform.inspection.utils.datafile.nps.NPSDataFileStruct; +import digital.laboratory.platform.inspection.vo.TestResultBusinessVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.apache.ibatis.exceptions.TooManyResultsException; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.security.Principal; +import java.util.List; +import java.util.Map; + +/** + * @author xy + * @version 1.0 + * @title TestRecordSampleDataController 实验数据控制器 + * @description + * @create 2024/1/19 15:57 + */ +@RestController +@RequestMapping("/testRecord_TestData") +@Api(tags = "15-检验记录-实验数据管理服务", description = "检验记录-实验数据管理服务接口") +public class TestRecordSampleDataController { + + @Resource + private TestRecordSampleDataService testRecordSampleDataService; + + //解析数据文件 + @PostMapping("/parseTestData") + @ApiOperation(value = "上传检验数据文件", notes = "上传检验数据文件") + @ApiImplicitParams({ + @ApiImplicitParam(name = "fileTypeCode", value = "上传的文件格式,10001 岛津 | 10002 沃特斯毛发案件 | 20002 沃特斯任务 | 20001 沃特斯毛发任务", required = true), + @ApiImplicitParam(name = "testId", value = "实验id", required = true) + }) + public R parseTestData(@RequestPart("file") MultipartFile file, + @RequestParam("fileTypeCode") String fileTypeCode, + @RequestParam("testId") String testId) { + try { + testRecordSampleDataService.validateTestStatus(testId); + switch (BusinessType.getBusinessTypeByType(fileTypeCode)) { + case SCREENING_EVENT: + case NPS_CASE: { + List retDataList = TestDataFileUtil.analysisNpsDataFile(file);//NPS文件解析 + // 先删除这个实验id有关的数据在插入下新数据 + testRecordSampleDataService.remove(Wrappers.lambdaQuery().eq(TestRecordSampleData::getTestId, testId)); + Boolean saveTestDataFromNps = testRecordSampleDataService.saveTestDataFromNps(retDataList, testId); + return saveTestDataFromNps ? R.ok(true, "上传数据成功") : R.failed(false, "上传数据失败!"); + } + case BOINT_CASE: { + Map> hairCompoundDataMap = TestDataFileUtil.analysisWtsDataFile(file, 1);//毛发案件文件解析 /毛发任务文件解析 + // 先删除这个实验id有关的数据在插入下新数据 + testRecordSampleDataService.remove(Wrappers.lambdaQuery().eq(TestRecordSampleData::getTestId, testId)); + Boolean saveTestDataHairCase = testRecordSampleDataService.saveTestDataHairCase(hairCompoundDataMap, testId); + return saveTestDataHairCase ? R.ok(true, "上传数据成功") : R.failed(false, "上传数据失败!"); + } + case SEWAGE_JOB: { + // /污水任务文件解析 + Map> sewageCompoundDataMap = TestDataFileUtil.analysisWtsDataFile(file, 2);//毛发案件文件解析 /毛发任务文件解析 + // 先删除这个实验id有关的数据在插入下新数据 + testRecordSampleDataService.remove(Wrappers.lambdaQuery().eq(TestRecordSampleData::getTestId, testId)); + Boolean saveTestDataHairCase = testRecordSampleDataService.saveTestDataHairSewageTask(sewageCompoundDataMap, testId, fileTypeCode); + return saveTestDataHairCase ? R.ok(true, "上传数据成功") : R.failed(false, "上传数据失败!"); + } + case BOINT_JOB: { + // /毛发任务文件解析 + Map> hairCompoundDataMap = TestDataFileUtil.analysisWtsDataFile(file, 1);//毛发案件文件解析 /毛发任务文件解析 + // 先删除这个实验id有关的数据在插入下新数据 + testRecordSampleDataService.remove(Wrappers.lambdaQuery().eq(TestRecordSampleData::getTestId, testId)); + Boolean saveTestDataHairCase = testRecordSampleDataService.saveTestDataHairSewageTask(hairCompoundDataMap, testId, fileTypeCode); + return saveTestDataHairCase ? R.ok(true, "上传数据成功") : R.failed(false, "上传数据失败!"); + } + } + } catch (Exception err) { + err.printStackTrace(); + if (err instanceof RuntimeException) { + return R.failed(err.getMessage()); + } + return R.failed("上传文件异常,请检查数据文件"); + } + return R.failed("上传文件异常,请检查数据文件"); + } + + //手动录入结果的保存 -nps + @PostMapping("/saveNpsManualData") + @ApiOperation(value = "保存手动录入的实验结果数据", notes = "保存手动录入的实验结果数据") + private R saveNpsManualData(@RequestBody List npsDataFileStruct, String testId) { + return R.ok(testRecordSampleDataService.saveTestDataFromNps(npsDataFileStruct, testId)); + } + + @PutMapping("/saveQuantitativeResults") + @ApiOperation(value = "保存实验数据的定量结果", notes = "保存实验数据的定量结果") + private R saveQuantitativeResults(@RequestBody SaveQuantitativeResultsDTO dto) { + boolean success = false; + try { + success = testRecordSampleDataService.saveQuantitativeResults(dto); + } catch (Exception e) { + e.printStackTrace(); + if (e instanceof TooManyResultsException) { + return R.failed(String.format("在上样编号 %s 中检测化合物 %s 在不同的实验中出现重复!", dto.getSampleName(), dto.getCompoundName())); + } else if (e instanceof RuntimeException) { + return R.failed(e.getMessage()); + } + return R.failed("系统出错,请联系管理员!"); + } + return R.ok(success); + } + + @DeleteMapping("/deleteQuantitativeResults") + @ApiOperation(value = "删除实验数据的定量结果", notes = "删除实验数据的定量结果, 这里的删除只是把定量结果制空") + private R deleteQuantitativeResults(@RequestParam("testSampleDataId") String testSampleDataId) { + boolean deleted = false; + try { + deleted = testRecordSampleDataService.deleteQuantitativeResults(testSampleDataId); + } catch (Exception e) { + e.printStackTrace(); + if (e instanceof RuntimeException) { + return R.failed("删除失败!" + e.getMessage()); + } + return R.failed("删除失败!"); + } + return R.ok(deleted); + } + + @PutMapping("/updateEntrustTestData") + @ApiOperation(value = "修改导入的实验数据", notes = "修改导入的实验数据") + private R updateEntrustTestData(@RequestBody UpdateEntrustTestDataDTO dto) { + try { + testRecordSampleDataService.validateTestStatus(dto.getTestId()); + List list = dto.getList(); + if (CollUtil.isNotEmpty(list)) { + for (UpdateEntrustTestDataDTO updateEntrustTestDataDTO : list) { + testRecordSampleDataService.updateEntrustTestData(updateEntrustTestDataDTO); + } + return R.ok("实验数据保存成功"); + } else { + return R.ok(testRecordSampleDataService.updateEntrustTestData(dto)); + } + } catch (Exception e) { + e.printStackTrace(); + if (e instanceof RuntimeException) { + return R.failed("实验数据保存失败!" + e.getMessage()); + } + return R.failed("实验数据保存失败!"); + } + } + + //分析获取检验结果 + @GetMapping("/getAnalysisTestResult") + @ApiOperation(value = "获取实验结果", notes = "获取实验结果, 其中 " + + "targetRtTime 目标物保留时间," + + "stdRtTime 标准物保留时间," + + "rtTimeError 保留时间相对误差," + + "rtTimeWithinError 保留时间是否在误差范围内") + @ApiImplicitParams({ + @ApiImplicitParam(name = "testId", value = "实验id", required = true), + @ApiImplicitParam(name = "type", value = "检验数据的类型,比如说是nps的还是毛发案件的", required = true) + }) + public R getAnalysisTestResult(@RequestParam("testId") String testId, @RequestParam("type") String type) { + if (type.equals(BusinessType.BOINT_CASE.getBusinessType()) + || type.equals(BusinessType.NPS_CASE.getBusinessType()) + || type.equals(BusinessType.SCREENING_EVENT.getBusinessType())) { + return R.ok(testRecordSampleDataService.getSampleTestDataByTestId(testId, type)); + } else { + // 任务实验数据 + Map map = testRecordSampleDataService.queryTaskTestResult(testId); + return R.ok(map); + } + } + + @PostMapping("/getAnalysisTestResultPage") + @ApiOperation(value = "分页查询-获取实验结果", notes = "分页查询-获取实验结果") + public R> getAnalysisTestResultPage(@RequestBody @Valid AnalysisTestResultPageDTO pageDTO) { + Page page = null; + try { + page = testRecordSampleDataService.getSampleTestDataByTestIdPage(pageDTO); + } catch (Exception e) { + e.printStackTrace(); + return R.failed("查询失败,系统异常!"); + } + return R.ok(page); + } + + @GetMapping("/getSampleTestDataByBusinessId") + @ApiOperation(value = "根据业务id查询检验数据, 这里的业务id可能是委托id 、 筛查id、 任务id", notes = "根据业务id查询检验数据, 这里的业务id可能是委托id 、 筛查id、 任务id") + @ApiImplicitParams({ + @ApiImplicitParam(name = "businessId", value = "业务id", required = true), + @ApiImplicitParam(name = "type", value = "查询的业务类型, 10000 委托 | 20000 任务 | 30000 筛查", required = false) + }) + public R getSampleTestDataByBusiness(@RequestParam("businessId") String businessId, Integer type) { + List sampleTestDataByBusiness = null; + try { + if (type != null && type.equals(20000)) { + // 20000 代表该业务id是任务的 + Map map = testRecordSampleDataService.queryTaskTestResultByBusiness(businessId); + return R.ok(map); + } + sampleTestDataByBusiness = testRecordSampleDataService.getSampleTestDataByBusiness(businessId); + } catch (Exception e) { + e.printStackTrace(); + if (e.getMessage().contains("Duplicate key")) { + return R.failed("查询失败,系统异常,数据中在同一个化合物中有重复编号存在!"); + } else if (e instanceof RuntimeException) { + return R.failed("查询失败,系统异常!" + e.getMessage()); + } + return R.failed("查询失败,系统异常!"); + } + return R.ok(sampleTestDataByBusiness); + } + + // 实验结果等相关接口 + @PostMapping("/queryTestResultPage") + @ApiOperation(value = "实验结果查询中分页查询", notes = "实验结果查询中分页查询, 10000 委托、20000 任务、 30000 筛查") + public R> queryTestResultPage(@RequestBody QueryTestResultPageDTO dto, HttpServletRequest theHttpServletRequest) { + Principal principal = theHttpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + IPage resultPage = null; + try { + resultPage = testRecordSampleDataService.queryTestResultPage( + new Page(dto.getCurrent(), dto.getSize()), + dto, dlpUser); + } catch (Exception e) { + e.printStackTrace(); + return R.failed("分页查询出错,详细信息请查看控制台!"); + } + + return R.ok(resultPage); + } + + @PostMapping("/finishTest") + @ApiOperation(value = "完成实验", notes = "完成实验") + @ApiImplicitParam(name = "testId", value = "实验id", required = true) + public R finishTest(@RequestParam("testId") String testId) { +// testRecordSampleDataService.finishTest(testId); + try { + return testRecordSampleDataService.finishTest(testId); + } catch (Exception e) { + e.printStackTrace(); + return R.failed(e.getMessage()); + } + } + + @PostMapping("/queryWaitApproveTaskTestDataPage") + @ApiOperation(value = "分页查询-获取审核的任务检验数据", notes = "分页查询-获取审核的任务检验数据") + public R queryWaitApproveTaskTestDataPage(@RequestBody @Valid TaskTestDataPageDTO pageDTO) { + Map map = null; + try { + map = testRecordSampleDataService.queryWaitApproveTaskTestDataPage(pageDTO); + } catch (Exception e) { + e.printStackTrace(); + return R.failed("查询失败,系统异常!"); + } + return R.ok(map); + } + + @PutMapping("/audit") + @ApiOperation(value = "审核审批数据", notes = "审核审批数据") + public R audit(@RequestBody @Valid AuditDataDTO auditDataDTO, HttpServletRequest httpServletRequest) { + return testRecordSampleDataService.auditTaskTestData(auditDataDTO, httpServletRequest); + } + + + private void NPSTestResultAnalysis(List npsDataFileStructList) { + //NPS的分析暂时只考虑定性分析,定性分析的逻辑如下 + // 1、获取定性分析的条件, 2、循环该实验下的所有检材的数据,根据定性条件判断获取分析结果 + + } + + + @PutMapping("/updateCompoundCnName") + @ApiOperation(value = "添加中文化合物名称", notes = "添加中文化合物名称") + public R updateCompoundCnName(@RequestBody UpdateCompoundCnNameDto dto) { + List list = testRecordSampleDataService.list(Wrappers.lambdaQuery() + .in(TestRecordSampleData::getId, dto.getIdList())); + + list.forEach(testRecordSampleData -> { + testRecordSampleData.setCompoundCnName(dto.getCompoundCnName()); + testRecordSampleDataService.updateById(testRecordSampleData); + }); + return R.ok("更新成功!"); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordSampleSolutionController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordSampleSolutionController.java new file mode 100644 index 0000000..2118763 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordSampleSolutionController.java @@ -0,0 +1,80 @@ +package digital.laboratory.platform.inspection.controller; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.dto.TestRecordSampleSolutionDto; +import digital.laboratory.platform.inspection.entity.TestRecordSampleSolution; +import digital.laboratory.platform.inspection.entity.TestRecordStandardSolution; +import digital.laboratory.platform.inspection.service.TestRecordSampleSolutionService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +@RestController +@RequestMapping("/testRecord_sampleSolution") +@Api(tags = "10-检验记录-使用的样本溶液,样本溶液管理", description = "检验记录-使用的样本溶液,样本溶液管理") +public class TestRecordSampleSolutionController { + + @Resource + private TestRecordSampleSolutionService testRecordSampleSolutionService; + + @PostMapping("/addSolution") + @ApiOperation(value = "添加实验样本溶液", notes = "添加实验过程中使用的样本溶液") + public R addTestRecordSampleSolution(@RequestBody TestRecordSampleSolutionDto testRecordSampleSolutionDto) { + TestRecordSampleSolution testRecordSampleSolution = testRecordSampleSolutionService.addTestRecordSampleSolution(testRecordSampleSolutionDto); + return testRecordSampleSolution != null ? R.ok(testRecordSampleSolution, "添加成功!") : R.failed("添加失败!"); + } + + @DeleteMapping("/delSolution") + @ApiOperation(value = "删除实验样本溶液", notes = "删除实验过程中使用的样本溶液") + + public R delTestRecordSampleSolution(String id) { + return testRecordSampleSolutionService.delTestRecordSampleSolution(id) ? R.ok("删除成功!") : R.failed("删除失败!"); + } + + @PutMapping("/updateSolution") + @ApiOperation(value = "修改实验样本溶液", notes = "修改实验过程中使用的样本溶液") + public R updateTestRecordSampleSolution(@RequestBody TestRecordSampleSolutionDto testRecordSampleSolutionDto) { + TestRecordSampleSolution testRecordSampleSolution = testRecordSampleSolutionService.updateTestRecordSampleSolution(testRecordSampleSolutionDto); + return testRecordSampleSolution != null ? R.ok(testRecordSampleSolution, "修改成功!") : R.failed("修改失败!"); + } + + @GetMapping("/getSolutionList") + @ApiOperation(value = "通过实验(检验)ID查询样本溶液集合", notes = "通过实验(检验)ID查询样本溶液集合") + public R> getSolutionList(String testId, String keywords) { + return R.ok(testRecordSampleSolutionService.getSolutionList(testId, keywords), "查询成功"); + } + + @GetMapping("/getSolutionPage") + @ApiOperation(value = "通过实验(检验)ID查询样本溶液分页集合", notes = "通过实验(检验)ID查询样本溶液分页集合") + public R> getSolutionPage(Page page, String testId, String keywords) { + return R.ok(testRecordSampleSolutionService.getSolutionPage(page, testId, keywords), "查询成功"); + } + + @PutMapping("/matchingWeighing") + @ApiOperation(value = "通过实验ID匹配样本溶液质量与计算浓度", notes = "通过实验ID匹配样本溶液质量与计算浓度") + public R> matchingWeighing(String id) { + List testRecordSampleSolutionList = testRecordSampleSolutionService.matchingWeighing(id); + return testRecordSampleSolutionList != null ? R.ok(testRecordSampleSolutionList, "匹配成功!") : R.failed("匹配失败!"); + } + + + @PostMapping("/createTaskSamSol") + @ApiOperation(value = "根据任务类型实验中选择的检材创建对应的样本溶液", notes = "根据任务类型实验中选择的检材创建对应的样本溶液") + public R createTaskSamSol(String testId) { + return testRecordSampleSolutionService.createTaskSamSol(testId) ? R.ok("创建成功!") : R.failed("创建失败!"); + } + + @PostMapping("/copy") + @ApiOperation(value = "根据已有样本溶液创建多个样本溶液",notes = "参数 testRecordSampleSolutionDto:已有样本溶液对象;testRecordSampleSolutionDto中的materialIdList:需要创建的对应检材ID集合") + public R copySolution(@RequestBody TestRecordSampleSolutionDto testRecordSampleSolutionDto) { + List recordSampleSolutions = testRecordSampleSolutionService.copySolution(testRecordSampleSolutionDto); + return recordSampleSolutions != null ? R.ok(recordSampleSolutions, "创建成功!") : R.failed("创建失败!"); + } +} \ No newline at end of file diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordStandardSolutionController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordStandardSolutionController.java new file mode 100644 index 0000000..7a745b9 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestRecordStandardSolutionController.java @@ -0,0 +1,82 @@ +package digital.laboratory.platform.inspection.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.dto.TestRecordStandardSolutionDto; +import digital.laboratory.platform.inspection.entity.TestRecordStandardSolution; +import digital.laboratory.platform.inspection.service.TestRecordStandardSolutionService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +@RestController +@RequestMapping("/testRecord_standardSolution") +@Api(tags = "11-检验记录-使用的标准溶液,标准溶液", description = "检验记录-使用的标准溶液,标准溶液") + +public class TestRecordStandardSolutionController { + @Resource + private TestRecordStandardSolutionService testRecordStandardSolutionService; + + @PostMapping("/addSolution") + @ApiOperation(value = "添加实验标准溶液", notes = "添加实验过程中使用的标准溶液") + public R addTestRecordStandardSolution(@RequestBody TestRecordStandardSolutionDto testRecordStandardSolution) { + return testRecordStandardSolutionService.addTestRecordStandardSolution(testRecordStandardSolution) != null ? R.ok(testRecordStandardSolution, "添加成功!") : R.failed("添加失败!"); + } + + @PostMapping("/addBlankSolution") + @ApiOperation(value = "添加空白溶剂、空白样品 type 1:空白溶剂 -1:空白样品", notes = "添加空白溶剂、空白样品 type 1:空白溶剂 -1:空白样品") + public R addBlankSolution(String testId,Integer type) { + TestRecordStandardSolution testRecordStandardSolution = testRecordStandardSolutionService.addBlankSolution(testId,type); + return testRecordStandardSolution != null ? R.ok(testRecordStandardSolution, "添加成功!") : R.failed("添加失败!"); + } + + @PostMapping("/addQCSolution") + @ApiOperation(value = "添加质控溶液", notes = "添加质控溶液") + public R createQualityControlSol(String testId) { + List qualityControlSol = testRecordStandardSolutionService.createQualityControlSol(testId); + return qualityControlSol.size()>0 ? R.ok(qualityControlSol, "添加成功!") : R.failed("添加失败!"); + } + + @DeleteMapping("/delSolution") + @ApiOperation(value = "删除实验标准溶液", notes = "删除实验过程中使用的标准溶液") + public R delTestRecordStandardSolution(String id) { + return testRecordStandardSolutionService.delTestRecordStandardSolution(id) ? R.ok("删除成功!") : R.failed("删除失败!"); + } + + @PutMapping("/updateSolution") + @ApiOperation(value = "修改实验标准溶液", notes = "修改实验过程中使用的标准溶液") + public R updateTestRecordStandardSolution(@RequestBody TestRecordStandardSolutionDto testRecordStandardSolutionDto) { + return testRecordStandardSolutionService.updateTestRecordStandardSolution(testRecordStandardSolutionDto) != null ? R.ok(testRecordStandardSolutionDto, "修改成功") : R.failed("修改失败!"); + } + + @GetMapping("/getSolutionPage") + @ApiOperation(value = "通过实验(检验)ID查询标准溶液分页集合", notes = "通过实验(检验)ID查询标准溶液分页集合") + public R> getTestRecordStandardSolutionPage(Page page, String testId, String keywords) { + return R.ok(testRecordStandardSolutionService.getTestRecordStandardSolutionPage(page, testId, keywords), "查询成功!"); + } + + @GetMapping("/getSolutionList") + @ApiOperation(value = "通过实验(检验)ID查询标准溶液集合", notes = "通过实验(检验)ID查询标准溶液集合") + public R> getTestRecordStandardSolutionList(String testId, String keywords) { + return R.ok(testRecordStandardSolutionService.getTestRecordStandardSolutionList(testId, keywords), "查询成功!"); + } + + @PutMapping("/matchingWeighing") + @ApiOperation(value = "通过实验ID匹配标准溶液质量与计算浓度", notes = "通过实验ID匹配标准溶液质量与计算浓度") + public R> matchingWeighing(String id) { + List testRecordStandardSolutions = testRecordStandardSolutionService.matchingWeighing(id); + return testRecordStandardSolutions != null ? R.ok(testRecordStandardSolutions, "匹配成功!") : R.failed("匹配失败!"); + } + + @GetMapping("/detection") + @ApiOperation(value = "判断实验中是否存在至少一瓶标准溶液", notes = "判断实验中是否存在至少一瓶标准溶液") + public R detection(String testId) { + return R.ok(testRecordStandardSolutionService.detection(testId)); + } + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestTemplateController.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestTemplateController.java new file mode 100644 index 0000000..ca2b5e1 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/controller/TestTemplateController.java @@ -0,0 +1,87 @@ +package digital.laboratory.platform.inspection.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.inspection.dto.TemplateDeleteDto; +import digital.laboratory.platform.inspection.entity.TestTemplate; +import digital.laboratory.platform.inspection.service.TestTemplateService; +import digital.laboratory.platform.inspection.vo.TestTemplateVo; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.security.Principal; +import java.util.List; + +@RestController +@RequestMapping("/test_template") +@Api(tags = "13-实验模板", description = "实验模板") +public class TestTemplateController { + @Resource + private TestTemplateService testTemplateService; + + @PostMapping("/createTemplate/{testId}") + @ApiOperation(value = "根据实验创建模板") + public R createTemplate(@RequestBody TestTemplate testTemplate, HttpServletRequest httpServletRequest, @PathVariable String testId) throws Exception { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + TestTemplate template = testTemplateService.createTemplate(testTemplate, testId, dlpUser); + return template != null ? R.ok(template, "创建成功!") : R.failed("创建失败!"); + } + + @PutMapping("/editTemplate") + @ApiOperation(value = "修改模版信息") + public R editTemplate(TestTemplate testTemplate) { + return testTemplateService.editTemplate(testTemplate) != null ? R.ok(testTemplate, "修改成功!") : R.failed("修改失败!"); + } + + @PutMapping("/publishTemplate") + @ApiOperation(value = "通过ID发布模板") + public R publishTemplate(String id) { + TestTemplateVo template = testTemplateService.publishTemplate(id); + return template != null ? R.ok(template, "发布成功!") : R.failed("发布失败!"); + } + + @PutMapping("/blockTemplate") + @ApiOperation(value = "通过ID停用模板") + public R blockTemplate(String id) { + TestTemplateVo template = testTemplateService.blockTemplate(id); + return template != null ? R.ok(template, "停用成功!") : R.failed("停用失败!"); + } + + @GetMapping("/getTemplateById") + @ApiOperation(value = "通过ID查询模板信息") + public R getTemplateById(String id) { + return R.ok(testTemplateService.getTemplateById(id), "数据获取成功!"); + } + + @GetMapping("/getTemplatePage") + @ApiOperation(value = "分页查询模板信息") + public R getTemplateVoPage(Page page, Integer opCode, HttpServletRequest httpServletRequest, String keywords) { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + return R.ok(testTemplateService.getTemplateVoPage(page, opCode, dlpUser, keywords), "数据获取成功!"); + } + + @GetMapping("/getTemplateList") + @ApiOperation(value = "列表查询模板信息(创建实验时)") + public R getTemplateVoList(HttpServletRequest httpServletRequest) { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + return R.ok(testTemplateService.getTemplateVoList(dlpUser), "数据获取成功!"); + } + + @DeleteMapping() + @ApiOperation(value = "根据ID删除模板") + public R delTemplate(@RequestBody ListidList, HttpServletRequest httpServletRequest) { + Principal principal = httpServletRequest.getUserPrincipal(); + DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal(); + return testTemplateService.delTemplate(idList, dlpUser) ? R.ok("删除成功!") : R.failed("删除失败!"); + } + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AnalysisTestResultPageDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AnalysisTestResultPageDTO.java new file mode 100644 index 0000000..8277fed --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AnalysisTestResultPageDTO.java @@ -0,0 +1,35 @@ +package digital.laboratory.platform.inspection.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 获取实验数据分页查询DTO类 + */ +@Data +@ApiModel(value = "AnalysisTestResultPageDTO", description = "获取实验数据分页查询DTO类") +public class AnalysisTestResultPageDTO { + + @ApiModelProperty("分页参数,每页多少条") + private long size = 10L; + + @ApiModelProperty("分页参数, 当前页") + private long current = 1L; + + @ApiModelProperty("实验id") + @NotBlank(message = "参数不全,请检查参数是否符合!") + private String testId; + + @ApiModelProperty("获取数据类型, 检验数据的类型,比如说是nps的还是毛发案件的") + private String type; + + // 搜索参数 待定 + @ApiModelProperty("关键字") + private String keyword; + + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AppraisalProcessDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AppraisalProcessDto.java new file mode 100644 index 0000000..6889b74 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AppraisalProcessDto.java @@ -0,0 +1,13 @@ +package digital.laboratory.platform.inspection.dto; + +import lombok.Data; + +@Data +public class AppraisalProcessDto { + + private String appraisalProcess; + + public AppraisalProcessDto(String appraisalProcess) { + this.appraisalProcess = appraisalProcess; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AssignmentInfoDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AssignmentInfoDto.java new file mode 100644 index 0000000..69d11d9 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AssignmentInfoDto.java @@ -0,0 +1,19 @@ +package digital.laboratory.platform.inspection.dto; + +import digital.laboratory.platform.inspection.entity.AssignmentInfo; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class AssignmentInfoDto extends AssignmentInfo { + + @ApiModelProperty(value = "类型 1 : 按业务分配 -1:按检材分配") + Integer type; + @ApiModelProperty(value = "查询参数") + private Integer opCode; + + @ApiModelProperty(value = "搜索参数") + private String keywords; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AuditDataDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AuditDataDTO.java new file mode 100644 index 0000000..98e80ed --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/AuditDataDTO.java @@ -0,0 +1,28 @@ +package digital.laboratory.platform.inspection.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import java.util.List; + +/** + * 审核数据请求参数DTO + */ +@Data +@ApiModel(value = "AuditDataDTO", description = "审核数据请求参数DTO") +public class AuditDataDTO { + + @ApiModelProperty("任务检验数据的编号列表") + @NotEmpty(message = "未选择审核的数据!") + private List sampleNoList; + + @ApiModelProperty("操作类型, -1 审核审批不通过 | 1 审核通过 | 2 审批通过 ") + @Min(value = -1, message = "操作值不匹配!") + @Max(value = 3, message = "操作值不匹配!") + private Integer opCode; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/BaseCaseDataDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/BaseCaseDataDto.java new file mode 100644 index 0000000..83e34c3 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/BaseCaseDataDto.java @@ -0,0 +1,20 @@ +package digital.laboratory.platform.inspection.dto; + +import java.util.List; + +/** + * 为了复用,通过BaseCaseDataDto 作为参数类型,在其中传递不同的具体子类对象 + */ +public abstract class BaseCaseDataDto { + // 定义抽象方法和属性 + public abstract String getTestId(); + public abstract String getTargetConcentration(); + public abstract String getStdConcentration(); + public abstract String getCompoundName(); + public abstract double getTargetRtTime(); + public abstract double getStdRtTime(); + public abstract String getRtTimeWithinError(); + public abstract List getTestSampleDataList(); + public abstract int getIsDetected();//是否检出目标化合物 + public abstract String getSampleType();//样本类型- QC(质控) STD(标准品) Analyte(待测样品) +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/BusinessDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/BusinessDto.java new file mode 100644 index 0000000..deaf849 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/BusinessDto.java @@ -0,0 +1,10 @@ +package digital.laboratory.platform.inspection.dto; + +import lombok.Data; + +@Data +public class BusinessDto { + + private String businessId; + private String businessType; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/DataSolutionSampleDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/DataSolutionSampleDTO.java new file mode 100644 index 0000000..660f304 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/DataSolutionSampleDTO.java @@ -0,0 +1,47 @@ +package digital.laboratory.platform.inspection.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 封装检验数据、样本溶液、检材连表查询的DTO类 + */ +@Data +@ApiModel(value = "DataSolutionSampleDTO", description = "封装检验数据、样本溶液、检材连表查询的DTO类") +public class DataSolutionSampleDTO { + + @ApiModelProperty("检验数据id") + private String sampleDataId; + + @ApiModelProperty("检验数据结果json") + private String dataResultJson; + + @ApiModelProperty("化合物名称") + private String compoundName; + + @ApiModelProperty("是否检出,是否检出该物质 1检出 0 未检出") + private Integer isDetected; + + @ApiModelProperty("溶液编号") + private String sampleNo; + + @ApiModelProperty("检验id") + private String testId; + + @ApiModelProperty("检材id") + private String materialId; + + @ApiModelProperty("检材名称") + private String sampleName; + + @ApiModelProperty("业务id") + private String businessId; + + @ApiModelProperty("化合物浓度") + private Double sampleConcentration; + + @ApiModelProperty("委托中检材的序号") + private Integer orderNo;//委托中检材的序号 + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/DeleteTestAtlasDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/DeleteTestAtlasDTO.java new file mode 100644 index 0000000..bfde0cc --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/DeleteTestAtlasDTO.java @@ -0,0 +1,25 @@ +package digital.laboratory.platform.inspection.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import java.util.List; + +/** + * 删除图谱DTO参数 + */ +@Data +@ApiModel(value = "DeleteTestAtlasDTO", description = "删除图谱DTO参数") +public class DeleteTestAtlasDTO { + + @ApiModelProperty("检验id") + @NotBlank(message = "实验id不能为空!") + private String testId; + + @ApiModelProperty("删除的文件id列表") + @NotEmpty(message = "文件id不能为空!") + private List fileIds; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/EntrustInfoDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/EntrustInfoDto.java new file mode 100644 index 0000000..15777cd --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/EntrustInfoDto.java @@ -0,0 +1,10 @@ +package digital.laboratory.platform.inspection.dto; +import digital.laboratory.platform.inspetion.api.entity.EntrustInfo; +import digital.laboratory.platform.inspetion.api.entity.MaterialDto; +import lombok.Data; + +import java.util.List; +@Data +public class EntrustInfoDto extends EntrustInfo { + private List materialList; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/ExportSewageAnalystReportsDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/ExportSewageAnalystReportsDTO.java new file mode 100644 index 0000000..012d9cb --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/ExportSewageAnalystReportsDTO.java @@ -0,0 +1,42 @@ +package digital.laboratory.platform.inspection.dto; + +import com.alibaba.fastjson.JSONArray; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.web.bind.annotation.RequestParam; + +import java.time.LocalDate; +import java.util.List; + +@Data +@ApiModel(value = "ExportSewageAnalystReportsDTO", description = "导出污水专项检测毒品分析报告") +public class ExportSewageAnalystReportsDTO { + + @ApiModelProperty("任务id") + String jobId; + +// @ApiModelProperty("月份") +// LocalDate month; + + @ApiModelProperty("省名称") + String provinceName = "陕西省"; + + @ApiModelProperty("省地区编码") + String provinceCode = "610000"; + + @ApiModelProperty("是否生成依托咪酯相关的数据, 默认不生成") + private Boolean generateEtomidateTable = false; + + @ApiModelProperty("人均日吸烟(支)") + private Double dailySmokingPerCapita; + + @ApiModelProperty("常见毒品及其代谢物") + private List commonDrugAndMetabolites; + + @ApiModelProperty("人口标记物") + private List populationMarkers; + + @ApiModelProperty("报告配置") + private JSONArray reportConfig; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/HairSewageDataDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/HairSewageDataDto.java new file mode 100644 index 0000000..b9e1ba5 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/HairSewageDataDto.java @@ -0,0 +1,118 @@ +package digital.laboratory.platform.inspection.dto; + +import digital.laboratory.platform.inspection.utils.datafile.hair.HairSewageCompoundData; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +/** + * @author xy + * @version 1.0 + * @title HairCaseDataDto 毛发案件 数据文件解析信息 + * @description + * @create 2024/1/19 10:40 + */ +@Data +@ApiModel(value = "HairCaseDataDto", description = "毛发案件 数据文件解析信息") +public class HairSewageDataDto extends BaseCaseDataDto { + + @ApiModelProperty("对应的检验数据id") + private String testSampleDataId; + + @ApiModelProperty("目标物编号") + private String sampleNo; + + @ApiModelProperty("目标物名称") + private String sampleName; + + @ApiModelProperty("所属实验的ID") + private String testId;//所属实验的ID + + @ApiModelProperty("目标物保留时间") + private double targetRtTime;//目标物保留时间 + + @ApiModelProperty("模板目标物保留时间") + private String tmpTargetRtTime;//模板目标物保留时间 + + @ApiModelProperty("目标物浓度 ng/mL") + private String targetConcentration;//目标物浓度 ng/mL + + @ApiModelProperty("标准物保留时间") + private double stdRtTime;//标准物保留时间 + + @ApiModelProperty("标准物浓度") + private String stdConcentration;//标准物浓度 + + @ApiModelProperty("保留时间相对误差(%)") + private double rtTimeError;//保留时间相对偏差 + + @ApiModelProperty("模板保留时间相对误差(%)") + private String tmpRtTimeError;//保留时间相对偏差 + + @ApiModelProperty("保留时间是否在误差范围内, 是否符合") + private String rtTimeWithinError;//保留时间是否在误差范围内 + + @ApiModelProperty("定性离子对-上") + private String qualitativeIonPairUp; + + @ApiModelProperty("定性离子对-下") + private String qualitativeIonPairDown; + + @ApiModelProperty("峰面积-上") + private double peakAreaUp; + + @ApiModelProperty("模板峰面积-上") + private String tmpPeakAreaUp; + + @ApiModelProperty("峰面积-下") + private double peakAreaDown; + + @ApiModelProperty("模板峰面积-下") + private String tmpPeakAreaDown; + + @ApiModelProperty("离子丰度比") + private double ionAbundanceRatio; + + @ApiModelProperty("模板离子丰度比") + private String tmpIonAbundanceRatio; + + @ApiModelProperty("离子丰度比相对偏差(%)") + private double ionAbundanceRatioWithinError; + + @ApiModelProperty("模板离子丰度比相对偏差(%)") + private String tmpIonAbundanceRatioWithinError; + + @ApiModelProperty("是否检出") + private String whetherCheckOut; + + @ApiModelProperty("化合物名称") + private String compoundName; + + @ApiModelProperty("是否检出目标化合物") + private int isDetected;//是否检出目标化合物 + + @ApiModelProperty("样本类型- QC(质控) STD(标准品) Analyte(待测样品)") + private String sampleType;//样本类型- QC(质控) STD(标准品) Analyte(待测样品) + + @ApiModelProperty("检验数据详情") + private List testSampleDataList;//检验数据详情 + + @ApiModelProperty("封装定性离子对和峰面积") + private List> maps;//检验数据详情 + + @ApiModelProperty("业务类型") + private String businessType; + + @ApiModelProperty("定量结果") + private String quantitativeResults; + + @ApiModelProperty("化合物的中文名称") + private String compoundCnName; + +} + + + diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/NPSCaseTestDataDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/NPSCaseTestDataDto.java new file mode 100644 index 0000000..4015681 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/NPSCaseTestDataDto.java @@ -0,0 +1,69 @@ +package digital.laboratory.platform.inspection.dto; + +import digital.laboratory.platform.inspection.utils.datafile.nps.NPSTestDetailDataStruct; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title NPSCaseTestData NPS 案件定性数据文件对象--原始数据 + * @description + * @create 2024/1/19 10:39 + */ +@Data +public class NPSCaseTestDataDto extends BaseCaseDataDto{ + + @ApiModelProperty("对应的检验数据id") + private String testSampleDataId; + + private String sampleNo; + private String sampleName; + private String testId;//所属实验的ID + private double targetRtTime;//目标物保留时间 + private String targetConcentration;//目标物浓度 + private double stdRtTime;//标准物保留时间 + private String stdConcentration;//标准物浓度 + private double rtTimeError;//保留时间相对偏差 + private String rtTimeWithinError;//保留时间是否在误差范围内 + private int isDetected;//是否检出目标化合物 + private String sampleType;//样本类型- QC(质控) STD(标准品) Analyte(待测样品) + private List testSampleDataList;//检验数据详情 + + @ApiModelProperty("是否检出") + private String whetherCheckOut; + + @ApiModelProperty("业务类型") + private String businessType; + + @ApiModelProperty("定量结果") + private String quantitativeResults; + + @ApiModelProperty("化合物名称") + private String compoundName; + + @ApiModelProperty("化合物的中文名称") + private String compoundCnName; + + //返回化合物名称 + /*public String getCompoundName(){ + String compoundName=""; + for (NPSTestDetailDataStruct npsTestDetailDataStruct : testSampleDataList) { + compoundName=npsTestDetailDataStruct.getName(); + break; + } + return compoundName; + }*/ + /*private String getDetectedResult(){ + if(isDetected==1){ + whetherCheckOut = "检出"+getCompoundName(); + return whetherCheckOut; + }else { + whetherCheckOut = "未检出"+getCompoundName(); + return whetherCheckOut; + } + + }*/ +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/NPSCaseTestResultDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/NPSCaseTestResultDto.java new file mode 100644 index 0000000..eadcd32 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/NPSCaseTestResultDto.java @@ -0,0 +1,40 @@ +package digital.laboratory.platform.inspection.dto; + +import lombok.Data; + +/** + * @author xy + * @version 1.0 + * @title NPSCaseTestResultDto NPS 案件数据结果对象,这个需要加入标准溶液的数据信息 + * @description + * @create 2024/1/19 11:20 + */ +@Data +public class NPSCaseTestResultDto { + + private String sampleId; + private String sampleName; + + private Double targetRetentionTime;//目标物保留时间 + private Double stdRetentionTime;//参考标准物质保留时间 + private Integer rtErrorValue;//保留时间误差值,就是目标物保留时间与参考标准物质保留时间的差值 + private Boolean isInErrorRange;//是否在误差范围内,true 在误差范围内,false 不在误差范围内 + + private Double stdIar2;//参考物质离子丰度比 + private Double stdIar3;//参考物质离子丰度比 + private Double stdIar4;//参考物质离子丰度比 + + private Double targetIar2;//检材离子丰度比2 + private Double targetIar3;//检材离子丰度比2 + private Double targetIar4;//检材离子丰度比2 + + private Double errorIarValue2;//碎片2的误差 + private Double errorIarValue3;//碎片3的误差 + private Double errorIarValue4;//碎片4的误差 + + + + + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/NPSCaseTestSampleData.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/NPSCaseTestSampleData.java new file mode 100644 index 0000000..873ac33 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/NPSCaseTestSampleData.java @@ -0,0 +1,35 @@ +package digital.laboratory.platform.inspection.dto; + +import digital.laboratory.platform.inspection.utils.datafile.nps.NPSTestDetailDataStruct; +import lombok.Data; + +@Data +public class NPSCaseTestSampleData { + private String sampleNo; + private String targetConcentration;//目标物浓度 + private String targetRtTime;//目标物保留时间 + private String stdRtTime;//标准物保留时间 + private String stdConcentration;//标准物浓度 + private String rtTimeError;//保留时间相对偏差 + private String rtTimeWithinError;//保留时间是否在误差范围内 + private String id; + private String name; + private String type; + private String mass;//mz 质荷比 + private String retTime;//保留时间 + private String startTime; + private String endTime; + private String area;//峰面积 + private String stdRetTime; + private String sn; + private String abundanceRatio;//丰度比,如果是基峰,我们设置为1,丰度比的公式为自己的峰面积/基峰峰面积 + private String abundanceRatio_std;// 标准物质的丰度比 + private String abundanceRatioError;//丰度比偏差,如果是基峰不需要比,公式是 (自己的丰度比-标准品的MZ对应丰度比)/标准品的MZ对应丰度比 + private String errorRange;//误差范围 + private String withinError;//丰度比偏差是否在误差范围内 + private int isBasePeak;//是否是基峰,0 不是基峰 1 是基峰 + + private String compoundName;//化合物名称 + private int isDetected;//是否检出 0:未检出 1:检出 +} + diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/QueryTestResultPageDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/QueryTestResultPageDTO.java new file mode 100644 index 0000000..60559f4 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/QueryTestResultPageDTO.java @@ -0,0 +1,43 @@ +package digital.laboratory.platform.inspection.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.Date; + +/** + * 实验结果查询分页查询 + */ +@Data +@ApiModel(value = "QueryTestResultPageDTO", description = "实验结果查询分页查询的参数") +public class QueryTestResultPageDTO { + + @ApiModelProperty("分页参数,每页多少条") + private long size = 10L; + + @ApiModelProperty("分页参数, 当前页") + private long current = 1L; + + @ApiModelProperty("类型,10000 委托、20000 任务、 30000 筛查") + @NotNull(message = "参数不全, 请检查参数是否符合!") + private Integer type; + + @ApiModelProperty("关键字") + private String keyword; + + @ApiModelProperty("录入人-查询") + private String createBy; + + @ApiModelProperty("开始时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime startTime; + + @ApiModelProperty("结束时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime endTime; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/RegionalDrugConsumptionDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/RegionalDrugConsumptionDTO.java new file mode 100644 index 0000000..ca7724f --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/RegionalDrugConsumptionDTO.java @@ -0,0 +1,59 @@ +package digital.laboratory.platform.inspection.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 各行政区主要毒品总消费量表 数据DTO 数据传输对象 + */ +@Data +@ApiModel(value = "RegionalDrugConsumptionDTO", description = "各行政区主要毒品总消费量表 数据DTO") +public class RegionalDrugConsumptionDTO { + + @ApiModelProperty("行政区域") + private String regional; + + @ApiModelProperty("人均消耗量Heroin 海洛因") + private String pccHeroin;//人均消耗量Heroin + + @ApiModelProperty("人均消耗量MA 冰毒") + private String pccMa;//人均消耗量MA + + @ApiModelProperty("人均消耗量K 氯胺酮") + private String pccK;//人均消耗量K + + @ApiModelProperty("人均消耗量MDMA") + private String pccMdma;//人均消耗量MDMA + + @ApiModelProperty("人均消耗量COC 可卡因") + private String pccCoc;//人均消耗量COC + + @ApiModelProperty("人均消耗量Fen 芬太尼") + private String pccFen;//人均消耗量Fen + + @ApiModelProperty("人均消耗量 - 综合") + private String pccTotal;//人均消耗量 - 综合 + + @ApiModelProperty("总消耗量Heroin 海洛因") + private String tcHeroin;//总消耗量Heroin + + @ApiModelProperty("总消耗量MA 冰毒") + private String tcMa;//总消耗量MA + + @ApiModelProperty("总消耗量K 氯胺酮") + private String tcK;//总消耗量K + + @ApiModelProperty("总消耗量MDMA 摇头丸") + private String tcMdma;//总消耗量MDMA + + @ApiModelProperty("总消耗量COC 可卡因") + private String tcCoc;//总消耗量COC + + @ApiModelProperty("总消耗量Fen 芬太尼") + private String tcFen;//总消耗量Fen + + @ApiModelProperty("总消费量(克/天) 综合") + private String tcTotal;//总消耗了THC + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/ReportConfigDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/ReportConfigDTO.java new file mode 100644 index 0000000..de539f9 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/ReportConfigDTO.java @@ -0,0 +1,26 @@ +package digital.laboratory.platform.inspection.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 生成污水报告或者毛发报告的配置信息 + */ +@Data +@ApiModel(value = "ReportConfigDTO", description = "生成污水报告或者毛发报告的配置信息") +public class ReportConfigDTO { + + @ApiModelProperty(value = "字典类型") + private String dictType; + + @ApiModelProperty(value = "字典名称") + private String dictLabel; + + @ApiModelProperty(value = "备注") + private String remark; + + @ApiModelProperty(value = "区分外层数据和里层的数据, 1 是外层 2 是里层或者为空") + private String type; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/ResetSampleInjectorDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/ResetSampleInjectorDTO.java new file mode 100644 index 0000000..5b29308 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/ResetSampleInjectorDTO.java @@ -0,0 +1,54 @@ +package digital.laboratory.platform.inspection.dto; + +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 重置进样信息位置请求参数 + */ +@Data +@ApiModel(value = "ResetSampleInjectorDTO", description = "重置进样信息位置请求参数") +public class ResetSampleInjectorDTO { + + @ApiModelProperty("进样信息的id") + @NotBlank(message = "参数不全,进样信息的id不能为空!") + private String id; + + + @ApiModelProperty("进样位置信息数组") + private JSONArray injectorInfo; + + /** + * 方盘-进样位置信息-1, 临时参数 + *//* + @ApiModelProperty("方盘-进样位置信息-1, 临时参数") + @TableField(exist = false) + private JSONArray injectorInfo1; + + *//** + * 方盘-进样位置信息-2, 临时参数 + *//* + @ApiModelProperty("方盘-进样位置信息-2, 临时参数") + @TableField(exist = false) + private JSONArray injectorInfo2; + + *//** + * 方盘-进样位置信息-3, 临时参数 + *//* + @ApiModelProperty("方盘-进样位置信息-3, 临时参数") + @TableField(exist = false) + private JSONArray injectorInfo3; + + *//** + * 方盘-进样位置信息-4, 临时参数 + *//* + @ApiModelProperty("方盘-进样位置信息-4, 临时参数") + @TableField(exist = false) + private JSONArray injectorInfo4;*/ +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SCCaseDataDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SCCaseDataDto.java new file mode 100644 index 0000000..019ea50 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SCCaseDataDto.java @@ -0,0 +1,12 @@ +package digital.laboratory.platform.inspection.dto; + +/** + * @author xy + * @version 1.0 + * @title SCCaseDataDto + * @description + * @create 2024/1/19 10:41 + */ + +public class SCCaseDataDto { +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SampleInjectorExcelDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SampleInjectorExcelDTO.java new file mode 100644 index 0000000..179f19a --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SampleInjectorExcelDTO.java @@ -0,0 +1,87 @@ +package digital.laboratory.platform.inspection.dto; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel(value = "SampleInjectorExcelDTO", description = "进样信息导出excel中的每一行数据DTO类") +public class SampleInjectorExcelDTO { + // @ExcelProperty:核心注解,value属性可用来设置表头名称,converter属性可以用来设置类型转换器; + @ExcelProperty(value = "FILE_NAME") + @ApiModelProperty(value = "溶液编号") + private String fileName; + + @ExcelProperty(value = "FILE_TEXT") + @ApiModelProperty(value = "溶液浓度") + private String fileText; + + @ExcelProperty(value = "MS_FILE") + @ApiModelProperty("默认空白") + private String msFile; + + @ExcelProperty(value = "MS_TUNE_FILE") + @ApiModelProperty(value = "") + private String msTuneFile; + + @ExcelProperty(value = "INLET_FILE") + @ApiModelProperty(value = "") + private String inletFile; + + @ExcelProperty(value = "SAMPLE_LOCATION") + @ApiModelProperty("检材进样位置") + private String sampleLocation; + + @ExcelProperty(value = "SAMPLE_GROUP") + @ApiModelProperty(value = "") + private String sampleGroup; + + @ExcelProperty(value = "TYPE") + @ApiModelProperty(value = "溶液类型") + private String type; + + @ExcelProperty(value = "ID") + @ApiModelProperty("") + private String id; + + @ExcelProperty(value = "CONC_A") + @ApiModelProperty(value = "") + private String concA; + + @ExcelProperty(value = "CONC_B") + @ApiModelProperty(value = "") + private String concB; + + @ExcelProperty(value = "CONC_C") + @ApiModelProperty("") + private String concC; + + @ExcelProperty(value = "CONC_D") + @ApiModelProperty(value = "") + private String concD; + + @ExcelProperty(value = "CONC_E") + @ApiModelProperty(value = "") + private String concE; + + @ExcelProperty(value = "CONC_F") + @ApiModelProperty("") + private String concF; + + @ExcelProperty(value = "INJ_VOL") + @ApiModelProperty(value = "") + private String injVol; + + @ExcelProperty(value = "QUAN_REF") + @ApiModelProperty(value = "") + private String quanRef; + + @ExcelProperty(value = "METH_DB") + @ApiModelProperty("") + private String methDb; + + @ExcelProperty(value = "Index") + @ApiModelProperty(value = "") + private Integer index; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SaveQuantitativeResultsDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SaveQuantitativeResultsDTO.java new file mode 100644 index 0000000..5640722 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SaveQuantitativeResultsDTO.java @@ -0,0 +1,33 @@ +package digital.laboratory.platform.inspection.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 保存实验数据的定量结果 + */ +@Data +@ApiModel(value = "SaveQuantitativeResultsDTO", description = "保存实验数据的定量结果") +public class SaveQuantitativeResultsDTO { + + @ApiModelProperty("目标物上样编号 --- 生物样本检验时的参数为上样编号") + private String sampleName; + + @ApiModelProperty("目标物检材编号 -- 缴获物检验时的参数为检材编号") + private String sampleNo; + + @ApiModelProperty("化合物名称") + @NotBlank(message = "参数不全,请检查参数!") + private String compoundName; + + @ApiModelProperty("定量结果") + @NotBlank(message = "参数不全,请检查参数!") + private String quantitativeResults; + + /*@ApiModelProperty("保存的数据类型") + @NotBlank(message = "参数不全,请检查参数!") + private String type;*/ +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SewageDataDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SewageDataDto.java new file mode 100644 index 0000000..676251e --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/SewageDataDto.java @@ -0,0 +1,51 @@ +package digital.laboratory.platform.inspection.dto; + +import digital.laboratory.platform.sewage.vo.SewageJobIdentificationMaterialVO; +import lombok.Data; + +@Data +@SuppressWarnings("all") +public class SewageDataDto extends SewageJobIdentificationMaterialVO { + private Double cotinineConcentration = 0.0;//可替宁(ng/L) + private Double codeineConcentration = 0.0;//可待因(ng/L) + private Double mdaConcentration = 0.0;//MDA(ng/L) + private Double mdmaConcentration = 0.0;//MDMA(ng/L) + private Double cocaineConcentration = 0.0;//可卡因(ng/L) + private Double benzoylecgonineConcentration = 0.0;//苯甲酰爱康宁(ng/L) + private Double morphineConcentration = 0.0;//吗啡(ng/L) + private Double acetylmorphineConcentration = 0.0;//O6-单乙酰吗啡(ng/L) + private Double methamphetamineConcentration = 0.0;//甲基苯丙胺(ng/L) + private Double amphetamineConcentration = 0.0;//苯丙胺(ng/L) + private Double ketamineConcentration = 0.0;//氯胺酮(ng/L) + private Double norketamineConcentration = 0.0;//去甲氯胺酮(ng/L) + private Double thcConcentration = 0.0;//四氢大麻酸(ng/L) + private Double fenConcentration = 0.0;//芬太尼(ng/L) + private Double etomidateConcentration = 0.0;//依托咪酯(ng/L) + private Double dailySmokingPerCapita;//人均日吸烟 + private Double cotinineExcretion;//可替宁排泄量(mg/千人天) + private Double estimatedPopulation;//测算人口(千人) + private Double morphineLoad;//吗啡负荷量 + private Double codeineLoad;//可待因负荷量 + private Double codeineIsConvertedToMorphineLoad;//可待因转化为吗啡负荷量 + private Double medicalMorphineLoad;//医用吗啡负荷量 + private Double MA_AM; + private Double K_NK; + private Double pccHeroin;//人均消耗量Heroin + private Double pccMa;//人均消耗量MA + + private Double pccK;//人均消耗量K + + private Double pccMdma;//人均消耗量MDMA + private Double pccCoc;//人均消耗量COC + private Double pccThc;//人均消耗量THC + private Double pccFen;//人均消耗量Fen + + private Double tcHeroin;//总消耗量Heroin + private Double tcMa;//总消耗量MA + private Double tcK;//总消耗量K + private Double tcMdma;//总消耗量MDMA + private Double tcCoc;//总消耗量COC + private Double tcThc;//总消耗量THC + private Double tcFen;//总消耗了Fen + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TaskInfoDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TaskInfoDto.java new file mode 100644 index 0000000..bca5fef --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TaskInfoDto.java @@ -0,0 +1,12 @@ +package digital.laboratory.platform.inspection.dto; + +import digital.laboratory.platform.inspection.entity.TaskInfo; +import digital.laboratory.platform.inspetion.api.entity.MaterialDto; +import lombok.Data; + +import java.util.List; + +@Data +public class TaskInfoDto extends TaskInfo { + List materialList; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TaskTestDataDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TaskTestDataDTO.java new file mode 100644 index 0000000..8588a83 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TaskTestDataDTO.java @@ -0,0 +1,61 @@ +package digital.laboratory.platform.inspection.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 获取任务数据的DTO类 + */ +@Data +@ApiModel(value = "TaskTestDataDTO", description = "获取任务数据的DTO类") +public class TaskTestDataDTO { + + @ApiModelProperty("检验数据id") + private String sampleDataId; + + @ApiModelProperty("检验数据结果json") + private String dataResultJson; + + @ApiModelProperty("化合物名称") + private String compoundName; + + @ApiModelProperty("是否检出,是否检出该物质 1检出 0 未检出") + private Integer isDetected; + + @ApiModelProperty("溶液编号") + private String sampleNo; + + @ApiModelProperty("检验id") + private String testId; + + @ApiModelProperty("检材id") + private String materialId; + + @ApiModelProperty("检材名称") + private String sampleName; + + @ApiModelProperty("检材编号") + private String acceptNo; + + @ApiModelProperty("业务id") + private String businessId; + + @ApiModelProperty("任务名称") + private String taskName; + + @ApiModelProperty("业务类型") + private String businessType; + + @ApiModelProperty("任务数据审核状态") + private Integer status; + + @ApiModelProperty("对应的检材含这个化合物浓度") + private Double sampleConcentration; + + @ApiModelProperty("数据生成时间") + private LocalDateTime createTime; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TaskTestDataPageDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TaskTestDataPageDTO.java new file mode 100644 index 0000000..934bb10 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TaskTestDataPageDTO.java @@ -0,0 +1,38 @@ +package digital.laboratory.platform.inspection.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +/** + * 获取任务审核数据时分页查询参数 + */ +@Data +@ApiModel(value = "TaskTestDataPageDTO", description = "获取任务审核数据时分页查询参数") +public class TaskTestDataPageDTO { + + @ApiModelProperty("分页参数,每页多少条") + @Min(value = 10, message = "每页条数不能小于10") + private int size = 10; + + @ApiModelProperty("分页参数, 当前页") + @Min(value = 1, message = "当前页不能小于1") + private int current = 1; + + // 搜索参数 待定 + @ApiModelProperty("关键字, 支持任务名称,检材名称") + private String keyword; + + // 搜索参数 待定 + @ApiModelProperty("业务类型") + private String businessType; + + // 状态值 + @ApiModelProperty("状态, 1 任务审核列表 | 2 任务审批列表") + @Max(value = 2, message = "最大值为2") + @Min(value = 1, message = "最小值不能小于1") + private Integer status; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TemplateDeleteDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TemplateDeleteDto.java new file mode 100644 index 0000000..8be002b --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TemplateDeleteDto.java @@ -0,0 +1,10 @@ +package digital.laboratory.platform.inspection.dto; + +import lombok.Data; + +import java.util.List; +@Data +public class TemplateDeleteDto { + + List idList; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordArgumentDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordArgumentDto.java new file mode 100644 index 0000000..3f02130 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordArgumentDto.java @@ -0,0 +1,18 @@ +package digital.laboratory.platform.inspection.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class TestRecordArgumentDto { + + @ApiModelProperty(value = "实验ID") + private String testRecordId; + @ApiModelProperty("参数ID:例如试剂耗材ID、设备ID等") + private String argumentId; + @ApiModelProperty(value = "区分是添加还是移除 1:添加 -1:移除") + private Integer opCode; + + @ApiModelProperty(value = "模板ID") + private String templateId; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordDto.java new file mode 100644 index 0000000..f3aca15 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordDto.java @@ -0,0 +1,14 @@ +package digital.laboratory.platform.inspection.dto; + +import digital.laboratory.platform.inspetion.api.entity.TestRecord; +import lombok.Data; + +import java.util.List; + +@Data +public class TestRecordDto extends TestRecord { + + List businessDtoList; + + private String templateId; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordSampleSolutionDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordSampleSolutionDto.java new file mode 100644 index 0000000..0b4868d --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordSampleSolutionDto.java @@ -0,0 +1,11 @@ +package digital.laboratory.platform.inspection.dto; + +import digital.laboratory.platform.inspection.entity.TestRecordSampleSolution; +import lombok.Data; + +import java.util.List; + +@Data +public class TestRecordSampleSolutionDto extends TestRecordSampleSolution { + List materialIdList; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordStandardSolutionDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordStandardSolutionDto.java new file mode 100644 index 0000000..7341c78 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/TestRecordStandardSolutionDto.java @@ -0,0 +1,16 @@ +package digital.laboratory.platform.inspection.dto; + +import digital.laboratory.platform.inspection.entity.TestRecordStandardSolution; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class TestRecordStandardSolutionDto extends TestRecordStandardSolution { + @ApiModelProperty(value = "编号后缀,使用单个标准物质时必填") + private Integer orderNum; + + @ApiModelProperty(value = "混合标准溶液名称集合") + private List standardNameList; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/UpdateCompoundCnNameDto.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/UpdateCompoundCnNameDto.java new file mode 100644 index 0000000..cb251ed --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/UpdateCompoundCnNameDto.java @@ -0,0 +1,12 @@ +package digital.laboratory.platform.inspection.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class UpdateCompoundCnNameDto { + + private List idList; + private String compoundCnName; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/UpdateEntrustTestDataDTO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/UpdateEntrustTestDataDTO.java new file mode 100644 index 0000000..7d77cab --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/dto/UpdateEntrustTestDataDTO.java @@ -0,0 +1,29 @@ +package digital.laboratory.platform.inspection.dto; + +import com.alibaba.fastjson.JSONObject; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * 修改导入的实验数据的参数DTO类 + */ +@Data +@ApiModel(value = "UpdateEntrustTestDataDTO", description = "修改导入的实验数据的参数DTO类") +public class UpdateEntrustTestDataDTO { + + @ApiModelProperty("保存的数据类型") + private String type; + + @ApiModelProperty("修改的具体数据信息") + private JSONObject param; + + @ApiModelProperty("修改的具体数据信息") + private String testId; + + @ApiModelProperty("只有该实验第一次保存数据时会接收这个参数,其他情况该参数为空") + List list; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/AssignmentInfo.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/AssignmentInfo.java new file mode 100644 index 0000000..3766db7 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/AssignmentInfo.java @@ -0,0 +1,53 @@ +package digital.laboratory.platform.inspection.entity; +/* + *@title AssignmentInfo + *@description 分配信息 + *@author xy + *@version 1.0 + *@create 2023/12/13 10:50 + */ + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@TableName(value = "b_assignmentInfo", autoResultMap = true) +@ApiModel(value = "分配信息", description = "分配信息") +public class AssignmentInfo extends BaseEntity { + private String id; + + @ApiModelProperty(value = "业务名称") + private String businessName; + + @ApiModelProperty(value = "业务类型") + private String businessType; + + @ApiModelProperty(value = "接收者Id") + private String testUser; + @ApiModelProperty(value = "分配者Id") + private String assignUser; + + @ApiModelProperty(value = "业务Id") + private String businessId; + + @ApiModelProperty(value = "样本ID") + private String sampleId; + + @ApiModelProperty(value = "样本名称") + private String sampleName; + + @ApiModelProperty(value = "接收者姓名") + private String testUserName; + + @ApiModelProperty(value = "分配者姓名") + private String assignUserName; + + //用来转换type类型的中文 + @TableField(exist = false) + private String businessTypeName; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/SampleInjector.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/SampleInjector.java new file mode 100644 index 0000000..bda44ea --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/SampleInjector.java @@ -0,0 +1,95 @@ +package digital.laboratory.platform.inspection.entity; + +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title 进样器管理 + * @description + * @create 2024/1/17 11:32 + */ +@Data +@TableName(value = "b_sample_injector", autoResultMap = true) +@ApiModel(value = "进样器信息", description = "进样器信息") +public class SampleInjector extends BaseEntity { + + @ApiModelProperty("主键id") + private String id; + + /** + * 进样器类型 1、圆盘进样器,2、方盘进样器 + */ + @ApiModelProperty("进样器类型 1、圆盘进样器,2、方盘进样器,0 未选择") + @NotNull(message = "请选择进样器类型!") + private Integer type = 0; + + /** + * 进样信息,位置信息,以json格式存储 + */ + @ApiModelProperty("进样信息,位置信息,以json格式存储") + private String injectorInfo; + + /** + * 检验ID,进样信息是属于某次试验的进样信息 + */ + @ApiModelProperty("检验ID,进样信息是属于某次试验的进样信息") + @NotBlank(message = "检验id不能为空!") + private String testId; + /** + * 空白起始位置 + */ + @ApiModelProperty("空白起始位置") + private Integer blankStartPosition; + + /** + * 空白穿插次数 + */ + @ApiModelProperty("空白穿插次数") + private Integer insertNumber; + + /** + * 是否已经保存, 默认false + */ + @ApiModelProperty("是否可以重置标识, true 可以重置, false 不能重置") + private boolean resetFlag = true; + +// /** +// * 方盘-进样位置信息-1, 临时参数 +// */ +// @ApiModelProperty("方盘-进样位置信息-1, 临时参数") +// @TableField(exist = false) +// private JSONArray injectorInfo1 = new JSONArray(); +// +// /** +// * 方盘-进样位置信息-2, 临时参数 +// */ +// @ApiModelProperty("方盘-进样位置信息-2, 临时参数") +// @TableField(exist = false) +// private JSONArray injectorInfo2 = new JSONArray(); +// +// /** +// * 方盘-进样位置信息-3, 临时参数 +// */ +// @ApiModelProperty("方盘-进样位置信息-3, 临时参数") +// @TableField(exist = false) +// private JSONArray injectorInfo3 = new JSONArray(); +// +// /** +// * 方盘-进样位置信息-4, 临时参数 +// */ +// @ApiModelProperty("方盘-进样位置信息-4, 临时参数") +// @TableField(exist = false) +// private JSONArray injectorInfo4 = new JSONArray(); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/ScreenInfo.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/ScreenInfo.java new file mode 100644 index 0000000..67d798b --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/ScreenInfo.java @@ -0,0 +1,38 @@ +package digital.laboratory.platform.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import digital.laboratory.platform.inspetion.api.entity.MaterialDto; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/* + *@title DrugScreen + *@description + *@author xy + *@version 1.0 + *@create 2023/12/8 11:33 + */ +@Data +@TableName("b_case_screen") +@ApiModel(value = "案前筛查信息", description = "案前筛查信息") +public class ScreenInfo extends BaseEntity { + private String id; + private String caseName; + private LocalDateTime obtainTime; + private String businessType;//业务类型 + private Integer source; + private String distributionSituation; //区分是否已被分配以及分配的数量 + private String originalId;//原筛查ID + @TableField(exist = false) + private String businessTypeName = "筛查事件"; + @TableField(exist = false) + private List materialList; + + @TableField(exist = false) + private Boolean isDistribution; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TaskInfo.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TaskInfo.java new file mode 100644 index 0000000..b433bd1 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TaskInfo.java @@ -0,0 +1,55 @@ +package digital.laboratory.platform.inspection.entity; + +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import digital.laboratory.platform.inspetion.api.entity.MaterialDto; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/* + *@title TaskInfo + *@description 任务信息实体 + *@author xy + *@version 1.0 + *@create 2023/12/7 15:17 + */ +@Data +@TableName(value = "b_taskInfo", autoResultMap = true) +@ApiModel(value = "任务信息", description = "任务信息") +public class TaskInfo extends BaseEntity { + private String id; + private String taskName;//任务名称 + private String businessType;//业务类型 + private LocalDateTime taskStartDate;//任务开始日期 + private LocalDateTime taskEndDate;//任务截止日期 + private Integer source;//0,系统录入 1,手工录入 + private String originalId;//原任务ID 可能是污水任务或者毛发任务 + private String distributionSituation; //区分是否已被分配以及分配的数量 + + private String compounds;//[{"compound1":"aaaa","english":"ab-fui"}] + + @ApiModelProperty(value = "生成报告的配置") + @TableField(value = "report_config", typeHandler = FastjsonTypeHandler.class) + private JSONArray reportConfig; + + @TableField(exist = false) + List materialList; + + @TableField(exist = false) + private String businessTypeName; + + @TableField(exist = false) + // 化合物json数组 + private JSONArray compoundsJsonArray; + + @TableField(exist = false) + private Boolean isDistribution; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordInstrument.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordInstrument.java new file mode 100644 index 0000000..53ba835 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordInstrument.java @@ -0,0 +1,28 @@ +package digital.laboratory.platform.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +/* + *@title TestRecordInstrument + *@description + *@author xy + *@version 1.0 + *@create 2023/12/19 11:12 + */ +@Data +@TableName("b_test_record_instrument") +@ApiModel(value = "实验中用到的仪器设备", description = "实验中用到的仪器设备") +public class TestRecordInstrument extends BaseEntity { + private String id; + private String instrumentNumber;//设备编号 + private String instrumentName;//设备名称 + private String instrumentProvider;//厂家名称 + private String instrumentTypeNo;//型号 + private Integer source;//来源,0 代表系统推送,1 代表手动录入 + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordInstrumentCondition.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordInstrumentCondition.java new file mode 100644 index 0000000..f22e5de --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordInstrumentCondition.java @@ -0,0 +1,27 @@ +package digital.laboratory.platform.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +/** + * @author xy + * @version 1.0 + * @title TestRecordInstrumentCondition 仪器使用条件 + * @description + * @create 2024/1/11 9:39 + */ +@Data +@TableName(value = "b_test_record_use_condition",autoResultMap = true) +@ApiModel(value = "实验中设备仪器条件", description = "实验中设备仪器条件") +public class TestRecordInstrumentCondition extends BaseEntity { + private String id; + private String testId;//检验ID + @TableField(typeHandler = FastjsonTypeHandler.class) + private String conditionData;//仪器条件内容(json 格式) + private Integer businessFlag;//判断是7楼还是六楼的业务 + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordMethod.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordMethod.java new file mode 100644 index 0000000..cc56f7d --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordMethod.java @@ -0,0 +1,32 @@ +package digital.laboratory.platform.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +import java.time.LocalDate; + +/* + *@title TestRecordInstrument + *@description 实验中用到的实验方法 + *@author xy + *@version 1.0 + *@create 2023/12/19 11:12 + */ +@Data +@TableName("b_test_record_Method") +@ApiModel(value = "实验中用到的实验方法", description = "实验中用到的实验方法") +public class TestRecordMethod extends BaseEntity { + private String id; + private String methodName;//方法名称 + private String methodDescribe;//方法描述 + private String methodRange;//范围 + private String methodLevel;//方法等级(国际、行标等) + private String methodFileNumber;//文件编号 + private LocalDate methodApprovalTime;//批准时间 + private LocalDate methodImplementTime;//实施时间 + private Integer source;//来源,0 代表系统推送,1 代表手动录入 + private String previewUrl;//方法Office地址 +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordQualitativeCondition.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordQualitativeCondition.java new file mode 100644 index 0000000..9d9b726 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordQualitativeCondition.java @@ -0,0 +1,42 @@ +package digital.laboratory.platform.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author xy + * @version 1.0 + * @description + * 保留时间的最大误差允许范围是 正负1% + *

+ * 离子丰度比相对偏差(检材离子丰度比与标准物质离子丰度比之间的差值 d),根据文件中的规则设定,规则是: + *

+ * 1、d>50% 相对偏差为:正负 10% + *

+ * 2、d>20%~50% d小于等于50%,大于20% 相对偏差为:正负 15% + *

+ * 3、d>10%~20% 小于等于20%,大于10% 相对偏差为:正负 20% + *

+ * 4、d<=10% 小于等于10% 相对偏差为:正负 50% + * @create 2024/1/30 17:28 + * + */ +@Data +@TableName(value = "b_test_record_qualitative_condition",autoResultMap = true) +public class TestRecordQualitativeCondition { + private String id; + @ApiModelProperty(value="保留时间相对误差") + private Double rtError; + @ApiModelProperty(value="是否包含保留时间上限: 0=不包含; 1=包含") + private Boolean includeRtErrorMax; + @ApiModelProperty(value="是否包含保留时间下限: 0=不包含; 1=包含") + private Boolean includeRtErrorMin; + @ApiModelProperty(value="是否包含离子丰度偏差下限: 0=不包含; 1=包含") + private Boolean includeRatioLow; + @ApiModelProperty(value="是否包含离子丰度偏差上限: 0=不包含; 1=包含") + private Boolean includeRatioHigh; + + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordReagent.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordReagent.java new file mode 100644 index 0000000..6d63e31 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordReagent.java @@ -0,0 +1,28 @@ +package digital.laboratory.platform.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +/** + * @author xy + * @version 1.0 + * @title TestRecordReagent + * @description 试剂耗材 + * @create 2023/12/20 11:02 + */ +@Data +@TableName("b_test_record_reagent_consumables") +@ApiModel(value = "实验中用到的试剂耗材", description = "实验中用到的试剂耗材") +public class TestRecordReagent extends BaseEntity { + private String id; + private String reagentConsumableName;//试剂耗材标准物质名称 + private String category;// 类别,表示是 试剂 还是 耗材 ,还是标准物质 + private String specifications; //型号规格 + private String purityGrade;//纯度等级,只有试剂有这个属性,当为耗材时为空 + private String number;//标准物质的编号,只有类型是标准物质的时候才设置 + private Integer sortIndex;// 排序 + private Integer source;//数据来源 + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordSampleData.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordSampleData.java new file mode 100644 index 0000000..96cd573 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordSampleData.java @@ -0,0 +1,69 @@ +package digital.laboratory.platform.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author xy + * @version 1.0 + * @title TestRecordSampleSolution + * @description 实验结果数据 + * @create 2023/12/20 11:36 + */ +@Data +@TableName(value = "b_test_record_sampledata", autoResultMap = true) +@ApiModel(value = "实验中样本检测结果数据", description = "实验中样本检测结果数据") +public class TestRecordSampleData extends BaseEntity { + private String id; + + private String testId;//实验ID,记录是哪次实验做的这个检材 + + @ApiModelProperty("数据从机器中导出的唯一标识, 目前只有生物样本案件需要") + private String name;//数据从机器中导出的唯一标识 + + private String sampleNo;//样本编号 + + private String compoundName;//检测的化合物(目标化合物) + + private String stdConcentration;//标准品的浓度 + + private String sampleConcentration;//样本的浓度 ng/mL + + private String rtTimeWithinError;//保留时间是否在误差范围 ±1 以内 + + private double targetRtTime;//目标物保留时间 + + private double stdRtTime;//标准物保留时间 + + private int isDetected;//是否检出目标化合物 + + private String sampleType;//样本类型- QC(质控) STD(标准品) Analyte(待测样品) + + private String dataJson;//实验数据-原始数据,以JSON的形式来存储该样本的实验数据 + + private String dataResultJson;//检验数据结果 + + private String compoundCnName;//检测的化合物的中文名字 + + @ApiModelProperty("任务数据审核状态, 状态:\n" + + "0 待审核,\n" + + "1 已审核,\n" + + "2 已审批, \n" + + "3 已上传 \n" + + "上传到大数据平台(仅针对任务数据, 其他业务类型的数据默认0)") + private Integer status; + + private String getDetectedResult() { + if (isDetected == 1) { + return "检出" + compoundName; + } else { + return "未检出" + compoundName; + } + + } + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordSampleSolution.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordSampleSolution.java new file mode 100644 index 0000000..0d53e33 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordSampleSolution.java @@ -0,0 +1,36 @@ +package digital.laboratory.platform.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +/** + * @author xy + * @version 1.0 + * @title TestRecordSampleSolution + * @description 样本溶液 + * @create 2023/12/20 11:36 + */ +@Data +@TableName("b_test_record_sample_solution") +@ApiModel(value = "实验中配置的样本溶液", description = "实验中配置的样本溶液") +public class TestRecordSampleSolution extends BaseEntity { + private String id; + private String sampleNo;//样品编号 + private String sampleShape;//样品性状 + private String dilutionName;//稀释溶剂名称 + private String extractionName;//提取溶剂名称 + private String constantVolume;//定容体积 + private String dilutionFactor;//稀释倍数 + private String originalConcentration;//原始浓度 + private String resultConcentration;//结果浓度 + private String weighingValue;//称取质量 + private String testId;//检验Id + private String materialId;//检材ID,表示这个溶液来自于 哪个检材 + @TableField(exist = false) + private String printSampleName;//打印检验记录中出现的名称:1号检材、2号检材 + private String remark; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordStandardSolution.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordStandardSolution.java new file mode 100644 index 0000000..e4502f6 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestRecordStandardSolution.java @@ -0,0 +1,83 @@ +package digital.laboratory.platform.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import digital.laboratory.platform.common.mybatis.base.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 标准溶液实体类。 + * + * 该类表示在实验过程中配置的标准溶液的相关信息。 + */ +@Data +@TableName(value = "b_test_record_standard_solution", autoResultMap = true) +@ApiModel(value = "TestRecordStandardSolution", description = "实验中配置的标准溶液") +public class TestRecordStandardSolution extends BaseEntity { + + @ApiModelProperty(value = "标准溶液ID") + private String id; + + @ApiModelProperty(value = "标准溶液编号") + private String number; + + @ApiModelProperty(value = "用到的标准物质名称,例如:甲基苯丙胺") + private String standardName; + + @ApiModelProperty(value = "稀释物质名称,例如:甲醇") + private String dilutionName; + + @ApiModelProperty(value = "定容体积") + private String constantVolume; + + @ApiModelProperty(value = "稀释倍数") + private String dilutionFactor; + + @ApiModelProperty(value = "原始浓度") + private String originalConcentration; + + @ApiModelProperty(value = "结果浓度") + private String resultConcentration; + + @ApiModelProperty(value = "结果浓度单位") + private String resultConcentrationUnit; + + @ApiModelProperty(value = "称取质量/移取体积") + private String weighingMoving; + + @ApiModelProperty(value = "检验ID") + private String testId; + + @ApiModelProperty(value = "选取标准物质数量(如果=1,则为单个标准物质溶液;如果>1,则为混合标准溶液;==0,则为空白溶液)") + private Integer standardSubstanceCount; + + @ApiModelProperty(value = "制备日期") + private LocalDateTime madeDate; + + @ApiModelProperty(value = "有效期") + private LocalDateTime expirationDate; + + @ApiModelProperty(value = "溶液类型(如质控溶液QC、标准工作溶液STD、空白溶液BLK)") + private String solutionType; + + @ApiModelProperty(value = "英文名,用于生成溶液编号") + private String englishName; + + @TableField(typeHandler = FastjsonTypeHandler.class) + @ApiModelProperty(value = "标准物质ID数组") + private List standardSubstanceNumList; + + @TableField(exist = false) + @ApiModelProperty(value = "打印制备日期", hidden = true) + private String madeDatePrint; + + @TableField(exist = false) + @ApiModelProperty(value = "打印有效期", hidden = true) + private String expirationDatePrint; +} \ No newline at end of file diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestTemplate.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestTemplate.java new file mode 100644 index 0000000..b0dd166 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/entity/TestTemplate.java @@ -0,0 +1,46 @@ +package digital.laboratory.platform.inspection.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title TestTemplate 检验模板实体 + * @description + * @create 2024/1/11 9:44 + */ +@TableName("b_test_template") +@ApiModel(value = "模板信息", description = "模板信息") +@Data +public class TestTemplate { + //仪器设备 + //试剂耗材 + //实验方法 + //仪器使用条件 + private String id; + private String name;//模板名称 + private boolean nature;//模板性质/公有-私有 0 =私有 1=公有 + private Integer status;//模板状态 0 =停用 1=启用 + private String author;//模板作者 + private Integer useCount;//模板被使用的次数 + private LocalDateTime createDate;//模板创建日期 + private LocalDateTime publishDate;//模板发布日期 + private String introduce;//模板介绍 + @TableField(typeHandler = FastjsonTypeHandler.class) + private List testMethods;//模板用到的实验方法 + @TableField(typeHandler = FastjsonTypeHandler.class) + private List deviceUseCondition;//仪器使用条件 + @TableField(typeHandler = FastjsonTypeHandler.class) + private List reagentConsumables;//使用的试剂耗材 + @TableField(typeHandler = FastjsonTypeHandler.class) + private List deviceIdList;//使用的仪器设备 + + private String businessType;//模板类型 +} \ No newline at end of file diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/event/AuditDataExecutionEvent.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/event/AuditDataExecutionEvent.java new file mode 100644 index 0000000..e91f3ad --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/event/AuditDataExecutionEvent.java @@ -0,0 +1,24 @@ +package digital.laboratory.platform.inspection.event; + +import org.springframework.context.ApplicationEvent; + +import java.util.List; + +/** + * 审核数据 自定义事件 + */ + +public class AuditDataExecutionEvent extends ApplicationEvent { + + private final List sampleNoList; + + + public AuditDataExecutionEvent(Object source, List sampleNoList) { + super(source); + this.sampleNoList = sampleNoList; + } + + public List getSampleNoList() { + return sampleNoList; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/event/FinishTestExecutionEvent.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/event/FinishTestExecutionEvent.java new file mode 100644 index 0000000..f651ead --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/event/FinishTestExecutionEvent.java @@ -0,0 +1,12 @@ +package digital.laboratory.platform.inspection.event; + +import org.springframework.context.ApplicationEvent; + +/** + * 监听实验完成 === 自定义事件类 + */ +public class FinishTestExecutionEvent extends ApplicationEvent { + public FinishTestExecutionEvent(Object source) { + super(source); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/listener/AuditDataExecutionEventListener.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/listener/AuditDataExecutionEventListener.java new file mode 100644 index 0000000..2d06b77 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/listener/AuditDataExecutionEventListener.java @@ -0,0 +1,31 @@ +package digital.laboratory.platform.inspection.listener; + +import digital.laboratory.platform.inspection.event.AuditDataExecutionEvent; +import digital.laboratory.platform.inspection.service.TaskInfoService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/*** + * 审核数据实验事件监听器 在审批数据成功后需要执行的方法 + */ +@Slf4j +@Component +public class AuditDataExecutionEventListener implements ApplicationListener { + + @Resource + private TaskInfoService taskInfoService; + + + @Override + public void onApplicationEvent(AuditDataExecutionEvent event) { + log.info("审核数据 监听器执行中 .........................."); + try { + taskInfoService.createUploadItem(event.getSampleNoList()); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/listener/FinishTestExecutionEventListener.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/listener/FinishTestExecutionEventListener.java new file mode 100644 index 0000000..8f17cfb --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/listener/FinishTestExecutionEventListener.java @@ -0,0 +1,22 @@ +package digital.laboratory.platform.inspection.listener; + +import digital.laboratory.platform.inspection.event.FinishTestExecutionEvent; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +/*** + * 完成实验事件监听器 在完成实验后需要执行的方法 + */ +@Slf4j +@Component +public class FinishTestExecutionEventListener implements ApplicationListener { + @Override + @Async + public void onApplicationEvent(FinishTestExecutionEvent event) { + + log.info("完成实验监听器执行中........"); + + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/AssignmentInfoMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/AssignmentInfoMapper.java new file mode 100644 index 0000000..dec205a --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/AssignmentInfoMapper.java @@ -0,0 +1,16 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import digital.laboratory.platform.inspection.entity.AssignmentInfo; +import org.apache.ibatis.annotations.Mapper; + +/* + *@title EntrustInfoMapper + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +@Mapper +public interface AssignmentInfoMapper extends BaseMapper { +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/EntrustInfoMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/EntrustInfoMapper.java new file mode 100644 index 0000000..f7468ec --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/EntrustInfoMapper.java @@ -0,0 +1,16 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import digital.laboratory.platform.inspetion.api.entity.EntrustInfo; +import org.apache.ibatis.annotations.Mapper; + +/* + *@title EntrustInfoMapper + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +@Mapper +public interface EntrustInfoMapper extends BaseMapper { +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/SampleInfoMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/SampleInfoMapper.java new file mode 100644 index 0000000..9846704 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/SampleInfoMapper.java @@ -0,0 +1,28 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/* + *@title EntrustInfoMapper + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +@Mapper +public interface SampleInfoMapper extends BaseMapper { + + List getSampleInfoList(@Param(value = "businessId") String businessId, @Param(value = "testUser") String testUser); + IPage getFullSampleInfoList(@Param("page") Page page, @Param(Constants.WRAPPER)LambdaQueryWrapper queryWrapper); + +// List getSampleInfoByAcceptNo(@Param(value = "acceptNo") String acceptNo, @Param(value = "idList") List idList); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/SampleInjectorMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/SampleInjectorMapper.java new file mode 100644 index 0000000..0b25821 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/SampleInjectorMapper.java @@ -0,0 +1,38 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import digital.laboratory.platform.inspection.entity.AssignmentInfo; +import digital.laboratory.platform.inspection.entity.SampleInjector; +import digital.laboratory.platform.inspection.vo.ResultConcentrationVO; +import digital.laboratory.platform.inspection.vo.TestRecordSolutionVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** +* 进样器mapper接口 +* date: 2024/2/18 17:04 +* @author: Chen +* @since JDK 1.8 +* Description: +*/ +@Mapper +public interface SampleInjectorMapper extends BaseMapper { + /** + * 获取进样信息中的检材列表 + * @param qw + * @return + */ + List queryMaterialList(@Param(Constants.WRAPPER) QueryWrapper qw); + + /** + * 查询相关样本或者标准品溶液结果浓度 + * @param qw + * @return + */ + List queryResultConcentrationList(@Param(Constants.WRAPPER) QueryWrapper qw); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/ScreenInfoMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/ScreenInfoMapper.java new file mode 100644 index 0000000..7029489 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/ScreenInfoMapper.java @@ -0,0 +1,16 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import digital.laboratory.platform.inspection.entity.ScreenInfo; +import org.apache.ibatis.annotations.Mapper; + +/* + *@title EntrustInfoMapper + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +@Mapper +public interface ScreenInfoMapper extends BaseMapper { +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TaskInfoMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TaskInfoMapper.java new file mode 100644 index 0000000..10a2675 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TaskInfoMapper.java @@ -0,0 +1,16 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import digital.laboratory.platform.inspection.entity.TaskInfo; +import org.apache.ibatis.annotations.Mapper; + +/* + *@title EntrustInfoMapper + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +@Mapper +public interface TaskInfoMapper extends BaseMapper { +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordInstrumentConditionMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordInstrumentConditionMapper.java new file mode 100644 index 0000000..f0868f7 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordInstrumentConditionMapper.java @@ -0,0 +1,23 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.inspection.entity.TestRecordInstrumentCondition; +import digital.laboratory.platform.inspection.vo.TestRecordInstrumentConditionVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface TestRecordInstrumentConditionMapper extends BaseMapper { + + IPage getTestRecordInstrumentConditionVoMapPage(Page page, @Param(Constants.WRAPPER) LambdaQueryWrapper qw); + + List getTestRecordInstrumentConditionVoMapList(@Param(Constants.WRAPPER) LambdaQueryWrapper qw); + + TestRecordInstrumentConditionVo getTestRecordInstrumentConditionVoMapByTestId(@Param(value = "testId") String testId); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordInstrumentMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordInstrumentMapper.java new file mode 100644 index 0000000..b3be5fa --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordInstrumentMapper.java @@ -0,0 +1,16 @@ +package digital.laboratory.platform.inspection.mapper; +/* + *@title TestRecordInstrumentMapper + *@description + *@author xy + *@version 1.0 + *@create 2023/12/19 11:45 + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import digital.laboratory.platform.inspection.entity.TestRecordInstrument; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TestRecordInstrumentMapper extends BaseMapper { +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordMapper.java new file mode 100644 index 0000000..d735d4b --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordMapper.java @@ -0,0 +1,28 @@ +package digital.laboratory.platform.inspection.mapper; +/* + *@title TestRecordMapper + *@description + *@author xy + *@version 1.0 + *@create 2023/12/19 11:43 + */ + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.inspetion.api.entity.TestRecord; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface TestRecordMapper extends BaseMapper { + TestRecordVo getTestRecordMapById(@Param(value = "id") String id); + + IPage getTestRecordMapPage(Page page, @Param(Constants.WRAPPER) LambdaQueryWrapper qw); + List getTestRecordMapList(@Param(Constants.WRAPPER) LambdaQueryWrapper qw); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordMethodMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordMethodMapper.java new file mode 100644 index 0000000..9319eac --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordMethodMapper.java @@ -0,0 +1,16 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import digital.laboratory.platform.inspection.entity.TestRecordMethod; +import org.apache.ibatis.annotations.Mapper; + +/* + *@title TestRecordMethodMapper + *@description + *@author xy + *@version 1.0 + *@create 2023/12/19 11:46 + */ +@Mapper +public interface TestRecordMethodMapper extends BaseMapper { +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordReagentMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordReagentMapper.java new file mode 100644 index 0000000..58bba30 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordReagentMapper.java @@ -0,0 +1,16 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import digital.laboratory.platform.inspection.entity.TestRecordReagent; +import org.apache.ibatis.annotations.Mapper; + +/** + * @author xy + * @version 1.0 + * @title TestRecordReagentMapper + * @description + * @create 2023/12/20 11:10 + */ +@Mapper +public interface TestRecordReagentMapper extends BaseMapper { +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordSampleDataMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordSampleDataMapper.java new file mode 100644 index 0000000..2c268ac --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordSampleDataMapper.java @@ -0,0 +1,70 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.inspection.dto.DataSolutionSampleDTO; +import digital.laboratory.platform.inspection.dto.TaskTestDataDTO; +import digital.laboratory.platform.inspection.entity.TestRecordSampleData; +import digital.laboratory.platform.inspection.vo.ESTBusinessInfoVO; +import digital.laboratory.platform.inspection.vo.TestResultBusinessVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title TestRecordSampleDataMapper + * @description + * @create 2024/1/18 11:06 + */ +@Mapper +public interface TestRecordSampleDataMapper extends BaseMapper { + + /** + * 通过业务id查询委托表、筛查表、任务表 + * @param qw + * @return + */ + List queryESTBusinessInfoList(@Param(Constants.WRAPPER) QueryWrapper qw); + + /** + * 实验结果查询中分页查询 + * @param page + * @param qw + * @return + */ + IPage queryTestResultTaskPage(Page page, @Param(Constants.WRAPPER) QueryWrapper qw); + + /** + * 实验结果查询中列表查询 + * @param qw + * @return + */ + List queryTestResultTaskList(@Param(Constants.WRAPPER) QueryWrapper qw); + + /** + * 通过业务id查询委托表、筛查表、任务表(以检验数据表为主表) + * @param qw + * @return + */ + List queryDataSolutionSampleDTOList(@Param(Constants.WRAPPER) QueryWrapper qw); + + /** + * 根据业务id 查询检材内容,然后通过检材id关联查询溶液,最后通过溶液编号查询数据(以检材表为主表) + * @param qw + * @return + */ + List getTestDataListByBusiness(@Param(Constants.WRAPPER) QueryWrapper qw); + + /** + * 获取任务检验数据中 + * @param qw + * @return + */ + List queryWaitApproveTaskTestDataList(@Param(Constants.WRAPPER) QueryWrapper qw); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordSampleSolutionMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordSampleSolutionMapper.java new file mode 100644 index 0000000..bfb5431 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordSampleSolutionMapper.java @@ -0,0 +1,9 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import digital.laboratory.platform.inspection.entity.TestRecordSampleSolution; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TestRecordSampleSolutionMapper extends BaseMapper { +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordStandardSolutionMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordStandardSolutionMapper.java new file mode 100644 index 0000000..5f82a9b --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestRecordStandardSolutionMapper.java @@ -0,0 +1,17 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.inspection.entity.TestRecordStandardSolution; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface TestRecordStandardSolutionMapper extends BaseMapper { + IPage getTestRecordStandardSolutionMapPage(Page page, @Param(value = "testId") String testId); + + List getTestRecordStandardSolutionMapList(@Param(value = "testId") String testId); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestTemplateMapper.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestTemplateMapper.java new file mode 100644 index 0000000..e0cb671 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/mapper/TestTemplateMapper.java @@ -0,0 +1,24 @@ +package digital.laboratory.platform.inspection.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import digital.laboratory.platform.inspection.entity.TestTemplate; +import digital.laboratory.platform.inspection.vo.TestTemplateVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface TestTemplateMapper extends BaseMapper { + + TestTemplateVo getTestTemplateMapById(@Param(value = "id")String id); + + IPage getTestTemplateMapPage(Page page,@Param(Constants.WRAPPER) LambdaQueryWrapper queryWrapper); + List getTestTemplateMapList(@Param(Constants.WRAPPER) LambdaQueryWrapper queryWrapper); + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/AssignmentInfoService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/AssignmentInfoService.java new file mode 100644 index 0000000..11c0b39 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/AssignmentInfoService.java @@ -0,0 +1,34 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.inspection.dto.AssignmentInfoDto; +import digital.laboratory.platform.inspection.entity.AssignmentInfo; +import digital.laboratory.platform.inspection.entity.TaskInfo; +import digital.laboratory.platform.inspection.vo.AssignmentInfoVo; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Objects; + +/* + *@title AssignmentInfoService + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +public interface AssignmentInfoService extends IService { + List addAssignmentInfo(List assignmentInfoDtoList);//添加任务信息 + public boolean cancelAssignmentInfo(List assignmentInfoList); + Boolean deleteAssignmentInfo(String id);//删除任务信息 + IPage getAssignmentInfoPageList(Page page, AssignmentInfoDto assignmentInfoDto); + List getAssignmentInfoList(AssignmentInfoDto assignmentInfoDto); + Boolean checkExist(String id); + + + boolean cancelByBusiness(List businessIdList); + + IPage getAssignedEntrustPage(Page page, String keywords); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/EntrustInfoService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/EntrustInfoService.java new file mode 100644 index 0000000..2af408c --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/EntrustInfoService.java @@ -0,0 +1,27 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.inspection.dto.EntrustInfoDto; +import digital.laboratory.platform.inspetion.api.entity.EntrustInfo; + +import java.util.List; + +/* + *@title EntrustInfoService + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +public interface EntrustInfoService extends IService { + EntrustInfo addEntrustInfo(EntrustInfoDto entrustInfo);//添加委托信息 + EntrustInfo updateEntrustInfo(EntrustInfo entrustInfo);//修改委托信息 + Boolean deleteEntrustInfo(String id);//删除委托信息 + IPage getEntrustPageList(Page page,Integer status, EntrustInfo entrustInfo, String keywords); + List getEntrustList(EntrustInfo entrustInfo); + Boolean checkExist(String id); + + boolean checkRepeatNo(String accept,String id); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/IdentifyBookDataService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/IdentifyBookDataService.java new file mode 100644 index 0000000..823e2ed --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/IdentifyBookDataService.java @@ -0,0 +1,30 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.common.core.util.R; +import org.apache.poi.ss.formula.functions.T; + +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title IdentifyBookDataService + * @description + * @create 2024/3/13 11:08 + */ + +public interface IdentifyBookDataService { + /** + * 获取鉴定文书需要的数据 + * @param businessId + * @return + */ + R getIdentifyBookDataByBusinessId(String businessId); + + /** + * 获取完成实验的数据 + * @return + */ + R getTestFinishBusinessData(List synedIdList); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/SampleInfoService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/SampleInfoService.java new file mode 100644 index 0000000..4a500bc --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/SampleInfoService.java @@ -0,0 +1,49 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import digital.laboratory.platform.inspetion.api.entity.MaterialDto; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/* + *@title SampleInfoService + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +public interface SampleInfoService extends IService { + SampleInfo addSampleInfo(SampleInfo sampleInfo);//添加样本信息 + + SampleInfo updateSampleInfo(SampleInfo sampleInfo);//修改样本信息 + + Boolean deleteSampleInfo(String id);//删除样本信息 + + IPage getSampleInfoPageList(Page page, SampleInfo sampleInfo); + + List getSampleInfoList(SampleInfo sampleInfo); + + Boolean checkExist(String id); + + IPage getPageForTestRecord(Page page, DLPUser dlpUser, String testId, String keywords); + + @Transactional + boolean useTestRecordSample(TestRecordArgumentDto testRecordArgumentDto); + + List getSampleInfoListForBusiness(String businessId, String testUser); + + boolean checkRepeatNo(String acceptNo,String id); + + /**复制其他系统检材内容 + * @param sampleInfo + * @param material + * @param type 0:委托 1:任务 2:筛查 + */ + void copy(SampleInfo sampleInfo, MaterialDto material, Integer type); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/SampleInjectorService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/SampleInjectorService.java new file mode 100644 index 0000000..1201d84 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/SampleInjectorService.java @@ -0,0 +1,59 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.inspection.dto.ResetSampleInjectorDTO; +import digital.laboratory.platform.inspection.entity.SampleInjector; +import digital.laboratory.platform.inspection.vo.TestRecordSolutionVO; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + +/** + * 进样器service 接口 + */ +public interface SampleInjectorService extends IService { + + /** + * 保存进样信息 + * @param sampleInjector + * @return + */ + SampleInjector saveSampleInjector(SampleInjector sampleInjector); + + /** + * 检材列表查询 + * @param testId + * @param key + * @return + */ + List queryMaterialList(String testId, String key); + + /** + * 导出进样信息excel表 + * @param id + * @param response + */ + void exportSampleInjectorInfoToExcel(String id, HttpServletResponse response); + + /** + * 重置进样信息 + * @param dto + * @return + */ + SampleInjector reset(ResetSampleInjectorDTO dto); + + /** + * 根据实验id获取,数据为空则初始部分数据返回 + * @param testId + * @return + */ + SampleInjector getByTestId(String testId); + + /** + * 判断当前进样器是否保存了进样位置信息 + * @param testId + * @return + */ + boolean whetherSave(String testId); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/ScreenInfoService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/ScreenInfoService.java new file mode 100644 index 0000000..e3c6b7b --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/ScreenInfoService.java @@ -0,0 +1,31 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.inspection.entity.ScreenInfo; +import digital.laboratory.platform.inspection.entity.TaskInfo; + +import java.util.List; + +/* + *@title EntrustInfoService + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +public interface ScreenInfoService extends IService { + ScreenInfo addScreenInfo(ScreenInfo screenInfo);//添加任务信息 + + ScreenInfo updateScreenInfo(ScreenInfo screenInfo);//修改任务信息 + + Boolean deleteScreenInfo(String id);//删除任务信息 + + IPage getScreenPageList(Page page, ScreenInfo screenInfo, String keywords); + + List getScreenList(ScreenInfo screenInfo, String keywords); + + Boolean checkExist(String id); + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/SewageDrugInspectReportService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/SewageDrugInspectReportService.java new file mode 100644 index 0000000..349d8d2 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/SewageDrugInspectReportService.java @@ -0,0 +1,14 @@ +package digital.laboratory.platform.inspection.service; + +import digital.laboratory.platform.inspection.dto.ExportSewageAnalystReportsDTO; + +/** + * 污水专项检测毒品分析报告 相关接口 + */ +public interface SewageDrugInspectReportService { + + /** + * 生成污水样品毒品检测分析报告 + */ + String generateSewageDrugInspectReportWord(ExportSewageAnalystReportsDTO dto) throws Exception; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TaskInfoService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TaskInfoService.java new file mode 100644 index 0000000..8604221 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TaskInfoService.java @@ -0,0 +1,61 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.dto.ExportSewageAnalystReportsDTO; +import digital.laboratory.platform.inspection.dto.SewageDataDto; +import digital.laboratory.platform.inspection.dto.TaskInfoDto; +import digital.laboratory.platform.inspection.entity.TaskInfo; +import digital.laboratory.platform.sewage.vo.SewageJobIdentificationMaterialVO; + +import java.time.LocalDate; +import java.io.IOException; +import java.util.List; + +/* + *@title EntrustInfoService + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +public interface TaskInfoService extends IService { + + /** + * 根据目标任务的开始时间进行排序 取4个任务的id + * @param targetTask + * @return + */ + List getTaskIdByOrderStartTimeLimit4(TaskInfo targetTask); + + TaskInfo addTaskInfo(TaskInfoDto taskInfo);//添加任务信息 + TaskInfo updateTaskInfo(TaskInfo taskInfo);//修改任务信息 + Boolean deleteTaskInfo(String id);//删除任务信息 + IPage getTaskPageList(Page page, TaskInfo taskInfo,String keywords); + List getTaskList(TaskInfo taskInfo,String keywords); + Boolean checkExist(String id); + + void createUploadItem(List sampleNos); + + List createSewageReportData(String taskId, Double dailySmokingPerCapita); + + /** + * 根据污水任务检材列表和人均日吸烟 处理报表数据,最后返回数据列表 + * @param dailySmokingPerCapita + * @param voList + * @return + */ + List processSewageDataDtos(Double dailySmokingPerCapita, List voList); + +// String createSewageReportExcel(List sewageDataDtos) throws IOException; + + /** + * 导出污水专项检测毒品分析报告 + * @param dto + * @return + */ + R exportSewageAnalystReports(ExportSewageAnalystReportsDTO dto); + String createSewageReportExcel(List sewageDataDtos,String id) throws IOException; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordInstrumentConditionService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordInstrumentConditionService.java new file mode 100644 index 0000000..f54648e --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordInstrumentConditionService.java @@ -0,0 +1,42 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TestRecordInstrumentCondition; +import digital.laboratory.platform.inspection.vo.TestRecordInstrumentConditionVo; +import org.apache.commons.fileupload.FileItem; + +import java.io.File; +import java.util.List; + +public interface TestRecordInstrumentConditionService extends IService { + TestRecordInstrumentCondition addInstrumentCondition(TestRecordInstrumentCondition testRecordInstrumentCondition); + + boolean delInstrumentCondition(String id); + + TestRecordInstrumentCondition updateInstrumentCondition(TestRecordInstrumentCondition testRecordInstrumentCondition); + + TestRecordInstrumentCondition getInstrumentConditionByTestId(String id); + + + boolean useInstrumentConditionToTemplate(TestRecordArgumentDto testRecordArgumentDto); + + + List copyCondition(List idList, String testId); + + String generatedOrNot(String testId); + + boolean createConditionWordByTest(String testId) throws Exception; + + //为模板创建仪器条件word + boolean createConditionWordByTemplate(String templateId) throws Exception; + + void copyConditionWord(String templateId, String testId) throws Exception; + + boolean mergeFile(String testId) throws Exception; + + //todo:一个文件类型转换的封装方法 + FileItem getMultipartFile(File file, String fieldName); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordInstrumentService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordInstrumentService.java new file mode 100644 index 0000000..41be600 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordInstrumentService.java @@ -0,0 +1,34 @@ +package digital.laboratory.platform.inspection.service; +/* + *@title TestRecordInstrumentService + *@description + *@author xy + *@version 1.0 + *@create 2023/12/19 14:40 + */ + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TestRecordInstrument; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +public interface TestRecordInstrumentService extends IService { + TestRecordInstrument addTestRecordInstrument(TestRecordInstrument testRecordInstrument);//添加实验使用仪器信息 + TestRecordInstrument updateTestRecordInstrument(TestRecordInstrument testRecordInstrument);//修改实验使用仪器信息 + Boolean deleteTestRecordInstrument(String id);//删除实验使用仪器信息 + IPage getTestRecordInstrumentPageList(Page page, String testId, String keywords, Integer opCode); + + IPage getTemplateInstrumentPageList(Page page, String templateId, String keywords, Integer opCode); + + List getTestRecordInstrumentList(TestRecordInstrument testRecordInstrument); + Boolean checkExist(String id); + + boolean useTestRecordInstrument(TestRecordArgumentDto testRecordArgumentDto); + + @Transactional(rollbackFor = Exception.class) + boolean useTemplateInstrument(TestRecordArgumentDto testRecordArgumentDto); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordMethodService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordMethodService.java new file mode 100644 index 0000000..30d0010 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordMethodService.java @@ -0,0 +1,28 @@ +package digital.laboratory.platform.inspection.service; +/* + *@title TestRecordMethodService + *@description + *@author xy + *@version 1.0 + *@create 2023/12/19 14:49 + */ + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TestRecordMethod; + +import java.util.List; +public interface TestRecordMethodService extends IService { + TestRecordMethod addTestRecordMethod(TestRecordMethod testRecordMethod);//添加实验使用方法 + TestRecordMethod updateTestRecordMethod(TestRecordMethod testRecordMethod);//修改实验使用方法 + Boolean deleteTestRecordMethod(String id);//删除实验使用方法 + IPage getTestRecordMethodPageList(Page page, TestRecordMethod testRecordMethod); + List getTestRecordMethodList(TestRecordMethod testRecordMethod); + Boolean checkExist(String id); + + boolean useTestRecordMethod(TestRecordArgumentDto testRecordArgumentDto); + + boolean useTemplateMethod(TestRecordArgumentDto testRecordArgumentDto); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordReagentService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordReagentService.java new file mode 100644 index 0000000..c48ad48 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordReagentService.java @@ -0,0 +1,36 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TestRecordMethod; +import digital.laboratory.platform.inspection.entity.TestRecordReagent; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title TestRecordReagentService + * @description + * @create 2023/12/20 11:12 + */ + +public interface TestRecordReagentService extends IService { + TestRecordReagent addTestRecordReagent(TestRecordReagent testRecordReagent);//添加实验使用方法 + TestRecordReagent updateTestRecordReagent(TestRecordReagent testRecordReagent);//修改实验使用方法 + Boolean deleteTestRecordReagent(String id);//删除实验使用方法 + IPage getTestRecordReagentPageList(Page page, String testId, String keywords, String category, Integer opCode); + List getTestRecordReagentList(String testId, String category); + + Boolean checkExist(String id); + + boolean useTestRecordReagent(TestRecordArgumentDto testRecordArgumentDto); + + @Transactional(rollbackFor = Exception.class) + boolean useTestTemplateReagent(TestRecordArgumentDto testRecordArgumentDto); + + IPage getTestTemplateReagentPageList(Page page, String templateId, String keywords, String category, Integer opCode); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordSampleDataService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordSampleDataService.java new file mode 100644 index 0000000..e7d21a8 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordSampleDataService.java @@ -0,0 +1,162 @@ +package digital.laboratory.platform.inspection.service; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.dto.*; +import digital.laboratory.platform.inspection.entity.TestRecordSampleData; +import digital.laboratory.platform.inspection.utils.datafile.hair.HairSewageCompoundData; +import digital.laboratory.platform.inspection.utils.datafile.nps.NPSDataFileStruct; +import digital.laboratory.platform.inspection.vo.TestResultBusinessVO; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Map; + +/** + * @author xy + * @version 1.0 + * @title TestRecordSampleDataService + * @description + * @create 2024/1/18 11:04 + */ + +public interface TestRecordSampleDataService extends IService { + + /** + * 校验实验状态是否完成,完成则提升不能修改数据 + * @param testId + */ + void validateTestStatus(String testId); + + //保存检验数据结果 + Boolean saveTestData(List testRecordSampleDataList); + + Boolean saveTestDataFromNps(List npsDataFileStructList,String testId); + + //获取检验记录中的样品信息数据 + List getNPSSampleTestDataByTestId(String testId); + + /** + * 根据业务id查询检验数据 + * @param businessId + * @return + */ + List getSampleTestDataByBusiness(String businessId); + + /** + * 毛发案件检验数据读取处理保存到数据库 + * + * @param hairCompoundDataMap 文件数据map + * @param testId 实验id + * @return + */ + Boolean saveTestDataHairCase(Map> hairCompoundDataMap, String testId); + + List getSampleTestDataByTestId(String testId, String type); + + /** + * 分页查询 根据实验id获取不同类型的数据 + * @param pageDTO + * @return + */ + Page getSampleTestDataByTestIdPage(AnalysisTestResultPageDTO pageDTO); + + /** + * 分页查询 获取审核的任务检验数据, header 是自定义头 data 是分页对象 + * @param pageDTO + * @return + */ + Map queryWaitApproveTaskTestDataPage(TaskTestDataPageDTO pageDTO); + + /** + * 毛发、污水任务检验数据导入并保存到数据库 + * + * @param sewageCompoundDataMap + * @param testId + * @param fileTypeCode + * @return + */ + Boolean saveTestDataHairSewageTask(Map> sewageCompoundDataMap, String testId, String fileTypeCode); + + /** + * 实验结果查询中分页查询 + * @param testResultBusinessVOPage + * @param dto + * @return + */ + IPage queryTestResultPage(Page testResultBusinessVOPage, QueryTestResultPageDTO dto, Object... arg); + + /** + * 修改导入的实验数据 + * + * @param dto + * @return + */ + JSONObject updateEntrustTestData(UpdateEntrustTestDataDTO dto); + + /** + * 获取任务实验结果数据 + * @param testId + * @return + */ + Map queryTaskTestResult(String testId); + + /** + * 根据业务id获取任务实验结果数据 + * @param businessId + * @return + */ + Map queryTaskTestResultByBusiness(String businessId); + + /** + * 保存实验数据的定量结果 + * @param dto + * @return + */ + boolean saveQuantitativeResults(SaveQuantitativeResultsDTO dto); + + /** + * 删除实验数据的定量结果 + * @param testSampleDataId + * @return + */ + boolean deleteQuantitativeResults(String testSampleDataId); + + /** + * 判断当前实验数据是否保存 + * @param testId + * @return + */ + boolean whetherSave(String testId); + + /** + * 根据业务id生成定性结果 + * @param businessId + * @return + */ + String generateQualitativeResults(String businessId); + + /** + * 完成实验 + * @param testId + * @return + */ + R finishTest(String testId); + + /** + * 审核审批数据 + * + * @param auditDataDTO + * @param httpServletRequest + * @return + */ + R auditTaskTestData(AuditDataDTO auditDataDTO, HttpServletRequest httpServletRequest); + + + //获取标准品样品信息数据 + // List getStdSampleTestDataByTestId(String testId); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordSampleSolutionService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordSampleSolutionService.java new file mode 100644 index 0000000..d362302 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordSampleSolutionService.java @@ -0,0 +1,30 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.inspection.dto.TestRecordSampleSolutionDto; +import digital.laboratory.platform.inspection.entity.TestRecordSampleSolution; + +import java.util.List; + +public interface TestRecordSampleSolutionService extends IService { + TestRecordSampleSolution addTestRecordSampleSolution(TestRecordSampleSolutionDto testRecordSampleSolutionDto); + + boolean delTestRecordSampleSolution(String id); + + TestRecordSampleSolution updateTestRecordSampleSolution(TestRecordSampleSolutionDto testRecordSampleSolutionDto); + + List getSolutionList(String testId,String keywords); + + IPage getSolutionPage(Page page, String testId,String keywords); + + List matchingWeighing(String testId); + + boolean createTaskSamSol(String testId); + + List copySolution(TestRecordSampleSolutionDto testRecordSampleSolutionDto); + + void isLoadSample(String acceptNo, String testId); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordService.java new file mode 100644 index 0000000..3f8ec0e --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordService.java @@ -0,0 +1,92 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.inspection.dto.DeleteTestAtlasDTO; +import digital.laboratory.platform.inspection.dto.TestRecordDto; +import digital.laboratory.platform.inspetion.api.entity.TestRecord; +import digital.laboratory.platform.inspection.vo.ProcedureVo; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +public interface TestRecordService extends IService { + @Transactional + TestRecord createTestInstance(TestRecordDto testRecord, DLPUser dlpUser) throws Exception; + + TestRecord updateTestInstance(TestRecord testRecord); + + TestRecordVo getTestRecord(String id, DLPUser dlpUser); + + IPage getTestRecordPageList(Page page, DLPUser dlpUser, LocalDateTime startTime, LocalDateTime endTime, String businessType); + + ListgetTestRecordList(DLPUser dlpUser); + + boolean updateTestRecordArgument(String testId, String testRecordArgumentId, String argument,Integer opCode); + + TestRecord useTemplate(String testId, String templateId) throws Exception; + + ProcedureVo getProcedure(String testId); + + Map getPrintData(String businessId) throws Exception; + + boolean createInspectionRecordByBiological(String businessId) throws Exception; + + boolean createInspectionRecord(String businessId) throws Exception; + + @Transactional(rollbackFor = Exception.class) + boolean delTestRecord(String testId); + + Page getResultSolutionPage(Page page, String testId); + + /** + * 上传实验图谱(单个) + * @param testId + * @param file + * @return + */ + R uploadTestAtlas(String testId, MultipartFile file) throws Exception; + + /** + * 上传实验图谱(批量) + * @param testId + * @param files + * @return + */ + R uploadTestAtlasBatch(String testId, List files); + + /** + * 获取该实验id的实验图谱 + * @param testId + * @return + */ + R getTestAtlasList(String testId); + + /** + * 删除实验图谱 + * @param dto + * @return + */ + R deleteTestAtlas(DeleteTestAtlasDTO dto) throws Exception; + + /** + * 根据业务id获取实验图谱 + * @param businessId + * @return + */ + R getTestAtlasListByBusinessId(String businessId); + + /** + * 根据业务id获取实验信息 + * @param businessIds + * @return + */ + R> queryTestRecordInfoByBusinessId(List businessIds); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordStandardSolutionService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordStandardSolutionService.java new file mode 100644 index 0000000..e2c8ac4 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestRecordStandardSolutionService.java @@ -0,0 +1,31 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.inspection.dto.TestRecordStandardSolutionDto; +import digital.laboratory.platform.inspection.entity.TestRecordStandardSolution; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +public interface TestRecordStandardSolutionService extends IService { + TestRecordStandardSolution addTestRecordStandardSolution(TestRecordStandardSolutionDto testRecordStandardSolution); + + TestRecordStandardSolution addBlankSolution(String testId,Integer type); + + List createQualityControlSol(String testId); + + boolean delTestRecordStandardSolution(String id); + + TestRecordStandardSolution updateTestRecordStandardSolution(TestRecordStandardSolutionDto testRecordStandardSolutionDto); + + IPage getTestRecordStandardSolutionPage(Page page,String testId, String keywords); + + List getTestRecordStandardSolutionList(String testId, String keywords); + + @Transactional + List matchingWeighing(String testId); + + boolean detection(String testId); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestTemplateService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestTemplateService.java new file mode 100644 index 0000000..daebcb3 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/TestTemplateService.java @@ -0,0 +1,32 @@ +package digital.laboratory.platform.inspection.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.inspection.dto.TemplateDeleteDto; +import digital.laboratory.platform.inspection.entity.TestTemplate; +import digital.laboratory.platform.inspection.vo.TestTemplateVo; + +import java.util.List; + +public interface TestTemplateService extends IService { + TestTemplate createTemplate(TestTemplate testTemplate, String testId, DLPUser dlpUser) throws Exception; + + TestTemplate editTemplate(TestTemplate testTemplate); + + boolean delTemplate(List idList, DLPUser dlpUser); + + boolean updateTestTemplate(String templateId, String argumentId, String argument, Integer opCode); + + TestTemplateVo publishTemplate(String id); + + TestTemplateVo blockTemplate(String id); + + TestTemplateVo getTemplateById(String id); + + IPage getTemplateVoPage(Page page, Integer opCode,DLPUser dlpUser, String keywords); + + List getTemplateVoList(DLPUser dlpUser); + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/AssignmentInfoServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/AssignmentInfoServiceImpl.java new file mode 100644 index 0000000..214ee05 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/AssignmentInfoServiceImpl.java @@ -0,0 +1,501 @@ +package digital.laboratory.platform.inspection.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import digital.laboratory.platform.inspection.constant.BusinessType; +import digital.laboratory.platform.inspection.dto.AssignmentInfoDto; +import digital.laboratory.platform.inspection.entity.*; +import digital.laboratory.platform.inspection.mapper.AssignmentInfoMapper; +import digital.laboratory.platform.inspection.service.*; +import digital.laboratory.platform.inspection.utils.PageUtils; +import digital.laboratory.platform.inspection.vo.AssignmentInfoVo; +import digital.laboratory.platform.inspetion.api.entity.EntrustInfo; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +/* + *@title AssignmentInfoServiceImpl + *@description + *@author xy + *@version 1.0 + *@create 2023/12/13 11:46 + */ +@Service +@Slf4j +public class AssignmentInfoServiceImpl extends ServiceImpl implements AssignmentInfoService { + + @Resource + private SampleInfoService sampleInfoService; + + @Resource + private EntrustInfoService entrustInfoService; + + @Resource + private ScreenInfoService screenInfoService; + + @Resource + private TaskInfoService taskInfoService; + + /** + * 创建分配任务信息 + * + * @param assignmentInfoDto + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public List addAssignmentInfo(List assignmentInfoDtoList) { + List assignmentInfos = new ArrayList<>(); + //1:通过业务 -1:通过检材 + Integer type = assignmentInfoDtoList.get(0).getType(); + //按业务进行分配 + if (type == 1) { + for (AssignmentInfoDto assignmentInfoDto : assignmentInfoDtoList) { + String businessId = assignmentInfoDto.getBusinessId(); + String businessType = assignmentInfoDto.getBusinessType(); + List sampleInfoList = sampleInfoService.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, businessId)); + if (businessType.startsWith("1")) { + List infoList = this.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, businessId)); + if (infoList != null && infoList.size() > 0 && !(infoList.get(0).getTestUser().equals(assignmentInfoDto.getTestUser()))) { + throw new RuntimeException(String.format("业务:" + infoList.get(0).getBusinessName() + "已分配给工作人员:" + infoList.get(0).getTestUserName() + ",如需继续分配,只能继续选择该工作人员,或者撤销已分配的任务后重新进分配!")); + } + EntrustInfo entrustInfo = entrustInfoService.getById(businessId); + entrustInfo.setStatus(1); + entrustInfoService.updateById(entrustInfo); + } else if (businessType.startsWith("2")) { + List infoList = this.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, businessId)); + if (infoList != null && infoList.size() > 0) { + throw new RuntimeException(String.format("业务:" + infoList.get(0).getBusinessName() + "中部分或全部检材已分配给其它工作人员,无法进行业务分配,你可以尝试点击右侧的分配检材功能继续进行分配!")); + } + TaskInfo taskInfo = taskInfoService.getById(businessId); + taskInfo.setDistributionSituation(sampleInfoList.size() + "/" + sampleInfoList.size()); + taskInfoService.updateById(taskInfo); + } else { + List infoList = this.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, businessId)); + if (infoList != null && infoList.size() > 0) { + throw new RuntimeException(String.format("业务:" + infoList.get(0).getBusinessName() + "中部分或全部检材已分配给其它工作人员,无法进行业务分配,你可以尝试点击右侧的分配检材功能继续进行分配!")); + } + ScreenInfo screenInfo = screenInfoService.getById(businessId); + screenInfo.setDistributionSituation(sampleInfoList.size() + "/" + sampleInfoList.size()); + screenInfoService.updateById(screenInfo); + } + if (CollUtil.isEmpty(sampleInfoList)) { + throw new RuntimeException("当前业务检材列表为空!不能添加分配信息。"); + } + + for (SampleInfo sampleInfo : sampleInfoList) { + AssignmentInfo assignmentInfo = new AssignmentInfo(); + BeanUtils.copyProperties(assignmentInfoDto, assignmentInfo); + assignmentInfo.setId(IdWorker.get32UUID().toUpperCase()); + assignmentInfo.setSampleId(sampleInfo.getId()); + assignmentInfo.setSampleName(sampleInfo.getSampleName()); + sampleInfo.setStatus(1); + assignmentInfos.add(assignmentInfo); + } + sampleInfoService.updateBatchById(sampleInfoList); + } + return this.saveBatch(assignmentInfos) ? assignmentInfos : null; + } else { + SampleInfo sampleInfo = sampleInfoService.getById(assignmentInfoDtoList.get(0).getSampleId()); + String businessType = sampleInfo.getBusinessType(); + String businessId = sampleInfo.getBusinessId(); + + ArrayList idList = new ArrayList<>(); + assignmentInfoDtoList.forEach(item -> idList.add(item.getSampleId())); + List sampleInfoList = sampleInfoService.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, businessId)); + List sampleInfos = sampleInfoService.list(Wrappers.lambdaQuery().in(SampleInfo::getId, idList)); + sampleInfos.forEach(item -> item.setStatus(1)); + sampleInfoService.updateBatchById(sampleInfos); + + List assignmentInfoList = this.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, businessId)); + int count = 0; + //计算分配情况 + if (assignmentInfoList != null && assignmentInfoList.size() > 0) { + count = assignmentInfoList.size() + assignmentInfoDtoList.size(); + } else { + count = assignmentInfoDtoList.size(); + } + String businessName = ""; + if (businessType.startsWith("1")) { + EntrustInfo entrustInfo = entrustInfoService.getById(businessId); + entrustInfo.setStatus(1); + businessName = entrustInfo.getCaseName(); + entrustInfoService.updateById(entrustInfo); + + } else if (businessType.startsWith("2")) { + TaskInfo taskInfo = taskInfoService.getById(businessId); + //分配情况 + taskInfo.setDistributionSituation(count + "/" + sampleInfoList.size()); + businessName = taskInfo.getTaskName(); + taskInfoService.updateById(taskInfo); + + } else { + ScreenInfo screenInfo = screenInfoService.getById(businessId); + //分配情况 + screenInfo.setDistributionSituation(count + "/" + sampleInfoList.size()); + businessName = screenInfo.getCaseName(); + screenInfoService.updateById(screenInfo); + } + for (AssignmentInfoDto assignmentInfoDto : assignmentInfoDtoList) { + AssignmentInfo assignmentInfo = new AssignmentInfo(); + BeanUtils.copyProperties(assignmentInfoDto, assignmentInfo); + assignmentInfo.setId(IdWorker.get32UUID().toUpperCase()); + assignmentInfo.setBusinessId(businessId); + assignmentInfo.setBusinessType(businessType); + assignmentInfo.setBusinessName(businessName); + assignmentInfos.add(assignmentInfo); + } + return this.saveBatch(assignmentInfos) ? assignmentInfos : null; + } + } + +// //通过业务ID创建 +// if (businessIdList != null && businessIdList.size() > 0) { +// for (String businessId : businessIdList) { +// List infoList = this.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, businessId)); +// if (infoList != null && infoList.size() > 0) { +// AssignmentInfo assignmentInfo = infoList.get(0); +// if (assignmentInfo.getBusinessType().startsWith("1") && !(assignmentInfo.getTestUser().equals(assignmentInfoDto.getTestUser()))) { +// throw new RuntimeException(String.format("业务:" + assignmentInfo.getBusinessName() + "已分配给工作人员:" + assignmentInfo.getTestUserName() + ",如需继续分配,只能继续选择该工作人员,或者撤销已分配的任务后重新进分配!")); +// } +// if (!assignmentInfo.getBusinessType().startsWith("1")) { +// throw new RuntimeException(String.format("业务:" + assignmentInfo.getBusinessName() + "中部分或全部检材已分配给其它工作人员,无法进行业务分配,你可以尝试点击右侧的分配检材功能继续进行分配!")); +// } +// } +// List list = sampleInfoService.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, businessId).eq(SampleInfo::getStatus, 0)); +// String businessName = ""; +// String status = ""; +// status = "分配情况:" + sampleInfoList.size() + "/" + sampleInfoList.size(); +// if (businessType.startsWith("1")) { +// EntrustInfo entrustInfo = entrustInfoService.getById(businessId); +// businessName = entrustInfo.getCaseName(); +// entrustInfo.setStatus(1); +// } else if (businessType.startsWith("3")) { +// ScreenInfo screenInfo = screenInfoService.getById(businessId); +// screenInfo.setStatus(status); +// businessName = screenInfo.getCaseName(); +// } else { +// TaskInfo taskInfo = taskInfoService.getById(businessId); +// businessName = taskInfo.getTaskName(); +// taskInfo.setStatus(status); +// } +// for (SampleInfo sampleInfo : list) { +// AssignmentInfo assignmentInfo = new AssignmentInfo(); +// BeanUtils.copyProperties(assignmentInfoDto, assignmentInfo); +// assignmentInfo.setId(IdWorker.get32UUID().toUpperCase()); +// assignmentInfo.setSampleId(sampleInfo.getId()); +// assignmentInfo.setSampleName(sampleInfo.getSampleName()); +// assignmentInfo.setBusinessId(businessId); +// assignmentInfo.setBusinessName(businessName); +// assignmentInfo.setBusinessType(sampleInfo.getBusinessType()); +// sampleInfo.setStatus(1); +// assignmentInfoList.add(assignmentInfo); +// sampleInfoList.add(sampleInfo); +// } +// +// sampleInfoList.addAll(sampleInfoList); +// } +// //通过样本ID创建 +// } else if (sampleIdList != null && sampleIdList.size() > 0) { +// SampleInfo sample = sampleInfoService.getById(sampleIdList.get(0)); +// String businessId = sample.getBusinessId(); +// +// for (String sampleId : sampleIdList) { +// SampleInfo sampleInfo = sampleInfoService.getById(sampleId); +// String businessName = ""; +// String status = ""; +// if (businessType.equals("筛查检验鉴定")) { +// ScreenInfo screenInfo = screenInfoService.getById(sampleInfo.getBusinessId()); +// businessName = screenInfo.getCaseName(); +// } else { +// TaskInfo taskInfo = taskInfoService.getById(sampleInfo.getBusinessId()); +// businessName = taskInfo.getTaskName(); +// } +// AssignmentInfo assignmentInfo = new AssignmentInfo(); +// BeanUtils.copyProperties(assignmentInfoDto, assignmentInfo); +// assignmentInfo.setId(IdWorker.get32UUID().toUpperCase()); +// assignmentInfo.setSampleId(sampleInfo.getId()); +// assignmentInfo.setSampleName(sampleInfo.getSampleName()); +// assignmentInfo.setBusinessName(businessName); +// assignmentInfo.setBusinessId(sampleInfo.getBusinessId()); +// assignmentInfo.setBusinessType(sampleInfo.getBusinessType()); +// sampleInfo.setStatus(1); +// assignmentInfoList.add(assignmentInfo); +// sampleInfoList.add(sampleInfo); +// } +// } else { +// throw new RuntimeException(String.format("至少传入一种类型的ID数组")); +// } +// if (this.saveBatch(assignmentInfoList) && sampleInfoService.updateBatchById(sampleInfoList)) { +// return assignmentInfoList; +// } else { +// return null; +// } +// } + + /** + * 撤销分配任务 + * + * @param assignmentInfoList + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean cancelAssignmentInfo(List assignmentInfoList) { + List sampleInfos = new ArrayList<>(); + for (AssignmentInfo assignmentInfo : assignmentInfoList) { + SampleInfo sampleInfo = sampleInfoService.getById(assignmentInfo.getSampleId()); + if (sampleInfo.getStatus() == 2) { + throw new RuntimeException(String.format("已使用检材%s进行实验,无法撤销!", sampleInfo.getSampleName())); + } + sampleInfo.setStatus(0); + sampleInfos.add(sampleInfo); + } + return this.removeBatchByIds(assignmentInfoList) && sampleInfoService.updateBatchById(sampleInfos); + } + + /** + * 删除分配任务 + * + * @param id + * @return + */ + @Override + public Boolean deleteAssignmentInfo(String id) { + return this.removeById(id); + } + + /** + * 分页查询 + * + * @param page + * @param assignmentInfoDto + * @return + */ + @Override + public IPage getAssignmentInfoPageList(Page page, AssignmentInfoDto assignmentInfoDto) { + //查询参数:可以是业务名称、样本名称、分配者姓名、接收者姓名 + String keywords = assignmentInfoDto.getKeywords(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().and(StringUtils.isNotBlank(keywords), queryWrapper -> queryWrapper + .like(AssignmentInfo::getBusinessName, keywords) + .or() + .like(AssignmentInfo::getSampleName, keywords) + .or() + .like(AssignmentInfo::getAssignUserName, keywords) + .or() + .like(AssignmentInfo::getTestUserName, keywords)) + .eq(StringUtils.isNotBlank(assignmentInfoDto.getAssignUser()), AssignmentInfo::getAssignUser, assignmentInfoDto.getAssignUser()) + .eq(StringUtils.isNotBlank(assignmentInfoDto.getTestUser()), AssignmentInfo::getTestUser, assignmentInfoDto.getTestUser()) + //这里前端由于无法一次性传入两个type,所以通过前缀来分类查询,例如2: 查询污水与毛发任务 + .likeRight(StringUtils.isNotBlank(assignmentInfoDto.getBusinessType()) && assignmentInfoDto.getBusinessType().startsWith("1"), AssignmentInfo::getBusinessType, 1) + .likeRight(StringUtils.isNotBlank(assignmentInfoDto.getBusinessType()) && assignmentInfoDto.getBusinessType().startsWith("2"), AssignmentInfo::getBusinessType, 2) + .likeRight(StringUtils.isNotBlank(assignmentInfoDto.getBusinessType()) && assignmentInfoDto.getBusinessType().startsWith("3"), AssignmentInfo::getBusinessType, 3) + .orderByDesc(AssignmentInfo::getCreateTime); + + if (StringUtils.isNotBlank(assignmentInfoDto.getTestUser())) {//检验人员查看我的待办 + List retList = this.list(wrapper); + Map> map = retList.stream().collect(Collectors.groupingBy(obj -> obj.getBusinessId())); + List assignmentInfoVos = new ArrayList<>(); + Set keySet = map.keySet(); + for (String key : keySet) { + List assignmentInfos = map.get(key); + AssignmentInfoVo assignmentInfoVo = new AssignmentInfoVo(); + BeanUtils.copyProperties(map.get(key).get(0), assignmentInfoVo); + assignmentInfoVo.setSampleId(""); + assignmentInfoVo.setSampleName(""); + List sampleInfos = new ArrayList<>(); + for (AssignmentInfo info : assignmentInfos) { + SampleInfo sampleInfo = sampleInfoService.getById(info.getSampleId()); + if (sampleInfo.getStatus() == 1) { + sampleInfos.add(sampleInfo); + } + } + assignmentInfoVo.setSampleInfoList(sampleInfos); + if (sampleInfos.size() > 0) { + assignmentInfoVos.add(assignmentInfoVo); + } + } + return new PageUtils().getPages(page.getCurrent(), page.getSize(), assignmentInfoVos); + } else { + //管理者查看所有分配信息 + IPage ret = this.page(page, wrapper); + List records = ret.getRecords(); + records.forEach(item -> { + item.setBusinessTypeName(BusinessType.getBusinessTypeName(item.getBusinessType())); + }); + return ret; + } + } + + /** + * 列表查询 + * + * @param assignmentInfoDto + * @return + */ + @Override + public List getAssignmentInfoList(AssignmentInfoDto assignmentInfoDto) { + //查询参数:可以是业务名称、样本名称、分配者姓名、接收者姓名 + String keywords = assignmentInfoDto.getKeywords(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().and(StringUtils.isNotBlank(keywords), queryWrapper -> queryWrapper + .like(AssignmentInfo::getBusinessName, keywords) + .or() + .like(AssignmentInfo::getSampleName, keywords) + .or() + .like(AssignmentInfo::getAssignUserName, keywords) + .or() + .like(AssignmentInfo::getTestUserName, keywords)) + .eq(StringUtils.isNotBlank(assignmentInfoDto.getAssignUser()), AssignmentInfo::getAssignUser, assignmentInfoDto.getAssignUser()) + .eq(StringUtils.isNotBlank(assignmentInfoDto.getTestUser()), AssignmentInfo::getTestUser, assignmentInfoDto.getTestUser()) + //这里前端由于无法一次性传入两个type,所以通过前缀来分类查询,例如2: 查询污水与毛发任务 + .likeRight(StringUtils.isNotBlank(assignmentInfoDto.getBusinessType()) && assignmentInfoDto.getBusinessType().startsWith("1"), AssignmentInfo::getBusinessType, 1) + .likeRight(StringUtils.isNotBlank(assignmentInfoDto.getBusinessType()) && assignmentInfoDto.getBusinessType().startsWith("2"), AssignmentInfo::getBusinessType, 2) + .likeRight(StringUtils.isNotBlank(assignmentInfoDto.getBusinessType()) && assignmentInfoDto.getBusinessType().startsWith("3"), AssignmentInfo::getBusinessType, 3) + .orderByDesc(AssignmentInfo::getCreateTime); + + if (StringUtils.isNotBlank(assignmentInfoDto.getTestUser())) {//检验人员查看我的待办 + List retList = this.list(wrapper); + Map> map = retList.stream().collect(Collectors.groupingBy(obj -> obj.getBusinessId())); + List assignmentInfoVos = new ArrayList<>(); + Set keySet = map.keySet(); + for (String key : keySet) { + List assignmentInfos = map.get(key); + String businessType = assignmentInfos.get(0).getBusinessType(); + AssignmentInfoVo assignmentInfoVo = new AssignmentInfoVo(); + BeanUtils.copyProperties(map.get(key).get(0), assignmentInfoVo); + assignmentInfoVo.setBusinessTypeName(BusinessType.getBusinessTypeName(businessType)); + assignmentInfoVo.setSampleId(""); + assignmentInfoVo.setSampleName(""); + List sampleInfos = new ArrayList<>(); + for (AssignmentInfo info : assignmentInfos) { + SampleInfo sampleInfo = sampleInfoService.getById(info.getSampleId()); + if (sampleInfo.getStatus() == 1) { + sampleInfos.add(sampleInfo); + } + } + if (sampleInfos.size() > 0) { + Collections.sort(sampleInfos, new Comparator() { + @Override + public int compare(SampleInfo o1, SampleInfo o2) { + return o1.getAcceptNo().compareTo(o2.getAcceptNo()); + } + }); + } + sampleInfos.forEach(o -> o.setBusinessTypeName(BusinessType.getBusinessTypeName(o.getBusinessType()))); + assignmentInfoVo.setSampleInfoList(sampleInfos); + if (sampleInfos.size() > 0) { + assignmentInfoVos.add(assignmentInfoVo); + } + } + return assignmentInfoVos; + } else { + //管理者查看所有分配信息 + List list = this.list(wrapper); + for (AssignmentInfo assignmentInfo : list) { + assignmentInfo.setBusinessTypeName(BusinessType.getBusinessTypeName(assignmentInfo.getBusinessType())); + } + return list; + } + } + + @Override + public Boolean checkExist(String id) { + List retList = this.list(Wrappers.lambdaQuery() + .eq(AssignmentInfo::getId, id)); + if (retList.size() > 0) { + return true; + } else { + return false; + } + } + + /** + * 批量撤销类别为委托的分配任务信息 + * + * @param businessIdList + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean cancelByBusiness(List businessIdList) { + ArrayList sampleInfos = new ArrayList<>(); + businessIdList.forEach(item -> { + List sampleInfoList = sampleInfoService.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, item)); + if (sampleInfoList.get(0).getBusinessType().startsWith("1")) { + EntrustInfo entrustInfo = entrustInfoService.getById(item); + entrustInfo.setStatus(0); + entrustInfoService.updateById(entrustInfo); + } + sampleInfoList.forEach(obj -> { + if (obj.getStatus() == 2) { + throw new RuntimeException(String.format("已使用检材%s进行实验,无法撤销!", obj.getSampleName())); + } + obj.setStatus(0); + sampleInfos.add(obj); + }); + }); + return this.remove(Wrappers.lambdaQuery().in(AssignmentInfo::getBusinessId, businessIdList)) && sampleInfoService.updateBatchById(sampleInfos); + } + + /** + * 查询类别为委托的已分配任务列表 + * + * @param page + * @param keywords 接收者名、业务名 + * @return + */ + @Override + public IPage getAssignedEntrustPage(Page page, String keywords) { + ArrayList assignmentInfoVos = new ArrayList<>(); + List assignmentInfoList = this.list(Wrappers.lambdaQuery() + .and(StringUtils.isNotBlank(keywords), queryWrapper -> queryWrapper + .like(AssignmentInfo::getTestUserName, keywords) + .or() + .like(AssignmentInfo::getBusinessName, keywords)) + .and(queryWrapper -> queryWrapper + .eq(AssignmentInfo::getBusinessType, "10001") + .or() + .eq(AssignmentInfo::getBusinessType, "10002"))); + Map> map = assignmentInfoList.stream().collect(Collectors.groupingBy(item -> item.getBusinessId())); + Set keySet = map.keySet(); + //按业务分个组~~~ + keySet.forEach(key -> { + List infoList = map.get(key); + + AssignmentInfoVo assignmentInfoVo = new AssignmentInfoVo(); + BeanUtils.copyProperties(infoList.get(0), assignmentInfoVo); + assignmentInfoVo.setSampleCount(infoList.size()); + assignmentInfoVo.setSampleName(""); + assignmentInfoVo.setSampleId(""); + assignmentInfoVo.setBusinessTypeName(BusinessType.getBusinessTypeName(infoList.get(0).getBusinessType())); + /*if (infoList.get(0).getBusinessType().equals("10001")) { + assignmentInfoVo.setBusinessTypeName("NPS案件"); + } else { + assignmentInfoVo.setBusinessTypeName("生物样本案件"); + }*/ + assignmentInfoVos.add(assignmentInfoVo); + }); + //按时间排个序~~~ + Collections.sort(assignmentInfoVos, new Comparator() { + @Override + public int compare(AssignmentInfoVo o1, AssignmentInfoVo o2) { + return o1.getCreateTime().compareTo(o2.getCreateTime()); + } + }); + return new PageUtils().getPages(page.getCurrent(), page.getSize(), assignmentInfoVos); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/EntrustInfoServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/EntrustInfoServiceImpl.java new file mode 100644 index 0000000..25492b5 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/EntrustInfoServiceImpl.java @@ -0,0 +1,184 @@ +package digital.laboratory.platform.inspection.service.impl; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import digital.laboratory.platform.inspection.dto.EntrustInfoDto; +import digital.laboratory.platform.inspection.entity.AssignmentInfo; +import digital.laboratory.platform.inspetion.api.entity.EntrustInfo; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import digital.laboratory.platform.inspection.mapper.EntrustInfoMapper; +import digital.laboratory.platform.inspection.service.AssignmentInfoService; +import digital.laboratory.platform.inspection.service.EntrustInfoService; +import digital.laboratory.platform.inspection.service.SampleInfoService; +import digital.laboratory.platform.inspetion.api.entity.MaterialDto; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +/* + *@title EntrustInfoServiceImpl + *@description + *@author xy + *@version 1.0 + *@create 2023/12/7 15:31 + */ +@Service +@Slf4j +public class EntrustInfoServiceImpl extends ServiceImpl implements EntrustInfoService { + + @Resource + private SampleInfoService sampleInfoService; + + @Resource + private AssignmentInfoService assignmentInfoService; + + @Override + @Transactional(rollbackFor = Exception.class) + public EntrustInfo addEntrustInfo(EntrustInfoDto entrustInfo) { + List materialList = entrustInfo.getMaterialList(); + + if (StringUtils.isBlank(entrustInfo.getId())) { + entrustInfo.setId(IdWorker.get32UUID()); + log.info("保存对象entrustInfo的ID为空,由系统生成一个给它使用 {}", entrustInfo.getId()); + } + if (entrustInfo.getMaterialType().equals("1")) { + entrustInfo.setBusinessType("10002"); + } else if (entrustInfo.getMaterialType().equals("0")) { + entrustInfo.setBusinessType("10001"); + } + //读取检材信息 + if (materialList != null && materialList.size() > 0) { + ArrayList sampleInfos = new ArrayList<>(); + for (MaterialDto material : materialList) { + SampleInfo sampleInfo = new SampleInfo(); + sampleInfoService.copy(sampleInfo, material, 0); + sampleInfo.setBusinessId(entrustInfo.getId()); + sampleInfo.setBusinessType(entrustInfo.getBusinessType()); + sampleInfos.add(sampleInfo); + } + sampleInfoService.saveBatch(sampleInfos); + } + entrustInfo.setStatus(0); + boolean ret = this.save(entrustInfo); + if (ret) { + log.info("{} 保存成功", entrustInfo); + return entrustInfo; + } else { + log.info("{} 保存失败", entrustInfo); + return null; + } + } + + @Override + public EntrustInfo updateEntrustInfo(EntrustInfo entrustInfo) { + if (entrustInfo.getSource() == 0) { + throw new RuntimeException(String.format("数据是其他系统推送录入的,不能修改")); + } + boolean ret = this.updateById(entrustInfo); + if (ret) { + return entrustInfo; + } else { + return null; + } + } + + @Override + public Boolean deleteEntrustInfo(String id) { + List assignmentInfoList = assignmentInfoService.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, id)); + if (assignmentInfoList.size() > 0) { + throw new RuntimeException(String.format("当前业务已被分配,无法删除!")); + } + return this.removeById(id); + } + + @Override + public IPage getEntrustPageList(Page page, Integer status, EntrustInfo entrustInfo, String keywords) { + IPage ret = this.page(page, Wrappers.lambdaQuery() + .and(StringUtils.isNotBlank(keywords), qw -> qw.like(EntrustInfo::getAcceptNo, keywords).or() + .like(EntrustInfo::getCaseName, keywords)) + .eq(StringUtils.isNotBlank(entrustInfo.getAcceptNo()), EntrustInfo::getAcceptNo, entrustInfo.getAcceptNo()) + .eq(StringUtils.isNotBlank(entrustInfo.getEntrustDepartment()), EntrustInfo::getEntrustDepartment, entrustInfo.getEntrustDepartment()) + .eq(entrustInfo.getSource() != null, EntrustInfo::getSource, entrustInfo.getSource()) + .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)); + List records = ret.getRecords(); + for (EntrustInfo info : records) { + List list = assignmentInfoService.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, info.getId())); + if (list.size() > 0) { + info.setIsDistribution(true); + } else { + info.setIsDistribution(false); + } + if (info.getBusinessType().equals("10001")) { + info.setBusinessTypeName("缴获物案件"); + } else { + info.setBusinessTypeName("生物样本案件"); + } + } + return ret; + } + + @Override + public List getEntrustList(EntrustInfo entrustInfo) { + List retList = this.list(Wrappers.lambdaQuery() + .eq(StringUtils.isNotBlank(entrustInfo.getAcceptNo()), EntrustInfo::getAcceptNo, entrustInfo.getAcceptNo()) + .eq(StringUtils.isNotBlank(entrustInfo.getEntrustDepartment()), EntrustInfo::getEntrustDepartment, entrustInfo.getEntrustDepartment()) + .eq(entrustInfo.getSource() != null, EntrustInfo::getSource, entrustInfo.getSource()) + .like(StringUtils.isNotBlank(entrustInfo.getCaseName()), EntrustInfo::getCaseName, entrustInfo.getCaseName()) + .eq(StringUtils.isNotBlank(entrustInfo.getId()), EntrustInfo::getId, entrustInfo.getId()) + .orderByDesc(EntrustInfo::getUpdateTime)); + for (EntrustInfo info : retList) { + List list = assignmentInfoService.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, info.getId())); + if (list.size() > 0) { + info.setIsDistribution(true); + } else { + info.setIsDistribution(false); + } + if (info.getBusinessType().equals("10001")) { + info.setBusinessTypeName("NPS案件"); + } else { + info.setBusinessTypeName("生物样本案件"); + } + } + return retList; + } + + /** + * 如果存在,返回true,否则返回false + * + * @param id + * @return + */ + @Override + public Boolean checkExist(String id) { + List retList = this.list(Wrappers.lambdaQuery() + .eq(EntrustInfo::getId, id)); + if (retList.size() > 0) { + return true; + } else { + return false; + } + } + + //检查是否具有重复的编号 + @Override + public boolean checkRepeatNo(String accept, String id) { + if (StringUtils.isNotBlank(id)) { + return true; + } + EntrustInfo entrustInfo = this.getOne(Wrappers.lambdaQuery().eq(EntrustInfo::getAcceptNo, accept)); + return entrustInfo == null ? true : false; + } + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/IdentifyBookDataServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/IdentifyBookDataServiceImpl.java new file mode 100644 index 0000000..1a9b139 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/IdentifyBookDataServiceImpl.java @@ -0,0 +1,346 @@ +package digital.laboratory.platform.inspection.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.entity.*; +import digital.laboratory.platform.inspection.service.*; +import digital.laboratory.platform.inspetion.api.entity.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * @author xy + * @version 1.0 + * @title IdentifyBookDataServiceImpl + * @description + * @create 2024/3/13 11:09 + */ +@Service +@Slf4j +public class IdentifyBookDataServiceImpl implements IdentifyBookDataService { + @Resource + private TestRecordService testRecordService;//实验记录 + @Resource + private EntrustInfoService entrustInfoService;//委托信息 + @Resource + private SampleInfoService sampleInfoService;//检材信息 + @Resource + private TestRecordSampleSolutionService testRecordSampleSolutionService;//样本溶液的service + @Resource + private TestRecordStandardSolutionService testRecordStandardSolutionService;//标准溶液的service + @Resource + private TestRecordSampleDataService testRecordSampleDataService;//检验数据 + @Resource + private TestRecordMethodService testRecordMethodService;//检验方法 + + /** + * 获取完成实验的数据/获取符合制作文书的数据 + * @return + */ + @Override + public R getTestFinishBusinessData(List synedIdList) { + List entrustInfoList = entrustInfoService.list(Wrappers.lambdaQuery() + .ge(EntrustInfo::getStatus, 3) + .notIn(CollectionUtils.isNotEmpty(synedIdList),EntrustInfo::getId,synedIdList)); + if (CollUtil.isNotEmpty(entrustInfoList)) { + Map> sampleGroupByBusinessId = sampleInfoService + .list(Wrappers.lambdaQuery() + .in(SampleInfo::getBusinessId, + entrustInfoList + .stream() + .map(EntrustInfo::getId) + .collect(Collectors.toList()))) + .stream() + .collect(Collectors.groupingBy(SampleInfo::getBusinessId)); + for (EntrustInfo entrustInfo : entrustInfoList) { + List sampleInfos = sampleGroupByBusinessId.get(entrustInfo.getId()); + entrustInfo.setMaterialNum(sampleInfos.size()); + } + } + return R.ok(entrustInfoList,"获取数据成功"); + } + /** + * 获取文书的数据 + * @param businessId + * @return + */ + @Override + public R getIdentifyBookDataByBusinessId(String businessId) { + //一个委托案件,只能属于一个实验,不允许一个委托中的检材分配到2个实验中做实验,这个是前提 + if(ObjectUtils.isNotEmpty(businessId)){ + IdentificationBookDTO identificationBookDTO = buildBookDataDetail(businessId); + return R.ok(identificationBookDTO,"构建数据成功"); + }else { + log.info("参数业务id不能为空,请检查参数{}",businessId); + return R.failed("参数业务id不能为空,请检查参数"+businessId); + } + } + //构建文书数据 + private IdentificationBookDTO buildBookDataDetail(String businessId){ + IdentificationBookDTO bookData=new IdentificationBookDTO(); + //委托信息 + EntrustInfo entrustInfo = entrustInfoService.getById(businessId); + bookData.setEntrustInfo(entrustInfo); + //检材 + List sampleList= sampleInfoService.list(Wrappers.lambdaQuery() + .eq(SampleInfo::getBusinessId, businessId).orderByAsc(SampleInfo::getAcceptNo)); + bookData.setSampleInfoList(sampleList); + + //设置检验结果 + List testRecordSampleSolutionList = getTestRecordSampleSolution(sampleList);//样本溶液 + List testRecordSampleDataList = getTestRecordSampleData(sampleList);//样本溶液对应的数据 + List testResultsList = buildTestResult(testRecordSampleDataList, testRecordSampleSolutionList, sampleList);//构建检验结果 + TestRecord testRecordInfo = getTestRecordInfo(testRecordSampleSolutionList); + //实验信息 + bookData.setTestMethod(getTestMethods(testRecordSampleSolutionList));//设置用到的实验方法 + //设置检验过程 + bookData.setTestProcessDes(testRecordInfo.getTestProcessDes());//设置检验过程 + bookData.setTestResult(testRecordSampleDataService.generateQualitativeResults(businessId)); + //bookData.setTestResult(buildTestResultDes(testResultsList));//检验结果 + //检验日期 + + DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyy年MM月dd日"); + bookData.setTestStartDate(sdf.format(testRecordInfo.getCreateTime())); + bookData.setTestOptUser(testRecordInfo.getTestUserId()); + bookData.setTestFinishDate(sdf.format(testRecordInfo.getUpdateTime())); + return bookData; + } + //获取业务的实验对象 + private TestRecord getTestRecordInfo(List testRecordSampleSolutionList){ + List testIdList= testRecordSampleSolutionList.stream().map(s -> s.getTestId()).collect(Collectors.toList()); + List distinctTestId= testIdList.stream().distinct().collect(Collectors.toList());//去重复 + if(distinctTestId.size()!=1){ + throw new RuntimeException("一个案件中的检材只能允许分配到一个实验中去做"); + } + String testId= distinctTestId.get(0); + TestRecord testRecord= testRecordService.getById(testId); + return testRecord; + } + //获取实验方法 + private String getTestMethods(List testRecordSampleSolutionList){ + TestRecord testRecordInfo= getTestRecordInfo(testRecordSampleSolutionList); + List testMethodList= testRecordInfo.getTestMethodList(); + List methodsList = testRecordMethodService.list(Wrappers.lambdaQuery() + .in(TestRecordMethod::getId, testMethodList)); + List methodsName = methodsList.stream().map(s -> s.getMethodName()).collect(Collectors.toList()); + StringBuffer sbMethodNameStr=new StringBuffer(); + methodsName.forEach(item->{ + sbMethodNameStr.append(item).append(","); + }); + sbMethodNameStr.delete(sbMethodNameStr.length()-1,sbMethodNameStr.length()); + return sbMethodNameStr.toString(); + } + //获取sampleData + private List getTestRecordSampleData(List sampleInfoList){ + List testRecordSampleSolution = getTestRecordSampleSolution(sampleInfoList); + if (CollUtil.isNotEmpty(testRecordSampleSolution)) { + List sampleNoList= testRecordSampleSolution.stream().map(m -> m.getSampleNo()).collect(Collectors.toList());//得到样本溶液编号 + //根据样本溶液编号查出对应的样本溶液检验数据 + List sampleTestDataList= getTestRecordData(sampleNoList); + return sampleTestDataList; + } + + return null; + } + //获取样本溶液 + private List getTestRecordSampleSolution( List sampleInfoList){ + List materialIdList= sampleInfoList.stream().map(m -> m.getId()).collect(Collectors.toList()); + if (CollUtil.isEmpty(materialIdList)) { + log.error("检材列表为空!"); + return null; + } + //查出对应的样本溶液 + List sampleSolutionList = testRecordSampleSolutionService.list(Wrappers.lambdaQuery() + .in(TestRecordSampleSolution::getMaterialId, materialIdList)); + return sampleSolutionList; + } + //构建TestResult + private List buildTestResult(List testRecordSampleDataList, + List testRecordSampleSolutionList,List sampleInfoList){ + //结果:应该是加入实验的检材的结果,目前暂定受理的检材我们按照受理顺序,全部定义为 1号检材,2号检材,3号检材等 + //拿出实验数据中的所有实验样本编号,就是数据文件中的sampleId,也是溶液编号中的溶液编号, + List sampleNoList= testRecordSampleDataList.stream().map(s -> s.getSampleNo()).collect(Collectors.toList()); + //取出检材ID + List okTestRecordSampleSolutionIdList=new ArrayList<>(); + testRecordSampleSolutionList.forEach(item->{ + //如果溶液在提供的溶液编号中,则取出来 + if(sampleNoList.contains(item.getSampleNo())){ + okTestRecordSampleSolutionIdList.add(item.getMaterialId()); + } + }); + List retTestResult=new ArrayList<>(); + for (TestRecordSampleData testRecordSampleData : testRecordSampleDataList) { + TestResult eg=new TestResult(); + SampleInfo sampleInfo=getSampleInfoBySampleId(testRecordSampleSolutionList, + sampleInfoList,testRecordSampleData.getSampleNo()); + eg.setCompoundName(testRecordSampleData.getCompoundName()); + eg.setMaterialNo(sampleInfo.getOrderNo()+"号"); + eg.setOrderNo(sampleInfo.getOrderNo()); + eg.setIsFind(testRecordSampleData.getIsDetected()); + eg.setTestId(testRecordSampleData.getTestId()); + retTestResult.add(eg); + } + return retTestResult; + } + //根据sampleID获取对应的检材信息 + private SampleInfo getSampleInfoBySampleId(List testRecordSampleSolutionList, + List sampleInfoList,String sampleId){ + List sampleSolutionList = testRecordSampleSolutionList.stream() + .filter(s -> s.getSampleNo().equals(sampleId)).collect(Collectors.toList()); + String materialId=""; + if(sampleSolutionList.size()>0){ + if(sampleSolutionList.size()>1){ + log.info("溶液编号重复 {} ",sampleId); + }else{ + materialId= sampleSolutionList.get(0).getMaterialId(); + } + } + List retObj=new ArrayList<>(); + for (SampleInfo sampleInfo : sampleInfoList) { + if(sampleInfo.getId().equals(materialId)){ + //找到 + retObj.add(sampleInfo); + } + } + if(retObj.size()!=1){ + log.info("存在重复的检材"); + return null; + } + if(retObj.size()==0){ + log.info("未查询到检材"); + return null; + }else { + return retObj.get(0); + } + } + //构建实验结果 + private List buildTestResultDes(List resultList){ + //按照检材编号先分组,这样的话,如果有n个检材,m个化合物,那么就会分成n组,每组中就m条数据 + Map> resultMap1 = resultList.stream().collect(Collectors.groupingBy(m -> m.getMaterialNo())); + //我们把每组中的List 数据再次分组,分组按检出和未检出分,这样就会得到2个组,一个组是检出的,一个组是未检出的 + Map>> resultMap2=new HashMap<>(); + resultMap1.forEach((k,v)->{ + //按检材编号分组,分成检出和未检出2组 + Map> tmp1Map= v.stream().collect(Collectors.groupingBy(m -> m.getIsFind())); + resultMap2.put(k,tmp1Map);//1号 检出 与未检出 + }); + // 对 resultMap2进行合并,然后再次分组 + List testResultDetailList=new ArrayList<>(); + resultMap2.forEach((k,v)->{ + Map> tmp2Map=v;//这个map中只有2个key,key为0代表未检出的集合,key为1表示检出的集合 + TestResultDetail testResultDetail= buildCompoundList(tmp2Map, k); + testResultDetailList.add(testResultDetail); + }); + // 对 testResultDetailList 进行 分组 + //现在对上面的数据进行从新分组,按检出+化合物的形式 + Map> temp2 = testResultDetailList.stream().collect( + Collectors.groupingBy(m -> m.getFindCompounds() + m.getNoFindCompounds())); + List testResultDes= testResultSorted(temp2); + return testResultDes; + } + //对第一个结果进行排序 + private List testResultSorted(Map> tmpMap){ + List>> targetList=new ArrayList>>(tmpMap.entrySet()); + targetList.sort(new Comparator>>() { + @Override + public int compare(Map.Entry> mp1, Map.Entry> mp2) { + int materialNo1 = getMinMaterialNo(mp1.getValue()); + int materialNo2 = getMinMaterialNo(mp2.getValue()); + return materialNo1-materialNo2; + } + }); + List testResultDes=new ArrayList<>(); + targetList.forEach((target)->{ + StringBuffer sbNo=new StringBuffer(); + target.getValue().forEach(item->{ + sbNo.append(item.getMaterialNo()).append(","); + }); + if(sbNo.length()>0){ + sbNo.delete(sbNo.length()-1,sbNo.length());//删除最后一个 , + } + testResultDes.add(sbNo.toString()+"检材未检出"+target.getValue().get(0).getNoFindCompounds()+",检出了"+target.getValue().get(0).getFindCompounds()); + }); + return testResultDes; + } + /** + * 构造出一个检材一共检出了多少个化合物和未检出多少化合物 + * @param mapCompound + * @param materialNo + * @return + */ + private TestResultDetail buildCompoundList(Map> mapCompound,String materialNo){ + + StringBuffer findCompounds=new StringBuffer();//检出化合物的集合 + StringBuffer noFindCompounds=new StringBuffer();//未检出化合物的集合 + mapCompound.forEach((k1,v1)->{ + if(k1==0){ + //未检出 + v1.forEach(item->{ + noFindCompounds.append(item.getCompoundName()).append(","); + }); + } + if(k1==1){ + //检出 + v1.forEach(item->{ + findCompounds.append(item.getCompoundName()).append(","); + }); + } + }); + if(findCompounds.length()>0){ + findCompounds.delete(findCompounds.length()-1,findCompounds.length());//删除最后一个 , + } + if(noFindCompounds.length()>0){ + noFindCompounds.delete(noFindCompounds.length()-1,noFindCompounds.length());//删除最后一个 , + } + TestResultDetail eg=new TestResultDetail(); + eg.setMaterialNo(materialNo); + eg.setFindCompounds(findCompounds.toString()); + eg.setNoFindCompounds(noFindCompounds.toString()); + return eg; + } + + private int getMinMaterialNo(List materialList){ + materialList.sort(new Comparator() { + @Override + public int compare(TestResultDetail t1, TestResultDetail t2) { + int mNo1= Integer.parseInt(getNumberByMaterialNo(t1.getMaterialNo())); + int mNo2= Integer.parseInt(getNumberByMaterialNo(t2.getMaterialNo())); + return mNo1-mNo2; + } + }); + return Integer.parseInt(getNumberByMaterialNo(materialList.get(0).getMaterialNo())); + } + + /** + * 根据编号获取排序值 + * @param materialNo + * @return + */ + private String getNumberByMaterialNo(String materialNo){ + Pattern pattern = Pattern.compile("\\d+"); + Matcher matcher = pattern.matcher(materialNo); + while (matcher.find()) { + return matcher.group(0); + } + return ""; + } + /** + * 根据溶液编号(sampleNo)获取仪器检测数据 + * @param sampleNoList + * @return + */ + private List getTestRecordData(List sampleNoList){ + return testRecordSampleDataService.list(Wrappers.lambdaQuery() + .in(TestRecordSampleData::getSampleNo, sampleNoList)); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/SampleInfoServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/SampleInfoServiceImpl.java new file mode 100644 index 0000000..cdcd571 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/SampleInfoServiceImpl.java @@ -0,0 +1,395 @@ +package digital.laboratory.platform.inspection.service.impl; +/* + *@title SampleInfoServiceImpl + *@description + *@author xy + *@version 1.0 + *@create 2023/12/8 11:10 + */ + +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.*; +import digital.laboratory.platform.inspection.constant.TestRecordArgumentType; +import digital.laboratory.platform.inspection.mapper.SampleInfoMapper; +import digital.laboratory.platform.inspection.mapper.TestRecordMapper; +import digital.laboratory.platform.inspection.service.*; +import digital.laboratory.platform.inspetion.api.entity.*; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import digital.laboratory.platform.sys.entity.DrugLite; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +@Service +@Slf4j +public class SampleInfoServiceImpl extends ServiceImpl implements SampleInfoService { + + @Resource + private AssignmentInfoService assignmentInfoService; + @Resource + private TestRecordService testRecordService; + @Resource + private TestRecordMapper testRecordMapper; + + @Resource + private TestRecordSampleSolutionService testRecordSampleSolutionService; + @Resource + private TestRecordSampleDataService testRecordSampleDataService; + + @Resource + @Lazy + private EntrustInfoService entrustInfoService; + + @Override + @Transactional(rollbackFor = Exception.class) + public SampleInfo addSampleInfo(SampleInfo sampleInfo) { + if (StringUtils.isBlank(sampleInfo.getId())) { + sampleInfo.setId(IdWorker.get32UUID()); + log.info("保存对象sampleInfo的ID为空,由系统生成一个给它使用 {}", sampleInfo.getId()); + } + List sampleInfos = new ArrayList<>(); + if (sampleInfo.getBusinessType().startsWith("1")) { + EntrustInfo entrustInfo = entrustInfoService.getById(sampleInfo.getBusinessId()); + sampleInfos = this.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, sampleInfo.getBusinessId()).orderByAsc(SampleInfo::getOrderNo)); + //鉴定要求与顺序号 + if (sampleInfos != null && sampleInfos.size() > 0) { + sampleInfos.add(sampleInfo); + sampleInfo.setOrderNo(sampleInfos.size()); + entrustInfo.setEntrustRequirement(this.getNameDesStrForEntrust(sampleInfos)); + } else { + sampleInfos.add(sampleInfo); + sampleInfo.setOrderNo(1); + entrustInfo.setEntrustRequirement(this.getNameDesStrForEntrust(sampleInfos)); + } + entrustInfoService.updateById(entrustInfo); + } + sampleInfo.setStatus(0); + boolean ret = this.save(sampleInfo); + if (ret) { + log.info("{} 保存成功", sampleInfo); + return sampleInfo; + } else { + log.info("{} 保存失败", sampleInfo); + return null; + } + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public SampleInfo updateSampleInfo(SampleInfo sampleInfo) { + if (sampleInfo.getSource() == 0) { + log.info("数据是其他系统推送录入的,不能修改"); + return null; + } + if (sampleInfo.getBusinessType().startsWith("1")) { + EntrustInfo entrustInfo = entrustInfoService.getById(sampleInfo.getBusinessId()); + List sampleInfoList = this.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, sampleInfo.getBusinessId())); + //鉴定要求 + entrustInfo.setEntrustRequirement(this.getNameDesStrForEntrust(sampleInfoList)); + entrustInfoService.updateById(entrustInfo); + } + boolean ret = this.updateById(sampleInfo); + if (ret) { + return sampleInfo; + } else { + return null; + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteSampleInfo(String id) { + SampleInfo sampleInfo = this.getById(id); + if (sampleInfo.getSource() == 0) { + log.info("数据是其他系统推送录入的,不能修改"); + throw new RuntimeException(String.format("数据是其他系统推送录入的,不能修改")); + } + //查询顺序号大于被删除的全部检材 + List sampleInfoList = this.list(Wrappers.lambdaQuery() + .eq(SampleInfo::getBusinessId, sampleInfo.getBusinessId()) + .gt(SampleInfo::getOrderNo, sampleInfo.getOrderNo())); + + //将后面的顺序号减一 保持不断号 + if (sampleInfoList != null && sampleInfoList.size() > 0) { + sampleInfoList.forEach(item -> { + item.setOrderNo(item.getOrderNo() - 1); + }); + } + this.updateBatchById(sampleInfoList); + return this.removeById(id); + } + + @Override + public IPage getSampleInfoPageList(Page page, SampleInfo sampleInfo) { + IPage ret = this.page(page, Wrappers.lambdaQuery() + .like(StringUtils.isNotBlank(sampleInfo.getSampleName()), SampleInfo::getSampleName, sampleInfo.getSampleName()) + .eq(sampleInfo.getStatus() != null, SampleInfo::getStatus, sampleInfo.getStatus()) + .orderByAsc(SampleInfo::getOrderNo)); + return ret; + } + + @Override + public List getSampleInfoList(SampleInfo sampleInfo) { + List retList = this.list(Wrappers.lambdaQuery() + .eq(SampleInfo::getBusinessId, sampleInfo.getBusinessId()) + .like(StringUtils.isNotBlank(sampleInfo.getSampleName()), SampleInfo::getSampleName, sampleInfo.getSampleName()) + .eq(sampleInfo.getStatus() != null, SampleInfo::getStatus, sampleInfo.getStatus()) + .orderByAsc(SampleInfo::getOrderNo)); + + for (SampleInfo info : retList) { + List list = assignmentInfoService.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getSampleId, info.getId())); + if (list.size() > 0) { + info.setIsDistribution(true); + } else { + info.setIsDistribution(false); + } + } + return retList; + } + + @Override + public Boolean checkExist(String id) { + List retList = this.list(Wrappers.lambdaQuery() + .eq(SampleInfo::getId, id)); + if (retList.size() > 0) { + return true; + } else { + return false; + } + } + + /** + * 分页查询 + * + * @param page + * @param dlpUser + * @param testId + * @param keywords 样本编号、样本名称、业务名称查询参数 + * @return + */ + @Override// + public IPage getPageForTestRecord(Page page, DLPUser dlpUser, String testId, String keywords) { + if (StringUtils.isNotBlank(testId)) {//查询这个实验下面绑定的检材列表 + TestRecordVo testRecordVo = testRecordMapper.getTestRecordMapById(testId); + List sampleTestList = testRecordVo.getSampleTestList(); + if (sampleTestList == null || sampleTestList.size() == 0) { + sampleTestList.add("");//这一步操作是为了保证下面查询的时候不出错,如果没有对应的ID集合,那么应该就查不出来 + } + return baseMapper.getFullSampleInfoList(page, Wrappers.lambdaQuery() + .in(SampleInfo::getId, sampleTestList) + .orderByAsc(SampleInfo::getOrderNo)); + } else { + Integer status = 1;//代表已分配但未加入实验的检材的状态 + List assignmentInfoList = assignmentInfoService.list(Wrappers.lambdaQuery().in(AssignmentInfo::getTestUser, dlpUser.getId())); + ArrayList idList = new ArrayList<>(); + if (assignmentInfoList != null && assignmentInfoList.size() > 0) { + assignmentInfoList.forEach(item -> idList.add(item.getSampleId())); + } + if (idList == null || idList.size() == 0) { + idList.add("");//这一步操作是为了保证下面查询的时候不出错,如果没有对应的ID集合,那么应该就查不出来 + } + return baseMapper.getFullSampleInfoList(page, Wrappers.lambdaQuery() + .and(StringUtils.isNotBlank(keywords), qw -> qw + .like(SampleInfo::getAcceptNo, keywords) + .or() + .like(SampleInfo::getSampleName, keywords) + .or() + .like(SampleInfo::getBusinessType, keywords)) + .in(SampleInfo::getId, idList).eq(SampleInfo::getStatus, status).orderByAsc(SampleInfo::getOrderNo)); + } + } + + /** + * 向实验添加或移除检材 + * + * @param testRecordArgumentDto + * @return + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean useTestRecordSample(TestRecordArgumentDto testRecordArgumentDto) { + SampleInfo sampleInfo = this.getById(testRecordArgumentDto.getArgumentId()); + TestRecord testRecord = testRecordService.getById(testRecordArgumentDto.getTestRecordId()); + if (testRecordArgumentDto.getOpCode() == -1) { + testRecordSampleSolutionService.isLoadSample(sampleInfo.getAcceptNo(), testRecordArgumentDto.getTestRecordId()); + List sampleDataList = testRecordSampleDataService.list(Wrappers.lambdaQuery() + .eq(TestRecordSampleData::getTestId, testRecordArgumentDto.getTestRecordId()) + .eq(TestRecordSampleData::getSampleNo, sampleInfo.getAcceptNo())); + if (testRecord.getBusinessType().startsWith("1") && sampleDataList.size() > 0) { + throw new RuntimeException(String.format("当前检材已存在上机数据,无法移除!")); + } + } + if (testRecordArgumentDto.getOpCode() == 1) { + if (sampleInfo.getStatus() != 1) { + throw new RuntimeException(String.format("当前检材状态有误,请选择状态为1的检材")); + } + sampleInfo.setStatus(2); + } else { + if (sampleInfo.getStatus() != 2) { + throw new RuntimeException(String.format("当前检材状态有误,请选择状态为2的检材")); + } + sampleInfo.setStatus(1); + } + return this.updateById(sampleInfo) && testRecordService.updateTestRecordArgument(testRecordArgumentDto.getTestRecordId(), sampleInfo.getId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_SAMPLE_DATA.getType(), testRecordArgumentDto.getOpCode()); + } + + /** + * 通过业务ID,查询这个业务下分配给自己的检材 + * + * @param businessId + * @param testUser + * @return + */ + @Override + public List getSampleInfoListForBusiness(String businessId, String testUser) { + return baseMapper.getSampleInfoList(businessId, testUser); + } + + /** + * 检查样本编号是否重复 + * + * @param acceptNo + * @param id + * @return + */ + @Override + public boolean checkRepeatNo(String acceptNo, String id) { + if (StringUtils.isNotBlank(id)) { + return true; + } + SampleInfo sampleInfo = this.getOne(Wrappers.lambdaQuery().eq(SampleInfo::getAcceptNo, acceptNo)); + return sampleInfo == null && StringUtils.isNotBlank(acceptNo) ? true : false; + } + + @Override + /**复制其他系统检材内容 + * @param sampleInfo + * @param material + * @param type 0:委托 1:任务 2:筛查 + */ + public void copy(SampleInfo sampleInfo, MaterialDto material, Integer type) { + sampleInfo.setId(IdWorker.get32UUID().toUpperCase()); + sampleInfo.setStatus(0); + if (StringUtils.isNotBlank(material.getFormName())) { + sampleInfo.setForm(material.getFormName()); + } else { + sampleInfo.setForm("/"); + } + if (StringUtils.isNotBlank(material.getColor())) { + sampleInfo.setColor(material.getColor()); + } else { + sampleInfo.setColor("/"); + } + if (type == 0 || type == 2) { + sampleInfo.setSampleName(material.getName()); + sampleInfo.setAcceptNo(material.getAcceptNo()); + } else if (type == 1) { + sampleInfo.setSampleName(material.getSampleName()); + sampleInfo.setAcceptNo(material.getImNo()); + } + if (material.getQuantity() != null && !(material.getQuantity().compareTo(BigDecimal.ZERO) == 0)) { + sampleInfo.setQuality(material.getQuantity().doubleValue()); + } else { + sampleInfo.setQuality(0.0); + } + if (material.getSample1RepeatWeigh() != null && !(material.getSample1RepeatWeigh().compareTo(BigDecimal.ZERO) == 0)) { + sampleInfo.setSampleQuality(material.getSample1RepeatWeigh().doubleValue()); + } else { + sampleInfo.setSampleQuality(0.0); + } + if (StringUtils.isNotBlank(material.getFundUnit())) { + sampleInfo.setSampleQualityUnit(material.getFundUnit()); + } else { + sampleInfo.setSampleQualityUnit("/"); + } + sampleInfo.setSource(0); + //检材的筛查物列表 + List candidateDrugs = material.getCandidateDrugs(); + if (candidateDrugs != null && candidateDrugs.size() > 0) { + ArrayList targetObjects = new ArrayList<>(); + for (DrugLite candidateDrug : candidateDrugs) { + TargetObject targetObject = new TargetObject(); + BeanUtils.copyProperties(candidateDrug, targetObject); + targetObjects.add(targetObject); + } + sampleInfo.setTargetObject(targetObjects); + } + if (StringUtils.isNotBlank(material.getUnit())) { + sampleInfo.setUnit(material.getUnit()); + } else { + sampleInfo.setUnit("/"); + } + if (type == 0 || type == 2 && StringUtils.isNotBlank(material.getAcceptNo())) { + String acceptNo = material.getAcceptNo(); + int lastIndexOf = acceptNo.lastIndexOf("-"); + sampleInfo.setOrderNo(Integer.parseInt(acceptNo.substring(lastIndexOf + 1))); + } + if (material.getAnalysisOption() != null) { + sampleInfo.setAnalysisOption(material.getAnalysisOption()); + } + } + + public String getNameDesStrForEntrust(List sampleInfos) { + //格式 + //对 xx号,xx号检材中的xx1、xx2进行 xx 分析, + //对1号、2号检材中的海洛因、甲基苯丙胺进行定量分析 + // 1.定性,2.定量 3.定性定量 4.关联性性 5.其他 + String result = ""; + //将检材排序 + Collections.sort(sampleInfos, new Comparator() { + @Override + public int compare(SampleInfo o1, SampleInfo o2) { + return o1.getOrderNo() - o2.getOrderNo(); + } + }); + for (int i = 0; i < sampleInfos.size(); i++) { + StringBuffer sbMaterialName = new StringBuffer(); + StringBuffer sbDrugDes = new StringBuffer(); + String analysisDes = ""; + StringBuffer sbAnalysisDes = new StringBuffer(); + SampleInfo sampleInfo = sampleInfos.get(i); + analysisDes = sampleInfo.getOrderNo() + "号"; + sbMaterialName.append(sampleInfo.getOrderNo() + "号").append(","); + String toJSONString = JSONArray.toJSONString(sampleInfo.getTargetObject()); + List drugLiteList = JSONArray.parseArray(toJSONString, TargetObject.class); + drugLiteList.forEach(item -> { + sbDrugDes.append(item.getName()).append("、"); + }); + sbDrugDes.delete(sbDrugDes.length() - 1, sbDrugDes.length());//删除多余的连接号 + if (sampleInfo.getAnalysisOption() == 1) { + sbAnalysisDes.append("定性"); + } else if (sampleInfo.getAnalysisOption() == 2) { + sbAnalysisDes.append("定量"); + } else { + sbAnalysisDes.append("定性定量"); + } + String req1 = "对" + analysisDes + "检材中的"; + String req2 = sbDrugDes.toString(); + String req3 = "进行" + sbAnalysisDes.toString() + "分析,"; + if (i == sampleInfos.size() - 1) { + result = result + req1 + req2 + "进行" + sbAnalysisDes.toString() + "分析。"; + } else { + result = result + req1 + req2 + req3; + } + } + return result; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/SampleInjectorServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/SampleInjectorServiceImpl.java new file mode 100644 index 0000000..c7cbfdf --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/SampleInjectorServiceImpl.java @@ -0,0 +1,465 @@ +package digital.laboratory.platform.inspection.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import digital.laboratory.platform.inspection.constant.SampleInjectorConstant; +import digital.laboratory.platform.inspection.constant.StdSolutionNum; +import digital.laboratory.platform.inspection.dto.ResetSampleInjectorDTO; +import digital.laboratory.platform.inspection.dto.SampleInjectorExcelDTO; +import digital.laboratory.platform.inspection.entity.SampleInjector; +import digital.laboratory.platform.inspetion.api.entity.TestRecord; +import digital.laboratory.platform.inspection.mapper.SampleInjectorMapper; +import digital.laboratory.platform.inspection.service.SampleInjectorService; +import digital.laboratory.platform.inspection.service.TestRecordService; +import digital.laboratory.platform.inspection.vo.ResultConcentrationVO; +import digital.laboratory.platform.inspection.vo.TestRecordSolutionVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 进样器信息接口实现类 + */ +@Slf4j +@Service +public class SampleInjectorServiceImpl extends ServiceImpl implements SampleInjectorService { + + @Resource + private TestRecordService testRecordService; + + /** + * 保存进样信息 + * @param sampleInjector + * @return SampleInjector + */ + @Override + @Transactional(rollbackFor = Exception.class) + public SampleInjector saveSampleInjector(SampleInjector sampleInjector) { + // 处理方盘,判断编号有没有重复放置 + if (sampleInjector.getType() == 2) { + Set sampleNoSet = new HashSet<>(); + int primalSize = 0; + // 合并方盘数组 + JSONArray injectorTypeArray = getJsonArrayByInjectorType(sampleInjector); + for (int i = 0; i < injectorTypeArray.size(); i++) { + JSONObject jsonObject = injectorTypeArray.getJSONObject(i); + String sampleNo = jsonObject.getString("sampleNo"); + if (StrUtil.isNotBlank(sampleNo)) { + sampleNoSet.add(sampleNo); + if (sampleNoSet.size() > primalSize) { + primalSize = sampleNoSet.size(); + } else { + throw new RuntimeException(String.format("溶液编号为 %s 的溶液重复放置,请取出来重新放置!", sampleNo)); + } + } + } + } + // 开始处理保存的数据 + boolean notBlank = StrUtil.isNotBlank(sampleInjector.getId()); + sampleInjector.setResetFlag(true);// 保存设置的重置的标识 + if (notBlank) { + SampleInjector oldInfo = this.getById(sampleInjector.getId()); + if (oldInfo == null) { + throw new RuntimeException(String.format("id为 %s 的进样信息不存在!", sampleInjector.getId())); + } + this.updateById(sampleInjector); + } else { + sampleInjector.setId(IdWorker.get32UUID()); + this.save(sampleInjector); + } + // 判断是否在上机,并更新状态值 + if (judgeOnTheMachine(sampleInjector)){ + testRecordService.update(Wrappers.lambdaUpdate() + .eq(TestRecord::getId, sampleInjector.getTestId()) + .set(TestRecord::getStatus, 1)); + } + return sampleInjector; + } + + /** + * 检材列表查询 + * @param testId + * @param key + * @return + */ + @Override + public List queryMaterialList(String testId, String key) { + TestRecord testInfo = testRecordService.getById(testId); + if (testInfo == null) { + throw new RuntimeException(String.format("查询不到检验任务id为 %s 的信息!", testId)); + } + // 查询是否已经进样 + SampleInjector one = this.getOne(Wrappers.lambdaQuery().eq(SampleInjector::getTestId, testId)); + + // 根据进样器类型返回json数组 + JSONArray jsonArray = getJsonArrayByInjectorType(one); + JSONArray finalJsonArray = jsonArray; + Map> testRecordSolutionVOSGroupByType = baseMapper.queryMaterialList(Wrappers.query() + .eq("T.test_id", testId) + .orderByDesc("T.number") + .and(StrUtil.isNotBlank(key), + wrapper -> wrapper.like("T.number", key))) + .parallelStream().peek(item -> { + // 根据其编号判断其溶液类型 + String number = item.getNumber(); + if (number.contains(StdSolutionNum.BLANK_SOLUTION.getPrefix())) { + + item.setTypeName(SampleInjectorConstant.BLANK_NAME); + } else if (number.contains(StdSolutionNum.SIMPLE_SOLUTION.getPrefix())) { + + item.setTypeName(SampleInjectorConstant.STANDARD_NAME); + } else if (number.contains(StdSolutionNum.MIXED_SOLUTION.getPrefix())) { + item.setTypeName(SampleInjectorConstant.MIX_STANDARD_NAME); + } else { + item.setTypeName(SampleInjectorConstant.NORMAL_NAME); + } + // 处理已经进样的数据 + if (finalJsonArray != null) { + for (int i = 0; i < finalJsonArray.size(); i++) { + JSONObject jsonObject = finalJsonArray.getJSONObject(i); + String sampleNo = jsonObject.getString("sampleNo"); + if (StrUtil.isNotBlank(sampleNo) && item.getNumber().equals(sampleNo)) { + item.setInjectorCount(jsonObject.getInteger("injectorCount")); + item.setFrameNumber(jsonObject.getString("frameNumber")); + String injectorLocation = one.getType() == 1 ? jsonObject.getString("title") : jsonObject.getString("name"); + item.setInjectorLocation(injectorLocation); + } + } + } + }).collect(Collectors.toList()).stream().collect(Collectors.groupingBy(TestRecordSolutionVO::getTypeName)); + + // 根据分类封装结果 + List testRecordSolutionVOS = new ArrayList<>(); + if (testRecordSolutionVOSGroupByType.containsKey(SampleInjectorConstant.NORMAL_NAME)) { + testRecordSolutionVOS.addAll(testRecordSolutionVOSGroupByType.get(SampleInjectorConstant.NORMAL_NAME)); + } + if (testRecordSolutionVOSGroupByType.containsKey(SampleInjectorConstant.BLANK_NAME)) { + testRecordSolutionVOS.addAll(testRecordSolutionVOSGroupByType.get(SampleInjectorConstant.BLANK_NAME)); + } + if (testRecordSolutionVOSGroupByType.containsKey(SampleInjectorConstant.MIX_STANDARD_NAME)) { + testRecordSolutionVOS.addAll(testRecordSolutionVOSGroupByType.get(SampleInjectorConstant.MIX_STANDARD_NAME)); + } + if (testRecordSolutionVOSGroupByType.containsKey(SampleInjectorConstant.STANDARD_NAME)) { + testRecordSolutionVOS.addAll(testRecordSolutionVOSGroupByType.get(SampleInjectorConstant.STANDARD_NAME)); + } + return testRecordSolutionVOS; + } + + /** + * 导出进样信息excel表 + * @param id + * @param response + */ + @Override + public void exportSampleInjectorInfoToExcel(String id, HttpServletResponse response){ + // 先查询进样信息,取出进样位置信息 + SampleInjector sampleInjector = this.getById(id); + if (sampleInjector == null) { + throw new RuntimeException("进样信息查询失败!"); + } + Map resultConcentrationVOMap = baseMapper.queryResultConcentrationList(Wrappers.query().eq("T.test_id", sampleInjector.getTestId())).stream().collect(Collectors.toMap(ResultConcentrationVO::getNumber, ResultConcentrationVO::getResultConcentration)); + List list = getSampleInjectorExportDataByDisk(sampleInjector, resultConcentrationVOMap); +// ServletOutputStream outputStream = null; + try { + + this.setExcelResponseProp(response, "进样表-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日-HH时mm分ss秒"))); +// outputStream = response.getOutputStream(); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + EasyExcel.write(byteArrayOutputStream) + .head(SampleInjectorExcelDTO.class) + .excelType(ExcelTypeEnum.CSV) + .sheet("进样表") + .doWrite(list); + response.getOutputStream().write(byteArrayOutputStream.toByteArray()); + response.getOutputStream().flush(); + + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + /** + * 重置进样信息 + * @param dto + * @return + */ + @Override + public SampleInjector reset(ResetSampleInjectorDTO dto) { + /*// 转json成map处理 + if (dto.getType() == 2) { // 如果是方盘先合并数组,在处理 + dto.setInjectorInfo( + mergeSquareInjectorInfo( + dto.getInjectorInfo1(), + dto.getInjectorInfo2(), + dto.getInjectorInfo3(), + dto.getInjectorInfo4() + ) + ); + } + List> injectorInfo = JSONArray.toJavaObject(dto.getInjectorInfo(), List.class); + // 使用并行流处理 + injectorInfo.parallelStream().forEach( item -> { + String sampleNo = item.get("sampleNo").toString(); + if (StrUtil.isNotBlank(sampleNo)) { + item.put("sampleNo", ""); + item.put("injectorCount", ""); + if (item.containsKey("active")) { + item.put("active", false); + } else { + item.put("selected", false); + } + } + + });*/ + + this.update(Wrappers.lambdaUpdate().eq(SampleInjector::getId, dto.getId()) + .set(SampleInjector::getInjectorInfo, null) + .set(SampleInjector::getType, 0) + .set(SampleInjector::isResetFlag, false) + .set(SampleInjector::getBlankStartPosition, null) + .set(SampleInjector::getInsertNumber, null)); + return this.getById(dto.getId()); + } + + /** + * 根据实验id获取,数据为空则初始部分数据返回 + * @param testId + * @return + */ + @Override + public SampleInjector getByTestId(String testId) { + SampleInjector sampleInjector = this.getOne(Wrappers.lambdaQuery().eq(SampleInjector::getTestId, testId)); + if (sampleInjector == null) { + sampleInjector = new SampleInjector(); + sampleInjector.setTestId(testId); + // 查询不到设置保存标记为false + sampleInjector.setResetFlag(false); + + } /*else if (sampleInjector.getType() == 2){ + // 方盘,取出json 处理 + JSONArray jsonArray = JSON.parseArray(sampleInjector.getInjectorInfo()); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + String frameNumber = jsonObject.getString("frameNumber"); + if (frameNumber.equals("P-1")) { + sampleInjector.getInjectorInfo1().add(jsonObject); + } else if (frameNumber.equals("P-2")) { + sampleInjector.getInjectorInfo2().add(jsonObject); + } else if (frameNumber.equals("P-3")) { + sampleInjector.getInjectorInfo3().add(jsonObject); + } else if (frameNumber.equals("P-4")) { + sampleInjector.getInjectorInfo4().add(jsonObject); + } else { + + } + } + } + // 第一次访问或者可以重置的都初始方盘数据 + if (sampleInjector.getId() == null || !sampleInjector.isResetFlag()) { + // 这里不管是圆盘还是方盘都返回方盘初始化的数组,前端根据情况选择参数 + sampleInjector.setInjectorInfo1(SampleInjectorConstant.P_1); + sampleInjector.setInjectorInfo2(SampleInjectorConstant.P_2); + sampleInjector.setInjectorInfo3(SampleInjectorConstant.P_3); + sampleInjector.setInjectorInfo4(SampleInjectorConstant.P_4); + }*/ + return sampleInjector; + } + + /** + * 判断当前进样器是否保存了进样位置信息 + * @param testId + * @return + */ + @Override + public boolean whetherSave(String testId) { + SampleInjector sampleInjector = this.getOne(Wrappers.lambdaQuery() + .eq(SampleInjector::getTestId, testId) + .eq(SampleInjector::isResetFlag, true) + .isNotNull(SampleInjector::getInjectorInfo)); + // 判断不为null, 则执行下面代码 + if (sampleInjector != null) { + return judgeOnTheMachine(sampleInjector); + } + return false; + } + + /** + * 判断是否正在上机 + * @param sampleInjector + * @return + */ + private boolean judgeOnTheMachine(SampleInjector sampleInjector) { + JSONArray injectorJsonArray = getJsonArrayByInjectorType(sampleInjector); + for (int i = 0; i < injectorJsonArray.size(); i++) { + JSONObject jsonObject = injectorJsonArray.getJSONObject(i); + String sampleNo = jsonObject.getString("sampleNo"); + boolean active = jsonObject.getBoolean("active"); + if (StrUtil.isNotBlank(sampleNo) && active) { + return true; + } + } + return false; + } + + /** + * 设置响应结果 + * + * @param response 响应结果对象 + * @param rawFileName 文件名 + * @throws UnsupportedEncodingException 不支持编码异常 + */ + private void setExcelResponseProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");// "application/vnd.ms-excel" "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + response.setCharacterEncoding("utf-8"); + String fileName = URLEncoder.encode(rawFileName, "UTF-8"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".csv"); + } + + /** + * 组装圆盘进样信息导出的数据 + * + * @param sampleInjector + * @param resultConcentrationVOMap + */ + private List getSampleInjectorExportDataByDisk(SampleInjector sampleInjector, Map resultConcentrationVOMap) { + // new 一个返回的结果列表 + List list = new ArrayList<>(); + // 根据进样器类型返回json数组 + JSONArray jsonArray = getJsonArrayByInjectorType(sampleInjector); + + int index = 1; // 导出表时的index值 + Integer blankCount = 1; // 空白穿插时的统计 + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + String sampleNo = jsonObject.getString("sampleNo"); // 默认取溶液编号 + if (StrUtil.isNotBlank(sampleNo)) { + if (sampleInjector.getBlankStartPosition() != null + && index == sampleInjector.getBlankStartPosition() + && !sampleNo.contains(StdSolutionNum.BLANK_SOLUTION.getPrefix())) { + // 判断是空白起始插入位置,空白开始插入 + list.addAll(blankInsert(sampleInjector.getInsertNumber(), blankCount)); + } + // 溶液编号不为空,证明这个进样盘号有检材 + SampleInjectorExcelDTO excelDTO = new SampleInjectorExcelDTO(); + excelDTO.setFileName(sampleNo); + excelDTO.setId(index == 1 ? "ID" : "ID" + (index)); + if (sampleInjector.getType() == 1) { + excelDTO.setSampleLocation(jsonObject.get("title").toString()); + } else { + excelDTO.setSampleLocation(jsonObject.getString("frameNumber") + "-" + jsonObject.getString("name")); + } + excelDTO.setIndex(index); + + if (CollUtil.isNotEmpty(resultConcentrationVOMap)) { + excelDTO.setFileText(resultConcentrationVOMap.get(sampleNo)); + } + if (sampleNo.contains(StdSolutionNum.BLANK_SOLUTION.getPrefix())) { + excelDTO.setType(SampleInjectorConstant.BLANK); + } else if (sampleNo.contains(StdSolutionNum.SIMPLE_SOLUTION.getPrefix())) { + excelDTO.setType(SampleInjectorConstant.STANDARD); + } + list.add(excelDTO); + + /*if (sampleInjector.getBlankStartPosition() != null && index == sampleInjector.getBlankStartPosition()) { + // 判断是空白起始插入位置,空白结束插入 + list.addAll(blankInsert(sampleInjector.getInsertNumber(), false)); + }*/ + index++; + } + } + return list; + } + + /** + * 空白穿插 + * @param insertNumber + * @param blankCount 是否是开始穿插, true 是, false 不是 + */ + + private List blankInsert(Integer insertNumber, Integer blankCount) { + List blankInsertList = new ArrayList<>(); + for (int i = 1; i <= insertNumber; i++) { + SampleInjectorExcelDTO blankExcelDTO = new SampleInjectorExcelDTO(); + + blankExcelDTO.setFileName(StdSolutionNum.BLANK_SOLUTION.getPrefix() + i); + + blankExcelDTO.setType(SampleInjectorConstant.BLANK); + blankInsertList.add(blankExcelDTO); + blankCount++; + } + return blankInsertList; + } + + /** + * 处理方盘的位置信息,把四个数组合并成一个 + * @param injectorInfo1 p-1 + * @param injectorInfo2 p-2 + * @param injectorInfo3 p-3 + * @param injectorInfo4 p-4 + * @return 返回json数组 + */ + private JSONArray mergeSquareInjectorInfo(JSONArray injectorInfo1, + JSONArray injectorInfo2, + JSONArray injectorInfo3, + JSONArray injectorInfo4) { + + if (CollUtil.isEmpty(injectorInfo1) + || CollUtil.isEmpty(injectorInfo2) + || CollUtil.isEmpty(injectorInfo3) + || CollUtil.isEmpty(injectorInfo4)) { + throw new RuntimeException("方盘参数不全,请检查参数是否合法!"); + } + // 合并四个数组到一个数组 + JSONArray resultArray = new JSONArray(); + resultArray.addAll(injectorInfo1); + resultArray.addAll(injectorInfo2); + resultArray.addAll(injectorInfo3); + resultArray.addAll(injectorInfo4); + return resultArray; + + } + + + /** + * 根据进样器类型返回json数组 + * @param one + * @return + */ + private static JSONArray getJsonArrayByInjectorType(SampleInjector one) { + // 处理已经进样的数据 + JSONArray jsonArray = new JSONArray(); + if (one != null && StrUtil.isNotBlank(one.getInjectorInfo())) { + // todo 返回列表时 相关检材的进样盘号也需要查询处理 + if (one.getType() == 1) { + jsonArray = JSON.parseArray(one.getInjectorInfo()); + } else if (one.getType() == 2){ + JSONArray totalArray = JSON.parseArray(one.getInjectorInfo()); + for (int i = 0; i < totalArray.size(); i++) { + jsonArray.addAll(totalArray.getJSONArray(i)); + } + } + } + return jsonArray; + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/ScreenInfoServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/ScreenInfoServiceImpl.java new file mode 100644 index 0000000..5e7998e --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/ScreenInfoServiceImpl.java @@ -0,0 +1,148 @@ +package digital.laboratory.platform.inspection.service.impl; +/* + *@title ScreenInfoServiceImpl + *@description + *@author xy + *@version 1.0 + *@create 2023/12/8 11:57 + */ + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import digital.laboratory.platform.inspection.entity.AssignmentInfo; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import digital.laboratory.platform.inspection.entity.ScreenInfo; +import digital.laboratory.platform.inspection.mapper.ScreenInfoMapper; +import digital.laboratory.platform.inspection.service.AssignmentInfoService; +import digital.laboratory.platform.inspection.service.SampleInfoService; +import digital.laboratory.platform.inspection.service.ScreenInfoService; +import digital.laboratory.platform.inspetion.api.entity.MaterialDto; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +@Service +@Slf4j +public class ScreenInfoServiceImpl extends ServiceImpl implements ScreenInfoService { + + @Resource + private SampleInfoService sampleInfoService; + + @Resource + private AssignmentInfoService assignmentInfoService; + + @Override + @Transactional(rollbackFor = Exception.class) + public ScreenInfo addScreenInfo(ScreenInfo screenInfo) { + //设置业务类型 + screenInfo.setBusinessType("30001"); + if (StringUtils.isBlank(screenInfo.getId())) { + screenInfo.setId(IdWorker.get32UUID()); + log.info("保存对象entrustInfo的ID为空,由系统生成一个给它使用 {}", screenInfo.getId()); + } + ScreenInfo info = this.getOne(Wrappers.lambdaQuery().eq(ScreenInfo::getOriginalId, screenInfo.getOriginalId())); + if (info != null) { + throw new RuntimeException(String.format("当前筛查任务已经同步至检验鉴定系统,无需再次同步!")); + } + List materialList = screenInfo.getMaterialList(); + if (materialList != null && materialList.size() > 0) { + List sampleInfos = new ArrayList<>(); + for (MaterialDto material : materialList) { + SampleInfo sampleInfo = new SampleInfo(); + sampleInfoService.copy(sampleInfo, material, 2); + sampleInfo.setBusinessType(screenInfo.getBusinessType()); + sampleInfo.setBusinessId(screenInfo.getId()); + sampleInfos.add(sampleInfo); + } + sampleInfoService.saveBatch(sampleInfos); + } + boolean ret = this.save(screenInfo); + if (ret) { + log.info("{} 保存成功", screenInfo); + return screenInfo; + } else { + log.info("{} 保存失败", screenInfo); + return null; + } + } + + @Override + public ScreenInfo updateScreenInfo(ScreenInfo screenInfo) { + if (screenInfo.getSource() == 0) { + log.info("数据是其他系统推送录入的,不能修改"); + return null; + } + boolean ret = this.updateById(screenInfo); + if (ret) { + return screenInfo; + } else { + return null; + } + } + + @Override + public Boolean deleteScreenInfo(String id) { + List assignmentInfos = assignmentInfoService.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, id)); + if (assignmentInfos.size() > 0) { + throw new RuntimeException(String.format("当前业务已被分配,无法删除!")); + } + + return this.removeById(id); + } + + @Override + public IPage getScreenPageList(Page page, ScreenInfo screenInfo,String keywords) { + IPage ret = this.page(page, Wrappers.lambdaQuery() + .like(StringUtils.isNotBlank(keywords), ScreenInfo::getCaseName,keywords) + .eq(StringUtils.isNotBlank(screenInfo.getId()), ScreenInfo::getId, screenInfo.getId()) + .orderByDesc(ScreenInfo::getCreateTime)); + + for (ScreenInfo info : ret.getRecords()) { + List list = assignmentInfoService.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, info.getId())); + if (list.size() > 0) { + info.setIsDistribution(true); + } else { + info.setIsDistribution(false); + } + } + + return ret; + } + + @Override + public List getScreenList(ScreenInfo screenInfo,String keywords) { + List retList = this.list(Wrappers.lambdaQuery() + .like(StringUtils.isNotBlank(keywords), ScreenInfo::getCaseName, keywords) + .eq(StringUtils.isNotBlank(screenInfo.getId()), ScreenInfo::getId, screenInfo.getId()) + .orderByDesc(ScreenInfo::getCreateTime)); + + for (ScreenInfo info : retList) { + List list = assignmentInfoService.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, info.getId())); + if (list.size() > 0) { + info.setIsDistribution(true); + } else { + info.setIsDistribution(false); + } + } + return retList; + } + + @Override + public Boolean checkExist(String id) { + List retList = this.list(Wrappers.lambdaQuery() + .eq(ScreenInfo::getId, id)); + if (retList.size() > 0) { + return true; + } else { + return false; + } + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/SewageDrugInspectReportServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/SewageDrugInspectReportServiceImpl.java new file mode 100644 index 0000000..fa24ce5 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/SewageDrugInspectReportServiceImpl.java @@ -0,0 +1,2652 @@ +package digital.laboratory.platform.inspection.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import digital.laboratory.platform.common.core.constant.CommonConstants; +import digital.laboratory.platform.common.core.constant.OSSDirectoryConstants; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.oss.service.OssFile; +import digital.laboratory.platform.inspection.constant.NumberTransferHanZi; +import digital.laboratory.platform.inspection.dto.ExportSewageAnalystReportsDTO; +import digital.laboratory.platform.inspection.dto.RegionalDrugConsumptionDTO; +import digital.laboratory.platform.inspection.dto.ReportConfigDTO; +import digital.laboratory.platform.inspection.dto.SewageDataDto; +import digital.laboratory.platform.inspection.entity.TaskInfo; +import digital.laboratory.platform.inspection.service.SampleInfoService; +import digital.laboratory.platform.inspection.service.SewageDrugInspectReportService; +import digital.laboratory.platform.inspection.service.TaskInfoService; +import digital.laboratory.platform.inspection.utils.sewagereport.*; +import digital.laboratory.platform.sewage.feign.RemoteSewageJobIdentificationMaterialService; +import digital.laboratory.platform.sewage.vo.SewageJobIdentificationMaterialVO; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.xwpf.usermodel.BreakType; +import org.apache.poi.xwpf.usermodel.ParagraphAlignment; +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.text.DecimalFormat; +import java.time.LocalDate; +import java.time.Year; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/*** + * 污水专项检测毒品分析报告 相关接口 + */ +@Slf4j +@Service +public class SewageDrugInspectReportServiceImpl implements SewageDrugInspectReportService { + + @Resource + private TaskInfoService taskInfoService; + + @Resource + private SampleInfoService sampleInfoService; + + @Resource + private RemoteSewageJobIdentificationMaterialService remoteSewageJobIdentificationMaterialService; + + @Resource + private OssFile ossFile; + + // 保留1位小数的数值格式 + private final static DecimalFormat keep1DecimalPlace = new DecimalFormat("#.#"); + + private final static DateTimeFormatter chineseYearDoubleMonthFormatter = DateTimeFormatter.ofPattern("yyyy年MM月"); + private final static DateTimeFormatter chineseDateFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日"); + private final static DateTimeFormatter chineseYearSingleMonthFormatter = DateTimeFormatter.ofPattern("yyyy年M月"); + + + /** + * 生成污水样品毒品检测分析报告 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public String generateSewageDrugInspectReportWord(ExportSewageAnalystReportsDTO dto) throws Exception{ + // 目前的污水报告 只针对于 陕西省的 默认设置参数为陕西省 + dto.setProvinceCode("610000"); + dto.setProvinceName("陕西省"); + // 陕西省各地市名称 + List cityNameList = new ArrayList<>(Arrays.asList("西安市","宝鸡市","咸阳市","铜川市","渭南市","延安市","榆林市","汉中市","安康市","商洛市")); + // 获取任务信息,得到任务的开始日期 + TaskInfo taskInfo = taskInfoService.getOne(Wrappers.lambdaQuery().eq(TaskInfo::getId, dto.getJobId())); + // 更新任务中报告配置的信息 + taskInfo.setReportConfig(dto.getReportConfig()); + taskInfoService.updateById(taskInfo); + // 数据 + String yearMonth = taskInfo.getTaskStartDate().format(chineseYearDoubleMonthFormatter ); + // 目前字典中的单位名称不统一,这里暂时写死,后期在改 + String organization = "国家毒品实验室陕西分中心"; + String generateDate = LocalDate.now().format(chineseDateFormatter); + String province = dto.getProvinceName(); + // 获取目前任务之前的四个任务信息 + List taskIdByOrderStartTimeLimit4 = taskInfoService.getTaskIdByOrderStartTimeLimit4(taskInfo); + + // 对任务进行排序, 获取到根据开始时间升序的任务列表 + List taskInfoList = getTaskInfos(taskIdByOrderStartTimeLimit4, taskInfo); + + // 这里的数据是按照任务的开始时间升序顺序对应的 + List> sewageDataDtoLists = getSewageTaskDataForAYear(taskInfoList, dto); + + // feign 接口调用获取 污水检材 + List data = getSewageJobIdentificationMaterialVOS(dto, taskInfo); + + // 使用stream 流进行排序 + List dateSortedByAcceptTime = data.stream() + .sorted((d1, d2) -> d1.getAcceptTime().compareTo(d2.getAcceptTime())) + .collect(Collectors.toList()); + List dateSortedByCollectTime = data.stream() + .sorted((d1, d2) -> d1.getCollectTime().compareTo(d2.getCollectTime())) + .collect(Collectors.toList()); + String collectDate1 = dateSortedByAcceptTime.get(0).getAcceptTime().format(chineseDateFormatter); + String collectDate2 = dateSortedByAcceptTime.get(dateSortedByAcceptTime.size()-1).getAcceptTime().format(chineseDateFormatter); + + String samplingDate1 = dateSortedByCollectTime.get(0).getCollectTime().format(chineseDateFormatter); + String samplingDate2 = dateSortedByCollectTime.get(dateSortedByCollectTime.size()-1).getCollectTime().format(chineseDateFormatter); + int materialNum = data.size(); // 本次样本数量 + + // 统计这些样本的地市数量 + Set cityCount = data.stream().map(SewageJobIdentificationMaterialVO::getCollectPlaceCityCode).collect(Collectors.toSet()); + + // 获取每个样品的数据 + List sewageDataDtos = taskInfoService.processSewageDataDtos(dto.getDailySmokingPerCapita(), data); + sewageDataDtoLists.add(sewageDataDtos); // 添加到 sewageDataDtoLists 方便后续进行陕西省毒品滥用情况分析 + // 统计这些样本来自多少个污水厂 + Set sewagePlantNum = sewageDataDtos.stream().map(o -> StrUtil.split(o.getSampleName(), "-").get(0)).collect(Collectors.toSet()); + + // 获取污水数据并根据地市分组 + Map> sewageDataGroupByMap = getSewageDataGroupByCityNameMap(sewageDataDtos); + // 获取陕西省各行政区主要毒品总消费量表数据 + List regionalDrugConsumptionDTOList = fetchRegionalDrugConsumption(sewageDataGroupByMap); + + // 取列表最后一个,最后一个是计算全省的 + RegionalDrugConsumptionDTO allProvince = regionalDrugConsumptionDTOList.get(regionalDrugConsumptionDTOList.size() - 1); + + // 根据行政区转map,方便后续的陕西省各污水厂服务区及各行政区毒品千人均消费量表 读取地区平均 + Map regionalDrugConsumptionDTOMap = regionalDrugConsumptionDTOList.stream().collect(Collectors.toMap(RegionalDrugConsumptionDTO::getRegional, Function.identity())); + + // 取四个任务的开始日期 + List taskStartDateList = getTaskStartDateList(taskInfoList, DateTimeFormatter.ofPattern("yyyy-MM")); + // 中国格式的日期 + List taskStartDateChinaFormatList = getTaskStartDateList(taskInfoList, chineseYearSingleMonthFormatter); + + List> allMergeMegionalDrugConsumptionDTOList = getAllMergeBeforeMegionalDrugConsumptionDTOList(sewageDataDtoLists, taskInfoList); + + // 把前面季度的全省毒品消费量和当前季度的放到一个list里,目的是为了后面的报告中 比较使用到 + List allTaskProvinceDrugConsumptionList = new ArrayList<>(); + extractedProvinceDrugConsumeData(allMergeMegionalDrugConsumptionDTOList, allTaskProvinceDrugConsumptionList, allProvince); + + // 生成word文档 + XWPFDocument doc = new XWPFDocument(); + // resourceLoader.getResource("classpath:template/templateStyles.docx").getInputStream() 获取resource目录下的模板文件 + ByteArrayInputStream filePath = getTemplateStyleFilePath(); // 获取模板路径 + WordUtils.setDocumentStyle(doc, filePath); + + generateHomePage(doc, yearMonth, organization, generateDate, province); + + WordUtils.createDocTitle(doc, yearMonth + "份"+ province +"污水专项检测毒品分析报告", false); + + WordUtils.createParagraphTitle(doc, "一、工作概况", false, 2); + WordUtils.createParagraph( + doc, + ParagraphAlignment.LEFT, + organization + + "自"+ collectDate1 +"至"+ collectDate2 + + "收到"+ province + cityCount.size() +"个地市共"+ + materialNum +"份污水样品(包含"+ sewagePlantNum.size() +"个污水处理厂),各污水处理厂监测点采样日期在" + + samplingDate1 +"至" + samplingDate2 + "。本次检测分析的物质包括以下13种,检测结果为各目标物的浓度数据(单位:纳克/升):", + false, + 2); + + // 获取常见毒品及其代谢物 === "甲基苯丙胺、苯丙胺(甲基苯丙胺代谢物);氯胺酮、去甲氯胺酮(氯胺酮代谢物);吗啡(海洛因二级代谢产物)、O6-单乙酰吗啡(海洛因一级代谢产物);" + + // "可待因;可卡因、苯甲酰爱康宁(可卡因代谢物);3,4-亚甲基二氧甲基苯丙胺(摇头丸MDMA)、3,4-亚甲基二氧基苯丙胺(摇头丸代谢物);芬太尼。" + List reportConfigDTOSFilterHeroin = dto.getCommonDrugAndMetabolites().stream().filter(o -> !o.getDictLabel().contains("海洛因")).collect(Collectors.toList()); + String commonDrugMetabolites = getCommonDrugMetabolites(reportConfigDTOSFilterHeroin); + + WordUtils.createParagraphAndBold(doc, ParagraphAlignment.LEFT, "常见毒品及其代谢物("+ reportConfigDTOSFilterHeroin.size() +"种):", + commonDrugMetabolites, false, 2); + // 人口标记物(1种):可替宁(烟草代谢物)。 + String populationMarkingMaterial = getPopulationMarking(dto.getPopulationMarkers()); + WordUtils.createParagraphAndBold(doc, ParagraphAlignment.LEFT, "人口标记物("+ dto.getPopulationMarkers().size() +"种):", + populationMarkingMaterial, false, 2); + + WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "根据各毒品目标物的浓度,并综合污水处理厂进水流量、人口标记物浓度," + + "计算了各污水处理厂服务区、各行政区的毒品千人均消费量和毒品总消费量,形成本分析报告。", false, 2); + + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.LEFT, + "(注:特别指出,本次检测工作只对收到的" + materialNum + "份污水样品进行分析评估,由于仅采集两天样品进行分析,数据结果仅供参考,个别异常数据还需深入研究,特此说明)", + "", + false, + 2); + + // 第二 + WordUtils.createParagraphTitle(doc, "二、全省总体情况", false, 2); + WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, yearMonth + "份,陕西省毒品消费结构:", false, 2); + + // 设置饼图数据 + PieChartForm pieChartForm = generateCommonDrugConsumeStructureChart(allProvince); + WordUtils.createPieChart(doc, pieChartForm, "图1 陕西省常见毒品消费结构图"); + + Map inspectResultAnalysisMap = getInspectResultAnalysis(pieChartForm, allProvince); + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.LEFT, + "根据检测结果分析:" + inspectResultAnalysisMap.get("resultAnalysis").toString(), + "", + false, + 2); + + // 全省监测区域内容生成 + String provinceMonitorsDrugConsumeContent = getProvinceMonitorsDrugConsumeContent(inspectResultAnalysisMap, allProvince); + WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, provinceMonitorsDrugConsumeContent, false, 2); + + // todo 待完成 + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.LEFT, + "各毒品滥用现状如下:", + "", + false, + 2); + + + // 循环生成各毒品的滥用现状 + /* + * 原文 + * 冰毒 2023年2月份在54%的污水厂有冰毒及其代谢物检出。 + * 全省冰毒的千人均消费量为2.5毫克/千人/天,核算陕西省冰毒的总消费量为39.4克/天。 + * 西安冰毒总消费量为32.5克/天,占全省总消费量的82.5%。 + */ + String methamphetamineAbuseCurrentSituation = getMethamphetamineAbuseCurrentSituation(yearMonth, sewageDataDtos, regionalDrugConsumptionDTOMap, allProvince, sewagePlantNum); + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.LEFT, + "冰毒 ", + methamphetamineAbuseCurrentSituation, + false, + 2); + + /* 原文 + * 海洛因 2023年2月在98%的污水处理厂均有吗啡检出(海洛因的代谢物)。 + * 陕西省海洛因的千人均消费量18毫克/千人/天,核算海洛因的总消费量为285.3克/天。 + * 特别指出,根据污水中的吗啡和可待因的浓度计算海洛因消费量时, + * 粗略扣除了合法药物、医用吗啡以及磷酸可待因代谢吗啡的干扰, + * 但未充分考虑干扰的区域性和季节性差异,因而存在一定误差,结果仅供参考。 + */ + String heroinAbuseCurrentSituation = getHeroinAbuseCurrentSituation(yearMonth, sewageDataDtos, regionalDrugConsumptionDTOMap, allProvince, sewagePlantNum); + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.LEFT, + "海洛因 ", + heroinAbuseCurrentSituation, + false, + 2); + + /* 原文 + * 氯胺酮 2023年2月在9.3%的污水处理厂均有氯胺酮检出, + * 与2022年相比,2023年2月份氯胺酮滥用明显增加,在西安、宝鸡、安康、渭南和榆林5个地市(19个污水处理厂)中均有检出, + * 氯胺酮浓度范围为0.3~2.9 ng/L,后续检测中可持续关注。 + */ + String ketamineAbuseCurrentSituation = getDrugAbuseCurrentSituation( + yearMonth, + sewageDataDtos, + allTaskProvinceDrugConsumptionList, + sewagePlantNum, + sewageDataDto -> sewageDataDto.getKetamineConcentration() != 0, + Comparator.comparing(SewageDataDto::getKetamineConcentration), + SewageDataDto::getKetamineConcentration, + "氯胺酮"); + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.LEFT, + "氯胺酮 ", + ketamineAbuseCurrentSituation, + false, + 2); + /* 原文 + * 可卡因 本次监测中,在汉中市宁强县污水处理厂中有12.7ng/L的可卡因检出, + * 其他地市均未检出,说明全省范围的明显滥用,需长期关注,掌握变化趋势。 + */ + String cocaineAbuseCurrentSituation = getDrugAbuseCurrentSituation( + yearMonth, + sewageDataDtos, + allTaskProvinceDrugConsumptionList, + sewagePlantNum, + sewageDataDto -> sewageDataDto.getCocaineConcentration() != 0, + Comparator.comparing(SewageDataDto::getCocaineConcentration), + SewageDataDto::getCocaineConcentration, + "可卡因"); + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.LEFT, + "可卡因 ", + cocaineAbuseCurrentSituation, + false, + 2); + + /* 原文 + * 摇头丸(MDMA)在本次监测中均未检出,说明不存在摇头丸的明显滥用。 + */ + String mdmaAbuseCurrentSituation = getDrugAbuseCurrentSituation( + yearMonth, + sewageDataDtos, + allTaskProvinceDrugConsumptionList, + sewagePlantNum, + sewageDataDto -> sewageDataDto.getMdmaConcentration() != 0 && sewageDataDto.getMdaConcentration() != 0, + Comparator.comparing(SewageDataDto::getMdmaConcentration), + SewageDataDto::getMdmaConcentration, + "摇头丸(MDMA)"); + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.LEFT, + "摇头丸(MDMA) ", + mdmaAbuseCurrentSituation, + false, + 2); + + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.LEFT, + "芬太尼 ", + "在本次监测中均未检出,说明不存在芬太尼的明显滥用。", + false, + 2); + + if (dto.getGenerateEtomidateTable()) { + // 判断是否要生成依托咪酯的滥用现状 + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.LEFT, + "依托咪酯 ", + getEtomidateAbuseSCurrentSituation(yearMonth, sewageDataDtos), + false, + 2); + } + + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.CENTER, + "表1 陕西省各行政区主要毒品总消费量表 ", + "", + false, + 0); + // 陕西省各行政区主要毒品总消费量表 + List nameList = new ArrayList<>(Arrays.asList("海洛因", "冰毒", "氯胺酮", "MDMA", "可卡因", "芬太尼", "综合")); + TableCreateUtils.fetchRegionalDrugConsumptionTable(doc, regionalDrugConsumptionDTOList.size() + 2,15, nameList, regionalDrugConsumptionDTOList); + + // 柱状图 + BarLineChartForm chartForm1 = getServiceAreaDrugConsumeBarLineChartForm(doc, regionalDrugConsumptionDTOList, pieChartForm, cityNameList); + WordUtils.createBarLineCharts(doc, chartForm1, "图2 陕西省各行政区毒品千人均消费量",true); + + // 折线柱状图 todo + doc.createParagraph().createRun().addBreak(); + BarLineChartForm chartForm = generateDrugConsumePerThousandTrendChartData( + taskStartDateList, + pieChartForm.getXData(), + allTaskProvinceDrugConsumptionList); + WordUtils.createBarLineCharts(doc, chartForm, "图3 陕西省毒品千人均消费量变化趋势",true); + // 生成对这几个任务中陕西省的毒品千人均消费量变化趋势进行描述 + String drugConsumePerThousandTrendDescribe = getDrugConsumePerThousandTrendDescribe(allTaskProvinceDrugConsumptionList, taskInfoList); + // 判断当前任务前面是否存在任务 + TaskInfo taskInfo1 = taskIdByOrderStartTimeLimit4.get(0) == null ? taskInfo : taskIdByOrderStartTimeLimit4.get(0); + WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, + "陕西省" + taskInfo1.getTaskStartDate().format(chineseYearDoubleMonthFormatter ) + + "至" + yearMonth +"综合千人均消费量变化趋势如图3所示。" + + drugConsumePerThousandTrendDescribe, + false, 2); + // 生成全省海洛因的消费量变化趋势描述 + String heroinProvinceAbuseTendDescribe = analysisHeroinProvinceAbuseTendDescribe(allTaskProvinceDrugConsumptionList, taskStartDateChinaFormatList); + /* 原文 + * 全省海洛因千人均消费量与综合千人均消费量变化趋势一致。 + * 2023年2月(18毫克/千人/天)与2022年3月(24.5毫克/千人/天)相比,同比下降36%, + * 与2022年12月(46.5毫克/千人/天)相比,环比下降47%,海洛因滥用趋势逐渐下降。 + */ + WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, + "全省海洛因千人均消费量与综合千人均消费量变化趋势一致。" + heroinProvinceAbuseTendDescribe, + false, 2); + + /* 原文 + * 全省冰毒千人均消费量2023年2月(2.5毫克/千人/天)与2022年3月(3毫克/千人/天)相比,同比下降16.6%, + * 与2022年12月(1.1毫克/千人/天)相比,环比增加127%。全省冰毒滥用明显增加。 + */ + String methamphetamineProvinceAbuseTendDescribe = analysisMethamphetamineProvinceAbuseTendDescribe(allTaskProvinceDrugConsumptionList, taskStartDateChinaFormatList); + WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, + methamphetamineProvinceAbuseTendDescribe, + false, 2); + + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.CENTER, + "表2 陕西省各污水厂服务区及各行政区毒品千人均消费量表 ", + "", + false, + 0); + + // 表2 陕西省各污水厂服务区及各行政区毒品千人均消费量表 + generateServiceAreaDrugConsumptionPerThousandTable(sewageDataGroupByMap, regionalDrugConsumptionDTOMap, doc); + + // 空两行,模仿得到的模板格式 + doc.createParagraph(); + doc.createParagraph(); + WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "注:1.因西安和铜川各行政区之间无独立污水处理厂,因此除西安和铜川外按照污水处理厂计算千人均消费量量,其余地市按照区县计算。", false, 2); + WordUtils.createParagraphCustomTab(doc, ParagraphAlignment.LEFT, "2.不合格样品:定义为检测出该样品中可替宁浓度低于500 ng/L。", false, 2, 2); + if (dto.getGenerateEtomidateTable()) { + doc.createParagraph().createRun().addBreak(BreakType.PAGE); // 创建新的一页 + TableCreateUtils.subsection(doc, TableCreateUtils.SUBSECTIONONE); + WordUtils.createParagraphAndBold(doc, + ParagraphAlignment.CENTER, + "表3 陕西省第"+ yearMonth +"份各行政区污水厂检出依托咪酯统计表", + "", + false, + 0); + List headerList = new ArrayList<>(Arrays.asList("行政区", "污水厂数量", "污水样品数量", "污水厂检出数量", "样品检出数量", "样品检出百分比", "污水厂检出百分比", "依托咪酯检出污水厂名称")); + List> tableDataList = new ArrayList<>(); + tableDataList.add(headerList); + // 组装依托咪酯统计数据 + getEtomidateDetectedStatisticalData(sewageDataGroupByMap, tableDataList); + TableCreateUtils.fetchEtomidateDetectedStatisticalTable(doc, tableDataList.size(), headerList.size(), tableDataList); + WordUtils.createParagraph(doc, + ParagraphAlignment.LEFT, + "注:榆林、杨凌送样时未建立依托咪酯检测方法,故未检。", + false, + 2); + TableCreateUtils.subsection(doc, TableCreateUtils.SUBSECTIONTWO); + + } + // 三、各区域情况 +// doc.createParagraph().createRun().addBreak(BreakType.PAGE); + WordUtils.createParagraphTitle(doc, "三、各区域情况", false, 2); + WordUtils.createParagraphAndBothSidesBold(doc, + ParagraphAlignment.LEFT, + "(详细数据见表1)", + "根据" + yearMonth + "监测结果分析,陕西省各行政区和各监测污水厂服务片区的常规毒品滥用情况分析如下", + ":", + false, + 2); + WordUtils.createParagraphAndMiddleBold( + doc, + ParagraphAlignment.LEFT, + "从", + "综合总消费量", + "(冰毒、K粉、海洛因、可卡因、摇头丸和芬太尼五种毒品折算总量,反映某区域内全体人口的毒品滥用总量)分析。", + false, + 2); + + // 对当前季度任务的各行政区的综合总消费量进行降序排序 + List tcRegionalDrugConsumptionDTOS = getRegionalDrugConsumptionDTOSSortedDesc(regionalDrugConsumptionDTOList, true, true); + // 根据得到的降序数组进行描述 + String combinedTotalConsumptionDescribe = compareEachCityCombinedTotalConsumptionDescribe(tcRegionalDrugConsumptionDTOS); + /** + * 按行政区,西安市的综合总消费量最高为178.1克/天,占全省监测区域消费总量的54.8%; + * 其次是咸阳市,综合总消费量为33.6克/天,分别占全省监测区域消费总量的10.3%; + * 位居第三、第四、第五位的是榆林市、渭南市和宝鸡市,综合总消费量分别为31.4克/天、27.1克/天和24.9克/天, + * 占全省监测区域消费总量的9.6%、8.3%和7.6%;其余五个行政区综合总消费量均低于20克/天,占比均低于6%。 + */ + WordUtils.createParagraph( + doc, + ParagraphAlignment.LEFT, + combinedTotalConsumptionDescribe, + true, + 2); + // 如图所示各行政区毒品滥用总量排序(即综合总消费量排序):西安市>咸阳市>榆林市>渭南市>宝鸡市>延安市>汉中市>安康市>商洛市>铜川市>杨凌区。 + String combinedTotalConsumptionSortedDescStr = getCombinedTotalConsumptionSortedDesc(tcRegionalDrugConsumptionDTOS); + WordUtils.createParagraphAndBold( + doc, + ParagraphAlignment.LEFT, + "如图所示各行政区毒品滥用总量排序(即综合总消费量排序):", + combinedTotalConsumptionSortedDescStr, + true, + 2); + + // 折线图 各行政区毒品总消费量变化趋势 + WordUtils.createBarLineCharts(doc, + getRendsInTotalDrugConsumptionInEachAdministrativeRegion( + allMergeMegionalDrugConsumptionDTOList, + regionalDrugConsumptionDTOList, + taskStartDateList, + cityNameList), + "", + false); + + WordUtils.createParagraphAndBold( + doc, + ParagraphAlignment.CENTER, + "图4 各行政区毒品总消费量变化趋势", + "", + false, + 0); + // todo 这里的文字描述不太好生, 暂时不做 + WordUtils.createHighLightParagraph(doc, + ParagraphAlignment.LEFT, + "如图4所示,"+ + taskStartDateChinaFormatList.get(0) + + "至" + + taskStartDateChinaFormatList.get(taskStartDateChinaFormatList.size() - 1) + + "各市毒品消费总量变化趋势基本一致," + + "2022年3月至2022年9月各市毒品消费总量呈现下降趋势,至2022年12月呈现上升趋势,2023年2月出现明显下降。其中西安变化趋势最为明显," + + "2023年2月与2022年3月相比,西安总消费量同比下降16.2%,与2022年12月相比,西安总费量环比下降70%。", + false, + 2); + + WordUtils.createParagraphAndMiddleBold( + doc, + ParagraphAlignment.LEFT, + "综合千人均消费量", + "从", + "(冰毒、K粉、海洛因、可卡因、摇头丸和芬太尼五种毒品千人均消费量的折算总量," + + "反映单位人口的毒品滥用量)分析。", + false, + 2); + + // 对当前季度任务的各行政区的综合总消费量进行降序排序 + List pccRegionalDrugConsumptionDTOS = getRegionalDrugConsumptionDTOSSortedDesc(regionalDrugConsumptionDTOList, false, true); + String combinedThousandPerConsumptionCompareDescribe = getCombinedThousandPerConsumptionCompareDescribe(pccRegionalDrugConsumptionDTOS, allProvince); + /** + * 全省各行政区千人均变化趋势如图2所示,全省平均千人均消费量为20.5毫克/千人/天, + * 咸阳市的综合千人均消费量最高,为63.9毫克/千人/天,是全省平均水平的3.1倍; + * 其次是汉中市和宝鸡市,综合千人均消费量为38毫克/千人/天和31.9毫克/千人/天; + * 位居第四的是商洛市,综合千人均消费量分别为为27.4毫克/千人/天; + * 位居第五至十一位的分别是杨凌区、安康市、西安市、渭南市、延安市、铜川市和榆林市, + * 分别为27.5毫克/千人/天、22.3毫克/千人/天、20.9毫克/千人/天、20.5毫克/千人/天、19.3毫克/千人/天、16.4毫克/千人/天和13.9毫克/千人/天 + */ + WordUtils.createParagraph(doc, + ParagraphAlignment.LEFT, + combinedThousandPerConsumptionCompareDescribe, + false, + 2); + + // 对当前季度任务的各行政区的综合总消费量进行降序排序(全省的也包含在排序的数组里) + List pccRegionalDrugConsumptionDTOS1 = getRegionalDrugConsumptionDTOSSortedDesc(regionalDrugConsumptionDTOList, false, false); + String combinedThousandPerConsumptionSortedDesc = getCombinedThousandPerConsumptionSortedDesc(pccRegionalDrugConsumptionDTOS1); + WordUtils.createParagraphAndBold( + doc, + ParagraphAlignment.LEFT, + "各行政区毒品滥用水平排序(即综合千人均消费量排序):", + combinedThousandPerConsumptionSortedDesc, + false, + 2); + + // 折线图 各行政区毒品千人均消费量变化趋势 + WordUtils.createBarLineCharts(doc, getTrendsInPerCapitaDrugConsumptionEachAdministrativeRegion(allMergeMegionalDrugConsumptionDTOList, regionalDrugConsumptionDTOList, taskStartDateList, cityNameList), "",false); + + WordUtils.createParagraphAndBold( + doc, + ParagraphAlignment.CENTER, + "图5 各行政区毒品千人均消费量变化趋势", + "", + false, + 0); + + WordUtils.createHighLightParagraph(doc, + ParagraphAlignment.LEFT, + "如图5所示,2023年2月全省千人均消费量(除汉中市和咸阳市外)整体变化趋势与全省总消费量变化趋势保持一致。" + + "2022年3月至2022年9月各市千人均消费量呈现下降趋势,至2022年12月呈现上升趋势,2023年2月出现明显下降," + + "其中西安市和汉中市变化最为明显。汉中市2022年3月至2022年6月有所下降," + + "后3个月基本保持平稳。咸阳市2022年3月至2022年9月有所下降,其后2个月保持上升趋势。" + + "各市具体增长率/下降率见下表。", + false, + 2); + WordUtils.createParagraphAndBold( + doc, + ParagraphAlignment.CENTER, + "表3 陕西省各污水厂服务区及各行政区毒品千人均消费量表", + "", + false, + 0); + + // 表3 陕西省各污水厂服务区及各行政区毒品千人均消费量表 + List> cityDrugConsumptionGrowthRatesData = fetchCityDrugConsumptionGrowthRatesData(allMergeMegionalDrugConsumptionDTOList, regionalDrugConsumptionDTOList, taskInfoList, cityNameList); + TableCreateUtils.fetchCityDrugConsumptionGrowthRatesTable(doc, 3, 11, cityNameList, cityDrugConsumptionGrowthRatesData); + + WordUtils.createParagraphAndBothSidesBold( + doc, + ParagraphAlignment.LEFT, + "生活污水处理厂水样中“人口标记物”可替宁浓度过低或过高,会被公安部禁毒情报技术中心判定为", + "另有一点需要再次说明:", + "数据不合格,", + false, + 2); + + WordUtils.createParagraph(doc, + ParagraphAlignment.LEFT, + "影响陕西省的检测数据质量。请各市禁毒部门除关注毒品消费量数据之外," + + "重点寻找部分污水处理厂水样中可替宁浓度异常的原因(公安部禁毒情报技术中心给出的经验值范围:500~5000纳克/升)。" + + "对于可替宁浓度持续低于经验值的区县,建议在条件允许的情况下,申请连续采样送检,以供陕西分中心技术人员判断原因。", + false, + 2); + + // 换页 + doc.createParagraph().createRun().addBreak(BreakType.PAGE); + WordUtils.createParagraphTitle(doc, "四、2023年2月陕西省毒品滥用情况分析", false, 2); + WordUtils.createParagraphTitle(doc, "1、冰毒(甲基苯丙胺)", false, 3); + + List tableName2List = new ArrayList<>(Arrays.asList("污水处理厂名称","甲基苯丙胺(ng/L)")); + // 对数据进行排序 + List> sortSewageDataDtos = getSortSewageDataDtos(sewageDataDtoLists, + Comparator.comparing(SewageDataDto::getMethamphetamineConcentration).reversed()); + List> cityDrugAbuseConditionAnalysisData = fetchCityDrugAbuseConditionAnalysisData( + sortSewageDataDtos, + SewageDataDto::getMethamphetamineConcentration, + 10); + // 描述 冰毒(甲基苯丙胺) 的排名情况 + String describeMethamphetamineConcentrationRank = getDescribeMethamphetamineConcentrationRank(sortSewageDataDtos.get(sortSewageDataDtos.size()-1)); + WordUtils.createParagraph(doc, + ParagraphAlignment.LEFT, + yearMonth + "份," + + describeMethamphetamineConcentrationRank, + false, + 2); + + WordUtils.createParagraphAndBold( + doc, + ParagraphAlignment.CENTER, + "表4 陕西省污水处理厂冰毒浓度排名表", + "", + false, + 0); + + int analysisTableCols = taskStartDateChinaFormatList.size() * 2 + 1; + TableCreateUtils.fetchCityDrugAbuseConditionAnalysisTable(doc, 12, analysisTableCols, taskStartDateChinaFormatList, tableName2List, cityDrugAbuseConditionAnalysisData); + + WordUtils.createParagraphTitle(doc, "2、吗啡", false, 3); + + // 对数据进行排序 + List> sortSewageDataDtos1 = getSortSewageDataDtos(sewageDataDtoLists, + Comparator.comparing(SewageDataDto::getMorphineConcentration).reversed()); + List> cityDrugAbuseConditionAnalysisData1 = fetchCityDrugAbuseConditionAnalysisData( + sortSewageDataDtos1, + SewageDataDto::getMorphineConcentration, + 15); // 吗啡是列表前15名的污水厂 + + WordUtils.createParagraph(doc, + ParagraphAlignment.LEFT, + yearMonth + "份吗啡对全省毒品消费总量贡献较大," + getDescribeMorphineConcentrationRank(sortSewageDataDtos1.get(sortSewageDataDtos1.size() - 1)), + false, + 2); + + WordUtils.createParagraphAndBold( + doc, + ParagraphAlignment.CENTER, + "表5 陕西省污水处理厂吗啡检测情况", + "", + false, + 0); + + List tableName4List = new ArrayList<>(Arrays.asList("污水处理厂名称","吗啡(ng/L)")); + + TableCreateUtils.fetchCityDrugAbuseConditionAnalysisTable(doc, 17, analysisTableCols, taskStartDateChinaFormatList, tableName4List,cityDrugAbuseConditionAnalysisData1); + + WordUtils.createParagraphAndBold(doc, ParagraphAlignment.LEFT, "注:", "100 ng/L为公安部禁毒情报技术中心定义的警戒值。", false, 2); + + TableCreateUtils.subsection(doc, TableCreateUtils.SUBSECTIONONE); + WordUtils.createParagraphAndBold( + doc, + ParagraphAlignment.CENTER, + "附表:陕西省各污水厂监测点主要毒品及其代谢物每日浓度表", + "", + false, + 0); + List tableName5List = getDailyDrugAndMetaboliteConcentrationName(reportConfigDTOSFilterHeroin, dto.getPopulationMarkers()); +// List tableName5List = new ArrayList<>(Arrays.asList("可替宁","可待因","MDA","MDMA","可卡因","苯甲酰爱康宁","吗啡","O6-单乙酰吗啡","甲基苯丙胺","苯丙胺","氯胺酮","去甲氯胺酮","芬太尼")); + Map>> map = generateDailyDrugAndMetaboliteConcentrationData(sewageDataGroupByMap, tableName5List); + // 加2 的原因是有两行表头 + TableCreateUtils.fetchDailyDrugAndMetaboliteConcentrationTable(doc, sewageDataDtos.size() + 2, 17, tableName5List, map); + TableCreateUtils.subsection(doc, TableCreateUtils.SUBSECTIONTWO); + // 因为设置横向后,多出了一页空白页,直接删除最后一页 +// int pages = doc.getBodyElements().size(); +// doc.removeBodyElement(pages - 1); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + doc.write(outputStream); + doc.close(); + String fileSaveMinioPath = OSSDirectoryConstants.DOCUMENT_SEWAGE_REPORTS_DIRECTORY + "/" + yearMonth + "/" + taskInfo.getId() + "/" + yearMonth + "份"+ province +"污水专项检测毒品分析报告.docx"; +// WordUtils.saveAs(doc, "污水报告测试-111.docx", "C:\\Users\\27109\\Desktop\\DesktopFiles\\PersonalFile\\workFile\\LianChuang\\task\\污水报告\\"); + ossFile.fileSave(fileSaveMinioPath, new ByteArrayInputStream(outputStream.toByteArray())); + return fileSaveMinioPath; + } + + /** + * 获取附表:陕西省各污水厂监测点主要毒品及其代谢物每日浓度表中的毒品名称 + * @param commonDrugAndMetabolites + * @param populationMarkers + * @return + */ + private List getDailyDrugAndMetaboliteConcentrationName(List commonDrugAndMetabolites, List populationMarkers) { + List dailyDrugAndMetaboliteConcentrationName = populationMarkers.stream().map(ReportConfigDTO::getDictLabel).collect(Collectors.toList()); + dailyDrugAndMetaboliteConcentrationName.addAll(commonDrugAndMetabolites.stream().map(ReportConfigDTO::getDictLabel).collect(Collectors.toList())); + return dailyDrugAndMetaboliteConcentrationName; + } + + /** + * 生成每常见毒品及代谢物的描述 + * @param reportConfigDTOSFilterHeroin + * @return + */ + private String getCommonDrugMetabolites(List reportConfigDTOSFilterHeroin) { + StringBuilder stringBuilder = new StringBuilder(); + Map> reportConfigGroupMap = reportConfigDTOSFilterHeroin.stream().collect(Collectors.groupingBy(ReportConfigDTO::getDictType)); + reportConfigGroupMap.forEach((dictType, reportConfigs) -> { + Map> reportConfigsByType = reportConfigs.stream().collect(Collectors.groupingBy(ReportConfigDTO::getType)); + List commonDrugs = reportConfigsByType.getOrDefault("1", Collections.emptyList()); + List metabolites = reportConfigsByType.getOrDefault("2", Collections.emptyList()); + // 常见毒品和代谢物都不可能为空 + if (CollUtil.isNotEmpty(commonDrugs)) { + stringBuilder.append(commonDrugs.get(0).getDictLabel()); + if (CollUtil.isNotEmpty(metabolites)) { + String metaboliteLabels = metabolites.stream() + .map(configDTO -> configDTO.getDictLabel() + configDTO.getRemark()) + .collect(Collectors.joining("、")); + stringBuilder.append("、").append(metaboliteLabels); + } + stringBuilder.append(";"); + } else { + String metaboliteLabels = metabolites.stream() + .map(configDTO -> configDTO.getDictLabel() + configDTO.getRemark()) + .collect(Collectors.joining("、")); + stringBuilder.append(metaboliteLabels).append(";"); + } + }); + String resultStr = stringBuilder.toString(); + if (StrUtil.isNotBlank(resultStr)) { + return resultStr.substring(0, resultStr.length() - 1) + "。"; + } + return ""; + } + + /** + * 生成人口标记物的描述 + * @param reportConfigDTOS + * @return + */ + private String getPopulationMarking(List reportConfigDTOS) { + StringBuilder stringBuilder = new StringBuilder(); + Map> reportConfigGroupMap = reportConfigDTOS.stream().collect(Collectors.groupingBy(ReportConfigDTO::getDictType)); + reportConfigGroupMap.forEach((dictType, reportConfigs) -> { + Map> reportConfigsByType = reportConfigs.stream().collect(Collectors.groupingBy(ReportConfigDTO::getType)); + List commonDrugs = reportConfigsByType.getOrDefault("1", Collections.emptyList()); + List metabolites = reportConfigsByType.getOrDefault("2", Collections.emptyList()); + // 常见毒品和代谢物都不可能为空 + if (CollUtil.isNotEmpty(commonDrugs)) { + stringBuilder.append(commonDrugs.get(0).getDictLabel()).append(commonDrugs.get(0).getRemark()); + if (CollUtil.isNotEmpty(metabolites)) { + String metaboliteLabels = metabolites.stream() + .map(configDTO -> configDTO.getDictLabel() + configDTO.getRemark()) + .collect(Collectors.joining("、")); + stringBuilder.append("、").append(metaboliteLabels); + } + stringBuilder.append(";"); + } else { + String metaboliteLabels = metabolites.stream() + .map(configDTO -> configDTO.getDictLabel() + configDTO.getRemark()) + .collect(Collectors.joining("、")); + stringBuilder.append(metaboliteLabels).append(";"); + } + }); + String resultStr = stringBuilder.toString(); + if (StrUtil.isNotBlank(resultStr)) { + return resultStr.substring(0, resultStr.length() - 1) + "。"; + } + return ""; + } + + /** + * 组装生成依托咪酯的统计数据 + * @param sewageDataGroupByMap + * @param tableDataList + */ + private void getEtomidateDetectedStatisticalData(Map> sewageDataGroupByMap, List> tableDataList) { +// int materialSize = sewageDataDtos.size(); // 污水样品的总数量 +// int plantSize = sewagePlantNum.size(); + sewageDataGroupByMap.forEach((k,v) -> { + int materialSize = v.size(); // 污水样品的总数量 + Set sewagePlantNum = v.stream().map(sewageDataDto -> StrUtil.split(sewageDataDto.getSampleName(), "-").get(0)).collect(Collectors.toSet()); + int plantSize = sewagePlantNum.size(); + List subDataList = new ArrayList<>(); + subDataList.add(k); // 行政区名称 + subDataList.add(plantSize);// 污水厂数量 + subDataList.add(materialSize); // 污水样品数量 + // 检出依托咪酯的污水厂 + List detectedEtomidateList = v.stream().filter(sewageDataDto -> sewageDataDto.getEtomidateConcentration() != 0).collect(Collectors.toList()); + Set sewagePlantNameList = detectedEtomidateList.stream().map(sewageDataDto -> StrUtil.split(sewageDataDto.getSampleName(), "-").get(0)).collect(Collectors.toSet()); + int detectedEtomidatePlantSize = sewagePlantNameList.size(); + int detectedEtomidateMaterialSize = detectedEtomidateList.size(); + subDataList.add(detectedEtomidatePlantSize);// 污水厂检出数量 + subDataList.add(detectedEtomidateMaterialSize); // 样品检出数量 + subDataList.add(Math.ceil(detectedEtomidateMaterialSize / (double) materialSize * 100) + "%"); // 样品检出百分比 + subDataList.add(Math.ceil(detectedEtomidatePlantSize / (double) plantSize * 100) + "%"); // 污水厂检出百分比 + subDataList.add(sewagePlantNameList.stream().collect(Collectors.joining(","))); + tableDataList.add(subDataList); + }); + } + + /** + * 生成相关依托咪酯相关的滥用现状 + * @param yearMonth + * @param sewageDataDtos + * @return + */ + private String getEtomidateAbuseSCurrentSituation(String yearMonth, List sewageDataDtos) { + StringBuilder stringBuilder = new StringBuilder(); + List sewageDataDtosDetectedEtomidate = sewageDataDtos.stream().filter(o -> o.getEtomidateConcentration() != 0).collect(Collectors.toList()); + Set sewagePlantNum = sewageDataDtosDetectedEtomidate.stream().map(o -> StrUtil.split(o.getSampleName(), "-").get(0)).collect(Collectors.toSet()); + + stringBuilder + .append(yearMonth) + .append("检测的全省污水中依托咪酯含量,发现全省有") + .append(sewagePlantNum.size()) + .append("家污水厂共") + .append(sewageDataDtosDetectedEtomidate.size()) + .append("份污水样品存在依托咪酯检出,详情见表3。"); + + return stringBuilder.toString(); + } + + /** + * 生成氯胺酮/可卡因/摇头丸的滥用现状描述 + * + * @param yearMonth + * @param sewageDataDtos + * @param provinceDataList + * @param sewagePlantNum + * @param predicate 筛选的函数式条件 + * @param comparator 排序的函数式条件 + * @param drugName 毒品名称 + * @return + */ + private String getDrugAbuseCurrentSituation(String yearMonth, + List sewageDataDtos, + List provinceDataList, + Set sewagePlantNum, + Predicate predicate, + Comparator comparator, + Function function, + String drugName) { + StringBuilder stringBuilder = new StringBuilder(); + // 筛选出氯胺酮浓度不为0的检材 + List sewageDataDtosByDetected = sewageDataDtos.stream().filter(predicate).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(sewageDataDtosByDetected)) { + if (sewageDataDtosByDetected.size() == 1) { + SewageDataDto sewageDataDto = sewageDataDtosByDetected.get(0); + stringBuilder.append("本次监测中,在") + .append(sewageDataDto.getCityName()) + .append(StrUtil.split(sewageDataDto.getSampleName(), "-").get(0)) + .append("中有") + .append(keep1DecimalPlace.format(function.apply(sewageDataDto))) + .append("ng/L的"+drugName+"检出,其他地市均未检出,说明全省范围内无明显滥用,需长期关注,掌握变化趋势。"); + } else { + // 列表不为空 + // 计算有多少个污水厂检出 + Set detectedKetaminePlant = sewageDataDtosByDetected.stream().map(o -> StrUtil.split(o.getSampleName(), "-").get(0)).collect(Collectors.toSet()); + List detectedCity = new ArrayList<>(sewageDataDtosByDetected.stream().map(SewageDataDto::getCityName).collect(Collectors.toSet())); + List sewageDataDtosByDetectedKetamineSorted = sewageDataDtosByDetected.stream().sorted(comparator).collect(Collectors.toList()); + int lastYear = Year.now().minusYears(1).getValue(); + stringBuilder + .append(yearMonth) + .append("在") + .append(keep1DecimalPlace.format( + detectedKetaminePlant.size() / (double) sewagePlantNum.size() * 100)) + .append("%") + .append("的污水处理厂均有") + .append(drugName) + .append("检出,与") + .append(lastYear) + .append("相比,") + .append(yearMonth) + .append("份") + .append(drugName) + .append("滥用"); + RegionalDrugConsumptionDTO yearOnYear = provinceDataList.get(0); + RegionalDrugConsumptionDTO dto = provinceDataList.get(provinceDataList.size() - 1); + double yoyKetamineCon = Double.parseDouble(yearOnYear.getTcK()); + double ketamineCon = Double.parseDouble(dto.getTcK()); + if (yoyKetamineCon > ketamineCon) { + stringBuilder.append("逐渐下降,"); + } else if (yoyKetamineCon < ketamineCon) { + stringBuilder.append("明显增加,"); + } else { + stringBuilder.append("程度没有变化,"); + } + + int citySize = detectedCity.size(); + for (String city : detectedCity) { + int indexOf = detectedCity.indexOf(city); + if (indexOf == 0) { + stringBuilder.append(city); + } else if (indexOf == citySize - 1 && citySize >= 2) { + stringBuilder.append("和").append(city); + } else { + stringBuilder.append("、").append(city); + } + } + stringBuilder + .append(citySize) + .append("个地市(") + .append(detectedKetaminePlant.size()) + .append("个污水处理厂)中均有检出,") + .append(drugName) + .append("浓度范围为") + .append(keep1DecimalPlace.format(function.apply(sewageDataDtosByDetectedKetamineSorted + .get(0) + ) + ) + ) + .append("~") + .append(keep1DecimalPlace.format(function.apply(sewageDataDtosByDetectedKetamineSorted + .get(sewageDataDtosByDetectedKetamineSorted.size() - 1) + ) + ) + ) + .append(" ng/L,后续检测中可持续关注。"); + } + } else { + stringBuilder.append("在本次监测中均未检出,说明不存在").append(drugName).append("的明显滥用。"); + } + return stringBuilder.toString(); + } + + /** + * 生成海洛因的滥用现状 + * + * @param yearMonth + * @param sewageDataDtos + * @param regionalDrugConsumptionDTOMap + * @param allProvince + * @param sewagePlantNum + * @return + */ + private String getHeroinAbuseCurrentSituation(String yearMonth, List sewageDataDtos, Map regionalDrugConsumptionDTOMap, RegionalDrugConsumptionDTO allProvince, Set sewagePlantNum) { + StringBuilder stringBuilder = new StringBuilder(); + List sewageDataDtosByMorphine = sewageDataDtos.stream().filter(o -> o.getMorphineConcentration() != 0).collect(Collectors.toList()); + Set detectedMorphineNum = sewageDataDtosByMorphine.stream().map(o -> StrUtil.split(o.getSampleName(), "-").get(0)).collect(Collectors.toSet()); + double pccHeroinProvince = Double.parseDouble(allProvince.getPccHeroin()); + double tcHeroinProvince = Double.parseDouble(allProvince.getTcHeroin()); + if (pccHeroinProvince != 0 && tcHeroinProvince != 0) { + stringBuilder + .append(yearMonth) + .append("在") + .append(keep1DecimalPlace.format( + detectedMorphineNum.size() / (double) sewagePlantNum.size() * 100)) + .append("%的污水处理厂均有吗啡检出(海洛因的代谢物)。") + .append("陕西省海洛因的千人均消费量") + .append(allProvince.getPccHeroin()) + .append("毫克/千人/天,核算海洛因的总消费量为") + .append(allProvince.getTcHeroin()) + .append("克/天。特别指出,根据污水中的吗啡和可待因的浓度计算海洛因消费量时,粗略扣除了合法药物、医用吗啡以及磷酸可待因代谢吗啡的干扰,但未充分考虑干扰的区域性和季节性差异,因而存在一定误差,结果仅供参考。"); + } else { + stringBuilder.append("在本次监测中均未检出,说明不存在海洛因的明显滥用。"); + } + + return stringBuilder.toString(); + } + + /** + * 生成冰毒的滥用现状描述 + * @param yearMonth + * @param sewageDataDtos + * @param regionalDrugConsumptionDTOMap + * @param allProvince + * @return + */ + private String getMethamphetamineAbuseCurrentSituation(String yearMonth, List sewageDataDtos, Map regionalDrugConsumptionDTOMap, RegionalDrugConsumptionDTO allProvince, Set sewagePlantNum) { + StringBuilder stringBuilder = new StringBuilder(); + // 筛选检出冰毒的污水厂 + List sewageDataDtosByDetectedMa = sewageDataDtos.stream().filter(o -> o.getPccMa() != 0).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(sewageDataDtosByDetectedMa)) { + // 计算出检测冰毒的污水厂比例 + Set detectedMaSewagePlantNum = sewageDataDtosByDetectedMa.stream().map(o -> StrUtil.split(o.getSampleName(), "-").get(0)).collect(Collectors.toSet()); + RegionalDrugConsumptionDTO dto = regionalDrugConsumptionDTOMap.get("西安市"); + double maPercent = Double.parseDouble(dto.getTcMa()) / Double.parseDouble(allProvince.getTcMa()); + stringBuilder + .append(yearMonth) + .append("份在") + .append(keep1DecimalPlace.format( + detectedMaSewagePlantNum.size() / (double) sewagePlantNum.size() * 100) + ) + .append("%的污水厂有冰毒及其代谢物检出。") + .append("全省冰毒的千人均消费量为") + .append(allProvince.getPccMa()) + .append("毫克/千人/天,核算陕西省冰毒的总消费量为") + .append(allProvince.getTcMa()) + .append("克/天。").append("西安冰毒总消费量为") + .append(dto.getTcMa()) + .append("克/天,占全省总消费量的") + .append(keep1DecimalPlace.format(maPercent)) + .append("%"); + } else { + stringBuilder.append("在本次监测中均未检出,说明不存在冰毒的明显滥用。"); + } + + return stringBuilder.toString(); + } + + /** + * 全省冰毒千人均消费量 描述 + * @param allTaskProvinceDrugConsumptionList + * @param taskStartDateChinaFormatList + * @return + */ + private String analysisMethamphetamineProvinceAbuseTendDescribe(List allTaskProvinceDrugConsumptionList, List taskStartDateChinaFormatList) { + StringBuilder stringBuilder = new StringBuilder(); + int size = allTaskProvinceDrugConsumptionList.size(); + if (size < 2) { + return ""; + } + RegionalDrugConsumptionDTO nowTaskData = allTaskProvinceDrugConsumptionList.get(size - 1); + double nowTaskMaData = Double.parseDouble(nowTaskData.getPccMa()); + boolean yearDecline = false; // 标记同比是否下降, true 是在下降, false 不是 + boolean monthDecline = false; // 标记环比是否下降, true 是在下降, false 不是 + for (int i = 0; i < size - 1; i++) { + RegionalDrugConsumptionDTO dto = allTaskProvinceDrugConsumptionList.get(i); + double oldTaskMaData = Double.parseDouble(dto.getPccMa()); + double abs = Math.abs((nowTaskMaData - oldTaskMaData) / oldTaskMaData * 100); + switch (i) { + case 0: { + stringBuilder + .append("全省冰毒千人均消费量") + .append(taskStartDateChinaFormatList.get(size - 1)) + .append("(") + .append(nowTaskMaData) + .append("毫克/千人/天)") + .append("与") + .append(taskStartDateChinaFormatList.get(i)) + .append("(") + .append(oldTaskMaData) + .append("毫克/千人/天)相比,"); + if (size == 2) { + stringBuilder.append("环比"); + } else { + stringBuilder.append("同比"); + } + if (oldTaskMaData > nowTaskMaData) { + yearDecline = true; + stringBuilder.append("下降"); + } else { + yearDecline = false; + stringBuilder.append("增加"); + } + stringBuilder.append(keep1DecimalPlace.format(abs)).append("%"); + if (size == 2) { + stringBuilder.append("全省冰毒滥用趋势"); + if (yearDecline) { + stringBuilder.append("逐渐下降"); + } else { + stringBuilder.append("明显增加"); + } + stringBuilder.append("。"); + } else { + stringBuilder.append(","); + } + break; + } + default: { + if (i == size - 2) { + stringBuilder + .append("与") + .append(taskStartDateChinaFormatList.get(i)) + .append("(") + .append(oldTaskMaData) + .append("毫克/千人/天)相比,") + .append("环比"); + if (oldTaskMaData > nowTaskMaData) { + monthDecline = true; + stringBuilder.append("下降"); + } else { + monthDecline = false; + stringBuilder.append("增加"); + } + stringBuilder + .append(keep1DecimalPlace.format( + abs + ) + ) + .append("%,"); + if(yearDecline && monthDecline || monthDecline) { + stringBuilder.append("全省冰毒滥用趋势逐渐下降。"); + } else if (yearDecline) { + stringBuilder.append("全省冰毒滥用趋势明显增加。"); + } + } + } + } + } + return stringBuilder.toString(); + } + + /** + * 生成全省海洛因的消费量变化趋势描述 + * + * @param allTaskProvinceDrugConsumptionList + * @param taskStartDateChinaFormatList + * @return + */ + private String analysisHeroinProvinceAbuseTendDescribe(List allTaskProvinceDrugConsumptionList, List taskStartDateChinaFormatList) { + + StringBuilder stringBuilder = new StringBuilder(); + int size = allTaskProvinceDrugConsumptionList.size(); + if (size < 2) { + return ""; + } + RegionalDrugConsumptionDTO nowTaskData = allTaskProvinceDrugConsumptionList.get(size - 1); + double nowTaskHeroinData = Double.parseDouble(nowTaskData.getPccHeroin()); + boolean yearDecline = false; // 标记同比是否下降, true 是在下降, false 不是 + boolean monthDecline = false; // 标记环比是否下降, true 是在下降, false 不是 + for (int i = 0; i < size - 1; i++) { + RegionalDrugConsumptionDTO dto = allTaskProvinceDrugConsumptionList.get(i); + double oldTaskHeroinData = Double.parseDouble(dto.getPccHeroin()); + double abs = Math.abs((nowTaskHeroinData - oldTaskHeroinData) / oldTaskHeroinData * 100); + switch (i) { + case 0: { + stringBuilder + .append(taskStartDateChinaFormatList.get(size - 1)) + .append("(") + .append(nowTaskHeroinData) + .append("毫克/千人/天)") + .append("与") + .append(taskStartDateChinaFormatList.get(i)) + .append("(") + .append(oldTaskHeroinData) + .append("毫克/千人/天)相比,"); + if (size == 2) { + stringBuilder.append("环比"); + } else { + stringBuilder.append("同比"); + } + if (oldTaskHeroinData > nowTaskHeroinData) { + yearDecline = true; + stringBuilder.append("下降"); + } else { + yearDecline = false; + stringBuilder.append("增加"); + } + stringBuilder.append(keep1DecimalPlace.format(abs)).append("%"); + if (size == 2) { + stringBuilder.append("海洛因滥用趋势"); + if (yearDecline) { + stringBuilder.append("逐渐下降"); + } else { + stringBuilder.append("明显增加"); + } + stringBuilder.append("。"); + } else { + stringBuilder.append(","); + } + break; + } + default: { + if (i == size - 2) { + stringBuilder + .append("与") + .append(taskStartDateChinaFormatList.get(i)) + .append("(") + .append(oldTaskHeroinData) + .append("毫克/千人/天)相比,") + .append("环比"); + if (oldTaskHeroinData > nowTaskHeroinData) { + monthDecline = true; + stringBuilder.append("下降"); + } else { + monthDecline = false; + stringBuilder.append("增加"); + } + stringBuilder + .append(keep1DecimalPlace.format( + abs + ) + ) + .append("%,"); + if(yearDecline && monthDecline || monthDecline) { + stringBuilder.append("海洛因滥用趋势逐渐下降。"); + } else if (yearDecline) { + stringBuilder.append("海洛因滥用趋势明显增加。"); + } + } + } + } + } + return stringBuilder.toString(); + } + + /** + * 各行政区毒品滥用水平排序(即综合千人均消费量排序) + * @param pccRegionalDrugConsumptionDTOS1 + * @return + */ + private String getCombinedThousandPerConsumptionSortedDesc(List pccRegionalDrugConsumptionDTOS1) { + StringBuilder stringBuilder = new StringBuilder(); + for (RegionalDrugConsumptionDTO regionalDrugConsumptionDTO : pccRegionalDrugConsumptionDTOS1) { + if (pccRegionalDrugConsumptionDTOS1.indexOf(regionalDrugConsumptionDTO) == 0) { + stringBuilder.append(regionalDrugConsumptionDTO.getRegional()); + } else { + if (regionalDrugConsumptionDTO.getRegional().contains("全省平均")) { + stringBuilder.append("≧"); + } else { + stringBuilder.append(">"); + } + stringBuilder.append(regionalDrugConsumptionDTO.getRegional()); + } + } + stringBuilder.append("。"); + return stringBuilder.toString(); + } + + /** + * 全省各行政区 综合千人均消费量 排名描述 + * + * @param pccRegionalDrugConsumptionDTOS + * @param allProvince 当前季度全省的消费量统计 + * @return + */ + private String getCombinedThousandPerConsumptionCompareDescribe(List pccRegionalDrugConsumptionDTOS, RegionalDrugConsumptionDTO allProvince) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder + .append("全省各行政区千人均变化趋势如图2所示,全省平均千人均消费量为") + .append(allProvince.getPccTotal()).append("毫克/千人/天,"); + + int size = pccRegionalDrugConsumptionDTOS.size(); + for (int i = 0; i < size && i < 5; i++) { // 只用循环5次 + RegionalDrugConsumptionDTO dto = pccRegionalDrugConsumptionDTOS.get(i); + double pccTotal = Double.parseDouble(dto.getPccTotal()); + switch (i) { + case 0: { + stringBuilder + .append(dto.getRegional()) + .append("的综合千人均消费量最高,为") + .append(dto.getPccTotal()) + .append("毫克/千人/天,是全省平均水平的") + .append( + keep1DecimalPlace.format( + pccTotal / Double.parseDouble(allProvince.getPccTotal()))) + .append("倍;"); + break; + } + case 1: { + stringBuilder.append("其次是").append(dto.getRegional()); + if (size >= 3) { + stringBuilder.append("和").append(pccRegionalDrugConsumptionDTOS.get(i + 1).getRegional()); + } + stringBuilder.append(",综合千人均消费量为").append(dto.getPccTotal()).append("毫克/千人/天"); + if (size >= 3) { + stringBuilder.append("和").append(pccRegionalDrugConsumptionDTOS.get(i + 1).getPccTotal()).append("毫克/千人/天"); + } + stringBuilder.append(";"); + break; + } + case 3: { + stringBuilder + .append("位居第四的是") + .append(dto.getRegional()) + .append(",综合千人均消费量分别为") + .append(dto.getPccTotal()) + .append("毫克/千人/天;"); + break; + } + case 4: { + stringBuilder.append("位居第五"); + if (size > 5) { + stringBuilder.append("至").append(NumberTransferHanZi.getHanZiNameByNumber(size)).append("位的分别是"); + } else { + stringBuilder.append("位的是"); + } + stringBuilder.append(dto.getRegional()); + for (int j = 5; j < size; j++) { + RegionalDrugConsumptionDTO consumptionDTO = pccRegionalDrugConsumptionDTOS.get(j); + if (pccRegionalDrugConsumptionDTOS.indexOf(consumptionDTO) == (size - 1)) { + stringBuilder.append("和").append(consumptionDTO.getRegional()); + } else { + stringBuilder.append("、").append(consumptionDTO.getRegional()); + } + } + stringBuilder.append(",综合千人均消费量分别为").append(dto.getPccTotal()).append("毫克/千人/天"); + for (int j = 5; j < size; j++) { + RegionalDrugConsumptionDTO consumptionDTO = pccRegionalDrugConsumptionDTOS.get(j); + if (pccRegionalDrugConsumptionDTOS.indexOf(consumptionDTO) == (size - 1)) { + stringBuilder.append("和").append(consumptionDTO.getPccTotal()).append("毫克/千人/天"); + } else { + stringBuilder.append("、").append(consumptionDTO.getPccTotal()).append("毫克/千人/天"); + } + } + stringBuilder.append("。"); + } + } + } + + return stringBuilder.toString(); + } + + /*** + * 各行政区毒品滥用总量排序(即综合总消费量排序) + * @param regionalDrugConsumptionDTOS + * @return + */ + private String getCombinedTotalConsumptionSortedDesc(List regionalDrugConsumptionDTOS) { + StringBuilder stringBuilder = new StringBuilder(); + for (RegionalDrugConsumptionDTO regionalDrugConsumptionDTO : regionalDrugConsumptionDTOS) { + stringBuilder.append(regionalDrugConsumptionDTO.getRegional()); + if (regionalDrugConsumptionDTOS.indexOf(regionalDrugConsumptionDTO) == (regionalDrugConsumptionDTOS.size() - 1)) { + stringBuilder.append("。"); + } else { + stringBuilder.append(">"); + } + } + return stringBuilder.toString(); + } + + /** + * 各行政区中的综合总消费量比较和描述 + * @param regionalDrugConsumptionDTOS + * @return + */ + private String compareEachCityCombinedTotalConsumptionDescribe(List regionalDrugConsumptionDTOS) { + + StringBuilder stringBuilder = new StringBuilder(); + double sum = regionalDrugConsumptionDTOS.stream().mapToDouble(o -> Double.parseDouble(o.getTcTotal())).sum(); + int size = regionalDrugConsumptionDTOS.size(); + for (int i = 0; i < size && i < 6; i++) { + RegionalDrugConsumptionDTO dto = regionalDrugConsumptionDTOS.get(i); + double v = Double.parseDouble(dto.getTcTotal()); // 当前地区的综合消费量 + switch (i) { + case 0: { + stringBuilder + .append("按行政区,") + .append(dto.getRegional()) + .append("的综合总消费量最高为") + .append(dto.getTcTotal()) + .append("克/天,占全省监测区域消费总量的") + .append(keep1DecimalPlace.format(v / sum * 100)) + .append("%;"); + break; + } + case 1: { + stringBuilder + .append("其次是") + .append(dto.getRegional()) + .append(",综合总消费量为") + .append(dto.getTcTotal()) + .append("克/天,") + .append("分别占全省监测区域消费总量的") + .append(keep1DecimalPlace.format(v / sum * 100)) + .append("%;"); + break; + } + case 2: { + stringBuilder.append("位居第三"); + if (size >= 4) { + // 判断当前季度任务下送检的样品地市是否超过 + stringBuilder.append("、第四"); + } + if (size >= 5) { + stringBuilder.append("、第五"); + } + stringBuilder.append("的是").append(dto.getRegional()); + if (size >= 4) { + stringBuilder.append("、").append(regionalDrugConsumptionDTOS.get(i + 1).getRegional()); + } + if (size >= 5) { + stringBuilder.append("、").append(regionalDrugConsumptionDTOS.get(i + 2).getRegional()); + } + + stringBuilder.append(",综合总消费量分别为").append(dto.getTcTotal()).append("克/天"); + if (size >= 4) { + stringBuilder.append("、").append(regionalDrugConsumptionDTOS.get(i + 1).getTcTotal()).append("克/天"); + } + if (size >= 5) { + stringBuilder.append("、").append(regionalDrugConsumptionDTOS.get(i + 2).getTcTotal()).append("克/天"); + } + + stringBuilder + .append(",占全省监测区域消费总量的") + .append(keep1DecimalPlace.format(v / sum * 100)) + .append("%"); + if (size >= 4) { + stringBuilder.append("、") + .append(keep1DecimalPlace.format( + Double.parseDouble(regionalDrugConsumptionDTOS.get(i + 1).getTcTotal()) / sum * 100)) + .append("%"); + } + if (size >= 5) { + stringBuilder.append("、") + .append(keep1DecimalPlace.format( + Double.parseDouble(regionalDrugConsumptionDTOS.get(i + 2).getTcTotal()) / sum * 100)) + .append("%"); + } + stringBuilder.append(";"); + break; + } + case 5: { + stringBuilder + .append("其余") + .append(size - i) + .append("个行政区综合总消费量均低于") + .append(Math.ceil(v)) + .append("克/天,") + .append("占比均低于") + .append(Math.ceil(v / sum * 100)) + .append("%"); + break; + } + } + } + stringBuilder.append("。"); + return stringBuilder.toString(); + } + + /** + * 根据flag决定时根据综合总消费量进行排序还是综合千人均消费量排序 + * @param regionalDrugConsumptionDTOList + * @param flag true -> 综合总消费量 false 综合千人均消费量 + * @param remove 是否移除最后一个全省的消费量 + * @return + */ + private static List getRegionalDrugConsumptionDTOSSortedDesc(List regionalDrugConsumptionDTOList, boolean flag, boolean remove) { + List regionalDrugConsumptionDTOS = new ArrayList<>(regionalDrugConsumptionDTOList); + if (remove) { + // 对综合总消费量排序时要排除全省的 + regionalDrugConsumptionDTOS.remove(regionalDrugConsumptionDTOS.size() - 1); + } + Collections.sort(regionalDrugConsumptionDTOS, new Comparator() { + @Override + public int compare(RegionalDrugConsumptionDTO o1, RegionalDrugConsumptionDTO o2) { + Double o1V = Double.parseDouble(flag ? o1.getTcTotal() : o1.getPccTotal()); + Double o2V = Double.parseDouble(flag ? o2.getTcTotal() : o2.getPccTotal()); + return o2V.compareTo(o1V); + } + }); + return regionalDrugConsumptionDTOS; + } + + /** + * 描述 冰毒(甲基苯丙胺) 在 陕西省污水处理厂冰毒浓度排名 + * @param sewageDataDtos + * @return + */ + private String getDescribeMethamphetamineConcentrationRank(List sewageDataDtos) { + + String resultStr = ""; + for (int i = 0; i < sewageDataDtos.size() && i < 3; i++) { + SewageDataDto sewageDataDto = sewageDataDtos.get(i); + String sewagePlantName = StrUtil.split(sewageDataDto.getSampleName(), "-").get(0); + Double methamphetamineConcentration = sewageDataDto.getMethamphetamineConcentration(); + switch (i) { + case 0: { + resultStr = resultStr + "陕西省的甲基苯丙胺浓度范围为0(表示未检出,下同)~"+ + keep1DecimalPlace.format(methamphetamineConcentration) +"ng/L。" + "各污水厂检测数据中,浓度最高的" + + sewagePlantName + + "," + "甲基苯丙胺含量为"+ + keep1DecimalPlace.format(methamphetamineConcentration) +" ng/L;"; + break; + } + case 1: { + resultStr = resultStr + + "排名第二的是" + + sewagePlantName + "," + + "甲基苯丙胺含量为"+ + keep1DecimalPlace.format(methamphetamineConcentration) +" ng/L;"; + break; + } + case 2: { + resultStr = resultStr + + "排名第三的是" + + sewagePlantName + "," + + "甲基苯丙胺含量为"+ + keep1DecimalPlace.format(methamphetamineConcentration) +" ng/L。"; + break; + } + } + + } + return resultStr; + } + + /** + * 描述 吗啡 在 陕西省污水处理厂冰毒浓度排名 + * @param sewageDataDtos + * @return + */ + private String getDescribeMorphineConcentrationRank(List sewageDataDtos) { + // 筛选大于100ng/L的数量 + long count = sewageDataDtos.stream().filter(o -> o.getMorphineConcentration() > 100).count(); + String resultStr = ""; + for (int i = 0; i < sewageDataDtos.size() && i < 3; i++) { + SewageDataDto sewageDataDto = sewageDataDtos.get(i); + String sewagePlantName = StrUtil.split(sewageDataDto.getSampleName(), "-").get(0); + Double morphineConcentration = sewageDataDto.getMorphineConcentration(); + switch (i) { + case 0: { + resultStr = resultStr + + "吗啡日浓度范围为0(表示未检出,下同)~"+ + keep1DecimalPlace.format(morphineConcentration) +"ng/L。" + "其中全省" + + (count == 0 ? "没有" : ("有" + count + "个")) + + "污水处理厂的吗啡浓度高于100 ng/L。" + + "表5列出了吗啡浓度排名前15的污水处理厂。" + "浓度最高的是" + + sewagePlantName + + "," + "吗啡浓度为"+ + keep1DecimalPlace.format(morphineConcentration) +" ng/L;"; + break; + } + case 1: { + resultStr = resultStr + + "排名第二的是" + + sewagePlantName + "," + + "吗啡浓度为"+ + keep1DecimalPlace.format(morphineConcentration) +" ng/L;"; + break; + } + case 2: { + resultStr = resultStr + + "排名第三的是" + + sewagePlantName + + "吗啡浓度为"+ + keep1DecimalPlace.format(morphineConcentration) +" ng/L。"; + break; + } + } + } + return resultStr; + } + + /** + * 组装陕西省毒品滥用情况分析 - 各污水厂毒品浓度排名表 + * @param sortSewageDataDtos + * @param mapper + * @param cols 表格的行数 + * @return + */ + private List> fetchCityDrugAbuseConditionAnalysisData(List> sortSewageDataDtos, Function mapper, Integer cols) { + List> list = new ArrayList<>(); +// List> sortSewageDataDtos = getSortSewageDataDtos(sewageDataDtoLists, sort); + // 11 是表格的列数, + for (int i = 0; i < cols; i++) { + List subList = new ArrayList<>(); + // 添加数据 + subList.add(i + 1); + list.add(subList); + } + for (int i = 0; i < sortSewageDataDtos.size(); i++) { + List sewageDataDtos = sortSewageDataDtos.get(i); + List concentrationList = sewageDataDtos.stream().map(mapper::apply).collect(Collectors.toList()); + for (int j = 0; j < cols; j++) { + List subList = null; + + subList = list.get(j); + if (j < sewageDataDtos.size()) { + SewageDataDto sewageDataDto = sewageDataDtos.get(j); + subList.add(StrUtil.split(sewageDataDto.getSampleName(), "-").get(0)); + subList.add(keep1DecimalPlace.format(concentrationList.get(j))); + } else { + subList.add(""); + subList.add(""); + } + } + } + + return list; + } + + /** + * 根据检材检测出的毒品浓度进行排序 + * @param sewageDataDtoLists + * @param sort + * @return + */ + private static List> getSortSewageDataDtos(List> sewageDataDtoLists, Comparator sort) { + List> sortSewageDataDtos = new ArrayList<>(); + // 进行排序-升序 + for (List sewageDataDtoList : sewageDataDtoLists) { + List sewageDataDtos = sewageDataDtoList.stream().sorted(sort).collect(Collectors.toList()); + sortSewageDataDtos.add(sewageDataDtos); + } + return sortSewageDataDtos; + } + + /** + * 获取一年内的任务检材数据 + * @param taskInfoList + * @param dto + * @return + */ + private List> getSewageTaskDataForAYear(List taskInfoList, ExportSewageAnalystReportsDTO dto) { + List> resultList = new ArrayList<>(); + for (int i = 0; i < taskInfoList.size() - 1; i++) { + TaskInfo taskInfo = taskInfoList.get(i); + // feign 接口调用获取 污水检材 + List data = getSewageJobIdentificationMaterialVOS(dto, taskInfo); + // 获取每个样品的数据 + List sewageDataDtos = taskInfoService.processSewageDataDtos(dto.getDailySmokingPerCapita(), data); + resultList.add(sewageDataDtos); + } + return resultList; + } + + /** + * 组装 表3 陕西省各污水厂服务区及各行政区毒品千人均消费量表 的数据 + * + * @param allMergeMegionalDrugConsumptionDTOList 之前季度的消费量数据 + * @param regionalDrugConsumptionDTOList 当前季度的消费数据 + * @param taskInfoList 任务列表, 目的是取同期的月份, 上期的月份, 本期的月份 + * @param cityNameList + * @return + */ + private List> fetchCityDrugConsumptionGrowthRatesData(List> allMergeMegionalDrugConsumptionDTOList, List regionalDrugConsumptionDTOList, List taskInfoList, List cityNameList) { + // 取上期的数据, 取0的原因是在计算时任务列表的顺序是升序的, 所有第一个元素就是上期的数据, 同理最后一个则是同期的数据 + List regionalDrugConsumptionDTOList_LastYear = allMergeMegionalDrugConsumptionDTOList.get(0); + List regionalDrugConsumptionDTOList_Last = allMergeMegionalDrugConsumptionDTOList.get(allMergeMegionalDrugConsumptionDTOList.size() - 1); + + // 上期数据 + List lastList = compareDiffQuarterCityDrugConsumptionGrowthRatesData( + regionalDrugConsumptionDTOList_Last, + regionalDrugConsumptionDTOList, + taskInfoList.get(taskInfoList.size() - 2), + cityNameList, true); + // 同期数据 + List lastYearList = compareDiffQuarterCityDrugConsumptionGrowthRatesData( + regionalDrugConsumptionDTOList_LastYear, + regionalDrugConsumptionDTOList, + taskInfoList.get(0), + cityNameList, + false); + + return new ArrayList<>(Arrays.asList(lastYearList, lastList)); + } + + /** + * 比较两个不同季度的消费量数据 + * @param sourceList 本期的数据 + * @param compareList 上期或者同期数据 + * @param taskInfo 比较的任务信息 + * @param cityNameList + * @param isMonthToMonth 是否是环比 + * @return + */ + private List compareDiffQuarterCityDrugConsumptionGrowthRatesData(List compareList, + List sourceList, + TaskInfo taskInfo, + List cityNameList, + boolean isMonthToMonth) { + // 先把两个列表转出map, 城市名是key + Map sourceMap = sourceList.stream().collect(Collectors.toMap(RegionalDrugConsumptionDTO::getRegional, Function.identity())); + Map compareMap = compareList.stream().collect(Collectors.toMap(RegionalDrugConsumptionDTO::getRegional, Function.identity())); + // 存数据的列表 + List dataList = new ArrayList<>(); + dataList.add("与" + taskInfo.getTaskStartDate().format(chineseYearSingleMonthFormatter) + (isMonthToMonth ? "环比" : "同比"));// 比较的任务月份 + + for (String cityName : cityNameList) { + RegionalDrugConsumptionDTO source = sourceMap.get(cityName); + RegionalDrugConsumptionDTO compare = compareMap.get(cityName); + if (source != null && compare != null) { + double compareV = Double.parseDouble(compare.getPccTotal()); + double sourceV = Double.parseDouble(source.getPccTotal()); + double rate = (sourceV - compareV) / compareV * 100; + dataList.add(keep1DecimalPlace.format(rate) + "%"); + } else { + // 默认添加空字符串 + dataList.add(""); + } + } + + return dataList; + } + + /** + * 根据得到的各个季度任务的全省毒品消费量值 去 描述 陕西省毒品千人均消费量变化趋势 + * 在这里说明一下本期,同期和上期之间的关系 + * 1 本期 指的是当前季度 + * 2 上期 是 当前季度的上一个季度 + * 3 同期指的是去年的同一季度 + * @param allTaskProvinceDrugConsumptionList + * @param taskInfoList 已经根据任务开始时间进行升序排序的列表 + * @return + */ + private String getDrugConsumePerThousandTrendDescribe(List allTaskProvinceDrugConsumptionList, List taskInfoList) { + String resultStr = ""; + boolean turnPoint = false; // 上升是true 下降是false + int size = allTaskProvinceDrugConsumptionList.size(); + if (size < 4) { + return resultStr; + } + for (int i = 0; i < size; i++) { + RegionalDrugConsumptionDTO dto = allTaskProvinceDrugConsumptionList.get(i); + switch (i) { + case 0: { + if (Double.parseDouble(dto.getPccTotal()) > Double.parseDouble(allTaskProvinceDrugConsumptionList.get(i + 1).getPccTotal())) { + resultStr = resultStr + "全省千人均消费量自" + + taskInfoList.get(0).getTaskStartDate().format(chineseYearSingleMonthFormatter) + + "以来呈下降趋势,"; + turnPoint = false; + } else { + resultStr = resultStr + "全省千人均消费量自" + + taskInfoList.get(0).getTaskStartDate().format(chineseYearSingleMonthFormatter) + + "以来呈上升趋势,"; + turnPoint = true; + } + break; + } + case 1: { + if (turnPoint && (Double.parseDouble(dto.getPccTotal()) > Double.parseDouble(allTaskProvinceDrugConsumptionList.get(i + 1).getPccTotal())) ) { + // 如果之前是上升,现在 是下降则出现转折点 + resultStr = resultStr + "于" + taskInfoList.get(1).getTaskStartDate().format(chineseYearSingleMonthFormatter) + "开始下降,"; + turnPoint = false; + } else if (!turnPoint && (Double.parseDouble(dto.getPccTotal()) < Double.parseDouble(allTaskProvinceDrugConsumptionList.get(i + 1).getPccTotal()))) { + // 如果之前是下降,现在 是上升则出现转折点 + resultStr = resultStr + "于" + taskInfoList.get(1).getTaskStartDate().format(chineseYearSingleMonthFormatter) + "开始上升,"; + turnPoint = true; + } + break; + } + case 2: { + if (turnPoint && (Double.parseDouble(dto.getPccTotal()) > Double.parseDouble(allTaskProvinceDrugConsumptionList.get(i + 1).getPccTotal())) ) { + // 如果之前是上升,现在 是下降则出现转折点 + resultStr = resultStr + taskInfoList.get(2).getTaskStartDate().format(chineseYearSingleMonthFormatter) + "下降,"; + turnPoint = false; + } else if (!turnPoint && (Double.parseDouble(dto.getPccTotal()) < Double.parseDouble(allTaskProvinceDrugConsumptionList.get(i + 1).getPccTotal()))) { + // 如果之前是下降,现在 是上升则出现转折点 + resultStr = resultStr + taskInfoList.get(2).getTaskStartDate().format(chineseYearSingleMonthFormatter) + "上升,"; + turnPoint = true; + } + break; + } + case 3: { + if (turnPoint && (Double.parseDouble(dto.getPccTotal()) > Double.parseDouble(allTaskProvinceDrugConsumptionList.get(i + 1).getPccTotal())) ) { + // 如果之前是上升,现在 是下降则出现转折点 + resultStr = resultStr + "至" + taskInfoList.get(4).getTaskStartDate().format(chineseYearSingleMonthFormatter) + "开始下降,"; + turnPoint = false; + } else if (!turnPoint && (Double.parseDouble(dto.getPccTotal()) < Double.parseDouble(allTaskProvinceDrugConsumptionList.get(i + 1).getPccTotal()))) { + // 如果之前是下降,现在 是上升则出现转折点 + resultStr = resultStr + "至" + taskInfoList.get(4).getTaskStartDate().format(chineseYearSingleMonthFormatter) + "开始上升,"; + turnPoint = true; + } + break; + } + } + } + if (size > 3) { + + RegionalDrugConsumptionDTO dto1 = allTaskProvinceDrugConsumptionList.get(0); + RegionalDrugConsumptionDTO dto2 = allTaskProvinceDrugConsumptionList.get(size -2); + RegionalDrugConsumptionDTO dto3 = allTaskProvinceDrugConsumptionList.get(size -1); + resultStr = resultStr + taskInfoList.get(4).getTaskStartDate().format(chineseYearSingleMonthFormatter) + + "与" + + taskInfoList.get(0).getTaskStartDate().format(chineseYearSingleMonthFormatter) + "相比,"; + // 同比 (本期-同期) / 同期 * 100% + double v1 = Double.parseDouble(dto1.getPccTotal()); // 同期数据 + double v2 = Double.parseDouble(dto2.getPccTotal()); // 上期期数据 + double v3 = Double.parseDouble(dto3.getPccTotal()); // 本期期期数据 + double yearOnYear = (v3 - v1) / v1 * 100; // 同比 + double monthOnMonth = (v3 - v2) / v2 * 100; // 环比, (本期-上期) / 上期 * 100% + + if (v3 < v1) { + // 小于0 证明下降了 + resultStr = resultStr + "同比下降了" + keep1DecimalPlace.format(Math.abs(yearOnYear)) + "%,"; + } else { + resultStr = resultStr + "同比上升了" + keep1DecimalPlace.format(Math.abs(yearOnYear)) + "%,"; + } + + // 环比 + resultStr = resultStr + "与" + taskInfoList.get(3).getTaskStartDate().format(chineseYearSingleMonthFormatter) + "相比,"; + if (v3 < v2) { + // 小于0 证明下降了 + resultStr = resultStr + "环比下降了" + keep1DecimalPlace.format(Math.abs(monthOnMonth)) + "%。"; + } else { + resultStr = resultStr + "环比上升了" + keep1DecimalPlace.format(Math.abs(monthOnMonth)) + "%。"; + } + } + return resultStr; + } + + /** + * 获取 前面四个季度的毒品消费量数据,也不定是4个 + * @param sewageDataDtoLists + * @param taskIdByOrderStartTimeLimit4 + * @return + */ + private List> getAllMergeBeforeMegionalDrugConsumptionDTOList(List> sewageDataDtoLists, List taskIdByOrderStartTimeLimit4) { + List> allMergeMegionalDrugConsumptionDTOList = new ArrayList<>(); + // 因为目前只获取之前4个任务的信息,所以列表的长度为4 + if (CollUtil.isNotEmpty(taskIdByOrderStartTimeLimit4)) { + for (int i = 0; i < taskIdByOrderStartTimeLimit4.size() - 1; i++) { // 这里之所以减一的原因是 参数任务列表中最后一个这里不用求 + List beforeDrugConsumptionDTOList = fetchRegionalDrugConsumption(getSewageDataGroupByCityNameMap(sewageDataDtoLists.get(i))); + allMergeMegionalDrugConsumptionDTOList.add(beforeDrugConsumptionDTOList); + } + } + return allMergeMegionalDrugConsumptionDTOList; + } + + /** + * 获取 陕西省毒品千人均消费量变化趋势 执行图的x轴名称 + * + * @param taskInfoList + * @return + */ + private List getTaskStartDateList(List taskInfoList, DateTimeFormatter dateTimeFormatter) { + List xAxisNameList = taskInfoList + .stream() + .map(o -> o.getTaskStartDate().format(dateTimeFormatter)) // 在获取任务的开始年月 + .collect(Collectors.toList()); + + return xAxisNameList; + } + + /** + * 对任务进行开始时间的升序排序 + * @param taskIdByOrderStartTimeLimit4 + * @param taskInfo + * @return + */ + private List getTaskInfos(List taskIdByOrderStartTimeLimit4, TaskInfo taskInfo) { + List tempList = new ArrayList<>(taskIdByOrderStartTimeLimit4); + tempList.add(taskInfo); + List taskInfoList = tempList + .stream() + .sorted(Comparator.comparing(TaskInfo::getTaskStartDate)) // 根据任务开始时间进行排序 + .collect(Collectors.toList()); + return taskInfoList; + } + + /** + * 根据任务查询污水检材,筛选出某个省份的已经受理了的检材 + * @param dto + * @param taskInfo + * @return + */ + private List getSewageJobIdentificationMaterialVOS(ExportSewageAnalystReportsDTO dto, TaskInfo taskInfo) { + R> voListByJobIdR = remoteSewageJobIdentificationMaterialService.getSewageJobIdentificationMaterialVOListByJobId(taskInfo.getOriginalId()); + if (voListByJobIdR.getCode() == CommonConstants.FAIL) { + log.error("根据任务id 获取检材失败!"); + throw new RuntimeException("根据任务id 获取检材失败!"); + } + List data = voListByJobIdR + .getData() + .stream() + .filter(vo -> + vo.getProvinceName() + .equals(dto.getProvinceName()) && vo.getAcceptTime() != null) // 根据省编码筛选 + .collect(Collectors.toList()); + return data; + } + + /** + * 根据当前任务去比较之前四个任务的数据 + * + * @param taskStartDateList 要比较的毒品消费量数据 + * @param legendNameList 要比较的毒品消费量数据 + * @param regionalDrugConsumptionDTOList 保存着全省毒品消费量数据 + * @return + */ + private BarLineChartForm generateDrugConsumePerThousandTrendChartData(List taskStartDateList, + List legendNameList, + List regionalDrugConsumptionDTOList) { + + List yData = new ArrayList<>(); + for (String drugName : legendNameList) { + List thousandPerCapitaConsumptionList = getThousandPerCapitaConsumptionByDrug(regionalDrugConsumptionDTOList, drugName, false); + AxisYVal axisYVal = new AxisYVal(); + axisYVal.setTitle(drugName); + axisYVal.setVal(thousandPerCapitaConsumptionList.toArray(new Double[]{})); + yData.add(axisYVal); + } + // 折线数据组装 + List pccTotals = regionalDrugConsumptionDTOList.stream() + .map(o -> Double.parseDouble(o.getPccTotal())) + .collect(Collectors.toList()); + AxisYVal zx = new AxisYVal(); + zx.setTitle("综合"); + // 这里的值不能跌倒过来 + zx.setVal(pccTotals.toArray(new Double[]{})); + List yLintData = Collections.singletonList(zx); // 使用不可变列表 + + BarLineChartForm chartForm = new BarLineChartForm(); + chartForm.setTitle(""); + chartForm.setXTitle(""); + chartForm.setYTitle("千人均消费量(毫克/千人/天)"); + chartForm.setXData(taskStartDateList); + chartForm.setYBarData(yData); + chartForm.setYLineData(yLintData); + return chartForm; + } + + /** + * 取出各行政区主要毒品总消费量表 数据DTO 列表中的全省数据 + * + * @param regionalDrugConsumptionDTOList + * @param list + * @param allProvince 当前报告中的全省毒品消费量 + */ + private void extractedProvinceDrugConsumeData(List> regionalDrugConsumptionDTOList, List list, RegionalDrugConsumptionDTO allProvince) { + for (int i = 0; i < regionalDrugConsumptionDTOList.size(); i++) { + List regionalDrugConsumptionDTOSubList = regionalDrugConsumptionDTOList.get(i); + list.add(regionalDrugConsumptionDTOSubList.get(regionalDrugConsumptionDTOSubList.size()-1)); + } + list.add(allProvince); + } + + /** + * 循环生成陕西省各污水厂服务区及各行政区毒品千人均消费量表 + * @param sewageDataGroupByMap + * @param regionalDrugConsumptionDTOMap + * @param doc + */ + private void generateServiceAreaDrugConsumptionPerThousandTable(Map> sewageDataGroupByMap, Map regionalDrugConsumptionDTOMap, XWPFDocument doc) { + List nameList1 = new ArrayList<>(Arrays.asList("海洛因", "冰毒", "氯胺酮", "MDMA", "可卡因", "芬太尼", "综合折算")); + + for (String cityName : sewageDataGroupByMap.keySet()) { + + Map>> dataMap = new HashMap<>(); + + // 取这个市的所有污水检材 + List sewageDataDtos = sewageDataGroupByMap.get(cityName); + Map> sewageDataGroupByAreaName = null; + if (cityName.equals("西安市") || cityName.equals("铜川市")) { + // 根据检材的名称分组,因为检材名称的组成是 污水厂名称 + "-" +节假日或工作日样本组成, 所以这里通过 - 分隔 取第一个元素 + sewageDataGroupByAreaName = sewageDataDtos.stream().collect(Collectors.groupingBy(o -> StrUtil.split(o.getSampleName(), "-").get(0))); + } else { + sewageDataGroupByAreaName = sewageDataDtos.stream().collect(Collectors.groupingBy(SewageDataDto::getDistrictName)); + } + List> list = new ArrayList<>(); + for (String areaName : sewageDataGroupByAreaName.keySet()) { + List sewageDataDtosByAreaName = sewageDataGroupByAreaName.get(areaName); + // 总测算人口 + double estimatedPopulationSum = sewageDataDtosByAreaName.stream().mapToDouble(SewageDataDto::getEstimatedPopulation).sum(); + // 这里变量名取错了,这里的变量名的意思是 每个区县的千人均消费量,以tc开头 + Double tcHeroinSum = sewageDataDtosByAreaName.stream().mapToDouble(item -> item.getPccHeroin() * item.getEstimatedPopulation()).sum() / estimatedPopulationSum; + Double tcMaSum = sewageDataDtosByAreaName.stream().mapToDouble(item -> item.getPccMa() * item.getEstimatedPopulation()).sum() /estimatedPopulationSum; + Double tcKSum = sewageDataDtosByAreaName.stream().mapToDouble(item -> item.getPccK() * item.getEstimatedPopulation()).sum() / estimatedPopulationSum; + Double tcMdmaSum = sewageDataDtosByAreaName.stream().mapToDouble(item -> item.getPccMdma() * item.getEstimatedPopulation()).sum() /estimatedPopulationSum; + Double tcCocSum = sewageDataDtosByAreaName.stream().mapToDouble(item -> item.getPccCoc() * item.getEstimatedPopulation()).sum() / estimatedPopulationSum; + Double tcFenSum = sewageDataDtosByAreaName.stream().mapToDouble(item -> item.getPccFen() * item.getEstimatedPopulation()).sum() / estimatedPopulationSum; + // 对计算出来的数据进行NAN判断处理 + ValidDrugConsumptionResult result = getValidDrugConsumptionResult(tcHeroinSum, tcMaSum, tcKSum, tcMdmaSum, tcCocSum, tcFenSum); + Double tcTotal = result.tcKSum + result.tcMaSum + result.tcHeroinSum + result.tcMdmaSum + result.tcCocSum; + List rowDataList = new ArrayList<>(); + rowDataList.add(areaName); // 区县 + for (String name : nameList1) { + if (name.equals("海洛因")) { + rowDataList.add(keep1DecimalPlace.format(result.tcHeroinSum)); + } else if (name.equals("冰毒")) { + rowDataList.add(keep1DecimalPlace.format(result.tcMaSum)); + } else if (name.equals("氯胺酮")) { + rowDataList.add(keep1DecimalPlace.format(result.tcKSum)); + } else if (name.equals("MDMA")) { + rowDataList.add(keep1DecimalPlace.format(result.tcMdmaSum)); + } else if (name.equals("可卡因")) { + rowDataList.add(keep1DecimalPlace.format(result.tcCocSum)); + } else if (name.equals("芬太尼")) { + rowDataList.add(keep1DecimalPlace.format(result.tcFenSum)); + } else if (name.equals("综合折算")) { + rowDataList.add(keep1DecimalPlace.format(tcTotal)); + } + } + // 样品中可替宁浓度低于500 ng/L 为 不合格样品 + boolean exist = whetExistsUnqualifiedSamples(sewageDataDtosByAreaName); + rowDataList.add(exist ? "存在不合格样品" : ""); + list.add(rowDataList); + } + // 添加地区平均 + List lastRowDataList = new ArrayList<>(); + RegionalDrugConsumptionDTO regionalDrugConsumptionDTO = regionalDrugConsumptionDTOMap.get(cityName); + lastRowDataList.add("地区平均"); + for (String name : nameList1) { + if (name.equals("海洛因")) { + lastRowDataList.add(regionalDrugConsumptionDTO.getPccHeroin()); + } else if (name.equals("冰毒")) { + lastRowDataList.add(regionalDrugConsumptionDTO.getPccMa()); + } else if (name.equals("氯胺酮")) { + lastRowDataList.add(regionalDrugConsumptionDTO.getPccK()); + } else if (name.equals("MDMA")) { + lastRowDataList.add(regionalDrugConsumptionDTO.getPccMdma()); + } else if (name.equals("可卡因")) { + lastRowDataList.add(regionalDrugConsumptionDTO.getPccCoc()); + } else if (name.equals("芬太尼")) { + lastRowDataList.add(regionalDrugConsumptionDTO.getPccFen()); + } else if (name.equals("综合折算")) { + lastRowDataList.add(regionalDrugConsumptionDTO.getPccTotal()); + } + } + list.add(lastRowDataList); + dataMap.put(cityName, list); // 行政区城市名 + // 加2 的原因是有两行表头 + TableCreateUtils.fetchServiceAreaDrugConsumptionPerThousandTable(doc,list.size() + 2, 10, nameList1, dataMap); + doc.createParagraph(); + doc.createParagraph(); + } + } + + /** + * 判断是否存在不合格样品 + * 不合格样品:定义为检测出该样品中可替宁浓度低于500 ng/L。 + * @param sewageDataDtosByAreaName + * @return + */ + private boolean whetExistsUnqualifiedSamples(List sewageDataDtosByAreaName) { + + for (SewageDataDto sewageDataDto : sewageDataDtosByAreaName) { + if (sewageDataDto.getCotinineConcentration() < 500) { + return true; + } + } + return false; + } + + /** + * 图2 陕西省各行政区毒品千人均消费量 柱状图 + * + * @param doc + * @param regionalDrugConsumptionDTOList + * @param pieChartForm + * @param cityNameList + * @return + */ + private BarLineChartForm getServiceAreaDrugConsumeBarLineChartForm(XWPFDocument doc, List regionalDrugConsumptionDTOList, PieChartForm pieChartForm, List cityNameList) { + List list = new ArrayList<>(regionalDrugConsumptionDTOList); // new 一个新的列表操作 + + for (int i = 0; i < 2; i++) { // 空两行 + doc.createParagraph().createRun().addBreak(); + } + List xData = new ArrayList<>(); + List yData = new ArrayList<>(); +// for (int i = 0; i < regionalDrugConsumptionDTOList.size() - 1; i++) { // 不去最后一个的原因是,最后一个元素计算的是全省的 +// RegionalDrugConsumptionDTO dto = regionalDrugConsumptionDTOList.get(i); +// xData.add(dto.getRegional()); +// } + for (int i = 0; i < cityNameList.size(); i++) { + String cityName = cityNameList.get(i); + if (i < regionalDrugConsumptionDTOList.size() - 1) { // 不取最后一个的原因是,最后一个元素计算的是全省的 + RegionalDrugConsumptionDTO dto = regionalDrugConsumptionDTOList.get(i); + xData.add(dto.getRegional()); + } else if (!xData.contains(cityName)){ + xData.add(cityName); + RegionalDrugConsumptionDTO dto = new RegionalDrugConsumptionDTO(); + dto.setRegional(cityName); + dto.setPccHeroin("0"); + dto.setPccFen("0"); + dto.setPccMa("0"); + dto.setPccMdma("0"); + dto.setPccK("0"); + dto.setPccCoc("0"); + list.add(dto); + } + } + for (String drugName : pieChartForm.getXData()) { + List thousandPerCapitaConsumptionList = getThousandPerCapitaConsumptionByDrug(list, drugName, true); + AxisYVal axisYVal = new AxisYVal(); + axisYVal.setTitle(drugName); + axisYVal.setVal(thousandPerCapitaConsumptionList.toArray(new Double[]{})); + yData.add(axisYVal); + } + + BarLineChartForm chartForm1 = new BarLineChartForm(); + chartForm1.setTitle(""); + chartForm1.setXTitle(""); + chartForm1.setYTitle("千人均消费量(毫克/千人/天)"); + // new ArrayList<>(Arrays.asList("西安市", "咸阳市", "宝鸡市", "渭南市", "铜川市", "榆林市", "延安市", "汉中市", "商洛市", "安康市", "杨凌区")) + chartForm1.setXData(xData); + chartForm1.setYBarData(yData); + chartForm1.setYLineData(null); + return chartForm1; + } + + /** + * 根据毒品的名称获取对应各行政区的千人均消费量列表 + * @param regionalDrugConsumptionDTOList + * @param drugName + * @param isRemoveLastElement 是否移除最后一个元素 + * @return + */ + private List getThousandPerCapitaConsumptionByDrug(List regionalDrugConsumptionDTOList, String drugName, boolean isRemoveLastElement) { + List thousandPerCapitaConsumptionList = new ArrayList<>(); + List list = new ArrayList<>(regionalDrugConsumptionDTOList); // 因为参数是引用类型,直接移除会影响其他地方的调用,这里通过新new 一个实例来操作 + if (isRemoveLastElement) { + // 因为最后一个是全省的所以移除 + list.remove(list.size() -1); + } + if (drugName.equals("冰毒")) { + thousandPerCapitaConsumptionList = list.stream().map(o -> Double.parseDouble(o.getPccMa())).collect(Collectors.toList()); + } else if (drugName.equals("海洛因")) { + thousandPerCapitaConsumptionList = list.stream().map(o -> Double.parseDouble(o.getPccHeroin())).collect(Collectors.toList()); + } else if (drugName.equals("氯胺酮")) { + thousandPerCapitaConsumptionList = list.stream().map(o -> Double.parseDouble(o.getPccK())).collect(Collectors.toList()); + } else if (drugName.equals("摇头丸(MDMA)")) { + thousandPerCapitaConsumptionList = list.stream().map(o -> Double.parseDouble(o.getPccMdma())).collect(Collectors.toList()); + } else if (drugName.equals("可卡因")) { + thousandPerCapitaConsumptionList = list.stream().map(o -> Double.parseDouble(o.getPccCoc())).collect(Collectors.toList()); + } else if (drugName.equals("芬太尼")) { + thousandPerCapitaConsumptionList = list.stream().map(o -> Double.parseDouble(o.getPccFen())).collect(Collectors.toList()); + } + return thousandPerCapitaConsumptionList; + } + + /** + * 全省监测区域 内容生成 + * @param inspectResultAnalysisMap 在生成检测结果分析时计算的百分比 + * @param allProvince + * @return + */ + private String getProvinceMonitorsDrugConsumeContent(Map inspectResultAnalysisMap, RegionalDrugConsumptionDTO allProvince) { + String provinceMonitorsDrugConsumeContent = ""; + for (String key : inspectResultAnalysisMap.keySet()) { + if (key.equals("resultAnalysis")) { + continue; + } + String consumption = getConsumption(allProvince, key); + String percent = keep1DecimalPlace.format((Double) inspectResultAnalysisMap.get(key) * 100d); + provinceMonitorsDrugConsumeContent = StrUtil.isNotBlank(provinceMonitorsDrugConsumeContent) + ? provinceMonitorsDrugConsumeContent + key + "消费量为" + consumption + "克/天,占比" + percent + "%;" + : "全省监测区域内," + key + "消费量为" + consumption + "克/天,占比" + percent + "%;" ; + } + // 删除最后一个;,替换成 。 + return provinceMonitorsDrugConsumeContent.substring(0, provinceMonitorsDrugConsumeContent.length()-1) + "(受合法药物干扰,存在一定误差,仅供参考)。"; + } + + /** + * 获取不同毒品的消费量 + * @param allProvince + * @param key + * @return + */ + private String getConsumption(RegionalDrugConsumptionDTO allProvince, String key) { + String consumption = ""; + if (key.equals("冰毒")) { + consumption = allProvince.getTcMa(); + } else if (key.equals("海洛因")) { + consumption = allProvince.getTcHeroin(); + } else if (key.equals("氯胺酮")) { + consumption = allProvince.getTcK(); + } else if (key.equals("摇头丸(MDMA)")) { + consumption = allProvince.getTcMdma(); + } else if (key.equals("可卡因")) { + consumption = allProvince.getTcCoc(); + } else if (key.equals("芬太尼")) { + consumption = allProvince.getTcFen(); + } + return consumption; + } + + /** + * 根据饼图数据生成检测结果分析 + * + * @param pieChartForm + * @param allProvince + * @return + */ + private Map getInspectResultAnalysis(PieChartForm pieChartForm, RegionalDrugConsumptionDTO allProvince) { + + + List drugNameList = pieChartForm.getXData(); // 毒品名称列表 + Double[] numbers = (Double[]) pieChartForm.getYData().getVal(); // 饼图各毒品的消费量 + boolean flagMaster = false; // 标记是否存在大于10%的毒品,默认没有 + // 求数组的和 + Double sum = calculateArraySum(numbers); + Map map = new HashMap<>(); + for (int i = 0; i < numbers.length; i++) { + double percent = numbers[i] / sum; + if (percent > 0.1) { + flagMaster = true; + } + map.put(drugNameList.get(i), percent); + } + + // 拼接检出的字符串 + String detectedDrug = ""; + if (drugNameList.size() > 0) { + detectedDrug = getDetectedDrugStr(numbers, flagMaster, drugNameList, map); + } + + // 未检出的 + String noDetected = getNoDetectedStr(allProvince); + + map.put("resultAnalysis", detectedDrug + noDetected); + return map; + } + + /** + * 获取检出的毒品字符串 + * + * @param numbers + * @param drugNameList + * @param map + * @return + */ + private String getDetectedDrugStr(Double[] numbers, boolean flagMaster, List drugNameList, Map map) { + + String detectedDrug = ""; + if (flagMaster) { + String masterStr = ""; // 主要毒品 + String secondStr = ""; // 其次 + for (String key : map.keySet()) { + Double v = (Double) map.get(key); + if (v > 0.1) { + masterStr = StrUtil.isNotBlank(masterStr) ? masterStr + "、" + key : "陕西省存在滥用的主要毒品为" + key; + } else { + secondStr = StrUtil.isNotBlank(secondStr) ? secondStr + "、" + key : "其次为" + key; + } + } + // 因为flag 为true 那么肯定是有大于0.1的 + detectedDrug = masterStr + (StrUtil.isBlank(secondStr) ? "。" : "," + secondStr + "。"); + } else { + detectedDrug = "陕西省存在滥用的毒品为" + drugNameList.stream().collect(Collectors.joining("、")) + "。"; + } + + return detectedDrug; + } + + /** + * 获取结果分析中未检出的字符串 + * @param allProvince + * @return + */ + private String getNoDetectedStr(RegionalDrugConsumptionDTO allProvince) { + String noDetected = ""; + if (Double.parseDouble(allProvince.getTcHeroin()) == 0) { + noDetected = noDetected + "海洛因"; + } + // 冰毒 + if (Double.parseDouble(allProvince.getTcMa()) == 0) { + noDetected = StrUtil.isNotBlank(noDetected) ? noDetected + "、冰毒" : "冰毒"; + } + // 氯胺酮 + if (Double.parseDouble(allProvince.getTcK()) == 0) { + noDetected = StrUtil.isNotBlank(noDetected) ? noDetected + "、氯胺酮" : "氯胺酮"; + } + // 摇头丸 + if (Double.parseDouble(allProvince.getTcMdma()) == 0) { + noDetected = StrUtil.isNotBlank(noDetected) ? noDetected + "、摇头丸" : "摇头丸"; + } + // 可卡因 + if (Double.parseDouble(allProvince.getTcCoc()) == 0) { + noDetected = StrUtil.isNotBlank(noDetected) ? noDetected + "、可卡因" : "可卡因"; + } + // 芬太尼 + if (Double.parseDouble(allProvince.getTcFen()) == 0) { + noDetected = StrUtil.isNotBlank(noDetected) ? noDetected + "、芬太尼" : "芬太尼"; + } + // 如果确实有未检出的,则拼接 均未检出,暂未发现明显滥用。 + if (StrUtil.isNotBlank(noDetected)) { + noDetected = noDetected + "均未检出,暂未发现明显滥用。"; + } + return noDetected; + } + + /** + * 数组求和 + * @param numbers + * @return + */ + private Double calculateArraySum(Number[] numbers) { + Double sum = 0d; + for (Number number : numbers) { + sum = sum + (Double) number; + } + return sum; + } + + /** + * 获取文件模板样式路径 + * + * @return + * @throws UnsupportedEncodingException + */ + private ByteArrayInputStream getTemplateStyleFilePath() throws Exception { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); +// ossFile.fileGet(OSSDirectoryConstants.TEMPLATE_DIRECTORY + "/" + "templateStyles.docx", bos); + String path = null; + try { +// path = new ClassPathResource("template\\templateStyles.docx").getPath(); + ossFile.fileGet(OSSDirectoryConstants.TEMPLATE_DIRECTORY + "/" + "templateStyles.docx", bos); + } catch (Exception e) { + log.error("文件名为 {} 的模板路径获取失败!", "template\\templateStyles.docx"); + e.printStackTrace(); + } +// String filePath = URLDecoder.decode(path, "UTF-8"); + return new ByteArrayInputStream(bos.toByteArray()); + } + + /** + * 生成文档首页 + * @param doc + * @param yearMonth 报告的月份 + * @param organization 国家毒品实验室陕西分中心 + * @param generateDate 生成日期 + * @param province 省份 + */ + private void generateHomePage(XWPFDocument doc, String yearMonth, String organization, String generateDate, String province) { + // 空三行 + for (int i = 0; i < 3; i++) { + doc.createParagraph().createRun().addBreak(); + } + WordUtils.createDocHomePage(doc, yearMonth + province + "污水样品毒品监测分析报告", "",16, 24); + WordUtils.createDocHomePage(doc, organization, "",0, 18); + WordUtils.createDocHomePage(doc, generateDate, "",0, 18); + } + + /** + * 各污水厂监测点主要毒品及其代谢物每日浓度表 的 数据组装 + * @param sewageDataGroupByMap + * @param tableName5List + * @return + */ + private Map>> generateDailyDrugAndMetaboliteConcentrationData(Map> sewageDataGroupByMap, List tableName5List) { + Map>> dataMap = new HashMap<>(); + Map> drugConcentrationMap = new HashMap<>(); + drugConcentrationMap.put("可替宁", SewageDataDto::getCotinineConcentration); + drugConcentrationMap.put("可待因", SewageDataDto::getCodeineConcentration); + drugConcentrationMap.put("MDA", SewageDataDto::getMdaConcentration); + drugConcentrationMap.put("MDMA", SewageDataDto::getMdmaConcentration); + drugConcentrationMap.put("可卡因", SewageDataDto::getCocaineConcentration); + drugConcentrationMap.put("苯甲酰爱康宁", SewageDataDto::getBenzoylecgonineConcentration); + drugConcentrationMap.put("吗啡", SewageDataDto::getMorphineConcentration); + drugConcentrationMap.put("O6-单乙酰吗啡", SewageDataDto::getAcetylmorphineConcentration); + drugConcentrationMap.put("甲基苯丙胺", SewageDataDto::getMethamphetamineConcentration); + drugConcentrationMap.put("苯丙胺", SewageDataDto::getAmphetamineConcentration); + drugConcentrationMap.put("氯胺酮", SewageDataDto::getKetamineConcentration); + drugConcentrationMap.put("去甲氯胺酮", SewageDataDto::getNorketamineConcentration); + drugConcentrationMap.put("芬太尼", SewageDataDto::getFenConcentration); + sewageDataGroupByMap.forEach((k,v) -> { + List dataList = new ArrayList(); + for (SewageDataDto sewageDataDto : v) { + ArrayList subDataList = new ArrayList<>(); + // 根据检材的名称分组,因为检材名称的组成是 污水厂名称 + "-" +节假日或工作日样本组成, 所以这里通过 - 分隔 取第一个元素 + subDataList.add(StrUtil.split(sewageDataDto.getSampleName(), "-").get(0));// 污水厂名称 + subDataList.add(sewageDataDto.getCollectTime().format(DateTimeFormatter.ofPattern("yyyy-M-d"))); + for (String name : tableName5List) { + Function concentrationGetterFunction = drugConcentrationMap.get(name); + if (concentrationGetterFunction != null) { + subDataList.add(keep1DecimalPlace.format(concentrationGetterFunction.apply(sewageDataDto))); + } else { + // 或者添加null,表示该数据不存在 + } + } + subDataList.add("备注"); + dataList.add(subDataList); + } + dataMap.put(k, dataList); + }); + + return dataMap; + } + + /** + * 各行政区毒品总消费量变化趋势 折线图 + * + * @param allMergeMegionalDrugConsumptionDTOList + * @param regionalDrugConsumptionDTOList + * @param taskStartDateList + * @param cityNameList + * @return + */ + private BarLineChartForm getRendsInTotalDrugConsumptionInEachAdministrativeRegion(List> allMergeMegionalDrugConsumptionDTOList, List regionalDrugConsumptionDTOList, List taskStartDateList, List cityNameList) { + + List yLintData1 = getAxisYValsByLiineChart(allMergeMegionalDrugConsumptionDTOList, regionalDrugConsumptionDTOList, cityNameList,true); + + BarLineChartForm lineChartForm = new BarLineChartForm(); + lineChartForm.setTitle(""); + lineChartForm.setXTitle(""); + lineChartForm.setYTitle("总消费量(克/天)"); + lineChartForm.setXData(taskStartDateList); + lineChartForm.setYBarData(null); + lineChartForm.setYLineData(yLintData1); + return lineChartForm; + } + + /** + * 获取折线图的数据 + * @param allMergeMegionalDrugConsumptionDTOList + * @param regionalDrugConsumptionDTOList + * @param cityNameList + * @param flag 取值是综合总消费量还是千人均总消费量 + * @return + */ + private static List getAxisYValsByLiineChart(List> allMergeMegionalDrugConsumptionDTOList, List regionalDrugConsumptionDTOList, List cityNameList, boolean flag) { + List> list = new ArrayList<>(allMergeMegionalDrugConsumptionDTOList); + list.add(regionalDrugConsumptionDTOList); + + List> mapList = list.stream().map(item -> { + return item.stream().collect(Collectors.toMap(RegionalDrugConsumptionDTO::getRegional, Function.identity())); + }).collect(Collectors.toList()); + + List yLintData1 = new ArrayList<>(); + for (String cityName : cityNameList) { + AxisYVal axisYVal = new AxisYVal(); + axisYVal.setTitle(cityName); + Double[] doubles = new Double[list.size()]; + for (int i = 0; i < mapList.size(); i++) { + Map map = mapList.get(i); + if (map.containsKey(cityName)) { + RegionalDrugConsumptionDTO dto = map.get(cityName); + doubles[i] = Double.valueOf(flag ? dto.getTcTotal() : dto.getPccTotal()); + } else { + doubles[i] = 0d; + } + } + axisYVal.setVal(doubles); + yLintData1.add(axisYVal); + } + return yLintData1; + } + + /** + * 图5 各行政区毒品千人均消费量变化趋势 + * @param allMergeMegionalDrugConsumptionDTOList + * @param regionalDrugConsumptionDTOList + * @param taskStartDateList + * @param cityNameList + * @return + */ + private BarLineChartForm getTrendsInPerCapitaDrugConsumptionEachAdministrativeRegion(List> allMergeMegionalDrugConsumptionDTOList, List regionalDrugConsumptionDTOList, List taskStartDateList, List cityNameList) { + + List yLintData1 = getAxisYValsByLiineChart(allMergeMegionalDrugConsumptionDTOList, regionalDrugConsumptionDTOList, cityNameList, false); + + BarLineChartForm lineChartForm = new BarLineChartForm(); + lineChartForm.setTitle(""); + lineChartForm.setXTitle(""); + lineChartForm.setYTitle("千人均消费量/(毫克/千人/天)"); + lineChartForm.setXData(taskStartDateList); + lineChartForm.setYBarData(null); + lineChartForm.setYLineData(yLintData1); + return lineChartForm; + } + + /** + * 获取陕西省各行政区主要毒品总消费量表数据 列表 + * @param sewageDataGroupByMap + * @return + */ + private List fetchRegionalDrugConsumption(Map> sewageDataGroupByMap) { + + List regionalDrugConsumptionDTOS = new ArrayList<>(); + + sewageDataGroupByMap.forEach((k,v) -> { + RegionalDrugConsumptionDTO dto = getRegionalDrugConsumptionDTO(v); + regionalDrugConsumptionDTOS.add(dto); + }); + // 全省平均/总计 计算方式目前还不清楚 + regionalDrugConsumptionDTOS.add(getAllProvinceAvgAndSumDataDTO(regionalDrugConsumptionDTOS)); + + return regionalDrugConsumptionDTOS; + } + + /** + * 根据污水检材 去计算污水毒品千人均消费量,然后根据城市名称进行分组 + * @param sewageDataDtos + * @return + */ + private Map> getSewageDataGroupByCityNameMap(List sewageDataDtos) { + // 根据市级编码 分组 + Map> sewageDataGroupByMap = sewageDataDtos + .stream() + .collect(Collectors + .groupingBy(SewageDataDto::getCityName)); + return sewageDataGroupByMap; + } + + /** + * 获取全省各种毒品的千人均消费量平均值和总消费量 + * @param regionalDrugConsumptionDTOS + * @return + */ + private RegionalDrugConsumptionDTO getAllProvinceAvgAndSumDataDTO(List regionalDrugConsumptionDTOS) { + // 这部分是先计算全省各毒品平均消耗量 + double allProvinceHeroinAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccHeroin())); + double allProvinceCocAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccCoc())); + double allProvinceKAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccK())); + double allProvinceMaAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccMa())); + double allProvinceMdmaAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccMdma())); + double allProvinceFenAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccFen())); + double allProvincePccTotalAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccTotal())); + // 全省各毒品的总消耗量 + double allProvinceHeroinTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcHeroin())); + double allProvinceMaTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcMa())); + double allProvinceKTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcK())); + double allProvinceMdmaTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcMdma())); + double allProvinceCocTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcCoc())); + double allProvinceFenTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcFen())); + double allProvinceTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcTotal())); + + RegionalDrugConsumptionDTO dto = new RegionalDrugConsumptionDTO(); + dto.setRegional("全省平均/总计"); + // 平均 + dto.setPccHeroin(keep1DecimalPlace.format(allProvinceHeroinAvg)); + dto.setPccMdma(keep1DecimalPlace.format(allProvinceMdmaAvg)); + dto.setPccK(keep1DecimalPlace.format(allProvinceKAvg)); + dto.setPccMa(keep1DecimalPlace.format(allProvinceMaAvg)); + dto.setPccCoc(keep1DecimalPlace.format(allProvinceCocAvg)); + dto.setPccFen(keep1DecimalPlace.format(allProvinceFenAvg)); + dto.setPccTotal(keep1DecimalPlace.format(allProvincePccTotalAvg)); + + // 总计 + dto.setTcHeroin(keep1DecimalPlace.format(allProvinceHeroinTotalSum)); + dto.setTcMdma(keep1DecimalPlace.format(allProvinceMdmaTotalSum)); + dto.setTcCoc(keep1DecimalPlace.format(allProvinceCocTotalSum)); + dto.setTcMa(keep1DecimalPlace.format(allProvinceMaTotalSum)); + dto.setTcK(keep1DecimalPlace.format(allProvinceKTotalSum)); + dto.setTcFen(keep1DecimalPlace.format(allProvinceFenTotalSum)); + dto.setTcTotal(keep1DecimalPlace.format(allProvinceTotalSum)); + + return dto; + } + + /** + * 全省各毒品平均消耗量 + * @param regionalDrugConsumptionDTOS + * @param mapper + * @return + */ + private double calculateAverage(List regionalDrugConsumptionDTOS, Function mapper) { + return regionalDrugConsumptionDTOS.stream() + .mapToDouble(mapper::apply) + .average() + .orElse(0.0); + } + + /** + * 全省各毒品总消耗量 + * @param regionalDrugConsumptionDTOS + * @param mapper + * @return + */ + private double calculateConsumeSum(List regionalDrugConsumptionDTOS, Function mapper) { + return regionalDrugConsumptionDTOS.stream().mapToDouble(mapper::apply).sum(); + } + + /** + * 获取各行政区主要毒品总消费量 数据传输对象 + * @param v + * @return + */ + private RegionalDrugConsumptionDTO getRegionalDrugConsumptionDTO(List v) { + // 对小数进行保留1位小数的操作 + DecimalFormat df = new DecimalFormat("#.##"); + + RegionalDrugConsumptionDTO dto = new RegionalDrugConsumptionDTO(); + SewageDataDto sewageDataDto = v.get(0); + dto.setRegional(sewageDataDto.getCityName()); // 城市名称 + // 总测算人口 +// double estimatedPopulationSum = v.stream().mapToDouble(SewageDataDto::getEstimatedPopulation).sum(); +// // 各类毒品的总消耗量 +// Double tcHeroinSum = v.stream().mapToDouble(item -> item.getPccHeroin() * item.getEstimatedPopulation()).sum() ; +// Double tcMaSum = v.stream().mapToDouble(item -> item.getPccMa() * item.getEstimatedPopulation()).sum(); +// Double tcKSum = v.stream().mapToDouble(item -> item.getPccK() * item.getEstimatedPopulation()).sum(); +// Double tcMdmaSum = v.stream().mapToDouble(item -> item.getPccMdma() * item.getEstimatedPopulation()).sum(); +// Double tcCocSum = v.stream().mapToDouble(item -> item.getPccCoc() * item.getEstimatedPopulation()).sum(); +// Double tcFenSum = v.stream().mapToDouble(item -> item.getPccFen() * item.getEstimatedPopulation()).sum(); + // 总测算人口及各毒品消耗量的统计 + double estimatedPopulationSum = 0; + double tcHeroinSum = 0, tcMaSum = 0, tcKSum = 0, tcMdmaSum = 0, tcCocSum = 0, tcFenSum = 0; + for (SewageDataDto item : v) { + estimatedPopulationSum += item.getEstimatedPopulation(); + tcHeroinSum += item.getPccHeroin() * item.getEstimatedPopulation(); + tcMaSum += item.getPccMa() * item.getEstimatedPopulation(); + tcKSum += item.getPccK() * item.getEstimatedPopulation(); + tcMdmaSum += item.getPccMdma() * item.getEstimatedPopulation(); + tcCocSum += item.getPccCoc() * item.getEstimatedPopulation(); + tcFenSum += item.getPccFen() * item.getEstimatedPopulation(); + } + // 对计算出来的数据进行NAN判断处理 + // 对计算出来的数据进行NAN判断处理 + ValidDrugConsumptionResult result = getValidDrugConsumptionResult(tcHeroinSum, tcMaSum, tcKSum, tcMdmaSum, tcCocSum, tcFenSum); + Double tcTotal = result.tcKSum + result.tcMaSum + result.tcHeroinSum + result.tcMdmaSum + result.tcCocSum; + // 总消费量(克/天), 因为算出来的单位是毫克,所以这里需要除以1000, 综合 + dto.setTcTotal(df.format(tcTotal / 1000)); + dto.setTcHeroin(df.format(result.tcHeroinSum / 1000)); + dto.setTcMa(df.format(result.tcMaSum / 1000)); + dto.setTcK(df.format(result.tcKSum / 1000)); + dto.setTcMdma(df.format(result.tcMdmaSum / 1000)); + dto.setTcCoc(df.format(result.tcCocSum / 1000)); + dto.setTcFen(df.format(result.tcFenSum / 1000)); + + // 千人均消费量(毫克/千人/天) + double pccHeroin = estimatedPopulationSum == 0.0 ? 0 : result.tcHeroinSum / estimatedPopulationSum; + double pccK = estimatedPopulationSum == 0.0 ? 0 : result.tcKSum / estimatedPopulationSum; + double pccCoc = estimatedPopulationSum == 0.0 ? 0 : result.tcCocSum / estimatedPopulationSum; + double pccMa = estimatedPopulationSum == 0.0 ? 0 : result.tcMaSum / estimatedPopulationSum; + double pccMdma = estimatedPopulationSum == 0.0 ? 0 : result.tcMdmaSum / estimatedPopulationSum; + double pccFen = estimatedPopulationSum == 0.0 ? 0 : result.tcFenSum / estimatedPopulationSum; + double pccTotal = estimatedPopulationSum == 0.0 ? 0 : pccCoc + pccHeroin + pccFen + pccMa + pccMdma; + dto.setPccHeroin(df.format(pccHeroin)); + dto.setPccK(df.format(pccK)); + dto.setPccCoc(df.format(pccCoc)); + dto.setPccMa(df.format(pccMa)); + dto.setPccMdma(df.format(pccMdma)); + dto.setPccFen(df.format(pccFen)); + dto.setPccTotal(df.format(pccTotal)); + return dto; + } + + /** + * 图1 陕西省常见毒品消费结构图 + * @param dto 陕西省各行政区主要毒品总消费量表数据 中计算全省的dto + * @return + */ + private PieChartForm generateCommonDrugConsumeStructureChart(RegionalDrugConsumptionDTO dto) { + // 取列表最后一个,最后一个是计算全省的 + List xDataSet = new ArrayList<>(); // 饼图图例名称 + AxisYVal val3 = new AxisYVal(); // 创建封装饼图数据的类 + val3.setTitle(""); + List dataList = new ArrayList<>(); + + // 封装转换与添加逻辑,减少重复代码 + addIfNotZero("海洛因", dto.getTcHeroin(), xDataSet, dataList); + addIfNotZero("冰毒", dto.getTcMa(), xDataSet, dataList); + addIfNotZero("氯胺酮", dto.getTcK(), xDataSet, dataList); + addIfNotZero("摇头丸(MDMA)", dto.getTcMdma(), xDataSet, dataList); + addIfNotZero("可卡因", dto.getTcCoc(), xDataSet, dataList); + addIfNotZero("芬太尼", dto.getTcFen(), xDataSet, dataList); + + val3.setVal(dataList.toArray(new Double[]{})); + + //拼图 + PieChartForm pieChartFrom = new PieChartForm(); + pieChartFrom.setTitle(""); + pieChartFrom.setXData(new ArrayList<>(xDataSet)); + pieChartFrom.setYData(val3); + + return pieChartFrom; + } + + // 辅助方法,用于简化主方法中的逻辑, 减少不必要的Double.parseDouble调用,提高了代码的执行效率 + private void addIfNotZero(String drugName, String valueStr, List xDataSet, List dataList) { + double value = Double.parseDouble(valueStr); + if (value != 0) { + xDataSet.add(drugName); + dataList.add(value); + } + } + + /** + * 判断各类毒品消费量是不是NAN + * @param tcHeroinSum + * @param tcMaSum + * @param tcKSum + * @param tcMdmaSum + * @param tcCocSum + * @param tcFenSum + * @return + */ + private static ValidDrugConsumptionResult getValidDrugConsumptionResult(Double tcHeroinSum, Double tcMaSum, Double tcKSum, Double tcMdmaSum, Double tcCocSum, Double tcFenSum) { + tcHeroinSum = tcHeroinSum.toString().equals("NaN") ? 0 : tcHeroinSum; + tcMaSum = tcMaSum.toString().equals("NaN") ? 0 : tcMaSum; + tcKSum = tcKSum.toString().equals("NaN") ? 0 : tcKSum; + tcMdmaSum = tcMdmaSum.toString().equals("NaN") ? 0 : tcMdmaSum; + tcCocSum = tcCocSum.toString().equals("NaN") ? 0 : tcCocSum; + tcFenSum = tcFenSum.toString().equals("NaN") ? 0 : tcFenSum; + ValidDrugConsumptionResult result = new ValidDrugConsumptionResult(tcHeroinSum, tcMaSum, tcKSum, tcMdmaSum, tcCocSum, tcFenSum); + return result; + } + + /** + * 封装处理数据计算结果是nan的毒品消费量数据的 静态内部类 + */ + private static class ValidDrugConsumptionResult { + public final Double tcHeroinSum; + public final Double tcMaSum; + public final Double tcKSum; + public final Double tcMdmaSum; + public final Double tcCocSum; + public final Double tcFenSum; + + public ValidDrugConsumptionResult(Double tcHeroinSum, Double tcMaSum, Double tcKSum, Double tcMdmaSum, Double tcCocSum, Double tcFenSum) { + this.tcHeroinSum = tcHeroinSum; + this.tcMaSum = tcMaSum; + this.tcKSum = tcKSum; + this.tcMdmaSum = tcMdmaSum; + this.tcCocSum = tcCocSum; + this.tcFenSum = tcFenSum; + } + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TaskInfoServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TaskInfoServiceImpl.java new file mode 100644 index 0000000..0f54248 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TaskInfoServiceImpl.java @@ -0,0 +1,1489 @@ +package digital.laboratory.platform.inspection.service.impl; +/* + *@title TaskInfoServiceImpl + *@description + *@author xy + *@version 1.0 + *@create 2023/12/8 11:10 + */ + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.deepoove.poi.data.ChartSingleSeriesRenderData; +import com.deepoove.poi.data.Charts; +import digital.laboratory.platform.api.dto.UploadHairJobDTO; +import digital.laboratory.platform.api.dto.UploadSewageJobDTO; +import digital.laboratory.platform.api.entity.UploadHairJobDetailLite; +import digital.laboratory.platform.api.entity.UploadSewageJobDetailLite; +import digital.laboratory.platform.api.feign.RemoteUploadService; +import digital.laboratory.platform.common.core.constant.CommonConstants; +import digital.laboratory.platform.common.core.constant.OSSDirectoryConstants; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.feign.RemoteGenerateWordService; +import digital.laboratory.platform.common.oss.service.OssFile; +import digital.laboratory.platform.inspection.constant.BusinessType; +import digital.laboratory.platform.inspection.constant.SewageReportColumn; +import digital.laboratory.platform.inspection.dto.*; +import digital.laboratory.platform.inspection.entity.AssignmentInfo; +import digital.laboratory.platform.inspection.entity.TaskInfo; +import digital.laboratory.platform.inspection.mapper.TaskInfoMapper; +import digital.laboratory.platform.inspection.mapper.TestRecordSampleDataMapper; +import digital.laboratory.platform.inspection.service.*; +import digital.laboratory.platform.inspetion.api.entity.MaterialDto; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import digital.laboratory.platform.sewage.feign.RemoteSewageJobIdentificationMaterialService; +import digital.laboratory.platform.sewage.vo.SewageJobIdentificationMaterialVO; +import digital.laboratory.platform.sys.feign.RemoteDictionaryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.lang.StringUtils; +import org.apache.poi.hssf.usermodel.*; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.VerticalAlignment; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.commons.CommonsMultipartFile; + +import javax.annotation.Resource; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.text.DecimalFormat; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Service +@Slf4j +@SuppressWarnings("all") +public class TaskInfoServiceImpl extends ServiceImpl implements TaskInfoService { + + @Resource + private SampleInfoService sampleInfoService; + + @Resource + private AssignmentInfoService assignmentInfoService; + + @Resource + private TestRecordSampleDataService testRecordSampleDataService; + + @Resource + private TestRecordSampleSolutionService testRecordSampleSolutionService; + + @Resource + private TestRecordSampleDataMapper testRecordSampleDataMapper; + + @Resource + private RemoteUploadService remoteUploadService; + + @Resource + private RemoteDictionaryService remoteDictionaryService; + + @Resource + private RemoteGenerateWordService remoteGenerateWordService; + + @Resource + private RemoteSewageJobIdentificationMaterialService remoteSewageJobIdentificationMaterialService; + + @Resource + private TestRecordInstrumentConditionService testRecordInstrumentConditionService; + + @Resource + private OssFile ossFile; + + /** + * 根据目标任务的开始时间进行排序 取4个任务的id + * + * @param targetTask + * @return + */ + @Override + public List getTaskIdByOrderStartTimeLimit4(TaskInfo targetTask) { + List list = this.list(Wrappers.lambdaQuery() + .ne(TaskInfo::getOriginalId, "") + .isNotNull(TaskInfo::getOriginalId) + .lt(TaskInfo::getTaskStartDate, targetTask.getTaskStartDate()) + .orderByDesc(TaskInfo::getTaskStartDate) + .last("limit 4") + ); + + return list; + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public TaskInfo addTaskInfo(TaskInfoDto taskInfo) { + String businessType = taskInfo.getBusinessType(); + if (businessType.equals("污水任务鉴定")) { + taskInfo.setBusinessType("20002"); + } else { + taskInfo.setBusinessType("20001"); + } + String originalId = taskInfo.getOriginalId(); + //判断是否是从其他系统读取过来的数据 + if (StringUtils.isNotBlank(originalId)) { + TaskInfo info = this.getOne(Wrappers.lambdaQuery().eq(TaskInfo::getOriginalId, originalId)); + //判断是否已经添加至本系统 + if (ObjectUtils.isNotNull(info)) { + int index = 0; + //已经添加过来了,update即可 + taskInfo.setId(info.getId()); + List materialList = taskInfo.getMaterialList(); + String distributionSituation = info.getDistributionSituation(); + + //获取检材信息 + if (materialList != null && materialList.size() > 0) { + List oldSampleInfoList = sampleInfoService.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, info.getId())); + List newSampleInfoList = new ArrayList<>(); + List oldSampleNoList = new ArrayList<>(); + //获取已读取的检材信息 + if (oldSampleInfoList != null && oldSampleInfoList.size() > 0) { + oldSampleInfoList.forEach(item -> oldSampleNoList.add(item.getAcceptNo())); + } + //去重处理 + if (oldSampleNoList.size() > 0) { + for (MaterialDto material : materialList) { + if (taskInfo.getBusinessType().equals("20001")) { + material.setImNo(material.getSampleCode()); + } + if (!oldSampleNoList.contains(material.getImNo())) { + SampleInfo sampleInfo = new SampleInfo(); + sampleInfoService.copy(sampleInfo, material, 1); + sampleInfo.setBusinessType(taskInfo.getBusinessType()); + sampleInfo.setBusinessId(taskInfo.getId()); + newSampleInfoList.add(sampleInfo); + index = index + 1; + } + } + } else { + for (MaterialDto material : materialList) { + SampleInfo sampleInfo = new SampleInfo(); + sampleInfoService.copy(sampleInfo, material, 1); + sampleInfo.setBusinessType(taskInfo.getBusinessType()); + sampleInfo.setBusinessId(taskInfo.getId()); + newSampleInfoList.add(sampleInfo); + } + } + sampleInfoService.saveBatch(newSampleInfoList); + } + //修改检材总数 + if (StringUtils.isNotBlank(distributionSituation)) { + int prefix = 0; + int suffix = 0; + String[] split = distributionSituation.split("/"); + prefix = Integer.parseInt(split[0]); + suffix = Integer.parseInt(split[1]); + taskInfo.setDistributionSituation(prefix + "/" + (suffix + index)); + } + this.updateById(taskInfo); + return taskInfo; + } else { + taskInfo.setId(IdWorker.get32UUID().toUpperCase()); + List materialList = taskInfo.getMaterialList(); + if (materialList != null && materialList.size() > 0) { + List newSampleInfoList = new ArrayList<>(); + for (MaterialDto material : materialList) { + if (taskInfo.getBusinessType().equals("20001")) { + material.setImNo(material.getSampleCode()); + } + SampleInfo sampleInfo = new SampleInfo(); + sampleInfoService.copy(sampleInfo, material, 1); + sampleInfo.setBusinessType(taskInfo.getBusinessType()); + sampleInfo.setBusinessId(taskInfo.getId()); + newSampleInfoList.add(sampleInfo); + } + sampleInfoService.saveBatch(newSampleInfoList); + } + this.save(taskInfo); + return taskInfo; + } + + } + if (StringUtils.isBlank(taskInfo.getId())) { + taskInfo.setId(IdWorker.get32UUID()); + log.info("保存对象entrustInfo的ID为空,由系统生成一个给它使用 {}", taskInfo.getId()); + } + boolean ret = this.save(taskInfo); + if (ret) { + log.info("{} 保存成功", taskInfo); + return taskInfo; + } else { + log.info("{} 保存失败", taskInfo); + return null; + } + } + + + @Override + public TaskInfo updateTaskInfo(TaskInfo taskInfo) { +// if (taskInfo.getSource() == 0) { +// log.info("数据是其他系统推送录入的,不能修改"); +// return null; +// } + if (CollUtil.isNotEmpty(taskInfo.getCompoundsJsonArray())) { + taskInfo.setCompounds(taskInfo.getCompoundsJsonArray().toJSONString()); + } + boolean ret = this.updateById(taskInfo); + if (ret) { + return taskInfo; + } else { + return null; + } + } + + @Override + public Boolean deleteTaskInfo(String id) { + List assignmentInfos = assignmentInfoService.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, id)); + if (assignmentInfos.size() > 0) { + throw new RuntimeException(String.format("当前业务已被分配,无法删除!")); + } + return this.removeById(id); + } + + @Override + public IPage getTaskPageList(Page page, TaskInfo taskInfo, String keywords) { + IPage ret = this.page(page, Wrappers.lambdaQuery() + .like(StringUtils.isNotBlank(keywords), TaskInfo::getTaskName, keywords) + .orderByDesc(TaskInfo::getCreateTime)); + List records = ret.getRecords(); + for (TaskInfo info : records) { + List list = assignmentInfoService.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, info.getId())); + if (list.size() > 0) { + info.setIsDistribution(true); + } else { + info.setIsDistribution(false); + } + if (info.getBusinessType().equals("20001")) { + info.setBusinessTypeName("毛发任务"); + } else { + info.setBusinessTypeName("污水任务"); + } + } + return ret; + } + + @Override + public List getTaskList(TaskInfo taskInfo, String keywords) { + List retList = this.list(Wrappers.lambdaQuery() + .like(StringUtils.isNotBlank(keywords), TaskInfo::getTaskName, keywords) + .eq(StringUtils.isNotBlank(taskInfo.getId()), TaskInfo::getId, taskInfo.getId()) + .orderByDesc(TaskInfo::getCreateTime)); + for (TaskInfo info : retList) { + List list = assignmentInfoService.list(Wrappers.lambdaQuery().eq(AssignmentInfo::getBusinessId, info.getId())); + if (list.size() > 0) { + info.setIsDistribution(true); + } else { + info.setIsDistribution(false); + } + if (info.getBusinessType().equals("20001")) { + info.setBusinessTypeName("毛发任务"); + } else { + info.setBusinessTypeName("污水任务"); + } + } + return retList; + } + + @Override + public Boolean checkExist(String id) { + List retList = this.list(Wrappers.lambdaQuery() + .eq(TaskInfo::getId, id)); + if (retList.size() > 0) { + return true; + } else { + return false; + } + } + + @Override + public void createUploadItem(List sampleNos) { + List taskTestDataDTOList = testRecordSampleDataMapper. + queryWaitApproveTaskTestDataList(Wrappers.query() + .in("ss.sample_no", sampleNos)); + // 获取当前数据的业务类型 毛发还是污水 + String businessType = taskTestDataDTOList.get(0).getBusinessType(); + //获取对应样本溶液编号的实验数据,按检材编号进行分组 + Map> map = taskTestDataDTOList + .stream().collect(Collectors.groupingBy(item -> item.getAcceptNo())); + + if (businessType.equals(BusinessType.BOINT_JOB.getBusinessType())) { + getUploadHairJobDTOS(map); + } else { + getUploadSewageJobDTOS(map); + } + + } + + /** + * 导出污水专项检测毒品分析报告 + * + * @param dto + * @return + */ + @Override + public R exportSewageAnalystReports(ExportSewageAnalystReportsDTO dto) { + + +// String yearMonth = dto.getMonth().format(DateTimeFormatter.ofPattern("yyyy年MM月")); + // 目前字典中的单位名称不统一,这里暂时写死,后期在改 + String organization = "国家毒品实验室陕西分中心"; + String generateDate = LocalDate.now().format(DateTimeFormatter.ofPattern("YYYY年MM月dd日")); + String province = dto.getProvinceName(); + R> voListByJobIdR = remoteSewageJobIdentificationMaterialService.getSewageJobIdentificationMaterialVOListByJobId(dto.getJobId()); + if (voListByJobIdR.getCode() == CommonConstants.FAIL) { + log.error("根据任务id 获取检材失败!"); + return R.failed("根据任务id 获取检材失败!"); + } + List data = voListByJobIdR + .getData() + .stream() + .filter(vo -> + vo.getProvinceName() + .equals(dto.getProvinceName()) && vo.getAcceptTime() != null) // 根据省编码筛选 + .collect(Collectors.toList()); + // 使用stream 流进行排序 + List dateSortedByAcceptTime = data.stream() + .sorted((d1, d2) -> d1.getAcceptTime().compareTo(d2.getAcceptTime())) + .collect(Collectors.toList()); + List dateSortedByCollectTime = data.stream() + .sorted((d1, d2) -> d1.getCollectTime().compareTo(d2.getCollectTime())) + .collect(Collectors.toList()); + String collectDate1 = dateSortedByAcceptTime.get(0).getAcceptTime().format(DateTimeFormatter.ofPattern("YYYY年MM月dd日")); + String collectDate2 = dateSortedByAcceptTime.get(dateSortedByAcceptTime.size() - 1).getAcceptTime().format(DateTimeFormatter.ofPattern("YYYY年MM月dd日")); + + String samplingDate1 = dateSortedByCollectTime.get(0).getCollectTime().format(DateTimeFormatter.ofPattern("YYYY年MM月dd日")); + String samplingDate2 = dateSortedByCollectTime.get(dateSortedByCollectTime.size() - 1).getCollectTime().format(DateTimeFormatter.ofPattern("YYYY年MM月dd日")); + int materialNum = data.size(); // 本次样本数量 + + // 常见的毒品及其代谢物 (先取检验鉴定中的样本表的目标物)和 TODO 人口标记物 还不知道怎么查 + List noList = data.stream().map(SewageJobIdentificationMaterialVO::getImNo).collect(Collectors.toList()); + // 查询检验鉴定的样本表 + List sampleInfoList = sampleInfoService.list(Wrappers.lambdaQuery().in(SampleInfo::getAcceptNo, noList)); + // 取所有的筛查物 列表 +// Set targetObjectSet = new HashSet<>(); +// for (SampleInfo sampleInfo : sampleInfoList) { +// // 获取这个检材的筛查物列表 +// List targetObjectList = sampleInfo.getTargetObject(); +// for (TargetObject targetObject : targetObjectList) { +// targetObjectSet.add(targetObject.getName()); +// } +// } + String commonDrugAndMetabolite = "甲基苯丙胺、苯丙胺(甲基苯丙胺代谢物);" + + "氯胺酮、去甲氯胺酮(氯胺酮代谢物);" + + "吗啡(海洛因二级代谢产物)、O6-单乙酰吗啡(海洛因一级代谢产物);" + + "可待因;" + + "可卡因、苯甲酰爱康宁(可卡因代谢物);" + + "3,4-亚甲基二氧甲基苯丙胺(摇头丸MDMA)、3,4-亚甲基二氧基苯丙胺(摇头丸代谢物);" + + "芬太尼。"; + String populationMarkers = "可替宁(烟草代谢物)"; + + // 查询检验数据 + List dataSolutionSampleDTOS = testRecordSampleDataMapper.queryDataSolutionSampleDTOList(Wrappers.query() + .in("si.id", sampleInfoList.stream().map(SampleInfo::getId).collect(Collectors.toList()))); + // 筛选出未检出的列表 + List undetectedList = dataSolutionSampleDTOS + .stream() + .filter(o -> o.getIsDetected() == 0) + .collect(Collectors.toList()); + // 筛选出检出的列表 + List detectedList = dataSolutionSampleDTOS + .stream() + .filter(o -> o.getIsDetected() == 1) + .collect(Collectors.toList()); + // 在根据检出的列表进行分类 + Map> groupByCompoundNameMap = detectedList + .stream() + .collect(Collectors.groupingBy(DataSolutionSampleDTO::getCompoundName)); + StringBuilder inspectResultAnalysis = new StringBuilder(); // 报告的检测结果分析 +// String commonDrugConsumeStructureChartInputStream = generateCommonDrugConsumeStructureChart(detectedList, groupByCompoundNameMap, inspectResultAnalysis); + // 把未检出的数据也拼凑到结果分析中 + inspectResultAnalysis + .append( + undetectedList + .stream() + .map(DataSolutionSampleDTO::getCompoundName) + .collect(Collectors.joining("、")) + ) + .append("均未检出,暂未发现明显滥用。"); + + // 获取陕西省各行政区主要毒品总消费量表数据 + List regionalDrugConsumptionDTOList = fetchRegionalDrugConsumption(data); + // 陕西省各行政区毒品千人均消费量统计图 输入流 +// ByteArrayInputStream drugConsumePerThousandPeopleByRegionChartInputStream = generateDrugConsumePerThousandPeopleByRegionChart(regionalDrugConsumptionDTOList, groupByCompoundNameMap.keySet()); + // 陕西省毒品千人均消费量变化趋势 统计图 输入流 +// generateDrugConsumePerThousandTrendChart(); + + Map docMap = new HashMap<>(); + docMap.put("yearMonth", null); + docMap.put("organization", organization); + docMap.put("generateDate", generateDate); + docMap.put("province", province); + docMap.put("collectDate1", collectDate1); + docMap.put("collectDate2", collectDate2); + docMap.put("samplingDate1", samplingDate1); + docMap.put("samplingDate2", samplingDate2); + docMap.put("materialNum", materialNum); + docMap.put("commonDrugAndMetabolite", commonDrugAndMetabolite); + docMap.put("populationMarkers", populationMarkers); + ChartSingleSeriesRenderData chartSingleSeriesRenderData = Charts + .ofSingleSeries("", new String[]{"海洛因", "冰毒", "氯胺酮", "可卡因"}) + .series("", new Number[]{76, 12, 2, 10}) + .create(); + docMap.put("demo", chartSingleSeriesRenderData); + +// docMap.put("commonDrugConsumeStructure", chartSingleSeriesRenderData); +// try { +// ChartSingleSeriesRenderData chartSingleSeriesRenderData = Charts.ofPie("", new String[]{"海洛因", "冰毒", "氯胺酮", "可卡因"}) +// .series("", new Number[]{76, 12, 2, 10}).create(); +// docMap.put("commonDrugConsumeStructure", chartSingleSeriesRenderData); +// docMap.put("commonDrugConsumeStructure", +// new ImageEntity(commonDrugConsumeStructureChartInputStream, 450, 265)); + +// } catch (Exception e) { +// e.printStackTrace(); +// log.error(e.getMessage()); +// } + docMap.put("abuseContent", inspectResultAnalysis.toString()); + docMap.put("regionalDrugConsumptionDTOList", regionalDrugConsumptionDTOList); + + String templatePath = OSSDirectoryConstants.DOCUMENT_SEWAGE_REPORTS_DIRECTORY + "/" + dto.getJobId() + "/" + "污水样品毒品检测分析报告-"; + String templateName = "污水样品毒品检测分析报告模板.docx"; + String fileType = ".docx"; + String originalFilename = "污水样品毒品检测分析报告-"; + List listNameCollection = new ArrayList<>(); + listNameCollection.add("abuseStatusList"); + listNameCollection.add("regionalDrugConsumptionDTOList"); + R r = remoteGenerateWordService.generateWord(templateName, originalFilename, templatePath, fileType, null, listNameCollection, false, docMap); + + return null; + } + + + /** + * 获取陕西省各行政区主要毒品总消费量表数据 列表 + * + * @param data + * @return + */ + private List fetchRegionalDrugConsumption(List data) { + + List regionalDrugConsumptionDTOS = new ArrayList<>(); + + List sewageDataDtos = processSewageDataDtos(5.19, data); + // 根据市级编码 分组 + Map> sewageDataGroupByMap = sewageDataDtos + .stream() + .collect(Collectors + .groupingBy(SewageDataDto::getCityName)); + + sewageDataGroupByMap.forEach((k, v) -> { + RegionalDrugConsumptionDTO dto = getRegionalDrugConsumptionDTO(v); + regionalDrugConsumptionDTOS.add(dto); + }); + // TODO 全省平均/总计 计算方式目前还不清楚 + regionalDrugConsumptionDTOS.add(getAllProvinceAvgAndSumDataDTO(regionalDrugConsumptionDTOS)); + + return regionalDrugConsumptionDTOS; + } + + /** + * 获取全省各种毒品的千人均消费量平均值和总消费量 + * + * @param regionalDrugConsumptionDTOS + * @return + */ + private RegionalDrugConsumptionDTO getAllProvinceAvgAndSumDataDTO(List regionalDrugConsumptionDTOS) { + // 这部分是先计算全省各毒品平均消耗量 + double allProvinceHeroinAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccHeroin())); + double allProvinceCocAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccCoc())); + double allProvinceKAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccK())); + double allProvinceMaAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccMa())); + double allProvinceMdmaAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccMdma())); + double allProvincePccTotalAvg = calculateAverage(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getPccTotal())); + // 全省各毒品的总消耗量 + double allProvinceHeroinTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcHeroin())); + double allProvinceMaTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcMa())); + double allProvinceKTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcK())); + double allProvinceMdmaTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcMdma())); + double allProvinceCocTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcCoc())); + double allProvinceTotalSum = calculateConsumeSum(regionalDrugConsumptionDTOS, regionalDrugConsumptionDTO -> Double.parseDouble(regionalDrugConsumptionDTO.getTcTotal())); + + // 对小数进行保留1位小数的操作 + DecimalFormat df = new DecimalFormat("#.#"); + RegionalDrugConsumptionDTO dto = new RegionalDrugConsumptionDTO(); + dto.setRegional("全省平均/总计"); + // 平均 + dto.setPccHeroin(df.format(allProvinceHeroinAvg)); + dto.setPccMdma(df.format(allProvinceMdmaAvg)); + dto.setPccK(df.format(allProvinceKAvg)); + dto.setPccMa(df.format(allProvinceMaAvg)); + dto.setPccCoc(df.format(allProvinceCocAvg)); + dto.setPccTotal(df.format(allProvincePccTotalAvg)); + + // 总计 + dto.setTcHeroin(df.format(allProvinceHeroinTotalSum)); + dto.setTcMdma(df.format(allProvinceMdmaTotalSum)); + dto.setTcCoc(df.format(allProvinceCocTotalSum)); + dto.setTcMa(df.format(allProvinceMaTotalSum)); + dto.setTcK(df.format(allProvinceKTotalSum)); + dto.setTcTotal(df.format(allProvinceTotalSum)); + + return dto; + } + + /** + * 全省各毒品平均消耗量 + * + * @param regionalDrugConsumptionDTOS + * @param mapper + * @return + */ + private double calculateAverage(List regionalDrugConsumptionDTOS, Function mapper) { + return regionalDrugConsumptionDTOS.stream() + .mapToDouble(mapper::apply) + .average() + .orElse(0.0); + } + + /** + * 全省各毒品总消耗量 + * + * @param regionalDrugConsumptionDTOS + * @param mapper + * @return + */ + private double calculateConsumeSum(List regionalDrugConsumptionDTOS, Function mapper) { + return regionalDrugConsumptionDTOS.stream().mapToDouble(mapper::apply).sum(); + } + + /** + * 获取各行政区主要毒品总消费量 数据传输对象 + * + * @param v + * @return + */ + private RegionalDrugConsumptionDTO getRegionalDrugConsumptionDTO(List v) { + // 对小数进行保留1位小数的操作 + DecimalFormat df = new DecimalFormat("#.#"); + + RegionalDrugConsumptionDTO dto = new RegionalDrugConsumptionDTO(); + SewageDataDto sewageDataDto = v.get(0); + dto.setRegional(sewageDataDto.getCityName()); // 城市名称 + // 总测算人口 + double estimatedPopulationSum = v.stream().mapToDouble(SewageDataDto::getEstimatedPopulation).sum(); + // 各类毒品的总消耗量 + double pccHeroinSum = v.stream().mapToDouble(SewageDataDto::getPccHeroin).sum(); + double pccMaSum = v.stream().mapToDouble(SewageDataDto::getPccMa).sum(); + double pccKSum = v.stream().mapToDouble(SewageDataDto::getPccK).sum(); + double pccMdmaSum = v.stream().mapToDouble(SewageDataDto::getPccMdma).sum(); + double pccCocSum = v.stream().mapToDouble(SewageDataDto::getPccCoc).sum(); + double tcTotal = pccKSum + pccMaSum + pccHeroinSum + pccMdmaSum + pccCocSum; + // 总消费量(克/天), 因为算出来的单位是毫克,所以这里需要除以1000, 综合 + dto.setTcTotal(df.format(tcTotal / 1000)); + dto.setTcHeroin(df.format(pccHeroinSum / 1000)); + dto.setTcMa(df.format(pccMaSum / 1000)); + dto.setTcK(df.format(pccKSum / 1000)); + dto.setTcMdma(df.format(pccMdmaSum / 1000)); + dto.setTcCoc(df.format(pccCocSum / 1000)); + + // 千人均消费量(毫克/千人/天) + double pccHeroin = pccHeroinSum / estimatedPopulationSum; + double pccK = pccKSum / estimatedPopulationSum; + double pccCoc = pccCocSum / estimatedPopulationSum; + double pccMa = pccMaSum / estimatedPopulationSum; + double pccMdma = pccMdmaSum / estimatedPopulationSum; + double pccTotal = pccCoc + pccHeroin + pccCoc + pccMa + pccMdma; + dto.setPccHeroin(df.format(pccHeroin)); + dto.setPccK(df.format(pccK)); + dto.setPccCoc(df.format(pccCoc)); + dto.setPccMa(df.format(pccMa)); + dto.setPccMdma(df.format(pccMdma)); + dto.setPccTotal(df.format(pccTotal)); + return dto; + } + +// /** +// * 生成常用毒品消费结构图, 返回其输入流 +// * +// * @param detectedList +// * @param groupByCompoundNameMap +// * @param inspectResultAnalysis 通过引用来获取值 +// * @return +// */ +// private String generateCommonDrugConsumeStructureChart(List detectedList, +// Map> groupByCompoundNameMap, +// StringBuilder inspectResultAnalysis) { +// String masterDrug = ""; // 主要毒品 +// String secondlyDrug = ""; // 其次毒品 +// +// int size = detectedList.size(); +// // 图例名称 +// List legendList = new ArrayList<>(groupByCompoundNameMap.keySet()); +// List dataList = new ArrayList<>(); +// // 图表背景 +// List colorList = randomGetColorList(legendList.size()); +// // 偏离百分比数据 +// List explodePercentList = new ArrayList<>(); +// for (String key : legendList) { +// List dataSolutionSampleDTOS = groupByCompoundNameMap.get(key); +// // 对小数进行保留两位小数的操作 +// DecimalFormat df = new DecimalFormat("#.##"); +// double percent = (dataSolutionSampleDTOS.size() / (double) size) * 100; +// dataList.add(df.format(percent)); +// // 设置偏离百分比 +// explodePercentList.add(0.01); +// // 大于10%的为主要毒品 +// if (percent > 10) { +// if (StrUtil.isNotBlank(masterDrug)) { +// masterDrug = "主要毒品为" + key; +// } else { +// masterDrug = masterDrug + "、" + key; +// } +// } else { +// if (StrUtil.isNotBlank(secondlyDrug)) { +// secondlyDrug = "其次为" + key; +// } else { +// secondlyDrug = secondlyDrug + "、" + key; +// } +// } +// } +// +// // 合成最终的检测结果分析 +// inspectResultAnalysis +// .append(masterDrug) +// .append(",") +// .append(secondlyDrug) +// .append("。"); +// +// // 创建输出流 +// ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); +// JFreeChart chart = null; +// try { +//// GeneratePieChartUtil.createPieChart( +//// byteArrayOutputStream, +//// "", +//// legendList, +//// dataList, +//// 450, +//// 265, +//// JFreeChartUtil.createChartTheme("宋体"), +//// colorList, +//// explodePercentList); +// chart = GeneratePieChartUtil.createPieChart( +// "", +// legendList, +// dataList, +// JFreeChartUtil.createChartTheme("宋体"), +// colorList, +// explodePercentList); +// File dirFile = new File(ResourceUtils.getURL("classpath:").getPath() + +// "chart/" + +// LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")) + "/"); +// if (!dirFile.exists()) { +// dirFile.mkdirs(); +// } +// String fileName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒")) + "-饼图" + ".png"; +// File file = new File(dirFile.getPath() + "/" + fileName); +// if (file.exists()) { +// file.delete(); +// } +// ChartUtils.saveChartAsPNG(file, chart, 800, 600); +// return dirFile.getPath() + "/" + fileName; +// } catch (Exception e) { +// e.printStackTrace(); +// log.error(e.getMessage()); +// } +// return null; +//// return new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); +//// return byteArrayOutputStream.toByteArray(); +// } + + /** + * 获取不同颜色的颜色列表 + * + * @param count + * @return + */ + private List randomGetColorList(int count) { + Random random = new Random(); + + Set colors = new HashSet<>(); + + while (colors.size() < count) { + int red = random.nextInt(256); + int green = random.nextInt(256); + int blue = random.nextInt(256); + + java.awt.Color color = new java.awt.Color(red, green, blue); + colors.add(color); + } + + log.info("获取的颜色RGB: " + colors.toString()); + return new ArrayList<>(colors); + } + + /** + * 推送毛发任务检验数据到上传系统 + * + * @param map + * @return + */ + private List getUploadHairJobDTOS(Map> map) { + List uploadHairJobDTOList = new ArrayList<>(); + map.forEach((k, v) -> { + UploadHairJobDTO uploadHairJobDTO = new UploadHairJobDTO(); + TaskTestDataDTO taskTestDataDTO = v.get(0); + uploadHairJobDTO.setResultId(taskTestDataDTO.getSampleDataId()); + uploadHairJobDTO.setExperimentId(taskTestDataDTO.getTestId()); + uploadHairJobDTO.setSampleId(taskTestDataDTO.getMaterialId()); + uploadHairJobDTO.setAnalysisTime(LocalDateTimeUtil.format(taskTestDataDTO.getCreateTime(), "yyyy-MM-dd")); + uploadHairJobDTO.setSampleCode(taskTestDataDTO.getAcceptNo()); // 样品编号 + uploadHairJobDTO.setEquipmentVendor("三重四极杆液质联用仪"); + uploadHairJobDTO.setEquipmentBrand("Waters TQ-S Micro"); + uploadHairJobDTO.setOrganizationName("国家毒品实验室陕西分中心"); + List uploadHairJobDetailLiteList = new ArrayList<>(); + // 取出每个检材中检测到的化合物浓度 + for (TaskTestDataDTO testDataDTO : v) { + UploadHairJobDetailLite uploadHairJobDetailLite = getUploadHairJobDetailLite(testDataDTO); + uploadHairJobDetailLiteList.add(uploadHairJobDetailLite); + } + uploadHairJobDTO.setDetails(uploadHairJobDetailLiteList); + + uploadHairJobDTOList.add(uploadHairJobDTO); + }); + + R hairJobUploadItem = remoteUploadService.createHairJobUploadItem(uploadHairJobDTOList); + if (hairJobUploadItem.getCode() == CommonConstants.FAIL) { + log.error("数据推送到上传系统失败!"); + throw new RuntimeException("数据推送到上传系统失败!"); + } + + return uploadHairJobDTOList; + } + + /** + * 生成毛发任务详细数据 + * + * @param testDataDTO + * @return + */ + private UploadHairJobDetailLite getUploadHairJobDetailLite(TaskTestDataDTO testDataDTO) { + UploadHairJobDetailLite uploadHairJobDetailLite = new UploadHairJobDetailLite(); + uploadHairJobDetailLite.setCompound(testDataDTO.getCompoundName()); + uploadHairJobDetailLite.setConcentration(testDataDTO.getSampleConcentration()); + // 检出限和定量限暂时设置 + uploadHairJobDetailLite.setExistLimit(0.01); + uploadHairJobDetailLite.setLowerLimit(0.02); + uploadHairJobDetailLite.setStatus(testDataDTO.getIsDetected() == 1 ? "detected" : "noDetected"); + return uploadHairJobDetailLite; + } + + /** + * 推送污水的检验数据到上传系统 + * + * @param map + * @return + */ + private List getUploadSewageJobDTOS(Map> map) { + List uploadSewageJobDTOS = new ArrayList<>(); + Set keySet = map.keySet(); + for (String acceptNo : keySet) { + UploadSewageJobDTO uploadSewageJobDTO = new UploadSewageJobDTO(); + uploadSewageJobDTO.setSampleCode(acceptNo); + ArrayList uploadSewageJobDetailLites = new ArrayList<>(); + List taskTestDataDTOS = map.get(acceptNo); + TaskTestDataDTO dataDTO = taskTestDataDTOS.get(0); + uploadSewageJobDTO.setResultId(taskTestDataDTOS.get(0).getSampleDataId()); + uploadSewageJobDTO.setExperimentId(taskTestDataDTOS.get(0).getTestId()); + uploadSewageJobDTO.setAnalysisTime(LocalDateTimeUtil.format(dataDTO.getCreateTime(), "yyyy-MM-dd")); + uploadSewageJobDTO.setEquipmentVendor("三重四极杆液质联用仪"); + uploadSewageJobDTO.setEquipmentBrand("Waters TQ-S Micro"); + uploadSewageJobDTO.setOrganizationName("国家毒品实验室陕西分中心"); + //获得化合物的Map,用来存储大数据平台需要的化合物信息 + Map compoundMap = this.getSewageCompoundMap(); + Set compoundKeySet = compoundMap.keySet(); + List compoundList = new ArrayList<>(compoundKeySet); + //组装上传数据的内容 + for (TaskTestDataDTO taskTestDataDTO : taskTestDataDTOS) { + String compoundName = taskTestDataDTO.getCompoundName().toLowerCase(); + //如果检验数据属于大数据平台要求上传的数据,那么就将检验出来的浓度赋值过去 + if (compoundKeySet.contains(compoundName)) { + compoundMap.put(compoundName, taskTestDataDTO.getSampleConcentration()); + } + } + //根据大数据平台要求的化合物来封装数据对象 + for (String compoundName : compoundList) { + UploadSewageJobDetailLite uploadSewageJobDetailLite = new UploadSewageJobDetailLite(); + uploadSewageJobDetailLite.setCompound(compoundName); + uploadSewageJobDetailLite.setConcentration(compoundMap.get(compoundName)); + uploadSewageJobDetailLites.add(uploadSewageJobDetailLite); + } + uploadSewageJobDTO.setDetails(uploadSewageJobDetailLites); + uploadSewageJobDTOS.add(uploadSewageJobDTO); + } + remoteUploadService.createUploadItem(uploadSewageJobDTOS); + return uploadSewageJobDTOS; + } + + //获得大数据平台要求的污水数据的化合物Map + public Map getSewageCompoundMap() { + Map map = new HashMap<>(); + map.put("cot", 0.0); + map.put("cod", 0.0); + map.put("mda", 0.0); + map.put("mdma", 0.0); + map.put("coc", 0.0); + map.put("bze", 0.0); + map.put("mor", 0.0); + map.put("o6", 0.0); + map.put("ma", 0.0); + map.put("am", 0.0); + map.put("k", 0.0); + map.put("nk", 0.0); + map.put("thc", 0.0); + return map; + } + + @Override + public List createSewageReportData(String taskId, Double dailySmokingPerCapita) { + TaskInfo taskInfo = this.getById(taskId); + String originalId = taskInfo.getOriginalId(); + if (!StringUtils.isNotBlank(originalId)) { + throw new RuntimeException("当前任务不是污水系统推送任务,无法生成报表!"); + } + R> r = remoteSewageJobIdentificationMaterialService.getSewageJobIdentificationMaterialVOListByJobId(originalId); + List voList = r.getData(); + + List sewageDataDtos = processSewageDataDtos(dailySmokingPerCapita, voList); + return sewageDataDtos; + } + + /** + * 根据污水任务检材列表和人均日吸烟 处理报表数据,最后返回数据列表 + * + * @param dailySmokingPerCapita + * @param voList + * @return + */ + @Override + public List processSewageDataDtos(Double dailySmokingPerCapita, List voList) { + List numList = new ArrayList<>(); + voList.forEach(item -> numList.add(item.getImNo())); + //获得任务中进行实验检材的检出数据 + List taskTestDataDTOList = testRecordSampleDataMapper. + queryWaitApproveTaskTestDataList(Wrappers.query() + .in("ss.sample_no", numList)); + + Map> map = taskTestDataDTOList.stream().collect(Collectors.groupingBy(item -> item.getAcceptNo()));//按照检材编号生成的Map + Set keySet = map.keySet(); + List sewageDataDtos = new ArrayList<>(); + //遍历每个检材,为检材添加化合物检测信息 + for (String key : keySet) { + SewageDataDto sewageDataDto = new SewageDataDto(); + for (SewageJobIdentificationMaterialVO vo : voList) { + if (vo.getImNo().equals(key)) { + BeanUtils.copyProperties(vo, sewageDataDto); + sewageDataDto.setDailySmokingPerCapita(dailySmokingPerCapita); + } + } + + List taskTestDataDTOS = map.get(key);//同一编号的一组化合物数据 + HashMap compoundMap = new HashMap<>(); + taskTestDataDTOS.forEach(item -> { + compoundMap.put(item.getCompoundName().toLowerCase(), item.getSampleConcentration()); + });//把化合物的名称与浓度封装到map中 + sewageDataDto.setCotinineConcentration(compoundMap.get("cot") != null ? compoundMap.get("cot") : 0d);//可替宁 + sewageDataDto.setCodeineConcentration(compoundMap.get("codeine") != null ? compoundMap.get("codeine") : 0d);//可待因 + sewageDataDto.setMdaConcentration(compoundMap.get("mda") != null ? compoundMap.get("mda") : 0d);//mad + sewageDataDto.setMdmaConcentration(compoundMap.get("mdma") != null ? compoundMap.get("mdma") : 0d);//mdma + sewageDataDto.setCocaineConcentration(compoundMap.get("cocaine") != null ? compoundMap.get("cocaine") : 0d);//可卡因 + sewageDataDto.setBenzoylecgonineConcentration(compoundMap.get("benzoylecgonine") != null ? compoundMap.get("benzoylecgonine") : 0d);//苯甲酰爱康宁 + sewageDataDto.setMorphineConcentration(compoundMap.get("morphine") != null ? compoundMap.get("morphine") : 0d);//吗啡 + sewageDataDto.setAcetylmorphineConcentration(compoundMap.get("6-acetylmorphine") != null ? compoundMap.get("6-acetylmorphine") : 0d);//O6-单乙酰吗啡 + sewageDataDto.setMethamphetamineConcentration(compoundMap.get("methamphetamine") != null ? compoundMap.get("methamphetamine") : 0d);//甲基苯丙胺 + sewageDataDto.setAmphetamineConcentration(compoundMap.get("amphetamine") != null ? compoundMap.get("amphetamine") : 0d);//苯丙胺 + sewageDataDto.setKetamineConcentration(compoundMap.get("ketamine") != null ? compoundMap.get("ketamine") : 0d);//氯胺酮 + sewageDataDto.setNorketamineConcentration(compoundMap.get("norketamine") != null ? compoundMap.get("norketamine") : 0d);//去甲氯胺酮 + sewageDataDto.setThcConcentration(compoundMap.get("thc") != null ? compoundMap.get("thc") : 0d);//四氢大麻酸 + sewageDataDto.setFenConcentration(compoundMap.get("fentanyl") != null ? compoundMap.get("fentanyl") : 0d);//芬太尼 + sewageDataDto.setEtomidateConcentration(compoundMap.get("etomidate") != null ? compoundMap.get("etomidate") : 0d);//依托咪酯 + +// for (TaskTestDataDTO taskTestDataDTO : taskTestDataDTOS) { +// switch (taskTestDataDTO.getCompoundName().toLowerCase()) { +// case "cot": +// case "cotinine": { +// sewageDataDto.setCotinineConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "codeine": { +// sewageDataDto.setCodeineConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "mda": { +// sewageDataDto.setMdaConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "mdma": { +// sewageDataDto.setMdmaConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "cocaine": { +// sewageDataDto.setCocaineConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "benzoylecgonine": { +// sewageDataDto.setBenzoylecgonineConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "morphine": { +// sewageDataDto.setMorphineConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "6-acetylmorphine": { +// sewageDataDto.setAcetylmorphineConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "methamphetamine": { +// sewageDataDto.setMethamphetamineConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "amphetamine": { +// sewageDataDto.setAmphetamineConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "ketamine": { +// sewageDataDto.setKetamineConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "norketamine": { +// sewageDataDto.setNorketamineConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "thc": { +// sewageDataDto.setThcConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "fentanyl": { +// sewageDataDto.setFenConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// case "etomidate": { +// sewageDataDto.setEtomidateConcentration(taskTestDataDTO.getSampleConcentration()); +// break; +// } +// } +// } + calculatedConsumption(sewageDataDto, dailySmokingPerCapita); + sewageDataDtos.add(sewageDataDto); + } + return sewageDataDtos; + } + + /** + * 把计算消费量的方法封装一下,此时sewageDataDto中已经保存了检验鉴定系统检出的化合物数据,此方法是用来计算消费量的 + * + * @param sewageDataDto + * @param dailySmokingPerCapita + */ + public void calculatedConsumption(SewageDataDto sewageDataDto, Double dailySmokingPerCapita) { + Double dailyFlow = sewageDataDto.getDailyFlow(); // 当前检材对应的日流 + sewageDataDto.setCotinineExcretion(dailySmokingPerCapita * 0.14 * 1000);//可替宁排泄量 + sewageDataDto.setEstimatedPopulation(sewageDataDto.getCotinineConcentration() * dailyFlow * 10 * sewageDataDto.getDomesticSewageProportion() / 100 / sewageDataDto.getCotinineExcretion());//测算人口 + + Double estimatedPopulation = sewageDataDto.getEstimatedPopulation(); // 当前检材对应的测算人口数量, 后面需要频繁使用到这个值,防止后面频繁调用get消耗时间这里提前存在一个变量里 + Double norketamineConcentration = sewageDataDto.getNorketamineConcentration(); // 去甲氯胺酮的浓度 + Double methamphetamineConcentration = sewageDataDto.getMethamphetamineConcentration(); // 甲基苯丙胺浓度 + Double morphineConcentration = sewageDataDto.getMorphineConcentration(); // 吗啡浓度 + Double amphetamineConcentration = sewageDataDto.getAmphetamineConcentration(); // 苯丙胺浓度 + Double ketamineConcentration = sewageDataDto.getKetamineConcentration(); // 氯胺酮浓度 + Double codeineConcentration = sewageDataDto.getCodeineConcentration(); // 可待因 浓度 + Double thcConcentration = sewageDataDto.getThcConcentration(); // 四氢大麻粉浓度 + Double mdmaConcentration = sewageDataDto.getMdmaConcentration(); // 摇头丸mdma浓度 + Double benzoylecgonineConcentration = sewageDataDto.getBenzoylecgonineConcentration(); // 苯甲酰爱康宁 浓度 + + sewageDataDto.setMorphineLoad(morphineConcentration == 0.0 ? 0 : morphineConcentration * dailyFlow * 10 / estimatedPopulation);//吗啡负荷量(mg/千人﹒天) + sewageDataDto.setCodeineLoad(codeineConcentration == 0.0 ? 0 : codeineConcentration * dailyFlow * 10 / estimatedPopulation);//可待因负荷量(mg/千人﹒天) + sewageDataDto.setCodeineIsConvertedToMorphineLoad(sewageDataDto.getCodeineLoad() * 0.065 / (0.3 * 1.05));//可待因转化为吗啡负荷量(mg/千人﹒天) + sewageDataDto.setMedicalMorphineLoad(1.0);//医用吗啡负荷量(mg/千人﹒天) + + if (amphetamineConcentration == 0.0) { + sewageDataDto.setMA_AM(0.0);//MA/AM + } else { + sewageDataDto.setMA_AM(methamphetamineConcentration / amphetamineConcentration);//MA/AM + } + if (norketamineConcentration == 0.0) { + sewageDataDto.setK_NK(0.0);//K/NK 除数为0了,我们直接把结果赋为0 + } else { + sewageDataDto.setK_NK(ketamineConcentration / norketamineConcentration);//K/NK + } + sewageDataDto.setPccHeroin((sewageDataDto.getMorphineLoad() - sewageDataDto.getCodeineIsConvertedToMorphineLoad() - sewageDataDto.getMedicalMorphineLoad()) * 3.07);//人均消耗量(mg/千人﹒天)Heroin + + if (amphetamineConcentration == 0.0 || (amphetamineConcentration != 0.0 && sewageDataDto.getMA_AM() <= 20)) { + sewageDataDto.setPccMa(methamphetamineConcentration == 0.0 ? 0 : methamphetamineConcentration * dailyFlow * 10 * 2.33 / estimatedPopulation);//人均消耗量(mg/千人﹒天)MA + } else { + sewageDataDto.setPccMa(amphetamineConcentration == 0.0 ? 0 : amphetamineConcentration * dailyFlow * 10 * 46.6 / estimatedPopulation);//人均消耗量(mg/千人﹒天)MA + } + if (norketamineConcentration == 0.0 || (norketamineConcentration != 0.0 && sewageDataDto.getK_NK() <= 6)) { + sewageDataDto.setPccK(ketamineConcentration == 0 ? 0 : ketamineConcentration * dailyFlow * 10 * 5 / estimatedPopulation);//人均消耗量(mg/千人﹒天)K + } else { + sewageDataDto.setPccK(norketamineConcentration == 0 ? 0 : norketamineConcentration * dailyFlow * 10 * 26.6 / estimatedPopulation);//人均消耗量(mg/千人﹒天)K + } + sewageDataDto.setPccFen(0d); + sewageDataDto.setTcFen(0d); + + sewageDataDto.setPccK(ketamineConcentration == 0.0 ? 0 : ketamineConcentration * dailyFlow * 10 * 5 / estimatedPopulation);//人均消耗量(mg/千人﹒天)K + sewageDataDto.setPccMdma(mdmaConcentration == 0.0 ? 0 : mdmaConcentration * dailyFlow * 10 * 4.44 / estimatedPopulation);//人均消耗量(mg/千人﹒天)MDMA + sewageDataDto.setPccCoc(benzoylecgonineConcentration == 0.0 ? 0 : benzoylecgonineConcentration * dailyFlow * 10 * 2.33 / estimatedPopulation);//人均消耗量(mg/千人﹒天)COC + sewageDataDto.setPccThc(thcConcentration == 0.0 ? 0 : thcConcentration * dailyFlow * 10 * 152 / estimatedPopulation);//人均消耗量(mg/千人﹒天)THC + // 在这里对计算结果为非数值的数据,防止对后续的使用造成影响 + processNaNAndInfinityData(sewageDataDto); + sewageDataDto.setTcHeroin(sewageDataDto.getPccHeroin() * estimatedPopulation);//总消耗量Heroin + sewageDataDto.setTcMa(sewageDataDto.getPccMa() * estimatedPopulation);//总消耗量MA + sewageDataDto.setTcK(sewageDataDto.getPccK() * estimatedPopulation);//总消耗量K + sewageDataDto.setTcMdma(sewageDataDto.getPccMdma() * estimatedPopulation);//总消耗量MDMA + sewageDataDto.setTcCoc(sewageDataDto.getPccCoc() * estimatedPopulation);//总消耗量COC + sewageDataDto.setTcThc(sewageDataDto.getPccThc() * estimatedPopulation);//总消耗量THC + } + + /** + * 在这里对计算结果为非数值的数据,防止对后续的使用造成影响 Double.isFinite() 这个的方法作用是判断当前数字是不是在规定的有限数值范围内,是返回true, 不是返回false + * + * @param sewageDataDto + */ + private void processNaNAndInfinityData(SewageDataDto sewageDataDto) { + if (!Double.isFinite(sewageDataDto.getPccCoc()) || sewageDataDto.getPccCoc() < 0d) { + sewageDataDto.setPccCoc(0d); + } + if (!Double.isFinite(sewageDataDto.getPccHeroin()) || sewageDataDto.getPccHeroin() < 0d) { + sewageDataDto.setPccHeroin(0d); + } + if (!Double.isFinite(sewageDataDto.getPccK()) || sewageDataDto.getPccK() < 0d) { + sewageDataDto.setPccK(0d); + } + if (!Double.isFinite(sewageDataDto.getPccMdma()) || sewageDataDto.getPccMdma() < 0d) { + sewageDataDto.setPccMdma(0d); + } + if (!Double.isFinite(sewageDataDto.getPccCoc()) || sewageDataDto.getPccCoc() < 0d) { + sewageDataDto.setPccMa(0d); + } + if (!Double.isFinite(sewageDataDto.getPccThc()) || sewageDataDto.getPccThc() < 0d) { + sewageDataDto.setPccThc(0d); + } + if (!Double.isFinite(sewageDataDto.getPccFen()) || sewageDataDto.getPccFen() < 0d) { + sewageDataDto.setPccFen(0d); + } + } + + @Override + public String createSewageReportExcel(List sewageDataDtos, String id) throws IOException { + String temporarilyPath = "C:\\tmp\\upload\\";//用来临时存储生成的文件,用于OSS上传,待OSS上传成功后将这个路径下的文件删除 + HSSFWorkbook workbook = new HSSFWorkbook(); + HSSFCellStyle redCellStyle = workbook.createCellStyle();//表头样式 + HSSFCellStyle cellStyle = workbook.createCellStyle();//表格样式 + HSSFCellStyle redBackdropStyle = workbook.createCellStyle();//红色背景样式 + HSSFCellStyle pinkBackgroundStyle = workbook.createCellStyle();//粉色背景样式 + + HSSFFont redBackdropFont = workbook.createFont(); + HSSFFont font = workbook.createFont(); + HSSFFont redFont = workbook.createFont(); + + redFont.setFontHeightInPoints((short) 9); + redFont.setFontName("黑体"); + redFont.setColor(IndexedColors.RED.getIndex()); + redBackdropFont.setFontHeightInPoints((short) 9); + redBackdropFont.setFontName("黑体"); + redBackdropFont.setColor(IndexedColors.MAROON.getIndex()); + font.setFontName("黑体"); + font.setFontHeightInPoints((short) 9); + //红色背景填充 + redBackdropStyle.setFillForegroundColor(IndexedColors.CORAL.getIndex());//填充颜色 + redBackdropStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);//填充类型 + redBackdropStyle.setAlignment(HorizontalAlignment.CENTER);//水平居中 + redBackdropStyle.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中 + //粉色背景填充 + pinkBackgroundStyle.setFillForegroundColor(IndexedColors.TAN.getIndex()); + pinkBackgroundStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + pinkBackgroundStyle.setAlignment(HorizontalAlignment.CENTER); + pinkBackgroundStyle.setVerticalAlignment(VerticalAlignment.CENTER); + + redCellStyle.setAlignment(HorizontalAlignment.CENTER); + redCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + + cellStyle.setAlignment(HorizontalAlignment.CENTER); + cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + + cellStyle.setFont(font); + redCellStyle.setFont(redFont); + redBackdropStyle.setFont(redBackdropFont); + pinkBackgroundStyle.setFont(font); + + + Map> map = sewageDataDtos.stream().collect(Collectors.groupingBy(item -> item.getCityName()));//按市名称进行分组 + Set cityNameList = map.keySet(); + + //组装每个市检材的数据 + for (String cityName : cityNameList) { + List sewageDataDtoList = map.get(cityName); + Collections.sort(sewageDataDtoList, new Comparator() { + @Override + public int compare(SewageDataDto o1, SewageDataDto o2) { + return o1.getImNo().compareTo(o2.getImNo()); + } + }); + //工作表名称 + HSSFSheet sheet = workbook.createSheet(sewageDataDtoList.get(0).getJobYear() + "-" + sewageDataDtoList.get(0).getJobSeason() + "-" + cityName.substring(0, cityName.length() - 1)); + for (int i = 0; i < 49; i++) { + sheet.setColumnWidth(i, 5000); + } + //给特殊的单元格设置长一点的宽度 + sheet.setColumnWidth(1, 10000); + sheet.setColumnWidth(10, 5800); + sheet.setColumnWidth(26, 5500); + sheet.setColumnWidth(27, 5800); + sheet.setColumnWidth(28, 6500); + sheet.setColumnWidth(29, 6500); + sheet.setColumnWidth(33, 5500); + sheet.setColumnWidth(50, 3500); + + //获得表头数据 + List columns = Arrays.asList(SewageReportColumn.values()); + + //开始构建表头 + HSSFRow row0 = sheet.createRow(0);//创建第一行 + row0.setHeight((short) 1200); + for (int i = 0; i < columns.size(); i++) { + HSSFCell cell = row0.createCell(i); + //有些列字体颜色会有变化,且会有背景填充,这边将逻辑写在枚举类中,用于传入单独的style样式 + SewageReportColumn sewageReportColumn = columns.get(i); + if (sewageReportColumn.getBackgroundColor().equals("red")) { + cell.setCellStyle(redBackdropStyle); + } else if (sewageReportColumn.getBackgroundColor().equals("pink")) { + cell.setCellStyle(pinkBackgroundStyle); + } else if (sewageReportColumn.getFontColor().equals("red") && sewageReportColumn.getBackgroundColor().equals("")) { + cell.setCellStyle(redCellStyle); + } else { + cell.setCellStyle(cellStyle); + } + cell.setCellValue(sewageReportColumn.getColumnName()); + } + //总消耗量与总测算人口 + double sumEstimatedPopulation = 0; + double sumHeroin = 0; + double sumMa = 0; + double sumK = 0; + double sumMDMA = 0; + double sumCoc = 0; + double sumThc = 0; + + for (int i = 0; i < sewageDataDtoList.size() + 1; i++) { + //构建最后两行中的消费量总量和人均量消费量数据 + if (i == sewageDataDtoList.size()) { + HSSFRow lastTwoRow = sheet.createRow(i + 1); + HSSFRow lastOneRow = sheet.createRow(i + 2); + lastTwoRow.setHeight((short) 300); + lastOneRow.setHeight((short) 300); + + HSSFCell lastTwoRowCell42 = lastTwoRow.createCell(42); + lastTwoRowCell42.setCellValue("总和"); + lastTwoRowCell42.setCellStyle(cellStyle); + + HSSFCell twoRowCell11 = lastTwoRow.createCell(11); + twoRowCell11.setCellValue(String.format("%.2f", sumEstimatedPopulation)); + twoRowCell11.setCellStyle(cellStyle); + + HSSFCell lastRowCell = lastOneRow.createCell(42); + lastRowCell.setCellValue("人均消耗量"); + lastRowCell.setCellStyle(pinkBackgroundStyle); + + HSSFCell lastRowCell50 = lastOneRow.createCell(50); + lastRowCell50.setCellValue("人均总消耗量"); + lastRowCell50.setCellStyle(pinkBackgroundStyle); + + HSSFCell lastTwoRowCell43 = lastTwoRow.createCell(43); + lastTwoRowCell43.setCellValue(String.format("%.1f", sumHeroin)); + lastTwoRowCell43.setCellStyle(cellStyle); + + HSSFCell lastTwoRowCell44 = lastTwoRow.createCell(44); + lastTwoRowCell44.setCellValue(String.format("%.1f", sumMa)); + lastTwoRowCell44.setCellStyle(cellStyle); + + HSSFCell lastTwoRowCell45 = lastTwoRow.createCell(45); + lastTwoRowCell45.setCellValue(String.format("%.1f", sumK)); + lastTwoRowCell45.setCellStyle(cellStyle); + + HSSFCell lastTwoRowCell46 = lastTwoRow.createCell(46); + lastTwoRowCell46.setCellValue(String.format("%.1f", sumMDMA)); + lastTwoRowCell46.setCellStyle(cellStyle); + + HSSFCell lastTwoRowCell47 = lastTwoRow.createCell(47); + lastTwoRowCell47.setCellValue(String.format("%.1f", sumCoc)); + lastTwoRowCell47.setCellStyle(cellStyle); + + HSSFCell lastTwoRowCell48 = lastTwoRow.createCell(48); + lastTwoRowCell48.setCellValue(String.format("%.1f", sumThc)); + lastTwoRowCell48.setCellStyle(cellStyle); + + HSSFCell lastOneRowCell43 = lastOneRow.createCell(43); + lastOneRowCell43.setCellValue(String.format("%.1f", (sumHeroin / sumEstimatedPopulation))); + lastOneRowCell43.setCellStyle(cellStyle); + + HSSFCell lastOneRowCell44 = lastOneRow.createCell(44); + lastOneRowCell44.setCellValue(String.format("%.1f", (sumMa / sumEstimatedPopulation))); + lastOneRowCell44.setCellStyle(cellStyle); + + HSSFCell lastOneRowCell45 = lastOneRow.createCell(45); + lastOneRowCell45.setCellValue(String.format("%.1f", (sumK / sumEstimatedPopulation))); + lastOneRowCell45.setCellStyle(cellStyle); + + HSSFCell lastOneRowCell46 = lastOneRow.createCell(46); + lastOneRowCell46.setCellValue(String.format("%.1f", (sumMDMA / sumEstimatedPopulation))); + lastOneRowCell46.setCellStyle(cellStyle); + + HSSFCell lastOneRowCell47 = lastOneRow.createCell(47); + lastOneRowCell47.setCellValue(String.format("%.1f", (sumCoc / sumEstimatedPopulation))); + lastOneRowCell47.setCellStyle(cellStyle); + + HSSFCell lastOneRowCell48 = lastOneRow.createCell(48); + lastOneRowCell48.setCellValue(String.format("%.1f", (sumThc / sumEstimatedPopulation))); + lastOneRowCell48.setCellStyle(cellStyle); + + HSSFCell lastOneRowCell51 = lastOneRow.createCell(51); + lastOneRowCell51.setCellValue(String.format("%.2f", sumHeroin / sumEstimatedPopulation + sumCoc / sumEstimatedPopulation + sumK / sumEstimatedPopulation * 0.1 + sumMa / sumEstimatedPopulation + sumMDMA / sumEstimatedPopulation * 0.5 + sumThc / sumEstimatedPopulation)); + lastOneRowCell51.setCellStyle(cellStyle); + break; + } + + //构建检材数据 + SewageDataDto sewageDataDto = sewageDataDtoList.get(i); + HSSFRow rowi = sheet.createRow(i + 1); + rowi.setHeight((short) 300); + + HSSFCell celli0 = rowi.createCell(0); + celli0.setCellValue(sewageDataDto.getImNo()); + celli0.setCellStyle(cellStyle); + + HSSFCell celli1 = rowi.createCell(1); + celli1.setCellValue(sewageDataDto.getSampleName()); + celli1.setCellStyle(cellStyle); + + HSSFCell celli2 = rowi.createCell(2); + celli2.setCellValue(sewageDataDto.getProvinceName()); + celli2.setCellStyle(cellStyle); + + HSSFCell celli3 = rowi.createCell(3); + celli3.setCellValue(sewageDataDto.getCityName()); + celli3.setCellStyle(cellStyle); + + HSSFCell celli4 = rowi.createCell(4); + celli4.setCellValue(sewageDataDto.getDistrictName()); + celli4.setCellStyle(cellStyle); + + HSSFCell celli5 = rowi.createCell(5); + celli5.setCellValue(LocalDateTimeUtil.format(sewageDataDto.getCollectTime(), "yyyy/MM/dd")); + celli5.setCellStyle(cellStyle); + + HSSFCell celli6 = rowi.createCell(6); + celli6.setCellValue(sewageDataDto.getServicePopulation()); + celli6.setCellStyle(cellStyle); + + HSSFCell celli7 = rowi.createCell(7); + celli7.setCellValue(sewageDataDto.getDomesticSewageProportion() + "%"); + celli7.setCellStyle(cellStyle); + + HSSFCell celli8 = rowi.createCell(8); + celli8.setCellValue(sewageDataDto.getDailyFlow()); + celli8.setCellStyle(cellStyle); + + HSSFCell celli9 = rowi.createCell(9); + celli9.setCellValue(sewageDataDto.getDailySmokingPerCapita()); + celli9.setCellStyle(cellStyle); + + HSSFCell celli10 = rowi.createCell(10); + celli10.setCellValue(sewageDataDto.getCotinineExcretion()); + celli10.setCellStyle(cellStyle); + + HSSFCell celli11 = rowi.createCell(11); + celli11.setCellValue(String.format("%.2f", sewageDataDto.getEstimatedPopulation())); + celli11.setCellStyle(cellStyle); + sumEstimatedPopulation += sewageDataDto.getEstimatedPopulation(); + + HSSFCell celli12 = rowi.createCell(12); + celli12.setCellStyle(cellStyle); + celli12.setCellValue(String.format("%.1f", sewageDataDto.getCotinineConcentration())); + + HSSFCell celli13 = rowi.createCell(13); + celli13.setCellStyle(cellStyle); + celli13.setCellValue(sewageDataDto.getCodeineConcentration()); + + HSSFCell celli14 = rowi.createCell(14); + celli14.setCellStyle(cellStyle); + celli14.setCellValue(String.format("%.1f", sewageDataDto.getMdaConcentration())); + + HSSFCell celli15 = rowi.createCell(15); + celli15.setCellStyle(cellStyle); + celli15.setCellValue(String.format("%.1f", sewageDataDto.getMdmaConcentration())); + + HSSFCell celli16 = rowi.createCell(16); + celli16.setCellStyle(cellStyle); + celli16.setCellValue(String.format("%.1f", sewageDataDto.getCocaineConcentration())); + + HSSFCell celli17 = rowi.createCell(17); + celli17.setCellStyle(cellStyle); + celli17.setCellValue(String.format("%.1f", sewageDataDto.getBenzoylecgonineConcentration())); + + HSSFCell celli18 = rowi.createCell(18); + celli18.setCellStyle(cellStyle); + celli18.setCellValue(String.format("%.1f", sewageDataDto.getMorphineConcentration())); + + HSSFCell celli19 = rowi.createCell(19); + celli19.setCellStyle(cellStyle); + celli19.setCellValue(String.format("%.1f", sewageDataDto.getAcetylmorphineConcentration())); + + HSSFCell celli20 = rowi.createCell(20); + celli20.setCellStyle(cellStyle); + celli20.setCellValue(String.format("%.1f", sewageDataDto.getMethamphetamineConcentration())); + + HSSFCell celli21 = rowi.createCell(21); + celli21.setCellStyle(cellStyle); + celli21.setCellValue(String.format("%.1f", sewageDataDto.getAmphetamineConcentration())); + + HSSFCell celli22 = rowi.createCell(22); + celli22.setCellStyle(cellStyle); + celli22.setCellValue(String.format("%.1f", sewageDataDto.getKetamineConcentration())); + + HSSFCell celli23 = rowi.createCell(23); + celli23.setCellStyle(cellStyle); + celli23.setCellValue(String.format("%.1f", sewageDataDto.getNorketamineConcentration())); + + HSSFCell celli24 = rowi.createCell(24); + celli24.setCellStyle(cellStyle); + celli24.setCellValue(String.format("%.1f", sewageDataDto.getThcConcentration())); + + HSSFCell celli25 = rowi.createCell(25); + celli25.setCellStyle(cellStyle); + celli25.setCellValue(""); + + + HSSFCell celli26 = rowi.createCell(26); + celli26.setCellStyle(cellStyle); + celli26.setCellValue(String.format("%.1f", sewageDataDto.getMorphineLoad())); + + HSSFCell celli27 = rowi.createCell(27); + celli27.setCellStyle(cellStyle); + celli27.setCellValue(String.format("%.1f", sewageDataDto.getCodeineLoad())); + + HSSFCell celli28 = rowi.createCell(28); + celli28.setCellStyle(cellStyle); + celli28.setCellValue(String.format("%.1f", sewageDataDto.getCodeineIsConvertedToMorphineLoad())); + + HSSFCell celli29 = rowi.createCell(29); + celli29.setCellValue(sewageDataDto.getMedicalMorphineLoad()); + celli29.setCellStyle(cellStyle); + + HSSFCell celli30 = rowi.createCell(30); + celli30.setCellStyle(cellStyle); + celli30.setCellValue(String.format("%.1f", sewageDataDto.getMA_AM())); + + HSSFCell celli31 = rowi.createCell(31); + celli31.setCellStyle(cellStyle); + celli31.setCellValue(String.format("%.1f", sewageDataDto.getK_NK())); + + HSSFCell celli32 = rowi.createCell(32); + celli32.setCellValue(""); + HSSFCell celli33 = rowi.createCell(33); + celli33.setCellValue(""); + + HSSFCell celli34 = rowi.createCell(34); + celli34.setCellStyle(cellStyle); + celli34.setCellValue(String.format("%.1f", sewageDataDto.getPccHeroin())); + + HSSFCell celli35 = rowi.createCell(35); + celli35.setCellStyle(pinkBackgroundStyle); + celli35.setCellValue(String.format("%.1f", sewageDataDto.getPccMa())); + + HSSFCell celli36 = rowi.createCell(36); + celli36.setCellStyle(cellStyle); + celli36.setCellValue(String.format("%.1f", sewageDataDto.getPccK())); + + HSSFCell celli37 = rowi.createCell(37); + celli37.setCellStyle(cellStyle); + celli37.setCellValue(String.format("%.1f", sewageDataDto.getPccMdma())); + + HSSFCell celli38 = rowi.createCell(38); + celli38.setCellStyle(cellStyle); + celli38.setCellValue(String.format("%.1f", sewageDataDto.getPccCoc())); + + HSSFCell celli39 = rowi.createCell(39); + celli39.setCellStyle(cellStyle); + celli39.setCellValue(String.format("%.1f", sewageDataDto.getPccThc())); + + HSSFCell celli40 = rowi.createCell(40); + celli40.setCellValue(""); + HSSFCell celli41 = rowi.createCell(41); + celli41.setCellValue(""); + HSSFCell celli42 = rowi.createCell(42); + celli42.setCellValue(""); + + HSSFCell celli43 = rowi.createCell(43); + celli43.setCellStyle(cellStyle); + celli43.setCellValue(String.format("%.1f", sewageDataDto.getTcHeroin())); + sumHeroin += sewageDataDto.getTcHeroin(); + + HSSFCell celli44 = rowi.createCell(44); + celli44.setCellStyle(cellStyle); + celli44.setCellValue(String.format("%.1f", sewageDataDto.getTcMa())); + sumMa += sewageDataDto.getTcMa(); + + HSSFCell celli45 = rowi.createCell(45); + celli45.setCellStyle(cellStyle); + celli45.setCellValue(String.format("%.1f", sewageDataDto.getTcK())); + sumK += sewageDataDto.getTcK(); + + HSSFCell celli46 = rowi.createCell(46); + celli46.setCellStyle(cellStyle); + celli46.setCellValue(String.format("%.1f", sewageDataDto.getTcMdma())); + sumMDMA += sewageDataDto.getTcMdma(); + + HSSFCell celli47 = rowi.createCell(47); + celli47.setCellStyle(cellStyle); + celli47.setCellValue(String.format("%.1f", sewageDataDto.getTcCoc())); + sumCoc += sewageDataDto.getTcCoc(); + + HSSFCell celli48 = rowi.createCell(48); + celli48.setCellStyle(cellStyle); + celli48.setCellValue(String.format("%.1f", sewageDataDto.getTcThc())); + sumThc += sewageDataDto.getTcThc(); + } + } + String fileName = sewageDataDtos.get(0).getJobYear() + "年" + sewageDataDtos.get(0).getJobSeason() + "月污水" + "消费量报表.xls"; + FileOutputStream fileOutputStream = new FileOutputStream(temporarilyPath + fileName); + workbook.write(fileOutputStream); + fileOutputStream.close(); + File file = new File(temporarilyPath, fileName); + FileItem fileItem = testRecordInstrumentConditionService.getMultipartFile(file, file.getName()); + MultipartFile multipartFile = new CommonsMultipartFile(fileItem); + String ossPath = "document/sewageReport/" + id; + boolean ret = ossFile.fileUpload(multipartFile, "document/sewageReport/" + id); + if (ret) { + Files.delete(Paths.get(temporarilyPath, fileName)); + } + workbook.close(); + return ossPath + "/" + fileName; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordInstrumentConditionServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordInstrumentConditionServiceImpl.java new file mode 100644 index 0000000..45836b9 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordInstrumentConditionServiceImpl.java @@ -0,0 +1,433 @@ +package digital.laboratory.platform.inspection.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.deepoove.poi.xwpf.NiceXWPFDocument; +import digital.laboratory.platform.common.oss.service.OssFile; +import digital.laboratory.platform.inspection.constant.TestRecordFileUrl; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TestRecordInstrumentCondition; +import digital.laboratory.platform.inspection.constant.TestRecordArgumentType; +import digital.laboratory.platform.inspection.mapper.TestRecordInstrumentConditionMapper; +import digital.laboratory.platform.inspection.mapper.TestRecordMapper; +import digital.laboratory.platform.inspection.mapper.TestTemplateMapper; +import digital.laboratory.platform.inspection.service.*; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import digital.laboratory.platform.inspection.vo.TestTemplateVo; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.poi.xwpf.usermodel.XWPFTable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.commons.CommonsMultipartFile; + +import javax.annotation.Resource; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +@Service +@SuppressWarnings("all") +public class TestRecordInstrumentConditionServiceImpl extends ServiceImpl implements TestRecordInstrumentConditionService { + + @Resource + private TestRecordService testRecordService; + @Resource + private TestRecordMapper testRecordMapper; + @Resource + private TestTemplateService testTemplateService; + @Resource + private TestTemplateMapper testTemplateMapper; + @Resource + private SampleInfoService sampleInfoService; + @Resource + private OssFile ossFile; + @Resource + private EntrustInfoService entrustInfoService; + private final String fileName = "仪器条件.docx"; + + /** + * 新增实验仪器条件 + * + * @param testRecordInstrumentCondition + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public TestRecordInstrumentCondition addInstrumentCondition(TestRecordInstrumentCondition testRecordInstrumentCondition) { + testRecordInstrumentCondition.setId(IdWorker.get32UUID().toUpperCase()); + boolean ret = testRecordService.updateTestRecordArgument(testRecordInstrumentCondition.getTestId(), testRecordInstrumentCondition.getId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT_CONDITION.getType(), 1); + return this.save(testRecordInstrumentCondition) && ret ? testRecordInstrumentCondition : null; + } + + /** + * 删除仪器条件 + * + * @param id + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean delInstrumentCondition(String id) { + Integer opCode = -1;//表示从实验中删除 + TestRecordInstrumentCondition instrumentCondition = this.getById(id); + List testRecordList = testRecordMapper.getTestRecordMapList(new LambdaQueryWrapper()); + boolean ret = testRecordService.updateTestRecordArgument(instrumentCondition.getTestId(), instrumentCondition.getId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT_CONDITION.getType(), opCode); + return this.removeById(id) && ret; + } + + /** + * 向实验添加仪器条件 + * + * @param testRecordInstrumentCondition + * @return + */ + @Override + public TestRecordInstrumentCondition updateInstrumentCondition(TestRecordInstrumentCondition testRecordInstrumentCondition) { + return this.updateById(testRecordInstrumentCondition) ? testRecordInstrumentCondition : null; + } + + /** + * 通过实验ID获取这个实验的仪器条件 + * + * @param testId + * @return + */ + @Override + public TestRecordInstrumentCondition getInstrumentConditionByTestId(String testId) { + return baseMapper.getTestRecordInstrumentConditionVoMapByTestId(testId); + } + + /** + * 为模板添加或移除仪器条件 + * + * @param testRecordArgumentDto + * @return + */ + @Override + public boolean useInstrumentConditionToTemplate(TestRecordArgumentDto testRecordArgumentDto) { + return testTemplateService.updateTestTemplate(testRecordArgumentDto.getTemplateId(), testRecordArgumentDto.getArgumentId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT_CONDITION.getType(), testRecordArgumentDto.getOpCode()); + } + + /** + * 复制仪器条件 + * + * @param idList 仪器条件ID集合 + * @param testId + * @return + */ + @Override + public List copyCondition(List idList, String testId) { + ArrayList newIdList = new ArrayList<>(); + ArrayList instrumentConditions = new ArrayList<>(); + List list = this.list(new LambdaQueryWrapper().in(TestRecordInstrumentCondition::getId, idList)); + for (TestRecordInstrumentCondition testRecordInstrumentConditionVo : list) { + TestRecordInstrumentCondition newTestRecordInstrumentCondition = new TestRecordInstrumentCondition(); + newTestRecordInstrumentCondition.setConditionData(testRecordInstrumentConditionVo.getConditionData()); + newTestRecordInstrumentCondition.setBusinessFlag(testRecordInstrumentConditionVo.getBusinessFlag()); + newTestRecordInstrumentCondition.setTestId(testId); + newTestRecordInstrumentCondition.setId(IdWorker.get32UUID().toUpperCase()); + newIdList.add(newTestRecordInstrumentCondition.getId()); + instrumentConditions.add(newTestRecordInstrumentCondition); + } + this.saveBatch(instrumentConditions); + return newIdList; + } + + /** + * 判断这个实验是否生成了仪器条件 + * + * @param testId + * @return + */ + @Override + public String generatedOrNot(String testId) { + String path = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId; + List fileList = ossFile.fileList(path); + for (String name : fileList) { + if (name.equals(fileName)) { + return path + "/" + fileName; + } + } + return null; + } + + /** + * 为实验生成仪器条件模板 + * + * @param testId + * @param type 1:生物样本仪器条件 -1 :缴获物仪器条件 + * @return + * @throws Exception + */ + @Override + public boolean createConditionWordByTest(String testId) throws Exception { + TestRecordVo vo = testRecordMapper.getTestRecordMapById(testId); + String businessType = vo.getBusinessType(); + if (!StringUtils.isNotBlank(businessType)) { + throw new RuntimeException(String.format("当前还未选择样本,无法确定实验类型,请添加样本后再进行创建!")); + } + if (!businessType.startsWith("1")) { + throw new RuntimeException(String.format("任务或筛查无需创建仪器条件!")); + } + String url = ""; + if (businessType.equals("10002")) {//type = 1 代表是生物样本类型的仪器条件 + url = TestRecordFileUrl.TEST_RECORD_BIOLOGICAL_SAMPLE_INSTRUMENT_CONDITION_TEMPLATE.getFileUrl(); + } else { + url = TestRecordFileUrl.TEST_RECORD_SEIZURE_INSTRUMENT_CONDITION_TEMPLATE.getFileUrl(); + } + String filePath = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + fileName; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + ossFile.fileGet(url, bos); + byte[] templateArray = bos.toByteArray(); + ByteArrayInputStream bis = new ByteArrayInputStream(templateArray); + boolean ret = ossFile.fileSave(filePath, bis); + bos.close(); + bis.close(); + return ret; + } + + /** + * 为模板生成仪器条件模板 + * + * @param testId + * @param type 1:生物样本仪器条件 -1 :缴获物仪器条件 + * @return + * @throws Exception + */ + @Override + public boolean createConditionWordByTemplate(String templateId) throws Exception { + String url = ""; + TestTemplateVo vo = testTemplateMapper.getTestTemplateMapById(templateId); + if (vo.getBusinessType().equals("10002")) {//代表是生物样本类型的仪器条件 + url = TestRecordFileUrl.TEST_RECORD_BIOLOGICAL_SAMPLE_INSTRUMENT_CONDITION_TEMPLATE.getFileUrl(); + } else { + url = TestRecordFileUrl.TEST_RECORD_SEIZURE_INSTRUMENT_CONDITION_TEMPLATE.getFileUrl(); + } + String filePath = TestRecordFileUrl.TEST_TEMPLATE_CATALOGUE.getFileUrl() + "/" + templateId + "/" + fileName; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + ossFile.fileGet(url, bos); + byte[] templateArray = bos.toByteArray(); + ByteArrayInputStream bis = new ByteArrayInputStream(templateArray); + boolean ret = ossFile.fileSave(filePath, bis); + //创建好后将仪器条件类型存储在实验里面 + bos.close(); + bis.close(); + return ret; + } + +// /** +// * 判断是否能够选择这个类型的仪器条件模板 +// * +// * @param testId +// * @param type : 1:生物样本仪器条件 -1 :缴获物仪器条件 +// */ +// public void comparisonTypeForTest(String testId, Integer type) { +// TestRecordVo vo = testRecordMapper.getTestRecordMapById(testId); +// String businessType = vo.getBusinessType(); +// if (StringUtils.isNotBlank(businessType)) { +// if (!businessType.startsWith("1")) { +// throw new RuntimeException(String.format("任务或筛查无需创建仪器条件!!!")); +// } +// if (businessType.equals("10001") && type != -1) { +// throw new RuntimeException(String.format("当前选择的仪器条件模板类别与实验类型不匹配!!!")); +// } +// if (businessType.equals("10002") && type != 1) { +// throw new RuntimeException(String.format("当前选择的仪器条件模板类别与实验类型不匹配!!!")); +// } +// } +// } + + /** + * 获取实验仪器条件的类别 + * + * @param testId + * @return + */ + public Integer getConditionFileType(String testId) { + TestRecordVo vo = testRecordMapper.getTestRecordMapById(testId); + List deviceUseCondition = vo.getDeviceUseCondition(); + if (deviceUseCondition != null && deviceUseCondition.size() > 0) { + return Integer.parseInt(deviceUseCondition.get(0)); + + } + return null; + } + /** + * 为模板创建仪器条件word + * + * @param templateId + * @param testId + * @throws Exception + */ + @Override + public void copyConditionWord(String templateId, String testId) throws Exception { + // TODO:要先判断是否已经存在仪器条件模板 + List fileNameList = ossFile.fileList(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId); + boolean ret = fileNameList.contains(fileName); + if (ret) { + String filePath = TestRecordFileUrl.TEST_TEMPLATE_CATALOGUE.getFileUrl() + "/" + templateId + "/" + fileName; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ossFile.fileGet(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + fileName, bos); + byte[] templateArray = bos.toByteArray(); + ByteArrayInputStream bis = new ByteArrayInputStream(templateArray); + ossFile.fileSave(filePath, bis); + bos.close(); + bis.close(); + } + } + + /** + * 将仪器条件内容合并至检验记录中 + * + * @param testId + * @throws Exception + */ + @Override + public boolean mergeFile(String testId) throws Exception { + String businessType = testRecordMapper.getTestRecordMapById(testId).getBusinessType(); + if (StringUtils.isNotBlank(businessType) && businessType.equals("10002")) { + return this.mergeBiologicalSampleFile(testId); + } else if (StringUtils.isNotBlank(businessType) && businessType.equals("10001")) { + return this.mergeSeizureFile(testId); + } + return false; + } + + /** + * 合并生物样本仪器条件与检验记录 + * + * @param testId + * @throws Exception + */ + public boolean mergeBiologicalSampleFile(String testId) throws Exception { + String filePath = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + fileName;//生物样本仪器条件 + ByteArrayOutputStream bos1 = new ByteArrayOutputStream(); + ossFile.fileGet(filePath, bos1); + byte[] templateArray1 = bos1.toByteArray(); + ByteArrayInputStream bis1 = new ByteArrayInputStream(templateArray1); + NiceXWPFDocument sourceDoc = new NiceXWPFDocument(bis1); + bos1.write(bis1); + + //获取仪器条件表格 + XWPFTable table = sourceDoc.getTables().get(0); + + String templatePath = TestRecordFileUrl.TEST_RECORD_BIOLOGICAL_SAMPLE_TEMPLATE.getFileUrl();//生物样本检验记录模板 + ByteArrayOutputStream bos2 = new ByteArrayOutputStream(); + ossFile.fileGet(templatePath, bos2); + byte[] templateArray2 = bos2.toByteArray(); + ByteArrayInputStream bis2 = new ByteArrayInputStream(templateArray2); + NiceXWPFDocument targetDoc = new NiceXWPFDocument(bis2); + + int insertPosition = 1;//替换到第2个段落的表格 + + //替换表格 + targetDoc.setTable(insertPosition, table); + +// //删除空白行 +// for (int i = targetDoc.getParagraphs().size() - 1; i >= 0; i--) { +// XWPFParagraph paragraph = targetDoc.getParagraphs().get(i); +// if (paragraph.getRuns().isEmpty() || paragraph.getText().trim().isEmpty()) { +// targetDoc.removeBodyElement(targetDoc.getPosOfParagraph(paragraph)); +// } +// } + String temporaryfileName = "生物样本检验记录.docx"; + String temporaryPath = TestRecordFileUrl.TEMPORARY_PATH.getFileUrl() + "/" + temporaryfileName;//临时存储 + FileOutputStream fileOutputStream = new FileOutputStream(temporaryPath); + targetDoc.write(fileOutputStream); + fileOutputStream.close(); + File file = new File(temporaryPath); + FileItem fileItem = this.getMultipartFile(file, file.getName()); + MultipartFile multipartFile = new CommonsMultipartFile(fileItem); + String ossPath = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId; + boolean ret = ossFile.fileUpload(multipartFile, ossPath); + if (ret) { + Files.delete(Paths.get(temporaryPath)); + } + return ret; + } + + /** + * 合并缴获物仪器条件与检验记录 + * + * @param testId + * @throws Exception + */ + public boolean mergeSeizureFile(String testId) throws Exception { + + String filePath = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + fileName;// + ByteArrayOutputStream bos1 = new ByteArrayOutputStream(); + ossFile.fileGet(filePath, bos1); + byte[] templateArray1 = bos1.toByteArray(); + ByteArrayInputStream bis1 = new ByteArrayInputStream(templateArray1); + NiceXWPFDocument sourceDoc = new NiceXWPFDocument(bis1); + bos1.write(bis1); + + //获取仪器条件表格 + XWPFTable table = sourceDoc.getTables().get(0); + + //todo:缴获物检验记录模板 + String templatePath = TestRecordFileUrl.TEST_RECORD_SEIZURE_TEMPLATE.getFileUrl(); + ByteArrayOutputStream bos2 = new ByteArrayOutputStream(); + ossFile.fileGet(templatePath, bos2); + byte[] templateArray2 = bos2.toByteArray(); + ByteArrayInputStream bis2 = new ByteArrayInputStream(templateArray2); + NiceXWPFDocument targetDoc = new NiceXWPFDocument(bis2); + + bis2.close(); + bos2.close(); + bis1.close(); + bos1.close(); + + int insertPosition = 5;//替换第五个表格之后的表格 + + //替换表格 + targetDoc.setTable(insertPosition, table); + + String temporaryfileName = "缴获物检验记录.docx"; + String temporaryPath = TestRecordFileUrl.TEMPORARY_PATH.getFileUrl() + temporaryfileName;//临时存储 + FileOutputStream fileOutputStream = new FileOutputStream(temporaryPath); + targetDoc.write(fileOutputStream); + fileOutputStream.close(); + File file = new File(temporaryPath); + FileItem fileItem = this.getMultipartFile(file, file.getName()); + FileInputStream fileInputStream = new FileInputStream(TestRecordFileUrl.TEMPORARY_PATH.getFileUrl() + temporaryfileName); + MultipartFile multipartFile = new CommonsMultipartFile(fileItem); + String ossPath = TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + temporaryfileName; + boolean ret = ossFile.fileSave(ossPath, fileInputStream); + if (ret) { + Files.delete(Paths.get(temporaryPath)); + } + return ret; + } + + //todo:一个文件类型转换的封装方法 + @Override + public FileItem getMultipartFile(File file, String fieldName) { + FileItemFactory factory = new DiskFileItemFactory(16, null); + FileItem item = factory.createItem(fieldName, "text/plain", true, file.getName()); + int bytesRead = 0; + byte[] buffer = new byte[8192]; + try { + FileInputStream fis = new FileInputStream(file); + OutputStream os = item.getOutputStream(); + while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) { + os.write(buffer, 0, bytesRead); + } + os.close(); + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return item; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordInstrumentServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordInstrumentServiceImpl.java new file mode 100644 index 0000000..be49d33 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordInstrumentServiceImpl.java @@ -0,0 +1,220 @@ +package digital.laboratory.platform.inspection.service.impl; +/* + *@title TestRecordInstrumentServiceImpl + *@description + *@author xy + *@version 1.0 + *@create 2023/12/19 14:51 + */ + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TestRecordInstrument; +import digital.laboratory.platform.inspection.constant.TestRecordArgumentType; +import digital.laboratory.platform.inspection.mapper.TestRecordInstrumentMapper; +import digital.laboratory.platform.inspection.mapper.TestRecordMapper; +import digital.laboratory.platform.inspection.mapper.TestTemplateMapper; +import digital.laboratory.platform.inspection.service.TestRecordInstrumentService; +import digital.laboratory.platform.inspection.service.TestRecordService; +import digital.laboratory.platform.inspection.service.TestTemplateService; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import digital.laboratory.platform.inspection.vo.TestTemplateVo; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Service +@Slf4j +public class TestRecordInstrumentServiceImpl extends ServiceImpl implements TestRecordInstrumentService { + + @Resource + private TestRecordService testRecordService; + + @Resource + private TestRecordMapper testRecordMapper; + + @Resource + private TestTemplateMapper testTemplateMapper; + + @Resource + private TestTemplateService testTemplateService; + + @Override + public TestRecordInstrument addTestRecordInstrument(TestRecordInstrument testRecordInstrument) { + if (StringUtils.isBlank(testRecordInstrument.getId())) { + testRecordInstrument.setId(IdWorker.get32UUID()); + log.info("保存对象testRecordInstrument的ID为空,由系统生成一个给它使用 {}", testRecordInstrument.getId()); + } + boolean ret = this.save(testRecordInstrument); + if (ret) { + log.info("{} 保存成功", testRecordInstrument); + return testRecordInstrument; + } else { + log.info("{} 保存失败", testRecordInstrument); + return null; + } + } + + @Override + public TestRecordInstrument updateTestRecordInstrument(TestRecordInstrument testRecordInstrument) { + if (testRecordInstrument.getSource() == 0) { + log.info("数据是其他系统推送录入的,不能修改"); + return null; + } + boolean ret = this.updateById(testRecordInstrument); + if (ret) { + return testRecordInstrument; + } else { + return null; + } + } + + /** + * 通过ID删除仪器设备 + * @param id + * @return + */ + @Override + public Boolean deleteTestRecordInstrument(String id) { + List testRecordMapList = testRecordMapper.getTestRecordMapList(new LambdaQueryWrapper()); + testRecordMapList.forEach(item -> { + if (item.getDeviceIdList() != null && item.getDeviceIdList().size() > 0 && item.getDeviceIdList().contains(id)) { + throw new RuntimeException(String.format("该设备已绑定编号为%s的实验,无法删除!", item.getTestSerialNumber())); + } + }); + List testTemplateMapList = testTemplateMapper.getTestTemplateMapList(new LambdaQueryWrapper()); + testTemplateMapList.forEach(item -> { + if (item.getDeviceIdList() != null && item.getDeviceIdList().size() > 0 && item.getDeviceIdList().contains(id)) { + throw new RuntimeException(String.format("该设备已绑定ID为%s的实验,无法删除!", item.getId())); + } + }); + return this.removeById(id); + } + + /** + * 分页查询 + * + * @param opCode 通过Opcode区分仪器条件列表 1:查询所有的仪器设备(这个实验绑定的除外) 2:查询这个实验下绑定的仪器设备 + * @param keywords 模糊查询参数 + */ + @Override + public IPage getTestRecordInstrumentPageList(Page page, String testId, String keywords, Integer opCode) { + TestRecordVo testRecordVo = testRecordMapper.getTestRecordMapById(testId); + List deviceIdList = testRecordVo.getDeviceIdList(); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.and(StringUtils.isNotBlank(keywords), qw -> qw + .like(TestRecordInstrument::getInstrumentNumber, keywords) + .or() + .like(TestRecordInstrument::getInstrumentProvider, keywords) + .or() + .like(TestRecordInstrument::getInstrumentName, keywords) + .or() + .like(TestRecordInstrument::getInstrumentTypeNo, keywords)); + if (opCode == 1) { + if (deviceIdList != null && deviceIdList.size() > 0) { + wrapper.notIn(TestRecordInstrument::getId, deviceIdList); + } + wrapper.orderByDesc(TestRecordInstrument::getCreateTime); + } else {//这是为了查询时不报错,加入了空字符串 + if (deviceIdList == null || deviceIdList.size() == 0) { + deviceIdList = new ArrayList(); + deviceIdList.add(""); + } + wrapper.in(TestRecordInstrument::getId, deviceIdList) + .orderByDesc(TestRecordInstrument::getUpdateTime); + } + return this.page(page, wrapper); + } + + /** + * 列表查询 + * + * @param opCode 通过Opcode区分仪器条件列表 1:查询所有的仪器设备(这个实验绑定的除外) 2:查询这个实验下绑定的仪器设备 + * @param keywords 模糊查询参数 + */ + @Override + public IPage getTemplateInstrumentPageList(Page page, String templateId, String keywords, Integer opCode) { + TestTemplateVo testTemplateVo = testTemplateMapper.getTestTemplateMapById(templateId); + List deviceIdList = testTemplateVo.getDeviceIdList(); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.and(StringUtils.isNotBlank(keywords), qw -> qw + .like(TestRecordInstrument::getInstrumentNumber, keywords) + .or() + .like(TestRecordInstrument::getInstrumentProvider, keywords) + .or() + .like(TestRecordInstrument::getInstrumentName, keywords) + .or() + .like(TestRecordInstrument::getInstrumentTypeNo, keywords)); + if (opCode == 1) { + if (deviceIdList != null && deviceIdList.size() > 0) { + wrapper.notIn(TestRecordInstrument::getId, deviceIdList); + } + wrapper.orderByDesc(TestRecordInstrument::getCreateTime); + } else {//这是为了查询时不报错,加入了空字符串 + if (deviceIdList == null || deviceIdList.size() == 0) { + deviceIdList = new ArrayList(); + deviceIdList.add(""); + } + wrapper.in(TestRecordInstrument::getId, deviceIdList) + .orderByDesc(TestRecordInstrument::getUpdateTime); + } + return this.page(page, wrapper); + } + + @Override + public List getTestRecordInstrumentList(TestRecordInstrument testRecordInstrument) { + List retList = this.list(Wrappers.lambdaQuery() + .like(StringUtils.isNotBlank(testRecordInstrument.getInstrumentName()), TestRecordInstrument::getInstrumentName, testRecordInstrument.getInstrumentName())); + return retList; + } + + @Override + public Boolean checkExist(String id) { + List retList = this.list(Wrappers.lambdaQuery() + .eq(TestRecordInstrument::getId, id)); + if (retList.size() > 0) { + return true; + } else { + return false; + } + } + + /** + * 添加或移除实验中的仪器设备 + * @param testRecordArgumentDto + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean useTestRecordInstrument(TestRecordArgumentDto testRecordArgumentDto) { + TestRecordInstrument testRecordInstrument = this.getById(testRecordArgumentDto.getArgumentId()); + testRecordInstrument.setUpdateTime(LocalDateTime.now());//这里修改是为了查询实验中已添加的列表可以按照添加顺序进行排序 + return this.updateById(testRecordInstrument) && testRecordService.updateTestRecordArgument(testRecordArgumentDto.getTestRecordId(), testRecordArgumentDto.getArgumentId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT.getType(), testRecordArgumentDto.getOpCode()); + } + + /** + * 添加或移除模板中的仪器设备 + * @param testRecordArgumentDto + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean useTemplateInstrument(TestRecordArgumentDto testRecordArgumentDto) { + TestRecordInstrument testRecordInstrument = this.getById(testRecordArgumentDto.getArgumentId()); + testRecordInstrument.setUpdateTime(LocalDateTime.now());//这里修改是为了查询实验中已添加的列表可以按照添加顺序进行排序 + boolean ret = testTemplateService.updateTestTemplate(testRecordArgumentDto.getTemplateId(), testRecordArgumentDto.getArgumentId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT.getType(), testRecordArgumentDto.getOpCode()); + return this.updateById(testRecordInstrument) && ret; + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordMethodServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordMethodServiceImpl.java new file mode 100644 index 0000000..2a36ad5 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordMethodServiceImpl.java @@ -0,0 +1,149 @@ +package digital.laboratory.platform.inspection.service.impl; +/* + *@title TestRecordMethodServiceImpl + *@description + *@author xy + *@version 1.0 + *@create 2023/12/19 14:51 + */ + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TestRecordMethod; +import digital.laboratory.platform.inspection.constant.TestRecordArgumentType; +import digital.laboratory.platform.inspection.mapper.TestRecordMapper; +import digital.laboratory.platform.inspection.mapper.TestRecordMethodMapper; +import digital.laboratory.platform.inspection.mapper.TestTemplateMapper; +import digital.laboratory.platform.inspection.service.TestRecordMethodService; +import digital.laboratory.platform.inspection.service.TestRecordService; +import digital.laboratory.platform.inspection.service.TestTemplateService; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import digital.laboratory.platform.inspection.vo.TestTemplateVo; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +@Service +@Slf4j +public class TestRecordMethodServiceImpl extends ServiceImpl implements TestRecordMethodService { + + @Resource + private TestRecordService testRecordService; + + @Resource + private TestRecordMapper testRecordMapper; + + @Resource + private TestTemplateMapper testTemplateMapper; + + @Resource + private TestTemplateService testTemplateService; + + @Override + public TestRecordMethod addTestRecordMethod(TestRecordMethod testRecordMethod) { + if (StringUtils.isBlank(testRecordMethod.getId())) { + testRecordMethod.setId(IdWorker.get32UUID()); + log.info("保存对象testRecordMethod的ID为空,由系统生成一个给它使用 {}", testRecordMethod.getId()); + } + boolean ret = this.save(testRecordMethod); + if (ret) { + log.info("{} 保存成功", testRecordMethod); + return testRecordMethod; + } else { + log.info("{} 保存失败", testRecordMethod); + return null; + } + } + + @Override + public TestRecordMethod updateTestRecordMethod(TestRecordMethod testRecordMethod) { + if (testRecordMethod.getSource() == 0) { + log.info("数据是其他系统推送录入的,不能修改"); + return null; + } + boolean ret = this.updateById(testRecordMethod); + if (ret) { + return testRecordMethod; + } else { + return null; + } + } + + /** + * 删除方法 + * @param id + * @return + */ + + @Override + public Boolean deleteTestRecordMethod(String id) { + List testRecordList = testRecordMapper.getTestRecordMapList(new LambdaQueryWrapper<>()); + testRecordList.forEach(item -> { + if (item.getTestMethodList() != null && item.getTestMethodList().size() > 0 && item.getTestMethodList().contains(id)) { + throw new RuntimeException(String.format("当前方法已绑定编号为%s的实验,无法删除!", item.getTestSerialNumber())); + } + }); + List testTemplateMapList = testTemplateMapper.getTestTemplateMapList(new LambdaQueryWrapper()); + testTemplateMapList.forEach(item -> { + if (item.getTestMethods() != null && item.getTestMethods().size() > 0 && item.getTestMethods().contains(id)) { + throw new RuntimeException(String.format("当前方法已绑定ID为%s的模板,无法删除!", item.getId())); + } + }); + this.list(Wrappers.lambdaQuery()); + return this.removeById(id); + } + + @Override + public IPage getTestRecordMethodPageList(Page page, TestRecordMethod testRecordMethod) { + IPage ret = this.pageMaps(page, Wrappers.lambdaQuery() + .like(StringUtils.isNotBlank(testRecordMethod.getMethodName()), TestRecordMethod::getMethodName, testRecordMethod.getMethodName())); + return ret; + } + + @Override + public List getTestRecordMethodList(TestRecordMethod testRecordMethod) { + List retList = this.list(Wrappers.lambdaQuery() + .like(StringUtils.isNotBlank(testRecordMethod.getMethodName()), TestRecordMethod::getMethodName, testRecordMethod.getMethodName()) + .orderByDesc(TestRecordMethod::getCreateTime)); + return retList; + } + + @Override + public Boolean checkExist(String id) { + List retList = this.list(Wrappers.lambdaQuery() + .eq(TestRecordMethod::getId, id)); + if (retList.size() > 0) { + return true; + } else { + return false; + } + } + + /** + * 向实验添加或移除方法 + * @param testRecordArgumentDto + * @return + */ + @Override + public boolean useTestRecordMethod(TestRecordArgumentDto testRecordArgumentDto) { + return testRecordService.updateTestRecordArgument(testRecordArgumentDto.getTestRecordId(), testRecordArgumentDto.getArgumentId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_METHOD.getType(), testRecordArgumentDto.getOpCode()); + } + + /** + * 向模板添加或移除方法 + * @param testRecordArgumentDto + * @return + */ + @Override + public boolean useTemplateMethod(TestRecordArgumentDto testRecordArgumentDto) { + return testTemplateService.updateTestTemplate(testRecordArgumentDto.getTemplateId(), testRecordArgumentDto.getArgumentId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_METHOD.getType(), testRecordArgumentDto.getOpCode()); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordReagentServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordReagentServiceImpl.java new file mode 100644 index 0000000..df22b8c --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordReagentServiceImpl.java @@ -0,0 +1,264 @@ +package digital.laboratory.platform.inspection.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto; +import digital.laboratory.platform.inspection.entity.TestRecordReagent; +import digital.laboratory.platform.inspection.constant.TestRecordArgumentType; +import digital.laboratory.platform.inspection.mapper.TestRecordMapper; +import digital.laboratory.platform.inspection.mapper.TestRecordReagentMapper; +import digital.laboratory.platform.inspection.mapper.TestTemplateMapper; +import digital.laboratory.platform.inspection.service.TestRecordReagentService; +import digital.laboratory.platform.inspection.service.TestRecordService; +import digital.laboratory.platform.inspection.service.TestTemplateService; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import digital.laboratory.platform.inspection.vo.TestTemplateVo; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title TestRecordReagentServiceImpl + * @description + * @create 2023/12/20 11:15 + */ +@Service +@Slf4j +public class TestRecordReagentServiceImpl extends ServiceImpl implements TestRecordReagentService { + + @Resource + private TestRecordService testRecordService; + @Resource + private TestRecordMapper testRecordMapper; + + @Resource + private TestTemplateService testTemplateService; + @Resource + private TestTemplateMapper testTemplateMapper; + + @Override + public TestRecordReagent addTestRecordReagent(TestRecordReagent testRecordReagent) { + if (StringUtils.isBlank(testRecordReagent.getId())) { + testRecordReagent.setId(IdWorker.get32UUID()); + log.info("保存对象testRecordReagent的ID为空,由系统生成一个给它使用 {}", testRecordReagent.getId()); + } + if (!testRecordReagent.getCategory().equals("试剂")){ + testRecordReagent.setPurityGrade("/"); + } + boolean ret = this.save(testRecordReagent); + if (ret) { + log.info("{} 保存成功", testRecordReagent); + return testRecordReagent; + } else { + log.info("{} 保存失败", testRecordReagent); + return null; + } + } + + @Override + public TestRecordReagent updateTestRecordReagent(TestRecordReagent testRecordReagent) { + if (testRecordReagent.getSource() == 0) { + log.info("数据是其他系统推送录入的,不能修改"); + return null; + } + boolean ret = this.updateById(testRecordReagent); + if (ret) { + return testRecordReagent; + } else { + return null; + } + } + + /** + * 删除试剂耗材 + * @param id + * @return + */ + @Override + public Boolean deleteTestRecordReagent(String id) { + TestRecordReagent recordReagent = this.getById(id); + List recordMapList = testRecordMapper.getTestRecordMapList(new LambdaQueryWrapper()); + List testTemplateMapList = testTemplateMapper.getTestTemplateMapList(new LambdaQueryWrapper()); + recordMapList.forEach(item -> { + if (item.getReagentConsumablesList() != null && item.getReagentConsumablesList().size() > 0 && item.getReagentConsumablesList().contains(recordReagent.getId())) { + throw new RuntimeException(String.format("该试剂耗材/标准物质已绑定编号为%s的实验,无法删除!", item.getTestSerialNumber())); + } + }); + testTemplateMapList.forEach(item -> { + if (item.getReagentConsumables() != null && item.getReagentConsumables().size() > 0 && item.getReagentConsumables().contains(recordReagent.getId())) { + throw new RuntimeException(String.format("该试剂耗材/标准物质已绑定ID为%s的模板,无法删除!", item.getId())); + } + }); + return this.removeById(id); + } + + /** + * 实验分页查询 + * @param page + * @param testId + * @param keywords 标准物质编号、名称查询参数 + * @param category 类别查询参数 + * @param opCode 1:查询所有的试剂耗材 -1:查询这个实验下的试剂耗材 + * @return + */ + @Override + public IPage getTestRecordReagentPageList(Page page, String testId, String keywords, String category, Integer opCode) { + ArrayList categoryList = new ArrayList<>(); + if (category.equals("试剂耗材")) { + categoryList.add("试剂"); + categoryList.add("耗材"); + } else { + categoryList.add("标准物质"); + categoryList.add("标准储备溶液"); + } + TestRecordVo testRecordVo = testRecordMapper.getTestRecordMapById(testId); + List reagentConsumablesList = testRecordVo.getReagentConsumablesList(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.and(StringUtils.isNotBlank(keywords), qw -> qw + .like(TestRecordReagent::getNumber, keywords) + .or() + .like(TestRecordReagent::getReagentConsumableName, keywords)) + .in(TestRecordReagent::getCategory, categoryList); + if (opCode == 1) { + queryWrapper.orderByDesc(TestRecordReagent::getCreateTime); + if (reagentConsumablesList != null && reagentConsumablesList.size() > 0) { + queryWrapper.notIn(TestRecordReagent::getId, reagentConsumablesList); + } + } else { + if (reagentConsumablesList == null || reagentConsumablesList.size() == 0) { + //下面两步是为了能使参数正常查询 + reagentConsumablesList = new ArrayList<>(); + reagentConsumablesList.add(""); + } + queryWrapper.in(TestRecordReagent::getId, reagentConsumablesList) + .orderByDesc(TestRecordReagent::getUpdateTime); + } + //给了实验ID,查询这个实验下的试剂耗材、标准物质 + return this.page(page, queryWrapper); + } + + /** + * 模板分页查询 + * @param page + * @param testId + * @param keywords 标准物质编号、名称查询参数 + * @param category 类别查询参数 + * @param opCode 1:查询所有的试剂耗材 -1:查询这个模板下的试剂耗材 + * @return + */ + @Override + public IPage getTestTemplateReagentPageList(Page page, String templateId, String keywords, String category, Integer opCode) { + ArrayList categoryList = new ArrayList<>(); + if (category.equals("试剂耗材")) { + categoryList.add("试剂"); + categoryList.add("耗材"); + } else { + categoryList.add("标准物质"); + categoryList.add("标准储备溶液"); + } + TestTemplateVo templateVo = testTemplateMapper.getTestTemplateMapById(templateId); + List reagentConsumablesList = templateVo.getReagentConsumables(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.and(StringUtils.isNotBlank(keywords), qw -> qw + .like(TestRecordReagent::getNumber, keywords) + .or() + .like(TestRecordReagent::getReagentConsumableName, keywords)) + .in(TestRecordReagent::getCategory, categoryList); + if (opCode == 1) {//查询所有的试剂耗材、标准物质(去重处理) + queryWrapper.orderByDesc(TestRecordReagent::getCreateTime); + if (reagentConsumablesList != null && reagentConsumablesList.size() > 0) { + queryWrapper.notIn(TestRecordReagent::getId, reagentConsumablesList); + } + } else {//查询这个模板中绑定的试剂耗材 + if (reagentConsumablesList == null || reagentConsumablesList.size() == 0) { + //下面两步是为了能使参数正常查询 + reagentConsumablesList = new ArrayList<>(); + reagentConsumablesList.add(""); + } + queryWrapper.in(TestRecordReagent::getId, reagentConsumablesList) + .orderByDesc(TestRecordReagent::getUpdateTime); + } + return this.page(page, queryWrapper); + } + + /** + * 实验列表查询 + * @param testId + * @param category 类别查询参数 + * @return + */ + @Override + public List getTestRecordReagentList(String testId, String category) { + ArrayList categoryList = new ArrayList<>(); + if (category.equals("试剂耗材")) { + categoryList.add("试剂"); + categoryList.add("耗材"); + } else { + categoryList.add("标准物质"); + categoryList.add("标准储备溶液"); + } + TestRecordVo testRecordVo = testRecordMapper.getTestRecordMapById(testId); + List reagentConsumablesList = testRecordVo.getReagentConsumablesList(); + if (reagentConsumablesList == null || reagentConsumablesList.size() == 0) { + //下面两步是为了能使参数正常查询 + reagentConsumablesList = new ArrayList<>(); + reagentConsumablesList.add(""); + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper + .in(TestRecordReagent::getCategory, categoryList).in(TestRecordReagent::getId, reagentConsumablesList) + .orderByDesc(TestRecordReagent::getUpdateTime); + //给了实验ID,查询这个实验下的试剂耗材、标准物质 + return this.list(queryWrapper); + } + + @Override + public Boolean checkExist(String id) { + List retList = this.list(Wrappers.lambdaQuery() + .eq(TestRecordReagent::getId, id)); + if (retList.size() > 0) { + return true; + } else { + return false; + } + } + + /** + * 向实验添加或移除试剂耗材 + * @param testRecordArgumentDto + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean useTestRecordReagent(TestRecordArgumentDto testRecordArgumentDto) { + TestRecordReagent testRecordReagent = this.getById(testRecordArgumentDto.getArgumentId()); + testRecordReagent.setUpdateTime(LocalDateTime.now()); + return this.updateById(testRecordReagent) && testRecordService.updateTestRecordArgument(testRecordArgumentDto.getTestRecordId(), testRecordArgumentDto.getArgumentId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_REAGENT.getType(), testRecordArgumentDto.getOpCode()); + } + + /** + * 向模板添加或移除试剂耗材 + * @param testRecordArgumentDto + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean useTestTemplateReagent(TestRecordArgumentDto testRecordArgumentDto) { + TestRecordReagent testRecordReagent = this.getById(testRecordArgumentDto.getArgumentId()); + testRecordReagent.setUpdateTime(LocalDateTime.now()); + boolean ret = testTemplateService.updateTestTemplate(testRecordArgumentDto.getTemplateId(), testRecordArgumentDto.getArgumentId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_REAGENT.getType(), testRecordArgumentDto.getOpCode()); + return this.updateById(testRecordReagent) && ret; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordSampleDataServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordSampleDataServiceImpl.java new file mode 100644 index 0000000..7dd80ce --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordSampleDataServiceImpl.java @@ -0,0 +1,1915 @@ +package digital.laboratory.platform.inspection.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import digital.laboratory.platform.common.core.constant.CommonConstants; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.comservice.entity.DlpDictData; +import digital.laboratory.platform.comservice.feign.RemoteDictDataService; +import digital.laboratory.platform.inspection.constant.*; +import digital.laboratory.platform.inspection.dto.*; +import digital.laboratory.platform.inspection.entity.*; +import digital.laboratory.platform.inspection.event.AuditDataExecutionEvent; +import digital.laboratory.platform.inspection.event.FinishTestExecutionEvent; +import digital.laboratory.platform.inspection.mapper.SampleInjectorMapper; +import digital.laboratory.platform.inspection.mapper.TestRecordSampleDataMapper; +import digital.laboratory.platform.inspection.service.*; +import digital.laboratory.platform.inspection.utils.datafile.hair.HairSewageCompoundData; +import digital.laboratory.platform.inspection.utils.datafile.nps.NPSDataFileStruct; +import digital.laboratory.platform.inspection.utils.datafile.nps.NPSTestDetailDataStruct; +import digital.laboratory.platform.inspection.vo.ESTBusinessInfoVO; +import digital.laboratory.platform.inspection.vo.ResultConcentrationVO; +import digital.laboratory.platform.inspection.vo.TestResultBusinessVO; +import digital.laboratory.platform.inspetion.api.entity.EntrustInfo; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import digital.laboratory.platform.inspetion.api.entity.TestRecord; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.interceptor.TransactionAspectSupport; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.text.DecimalFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * @author xy + * @version 1.0 + * @title TestRecordSampleDataServiceImpl + * @description 检验数据实现类 + * @create 2024/1/30 11:07 + */ +@Service +@Slf4j +public class TestRecordSampleDataServiceImpl extends ServiceImpl implements TestRecordSampleDataService { + @Resource + private TestRecordSampleSolutionService testRecordSampleSolutionService; + + @Resource + private TestRecordStandardSolutionService testRecordStandardSolutionService; + + @Resource + private SampleInfoService sampleInfoService; + + @Resource + private SampleInjectorMapper sampleInjectorMapper; + + @Resource + private TestRecordSampleDataMapper testRecordSampleDataMapper; + + @Resource + private TestRecordService testRecordService; + + @Resource + private EntrustInfoService entrustInfoService; + + @Resource + private TaskInfoService taskInfoService; + + @Resource + private ApplicationContext applicationContext; + + /** + * 校验实验状态是否完成,完成则提升不能修改数据 + * + * @param testId 实验id + */ + @Override + public void validateTestStatus(String testId) { + // 校验实验状态是否完成 + if (testRecordService + .count(Wrappers.lambdaQuery() + .eq(TestRecord::getId, testId) + .ge(TestRecord::getStatus, 5)) + > 0) { + // 大于0 说明该实验已经完成 + throw new RuntimeException("该实验已经完成,禁止修改原始数据!"); + } + } + + + @Override + public Boolean saveTestData(List testRecordSampleDataList) { + return super.saveBatch(testRecordSampleDataList); + } + + //获取检验记录中的样品信息数据 + @Override + public List getNPSSampleTestDataByTestId(String testId) { + List list = this.list(Wrappers.lambdaQuery().eq(TestRecordSampleData::getTestId, testId)); + List retList = new ArrayList<>(); + for (TestRecordSampleData testRecordSampleData : list) { +// NPSCaseTestDataDto npsCaseTestDataDto = testRecordSampleDataToPSCaseTestDataDto(testRecordSampleData); + NPSCaseTestDataDto npsCaseTestDataDto = testRecordSampleDataToPSCaseTestDataDto(testRecordSampleData, NPSCaseTestDataDto.class); + retList.add(npsCaseTestDataDto); + } + return retList; + } + + /** + * TestRecordSampleDataMapper + * 根据业务id获取检验数据 + * + * @param businessId 业务id + * @return + */ + @Override + public List getSampleTestDataByBusiness(String businessId) { + // 先根据业务id查询委托、筛查、任务表中有没有这个id + List estBusinessInfoVOS = testRecordSampleDataMapper.queryESTBusinessInfoList(Wrappers.query().eq("T.id", businessId)); + if (CollUtil.isEmpty(estBusinessInfoVOS)) { + return null; + } + // 根据业务id查询样品信息 + List sampleInfoIds = sampleInfoService.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, businessId)) + .stream().map(SampleInfo::getId).collect(Collectors.toList()); + TestRecord testRecord = null; + for (String sampleInfoId : sampleInfoIds) { + TestRecord testRecord1 = testRecordService.getOne(Wrappers.lambdaQuery().like(TestRecord::getSampleTestList, sampleInfoId)); + if (testRecord1 != null) { + testRecord = testRecord1; + break; + } + } + if (testRecord == null) { + throw new RuntimeException(String.format("没有查询到委托对应的试实验信息!")); + } + // 根据检材id 查询溶液编号 + Set testRecordSampleSolutionsNoList = testRecordSampleSolutionService.list(Wrappers.lambdaQuery() + .in(TestRecordSampleSolution::getMaterialId, sampleInfoIds)) + .stream() + .map(TestRecordSampleSolution::getSampleNo) + .collect(Collectors.toSet()); + + List testRecordSampleDataList = this.list(Wrappers.lambdaQuery() + .eq(TestRecordSampleData::getTestId, testRecord.getId()) + .last("ORDER BY SUBSTRING_INDEX(name, '-', -1) + 0")).stream().filter(item -> { +// int size = testRecordSampleSolutionsNoList.size(); + // 这里判断了如果不是检材也返回true,是检材的话判断是不是这个业务id下的检材,根据编号判断 + if (!item.getSampleType().equals(TestRecordSampleDataConstant.SAMPLE_TYPE_ANALYTE) || + (item.getSampleType().equals(TestRecordSampleDataConstant.SAMPLE_TYPE_ANALYTE) + && testRecordSampleSolutionsNoList.contains(item.getSampleNo()) + )) { + return true; + } else { + return false; + } + }).collect(Collectors.toList()); + ESTBusinessInfoVO estBusinessInfoVO = estBusinessInfoVOS.get(0); + // 封装的结果集 + List retList = new ArrayList<>(); + if (estBusinessInfoVO.getBusinessType().equals(BusinessType.BOINT_CASE.getBusinessType())) { + extractedSampleTestData(testRecordSampleDataList, retList, HairSewageDataDto.class); + } else if (estBusinessInfoVO.getBusinessType().equals(BusinessType.NPS_CASE.getBusinessType()) || estBusinessInfoVO.getBusinessType().equals(BusinessType.SCREENING_EVENT.getBusinessType())) { + extractedSampleTestData(testRecordSampleDataList, retList, NPSCaseTestDataDto.class); + } else { + extractedSampleTestData(testRecordSampleDataList, retList, HairSewageDataDto.class); + } +// List collect = TypeCasting(retList); + return typeCasting(retList); + } + + /** + * 毛发案件检验数据读取处理保存到数据库 + * + * @param hairCompoundDataMap + * @param testId + * @return + */ + @Override + public Boolean saveTestDataHairCase(Map> hairCompoundDataMap, String testId) { + try { + buildSampleDataFromHairCase(hairCompoundDataMap, testId);//构造实验数据 + testRecordService.update(Wrappers.lambdaUpdate().eq(TestRecord::getId, testId).set(TestRecord::getStatus, 2)); + return true; + } catch (Exception err) { + log.info("程序执行异常{}", err.getMessage()); + err.printStackTrace(); + return false; + } + } + + /** + * 根据实验id获取不同类型的数据 + * + * @param testId + * @param type + * @return + */ + @Override + public List getSampleTestDataByTestId(String testId, String type) { + List list = this.list(Wrappers.lambdaQuery() + .eq(TestRecordSampleData::getTestId, testId) + .last("ORDER BY SUBSTRING_INDEX(name, '-', -1) + 0")); + List retList = new ArrayList<>(); + switch (BusinessType.getBusinessTypeByType(type)) { + case SCREENING_EVENT: + case NPS_CASE: + // NPS的数据分析 + extractedSampleTestData(list, retList, NPSCaseTestDataDto.class); + break; + case BOINT_CASE: + extractedSampleTestData(list, retList, HairSewageDataDto.class); + break; + } + + // z最后转换类型 +// TypeCasting(retList); + return typeCasting(retList); + } + + /** + * 分页查询 根据实验id获取不同类型的数据 + * + * @param pageDTO + * @return + */ + @Override + public Page getSampleTestDataByTestIdPage(AnalysisTestResultPageDTO pageDTO) { + Page page = this.page(new Page<>(pageDTO.getCurrent(), pageDTO.getSize()), Wrappers.lambdaQuery() + .eq(TestRecordSampleData::getTestId, pageDTO.getTestId()) + .orderByDesc(TestRecordSampleData::getCompoundName) + .orderByDesc(TestRecordSampleData::getSampleNo)); + List retList = new ArrayList<>(); + switch (BusinessType.getBusinessTypeByType(pageDTO.getType())) { + case NPS_CASE: + // NPS的数据分析 + extractedSampleTestData(page.getRecords(), retList, NPSCaseTestDataDto.class); + case BOINT_CASE: + extractedSampleTestData(page.getRecords(), retList, HairSewageDataDto.class); + } + Page resultPage = new Page<>(); + BeanUtils.copyProperties(page, resultPage, "records"); + // z最后转换类型 +// TypeCasting(retList); + resultPage.setRecords(retList); + return resultPage; + } + + /** + * 分页查询 获取审核的任务检验数据 + * + * @param pageDTO + * @return + */ + @Override + public Map queryWaitApproveTaskTestDataPage(TaskTestDataPageDTO pageDTO) { + QueryWrapper queryWrapper = generateTaskTestDataQW(pageDTO); + // 获取所有的任务数据 + List taskTestDataDTOList = baseMapper.queryWaitApproveTaskTestDataList(queryWrapper); + + // 根据检材编号进行分组, 使用LinkedHashMap的原因是保证顺序不乱 + LinkedHashMap> dataGroupBySampleNoMap = taskTestDataDTOList + .stream() + .collect(Collectors.groupingBy(TaskTestDataDTO::getSampleNo, LinkedHashMap::new, Collectors.toList())); + + Map map = new HashMap<>(); + + JSONArray headerArray = generateHeaderArray(dataGroupBySampleNoMap); + JSONArray dataArray = generateDataArray(dataGroupBySampleNoMap); + /*// 标记表头是否添加完成 + AtomicReference finish = new AtomicReference<>(false); // 为了能在lambda中使用 + dataGroupBySampleNoMap.forEach((k, v) -> { + // 组装列表数据 + JSONObject dataObject = new JSONObject(); + dataObject.put("sampleNo", k); + int size = v.size(); // 防止频繁调用方法 + for (int i = 0; i < size; i++) { + TaskTestDataDTO taskTestDataDTO = v.get(i); + String compoundKey = "compound" + (i + 1); + if (!finish.get()) { + // 组装自定义列表头部 + JSONObject object = new JSONObject(); + if (i == 0) { + JSONObject sampleNoObject = new JSONObject(); + sampleNoObject.put(TestRecordSampleDataConstant.LABEL, "溶液编号"); + sampleNoObject.put(TestRecordSampleDataConstant.PROP, "sampleNo"); + sampleNoObject.put("fixed", true); + JSONObject name = new JSONObject(); + name.put(TestRecordSampleDataConstant.PROP, "taskName"); + name.put(TestRecordSampleDataConstant.LABEL, "案件/任务名称"); + JSONObject business = new JSONObject(); + business.put(TestRecordSampleDataConstant.PROP, "businessTypeName"); + business.put(TestRecordSampleDataConstant.LABEL, "业务类型"); + JSONObject status = new JSONObject(); + status.put(TestRecordSampleDataConstant.PROP, "statusName"); + status.put(TestRecordSampleDataConstant.LABEL, "状态"); + + headerArray.add(name); + headerArray.add(business); + headerArray.add(status); + headerArray.add(sampleNoObject); + } + object.put(TestRecordSampleDataConstant.PROP, compoundKey); + object.put(TestRecordSampleDataConstant.LABEL, "化合物" + (i + 1) + "(" + taskTestDataDTO.getCompoundName() + ")"); + headerArray.add(object); + } + // 把化合物组装导对象里 + dataObject.put("taskName", taskTestDataDTO.getTaskName()); + dataObject.put("businessTypeName", BusinessType.getBusinessTypeName(taskTestDataDTO.getBusinessType())); + dataObject.put("status", taskTestDataDTO.getStatus()); + dataObject.put("statusName", TaskTestDataStatus.getStatusNameByCode(taskTestDataDTO.getStatus())); + dataObject.put(compoundKey, taskTestDataDTO.getSampleConcentration()); + if (i == size - 1) { + finish.set(true); + } + } + dataArray.add(dataObject); + }); +*/ + // 手动分页 + map.put("header", headerArray); + map.put("page", getPageData(dataArray, pageDTO.getCurrent(), pageDTO.getSize())); + return map; + } + + + /** + * 毛发、污水任务检验数据导入并保存到数据库 + * + * @param hairSewageCompoundDataMap + * @param testId + * @param fileTypeCode + * @return + */ + @Override + public Boolean saveTestDataHairSewageTask(Map> hairSewageCompoundDataMap, String testId, String fileTypeCode) { + List testRecordSampleDataList_All = new Vector<>(); + + hairSewageCompoundDataMap.forEach((k, v) -> { + v.parallelStream().forEach(hairsSewageCompoundData -> { + String idName = hairsSewageCompoundData.getIdName(); + HairSewageDataDto hairSewageDataDto = new HairSewageDataDto(); + hairSewageDataDto.setSampleNo(idName); // 样本编号 + hairSewageDataDto.setSampleName(hairsSewageCompoundData.getSampleName()); // 样本名称 + hairSewageDataDto.setTestId(testId); // 实验id + hairSewageDataDto.setBusinessType(fileTypeCode); + // 设置对应的元素数据 + hairSewageDataDto.setTestSampleDataList(Lists.newArrayList(hairsSewageCompoundData)); + hairSewageDataDto.setCompoundName(k); // 化合物名称 + completeHairDataInfo(hairsSewageCompoundData, hairSewageDataDto); + hairSewageDataDto.setTargetConcentration(hairsSewageCompoundData.getConcentration()); + if (hairsSewageCompoundData.getRatioFlag().equals("NO")) { + hairSewageDataDto.setIsDetected(1); + } else { + hairSewageDataDto.setIsDetected(0); + } + if (idName.startsWith(StdSolutionNum.QC_SOLUTION.getPrefix())) { + hairSewageDataDto.setSampleType(TestRecordSampleDataConstant.SAMPLE_TYPE_QC); + } else if (idName.startsWith(StdSolutionNum.MIXED_SOLUTION.getPrefix()) || idName.startsWith(StdSolutionNum.SIMPLE_SOLUTION.getPrefix())) { + hairSewageDataDto.setSampleType(TestRecordSampleDataConstant.SAMPLE_TYPE_STD); + } else { + hairSewageDataDto.setSampleType(TestRecordSampleDataConstant.SAMPLE_TYPE_ANALYTE); + } + testRecordSampleDataList_All.add(hairSewageDataDto);//所有的样本的数据 + }); + }); + + List testRecordSampleDataAnalyteList = genPersistenceSampleData(testRecordSampleDataList_All); + // 批量保存到数据库 + if (super.saveBatch(testRecordSampleDataAnalyteList)) { + return testRecordService.update(Wrappers.lambdaUpdate().eq(TestRecord::getId, testId).set(TestRecord::getStatus, 2)); + } + return false; + } + + /** + * 实验结果查询中分页查询 + * + * @param testResultBusinessVOPage + * @param dto + * @return + */ + @Override + public IPage queryTestResultPage(Page testResultBusinessVOPage, QueryTestResultPageDTO dto, Object... arg) { + DLPUser dlpUsers = (DLPUser) arg[0]; + IPage testResultBusinessVOIPage = new Page<>(); + /** 1 查询当前用户做了哪些实验 + * 2 取出实验中关联的检材id + * 3 根据检材id 取查询检材 + * 4 根据检材提取出对应的业务id + * 5 最后通过业务id 进行分页查询 + */ + List testRecordList = testRecordService.list(Wrappers.lambdaQuery() + .eq(TestRecord::getTestUserId, dlpUsers.getId()) + .eq(TestRecord::getStatus, 5)); + List sampleTestListAll = new ArrayList<>(); + testRecordList.forEach(o -> sampleTestListAll.addAll(o.getSampleTestList())); // 合并所有的检材id + + Set businessIdList = new HashSet<>(); + if (CollUtil.isNotEmpty(sampleTestListAll)) { + businessIdList = sampleInfoService.list(Wrappers.lambdaQuery().in(SampleInfo::getId, sampleTestListAll)).stream().map(SampleInfo::getBusinessId).collect(Collectors.toSet()); + } else { + return testResultBusinessVOIPage; + } + // 查询所有污水报告配置信息不为空的的任务信息 + Map taskInfoMap = taskInfoService.list(Wrappers.lambdaQuery().isNotNull(TaskInfo::getReportConfig).ne(TaskInfo::getReportConfig, "")).stream().collect(Collectors.toMap(TaskInfo::getId, Function.identity())); + QueryWrapper queryWrapper = generateQueryWrapperByDTO(dto, businessIdList); + testResultBusinessVOIPage = baseMapper.queryTestResultTaskPage(testResultBusinessVOPage, queryWrapper); + testResultBusinessVOIPage.getRecords().parallelStream().forEach(item -> { + item.setBusinessTypeName(BusinessType.getBusinessTypeName(item.getBusinessType())); + if (taskInfoMap.containsKey(item.getId())) { + item.setReportConfig(taskInfoMap.get(item.getId()).getReportConfig()); + } + if (StrUtil.isNotBlank(item.getCompounds())) { + item.setCompoundsJsonArray(JSONArray.parseArray(item.getCompounds())); + } + }); + return testResultBusinessVOIPage; + } + + /** + * 修改导入的实验数据 + * + * @param dto + * @return + */ + @Override + public JSONObject updateEntrustTestData(UpdateEntrustTestDataDTO dto) { + JSONObject dtoParam = dto.getParam(); + TestRecordSampleData oldInfo = this.getById(dtoParam.getString("testSampleDataId")); // 取实验数据id + // 取出老数据,进行更改 + JSONObject oldObject = new JSONObject(); + if (oldInfo != null) { + oldObject = JSONObject.parseObject(oldInfo.getDataResultJson()); + dtoParam.put("testSampleDataList", oldObject.get("testSampleDataList")); + } else { + dtoParam.put("testSampleDataList", new JSONArray()); + } + dtoParam.put("businessType", dto.getType()); + // 根据类型去判断当前是nps还是毛发 + boolean saved = false; // 标记保存是否成功 + if (dto.getType().equals(BusinessType.NPS_CASE.getBusinessType()) + || dto.getType().equals(BusinessType.SCREENING_EVENT.getBusinessType())) { + // 设置nps中的testSampleDataList 为空, 因为这里的数据不能修改 + /*dtoParam.put("testSampleDataList", null);*/ + NPSCaseTestDataDto param = JSONObject.toJavaObject(dtoParam, NPSCaseTestDataDto.class); + + saved = saveOrUpdateTestData( + oldInfo, + param.getCompoundName(), + JSONUtil.toJsonStr(param), + param.getSampleNo(), + param.getTestId(), + param.getSampleName(), + param.getCompoundCnName()); + + } else if (dto.getType().equals(BusinessType.BOINT_CASE.getBusinessType())) { + HairSewageDataDto param = JSONObject.toJavaObject(dtoParam, HairSewageDataDto.class); + saved = saveOrUpdateTestData( + oldInfo, + param.getCompoundName(), + JSONUtil.toJsonStr(param), + param.getSampleNo(), + param.getTestId(), + param.getSampleName(), + param.getCompoundCnName()); + } + // 根据成功标识返回 + if (saved) { + // 保存成功, 返回成功的json对象 + return dtoParam; + } else { + // 保存失败, 返回之前的json对象 + return oldObject; + } + } + + /** + * 获取任务实验结果数据 + * + * @param testId + * @return + */ + @Override + public Map queryTaskTestResult(String testId) { + // 查询初2这个实验id下的实验数据,然后根据检材编号进行分组 + Map> dataGroupBySampleNoMap = this + .list(Wrappers.lambdaQuery() + .eq(TestRecordSampleData::getTestId, testId) + // 对名称进行排序,因为字符串的排序中 22 < 3,所以需要转换进行怕排序 + .last("ORDER BY SUBSTRING_INDEX(name, '-', -1) + 0")) + .stream() + .collect(Collectors.groupingBy(TestRecordSampleData::getSampleNo, LinkedHashMap::new, Collectors.toList())); + if (CollUtil.isEmpty(dataGroupBySampleNoMap)) { + return null; + } + Map map = new HashMap<>(); + + JSONArray headerArray = new JSONArray(); + JSONArray dataArray = new JSONArray(); + // 标记表头是否添加完成 + AtomicReference finish = new AtomicReference<>(false); // 为了能在lambda中使用 + dataGroupBySampleNoMap.forEach((k, v) -> { + // 组装列表数据 + JSONObject dataObject = new JSONObject(); + dataObject.put("sampleNo", k); + int size = v.size(); // 防止频繁调用方法 + for (int i = 0; i < size; i++) { + TestRecordSampleData testRecordSampleData = v.get(i); + String compoundKey = "compound" + (i + 1); + if (!finish.get()) { + if (i == 0) { + headerArray.add(createHeaderObject("sampleNo", "溶液编号", false)); + } + headerArray.add(createHeaderObject(compoundKey, "化合物" + "(" + testRecordSampleData.getCompoundName() + ")", false)); + } + // 把化合物组装导对象里 + dataObject.put(compoundKey, testRecordSampleData.getSampleConcentration()); + if (i == size - 1) { + finish.set(true); + } + } + dataArray.add(dataObject); + }); + map.put("header", headerArray); + map.put("data", dataArray); + return map; + } + + /** + * 根据业务id获取任务实验结果数据 + * + * @param businessId + * @return + */ + @Override + public Map queryTaskTestResultByBusiness(String businessId) { + // 获取业务信息 + List testResultBusinessVOS = baseMapper.queryTestResultTaskList(Wrappers.query().eq("T.id", businessId)); + if (CollUtil.isEmpty(testResultBusinessVOS)) { + throw new RuntimeException(String.format("业务id 为 %s 的数据在系统查询不到!", businessId)); + } + TestResultBusinessVO testResultBusinessVO = testResultBusinessVOS.get(0); + JSONArray compoundsJsonArray = JSONArray.parseArray(testResultBusinessVO.getCompounds()); // 获取头数组 + + /** + * 1 根据业务id查询到所有的检材 + * 2 通过查询到的检材id 关联查询到溶液 + * 3 通过溶液编号查询实验数据 + */ + List testDataListByBusiness = baseMapper + .getTestDataListByBusiness(Wrappers.query().eq("si.business_id", businessId) + .orderByDesc("si.accept_no")) + .stream() + .filter(item -> StrUtil.isNotBlank(item.getSampleDataId()) && StrUtil.isNotBlank(item.getCompoundName())) // 筛选 检验数据不为空的检材数据 + .collect(Collectors.toList()); + // 根据化合物进行分组 + Map> dataGroupByCompoundMap = testDataListByBusiness.stream() + .collect(Collectors.groupingBy(DataSolutionSampleDTO::getSampleNo, LinkedHashMap::new, Collectors.toList())); + + Map map = new HashMap<>(); + + JSONArray headerArray = new JSONArray(); + JSONArray dataArray = new JSONArray(); + // 标记表头是否添加完成 + AtomicReference finish = new AtomicReference<>(false); // 为了能在lambda中使用 + dataGroupByCompoundMap.forEach((k, v) -> { + + Map dataSolutionSampleDTOMap = v.stream() + .collect(Collectors + .toMap(DataSolutionSampleDTO::getCompoundName, Function.identity(), (v1, v2) -> v2)); // 化合物相同则后面的覆盖前面的值 + // 组装列表数据 + JSONObject dataObject = new JSONObject(); + dataObject.put("sampleNo", k); + int size = compoundsJsonArray.size(); // 防止频繁调用方法 + for (int i = 0; i < size; i++) { + JSONObject headerObject = compoundsJsonArray.getJSONObject(i); + String dictValue = headerObject.getString("dictValue"); + String dictLabel = headerObject.getString("dictLabel").substring(0, 3);//把化合物后缀取消,例如化合物1 + + // 第一次循环时添加头部信息 + if (!finish.get()) { + if (i == 0) { + headerArray.add(createHeaderObject("sampleNo", "溶液编号", false)); + } + headerArray.add(createHeaderObject(dictValue, dictLabel + "(" + dictValue + ")", false)); + } + // 设置标记,避免多次执行上面的代码 + if (i == size - 1) { + finish.set(true); + } + DataSolutionSampleDTO dto = dataSolutionSampleDTOMap.get(dictValue); + // 显示的数据 +// if (dto != null) { + // 把化合物组装导对象里 + dataObject.put(dictValue, dto != null ? dto.getSampleConcentration() : 0); +// } + } + dataArray.add(dataObject); + }); + map.put("header", headerArray); + map.put("data", dataArray); + return map; + } + + /** + * 保存实验数据的定量结果 + * + * @param dto + * @return + */ + @Override + public boolean saveQuantitativeResults(SaveQuantitativeResultsDTO dto) { + TestRecordSampleData testRecordSampleData = this.getOne(Wrappers.lambdaQuery() + .eq(TestRecordSampleData::getCompoundName, dto.getCompoundName()) + .eq(StrUtil.isNotBlank(dto.getSampleName()), TestRecordSampleData::getName, dto.getSampleName()) + .eq(StrUtil.isNotBlank(dto.getSampleNo()), TestRecordSampleData::getSampleNo, dto.getSampleNo()) + ); + if (testRecordSampleData == null) { + throw new RuntimeException(String.format("定量结果保存失败!%s 和 化合物 %s 对应数据不存在!", + StrUtil.isNotBlank(dto.getSampleName()) ? "上样编号 " + dto.getSampleName() : "检材编号 " + dto.getSampleNo(), dto.getCompoundName())); + } + validateTestStatus(testRecordSampleData.getTestId()); + JSONObject jsonObject = JSONObject.parseObject(testRecordSampleData.getDataResultJson()); + jsonObject.put("quantitativeResults", dto.getQuantitativeResults()); + return this.update(Wrappers.lambdaUpdate() + .eq(TestRecordSampleData::getId, testRecordSampleData.getId()) + .set(TestRecordSampleData::getDataResultJson, jsonObject.toJSONString())); + } + + + /** + * 删除实验数据的定量结果 + * + * @param testSampleDataId + * @return + */ + @Override + public boolean deleteQuantitativeResults(String testSampleDataId) { + TestRecordSampleData testRecordSampleData = this.getById(testSampleDataId); + if (testRecordSampleData == null) { + throw new RuntimeException(String.format("id 为 %s 的检验数据在系统中查询不到!", testSampleDataId)); + } + validateTestStatus(testRecordSampleData.getTestId()); + JSONObject jsonObject = JSONObject.parseObject(testRecordSampleData.getDataResultJson()); + jsonObject.put("quantitativeResults", null); + return this.update(Wrappers.lambdaUpdate() + .eq(TestRecordSampleData::getId, testRecordSampleData.getId()) + .set(TestRecordSampleData::getDataResultJson, jsonObject.toJSONString())); + } + + /** + * 标记该流程是否开始实验 + * + * @param testId + * @return + */ + @Override + public boolean whetherSave(String testId) { + long count = this.count(Wrappers.lambdaQuery().eq(TestRecordSampleData::getTestId, testId)); + return count > 0; + } + + /** + * 根据实验id生成定性结果 + * + * @param businessId + * @return 从1号和2号检材中均检出合成大麻素类物质 MDMB-4E-PINACA, + * 未检出四氢大麻酚和 ADB-BUTINACA4F-MDMB-BUTICA、AMB-FUBICA、ADB-4E-PINACA、4F-MDMB-BUTINACA、SF-EDMB-PICA、 + * SF-ADB、SF-MPP-PICA4F-ABUTINACA、EDMB-PINACA、SCIAPINACA、4CN-CUMYL-BUTINACA、FUB-144。 + */ + @Override + public String generateQualitativeResults(String businessId) { + + List dataSolutionSampleDTOS = baseMapper.queryDataSolutionSampleDTOList(Wrappers.query() + .eq("si.business_id", businessId) + .last("ORDER BY SUBSTRING_INDEX(rs.name, '-', -1) + 0")); + Map> dataMap = dataSolutionSampleDTOS + .stream() + .collect( + Collectors.groupingBy( + item -> StrUtil.join("_", item.getCompoundName(), item.getIsDetected()), + LinkedHashMap::new, + Collectors.toList() + ) + ); + + StringBuilder stringBuilder = new StringBuilder(); +// AtomicInteger index = new AtomicInteger(1); // 在lambda里进行递增 + if (dataMap.size() == 1) { + dataMap.forEach((key, value) -> { + DataSolutionSampleDTO first = value.get(0); + stringBuilder + .append("\t") +// .append(index.getAndIncrement()) +// .append("、") + .append(first.getOrderNo()).append("号"); + if (value.size() > 1) { + stringBuilder.append("至").append(value.get(value.size() - 1).getOrderNo()).append("号"); + } + stringBuilder.append("检材") + .append(first.getIsDetected() == 1 ? TestRecordSampleDataConstant.CHECK_OUT : TestRecordSampleDataConstant.NOT_CHECK_OUT) + .append(first.getCompoundName()) + .append("\n"); + }); + } else { + dataMap.forEach((key, value) -> { + DataSolutionSampleDTO first = value.get(0); + stringBuilder + .append("\t") +// .append(index.getAndIncrement()) +// .append("、") + .append(value.stream().map(item -> item.getOrderNo() + "号检材").collect(Collectors.joining("、"))); + stringBuilder.append(first.getIsDetected() == 1 ? TestRecordSampleDataConstant.CHECK_OUT : TestRecordSampleDataConstant.NOT_CHECK_OUT) + .append(first.getCompoundName()) + .append("。\n"); + }); + } + +// dataMap.forEach((k, v) -> { +// Map> groupByCompoundMap = v.stream().collect(Collectors.groupingBy(DataSolutionSampleDTO::getCompoundName)); +// stringBuilder.append("\t").append(index.getAndIncrement()).append("、从").append(v.get(0).getSampleName() + "(" + v.get(0).getSampleNo() + ")"); +// String checkOutResult = ""; +// String notCheckOutResult = ""; +// Set keySet = groupByCompoundMap.keySet(); +// for (String key : keySet) { +// List dtoS1 = groupByCompoundMap.get(key); +// boolean detected = true; +// /// 下面先判断是否检出 +// if (dtoS1.size() > 1) { +// Set isDetected = dtoS1.stream().map(DataSolutionSampleDTO::getIsDetected).collect(Collectors.toSet()); +// // 如果set的长度大于1 则证明其中有的检出,有的未检出, 或者其中值有0 +// if (isDetected.size() > 1 || isDetected.contains(0)) { +// detected = false; +// } +// } else { +// // 不等于1 未检出 +// detected = dtoS1.get(0).getIsDetected() == 1; +// } +// // 拼接结果 +// if (detected) { +// if (StrUtil.isBlank(checkOutResult)) { +// checkOutResult = TestRecordSampleDataConstant.CHECK_OUT + key; +// } else { +// checkOutResult = checkOutResult + "、" + key; +// } +// +// } else { +// if (StrUtil.isBlank(notCheckOutResult)) { +// notCheckOutResult = TestRecordSampleDataConstant.NOT_CHECK_OUT + key; +// } else { +// notCheckOutResult = notCheckOutResult + "、" + key; +// } +// } +// } +// if (StrUtil.isNotBlank(checkOutResult) && StrUtil.isNotBlank(notCheckOutResult)) { +// stringBuilder.append(checkOutResult + ","); +// stringBuilder.append(notCheckOutResult + "。"); +// } else if (StrUtil.isNotBlank(checkOutResult)) { +// stringBuilder.append(checkOutResult + "。"); +// } else { +// stringBuilder.append(notCheckOutResult + "。"); +// } +// stringBuilder.append("\n"); +// }); + + return stringBuilder.toString(); + } +// 之前生成定性结果的代码 + // Map> isDetectedMap = v.stream().collect(Collectors.groupingBy(DataSolutionSampleDTO::getIsDetected)); +// List checkOutList = isDetectedMap.get(1); +// List notCheckOutList = isDetectedMap.get(0); +//// String result = "从" + v.get(0).getSampleName(); +// stringBuilder.append("\t"); +// stringBuilder.append(index.getAndIncrement() + "、从" + v.get(0).getSampleName()); +// if (CollUtil.isNotEmpty(checkOutList)) { +// String result = TestRecordSampleDataConstant.CHECK_OUT + +// StrUtil.join("、", checkOutList.stream().map(DataSolutionSampleDTO::getCompoundName).collect(Collectors.toList())) + ","; +// stringBuilder.append(result); +// } +// if (CollUtil.isNotEmpty(notCheckOutList)) { +// String result = TestRecordSampleDataConstant.NOT_CHECK_OUT + +// StrUtil.join("、", notCheckOutList.stream().map(DataSolutionSampleDTO::getCompoundName).collect(Collectors.toList())) + "。"; +// stringBuilder.append(result); +// } + + /** + * 完成实验 + * + * @param testId + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public R finishTest(String testId) { + TestRecord testRecord = testRecordService.getById(testId); + if (testRecord == null) { + return R.failed(String.format("id 为 %s 的数据不存在!", testId)); + } + // 更新实验状态 + if (testRecordService.update(Wrappers.lambdaUpdate() + .eq(TestRecord::getId, testId) + .set(TestRecord::getStatus, 5) + .set(TestRecord::getTestEndDate, LocalDate.now()))) { + // 获取业务id + List dataSolutionSampleDTOS = baseMapper.queryDataSolutionSampleDTOList(Wrappers.query() + .in("si.id", testRecord.getSampleTestList())); + if (CollUtil.isEmpty(dataSolutionSampleDTOS)) { + throw new RuntimeException("检验数据和检材不匹配!"); + } + Set businessIdSet = dataSolutionSampleDTOS.stream().map(DataSolutionSampleDTO::getBusinessId).collect(Collectors.toSet()); + // 获取业务信息 + List testResultBusinessVOS = baseMapper.queryTestResultTaskList(Wrappers.query().in("T.id", businessIdSet)); + // 进行分组 + Map> testResultBusinessVOTypeMap = testResultBusinessVOS.stream().collect(Collectors.groupingBy(TestResultBusinessVO::getType)); + testResultBusinessVOTypeMap.forEach((k, v) -> { + if (k == 10000 && CollUtil.isNotEmpty(v)) { + List entrustIds = v.stream().map(TestResultBusinessVO::getId).collect(Collectors.toList()); + if (!entrustInfoService.update(Wrappers.lambdaUpdate() + .in(EntrustInfo::getId, entrustIds).set(EntrustInfo::getStatus, 3))) { + throw new RuntimeException("委托状态更新失败!"); + } + } + }); + } else { + throw new RuntimeException("实验状态更新失败!"); + } + // 发布事件 + applicationContext.publishEvent(new FinishTestExecutionEvent(this)); + return R.ok("完成实验成功!"); + } + + /** + * 审核审批数据 + * + * @param auditDataDTO + * @param httpServletRequest + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public R auditTaskTestData(AuditDataDTO auditDataDTO, HttpServletRequest httpServletRequest) { + // 标记操作是否成功 + boolean success = true; + try { + // 获取参数中所有编号的检验数据 + Map> testRecordSampleDataMap = this.list(Wrappers.lambdaQuery() + .in(TestRecordSampleData::getSampleNo, auditDataDTO.getSampleNoList())) + .stream() + .collect(Collectors.groupingBy(TestRecordSampleData::getSampleNo)); + // 对执行数据进行校验 + testRecordSampleDataMap.forEach((k, v) -> { + TestRecordSampleData testRecordSampleData = v.get(0); + if (auditDataDTO.getOpCode().equals(TaskTestDataStatus.REVIEWED.getCode())) { + if (testRecordSampleData.getStatus() > TaskTestDataStatus.REVIEWED.getCode()) { + throw new RuntimeException(String.format("编号为 %s 的数据已经审核过,不能重复审核!", k)); + } + } else if (auditDataDTO.getOpCode().equals(TaskTestDataStatus.APPROVED.getCode())) { + if (testRecordSampleData.getStatus() > TaskTestDataStatus.APPROVED.getCode()) { + throw new RuntimeException(String.format("编号为 %s 的数据已经审批过,不能重复审批!", k)); + } + } + }); + + switch (TaskTestDataStatus.getEnumByCode(auditDataDTO.getOpCode())) { +// case REJECT: +// success = this.update(Wrappers.lambdaUpdate() +// .in(TestRecordSampleData::getSampleNo, auditDataDTO.getSampleNoList()) +// .set(TestRecordSampleData::getStatus, TaskTestDataStatus.REJECT.getCode())); +// break; + case REVIEWED: + success = this.update(Wrappers.lambdaUpdate() + .in(TestRecordSampleData::getSampleNo, auditDataDTO.getSampleNoList()) + .set(TestRecordSampleData::getStatus, TaskTestDataStatus.REVIEWED.getCode())); + + break; + case APPROVED: + success = this.update(Wrappers.lambdaUpdate() + .in(TestRecordSampleData::getSampleNo, auditDataDTO.getSampleNoList()) + .set(TestRecordSampleData::getStatus, TaskTestDataStatus.APPROVED.getCode())); + List sampleNoList = auditDataDTO.getSampleNoList(); +// taskInfoService.createUploadItem(sampleNoList); + applicationContext.publishEvent(new AuditDataExecutionEvent(this, sampleNoList)); + break; + + } + } catch (Exception e) { + e.printStackTrace(); + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + } + if (success) { + return R.ok(true, "操作成功"); + } else { + return R.failed(false, "操作失败!"); + } + } + + //获取标准品样品信息数据 + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean saveTestDataFromNps(List npsDataFileStructList, String testId) { +// try { + List testRecordSampleDataList = buildSampleDataFromNps(npsDataFileStructList, testId);//构造实验数据 + testRecordService.update(Wrappers.lambdaUpdate().eq(TestRecord::getId, testId).set(TestRecord::getStatus, 2)); + return true; +// } catch (Exception err) { +// log.info("程序执行异常{}", err.getMessage()); +// err.printStackTrace(); +// return false; +// } + } + + + /** + * 更新或者保存实验数据 + * + * @param oldInfo 未更新前的数据 + * @param compoundName + * @param jsonStr DTO 转 json String + * @param sampleNo + * @param testId + * @param sampleName + * @return + */ + private boolean saveOrUpdateTestData(TestRecordSampleData oldInfo, + String compoundName, + String jsonStr, + String sampleNo, + String testId, String sampleName, String compoundCnName) { +// TestRecordSampleData one = this.getById(testSampleDataId); + if (oldInfo != null) { + return this.update(Wrappers.lambdaUpdate() + .eq(TestRecordSampleData::getId, oldInfo.getId()) + .set(!oldInfo.getCompoundName().equals(compoundName), TestRecordSampleData::getCompoundName, compoundName) + .set(sampleName != null && !sampleName.equals(oldInfo.getName()), TestRecordSampleData::getName, sampleName) + .set(TestRecordSampleData::getDataResultJson, jsonStr) + .set(StringUtils.isNotBlank(compoundCnName), TestRecordSampleData::getCompoundCnName, compoundCnName)); + } else { + TestRecordSampleData testRecordSampleData = new TestRecordSampleData(); + testRecordSampleData.setId(IdWorker.get32UUID()); + testRecordSampleData.setSampleNo(sampleNo); + testRecordSampleData.setCompoundName(compoundName); + testRecordSampleData.setTestId(testId); + testRecordSampleData.setDataResultJson(jsonStr); + if (sampleNo.startsWith(StdSolutionNum.QC_SOLUTION.getPrefix())) { + testRecordSampleData.setSampleType(TestRecordSampleDataConstant.SAMPLE_TYPE_QC); + } else if (sampleNo.startsWith(StdSolutionNum.MIXED_SOLUTION.getPrefix()) || sampleNo.startsWith(StdSolutionNum.SIMPLE_SOLUTION.getPrefix())) { + testRecordSampleData.setSampleType(TestRecordSampleDataConstant.SAMPLE_TYPE_STD); + } else { + testRecordSampleData.setSampleType(TestRecordSampleDataConstant.SAMPLE_TYPE_ANALYTE); + } + return this.save(testRecordSampleData); + } + } + + /** + * 毛发案件检验数据持久化到数据库 + * + * @param hairCompoundDataMap + * @param testId + * @return + */ + private List buildSampleDataFromHairCase(Map> hairCompoundDataMap, String testId) { + List testRecordSampleDataList_All = new Vector<>(); + List testRecordSampleDataList_Std = new Vector<>();//如果筛查物是多个,就可能出现多个标准品的数据 + List testRecordSampleDataList_Analyte = new Vector<>();//检材样品的数据 + + hairCompoundDataMap.forEach((k, v) -> { + v.parallelStream().forEach(hairCompoundData -> { + String sampleName = hairCompoundData.getSampleName(); + String idName = hairCompoundData.getIdName(); + HairSewageDataDto hairSewageDataDto = new HairSewageDataDto(); + hairSewageDataDto.setSampleNo(idName); // 样本编号 + hairSewageDataDto.setSampleName(sampleName); // 样本名称 + hairSewageDataDto.setTestId(testId); // 实验id + // 设置对应的元素数据 + hairSewageDataDto.setTestSampleDataList(Lists.newArrayList(hairCompoundData)); + hairSewageDataDto.setCompoundName(k); // 化合物名称 + + hairSewageDataDto.setBusinessType(BusinessType.BOINT_CASE.getBusinessType()); + completeHairDataInfo(hairCompoundData, hairSewageDataDto); + if (idName.contains(TestRecordSampleDataConstant.SAMPLE_TYPE_STD)) { + hairSewageDataDto.setRtTimeError(-999); // 标准溶液的相对误差为 / + hairSewageDataDto.setRtTimeWithinError(TestRecordSampleDataConstant.IS); + hairSewageDataDto.setIonAbundanceRatioWithinError(-999); // 离子丰度比相对误差 + hairSewageDataDto.setWhetherCheckOut(TestRecordSampleDataConstant.IS); + hairSewageDataDto.setStdRtTime(hairSewageDataDto.getTargetRtTime()); + hairSewageDataDto.setSampleType(TestRecordSampleDataConstant.SAMPLE_TYPE_STD); + testRecordSampleDataList_Std.add(hairSewageDataDto);//放标准品的列表 + } else { + hairSewageDataDto.setSampleType( + idName.startsWith(TestRecordSampleDataConstant.SAMPLE_TYPE_QC) ? + TestRecordSampleDataConstant.SAMPLE_TYPE_QC : TestRecordSampleDataConstant.SAMPLE_TYPE_ANALYTE); +// hairSewageDataDto.setTargetRtTime(rtTime); // 目标物保留时间 + testRecordSampleDataList_Analyte.add(hairSewageDataDto);//放被分析物 + } + testRecordSampleDataList_All.add(hairSewageDataDto);//所有的样本的数据 + }); + }); + // 计算相对误差喝离子丰度比相对误差,并判断是否符合 + settingHairCaseStdConcentration(testRecordSampleDataList_Std, testId); + settingHairCaseRelativeErrorAnalyte(testRecordSampleDataList_Std, testRecordSampleDataList_Analyte, testId); + + // 组装数据持久化到数据库 + List testRecordSampleDataStdList = genPersistenceSampleData(testRecordSampleDataList_Std); + List testRecordSampleDataAnalyteList = genPersistenceSampleData(testRecordSampleDataList_Analyte); + // 合并数组 + List mergeList = new ArrayList<>(); + mergeList.addAll(testRecordSampleDataStdList); + mergeList.addAll(testRecordSampleDataAnalyteList); + // 批量保存到数据库 + this.saveBatch(mergeList); + return mergeList; + } + + /** + * 补全毛发检验数据信息 + * + * @param hairCompoundData + * @param hairSewageDataDto + */ + private void completeHairDataInfo(HairSewageCompoundData hairCompoundData, HairSewageDataDto hairSewageDataDto) { + hairSewageDataDto.setQualitativeIonPairUp(hairCompoundData.getQuanTrace()); // 定性离子对 + hairSewageDataDto.setQualitativeIonPairDown(hairCompoundData.getTrace1()); + hairSewageDataDto.setPeakAreaUp(hairCompoundData.getArea() == null ? -999 : hairCompoundData.getArea()); // 峰面积 + hairSewageDataDto.setPeakAreaDown(hairCompoundData.getArea1() == null ? -999 : hairCompoundData.getArea1()); + + // 封装定性离子对和峰面积 + Map upMap = new HashMap<>(); + upMap.put("qualitativeIonPair", hairSewageDataDto.getQualitativeIonPairUp()); + upMap.put("peakArea", hairSewageDataDto.getPeakAreaUp()); + Map downMap = new HashMap<>(); + downMap.put("qualitativeIonPair", hairSewageDataDto.getQualitativeIonPairDown()); + downMap.put("peakArea", hairSewageDataDto.getPeakAreaDown()); + hairSewageDataDto.setMaps(Lists.newArrayList(upMap, downMap)); + // 离子丰度比 + if (hairCompoundData.getRatioActual() == null) { + if (hairCompoundData.getArea() != null && hairCompoundData.getArea1() != null) { + hairSewageDataDto.setIonAbundanceRatio(hairCompoundData.getArea1() / hairCompoundData.getArea()); + } else { + hairSewageDataDto.setIonAbundanceRatio(-999); + } + } else { + hairSewageDataDto.setIonAbundanceRatio(hairCompoundData.getRatioActual()); + } + Double rtTime = hairCompoundData.getRtTime() == null ? -999 : hairCompoundData.getRtTime(); // 取文件的保留时间 + hairSewageDataDto.setTargetRtTime(rtTime); // 目标物保留时间, 标准物质的保留时间同时存在 TargetRtTime 和 StdRtTime + } + +// /** +// * 生成持久化到数据库的实体类 +// * @param hairCaseDataDtoList +// * @return +// */ +// private List generateTestRecordSampleData(List hairCaseDataDtoList) { +// +// List persistenceSampleDataList = new ArrayList<>(); +// hairCaseDataDtoList.forEach(item->{ +// TestRecordSampleData testRecordSampleData = new TestRecordSampleData(); +// testRecordSampleData.setId(IdWorker.get32UUID()); +// testRecordSampleData.setTestId(item.getTestId()); +// testRecordSampleData.setSampleNo(item.getSampleNo()); +// testRecordSampleData.setSampleConcentration(item.getTargetConcentration()); +// testRecordSampleData.setStdConcentration(item.getStdConcentration()); +// testRecordSampleData.setCompoundName(item.getCompoundName()); +// testRecordSampleData.setTargetRtTime(item.getTargetRtTime());//检材保留时间 +// testRecordSampleData.setStdRtTime(item.getStdRtTime());//标准品保留时间 +// testRecordSampleData.setRtTimeWithinError(item.getRtTimeWithinError()); +// String dataJsonStr=JSONUtil.toJsonStr(item.getTestSampleDataList()); +// String dataResultJsonStr=JSONUtil.toJsonStr(item); +// testRecordSampleData.setDataJson(dataJsonStr); +// testRecordSampleData.setDataResultJson(dataResultJsonStr); +// persistenceSampleDataList.add(testRecordSampleData); +// }); +// return persistenceSampleDataList; +// } + + /** + * 计算相对误差喝离子丰度比相对误差,并判断是否符合 + * + * @param testRecordSampleDataListStd + * @param testRecordSampleDataListAnalyte + * @param testId + * @return + */ + private List settingHairCaseRelativeErrorAnalyte(List testRecordSampleDataListStd, + List testRecordSampleDataListAnalyte, String testId) { + + List resultConcentrationVOList = sampleInjectorMapper.queryResultConcentrationList( + Wrappers.query().eq("T.test_id", testId)); + Map stdMap = testRecordSampleDataListStd.stream() + .collect(Collectors.toMap(HairSewageDataDto::getCompoundName, Function.identity())); + + testRecordSampleDataListAnalyte.parallelStream().forEach(hairSewageDataDto -> { + List testRecordSampleSolutionlist = resultConcentrationVOList.stream() + .filter(item -> item.getNumber().equals(hairSewageDataDto.getSampleNo())).collect(Collectors.toList()); + /// 设置目标物浓度 + if (CollUtil.isNotEmpty(testRecordSampleSolutionlist)) { + hairSewageDataDto.setStdConcentration(testRecordSampleSolutionlist.get(0).getResultConcentration()); + } else { + log.info("没有找到该样本溶液,检验的化合物 {} 样本编号 {}", hairSewageDataDto.getCompoundName(), hairSewageDataDto.getSampleNo()); + hairSewageDataDto.setStdConcentration("/"); + } + + // 设置标准物质浓度 + HairSewageDataDto hairSewageDataDtoStd = stdMap.get(hairSewageDataDto.getCompoundName()); // 获取化合物下的标准物质信息 + if (hairSewageDataDtoStd != null) { +// hairSewageDataDto.setConcentration(hairSewageDataDtoStd.getStdConcentration()); +// hairSewageDataDto.setStdRtTime(hairSewageDataDtoStd.getStdRtTime()); + // 计算相对误差 (目标物保留时间 - 标准物保留时间) / 标准物质保留时间 * 100 + calculateHairCaseRtTimeError(hairSewageDataDto, hairSewageDataDtoStd); + // 计算离子丰度比 相对偏差 (目标物离子丰度比 - 标准物离子丰度比) / 标准物质离子丰度比 * 100 + calculateHairCaseIonAbundanceRatioWithinError(hairSewageDataDto, hairSewageDataDtoStd); + } +// else { +// log.info("没有找到该标准溶液,化合物 {} 样本ID {}", hairSewageDataDto.getCompoundName(), hairSewageDataDto.getSampleNo()); +// hairSewageDataDto.setStdConcentration("-1"); +// hairSewageDataDto.setStdRtTime(-999); +// } + }); + return testRecordSampleDataListAnalyte; + } + + /** + * 计算离子丰度比 相对偏差 (目标物离子丰度比 - 标准物离子丰度比) / 标准物质离子丰度比 * 100 + * + * @param hairSewageDataDto + * @param hairSewageDataDtoStd + */ + private void calculateHairCaseIonAbundanceRatioWithinError(HairSewageDataDto hairSewageDataDto, HairSewageDataDto hairSewageDataDtoStd) { + if (hairSewageDataDto.getIonAbundanceRatio() != -999) { + double ionAbundanceRatioWithinError = getHairCaseIonAbundanceRatioWithinError(hairSewageDataDto, hairSewageDataDtoStd); + hairSewageDataDto.setIonAbundanceRatioWithinError(ionAbundanceRatioWithinError); + double stdIonAbundanceRatio = hairSewageDataDtoStd.getIonAbundanceRatio(); + // 判断是否在离子丰度比允许的最大偏差范围 + if (stdIonAbundanceRatio > TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_1) { + + setHairCaseWhetherCheckOut( + hairSewageDataDto, + TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_1, + TestRecordSampleDataConstant.HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_1); + + } else if (stdIonAbundanceRatio > TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_2 + && stdIonAbundanceRatio <= TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_1) { + + setHairCaseWhetherCheckOut( + hairSewageDataDto, + TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_2, + TestRecordSampleDataConstant.HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_2); + + } else if (stdIonAbundanceRatio > TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_3 + && stdIonAbundanceRatio <= TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_2) { + + setHairCaseWhetherCheckOut( + hairSewageDataDto, + TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_3, + TestRecordSampleDataConstant.HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_3); + } else if (stdIonAbundanceRatio <= TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_3) { + setHairCaseWhetherCheckOut( + hairSewageDataDto, + TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_4, + TestRecordSampleDataConstant.HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_4); + } + } else { + hairSewageDataDto.setIonAbundanceRatioWithinError(-999); + hairSewageDataDto.setWhetherCheckOut("/"); + } + } + + /** + * 计算离子丰度比相对误差 + * + * @param hairSewageDataDto + * @param hairSewageDataDtoStd + * @return + */ + private double getHairCaseIonAbundanceRatioWithinError(HairSewageDataDto hairSewageDataDto, HairSewageDataDto hairSewageDataDtoStd) { + return (hairSewageDataDto.getIonAbundanceRatio() - hairSewageDataDtoStd.getIonAbundanceRatio()) / hairSewageDataDtoStd.getIonAbundanceRatio() * 100; + } + + /** + * 根据计算出来的离子丰度比误差来判断是否检出 + * + * @param hairSewageDataDto + * @param positive + * @param negative + */ + private void setHairCaseWhetherCheckOut(HairSewageDataDto hairSewageDataDto, double positive, double negative) { + if (hairSewageDataDto.getIonAbundanceRatioWithinError() < positive + && hairSewageDataDto.getIonAbundanceRatioWithinError() > negative) { + hairSewageDataDto.setWhetherCheckOut(TestRecordSampleDataConstant.IS); + hairSewageDataDto.setIsDetected(1); + } else { + hairSewageDataDto.setWhetherCheckOut(TestRecordSampleDataConstant.NO); + hairSewageDataDto.setIsDetected(0); + } + } + + /** + * 计算相对误差 (目标物保留时间 - 标准物保留时间) / 标准物质保留时间 * 100 + * + * @param hairSewageDataDto + * @param hairSewageDataDtoStd + */ + private void calculateHairCaseRtTimeError(HairSewageDataDto hairSewageDataDto, HairSewageDataDto hairSewageDataDtoStd) { + if (hairSewageDataDto.getTargetRtTime() != -999) { + // 计算保留时间的相对误差 + double rtTimeError = getHairCaseRtTimeError(hairSewageDataDto, hairSewageDataDtoStd); + hairSewageDataDto.setRtTimeError(rtTimeError); + // 判断保留时间相对误差是否符合误差范围 + setHairCaseRtTimeWithinError(hairSewageDataDto); + } else { + hairSewageDataDto.setRtTimeError(-999); + hairSewageDataDto.setRtTimeWithinError("/"); + } + } + + /** + * 计算保留时间的相对误差 + * + * @param hairSewageDataDto 目标物信息 + * @param hairSewageDataDtoStd 标准物信息 + * @return + */ + private double getHairCaseRtTimeError(HairSewageDataDto hairSewageDataDto, HairSewageDataDto hairSewageDataDtoStd) { + return (hairSewageDataDto.getTargetRtTime() - hairSewageDataDtoStd.getStdRtTime()) / hairSewageDataDtoStd.getStdRtTime() * 100; + } + + /** + * 判断保留时间相对误差是否符合误差范围 + * + * @param hairSewageDataDto + */ + private void setHairCaseRtTimeWithinError(HairSewageDataDto hairSewageDataDto) { + if (hairSewageDataDto.getRtTimeError() > TestRecordSampleDataConstant.HAIR_CASE_NEGATIVE_RT_ERROR + && hairSewageDataDto.getRtTimeError() < TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_RT_ERROR) { + hairSewageDataDto.setRtTimeWithinError(TestRecordSampleDataConstant.IS); + } else { + hairSewageDataDto.setRtTimeWithinError(TestRecordSampleDataConstant.NO); + } + } + + /** + * 设置标准物的溶液浓度 + * + * @param testRecordSampleDataListStd + * @param testId + * @return + */ + private List settingHairCaseStdConcentration(List testRecordSampleDataListStd, String testId) { + List testRecordStandardSolutionList = testRecordStandardSolutionService.list( + Wrappers.lambdaQuery() + .eq(TestRecordStandardSolution::getTestId, testId)); + // 根据编号转map 方便获取 + Map testRecordStandardSolutionMap = testRecordStandardSolutionList + .stream() + .collect(Collectors.toMap(TestRecordStandardSolution::getNumber, Function.identity())); + for (HairSewageDataDto hairSewageDataDto : testRecordSampleDataListStd) { + //设置标准品的浓度 + TestRecordStandardSolution testRecordStandardSolution = testRecordStandardSolutionMap.get(hairSewageDataDto.getSampleNo()); + if (ObjectUtil.isNotEmpty(testRecordStandardSolution)) { + hairSewageDataDto.setStdConcentration(testRecordStandardSolution.getResultConcentration());//设置标准品的浓度 + } else { + log.info("没有找到该标准溶液,实验ID {} {}", hairSewageDataDto.getCompoundName(), hairSewageDataDto.getSampleNo()); + hairSewageDataDto.setStdConcentration("/"); + } + } + return testRecordSampleDataListStd; + } + + /** + * 构建数据库持久化对象 + * + * @param npsDataFileStructList + * @param testId + * @return + */ + private List buildSampleDataFromNps(List npsDataFileStructList, String testId) { + List testRecordSampleDataList_All = new ArrayList<>(); + List testRecordSampleDataList_Std = new ArrayList<>();//如果筛查物是多个,就可能出现多个标准品的数据 + List testRecordSampleDataList_Analyte = new ArrayList<>();//检材样品的数据 + + //一批文件中含有多个样本,将一个样本的检验数据封装到一个NPSCaseTestDataDto对象中 + //查出这批实验中的标准品数据,并将NPSDataFileStruct 转化为NPSCaseTestDataDto对象 + npsDataFileStructList.forEach(item -> { + String sampleNo = item.getSi_SampleId(); + String sampleType = item.getSi_SampleType(); + //离子丰度比数据 + NPSCaseTestDataDto npsCaseTestDataDto = getNpsCaseTestDataDto(testId, item, sampleNo); + if (sampleType.equals(TestRecordSampleDataConstant.SAMPLE_TYPE_STD)) { + testRecordSampleDataList_Std.add(npsCaseTestDataDto);//放标准品的列表 + } else { + testRecordSampleDataList_Analyte.add(npsCaseTestDataDto);//放被分析物 + } + testRecordSampleDataList_All.add(npsCaseTestDataDto);//所有的样本的数据 + }); + //设置计算保留时间和丰度比 + settingAbundanceRatioStd(testRecordSampleDataList_Std, testId); + settingAbundanceRatioAnalyte(testRecordSampleDataList_Analyte, testRecordSampleDataList_Std, testId); + //构造持久化到数据库的对象 + List testRecordSampleDataList_std = genPersistenceSampleData(testRecordSampleDataList_Std); + List testRecordSampleDataList_analyte = genPersistenceSampleData(testRecordSampleDataList_Analyte); + this.saveBatch(testRecordSampleDataList_std); + this.saveBatch(testRecordSampleDataList_analyte); + List retList = new ArrayList<>(); + retList.addAll(testRecordSampleDataList_std); + retList.addAll(testRecordSampleDataList_analyte); + return retList; + } + + /** + * 生成npsDTO + * + * @param testId + * @param item + * @param sampleNo + * @return + */ + private NPSCaseTestDataDto getNpsCaseTestDataDto(String testId, NPSDataFileStruct item, String sampleNo) { + List testDetailDataList = item.getChildDataList(); + NPSCaseTestDataDto npsCaseTestDataDto = new NPSCaseTestDataDto(); + npsCaseTestDataDto.setSampleName(item.getSi_SampleName()); + npsCaseTestDataDto.setSampleNo(sampleNo); + npsCaseTestDataDto.setTestId(testId); + npsCaseTestDataDto.setTestSampleDataList(testDetailDataList); + npsCaseTestDataDto.setCompoundName(testDetailDataList.get(0).getName()); + npsCaseTestDataDto.setBusinessType(BusinessType.NPS_CASE.getBusinessType()); // 设置业务类型 + return npsCaseTestDataDto; + } + + /** + * 构造持久化到数据库的对象 + * 使用了通配符 来接收不同类型的数据对象,并通过 instanceof 关键字进行类型判断以获取对应的属性值。 + * 这样可以避免重复的代码逻辑,提高代码的可维护性和复用性 + * + * @param npsCaseTestDataDtoList + * @return + */ + private List genPersistenceSampleData(List npsCaseTestDataDtoList) { + List persistenceSampleDataList = Collections.synchronizedList(new ArrayList<>()); + npsCaseTestDataDtoList.parallelStream().forEach(item -> { + + TestRecordSampleData testRecordSampleData = new TestRecordSampleData(); + testRecordSampleData.setId(IdWorker.get32UUID()); + testRecordSampleData.setTestId(item.getTestId()); +// testRecordSampleData.setSampleNo(item.getSampleId()); + if (item instanceof HairSewageDataDto) { + testRecordSampleData.setName(((HairSewageDataDto) item).getSampleName()); + testRecordSampleData.setSampleNo(((HairSewageDataDto) item).getSampleNo()); + } else if (item instanceof NPSCaseTestDataDto) { + NPSCaseTestDataDto npsCaseTestDataDto = (NPSCaseTestDataDto) item; + testRecordSampleData.setName(npsCaseTestDataDto.getSampleName()); + testRecordSampleData.setSampleNo(npsCaseTestDataDto.getSampleNo()); + } + testRecordSampleData.setSampleConcentration(item.getTargetConcentration()); + testRecordSampleData.setStdConcentration(item.getStdConcentration()); + testRecordSampleData.setTargetRtTime(item.getTargetRtTime());//检材保留时间 + testRecordSampleData.setStdRtTime(item.getStdRtTime());//标准品保留时间 + testRecordSampleData.setCompoundName(item.getCompoundName()); + testRecordSampleData.setRtTimeWithinError(item.getRtTimeWithinError()); + testRecordSampleData.setIsDetected(item.getIsDetected()); + testRecordSampleData.setSampleType(item.getSampleType()); + String dataJsonStr = null; + String dataResultJsonStr = null; + try { + dataJsonStr = JSON.toJSONString(item.getTestSampleDataList()); + } catch (Exception e) { + log.error("错误位置详细信息 ============== {}", item.getTestSampleDataList()); + e.printStackTrace(); + } + try { + dataResultJsonStr = JSON.toJSONString(item); + } catch (Exception e) { + log.error("错误位置详细信息 ============== {}", item); + e.printStackTrace(); + } + testRecordSampleData.setDataJson(dataJsonStr); + testRecordSampleData.setDataResultJson(dataResultJsonStr); + persistenceSampleDataList.add(testRecordSampleData); + }); + return persistenceSampleDataList; + } + + //计算标准品的丰度比 + private List settingAbundanceRatioStd(List testRecordSampleDataListStd, String testId) { + // + if (CollUtil.isEmpty(testRecordSampleDataListStd)) { + throw new RuntimeException("未检测到数据文件中的标准品溶液!"); + } +// Optional testId = testRecordSampleDataListStd.stream().map(item -> item.getTestId()).findFirst(); + List testRecordStandardSolutionList = testRecordStandardSolutionService.list( + Wrappers.lambdaQuery() + .eq(TestRecordStandardSolution::getTestId, testId)); + + for (NPSCaseTestDataDto npsCaseTestDataDto : testRecordSampleDataListStd) { + //设置标准品的浓度 + List testRecordStandardSolution = testRecordStandardSolutionList.stream() + .filter(item -> item.getNumber().equals(npsCaseTestDataDto.getSampleNo())).collect(Collectors.toList()); + if (testRecordStandardSolution.size() > 0) { + npsCaseTestDataDto.setStdConcentration(testRecordStandardSolution.get(0).getResultConcentration());//设置标准品的浓度 + } else { + log.info("没有找到该标准溶液,实验ID {} {}", npsCaseTestDataDto.getCompoundName(), npsCaseTestDataDto.getSampleNo()); + npsCaseTestDataDto.setStdConcentration("/"); + } + + //根据化合物名称查出谁是基峰 + List testSampleDataList = npsCaseTestDataDto.getTestSampleDataList(); + NPSTestDetailDataStruct npsTestDetailDataStruct_Base = getBasePeakMass(testSampleDataList); + if (npsTestDetailDataStruct_Base == null) { + throw new RuntimeException("在系统中没有找到对应的化合物基峰!"); + } + double sumRetTime = 0; + for (NPSTestDetailDataStruct npsTestDetailDataStruct : testSampleDataList) { + //求保留时间 + sumRetTime = sumRetTime + npsTestDetailDataStruct.getRetTime(); + if (!npsTestDetailDataStruct.getId().equals(npsTestDetailDataStruct_Base.getId())) { + //计算丰度比 + double mzValue = npsTestDetailDataStruct.getArea() / npsTestDetailDataStruct_Base.getArea() * 100; + npsTestDetailDataStruct.setAbundanceRatio(mzValue); + } else { + npsTestDetailDataStruct.setAbundanceRatio(-999); + npsTestDetailDataStruct.setIsBasePeak(1); + } + + } + double sampleRetTime = sumRetTime / testSampleDataList.size(); + npsCaseTestDataDto.setStdRtTime(sampleRetTime);//设置样品的保留时间 + npsCaseTestDataDto.setSampleType(TestRecordSampleDataConstant.SAMPLE_TYPE_STD); + + } + return testRecordSampleDataListStd; + } + + /** + * 计算待测样品的保留时间和丰度比 + * + * @param testRecordSampleDataList + * @param testId + */ + private List settingAbundanceRatioAnalyte(List testRecordSampleDataList, List testRecordSampleDataList_std, String testId) { + //因为要读样本的浓度,所以我们把该实验下所有样本信息拿过来 +// Optional testId = testRecordSampleDataList.stream().map(item -> item.getTestId()).findFirst(); + List sampleSolutionlist = testRecordSampleSolutionService.list(Wrappers.lambdaQuery() + .eq(TestRecordSampleSolution::getTestId, testId)); + + for (NPSCaseTestDataDto npsCaseTestDataDto : testRecordSampleDataList) { + + List testRecordSampleSolutionlist = sampleSolutionlist.stream() + .filter(item -> item.getSampleNo().equals(npsCaseTestDataDto.getSampleNo())).collect(Collectors.toList()); + if (testRecordSampleSolutionlist.size() > 0) { + npsCaseTestDataDto.setTargetConcentration(testRecordSampleSolutionlist.get(0).getResultConcentration());//设置标准品的浓度 + } else { + log.info("没有找到该样本溶液,检验的化合物 {} 样本编号 {}", npsCaseTestDataDto.getCompoundName(), npsCaseTestDataDto.getSampleNo()); + npsCaseTestDataDto.setTargetConcentration("/"); + } + //设置标准物质的浓度 + List stdSolution = testRecordSampleDataList_std.stream() + .filter(item -> item.getCompoundName().equals(npsCaseTestDataDto.getCompoundName())) + .collect(Collectors.toList()); + if (stdSolution.size() > 0) { + npsCaseTestDataDto.setStdConcentration(stdSolution.get(0).getStdConcentration()); + } else { + log.info("没有找到该标准溶液,化合物 {} 样本ID {}", npsCaseTestDataDto.getCompoundName(), npsCaseTestDataDto.getSampleNo()); + npsCaseTestDataDto.setStdConcentration("/"); + } + // 取出这个子列表 + List testSampleDataList = npsCaseTestDataDto.getTestSampleDataList(); + List notIdentifiedList = testSampleDataList.stream().filter(o -> o.isNotIdentified()).collect(Collectors.toList()); + if (CollUtil.isEmpty(notIdentifiedList)) { // 没有未检出的数据 + //根据化合物名称查出谁是基峰 + NPSTestDetailDataStruct npsTestDetailDataStruct_Base = getBasePeakMass(testSampleDataList); + double sumRetTime = 0; + //定义1个List来保存除基峰之外的其他碎片峰 + List otherList = new ArrayList<>(); + for (NPSTestDetailDataStruct npsTestDetailDataStruct : testSampleDataList) { + //求保留时间 + sumRetTime = sumRetTime + npsTestDetailDataStruct.getRetTime(); + if (!npsTestDetailDataStruct.getId().equals(npsTestDetailDataStruct_Base.getId())) { + //计算丰度比 + double mzValue = npsTestDetailDataStruct.getArea() / npsTestDetailDataStruct_Base.getArea() * 100; + npsTestDetailDataStruct.setAbundanceRatio(mzValue); + //设置误差范围,基峰不用设置误差范围 + double errorRange = getErrorRange(mzValue); + npsTestDetailDataStruct.setErrorRange(errorRange); + //设置标准品的丰度比 + double stdCorrespondingAbundanceRatio = getStdCorrespondingAbundanceRatio(npsTestDetailDataStruct.getMass(), + npsTestDetailDataStruct.getName(), testRecordSampleDataList_std); + npsTestDetailDataStruct.setAbundanceRatio_std(stdCorrespondingAbundanceRatio); + //设置偏差,公式是 样品-标准品/标准品 + double abundanceRatioErrorValue = getAbundanceRatioErrorValue(npsTestDetailDataStruct.getAbundanceRatio(), + npsTestDetailDataStruct.getAbundanceRatio_std()); + npsTestDetailDataStruct.setAbundanceRatioError(abundanceRatioErrorValue); + //设置是否在误差范围内 + String withinErrorText = getWithinErrorText(npsTestDetailDataStruct.getAbundanceRatioError(), npsTestDetailDataStruct.getErrorRange()); + npsTestDetailDataStruct.setWithinError(withinErrorText); + otherList.add(npsTestDetailDataStruct); + } else { + npsTestDetailDataStruct.setAbundanceRatio(-999);//设置检材丰度比 + npsTestDetailDataStruct.setAbundanceRatio_std(-999);//设置标准物质丰度比 + npsTestDetailDataStruct.setErrorRange(-999);//设置丰度比偏差 + npsTestDetailDataStruct.setAbundanceRatioError(-999);//设置偏差范围 + npsTestDetailDataStruct.setWithinError("/");//设置是否在误差范围内 + npsTestDetailDataStruct.setIsBasePeak(1);//设置他是基峰 + } + + } + double sampleRetTime = sumRetTime / testSampleDataList.size(); + npsCaseTestDataDto.setTargetRtTime(sampleRetTime);//设置样品的保留时间 + //设置标准品的保留时间 + double stdRtTime = findStdRtTime(npsCaseTestDataDto.getTestSampleDataList().get(0).getName(), testRecordSampleDataList_std); + npsCaseTestDataDto.setStdRtTime(stdRtTime); + //设置保留时间偏差是否在范围 ±1 范围内 公式是 (Rt样品-标品)/标品 *100% + double tmp1 = (sampleRetTime - stdRtTime) / stdRtTime; + tmp1 = Math.abs(tmp1) * 100; + npsCaseTestDataDto.setRtTimeError(tmp1); + String rtWithinErrorText = getRtWithinErrorText(tmp1, 1); + npsCaseTestDataDto.setRtTimeWithinError(rtWithinErrorText); + //设置碎片峰的结果,条件是 除了基峰外的所有特征碎片都满足 离子丰度误差,才算是检出条件之一 + int isOk = checkOtherFragmentResult(otherList); + npsCaseTestDataDto.setIsDetected(isOk);//1是检出,0是未检出 + npsCaseTestDataDto.setWhetherCheckOut(isOk == 1 ? + TestRecordSampleDataConstant.CHECK_OUT + npsCaseTestDataDto.getCompoundName() : + TestRecordSampleDataConstant.NOT_CHECK_OUT + npsCaseTestDataDto.getCompoundName()); + npsCaseTestDataDto.setSampleType(TestRecordSampleDataConstant.SAMPLE_TYPE_ANALYTE); + } else { + npsCaseTestDataDto.setTargetRtTime(-999);//设置样品的保留时间 + npsCaseTestDataDto.setStdRtTime(-999); + npsCaseTestDataDto.setRtTimeError(-999); + npsCaseTestDataDto.setRtTimeWithinError("/"); + npsCaseTestDataDto.setIsDetected(0);//1是检出,0是未检出 + npsCaseTestDataDto.setWhetherCheckOut(TestRecordSampleDataConstant.NOT_CHECK_OUT + npsCaseTestDataDto.getCompoundName()); + npsCaseTestDataDto.setSampleType(TestRecordSampleDataConstant.SAMPLE_TYPE_ANALYTE); + } + } + return testRecordSampleDataList; + } + + @Resource + private RemoteDictDataService remoteDictDataService; + /** + * 根据化合物名称找出基峰的对应的数据 + * + * @param testSampleDataList + * @return 如果没找到 返回null + */ + private NPSTestDetailDataStruct getBasePeakMass(List testSampleDataList) { + NPSTestDetailDataStruct npsTestDetailDataStruct_Base = null; + R> r = remoteDictDataService.getDictDataListByDictType(TestRecordSampleDataConstant.COMPOUND_BASIC_PEAK); + if (r.getCode() == CommonConstants.FAIL) { + log.error(LocalDateTime.now() + "从字典中获取化合物基峰数据失败!"); + throw new RuntimeException(LocalDateTime.now() + "从字典中获取化合物基峰数据失败!"); + } + Map compoundBasicPeak = r.getData(); // 这里我们需要注意的是化合物基峰的值我们存储在备注里 + for (NPSTestDetailDataStruct npsTestDetailDataStruct : testSampleDataList) { + String compoundName = npsTestDetailDataStruct.getName();//化合物名称 + double massValue = compoundBasicPeak.containsKey(compoundName) ? Double.parseDouble(compoundBasicPeak.get(compoundName).getRemark()) : 0; + if (Double.parseDouble(npsTestDetailDataStruct.getMass()) == massValue) { + npsTestDetailDataStruct_Base = npsTestDetailDataStruct; + log.info("找到化合物 {} 的基峰质荷比(mz)是 {}", compoundName, npsTestDetailDataStruct_Base); + break; + } + } + return npsTestDetailDataStruct_Base; + } + + //设置是否在误差范围内 + private String getWithinErrorText(double actualValue, double expectedValue) { + if (actualValue < expectedValue) { + return TestRecordSampleDataConstant.IS; + } else { + return TestRecordSampleDataConstant.NO; + } + } + + //判断保留时间范围是否符合 + private String getRtWithinErrorText(double targetRtErr, double errorRange) { + if (targetRtErr < errorRange) { + return TestRecordSampleDataConstant.IS; + } else { + return TestRecordSampleDataConstant.NO; + } + + } + + //查找标准品的保留时间 + private double findStdRtTime(String compoundName, List testRecordSampleDataList_std) { + List retStd = testRecordSampleDataList_std.stream() + .filter(item -> item.getCompoundName() + .equals(compoundName)).collect(Collectors.toList()); + + if (retStd.size() > 0) { + return retStd.get(0).getStdRtTime(); + } else { + log.info("没有找到化合物是{}的标准溶液,请核查参数是否准确", compoundName); + return -1; + } + } + + /** + * 计算丰度比偏差 + * + * @param sampleAbundanceRatio + * @param sampleAbundanceRatio_std + * @return + */ + private double getAbundanceRatioErrorValue(double sampleAbundanceRatio, double sampleAbundanceRatio_std) { + double diffValue = sampleAbundanceRatio - sampleAbundanceRatio_std; + double abundanceRatioErrorValue = Math.abs(diffValue) / sampleAbundanceRatio_std * 100; + return abundanceRatioErrorValue; + } + + /** + * 获取碎片的丰度比偏差范围 + * + * @param abundanceRatio + * @return + */ + private double getErrorRange(double abundanceRatio) { + double retValue = 0; + if (abundanceRatio > 0.5) { + retValue = 10; + } else if (abundanceRatio > 0.2) { + retValue = 15; + } else if (abundanceRatio > 0.1) { + retValue = 20; + } else { + retValue = 50; + } + return retValue; + } + + private double getStdCorrespondingAbundanceRatio(String massValue, String compoundName, List testRecordSampleDataList_std) { + double retValue = 0; + //根据化合物名称找出对应的标准品 + List std = testRecordSampleDataList_std.stream() + .filter(item -> item.getCompoundName().equals(compoundName)).collect(Collectors.toList()); + NPSCaseTestDataDto std_NPSCaseTestDataDto = null; + for (NPSCaseTestDataDto item : testRecordSampleDataList_std) { + if (item.getCompoundName().equals(compoundName)) { + std_NPSCaseTestDataDto = item; + break; + } + } + for (NPSTestDetailDataStruct npsTestDetailDataStruct : std_NPSCaseTestDataDto.getTestSampleDataList()) { + if (Double.parseDouble(npsTestDetailDataStruct.getMass()) == Double.parseDouble(massValue)) { + retValue = npsTestDetailDataStruct.getAbundanceRatio(); + } + } + return retValue; + } + + //TestRecordSampleData 与NPSCaseTestDataDto的转换 + private NPSCaseTestDataDto testRecordSampleDataToPSCaseTestDataDto(TestRecordSampleData testRecordSampleData) { + JSONObject jsonObject = (JSONObject) JSONObject.parse(testRecordSampleData.getDataResultJson()); + NPSCaseTestDataDto npsCaseTestDataDto = JSONObject.toJavaObject(jsonObject, NPSCaseTestDataDto.class); + return npsCaseTestDataDto; + } + + private int checkOtherFragmentResult(List npsTestDetailDataStructList) { + int ret = 1; + + for (NPSTestDetailDataStruct npsTestDetailDataStruct : npsTestDetailDataStructList) { + if (npsTestDetailDataStruct.getWithinError().equals(TestRecordSampleDataConstant.NO)) { + ret = 0; + } + } + return ret; + } + + /** + * 封装根据类的类型去组装数据 + * + * @param list + * @param retList + * @param clazz + * @param + */ + private void extractedSampleTestData(List list, List retList, Class clazz) { + for (TestRecordSampleData testRecordSampleData : list) { + retList.add(testRecordSampleDataToPSCaseTestDataDto(testRecordSampleData, clazz)); + } + } + + /** + * 获取TestRecordSampleData中的dataResultJson 转换成指定的对象 + * + * @param testRecordSampleData + * @param clazz + * @param + * @return + */ + private T testRecordSampleDataToPSCaseTestDataDto(TestRecordSampleData testRecordSampleData, Class clazz) { + JSONObject jsonObject = (JSONObject) JSONObject.parse(testRecordSampleData.getDataResultJson()); + jsonObject.put("testSampleDataId", testRecordSampleData.getId()); + // 对小数进行保留两位小数的操作 + DecimalFormat df = new DecimalFormat("#.##"); + jsonObject.put("rtTimeError", df.format(jsonObject.getDouble("rtTimeError"))); + jsonObject.put("compoundCnName", testRecordSampleData.getCompoundCnName()); + return JSONObject.toJavaObject(jsonObject, clazz); + } + + /** + * 检验数据类型转换 + * + * @param retList + * @return + */ + private List typeCasting(List retList) { + List collect = retList.stream().map(item -> { + if (item instanceof HairSewageDataDto) { + return (HairSewageDataDto) item; + } else if (item instanceof NPSCaseTestDataDto) { + return (NPSCaseTestDataDto) item; + } else { + // todo 待处理的任务dto + return item; + } + }).collect(Collectors.toList()); + return collect; + } + + /** + * 生成审核任务列表的头部名称json数组 + * + * @param dataGroupBySampleNoMap + * @return + */ + private JSONArray generateHeaderArray(LinkedHashMap> dataGroupBySampleNoMap) { + JSONArray headerArray = new JSONArray(); + AtomicBoolean finish = new AtomicBoolean(false); + + dataGroupBySampleNoMap.forEach((sampleNo, dataList) -> { + if (!finish.get()) { + headerArray.add(createHeaderObject("sampleNo", "溶液编号", true)); + headerArray.add(createHeaderObject("taskName", "案件/任务名称", false)); + headerArray.add(createHeaderObject("businessTypeName", "业务类型", false)); + headerArray.add(createHeaderObject("statusName", "状态", false)); + + IntStream.range(0, dataList.size()) + .forEach(i -> headerArray + .add(createHeaderObject( + "compound" + (i + 1), + "化合物" + "(" + dataList.get(i).getCompoundName() + ")", + false))); + finish.set(true); + } + }); + + return headerArray; + } + + /** + * 创建列表头名称json + * + * @param prop + * @param label + * @param fixed + * @return + */ + private JSONObject createHeaderObject(String prop, String label, boolean fixed) { + JSONObject object = new JSONObject(); + object.put(TestRecordSampleDataConstant.PROP, prop); + object.put(TestRecordSampleDataConstant.LABEL, label); + if (fixed) { + object.put("fixed", true); + } + return object; + } + + /** + * 组装具体的检验数据 + * + * @param dataGroupBySampleNoMap + * @return + */ + private JSONArray generateDataArray(LinkedHashMap> dataGroupBySampleNoMap) { + JSONArray dataArray = new JSONArray(); + + dataGroupBySampleNoMap.forEach((sampleNo, dataList) -> { + JSONObject dataObject = new JSONObject(); + dataObject.put("sampleNo", sampleNo); + + dataList.forEach(taskTestDataDTO -> { + dataObject.put("taskName", taskTestDataDTO.getTaskName()); + dataObject.put("businessTypeName", BusinessType.getBusinessTypeName(taskTestDataDTO.getBusinessType())); + dataObject.put("status", taskTestDataDTO.getStatus()); + dataObject.put("statusName", TaskTestDataStatus.getStatusNameByCode(taskTestDataDTO.getStatus())); + IntStream.range(0, dataList.size()) + .forEach(i -> dataObject.put("compound" + (i + 1), dataList.get(i).getSampleConcentration())); + }); + + dataArray.add(dataObject); + }); + + return dataArray; + } + + + /** + * 手动分页方法 + * + * @param dataList + * @param current + * @param size + * @return + */ + private Page getPageData(JSONArray dataList, int current, int size) { + int fromIndex = (current - 1) * size; + if (fromIndex >= dataList.size()) { + return new Page<>(); // 如果起始索引超出数据范围,返回空page + } + int toIndex = Math.min(fromIndex + size, dataList.size()); + Page page = new Page<>(); + page.setCurrent(current); + page.setSize(size); + page.setRecords(dataList.subList(fromIndex, toIndex)); + page.setTotal(dataList.size()); + return page; + } + + /** + * 生成查询条件 + * + * @param pageDTO + * @return + */ + private QueryWrapper generateTaskTestDataQW(TaskTestDataPageDTO pageDTO) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByDesc("ti.create_time").orderByDesc("ss.sample_no"); + queryWrapper.and(StrUtil.isNotBlank(pageDTO.getKeyword()), + wrapper -> + wrapper + .like("ti.task_name", pageDTO.getKeyword()) + .or() + .like("si.sample_name", pageDTO.getKeyword()) + .or() + .like("ss.sample_no", pageDTO.getKeyword())); + queryWrapper.eq(StrUtil.isNotBlank(pageDTO.getBusinessType()), "ti.business_type", pageDTO.getBusinessType()); + if (pageDTO.getStatus().equals(TaskTestDataStatus.REVIEWED.getCode())) { + // 任务审核列表,查询待审核的数据返回 + queryWrapper.eq("rs.status", TaskTestDataStatus.WAIT_REVIEW.getCode()); + } else if (pageDTO.getStatus().equals(TaskTestDataStatus.APPROVED.getCode())) { + // 任务审批列表,查询待审批的数据返回 + queryWrapper.eq("rs.status", TaskTestDataStatus.REVIEWED.getCode()); + } + return queryWrapper; + } + + /** + * 生成查询条件 + * + * @param dto + * @param businessIdList + * @return + */ + private QueryWrapper generateQueryWrapperByDTO(QueryTestResultPageDTO dto, Set businessIdList) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + // 获取查询的关键字字段 + String keyword = dto.getKeyword(); + queryWrapper.in("T.id", businessIdList); + queryWrapper.eq("T.type", dto.getType()); + queryWrapper.ge("T.status", 3); + // 如果创建人不为空,则查询该创建人的任务 + queryWrapper.eq(StrUtil.isNotBlank(dto.getCreateBy()), "T.create_by", dto.getCreateBy()) + .and(StrUtil.isNotBlank(keyword), wrapper -> + wrapper.like("T.case_name", keyword)); + // 时间范围查询,包含开始时间和结束时间 + queryWrapper.ge(dto.getStartTime() != null, "T.create_time", dto.getStartTime()) + .le(dto.getEndTime() != null, "T.create_time", dto.getEndTime()); + // 根据创建时间进行排序 + if (dto.getType().equals(20000)) { + queryWrapper.orderByDesc("T.task_start_date"); + } else { + queryWrapper.orderByDesc("T.create_time"); + } + return queryWrapper; + } + + /** + * 拼接定性结果,检出或未检出的字符串 + * + * @param existingResult + * @param newResult + * @return + */ + private String appendCheckOutResult(String existingResult, String newResult) { + return StrUtil.isBlank(existingResult) ? newResult : existingResult + "、" + newResult; + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordSampleSolutionServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordSampleSolutionServiceImpl.java new file mode 100644 index 0000000..101a787 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordSampleSolutionServiceImpl.java @@ -0,0 +1,371 @@ +package digital.laboratory.platform.inspection.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.dto.TestRecordSampleSolutionDto; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import digital.laboratory.platform.inspection.entity.SampleInjector; +import digital.laboratory.platform.inspection.entity.TestRecordSampleSolution; +import digital.laboratory.platform.inspection.constant.TestRecordArgumentType; +import digital.laboratory.platform.inspection.mapper.TestRecordMapper; +import digital.laboratory.platform.inspection.mapper.TestRecordSampleSolutionMapper; +import digital.laboratory.platform.inspection.service.SampleInfoService; +import digital.laboratory.platform.inspection.service.SampleInjectorService; +import digital.laboratory.platform.inspection.service.TestRecordSampleSolutionService; +import digital.laboratory.platform.inspection.service.TestRecordService; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import digital.laboratory.platform.sys.feign.RemoteBalanceRMaterialService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@SuppressWarnings("all") +public class TestRecordSampleSolutionServiceImpl extends ServiceImpl implements TestRecordSampleSolutionService { + + @Resource + private RemoteBalanceRMaterialService remoteBalanceRMaterialService; + + @Resource + private TestRecordService testRecordService; + + @Resource + private SampleInfoService sampleInfoService; + + @Resource + private TestRecordMapper testRecordMapper; + + @Resource + private SampleInjectorService sampleInjectorService; + + /** + * 新增样本溶液 + * + * @param testRecordSampleSolutionDto + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public TestRecordSampleSolution addTestRecordSampleSolution(TestRecordSampleSolutionDto testRecordSampleSolutionDto) { + TestRecordSampleSolution testRecordSampleSolution = new TestRecordSampleSolution(); + BeanUtils.copyProperties(testRecordSampleSolutionDto, testRecordSampleSolution); + SampleInfo sampleInfo = sampleInfoService.getById(testRecordSampleSolutionDto.getMaterialId()); + testRecordSampleSolution.setSampleShape(sampleInfo.getForm()); + testRecordSampleSolution.setId(IdWorker.get32UUID().toUpperCase()); + testRecordSampleSolution.setSampleNo(this.createSampleNo(testRecordSampleSolutionDto.getMaterialId(), testRecordSampleSolutionDto.getTestId()));//获取编号 +// SampleInfo sampleInfo = sampleInfoService.getOne(Wrappers.lambdaQuery().eq(SampleInfo::getAcceptNo, testRecordSampleSolutionDto.getSampleNo())); +// if (sampleInfo == null) { +// throw new RuntimeException(String.format("没有找到编号为%s的样本!", testRecordSampleSolutionDto.getSampleNo())); +// } + //计算浓度 + testRecordSampleSolution = this.calculatedConcentration(testRecordSampleSolution); + Integer opCode = 1;//代表是向实验添加溶液 + boolean ret = testRecordService.updateTestRecordArgument(testRecordSampleSolution.getTestId(), testRecordSampleSolution.getId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_SAMPLE_SOLUTION.getType(), opCode); + return this.save(testRecordSampleSolution) && ret ? testRecordSampleSolution : null; + } + + /** + * 创建编号 + * + * @param testRecordSampleSolutionDto + * @return + */ + public String createSampleNo(String materialId, String testId) { + SampleInfo sampleInfo = sampleInfoService.getById(materialId); + String acceptNo = sampleInfo.getAcceptNo(); + + //根据这个样本在实验中创建为溶液的次数来生成后缀,以便能自动匹配称量数据 + List list = this.list(Wrappers.lambdaQuery().eq(TestRecordSampleSolution::getMaterialId, materialId)); + + if (list == null || list.size() == 0) { + return acceptNo; + } else if (list != null && list.size() == 1) { + //判断是否已上样 + this.isLoadSample(acceptNo, testId); + //选中同一样本创建第二个溶液时,要将第一个溶液的编号后缀修改为-1 + TestRecordSampleSolution testRecordSampleSolution = list.get(0); + testRecordSampleSolution.setSampleNo(acceptNo + "-1"); + this.updateById(testRecordSampleSolution); + return acceptNo + "-2"; + } else { + return acceptNo + "-" + (list.size() + 1); + } + + } + + /** + * 删除样本溶液 + * + * @param id + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean delTestRecordSampleSolution(String id) { + TestRecordSampleSolution oldTestRecordSampleSolution = this.getOne(Wrappers.lambdaQuery().eq(TestRecordSampleSolution::getId, id)); + Integer opCode = -1;//代表向实验删除这个溶液 + if (oldTestRecordSampleSolution == null) { + throw new RuntimeException(String.format("没有找到ID为%s的样本溶液!", id)); + } + this.isLoadSample(oldTestRecordSampleSolution.getSampleNo(), oldTestRecordSampleSolution.getTestId()); + List list = this.list(Wrappers.lambdaQuery().eq(TestRecordSampleSolution::getMaterialId, oldTestRecordSampleSolution.getMaterialId())); + if (list.size() == 2) { + list.remove(oldTestRecordSampleSolution); + TestRecordSampleSolution testRecordSampleSolution = list.get(0); + String sampleNo = testRecordSampleSolution.getSampleNo(); + this.isLoadSample(sampleNo, testRecordSampleSolution.getTestId()); + int lastInde = sampleNo.lastIndexOf("-"); + String newSampleNo = sampleNo.substring(0, lastInde); + testRecordSampleSolution.setSampleNo(newSampleNo); + this.updateById(testRecordSampleSolution); + } + boolean ret = testRecordService.updateTestRecordArgument(oldTestRecordSampleSolution.getTestId(), oldTestRecordSampleSolution.getId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_SAMPLE_SOLUTION.getType(), opCode); + return this.removeById(id) && ret; + } + + /** + * 修改样本溶液 + * + * @param testRecordSampleSolutionDto + * @return + */ + @Override + public TestRecordSampleSolution updateTestRecordSampleSolution(TestRecordSampleSolutionDto testRecordSampleSolutionDto) { + TestRecordSampleSolution oldTestRecordSampleSolution = this.getOne(Wrappers.lambdaQuery().eq(TestRecordSampleSolution::getId, testRecordSampleSolutionDto.getId())); + if (oldTestRecordSampleSolution == null) { + throw new RuntimeException(String.format("没有找到ID为%s的样本溶液!", testRecordSampleSolutionDto.getId())); + } + BeanUtils.copyProperties(testRecordSampleSolutionDto, oldTestRecordSampleSolution); + //计算浓度 + oldTestRecordSampleSolution = this.calculatedConcentration(oldTestRecordSampleSolution); + return this.updateById(oldTestRecordSampleSolution) ? oldTestRecordSampleSolution : null; + } + + /** + * 计算浓度 + * + * @param testRecordSampleSolution + * @return + */ + public TestRecordSampleSolution calculatedConcentration(TestRecordSampleSolution testRecordSampleSolution) { + //计算原始浓度 + if (StrUtil.isNotBlank(testRecordSampleSolution.getWeighingValue())) { + BigDecimal weighingValue = new BigDecimal(testRecordSampleSolution.getWeighingValue()); + BigDecimal constantVolume = new BigDecimal(testRecordSampleSolution.getConstantVolume()); + BigDecimal originalConcentration = weighingValue.divide(constantVolume, 2, RoundingMode.HALF_UP); + testRecordSampleSolution.setOriginalConcentration(originalConcentration.toString()); + } + + //计算结果浓度 + if (StrUtil.isNotBlank(testRecordSampleSolution.getOriginalConcentration()) && StrUtil.isNotBlank(testRecordSampleSolution.getDilutionFactor()) && !testRecordSampleSolution.getDilutionFactor().equals("/")) { + BigDecimal originalConcentration = new BigDecimal(testRecordSampleSolution.getOriginalConcentration()); + BigDecimal dilutionFactor = new BigDecimal(testRecordSampleSolution.getDilutionFactor()); + BigDecimal resultConcentration = originalConcentration.divide(dilutionFactor, 2, RoundingMode.HALF_UP); + testRecordSampleSolution.setResultConcentration(resultConcentration.toString()); + } + return testRecordSampleSolution; + } + + /** + * 列表查询 + * + * @param testId + * @param keywords 样本编号模糊查询 + * @return + */ + @Override + public List getSolutionList(String testId, String keywords) { + return this.list(Wrappers.lambdaQuery() + .eq(TestRecordSampleSolution::getTestId, testId) + .like(StrUtil.isNotBlank(keywords), TestRecordSampleSolution::getSampleNo, keywords) + .orderByAsc(TestRecordSampleSolution::getSampleNo)); + } + + /** + * 分页查询 + * + * @param testId + * @param page + * @param keywords 样本编号模糊查询 + * @return + */ + @Override + public IPage getSolutionPage(Page page, String testId, String keywords) { + return this.page(page, Wrappers.lambdaQuery() + .eq(TestRecordSampleSolution::getTestId, testId) + .like(StrUtil.isNotBlank(keywords), TestRecordSampleSolution::getSampleNo, keywords) + .orderByAsc(TestRecordSampleSolution::getSampleNo)); + } + + /** + * ] + * 匹配称量数据 + * + * @param id + * @return + */ + @Override + public List matchingWeighing(String id) { + List testRecordSampleSolutionList = this.list(Wrappers.lambdaQuery().eq(TestRecordSampleSolution::getTestId, id)); + if (testRecordSampleSolutionList.size() == 0) { + throw new RuntimeException(String.format("没有找到ID为%s的实验!", id)); + } + Map> map = testRecordSampleSolutionList.stream().collect(Collectors.groupingBy(item -> item.getMaterialId())); + + List sampleSolutions = new ArrayList<>(); + Set keySet = map.keySet(); + + List idList = new ArrayList<>(); + for (String key : keySet) { + List solutionList = map.get(key); + if (solutionList.size() == 1) { + TestRecordSampleSolution solution = solutionList.get(0); + idList.add(solution.getId()); + } + sampleSolutions.addAll(solutionList); + } + + //如果匹配到了称量质量,那么就自动去计算浓度 + for (TestRecordSampleSolution testRecordSampleSolution : sampleSolutions) { + String weighingNum = ""; + if (idList.contains(testRecordSampleSolution.getId())) { + weighingNum = testRecordSampleSolution.getSampleNo() + "-1"; + } else { + weighingNum = testRecordSampleSolution.getSampleNo(); + } + R data = remoteBalanceRMaterialService.getWeightForNumber(weighingNum); + BigDecimal weighing = data.getData(); + if (weighing.compareTo(BigDecimal.ZERO) != 0) { + //计算原始浓度 + testRecordSampleSolution.setWeighingValue(weighing.toString()); + BigDecimal constantVolume = new BigDecimal(testRecordSampleSolution.getConstantVolume()); + BigDecimal originalConcentration = weighing.divide(constantVolume, 2, RoundingMode.HALF_UP); + testRecordSampleSolution.setOriginalConcentration(originalConcentration.toString()); + //计算结果浓度 + if (StrUtil.isNotBlank(testRecordSampleSolution.getDilutionFactor())) { + BigDecimal dilutionFactor = new BigDecimal(testRecordSampleSolution.getDilutionFactor()); + BigDecimal resultConcentration = originalConcentration.divide(dilutionFactor, 2, RoundingMode.HALF_UP); + testRecordSampleSolution.setResultConcentration(resultConcentration.toString()); + } else { + testRecordSampleSolution.setResultConcentration(originalConcentration.toString()); + } + } + } + return this.updateBatchById(testRecordSampleSolutionList) ? testRecordSampleSolutionList : null; + } + + /** + * 为任务创建所有检材对应的样本溶液 + * + * @param testId + * @return + */ + @Override + public boolean createTaskSamSol(String testId) { + TestRecordVo vo = testRecordMapper.getTestRecordMapById(testId); + if (StringUtils.isNotBlank(vo.getBusinessType()) && !vo.getBusinessType().startsWith("2")) { + return true; + } + List sampleSolutionList = new ArrayList<>(); + List sampleTestList = vo.getSampleTestList(); + this.remove(Wrappers.lambdaQuery().eq(TestRecordSampleSolution::getTestId, testId)); + if (sampleTestList != null && sampleTestList.size() > 0) { + List solutions = new ArrayList<>(); + List sampleInfoList = sampleInfoService.list(Wrappers.lambdaQuery().in(SampleInfo::getId, sampleTestList)); + for (SampleInfo sampleInfo : sampleInfoList) { + TestRecordSampleSolution testRecordSampleSolution = new TestRecordSampleSolution(); + testRecordSampleSolution.setId(IdWorker.get32UUID().toUpperCase()); + testRecordSampleSolution.setSampleNo(sampleInfo.getAcceptNo()); + testRecordSampleSolution.setMaterialId(sampleInfo.getId()); + testRecordSampleSolution.setTestId(vo.getId()); + testRecordSampleSolution.setSampleShape("/"); + testRecordSampleSolution.setDilutionName("/"); + testRecordSampleSolution.setConstantVolume("0.0"); + testRecordSampleSolution.setDilutionFactor("0"); + testRecordSampleSolution.setOriginalConcentration("/"); + testRecordSampleSolution.setResultConcentration("/"); + testRecordSampleSolution.setWeighingValue("/"); + solutions.add(testRecordSampleSolution); + sampleSolutionList.add(testRecordSampleSolution.getId()); + } + vo.setSampleSolution(sampleSolutionList); + testRecordService.updateById(vo); + return this.saveBatch(solutions); + } else return true; + } + + /* + * 复制样品溶液 + * + * @param testRecordSampleSolutionDto + * @return + */ + @Override + public List copySolution(TestRecordSampleSolutionDto testRecordSampleSolutionDto) { + TestRecordSampleSolution sampleSolution = this.getById(testRecordSampleSolutionDto.getId()); + List materialIdList = testRecordSampleSolutionDto.getMaterialIdList(); + ArrayList testRecordSampleSolutions = new ArrayList<>(); + TestRecordVo vo = testRecordMapper.getTestRecordMapById(sampleSolution.getTestId()); + List solutionIdList = new ArrayList<>(); + for (String id : materialIdList) { + SampleInfo sampleInfo = sampleInfoService.getById(id); + String acceptNo = sampleInfo.getAcceptNo(); + String sampleNo = this.createSampleNo(id, testRecordSampleSolutionDto.getTestId()); + TestRecordSampleSolution testRecordSampleSolution = new TestRecordSampleSolution(); + BeanUtils.copyProperties(sampleSolution, testRecordSampleSolution); + testRecordSampleSolution.setCreateBy(null); + testRecordSampleSolution.setUpdateBy(null); + testRecordSampleSolution.setCreateTime(null); + testRecordSampleSolution.setUpdateTime(null); + testRecordSampleSolution.setId(IdWorker.get32UUID().toUpperCase()); + testRecordSampleSolution.setSampleNo(sampleNo); + testRecordSampleSolution.setMaterialId(id); + testRecordSampleSolution.setSampleShape(sampleInfo.getForm()); + testRecordSampleSolutions.add(testRecordSampleSolution); + solutionIdList.add(testRecordSampleSolution.getId()); + } + List voSampleSolution = vo.getSampleSolution(); + voSampleSolution.addAll(solutionIdList); + vo.setSampleSolution(voSampleSolution); + if (this.saveBatch(testRecordSampleSolutions) && testRecordService.updateById(vo)) { + return testRecordSampleSolutions; + } else return null; + } + + @Override + public void isLoadSample(String acceptNo, String testId) { + SampleInjector sampleInjector = sampleInjectorService.getOne(Wrappers.lambdaQuery().eq(SampleInjector::getTestId, testId)); + if (sampleInjector == null) { + return; + } + String injectorInfo = sampleInjector.getInjectorInfo(); + if (injectorInfo == null) { + return; + } + JSONArray jsonArray = JSON.parseArray(injectorInfo); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + if (jsonObject.getString("sampleNo").equals(acceptNo)) { + throw new RuntimeException(String.format("编号为:%s的溶液已存在上样记录,请先修改上样记录后再进行操作!", acceptNo)); + } + } + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordServiceImpl.java new file mode 100644 index 0000000..f545294 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordServiceImpl.java @@ -0,0 +1,1529 @@ +package digital.laboratory.platform.inspection.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.io.file.FileNameUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.deepoove.poi.XWPFTemplate; +import com.deepoove.poi.config.Configure; +import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy; +import com.deepoove.poi.util.TableTools; +import com.deepoove.poi.xwpf.NiceXWPFDocument; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.common.oss.service.OssFile; +import digital.laboratory.platform.inspection.constant.BusinessType; +import digital.laboratory.platform.inspection.constant.TestRecordFileUrl; +import digital.laboratory.platform.inspection.constant.TestRecordSampleDataConstant; +import digital.laboratory.platform.inspection.dto.*; +import digital.laboratory.platform.inspection.entity.*; +import digital.laboratory.platform.inspection.constant.TestRecordArgumentType; +import digital.laboratory.platform.inspection.mapper.TestRecordMapper; +import digital.laboratory.platform.inspection.mapper.TestRecordSampleDataMapper; +import digital.laboratory.platform.inspection.mapper.TestTemplateMapper; +import digital.laboratory.platform.inspection.service.*; +import digital.laboratory.platform.inspection.utils.PageUtils; +import digital.laboratory.platform.inspection.utils.datafile.nps.NPSTestDetailDataStruct; +import digital.laboratory.platform.inspection.vo.ProcedureVo; +import digital.laboratory.platform.inspetion.api.entity.TestRecord; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import digital.laboratory.platform.inspection.vo.TestTemplateVo; +import digital.laboratory.platform.inspetion.api.entity.EntrustInfo; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.poi.xwpf.usermodel.*; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.ByteArrayInputStream; +import java.text.DecimalFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Service +@SuppressWarnings("all") +public class TestRecordServiceImpl extends ServiceImpl implements TestRecordService { + + @Resource + private SampleInfoService sampleInfoService; + + @Resource + private TestRecordMethodService testRecordMethodService; + + @Resource + private TestTemplateMapper testTemplateMapper; + + @Resource + private TestRecordInstrumentConditionService testRecordInstrumentConditionService; + + @Resource + private TestRecordReagentService testRecordReagentService; + + @Resource + private TestRecordInstrumentService testRecordInstrumentService; + + @Resource + private TestRecordStandardSolutionService testRecordStandardSolutionService; + + @Resource + private TestRecordSampleSolutionService testRecordSampleSolutionService; + + @Resource + private TestRecordSampleDataService testRecordSampleDataService; + + + @Resource + private OssFile ossFile; + @Resource + private EntrustInfoService entrustInfoService; + + @Resource + private SampleInjectorService sampleInjectorService; + + @Resource + private TestRecordSampleDataMapper testRecordSampleDataMapper; + + /** + * 创建一个实验 + * + * @param testRecord + * @param dlpUser 用户信息 + * @return + * @throws Exception + */ + @Transactional(rollbackFor = Exception.class) + @Override + public TestRecord createTestInstance(TestRecordDto testRecord, DLPUser dlpUser) throws Exception { + testRecord.setId(IdWorker.get32UUID().toUpperCase()); + List sampleInfos = new ArrayList<>(); + testRecord.setStatus(0); + // 设置开始时间 + testRecord.setTestStartDate(LocalDate.now()); + //通过样本ID创建实验 + if (testRecord.getSampleTestList() != null && testRecord.getSampleTestList().size() > 0) { + for (String sampleId : testRecord.getSampleTestList()) { + SampleInfo sampleInfo = sampleInfoService.getById(sampleId); + if (sampleInfo == null) { + throw new RuntimeException(String.format("没有找到ID为%s的样本!", sampleId)); + } + sampleInfo.setStatus(2); + sampleInfos.add(sampleInfo); + } + this.judgmentSampleType(sampleInfos);//判断是否有不同类型的检材 + testRecord.setId(IdWorker.get32UUID().toUpperCase()); + testRecord.setTestUserId(dlpUser.getId()); + testRecord.setTestSerialNumber(this.createTestNumber()); + testRecord.setBusinessType(sampleInfos.get(0).getBusinessType()); + + sampleInfoService.updateBatchById(sampleInfos);//更新检材状态 + return this.save(testRecord) ? testRecord : null; + + //通过业务ID创建实验 + } else if (testRecord.getBusinessDtoList() != null && testRecord.getBusinessDtoList().size() > 0) { + List businessDtoList = testRecord.getBusinessDtoList(); + this.judgmentBusinessType(businessDtoList);//判断是否有不同类型的业务 + businessDtoList.forEach(item -> { + List infos = sampleInfoService.getSampleInfoListForBusiness(item.getBusinessId(), dlpUser.getId()); + String businessType = item.getBusinessType(); + //如果是委托,需要更新一下委托的状态 + if (businessType.startsWith("1")) { + entrustInfoService.update(Wrappers.lambdaUpdate() + .eq(EntrustInfo::getId, item.getBusinessId()) + .set(EntrustInfo::getStatus, 1)); + } + sampleInfos.addAll(infos); + + }); + List sampleIdList = new ArrayList<>(); + if (sampleInfos.size() > 0) { + for (SampleInfo sampleInfo : sampleInfos) { + sampleIdList.add(sampleInfo.getId()); + sampleInfo.setStatus(2); + } + sampleInfoService.updateBatchById(sampleInfos); + } + testRecord.setTestUserId(dlpUser.getId()); + testRecord.setTestSerialNumber(this.createTestNumber()); + testRecord.setSampleTestList(sampleIdList); + testRecord.setBusinessType(testRecord.getBusinessDtoList().get(0).getBusinessType()); + + return this.save(testRecord) ? testRecord : null; + //创建空实验 + } else { + testRecord.setId(IdWorker.get32UUID().toUpperCase()); + testRecord.setTestUserId(dlpUser.getId()); + testRecord.setTestSerialNumber(this.createTestNumber()); + return this.save(testRecord) ? testRecord : null; + } + } + + /** + * 判断是否有不同类型的业务 + * + * @param businessDtoList : 业务集合 + */ + public void judgmentBusinessType(List businessDtoList) { + Map> map = businessDtoList.stream().collect(Collectors.groupingBy(item -> item.getBusinessType())); + if (map.keySet().size() > 1) { + throw new RuntimeException(String.format("实验创建失败,请选择相同类型的业务进行实验!")); + } + if (businessDtoList.get(0).getBusinessType().startsWith("1")) { + businessDtoList.forEach(item -> { + List sampleInfoList = sampleInfoService.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, item.getBusinessId())); + EntrustInfo entrustInfo = entrustInfoService.getById(item.getBusinessId()); + sampleInfoList.forEach(obj -> { + TestRecord record = this.getOne(Wrappers.lambdaQuery().like(TestRecord::getSampleTestList, obj.getId())); + if (record != null) { + throw new RuntimeException(String.format("%s中的其余检材已进行了编号为" + record.getTestSerialNumber() + "的实验,无法继续选择该委托!" + record.getId(), entrustInfo.getCaseName())); + } + }); + }); + } + } + + /** + * 判断是否有不同类型的检材 + * + * @param sampleInfoList : 检材集合 + */ + public void judgmentSampleType(List sampleInfoList) { + Map> map = sampleInfoList.stream().collect(Collectors.groupingBy(item -> item.getBusinessType())); + if (map.keySet().size() > 1) { + throw new RuntimeException(String.format("实验创建失败,请选择相同类型的检材进行实验!")); + } + String businessType = ""; + if (sampleInfoList.get(0).getBusinessType().startsWith("1")) { + Map> map1 = sampleInfoList.stream().collect(Collectors.groupingBy(item -> item.getBusinessId())); + Set keySet = map1.keySet(); + keySet.forEach(item -> { + EntrustInfo entrustInfo = entrustInfoService.getById(item); + List list = sampleInfoService.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, item)); + List list1 = map1.get(item); + if (list.size() != list1.size()) { + throw new RuntimeException(String.format("没有选择完%s下的所有检材!", entrustInfo.getCaseName())); + } + }); + } + } + + /** + * 使用模板 + * + * @param testRecord : 实验对象 + * @param templateId : 模板Id + */ + public void copyFromTemplate(TestRecord testRecord, String templateId) throws Exception { + //将模板内容赋值给实验 + TestTemplateVo testTemplateVo = testTemplateMapper.getTestTemplateMapById(templateId); + if (testTemplateVo.getUseCount() == null || testTemplateVo.getUseCount() == 0) { + testTemplateVo.setUseCount(1); + } else { + testTemplateVo.setUseCount(testTemplateVo.getUseCount() + 1); + } + //复制方法 + if (testTemplateVo.getTestMethods() != null && testTemplateVo.getTestMethods().size() > 0) { + testRecord.setTestMethodList(testTemplateVo.getTestMethods()); + } + //复制仪器设备 + if (testTemplateVo.getDeviceIdList() != null && testTemplateVo.getDeviceIdList().size() > 0) { + testRecord.setDeviceIdList(testTemplateVo.getDeviceIdList()); + } + //复制仪器设备条件 + if (testTemplateVo.getDeviceUseCondition() != null && testTemplateVo.getDeviceUseCondition().size() > 0) { + List idList = testRecordInstrumentConditionService.copyCondition(testTemplateVo.getDeviceUseCondition(), testRecord.getId()); + testRecord.setDeviceUseCondition(idList); + } + //复制试剂耗材 + if (testTemplateVo.getReagentConsumables() != null && testTemplateVo.getReagentConsumables().size() > 0) { + testRecord.setReagentConsumablesList(testTemplateVo.getReagentConsumables()); + } + //复制仪器条件Word + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ossFile.fileGet(TestRecordFileUrl.TEST_TEMPLATE_CATALOGUE.getFileUrl() + "/" + templateId + "/" + "仪器条件.docx", bos); + byte[] templateArray = bos.toByteArray(); + ByteArrayInputStream bis = new ByteArrayInputStream(templateArray); + ossFile.fileSave(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testRecord.getId() + "/" + "仪器条件.docx", bis); + testRecord.setTemplateName(testTemplateVo.getName()); + testTemplateMapper.updateById(testTemplateVo); + this.updateById(testRecord); + } + + /** + * 添加实验处理步骤 + * + * @param testRecord + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public TestRecord updateTestInstance(TestRecord testRecord) { + TestRecord record = this.getById(testRecord.getId()); + //样本溶液处理步骤 + if (StrUtil.isNotBlank(testRecord.getSampleSolutionProcessing())) { + record.setSampleSolutionProcessing(testRecord.getSampleSolutionProcessing()); + } else { + record.setSampleSolutionProcessing(""); + } + //标准溶液处理步骤 + if (StrUtil.isNotBlank(testRecord.getStandardSolutionProcessing())) { + record.setStandardSolutionProcessing(testRecord.getStandardSolutionProcessing()); + } else { + record.setStandardSolutionProcessing(""); + } + if (StringUtils.isNotBlank(testRecord.getTestProcessDes())) { + record.setTestProcessDes(testRecord.getTestProcessDes()); + } + return this.updateById(record) ? record : null; + } + + /** + * 通过实验ID查看实验 + * + * @param id + * @param dlpUser 用户信息 + * @return + */ + @Override + public TestRecordVo getTestRecord(String id, DLPUser dlpUser) { + TestRecordVo testRecordVo = baseMapper.getTestRecordMapById(id); + if (testRecordVo.getTestMethodList() != null && testRecordVo.getTestMethodList().size() > 0) { + this.getTestMethodName(testRecordVo); + } + if (StringUtils.isNotBlank(testRecordVo.getBusinessType())) { + testRecordVo.setBusinessTypeName(BusinessType.getBusinessTypeName(testRecordVo.getBusinessType())); + } + //需要判断这个实验是否由操作者创建的 + return testRecordVo.getTestUserId().equals(dlpUser.getId()) ? testRecordVo : null; + } + + /** + * 获取实验的方法名集合 + * + * @param testRecordVo + */ + public void getTestMethodName(TestRecordVo testRecordVo) { + List testMethodName = new ArrayList(); + List list = testRecordMethodService.list(Wrappers.lambdaQuery().in(TestRecordMethod::getId, testRecordVo.getTestMethodList())); + if (list.size() > 0) { + for (TestRecordMethod testRecordMethod : list) { + testMethodName.add(testRecordMethod.getMethodName()); + } + } + testRecordVo.setTestMethodName(testMethodName); + } + + /** + * 分页查询实验 + * + * @param page + * @param dlpUser :实验创建者 + * @param startTime :时间范围查询 + * @param endTime :时间范围查询 + * @param businessType + */ + @Override + public IPage getTestRecordPageList(Page page, DLPUser dlpUser, LocalDateTime startTime, LocalDateTime endTime, String businessType) { + IPage testRecordMapPage = baseMapper.getTestRecordMapPage(page, Wrappers.lambdaQuery() + .eq(TestRecord::getTestUserId, dlpUser.getId()) + .ge(startTime != null, TestRecord::getCreateTime, startTime) + .le(endTime != null, TestRecord::getCreateTime, endTime) + .eq(StrUtil.isNotBlank(businessType), TestRecord::getBusinessType, businessType) + .orderByDesc(TestRecord::getCreateTime)); + for (TestRecordVo testRecordVo : testRecordMapPage.getRecords()) { + if (testRecordVo.getTestMethodList() != null && testRecordVo.getTestMethodList().size() > 0) { + this.getTestMethodName(testRecordVo); + } + if (StringUtils.isNotBlank(testRecordVo.getBusinessType())) { + testRecordVo.setBusinessTypeName(BusinessType.getBusinessTypeName(testRecordVo.getBusinessType())); + } + } + return testRecordMapPage; + } + + /** + * 列表查询实验 + * + * @param dlpUser 用户信息 + */ + @Override + public List getTestRecordList(DLPUser dlpUser) { + List testRecordMapList = baseMapper.getTestRecordMapList(Wrappers.lambdaQuery() + .eq(TestRecord::getTestUserId, dlpUser.getId()) + .orderByDesc(TestRecord::getCreateTime)); + for (TestRecordVo testRecordVo : testRecordMapList) { + if (StringUtils.isNotBlank(testRecordVo.getBusinessType())) { + testRecordVo.setBusinessTypeName(BusinessType.getBusinessTypeName(testRecordVo.getBusinessType())); + } + if (testRecordVo.getTestMethodList() != null && testRecordVo.getTestMethodList().size() > 0) { + this.getTestMethodName(testRecordVo); + } + } + return testRecordMapList; + } + + /** + * 编号生成规则 + * + * @return + */ + public String createTestNumber() { + String number = "SXT"; + LocalDateTime localDateTime = LocalDateTime.now(); + number = number + LocalDateTimeUtil.format(localDateTime, "yyyyMMdd"); + List list = this.list(Wrappers.lambdaQuery().likeRight(TestRecord::getTestSerialNumber, number)); + if (list.size() == 0) { + number = number + "001"; + return number; + } else { + //保留三位小数 + number = number + String.format("%03d", list.size() + 1); + return number; + } + } + + /** + * 为实验添加或移除内容 + * + * @param testId 实验Id + * @param testRecordArgumentId 参数Id + * @param argument 参数类型 + * @param opCode 判断是添加还是删除 1 :添加 -1 :删除 + * @return + */ + @Override//opCode: + public boolean updateTestRecordArgument(String testId, String testRecordArgumentId, String argument, Integer opCode) { + TestRecord testRecord = baseMapper.getTestRecordMapById(testId); + List argumentIdList = new ArrayList<>(); + if (testRecord == null) { + throw new RuntimeException(String.format("没有找到ID为%s的实验", testId)); + } + + //添加或移除仪器设备 + if (argument.equals(TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT.getType())) { + if (testRecord.getDeviceIdList() != null && testRecord.getDeviceIdList().size() > 0) { + argumentIdList = testRecord.getDeviceIdList(); + } + this.updateArgument(argumentIdList, opCode, testRecordArgumentId); + testRecord.setDeviceIdList(argumentIdList); + + //添加或移除仪器条件 + } else if (argument.equals(TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT_CONDITION.getType())) { + if (testRecord.getDeviceUseCondition() != null && testRecord.getDeviceUseCondition().size() > 0) { + argumentIdList = testRecord.getDeviceUseCondition(); + } + this.updateArgument(argumentIdList, opCode, testRecordArgumentId); + testRecord.setDeviceUseCondition(argumentIdList); + + + //添加或移除方法 + } else if (argument.equals(TestRecordArgumentType.TEST_RECORD_ARGUMENT_METHOD.getType())) { + if (testRecord.getTestMethodList() != null && testRecord.getTestMethodList().size() > 0) { + argumentIdList = testRecord.getTestMethodList(); + } + this.updateArgument(argumentIdList, opCode, testRecordArgumentId); + testRecord.setTestMethodList(argumentIdList); + + //添加或移除试剂耗材 + } else if (argument.equals(TestRecordArgumentType.TEST_RECORD_ARGUMENT_REAGENT.getType())) { + if (testRecord.getReagentConsumablesList() != null && testRecord.getReagentConsumablesList().size() > 0) { + argumentIdList = testRecord.getReagentConsumablesList(); + } + this.updateArgument(argumentIdList, opCode, testRecordArgumentId); + testRecord.setReagentConsumablesList(argumentIdList); + + //添加或移除样本溶液 + } else if (argument.equals(TestRecordArgumentType.TEST_RECORD_ARGUMENT_SAMPLE_SOLUTION.getType())) { + if (testRecord.getSampleSolution() != null && testRecord.getSampleSolution().size() > 0) { + argumentIdList = testRecord.getSampleSolution(); + } + this.updateArgument(argumentIdList, opCode, testRecordArgumentId); + testRecord.setSampleSolution(argumentIdList); + + //添加或移除标准溶液 + } else if (argument.equals(TestRecordArgumentType.TEST_RECORD_ARGUMENT_STANDARD_SOLUTION.getType())) { + if (testRecord.getStandardSolution() != null && testRecord.getStandardSolution().size() > 0) { + argumentIdList = testRecord.getStandardSolution(); + } + this.updateArgument(argumentIdList, opCode, testRecordArgumentId); + testRecord.setStandardSolution(argumentIdList); + + //添加或移除样本 + } else if (argument.equals(TestRecordArgumentType.TEST_RECORD_ARGUMENT_SAMPLE_DATA.getType())) { + String businessType; + SampleInfo sampleInfo = sampleInfoService.getById(testRecordArgumentId); + businessType = sampleInfo.getBusinessType(); + //判断与实验的业务类型是否相同 + if (StringUtils.isNotBlank(testRecord.getBusinessType()) && !testRecord.getBusinessType().equals(businessType)) { + throw new RuntimeException(String.format("添加失败,请添加%s类型的样本!", BusinessType.getBusinessTypeName(testRecord.getBusinessType()))); + } + if (testRecord.getSampleTestList() != null && testRecord.getSampleTestList().size() > 0) { + //如果该实验已存在样本了,添加样本时就要判断是否为同一类型 + businessType = sampleInfoService.getById(testRecord.getSampleTestList().get(0)).getBusinessType(); + if (!businessType.equals(sampleInfo.getBusinessType())) { + throw new RuntimeException(String.format("添加失败,请添加相同类型的样本!")); + } + //添加检材时,需判是否已经存在其他实验选择了该检材相关的委托下其余的检材 + if (businessType.startsWith("1") && opCode == 1) { + this.addOrRemoveSample(sampleInfo.getBusinessId(), testId); + } + argumentIdList = testRecord.getSampleTestList(); + } else { + businessType = sampleInfo.getBusinessType(); + //添加检材时,需判是否已经存在其他实验选择了该检材相关的委托下其余的检材 + if (businessType.startsWith("1") && opCode == 1) { + this.addOrRemoveSample(sampleInfo.getBusinessId(), testId); + } + //如果是第一次添加检材,那么就给这个实验赋予这个检材的业务类型 + testRecord.setBusinessType(sampleInfo.getBusinessType()); + } + this.updateArgument(argumentIdList, opCode, testRecordArgumentId); + testRecord.setSampleTestList(argumentIdList); + } + return this.updateById(testRecord); + } + + /** + * 添加检材时,需判是否已经存在其他实验选择了该检材相关的委托下其余的检材 + * + * @param businessId + * @param testId + */ + public void addOrRemoveSample(String businessId, String testId) { + List sampleInfoList = sampleInfoService.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, businessId)); + EntrustInfo entrustInfo = entrustInfoService.getById(businessId); + sampleInfoList.forEach(item -> { + TestRecord record = this.getOne(Wrappers.lambdaQuery().like(TestRecord::getSampleTestList, item.getId())); + if (record != null && (!record.getId().equals(testId))) { + throw new RuntimeException(String.format("委托" + entrustInfo.getCaseName() + "中的其余检材已进行了编号为%s的实验,无法选择该检材!", record.getTestSerialNumber())); + } + }); + } + + /** + * 判断有没有向实验重复添加或者添加了无效的参数 + * + * @param argumentIdList 已添加的参数集合 + * @param opCode 1:添加 -1 移除 + * @param testRecordArgumentId 参数ID + */ + public void updateArgument(List argumentIdList, Integer opCode, String testRecordArgumentId) { + if (opCode == 1) { + if (argumentIdList.size() > 0 && argumentIdList.contains(testRecordArgumentId)) { + throw new RuntimeException(String.format("当前内容已添加至实验,请勿重复添加!")); + } + argumentIdList.add(testRecordArgumentId); + } else if (opCode == -1 && argumentIdList.contains(testRecordArgumentId)) { + boolean ret = argumentIdList.remove(testRecordArgumentId); + if (!ret) { + throw new RuntimeException(String.format("在实验中没有找到ID为%s的内容!", testRecordArgumentId)); + } + } + } + + /** + * 使用模板 + * + * @param testId + * @param templateId + * @return + * @throws Exception + */ + @Override + public TestRecord useTemplate(String testId, String templateId) throws Exception { + TestRecord testRecord = this.getById(testId); + this.copyFromTemplate(testRecord, templateId); + return testRecord; + } + + + /** + * 实验中不同流程的完成程度(只要在某个流程添加了数据,就传给前端true) + * + * @param testId + * @return + */ + @Override + public ProcedureVo getProcedure(String testId) { + TestRecordVo testRecordVo = baseMapper.getTestRecordMapById(testId); + ProcedureVo procedureVo = new ProcedureVo(); + if (StringUtils.isNotBlank(testRecordInstrumentConditionService.generatedOrNot(testId))) { + procedureVo.setSetInstrumentConditions(true); + } else { + procedureVo.setSetInstrumentConditions(false); + } + + if (testRecordVo.getTestMethodList() != null && testRecordVo.getTestMethodList().size() > 0) { + procedureVo.setTestRecordMethod(true); + } else { + procedureVo.setTestRecordMethod(false); + } + if (testRecordVo.getDeviceIdList() != null && testRecordVo.getDeviceIdList().size() > 0) { + procedureVo.setTestRecordInstrument(true); + } else { + procedureVo.setTestRecordInstrument(false); + } + if (testRecordVo.getReagentConsumablesList() != null && testRecordVo.getReagentConsumablesList().size() > 0) { + List testRecordReagentList = testRecordReagentService.list(Wrappers.lambdaQuery() + .in(TestRecordReagent::getCategory, "试剂", "耗材") + .in(TestRecordReagent::getId, testRecordVo.getReagentConsumablesList())); + + List testRecordStandardSubstanceList = testRecordReagentService.list(Wrappers.lambdaQuery() + .notIn(TestRecordReagent::getCategory, "试剂", "耗材") + .in(TestRecordReagent::getId, testRecordVo.getReagentConsumablesList())); + if (testRecordReagentList.size() > 0) { + procedureVo.setTestRecordReagentConsumables(true); + } else { + procedureVo.setTestRecordReagentConsumables(false); + } + if (testRecordStandardSubstanceList.size() > 0) { + procedureVo.setTestRecordStandardSubstance(true); + } else { + procedureVo.setTestRecordStandardSubstance(false); + } + } + procedureVo.setTestRecordReagentConsumables(true); + if (testRecordVo.getStandardSolution() != null && testRecordVo.getStandardSolution().size() > 0 && testRecordVo.getSampleSolution() != null && testRecordVo.getSampleSolution().size() > 0) { + procedureVo.setPretreatment(true); + } else { + procedureVo.setPretreatment(false); + } + if (testRecordVo.getSampleTestList() != null && testRecordVo.getSampleTestList().size() > 0) { + procedureVo.setSampleInfo(true); + } else { + procedureVo.setSampleInfo(false); + } + procedureVo.setEmbarkation(true); + procedureVo.setResultAnalysis(testRecordSampleDataService.whetherSave(testId)); + return procedureVo; + } + + /** + * 获取打印数据 + * + * @param businessId + * @return + */ + @Override + public Map getPrintData(String businessId) throws Exception { + //这个委托下检材信息 + List sampleInfos = sampleInfoService.list(Wrappers.lambdaQuery().eq(SampleInfo::getBusinessId, businessId)); + ArrayList sampleNoList = new ArrayList<>(); + ArrayList sampleIdList = new ArrayList<>(); + sampleInfos.forEach(item -> { + sampleNoList.add(item.getAcceptNo()); + sampleIdList.add(item.getId()); + }); + EntrustInfo entrustInfo = entrustInfoService.getById(businessId); + String businessType = entrustInfo.getBusinessType(); + TestRecord vo = new TestRecord(); + + //查询实验 + for (String sampleId : sampleIdList) { + TestRecord testRecord = this.getOne(Wrappers.lambdaQuery().like(TestRecord::getSampleTestList, sampleId)); + if (testRecord != null) { + vo = testRecord; + break; + } + } + testRecordInstrumentConditionService.mergeFile(vo.getId()); + HashMap data = new HashMap<>(); + //构建检验记录的参数 + data.put("acceptNo", entrustInfo.getAcceptNo()); + if (vo.getTestMethodList() != null && vo.getTestMethodList().size() > 0) { + List testRecordMethods = testRecordMethodService.list(Wrappers.lambdaQuery().in(TestRecordMethod::getId, vo.getTestMethodList())); + if (BusinessType.NPS_CASE.getBusinessType().equals(businessType)) { + String method = ""; + for (TestRecordMethod testRecordMethod : testRecordMethods) { + if (method.equals("")) { + method = "☑ " + testRecordMethod.getMethodName(); + } else { + method = method + "\n" + "☑ " + testRecordMethod.getMethodName(); + } + } + method = method + "\n" + "□ " + "其他"; + data.put("method", method); + } + data.put("testRecordMethods", testRecordMethods); + } + if (vo.getDeviceIdList() != null && vo.getDeviceIdList().size() > 0) { + List testRecordInstruments = testRecordInstrumentService.list(Wrappers.lambdaQuery().in(TestRecordInstrument::getId, vo.getDeviceIdList())); + data.put("testRecordInstruments", testRecordInstruments); + } + if (vo.getStandardSolution() != null && vo.getStandardSolution().size() > 0) { + List testRecordStandardSolutions = testRecordStandardSolutionService.list(Wrappers.lambdaQuery().in(TestRecordStandardSolution::getId, vo.getStandardSolution()).eq(TestRecordStandardSolution::getSolutionType, "STD")); + testRecordStandardSolutions.forEach(item -> { + item.setExpirationDatePrint(item.getExpirationDate().getYear() + "-" + item.getExpirationDate().getMonthValue() + "-" + item.getExpirationDate().getDayOfMonth()); + item.setMadeDatePrint(item.getMadeDate().getYear() + "-" + item.getMadeDate().getMonthValue() + "-" + item.getMadeDate().getDayOfMonth()); + }); + data.put("testRecordStandardSolutions", testRecordStandardSolutions); + } + if (vo.getSampleSolution() != null && vo.getSampleSolution().size() > 0) { + List testRecordSampleSolutions = testRecordSampleSolutionService.list(Wrappers.lambdaQuery().eq(TestRecordSampleSolution::getTestId, vo.getId()).in(TestRecordSampleSolution::getMaterialId, sampleIdList).orderByAsc(TestRecordSampleSolution::getSampleNo)); + Collections.sort(testRecordSampleSolutions, new Comparator() { + @Override + public int compare(TestRecordSampleSolution o1, TestRecordSampleSolution o2) { + Integer o1No = Integer.parseInt(o1.getSampleNo().substring(o1.getSampleNo().lastIndexOf("-") + 1)); + Integer o2No = Integer.parseInt(o2.getSampleNo().substring(o2.getSampleNo().lastIndexOf("-") + 1)); + return Integer.compare(o1No, o2No); + } + }); + for (int i = 0; i < testRecordSampleSolutions.size(); i++) { + testRecordSampleSolutions.get(i).setPrintSampleName(i + 1 + "号检材"); + } + data.put("testRecordSampleSolutions", testRecordSampleSolutions); + } + //缴获物检验记录数据 + if (BusinessType.NPS_CASE.getBusinessType().equals(businessType)) { + List npsCaseTestDataDtos = new ArrayList<>(); + List stdDataList = new ArrayList<>(); + List npsCaseTestDataDtoList = (List) testRecordSampleDataService.getSampleTestDataByBusiness(entrustInfo.getId()); + //判断是标准溶液数据还是样本的数据 + for (NPSCaseTestDataDto npsCaseTestDataDto : npsCaseTestDataDtoList) { + if (TestRecordSampleDataConstant.SAMPLE_TYPE_STD.equals(npsCaseTestDataDto.getSampleType())) { + stdDataList.add(npsCaseTestDataDto); + data.put("stdDataList", stdDataList); + } else { + npsCaseTestDataDtos.add(npsCaseTestDataDto); + data.put("npsCaseTestDataDtos", npsCaseTestDataDtos); + } + } + //生物样本检验记录数据 + } else { + //鉴定过程 + List appraisalProcessDtoList = new ArrayList<>(); + if (StringUtils.isNotBlank(vo.getStandardSolutionProcessing())) { + appraisalProcessDtoList.add(new AppraisalProcessDto(vo.getStandardSolutionProcessing())); + + } + if (StringUtils.isNotBlank(vo.getSampleSolutionProcessing())) { + appraisalProcessDtoList.add(new AppraisalProcessDto(vo.getSampleSolutionProcessing())); + } + + if (StringUtils.isNotBlank(vo.getTestProcessDes())) { + appraisalProcessDtoList.add(new AppraisalProcessDto(vo.getTestProcessDes())); + } + data.put("appraisalProcessDtoList", appraisalProcessDtoList); + + List hairSewageDataDtoList = new ArrayList<>(); + List hairSewageDataDtos = new ArrayList<>(); + List list = (List) testRecordSampleDataService.getSampleTestDataByBusiness(entrustInfo.getId()); + Map> map = list.stream().collect(Collectors.groupingBy(item -> item.getSampleType())); + List bls = testRecordStandardSolutionService.list(Wrappers.lambdaQuery().eq(TestRecordStandardSolution::getTestId, vo.getId()).eq(TestRecordStandardSolution::getSolutionType, "BLS")); + List blk = testRecordStandardSolutionService.list(Wrappers.lambdaQuery().eq(TestRecordStandardSolution::getTestId, vo.getId()).eq(TestRecordStandardSolution::getSolutionType, "BLK")); + Set keySet = map.keySet(); + + keySet.forEach(key -> { + if (key.equals("STD")) { + hairSewageDataDtoList.addAll(map.get(key)); + data.put("STDIndex", map.get(key).size()); + } + }); + keySet.forEach(key -> { + if (key.equals("QC")) { + hairSewageDataDtoList.addAll(map.get(key)); + data.put("QCIndex", map.get(key).size()); + } + }); + //根据选取的溶液创建数据 + if (blk != null && blk.size() > 0) { + //创建空白溶剂 + for (TestRecordStandardSolution testRecordStandardSolution : blk) { + HairSewageDataDto hairSewageDataDto = new HairSewageDataDto(); + hairSewageDataDto.setSampleNo(testRecordStandardSolution.getNumber()); + hairSewageDataDto.setSampleType("空白溶剂"); + hairSewageDataDto.setTmpPeakAreaUp("/"); + hairSewageDataDto.setTmpIonAbundanceRatio("/"); + hairSewageDataDto.setTmpTargetRtTime("/"); + hairSewageDataDto.setTmpRtTimeError("/"); + hairSewageDataDto.setCompoundName("/"); + hairSewageDataDto.setTmpPeakAreaDown("/"); + hairSewageDataDto.setTmpIonAbundanceRatioWithinError("/"); + hairSewageDataDto.setRtTimeWithinError("/"); + hairSewageDataDto.setQualitativeIonPairUp("/"); + hairSewageDataDto.setQualitativeIonPairDown("/"); + hairSewageDataDto.setWhetherCheckOut("/"); + hairSewageDataDtoList.add(hairSewageDataDto); + data.put("BLKIndex", blk.size()); + } + } + if (bls != null && blk.size() > 0) { + //创建空白样品 + for (TestRecordStandardSolution testRecordStandardSolution : bls) { + HairSewageDataDto hairSewageDataDto = new HairSewageDataDto(); + hairSewageDataDto.setSampleNo(testRecordStandardSolution.getNumber()); + hairSewageDataDto.setSampleType("空白样品"); + hairSewageDataDto.setTmpPeakAreaUp("/"); + hairSewageDataDto.setTmpIonAbundanceRatio("/"); + hairSewageDataDto.setTmpTargetRtTime("/"); + hairSewageDataDto.setTmpRtTimeError("/"); + hairSewageDataDto.setTmpPeakAreaDown("/"); + hairSewageDataDto.setCompoundName("/"); + hairSewageDataDto.setTmpIonAbundanceRatioWithinError("/"); + hairSewageDataDto.setRtTimeWithinError("/"); + hairSewageDataDto.setQualitativeIonPairUp("/"); + hairSewageDataDto.setQualitativeIonPairDown("/"); + hairSewageDataDto.setWhetherCheckOut("/"); + hairSewageDataDtoList.add(hairSewageDataDto); + data.put("BLSIndex", bls.size()); + } + } + keySet.forEach(key -> { + if (key.equals("Analyte")) { + ArrayList hairSewageDataDtos2 = new ArrayList<>(); + List hairSewageDataDtos1 = map.get(key); + //按照化合物进行分组 + Map> map2 = hairSewageDataDtos1.stream().collect(Collectors.groupingBy(item -> item.getCompoundName())); + Set keySet2 = map2.keySet(); + for (String compoundName : keySet2) { + List hairSewageDataDtos4 = map2.get(compoundName); + //分组来组装数据,因为生物样本的数据会有两条溶液编号一样的结果数据,我们需要对数据进行加工,在溶液编号后面加上-1和-2 + Map> map1 = hairSewageDataDtos4.stream().collect(Collectors.groupingBy(item -> item.getSampleNo())); + Set keySet1 = map1.keySet(); + List list1 = new ArrayList<>(keySet1); + Integer x = 0; + //对溶液数据进行排序 + Collections.sort(list1, new Comparator() { + @Override + public int compare(String o1, String o2) { + int num1 = Integer.parseInt(o1.substring(o1.lastIndexOf("-") + 1)); + int num2 = Integer.parseInt(o2.substring(o2.lastIndexOf("-") + 1)); + return Integer.compare(num1, num2); + } + }); + for (String key1 : list1) { + List hairSewageDataDtos3 = map1.get(key1); + Collections.sort(hairSewageDataDtos3, new Comparator() { + @Override + public int compare(HairSewageDataDto o1, HairSewageDataDto o2) { + return o1.getSampleName().compareTo(o2.getSampleName()); + } + }); + if (hairSewageDataDtos3.size() != 1) { + for (int i = 0; i < hairSewageDataDtos3.size(); i++) { + HairSewageDataDto hairSewageDataDto = hairSewageDataDtos3.get(i); + hairSewageDataDto.setSampleNo(hairSewageDataDto.getSampleNo() + "-" + (i + 1)); + hairSewageDataDtos2.add(hairSewageDataDto); + } + } else { + hairSewageDataDtos2.add(hairSewageDataDtos3.get(0)); + } +// if (dto1.getWhetherCheckOut().equals("是") && dot2.getWhetherCheckOut().equals("是")) { +// } + } + } + hairSewageDataDtoList.addAll(hairSewageDataDtos2); + } + }); + //处理数据类型格式转化问题 + hairSewageDataDtoList.forEach(item -> { + switch (item.getSampleType()) { + case "STD": + item.setSampleType("标准溶液"); + break; + case "QC": + item.setSampleType("质控样品"); + break; + case "Analyte": + item.setSampleType(item.getSampleNo()); + break; + } + if (!item.getSampleType().startsWith("空")) { + if (item.getTargetRtTime() == -999.0 || item.getTargetRtTime() == 0.00) { + item.setTmpTargetRtTime("/"); + } else { + item.setTmpTargetRtTime(String.format("%.02f", item.getTargetRtTime())); + } + if (item.getRtTimeError() == -999.0 || item.getRtTimeError() == -100 || item.getRtTimeError() == 0.00) { + item.setTmpRtTimeError("/"); + } else { + item.setTmpRtTimeError(String.format("%.02f", item.getRtTimeError())); + } + if (item.getIonAbundanceRatioWithinError() == -999.0 || item.getIonAbundanceRatioWithinError() == -100) { + item.setTmpIonAbundanceRatioWithinError("/"); + } else { + item.setTmpIonAbundanceRatioWithinError(String.format("%.02f", item.getIonAbundanceRatioWithinError())); + } + if (item.getPeakAreaUp() == 0.00) { + item.setTmpPeakAreaUp("/"); + } else { + item.setTmpPeakAreaUp(String.format("%.02f", item.getPeakAreaUp())); + } + + if (item.getPeakAreaDown() == 0.00) { + item.setTmpPeakAreaDown("/"); + } else { + item.setTmpPeakAreaDown(String.format("%.02f", item.getPeakAreaDown())); + } + if (item.getIonAbundanceRatio() == 0.00) { + item.setTmpIonAbundanceRatio("/"); + } else { + item.setTmpIonAbundanceRatio(String.format("%.02f", item.getIonAbundanceRatio())); + } + } + + HairSewageDataDto hairSewageDataDto = new HairSewageDataDto(); + BeanUtils.copyProperties(item, hairSewageDataDto); + if (item.getQualitativeIonPairDown() != null) { + hairSewageDataDto.setQualitativeIonPairUp(item.getQualitativeIonPairDown()); + hairSewageDataDto.setQualitativeIonPairUp(item.getQualitativeIonPairDown()); + } + if (item.getPeakAreaDown() != 0.0) { + hairSewageDataDto.setTmpPeakAreaUp(String.format("%.02f", item.getPeakAreaDown())); + } + hairSewageDataDtos.add(item); + hairSewageDataDtos.add(hairSewageDataDto); + }); + data.put("hairSewageDataDtos", hairSewageDataDtos); + String results = testRecordSampleDataService.generateQualitativeResults(businessId); + data.put("results", results); + } + data.put("createTime", LocalDateTimeUtil.format(entrustInfo.getAcceptDate(), "yyyy年MM月dd日")); + data.put("vo", vo); + return data; + } + + /** + * 创建生物样本检验记录 + * + * @param businessId + * @return + * @throws Exception + */ + @Override + public boolean createInspectionRecordByBiological(String businessId) throws Exception { + Map data = this.getPrintData(businessId); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + TestRecord vo = (TestRecord) data.get("vo"); + ossFile.fileGet(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + vo.getId() + "/" + "生物样本检验记录.docx", bos); + byte[] templateArray = bos.toByteArray(); + ByteArrayInputStream bis = new ByteArrayInputStream(templateArray); + bos.close(); + + LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy(); + Configure config = Configure.builder(). + bind("testRecordMethods", policy) + .bind("testRecordInstruments", policy) + .bind("testRecordStandardSolutions", policy) + .bind("testRecordSampleSolutions", policy) + .bind("hairSewageDataDtos", policy) + .bind("appraisalProcessDtoList", policy) + .build(); + XWPFTemplate template = XWPFTemplate.compile(bis, config).render( + new HashMap() {{ + put("testRecordMethods", data.get("testRecordMethods")); + put("testRecordInstruments", data.get("testRecordInstruments")); + put("testRecordStandardSolutions", data.get("testRecordStandardSolutions")); + put("testRecordSampleSolutions", data.get("testRecordSampleSolutions")); + put("createTime", data.get("createTime")); + put("acceptNo", data.get("acceptNo")); + put("hairSewageDataDtos", data.get("hairSewageDataDtos")); + put("results", data.get("results")); + put("appraisalProcessDtoList", data.get("appraisalProcessDtoList")); + }} + ); + NiceXWPFDocument document = template.getXWPFDocument(); + XWPFTable table = document.getTables().get(3); + List hairSewageDataDtos = (List) data.get("hairSewageDataDtos"); + int size = hairSewageDataDtos.size() / 2; + int mergeIndex = 2; + //合并单元格 + for (int i = 0; i < size; i++) { + TableTools.mergeCellsVertically(table, 0, mergeIndex, mergeIndex + 1); + TableTools.mergeCellsVertically(table, 1, mergeIndex, mergeIndex + 1); + TableTools.mergeCellsVertically(table, 2, mergeIndex, mergeIndex + 1); + TableTools.mergeCellsVertically(table, 3, mergeIndex, mergeIndex + 1); + TableTools.mergeCellsVertically(table, 4, mergeIndex, mergeIndex + 1); + TableTools.mergeCellsVertically(table, 7, mergeIndex, mergeIndex + 1); + TableTools.mergeCellsVertically(table, 8, mergeIndex, mergeIndex + 1); + TableTools.mergeCellsVertically(table, 9, mergeIndex, mergeIndex + 1); + mergeIndex += 2; + } + int stdIndex = (int) data.get("STDIndex") * 2; + int qcIndex = (int) data.get("QCIndex") * 2; + System.out.println(stdIndex); + //根据标准溶液和质控溶液的数量来确定合并多少行 + TableTools.mergeCellsVertically(table, 0, 2, stdIndex + 1); + TableTools.mergeCellsVertically(table, 0, stdIndex + 2, stdIndex + 2 + qcIndex - 1); + List paragraphs = document.getParagraphs(); + for (int i = 0; i < paragraphs.size(); i++) { + XWPFParagraph paragraph = paragraphs.get(i); + + // 检查段落内容是否为空 + if (paragraph.getParagraphText().trim().isEmpty()) { + // 删除空白段落 + document.removeBodyElement(document.getPosOfParagraph(paragraph)); + i--; // 更新索引以考虑删除的段落 + } + } + + bis.close(); + ByteArrayOutputStream fosWord = new ByteArrayOutputStream(); + template.write(fosWord); + template.close(); + ByteArrayInputStream fisWord = new ByteArrayInputStream(fosWord.toByteArray()); + fosWord.close(); + document.close(); + return ossFile.fileSave(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + businessId + "/" + "生物样本检验记录.docx", fisWord); + } + + /** + * 创建缴获物检验记录 + * + * @param businessId + * @return + * @throws Exception + */ + public boolean createInspectionRecordBySeizure(String businessId) throws Exception { + Map data = this.getPrintData(businessId); + String fileName = "缴获物检验记录.docx"; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + TestRecord vo = (TestRecord) data.get("vo"); + ossFile.fileGet(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + vo.getId() + "/" + fileName, bos); + byte[] templateArray = bos.toByteArray(); + ByteArrayInputStream bis = new ByteArrayInputStream(templateArray); + bos.close(); + + List npsCaseTestDataDtos = (List) data.get("npsCaseTestDataDtos"); + if (npsCaseTestDataDtos != null && npsCaseTestDataDtos.size() != 0) { + List sampleDataList = new ArrayList<>(); + Collections.sort(npsCaseTestDataDtos, new Comparator() { + @Override + public int compare(NPSCaseTestDataDto o1, NPSCaseTestDataDto o2) { + return o1.getSampleNo().compareTo(o2.getSampleNo()); + } + }); + for (NPSCaseTestDataDto npsCaseTestDataDto : npsCaseTestDataDtos) { + List testSampleDataList = npsCaseTestDataDto.getTestSampleDataList(); + for (NPSTestDetailDataStruct npsTestDetailDataStruct : testSampleDataList) { + NPSCaseTestSampleData sampleData = new NPSCaseTestSampleData(); + this.disposalData(npsCaseTestDataDto, npsTestDetailDataStruct, sampleData); + sampleDataList.add(sampleData); + } + } + data.put("sampleDataList", sampleDataList); + } + + LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy(); + Configure config = Configure.builder() + .bind("testRecordMethods", policy) + .bind("testRecordInstruments", policy) + .bind("testRecordStandardSolutions", policy) + .bind("testRecordSampleSolutions", policy) + .bind("npsCaseTestDataDtoList", policy) + .bind("sampleDataList", policy) + .build(); + XWPFTemplate template = XWPFTemplate.compile(bis, config).render( + new HashMap() {{ + put("testRecordMethods", data.get("testRecordMethods")); + put("testRecordInstruments", data.get("testRecordInstruments")); + put("testRecordStandardSolutions", data.get("testRecordStandardSolutions")); + put("testRecordSampleSolutions", data.get("testRecordSampleSolutions")); + put("createTime", data.get("createTime")); + put("acceptNo", data.get("acceptNo")); + put("method", data.get("method")); + put("sampleDataList", data.get("sampleDataList")); + }} + ); + bis.close(); + ByteArrayOutputStream fosWord = new ByteArrayOutputStream(); + NiceXWPFDocument xwpfDocument = template.getXWPFDocument(); + List stdDataList = (List) data.get("stdDataList"); + if (stdDataList != null && stdDataList.size() != 0) { + //创建标准溶液的数据表格 + XWPFTable stdTable = xwpfDocument.createTable(stdDataList.size() * 6, 4); + int index = 0; + for (int i = 0; i < stdDataList.size(); i++) { + NPSCaseTestDataDto npsCaseTestDataDto = stdDataList.get(i); + XWPFTableRow row1 = stdTable.getRow(index); + row1.getCell(0).setText(npsCaseTestDataDto.getCompoundName()); + row1.getCell(1).setText(npsCaseTestDataDto.getStdConcentration()); + row1.getCell(2).setText("保留时间"); + row1.getCell(3).setText(String.valueOf(npsCaseTestDataDto.getStdRtTime())); + XWPFTableRow row2 = stdTable.getRow(index + 1); + row2.getCell(0).setText("m/z"); + row2.getCell(1).setText("S/N"); + row2.getCell(2).setText("峰面积"); + row2.getCell(3).setText("丰度比"); + List testSampdleDataList = npsCaseTestDataDto.getTestSampleDataList(); + for (int j = 0; j < testSampdleDataList.size(); j++) { + NPSTestDetailDataStruct struct = testSampdleDataList.get(j); + XWPFTableRow row3 = stdTable.getRow(index + 2 + j); + //判断是不是基峰 + if (struct.getIsBasePeak() == 1) { + row3.getCell(0).setText(String.valueOf((int) Double.parseDouble(struct.getMass())) + "*"); + } else { + row3.getCell(0).setText(String.valueOf((int) Double.parseDouble(struct.getMass()))); + } + row3.getCell(1).setText(String.format("%.02f", struct.getSn())); + row3.getCell(2).setText(String.valueOf((int) struct.getArea())); + if (Double.compare(struct.getAbundanceRatio(), -999) == 0) { + row3.getCell(3).setText("/"); + } else { + row3.getCell(3).setText(String.format("%.02f", struct.getAbundanceRatio()) + "%"); + } + } + index = index + 6; + } + //设置文本居中 + for (XWPFTableRow row : stdTable.getRows()) { + for (XWPFTableCell cell : row.getTableCells()) { + for (XWPFParagraph paragraph : cell.getParagraphs()) { + paragraph.setAlignment(ParagraphAlignment.CENTER); + } + } + } + List rows = stdTable.getRows(); +// 设置宽度 + for (XWPFTableRow row : rows) { + for (int i = 0; i < 4; i++) { + row.getCell(i).setWidth("4200"); + } + } + xwpfDocument.setTable(6, stdTable); + //因为上面的方法会默认在word最后添加这个表格,所以我们要删除掉这个表格 + List tables = xwpfDocument.getTables(); + XWPFTable table = tables.get(tables.size() - 1); + xwpfDocument.removeBodyElement(xwpfDocument.getBodyElements().indexOf(table)); + } + + XWPFTable sampleDataTable = xwpfDocument.getTables().get(7); + XWPFTable resultTable = xwpfDocument.getTables().get(8); + + //设置需要合并的单元格 + int mergeIndex = 1; + for (int i = 0; i < npsCaseTestDataDtos.size(); i++) { + TableTools.mergeCellsVertically(sampleDataTable, 0, mergeIndex, mergeIndex + 3); + TableTools.mergeCellsVertically(sampleDataTable, 1, mergeIndex, mergeIndex + 3); + TableTools.mergeCellsVertically(sampleDataTable, 2, mergeIndex, mergeIndex + 3); + TableTools.mergeCellsVertically(resultTable, 0, mergeIndex, mergeIndex + 3); + TableTools.mergeCellsVertically(resultTable, 1, mergeIndex, mergeIndex + 3); + TableTools.mergeCellsVertically(resultTable, 2, mergeIndex, mergeIndex + 3); + TableTools.mergeCellsVertically(resultTable, 3, mergeIndex, mergeIndex + 3); + TableTools.mergeCellsVertically(resultTable, 4, mergeIndex, mergeIndex + 3); + TableTools.mergeCellsVertically(resultTable, 5, mergeIndex, mergeIndex + 3); + TableTools.mergeCellsVertically(resultTable, 12, mergeIndex, mergeIndex + 3); + mergeIndex = mergeIndex + 4; + } + template.write(fosWord); + template.close(); + ByteArrayInputStream fisWord = new ByteArrayInputStream(fosWord.toByteArray()); + fosWord.close(); + return ossFile.fileSave(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + businessId + "/" + fileName, fisWord); + } + + /** + * 处理打印数据 + * + * @param caseTest 仪器导出数据 + * @param dataStruct 仪器导出数据 + * @param sampleData 样本数据 + */ + public void disposalData(NPSCaseTestDataDto caseTest, NPSTestDetailDataStruct dataStruct, NPSCaseTestSampleData sampleData) { + DecimalFormat format = new DecimalFormat("#.00"); + sampleData.setStdConcentration(caseTest.getStdConcentration()); + sampleData.setRtTimeWithinError(caseTest.getRtTimeWithinError()); + sampleData.setSampleNo(caseTest.getSampleNo()); + sampleData.setTargetConcentration(caseTest.getTargetConcentration()); + + if (Double.compare(caseTest.getStdRtTime(), -999) == 0) { + sampleData.setStdRtTime("/"); + } else { + sampleData.setStdRtTime(String.format("%.02f", caseTest.getStdRtTime()) + "%"); + } + + if (Double.compare(caseTest.getRtTimeError(), -999) == 0) { + sampleData.setRtTimeError("/"); + } else { + sampleData.setRtTimeError(String.format("%.02f", caseTest.getRtTimeError()) + "%"); + } + + if (Double.compare(caseTest.getTargetRtTime(), -999) == 0) { + sampleData.setTargetRtTime("/"); + } else { + sampleData.setTargetRtTime(String.format("%.02f", caseTest.getTargetRtTime()) + "%"); + } + + //判断是不是基峰 + if (dataStruct.getIsBasePeak() == 1) { + sampleData.setMass(String.valueOf((int) Double.parseDouble(dataStruct.getMass())) + "*"); + } else { + sampleData.setMass(String.valueOf((int) Double.parseDouble(dataStruct.getMass()))); + } + + if (Double.compare(dataStruct.getAbundanceRatio(), -999) == 0) { + sampleData.setAbundanceRatio("/"); + } else { + sampleData.setAbundanceRatio(String.format("%.02f", dataStruct.getAbundanceRatio()) + "%"); + } + + if (Double.compare(dataStruct.getAbundanceRatio_std(), -999) == 0) { + sampleData.setAbundanceRatio_std("/"); + } else { + sampleData.setAbundanceRatio_std(String.format("%.02f", dataStruct.getAbundanceRatio_std()) + "%"); + } + + if (Double.compare(dataStruct.getAbundanceRatioError(), -999) == 0) { + sampleData.setAbundanceRatioError("/"); + } else { + sampleData.setAbundanceRatioError(String.format("%.02f", dataStruct.getAbundanceRatioError()) + "%"); + } + + if (Double.compare(dataStruct.getErrorRange(), -999) == 0) { + sampleData.setErrorRange("/"); + } else { + sampleData.setErrorRange("±" + (int) dataStruct.getErrorRange() + "%"); + } + + if (caseTest.getIsDetected() == 0) { + sampleData.setCompoundName("未检出" + caseTest.getCompoundName()); + } else if (caseTest.getIsDetected() == 1) { + sampleData.setCompoundName("检出" + caseTest.getCompoundName()); + } + sampleData.setWithinError(dataStruct.getWithinError()); + sampleData.setArea(String.valueOf((int) dataStruct.getArea())); + sampleData.setSn(String.format("%.02f", dataStruct.getSn())); + } + + /** + * 创建检验记录 + * + * @param businessId + * @param type + * @return + * @throws Exception + */ + @Override + public boolean createInspectionRecord(String businessId) throws Exception { + EntrustInfo entrustInfo = entrustInfoService.getById(businessId); + /** + * @apiNote invivo 生物样本 + * @apiNote inVitro 缴获物 + */ + if (entrustInfo.getBusinessType().equals(BusinessType.BOINT_CASE.getBusinessType())) { + return this.createInspectionRecordByBiological(businessId); + } else { + return this.createInspectionRecordBySeizure(businessId); + } + } + + /** + * 删除实验 + * + * @param testId + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean delTestRecord(String testId) { + TestRecordVo vo = baseMapper.getTestRecordMapById(testId); + if (vo.getStatus() >= 5) { + throw new RuntimeException(String.format("该实验已上机,无法删除!")); + } + List sampleTestList = vo.getSampleTestList(); + if (sampleTestList != null && sampleTestList.size() > 0) { + List sampleInfoList = sampleInfoService.list(Wrappers.lambdaQuery().in(SampleInfo::getId, sampleTestList)); + sampleInfoList.forEach(sampleInfo -> sampleInfo.setStatus(1)); + sampleInfoService.updateBatchById(sampleInfoList); + } + testRecordSampleSolutionService.remove(Wrappers.lambdaQuery().eq(TestRecordSampleSolution::getTestId, testId)); + testRecordStandardSolutionService.remove(Wrappers.lambdaQuery().eq(TestRecordStandardSolution::getTestId, testId)); + + //文件集合:包括仪器条件、检验记录 + List fileNameList = ossFile.fileList(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId); + if (fileNameList != null && fileNameList.size() > 0) { + fileNameList.forEach(fileName -> { + try { + ossFile.fileDelete(TestRecordFileUrl.TEST_RECORD_CATALOGUE.getFileUrl() + "/" + testId + "/" + fileName); + } catch (Exception e) { + // 处理异常,可以记录日志或者回滚事务 + throw new RuntimeException("Failed to delete file: " + fileName, e); + } + }); + } + testRecordSampleDataService.remove(Wrappers.lambdaQuery().eq(TestRecordSampleData::getTestId, testId)); + sampleInjectorService.remove(Wrappers.lambdaQuery().eq(SampleInjector::getTestId, testId)); + return this.removeById(vo); + } + + /** + * 获取实验中所有的溶液列表 + * + * @param page + * @param testId + * @return + */ + @Override + public Page getResultSolutionPage(Page page, String testId) { + TestRecordVo vo = baseMapper.getTestRecordMapById(testId); + List standardSolutions = testRecordStandardSolutionService.list(Wrappers.lambdaQuery().eq(TestRecordStandardSolution::getTestId, testId).orderByAsc(TestRecordStandardSolution::getNumber)); + List sampleSolutions = testRecordSampleSolutionService.list(Wrappers.lambdaQuery().eq(TestRecordSampleSolution::getTestId, testId).orderByAsc(TestRecordSampleSolution::getSampleNo)); + List list = new ArrayList<>(); + + if (standardSolutions != null && standardSolutions.size() > 0) { + standardSolutions.forEach(item -> { + list.add(item.getNumber()); + }); + } + if (sampleSolutions != null && sampleSolutions.size() > 0) { + sampleSolutions.forEach(item -> { + list.add(item.getSampleNo()); + }); + } + return new PageUtils().getPages(page.getCurrent(), page.getSize(), list); + } + + /** + * 上传实验图谱 + * + * @param testId + * @param files + * @return + */ + @Override + public R uploadTestAtlas(String testId, MultipartFile file) throws Exception { + TestRecord testRecord = this.getById(testId); + if (testRecord == null) { + throw new RuntimeException(String.format("实验id为 %s 的数据在系统中不存在!", testId)); + } + // 取已上传过的实验图谱 + JSONArray testAtlas = StrUtil.isBlank(testRecord.getTestAtlas()) ? new JSONArray() : JSONArray.parseArray(testRecord.getTestAtlas()); + // 获取文件名list + List fileNameList = new ArrayList<>(); + for (int i = 0; i < testAtlas.size(); i++) { + JSONObject jsonObject = testAtlas.getJSONObject(i); + fileNameList.add(jsonObject.getString("fileName")); + } + // 拼接上传的路径,以实验id为文件夹 + String commonPath = TestRecordFileUrl.TEST_ATLAS_PATH.getFileUrl() + testRecord.getId(); + + // 生成一个文件id + String fileId = IdWorker.getIdStr(); + boolean upload = ossFile.fileUpload(file, commonPath); + String fileName = FileNameUtil.getName(file.getOriginalFilename()); + String type = file.getContentType(); + if (!upload) { + // 上传失败 + Map resultData = new HashMap<>(); + resultData.put("fileName", fileName); + resultData.put("path", commonPath); + return R.failed(resultData, "上传实验图谱删除失败"); + } + if (testAtlas.size() > 0) { + // 删除之前上传的 + JSONObject oldObject = testAtlas.getJSONObject(0); + ossFile.fileDelete(oldObject.getString("path")); + testAtlas = new JSONArray(); + } + JSONObject jsonObject = new JSONObject(); + jsonObject.put("fileId", fileId); + jsonObject.put("fileName", fileName); + jsonObject.put("type", type); + jsonObject.put("path", commonPath + "/" + fileName); + testAtlas.add(jsonObject); + + testRecord.setTestAtlas(testAtlas.toJSONString()); + if (this.updateById(testRecord)) { + return R.ok("上传实验图谱成功!"); + } else { + return R.failed("上传实验图谱失败!"); + } + } + + /** + * 上传实验图谱 + * + * @param testId + * @param files + * @return + */ + @Override + public R uploadTestAtlasBatch(String testId, List files) { + TestRecord testRecord = this.getById(testId); + if (testRecord == null) { + throw new RuntimeException(String.format("实验id为 %s 的数据在系统中不存在!", testId)); + } + // 取已上传过的实验图谱 + JSONArray testAtlas = StrUtil.isBlank(testRecord.getTestAtlas()) ? new JSONArray() : JSONArray.parseArray(testRecord.getTestAtlas()); + // 获取文件名list + List fileNameList = new ArrayList<>(); + for (int i = 0; i < testAtlas.size(); i++) { + JSONObject jsonObject = testAtlas.getJSONObject(i); + fileNameList.add(jsonObject.getString("fileName")); + } + // 拼接上传的路径,以实验id为文件夹 + String commonPath = TestRecordFileUrl.TEST_ATLAS_PATH.getFileUrl() + testRecord.getId(); + // 这里遍历要上传的文件 + for (MultipartFile file : files) { + // 获取id来防止因为文件名重复导致的问题 + String fileId = IdWorker.getIdStr(); + /*String filePath = commonPath + "/" + fileId + "/";*/ + boolean upload = ossFile.fileUpload(file, commonPath); + String fileName = FileNameUtil.getName(file.getOriginalFilename()); + String type = file.getContentType(); + if (!upload) { + // 上传失败 + Map resultData = new HashMap<>(); + resultData.put("fileName", fileName); + resultData.put("path", commonPath); + return R.failed(resultData, "上传实验图谱删除失败"); + } + if (fileNameList.contains(fileName)) { + // 文件名存在则不用在添加一个json对象 + continue; + } + JSONObject jsonObject = new JSONObject(); + jsonObject.put("fileId", fileId); + jsonObject.put("fileName", fileName); + jsonObject.put("type", type); + jsonObject.put("path", commonPath + "/" + fileName); + testAtlas.add(jsonObject); + } + testRecord.setTestAtlas(testAtlas.toJSONString()); + if (this.updateById(testRecord)) { + return R.ok("上传实验图谱成功!"); + } else { + return R.failed("上传实验图谱失败!"); + } + } + + /** + * 获取该实验id的实验图谱 + * + * @param testId + * @return + */ + @Override + public R getTestAtlasList(String testId) { + TestRecord testRecord = this.getById(testId); + if (testRecord == null) { + throw new RuntimeException(String.format("实验id为 %s 的数据在系统中不存在!", testId)); + } + if (StrUtil.isBlank(testRecord.getTestAtlas())) { + return R.ok(); + } + + return R.ok(JSONArray.parseArray(testRecord.getTestAtlas()), "获取实验图谱列表成功!"); + } + + /** + * 删除实验图谱 + * + * @param dto + * @return + */ + @Override + public R deleteTestAtlas(DeleteTestAtlasDTO dto) throws Exception { + TestRecord testRecord = this.getById(dto.getTestId()); + if (testRecord == null) { + throw new RuntimeException(String.format("实验id为 %s 的数据在系统中不存在!", dto.getTestId())); + } + JSONArray array = JSONArray.parseArray(testRecord.getTestAtlas()); + if (CollUtil.isEmpty(array)) { + throw new RuntimeException("该实验的图谱为空!"); + } + // 获取删除的fileid + List fileIds = dto.getFileIds(); + JSONArray newArray = new JSONArray(); + int size = array.size(); + for (int i = 0; i < size; i++) { + JSONObject jsonObject = array.getJSONObject(i); + String fileId = jsonObject.getString("fileId"); + if (fileIds.contains(fileId)) { + ossFile.fileDelete(jsonObject.getString("path")); + } else { + // 不是删除的,就添加到新的数组 + newArray.add(jsonObject); + } + } + + // 更新 + testRecord.setTestAtlas(newArray.toJSONString()); + if (this.updateById(testRecord)) { + return R.ok(true, "实验图谱删除成功!"); + } else { + return R.ok(false, "实验图谱删除失败!"); + } + } + + /** + * 根据业务id获取实验图谱 + * + * @param businessId + * @return + */ + @Override + public R getTestAtlasListByBusinessId(String businessId) { + /** + * 先根据业务id 查询出检材id + */ + List testDataListByBusiness = testRecordSampleDataMapper + .queryDataSolutionSampleDTOList(Wrappers.query().eq("si.business_id", businessId)); + if (CollUtil.isEmpty(testDataListByBusiness)) { + return R.ok(); + } + // 2 根据查询出来的结果,取出实验id + List testIdList = testDataListByBusiness.stream().map(DataSolutionSampleDTO::getTestId).collect(Collectors.toList()); + // 3 根据实验id 获取实验信息 + List testRecordList = this.list(Wrappers.lambdaQuery() + .in(TestRecord::getId, testIdList) + .orderByDesc(TestRecord::getUpdateTime)); + // 最终返回的结果数组 + JSONArray resultArray = new JSONArray(); + for (TestRecord testRecord : testRecordList) { + if (StrUtil.isNotBlank(testRecord.getTestAtlas())) { + resultArray.addAll(JSONArray.parseArray(testRecord.getTestAtlas())); + } + } + return R.ok(resultArray, "根据业务id获取列表成功!"); + } + + /** + * 根据业务id获取实验信息 + * + * @param businessIds + * @return + */ + @Override + public R> queryTestRecordInfoByBusinessId(List businessIds) { + List dataSolutionSampleDTOS = testRecordSampleDataMapper + .queryDataSolutionSampleDTOList(Wrappers.query() + .in("si.business_id", businessIds)); + Set testIdSet = dataSolutionSampleDTOS + .stream() + .map(DataSolutionSampleDTO::getTestId) + .collect(Collectors.toSet()); + // 以实验id为key + Map dataSolutionSampleDTOMap = dataSolutionSampleDTOS + .stream() + .collect( + Collectors + .toMap( + DataSolutionSampleDTO::getTestId, + Function.identity(), + (v1, v2) -> v2 + ) + ); + List testRecordMapList = baseMapper.getTestRecordMapList(Wrappers.lambdaQuery().in(TestRecord::getId, testIdSet)); + // 业务id为key + Map map = new HashMap<>(); + for (TestRecordVo testRecordVo : testRecordMapList) { + DataSolutionSampleDTO dataSolutionSampleDTO = dataSolutionSampleDTOMap.get(testRecordVo.getId()); + map.put(dataSolutionSampleDTO.getBusinessId(), testRecordVo); + } + return R.ok(map); + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordStandardSolutionServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordStandardSolutionServiceImpl.java new file mode 100644 index 0000000..95fccf8 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordStandardSolutionServiceImpl.java @@ -0,0 +1,423 @@ +package digital.laboratory.platform.inspection.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.constant.StdSolutionNum; +import digital.laboratory.platform.inspection.constant.TestRecordSampleDataConstant; +import digital.laboratory.platform.inspection.dto.TestRecordStandardSolutionDto; +import digital.laboratory.platform.inspetion.api.entity.TestRecord; +import digital.laboratory.platform.inspection.entity.TestRecordStandardSolution; +import digital.laboratory.platform.inspection.constant.TestRecordArgumentType; +import digital.laboratory.platform.inspection.mapper.TestRecordStandardSolutionMapper; +import digital.laboratory.platform.inspection.service.TestRecordReagentService; +import digital.laboratory.platform.inspection.service.TestRecordService; +import digital.laboratory.platform.inspection.service.TestRecordStandardSolutionService; +import digital.laboratory.platform.sys.feign.RemoteBalanceRMaterialService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Service +@SuppressWarnings("all") +public class TestRecordStandardSolutionServiceImpl extends ServiceImpl implements TestRecordStandardSolutionService { + @Resource + private RemoteBalanceRMaterialService remoteBalanceRMaterialService; + + @Resource + private TestRecordService testRecordService; + + @Resource + private TestRecordReagentService testRecordReagentService; + + /** + * 创建标准溶液。 + *

+ * 此方法接收一个包含标准溶液信息的数据传输对象(DTO),并将其转换为实体对象进行保存。 + * 同时,根据输入数据计算浓度,并将该标准溶液与相应的实验记录绑定。 + * + * @param testRecordStandardSolutionDto 包含标准溶液信息的数据传输对象 + * @return 成功保存的标准溶液实体对象,如果保存失败则返回null + */ + @Override + @Transactional(rollbackFor = Exception.class) // 确保事务管理,发生异常时回滚 + public TestRecordStandardSolution addTestRecordStandardSolution(TestRecordStandardSolutionDto testRecordStandardSolutionDto) { + + Integer opCode = 1; // 操作码,用于标识操作类型 + + TestRecordStandardSolution testRecordStandardSolution = new TestRecordStandardSolution(); + + // 将DTO中的属性复制到实体对象中 + BeanUtils.copyProperties(testRecordStandardSolutionDto, testRecordStandardSolution); + + String standardName = ""; + + // 设置标准物质数量,默认为1,表示单个标准物质溶液 + testRecordStandardSolution.setStandardSubstanceCount(1); + + // 生成标准溶液编号 + testRecordStandardSolution.setNumber(this.createNumber(testRecordStandardSolution)); + + // 生成唯一ID + testRecordStandardSolution.setId(IdWorker.get32UUID().toUpperCase()); + + // 设置有效期为制备日期后7天 + testRecordStandardSolution.setExpirationDate(testRecordStandardSolutionDto.getMadeDate().plusDays(7)); + + // 设置溶液类型为标准工作溶液(STD) + testRecordStandardSolution.setSolutionType(TestRecordSampleDataConstant.SAMPLE_TYPE_STD); + + // 如果提供了称取质量/移取体积,则计算浓度;否则假设用户已填写好浓度 + if (StringUtils.isNotBlank(testRecordStandardSolution.getWeighingMoving())) { + testRecordStandardSolution = this.calculatedConcentration(testRecordStandardSolution); + } else { + testRecordStandardSolution.setWeighingMoving(testRecordStandardSolution.getResultConcentration()); + testRecordStandardSolution.setDilutionFactor("1"); + testRecordStandardSolution.setOriginalConcentration(testRecordStandardSolution.getResultConcentration()); + testRecordStandardSolution.setConstantVolume("1"); + } + + // 命名溶液名称 + testRecordStandardSolution.setStandardName(testRecordStandardSolutionDto.getStandardName() + + testRecordStandardSolution.getDilutionName() + "溶液"); + + // 将该标准溶液与对应的实验记录进行绑定 + boolean ret = testRecordService.updateTestRecordArgument( + testRecordStandardSolution.getTestId(), + testRecordStandardSolution.getId(), + TestRecordArgumentType.TEST_RECORD_ARGUMENT_STANDARD_SOLUTION.getType(), + opCode + ); + + // 保存标准溶液实体对象,并检查是否成功保存以及是否成功更新实验记录参数 + return this.save(testRecordStandardSolution) && ret ? testRecordStandardSolution : null; + } + + /** + * 生成空白溶液。 + *

+ * 根据提供的实验ID和类型(空白溶剂或空白样品),创建并保存一个空白溶液记录。 + * 编号生成规则基于当前日期和已有溶液的数量进行编号。 + * + * @param testId 实验ID + * @param type 类型标识,1表示空白溶剂,-1表示空白样品 + * @return 成功保存的标准溶液实体对象,如果保存失败则返回null + */ + @Override + public TestRecordStandardSolution addBlankSolution(String testId, Integer type) { + // 创建新的标准溶液实体对象 + TestRecordStandardSolution solution = new TestRecordStandardSolution(); + + // 设置标准物质数量为0,表示空白溶液 + solution.setStandardSubstanceCount(0); + + // 设置实验ID + solution.setTestId(testId); + + // 设置溶液类型和名称 + String solutionType; + String standardName; + String prefix; + if (type == 1) { // 空白溶剂 + solutionType = "BLK"; // 溶液类型:空白溶剂 + standardName = "空白溶剂"; // 名称:空白溶剂 + prefix = StdSolutionNum.BLANK_SOLUTION.getPrefix(); // 前缀用于生成编号 + } else { // 空白样品 + solutionType = "BLS"; // 溶液类型:空白样品 + standardName = "空白样品"; // 名称:空白样品 + prefix = StdSolutionNum.BLANK_SAMPLE_SOLUTION.getPrefix(); // 前缀用于生成编号 + } + solution.setStandardName(standardName); // 设置标准溶液名称 + solution.setSolutionType(solutionType); // 设置溶液类型 + + // 查询已有的溶液列表以生成编号 + List solutionList = this.list( + Wrappers.lambdaQuery() + .eq(TestRecordStandardSolution::getSolutionType, solutionType) // 过滤条件:溶液类型 + .eq(TestRecordStandardSolution::getTestId, testId) // 过滤条件:实验ID + ); + + // 生成编号 + String suffix = solutionList == null || solutionList.isEmpty() ? "01" : String.format("%02d", solutionList.size() + 1); + String number = prefix + "-" + LocalDateTimeUtil.format(LocalDateTime.now(), "yyyyMMdd") + "-" + suffix; + solution.setNumber(number); // 设置生成的编号 + + // 设置其他属性 + solution.setResultConcentration("/"); // 结果浓度默认值 + solution.setMadeDate(LocalDateTime.now()); // 制备日期设置为当前时间 + solution.setOriginalConcentration("/"); // 原始浓度默认值 + solution.setWeighingMoving("0"); // 称取质量/移取体积默认值 + solution.setConstantVolume("0"); // 定容体积默认值 + solution.setDilutionFactor("0"); // 稀释倍数默认值 + solution.setDilutionName("/"); // 稀释物质名称默认值 + solution.setExpirationDate(LocalDateTime.now()); // 有效期设置为当前时间 + solution.setId(IdWorker.get32UUID().toUpperCase()); // 设置唯一ID + solution.setResultConcentrationUnit("/"); //设置单位 + + // 更新实验记录参数,将该标准溶液与对应的实验记录进行绑定 + boolean ret = testRecordService.updateTestRecordArgument( + solution.getTestId(), + solution.getId(), + TestRecordArgumentType.TEST_RECORD_ARGUMENT_STANDARD_SOLUTION.getType(), + 1 + ); + + // 保存标准溶液实体对象,并检查是否成功保存以及是否成功更新实验记录参数 + return this.save(solution) && ret ? solution : null; + } + + /** + * 根据标准溶液种数创建质控溶液。 + * + * @param testId 实验ID + * @return 成功保存的质控溶液列表,如果保存失败则返回null + */ + @Override + public List createQualityControlSol(String testId) { + // 获取实验记录 + TestRecord record = testRecordService.getById(testId); + + // 查询所有非空白和非质控的标准溶液 + List standardSolutions = this.list( + Wrappers.lambdaQuery() + .eq(TestRecordStandardSolution::getSolutionType, "STD") + .eq(TestRecordStandardSolution::getTestId, testId) + ); + + // 检查是否有标准溶液 + if (standardSolutions.isEmpty()) { + throw new RuntimeException("请先添加至少一瓶标准溶液后再进行添加质控溶液!"); + } + + // 计算所有标准溶液中的标准物质数量总和 + + int totalSubstanceCount = standardSolutions.size(); + + // 清除现有的质控溶液 + + List qcList = this.list( + Wrappers.lambdaQuery() + .eq(TestRecordStandardSolution::getStandardSubstanceCount, 0) + .eq(TestRecordStandardSolution::getTestId, testId) + .likeRight(TestRecordStandardSolution::getNumber, TestRecordSampleDataConstant.SAMPLE_TYPE_QC) + ); + + // 删除现有质控溶液 + if (!qcList.isEmpty()) { + this.remove(Wrappers.lambdaQuery() + .eq(TestRecordStandardSolution::getStandardSubstanceCount, 0) + .eq(TestRecordStandardSolution::getTestId, testId) + .likeRight(TestRecordStandardSolution::getNumber, TestRecordSampleDataConstant.SAMPLE_TYPE_QC)); + + // 更新实验记录中的标准溶液列表,移除旧的质控溶液ID + List standardSolutionIds = record.getStandardSolution(); + for (TestRecordStandardSolution qcSolution : qcList) { + standardSolutionIds.remove(qcSolution.getId()); + } + } + + // 创建新的质控溶液 + List qcSolutions = new ArrayList<>(); + for (int i = 0; i < totalSubstanceCount; i++) { + TestRecordStandardSolution qcSolution = new TestRecordStandardSolution(); + qcSolution.setStandardSubstanceCount(0); // 设置标准物质数量为0 + qcSolution.setTestId(testId); // 设置实验ID + qcSolution.setStandardName("标准添加样品"); // 设置名称为“标准添加样品” + String suffix = String.format("%02d", i + 1); // 生成编号后缀 + String number = StdSolutionNum.QC_SOLUTION.getPrefix() + "-" + LocalDateTimeUtil.format(LocalDateTime.now(), "yyyyMMdd") + "-" + suffix; // 生成编号 + qcSolution.setNumber(number); // 设置编号 + qcSolution.setResultConcentration("/"); // 设置结果浓度默认值 + qcSolution.setMadeDate(LocalDateTime.now()); // 设置制备日期为当前时间 + qcSolution.setOriginalConcentration("/"); // 设置原始浓度默认值 + qcSolution.setWeighingMoving("0"); // 设置称取质量/移取体积默认值 + qcSolution.setConstantVolume("0"); // 设置定容体积默认值 + qcSolution.setDilutionFactor("0"); // 设置稀释倍数默认值 + qcSolution.setDilutionName("/"); // 设置稀释物质名称默认值 + qcSolution.setExpirationDate(LocalDateTime.now()); // 设置有效期为当前时间 + qcSolution.setId(IdWorker.get32UUID().toUpperCase()); // 设置唯一ID + qcSolution.setSolutionType(TestRecordSampleDataConstant.SAMPLE_TYPE_QC); // 设置溶液类型为质控溶液 + qcSolution.setResultConcentrationUnit("/"); // 设置单位 + qcSolutions.add(qcSolution); // 添加到质控溶液列表中 + } + + + // 更新实验记录中的标准溶液列表,添加新的质控溶液ID + List standardSolutionIds = record.getStandardSolution(); + for (TestRecordStandardSolution qcSolution : qcSolutions) { + standardSolutionIds.add(qcSolution.getId()); // 添加新的质控溶液ID + } + record.setStandardSolution(standardSolutionIds); // 更新实验记录中的标准溶液列表 + testRecordService.updateById(record); // 更新实验记录 + // 批量保存新创建的质控溶液 + return this.saveBatch(qcSolutions) ? qcSolutions : null; + } + + + /** + * 创建标准溶液编号 + * + * @param standardSubstanceNumList + * @param orderNum 溶液编号后缀,用来匹配称量系统那边的称量编号 + * @return + */ + public String createNumber(TestRecordStandardSolution solution) { + String number = ""; + String englishName = solution.getEnglishName(); + String date = LocalDateTimeUtil.format(LocalDateTime.now(), "yyyyMMdd"); + return englishName + "-" + date; + } + + /** + * 删除标准溶液 + * + * @param id + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean delTestRecordStandardSolution(String id) { + Integer opCode = -1; + TestRecordStandardSolution testRecordStandardSolution = this.getById(id); + if (testRecordStandardSolution == null) { + throw new RuntimeException(String.format("没有找到ID为%s的标准溶液", id)); + } + boolean ret = testRecordService.updateTestRecordArgument(testRecordStandardSolution.getTestId(), testRecordStandardSolution.getId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_STANDARD_SOLUTION.getType(), opCode); + return this.removeById(id) && ret; + } + + /** + * 修改标准溶液 + * + * @param testRecordStandardSolution + * @return + */ + @Override + public TestRecordStandardSolution updateTestRecordStandardSolution(TestRecordStandardSolutionDto testRecordStandardSolutionDto) { + TestRecordStandardSolution oldTestRecordStandardSolution = this.getOne(Wrappers.lambdaQuery().eq(TestRecordStandardSolution::getId, testRecordStandardSolutionDto.getId())); + if (oldTestRecordStandardSolution == null) { + throw new RuntimeException(String.format("没有找到ID为%s的标准溶液", testRecordStandardSolutionDto.getId())); + } + TestRecordStandardSolution solution = new TestRecordStandardSolution(); + BeanUtils.copyProperties(testRecordStandardSolutionDto, solution); + solution.setNumber(this.createNumber(solution)); + solution.setExpirationDate(solution.getMadeDate().plusDays(7)); + + // 如果提供了称取质量/移取体积,则计算浓度;否则假设用户已填写好浓度 +// if (!testRecordStandardSolutionDto.getWeighingMoving().isEmpty()) { +// solution = this.calculatedConcentration(solution); +// } else { + solution.setWeighingMoving(solution.getResultConcentration()); + solution.setDilutionFactor("1"); + solution.setOriginalConcentration(solution.getResultConcentration()); + solution.setConstantVolume("1"); +// } + return this.updateById(solution) ? solution : null; + } + + /** + * 计算溶液浓度 + * + * @param testRecordStandardSolution + * @return + */ + public TestRecordStandardSolution calculatedConcentration(TestRecordStandardSolution testRecordStandardSolution) { + //计算原始浓度 + if (StrUtil.isNotBlank(testRecordStandardSolution.getWeighingMoving())) { + BigDecimal weighingValue = new BigDecimal(testRecordStandardSolution.getWeighingMoving()); + BigDecimal constantVolume = new BigDecimal(testRecordStandardSolution.getConstantVolume()); + BigDecimal originalConcentration = weighingValue.divide(constantVolume, 2, RoundingMode.HALF_UP); + testRecordStandardSolution.setOriginalConcentration(originalConcentration.toString()); + } + //计算结果浓度 + if (StrUtil.isNotBlank(testRecordStandardSolution.getOriginalConcentration()) && StrUtil.isNotBlank(testRecordStandardSolution.getDilutionFactor())) { + BigDecimal originalConcentration = new BigDecimal(testRecordStandardSolution.getOriginalConcentration()); + BigDecimal dilutionFactor = new BigDecimal(testRecordStandardSolution.getDilutionFactor()); + BigDecimal resultConcentration = originalConcentration.divide(dilutionFactor, 2, RoundingMode.HALF_UP); + testRecordStandardSolution.setResultConcentration(resultConcentration.toString()); + } + return testRecordStandardSolution; + } + + /** + * 通过实验ID分页查询 + * + * @param page + * @param testId + * @return + */ + @Override + public IPage getTestRecordStandardSolutionPage(Page page, String testId, String keywords) { + return baseMapper.getTestRecordStandardSolutionMapPage(page, testId); + } + + /** + * 通过实验ID列表查询 + * + * @param testId + * @param keywords + * @return + */ + @Override + public List getTestRecordStandardSolutionList(String testId, String keywords) { + return baseMapper.getTestRecordStandardSolutionMapList(testId); + } + + /** + * 匹配称量数据 + * + * @param id + * @return + */ + @Override + public List matchingWeighing(String id) { + List testRecordStandardSolutionList = this.list(Wrappers.lambdaQuery().eq(TestRecordStandardSolution::getTestId, id)); + if (testRecordStandardSolutionList == null || testRecordStandardSolutionList.size() == 0) { + throw new RuntimeException(String.format("没有找到ID为%s的实验具有相关的标准溶液信息!", id)); + } + + //如果匹配到了称量质量,那么就自动去计算浓度 + for (TestRecordStandardSolution testRecordStandardSolution : testRecordStandardSolutionList) { + String standardSolutionNumber = testRecordStandardSolution.getNumber(); + String number = standardSolutionNumber.substring(4); + R data = remoteBalanceRMaterialService.getWeightForNumber(number); + BigDecimal weighing = data.getData(); + if (weighing.compareTo(BigDecimal.ZERO) != 0) { + testRecordStandardSolution.setWeighingMoving(weighing.toString()); + BigDecimal constantVolume = new BigDecimal(testRecordStandardSolution.getConstantVolume()); + BigDecimal originalConcentration = weighing.divide(constantVolume, 2, RoundingMode.HALF_UP); + testRecordStandardSolution.setOriginalConcentration(originalConcentration.toString()); + + if (StrUtil.isNotBlank(testRecordStandardSolution.getDilutionFactor())) { + BigDecimal dilutionFactor = new BigDecimal(testRecordStandardSolution.getDilutionFactor()); + BigDecimal resultConcentration = originalConcentration.divide(dilutionFactor, 2, RoundingMode.HALF_UP); + testRecordStandardSolution.setResultConcentration(resultConcentration.toString()); + } else { + testRecordStandardSolution.setResultConcentration(originalConcentration.toString()); + } + } + } + return this.updateBatchById(testRecordStandardSolutionList) ? testRecordStandardSolutionList : null; + } + + @Override + public boolean detection(String testId) { + List stdList = this.list(Wrappers.lambdaQuery().eq(TestRecordStandardSolution::getTestId, testId).eq(TestRecordStandardSolution::getSolutionType, TestRecordSampleDataConstant.SAMPLE_TYPE_STD)); + if (stdList == null || stdList.size() < 1) { + return false; + } else return true; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestTemplateServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestTemplateServiceImpl.java new file mode 100644 index 0000000..8fc00a7 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestTemplateServiceImpl.java @@ -0,0 +1,278 @@ +package digital.laboratory.platform.inspection.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import digital.laboratory.platform.common.mybatis.security.service.DLPUser; +import digital.laboratory.platform.common.oss.service.OssFile; +import digital.laboratory.platform.inspection.constant.TestRecordFileUrl; +import digital.laboratory.platform.inspection.entity.TestRecordMethod; +import digital.laboratory.platform.inspection.entity.TestTemplate; +import digital.laboratory.platform.inspection.constant.TestRecordArgumentType; +import digital.laboratory.platform.inspection.mapper.TestRecordMapper; +import digital.laboratory.platform.inspection.mapper.TestTemplateMapper; +import digital.laboratory.platform.inspection.service.TestRecordInstrumentConditionService; +import digital.laboratory.platform.inspection.service.TestRecordMethodService; +import digital.laboratory.platform.inspection.service.TestTemplateService; +import digital.laboratory.platform.inspetion.api.vo.TestRecordVo; +import digital.laboratory.platform.inspection.vo.TestTemplateVo; +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Service +public class TestTemplateServiceImpl extends ServiceImpl implements TestTemplateService { + @Resource + private TestRecordMapper testRecordMapper; + @Resource + private TestTemplateMapper testTemplateMapper; + @Resource + private TestRecordMethodService testRecordMethodService; + + @Resource + private TestRecordInstrumentConditionService testRecordInstrumentConditionService; + + @Resource + private OssFile ossFile; + + /** + * 将实验设置为模板 + * @param testTemplate + * @param testId + * @param dlpUser + * @return + * @throws Exception + */ + @Override + public TestTemplate createTemplate(TestTemplate testTemplate, String testId, DLPUser dlpUser) throws Exception { + TestRecordVo testRecord = testRecordMapper.getTestRecordMapById(testId); + if (testRecord.getDeviceIdList() != null && testRecord.getDeviceIdList().size() > 0) { + testTemplate.setDeviceIdList(testRecord.getDeviceIdList()); + } + if (testRecord.getTestMethodList() != null && testRecord.getTestMethodList().size() > 0) { + testTemplate.setTestMethods(testRecord.getTestMethodList()); + } + if (testRecord.getReagentConsumablesList() != null && testRecord.getReagentConsumablesList().size() > 0) { + testTemplate.setReagentConsumables(testRecord.getReagentConsumablesList()); + } + if (testRecord.getDeviceUseCondition() != null && testRecord.getDeviceUseCondition().size() > 0) { + testTemplate.setDeviceUseCondition(testRecord.getDeviceUseCondition()); + } + testTemplate.setAuthor(dlpUser.getId()); + testTemplate.setStatus(0); + testTemplate.setCreateDate(LocalDateTime.now()); + testTemplate.setUseCount(0); + testTemplate.setId(IdWorker.get32UUID().toUpperCase()); + //创建仪器条件 + testRecordInstrumentConditionService.copyConditionWord(testTemplate.getId(), testId); + return this.save(testTemplate) ? testTemplate : null; + } + + /** + * 修改模板 + * @param testTemplate + * @return + */ + @Override + public TestTemplate editTemplate(TestTemplate testTemplate) { + if (testTemplate.getStatus() != 0) { + throw new RuntimeException(String.format("当前模板仍处于发布状态,请先停用后再进行编辑!")); + } + return this.updateById(testTemplate) ? testTemplate : null; + } + + /** + * 删除模板 支持批量 + * @param idList + * @param dlpUser + * @return + */ + @Override + public boolean delTemplate(List idList, DLPUser dlpUser) { + List list = this.list(Wrappers.lambdaQuery().in(TestTemplate::getId, idList)); + for (TestTemplate testTemplate : list) { + if (!testTemplate.getAuthor().equals(dlpUser.getId())) { + throw new RuntimeException(String.format("这个模板不是你创建的,无法删除!")); + } + if (testTemplate.getStatus() != 0) { + throw new RuntimeException(String.format("请先停用模板后再进行删除!")); + } + } + return this.removeBatchByIds(list); + } + + /** + * 向模板添加或移除参数 + * @param templateId 模板ID + * @param argumentId 物品ID + * @param argument 物品类型 + * @param opCode 添加还是移除 + * @return + */ + @Override + public boolean updateTestTemplate(String templateId, String argumentId, String argument, Integer opCode) { + TestTemplateVo templateVo = baseMapper.getTestTemplateMapById(templateId); + if (templateVo.getStatus() != 0) { + throw new RuntimeException(String.format("当前模板仍处于发布状态,请先停用后再进行编辑!")); + } + ArrayList argumentIdList = new ArrayList<>(); + if (argument.equals(TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT.getType())) { + if (templateVo.getDeviceIdList() != null && templateVo.getDeviceIdList().size() > 0) { + argumentIdList.addAll(templateVo.getDeviceIdList()); + } + this.updateArgument(argumentIdList, opCode, argumentId); + templateVo.setDeviceIdList(argumentIdList); + } else if (argument.equals(TestRecordArgumentType.TEST_RECORD_ARGUMENT_INSTRUMENT_CONDITION.getType())) { + if (templateVo.getDeviceUseCondition() != null && templateVo.getDeviceUseCondition().size() > 0) { + argumentIdList.addAll(templateVo.getDeviceUseCondition()); + } + this.updateArgument(argumentIdList, opCode, argumentId); + templateVo.setDeviceUseCondition(argumentIdList); + } else if (argument.equals(TestRecordArgumentType.TEST_RECORD_ARGUMENT_METHOD.getType())) { + if (templateVo.getTestMethods() != null && templateVo.getTestMethods().size() > 0) { + argumentIdList.addAll(templateVo.getTestMethods()); + } + this.updateArgument(argumentIdList, opCode, argumentId); + templateVo.setTestMethods(argumentIdList); + } else if (argument.equals(TestRecordArgumentType.TEST_RECORD_ARGUMENT_REAGENT.getType())) { + if (templateVo.getReagentConsumables() != null && templateVo.getReagentConsumables().size() > 0) { + argumentIdList.addAll(templateVo.getReagentConsumables()); + } + this.updateArgument(argumentIdList, opCode, argumentId); + templateVo.setReagentConsumables(argumentIdList); + } else { + throw new RuntimeException(String.format("没有传入正常的argument!")); + } + return this.updateById(templateVo); + } + + /** + * 判断添加物品的参数是否正确 + * @param argumentIdList + * @param opCode + * @param argumentId + */ + public void updateArgument(List argumentIdList, Integer opCode, String argumentId) { + if (opCode == 1) { + if (argumentIdList.size() > 0 && argumentIdList.contains(argumentId)) { + throw new RuntimeException(String.format("当前内容已添加至模板,请勿重复添加!")); + } + argumentIdList.add(argumentId); + } else if (opCode == -1 && argumentIdList.contains(argumentId)) { + boolean ret = argumentIdList.remove(argumentId); + if (!ret) { + throw new RuntimeException(String.format("在模板中没有找到ID为%s的内容!", argumentId)); + } + } + } + + /** + * 发布模板 + * @param id + * @return + */ + @Override + public TestTemplateVo publishTemplate(String id) { + TestTemplateVo templateVo = testTemplateMapper.getTestTemplateMapById(id); + templateVo.setPublishDate(LocalDateTime.now()); + if (templateVo.getStatus() != 0) { + throw new RuntimeException(String.format("当前模板不处在未发布的状态,无法进行发布!")); + } + templateVo.setStatus(1); + return this.updateById(templateVo) ? templateVo : null; + } + + /** + * 停用模板 + * @param id + * @return + */ + @Override + public TestTemplateVo blockTemplate(String id) { + TestTemplateVo templateVo = testTemplateMapper.getTestTemplateMapById(id); + templateVo.setStatus(0); + return this.updateById(templateVo) ? templateVo : null; + } + + /** + * 通过ID查询模板 + * @param id + * @return + */ + @Override + public TestTemplateVo getTemplateById(String id) { + TestTemplateVo templateVo = baseMapper.getTestTemplateMapById(id); + this.getMethodName(templateVo); + List fileNameList = ossFile.fileList(TestRecordFileUrl.TEST_TEMPLATE_CATALOGUE.getFileUrl() + "/" + templateVo.getId()); + if (fileNameList != null && fileNameList.size() > 0) { + boolean ret = fileNameList.contains("仪器条件.docx"); + if (ret) { + templateVo.setInstrumentConditionFileName("仪器条件.docx"); + templateVo.setInstrumentConditionUrl(TestRecordFileUrl.TEST_TEMPLATE_CATALOGUE.getFileUrl() + "/" + templateVo.getId() + "/" + "仪器条件.docx"); + } + } + return templateVo; + } + + /** + * @param opCode 1:查询所有发布的公有模板 -1:查询自己发布的所有模板 + * @param dlpUser 用户信息 + * @param keywords 查询参数:模板名称 + * */ + @Override + public IPage getTemplateVoPage(Page page, Integer opCode, DLPUser dlpUser, String keywords) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + //查询所有公有且已发布的模板(去掉自己发布的) + if (opCode == 1) { + wrapper.ne(TestTemplate::getAuthor, dlpUser.getId()) + .eq(TestTemplate::getStatus, 1) + .eq(TestTemplate::isNature, true) + .like(StrUtil.isNotBlank(keywords), TestTemplate::getName, keywords) + .orderByDesc(TestTemplate::getCreateDate); + IPage iPage = baseMapper.getTestTemplateMapPage(page, wrapper); + return iPage; + //查询所有自己发布的模板 + } else { + wrapper.eq(TestTemplate::getAuthor, dlpUser.getId()) + .like(StrUtil.isNotBlank(keywords), TestTemplate::getName, keywords) + .orderByDesc(TestTemplate::getCreateDate); + IPage iPage = baseMapper.getTestTemplateMapPage(page, wrapper); + return iPage; + } + } + + /** + * 获取模板中的方法名集合 + * @param testTemplate + */ + public void getMethodName(TestTemplateVo testTemplate) { + if (testTemplate.getTestMethods() != null && testTemplate.getTestMethods().size() > 0) { + ArrayList nameList = new ArrayList<>(); + List list = testRecordMethodService.list(Wrappers.lambdaQuery().in(TestRecordMethod::getId, testTemplate.getTestMethods())); + list.forEach(item -> nameList.add(item.getMethodName())); + testTemplate.setTestMethodName(nameList); + } + } + + /** + * 列表查询模板信息(创建实验时) + * @param dlpUser + * @return + */ + @Override + public List getTemplateVoList(DLPUser dlpUser) { + return baseMapper.getTestTemplateMapList(Wrappers.lambdaQuery() + .and(wrapper -> wrapper.eq(TestTemplate::getAuthor, dlpUser.getId()) + .or() + .eq(TestTemplate::isNature, true)) + .eq(TestTemplate::getStatus, 1) + .orderByDesc(TestTemplate::getCreateDate)); + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/PageUtils.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/PageUtils.java new file mode 100644 index 0000000..c580d94 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/PageUtils.java @@ -0,0 +1,52 @@ +package digital.laboratory.platform.inspection.utils; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import java.util.ArrayList; +import java.util.List; + +public class PageUtils { + + /** + * 分页函数 + * + * @param currentPage 当前页数 + * @param pageSize 每一页的数据条数 + * @param list 要进行分页的数据列表 + * @return 当前页要展示的数据 + * @author yhh + */ + public Page getPages(long currentPage, long pageSize, List list) { + Page page = new Page(); + if (list == null) { + return null; + } + int size = list.size(); + + if (pageSize > size) { + pageSize = size; + } + if (pageSize != 0) { + // 求出最大页数,防止currentPage越界 + long maxPage = size % pageSize == 0 ? size / pageSize : size / pageSize + 1; + + if (currentPage > maxPage) { + currentPage = maxPage; + } + } + // 当前页第一条数据的下标 + long x = currentPage > 1 ? (currentPage - 1) * pageSize : 0; + + int curIdx = (int) x; + + List pageList = new ArrayList(); + + // 将当前页的数据放进pageList + for (int i = 0; i < pageSize && curIdx + i < size; i++) { + pageList.add(list.get(curIdx + i)); + } + page.setCurrent(currentPage).setSize(pageSize).setTotal(list.size()).setRecords(pageList); + return page; + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/TestDataFileUtil.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/TestDataFileUtil.java new file mode 100644 index 0000000..03f9043 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/TestDataFileUtil.java @@ -0,0 +1,63 @@ +package digital.laboratory.platform.inspection.utils; + +import digital.laboratory.platform.inspection.utils.datafile.HairDataFileUtil; +import digital.laboratory.platform.inspection.utils.datafile.NPSDataFileUtil; +import digital.laboratory.platform.inspection.utils.datafile.SewageDataFileUtil; +import digital.laboratory.platform.inspection.utils.datafile.hair.HairSewageCompoundData; +import digital.laboratory.platform.inspection.utils.datafile.nps.NPSDataFileStruct; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; +import java.util.Map; + +/** + * @author xy + * @version 1.0 + * @title TestDataFileUtil 实验数据文件解析工具类 + * @description + * @create 2024/1/8 16:05 + */ + +public class TestDataFileUtil { + private static String getFileText(MultipartFile file) throws Exception{ + String charset = TextEncodeUtil.checkFileCharset(file);//查看文件流的编码格式 + String fileText = TextEncodeUtil.formatStream(file, charset);//将其转化为一个字符文本 + return fileText; + } + /** + * 解析毛发实验数据文件 毛发任务数据,污水任务数据 + * @param file + * @param code 1 调用毛发的方法 2 调用污水的方法 + * @return + * @throws Exception + */ + public static Map> analysisWtsDataFile(MultipartFile file, Integer code) throws Exception{ + String fileText=getFileText(file); + Map> retMap = null; + if (code == 1) { + retMap=HairDataFileUtil.readDataFromText(fileText); + } else if (code == 2) { + retMap = SewageDataFileUtil.readDataFromText(fileText); + } else { + throw new RuntimeException("code 的值不合法!"); + } + return retMap; + } + /** + * 解析NPS案件的实验数据文件 + * @param file 实验数据文件 + * @throws Exception + */ + public static List analysisNpsDataFile(MultipartFile file) throws Exception{ + String fileText=getFileText(file); + //NPS数据文件解析 + List fileStructList= NPSDataFileUtil.readDataFromText(fileText); + return fileStructList; + } + //解析冰毒,海洛因实验数据文件 + + + + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/TextEncodeUtil.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/TextEncodeUtil.java new file mode 100644 index 0000000..96d0a92 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/TextEncodeUtil.java @@ -0,0 +1,144 @@ +package digital.laboratory.platform.inspection.utils; + +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +/** + * @author xy + * @version 1.0 + * @title TextEncodeUtil 文本文件编码工具类 + * @description + * @create 2024/1/8 16:20 + */ + +public class TextEncodeUtil { + + /** + * 检查文件的字符集 + * + * @param inputStream + * @return + * UTF-8 表示是 UTF-8 格式 + * UTF-16 表示是 UTF-16 格式 + * GBK 表示是 GBK 格式 + */ + public static String checkFileCharset(MultipartFile file) throws IOException { + byte[] bytes = new byte[256]; + InputStream inputStream=file.getInputStream(); + int n = inputStream.read(bytes); + inputStream.close(); + if (n<=2) { + return "GBK"; + } + if (bytes[0]==-17 && bytes[1]==-69 && bytes[2]==-65) { + return "UTF-8"; + } + + ENCODE_TYPE encodeType =detectEncodeType(bytes); + if (encodeType ==ENCODE_TYPE.UTF8) + return "UTF-8"; + else + + return "GBK"; + } + public static String formatStream(MultipartFile file, String charset) throws IOException { + + InputStream inputStream=file.getInputStream(); + Reader reader = new InputStreamReader(inputStream, charset); + StringBuilder sbText = new StringBuilder(); + char[] buffer = new char[1024]; + int n; + while ((n = reader.read(buffer)) != -1) { + sbText.append(buffer, 0, n); + } + inputStream.close(); + return sbText.toString(); + } + public enum ENCODE_TYPE { + UNKNOW, + ANSI, + UTF8, + UTF16_big_endian, + UTF16_little_endian + } + public static ENCODE_TYPE detectEncodeType(byte[] inputBuffer /*, int bufLen*/) { + ENCODE_TYPE filetype = ENCODE_TYPE.ANSI; + + if (Byte.toUnsignedInt(inputBuffer[0]) == 0xFF + && Byte.toUnsignedInt(inputBuffer[1]) == 0xFE) //fffe,小头,windows默认 + filetype = ENCODE_TYPE.UTF16_little_endian; + else if (Byte.toUnsignedInt(inputBuffer[0]) == 0xFE + && Byte.toUnsignedInt(inputBuffer[1]) == 0xFF) + filetype = ENCODE_TYPE.UTF16_big_endian; + else { + if (validUtf8(inputBuffer)) { + filetype = ENCODE_TYPE.UTF8; + } + } + return filetype; + } + static final int MASK1 = 1 << 7; + static final int MASK2 = (1 << 7) + (1 << 6); + + public static boolean validUtf8(byte[] data) { + int m = data.length; + int index = 0; + while (index < m) { + int num = Byte.toUnsignedInt(data[index]); + int n = getBytes(num); + if (n < 0 || index + n > m) { + return false; + } + for (int i = 1; i < n; i++) { + if (!isValid(Byte.toUnsignedInt(data[index + i]))) { + return false; + } + } + index += n; + } + return true; + } + + public static boolean validUtf8(int[] data) { + int m = data.length; + int index = 0; + while (index < m) { + int num = data[index]; + int n = getBytes(num); + if (n < 0 || index + n > m) { + return false; + } + for (int i = 1; i < n; i++) { + if (!isValid(data[index + i])) { + return false; + } + } + index += n; + } + return true; + } + + public static int getBytes(int num) { + if ((num & MASK1) == 0) { + return 1; + } + int n = 0; + int mask = MASK1; + while ((num & mask) != 0) { + n++; + if (n > 4) { + return -1; + } + mask >>= 1; + } + return n >= 2 ? n : -1; + } + + public static boolean isValid(int num) { + return (num & MASK2) == MASK1; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/HairDataFileUtil.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/HairDataFileUtil.java new file mode 100644 index 0000000..c9bd2c5 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/HairDataFileUtil.java @@ -0,0 +1,92 @@ +package digital.laboratory.platform.inspection.utils.datafile; + +import cn.hutool.core.util.StrUtil; +import digital.laboratory.platform.inspection.utils.datafile.hair.HairSewageCompoundData; +import lombok.extern.slf4j.Slf4j; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import java.util.*; + +/** + * @author xy + * @version 1.0 + * @title HairDataFileUtil 毛发数据的文件解析工具类 + * @description + * @create 2024/1/29 14:37 + */ +@Slf4j +public class HairDataFileUtil { + public static Map> readDataFromText(String dataText) throws Exception{ + ByteArrayInputStream tInputStringStream = new ByteArrayInputStream(dataText.getBytes()); + BufferedReader reader = new BufferedReader(new InputStreamReader(tInputStringStream)); + String currentLineContent="";//当前行 + int sampleCount=0; + Map> retMap=new HashMap<>();//某种化合物的 10个样本的该化合物含量数据 + HairSewageCompoundData hairSewageCompoundData =null; + List hairSewageCompoundDataList =null; + String compoundName=""; + List fieldList = null; + boolean clearTab = true; + while ((currentLineContent = reader.readLine()) != null) { + if(StrUtil.isBlank(currentLineContent)) continue;//如果该行是空行,直接跳到下一行 + String[] arrayLineTemp = currentLineContent.split("\t",-1); + String[] arrayLine = null; + if (clearTab || arrayLineTemp[0].startsWith("Compound")) { + arrayLine = Arrays.stream(arrayLineTemp).filter(s -> StrUtil.isNotBlank(s)).toArray(String[]::new); + } else { + arrayLine = arrayLineTemp; + } + if(arrayLine.length==1){ + //说明这一行就是一个标题 + //arrayLine[0].indexOf("Compound")!=-1&&arrayLine[0].indexOf(":")!=-1 + if(arrayLine[0].startsWith("Compound")){ + //如果条件成立,就是化合物名称 + compoundName=arrayLine[0].split(":")[1].trim(); + // 标识后面的不用在去清除制表符\t + clearTab = false; + //hairSewageCompoundData=new HairSewageCompoundData(); + hairSewageCompoundDataList = new ArrayList<>(); + //hairSewageCompoundData.setCompoundName(compoundName); + //hairSewageCompoundDataList.add(hairSewageCompoundData); + //retMap.put(compoundName,hairSewageCompoundDataList); + sampleCount=0; + } + }else if(arrayLine.length>1){ + //说明现在是某种化合物数据了 + if(arrayLine[2].equals("Name")){ + //说明是表头行 + fieldList= Arrays.asList(arrayLine); + //hairSewageCompoundData.setFieldList(fieldList); + }else{ + sampleCount++; + //说明是数据行 + hairSewageCompoundData =new HairSewageCompoundData(); + + hairSewageCompoundData.setCompoundName(compoundName); + hairSewageCompoundData.setFieldList(fieldList); // 表头 + hairSewageCompoundData.setIndexNo(Integer.parseInt(arrayLine[1]));// + hairSewageCompoundData.setSampleName(arrayLine[2]); + hairSewageCompoundData.setIdName(arrayLine[3]); + hairSewageCompoundData.setRtTime(StrUtil.isBlank(arrayLine[4])?0:Double.parseDouble(arrayLine[4])); + hairSewageCompoundData.setQuanTrace(arrayLine[5]); + hairSewageCompoundData.setArea(StrUtil.isBlank(arrayLine[6])?0:Double.parseDouble(arrayLine[6])); + hairSewageCompoundData.setTrace1(arrayLine[7]); + hairSewageCompoundData.setArea1(StrUtil.isBlank(arrayLine[8])?0:Double.parseDouble(arrayLine[8])); + hairSewageCompoundData.setRatioActual(StrUtil.isBlank(arrayLine[9])?0:Double.parseDouble(arrayLine[9])); + hairSewageCompoundData.setRatioPred(StrUtil.isBlank(arrayLine[10])?0:Double.parseDouble(arrayLine[10])); + hairSewageCompoundData.setRatioFlag(arrayLine[11]); + hairSewageCompoundData.setPrimaryFlags(arrayLine[13]); + hairSewageCompoundData.setConcentration(arrayLine[14]); + + hairSewageCompoundDataList.add(hairSewageCompoundData); + retMap.put(compoundName, hairSewageCompoundDataList); + } + + } + } + log.info("此次一共解析出{}种化合物,包含{}个检材样本",retMap.size(),sampleCount); + return retMap; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/NPSDataFileUtil.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/NPSDataFileUtil.java new file mode 100644 index 0000000..0d191f3 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/NPSDataFileUtil.java @@ -0,0 +1,235 @@ +package digital.laboratory.platform.inspection.utils.datafile; + +import cn.hutool.core.util.StrUtil; +import digital.laboratory.platform.inspection.utils.datafile.nps.NPSDataFileStruct; +import digital.laboratory.platform.inspection.utils.datafile.nps.NPSTestDetailDataStruct; +import lombok.extern.slf4j.Slf4j; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title NPSDataFile 文件是按 [ ] 分成不同的小节,我们只需要找到对应的小节进行数据读取即可 + * @description + * @create 2024/1/9 11:59 + */ +@Slf4j +public class NPSDataFileUtil { + //文件是按[]分成各小节,不同小节的解析不方式不同 + public static List readDataFromText(String dataText) throws Exception{ + ByteArrayInputStream tInputStringStream = new ByteArrayInputStream(dataText.getBytes()); + BufferedReader reader = new BufferedReader(new InputStreamReader(tInputStringStream)); + String currentLineContent="";//当前行 + String currentSectionContent="";//当前节点的内容 + int currentSectionIndex=0;//当前节点的序号 + List materialDataList=new ArrayList<>(); + NPSDataFileStruct npsDataFileStruct=null;//一个NPSDataFileStruct 对象代表一个检材样本 + //文件中,可能存在多个样本,因此应该生成多个对象 + while ((currentLineContent = reader.readLine()) != null) { + if(StrUtil.isBlank(currentLineContent)) continue; + String[] arrayLine = currentLineContent.split("\t"); + //如果当前行是以 [ 开始,以 ] 结束 + if (StrUtil.startWith(arrayLine[0], "[") && StrUtil.endWith(arrayLine[0], "]")) { + // 开始新的 secion + String tmp1= StrUtil.removePrefix(arrayLine[0], "[");//去掉左边中括号 + String tmp2= StrUtil.removeSuffix(tmp1, "]");//去掉右边中括号 + currentSectionContent=tmp2; + npsDataFileStruct=handleSectionTitle(currentSectionContent,npsDataFileStruct); + currentSectionIndex=npsDataFileStruct.getCurrentSection(); + if(currentSectionIndex==1){ + materialDataList.add(npsDataFileStruct); + } + }else if(arrayLine.length>1){ + //如果不是空行且不是以 [ 开始,以 ] 结束,我们就解析数据 + //当然前提是知道他是哪个节点的数据,不同节点的数据,解析需求是不相同的。 + if(currentSectionIndex!=-1){ + handleSectionContent(currentSectionIndex,arrayLine,npsDataFileStruct); + }else{ + System.out.println("对不起,未知的节点数据,请联系开发人员"); + } + } + } + //输出结果 + log.info("此次一共解析样本{}条",materialDataList.size()); + log.info("解析内容如下:{}",materialDataList); + return materialDataList; + } + private static NPSDataFileStruct handleSectionTitle(String lineSectionName, NPSDataFileStruct _npsDataFileStruct){ + //无论是一个检材还是几个检材,肯定先执行到的是header section + if (StrUtil.equalsIgnoreCase(lineSectionName, "Header")) { + _npsDataFileStruct=new NPSDataFileStruct(); + _npsDataFileStruct.setCurrentSection(1); + return _npsDataFileStruct; + } + if (StrUtil.equalsIgnoreCase(lineSectionName, "File Information")) { + _npsDataFileStruct.setCurrentSection(2); + return _npsDataFileStruct; + } + if (StrUtil.equalsIgnoreCase(lineSectionName, "Sample Information")) { + _npsDataFileStruct.setCurrentSection(3); + return _npsDataFileStruct; + } + if (StrUtil.equalsIgnoreCase(lineSectionName, "Original Files")) { + _npsDataFileStruct.setCurrentSection(4); + return _npsDataFileStruct; + } + if (StrUtil.equalsIgnoreCase(lineSectionName, "File Description")) { + _npsDataFileStruct.setCurrentSection(5); + return _npsDataFileStruct; + } + if (StrUtil.equalsIgnoreCase(lineSectionName, "MS Quantitative Results")) { + _npsDataFileStruct.setCurrentSection(6); + return _npsDataFileStruct; + } + _npsDataFileStruct.setCurrentSection(-1); + return _npsDataFileStruct; + } + + /** + * 处理不同节点的数据 + * @param sectionNo + * @param arrayLine + * @param _npsDataFileStruct + */ + private static void handleSectionContent(int sectionNo,String[] arrayLine,NPSDataFileStruct _npsDataFileStruct){ + + switch (sectionNo){ + case 1: + { + //如果是1,则表明是新的一份检材数据的开始 + if (StrUtil.equalsIgnoreCase(arrayLine[0], "Data File Name")) { + _npsDataFileStruct.setHeader_DataFileName((arrayLine.length > 1) ? arrayLine[1] : ""); + } + else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Output Date")) { + _npsDataFileStruct.setHeader_OutputDate((arrayLine.length > 1) ? arrayLine[1] : ""); + } + else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Output Time")) { + _npsDataFileStruct.setHeader_OutputTime((arrayLine.length > 1) ? arrayLine[1] : ""); + } + } + break; + case 2:{ + if (StrUtil.equalsIgnoreCase(arrayLine[0], "Type")) { + _npsDataFileStruct.setFi_FileType((arrayLine.length > 1) ? arrayLine[1] : ""); + } + else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Generated")) { + _npsDataFileStruct.setFi_FileGenerated((arrayLine.length > 1) ? arrayLine[1] : ""); + } + else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Generated by")) { + _npsDataFileStruct.setFi_FileGeneratedBy((arrayLine.length > 1) ? arrayLine[1] : ""); + }else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Modified")) { + _npsDataFileStruct.setFi_FileModified((arrayLine.length > 1) ? arrayLine[1] : ""); + }else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Modified by")) { + _npsDataFileStruct.setFi_FileModifiedBy((arrayLine.length > 1) ? arrayLine[1] : ""); + } + } + break; + case 3:{ + if (StrUtil.equalsIgnoreCase(arrayLine[0], "Operator Name")) { + _npsDataFileStruct.setSi_SampleOperatorName((arrayLine.length > 1) ? arrayLine[1] : ""); + } + else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Analyzed")) { + _npsDataFileStruct.setSi_SampleAnalyzed((arrayLine.length > 1) ? arrayLine[1] : ""); + } + else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Type")) { + _npsDataFileStruct.setSi_SampleType((arrayLine.length > 1) ? arrayLine[1] : ""); + }else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Level")) { + _npsDataFileStruct.setSi_SampleLevel((arrayLine.length > 1) ? arrayLine[1] : ""); + }else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Sample Name")) { + _npsDataFileStruct.setSi_SampleName(arrayLine[1]); + }else if(StrUtil.equalsIgnoreCase(arrayLine[0], "Sample ID")) { + _npsDataFileStruct.setSi_SampleId((arrayLine.length > 1) ? arrayLine[1] : ""); + }else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Dilution Factor")) { + _npsDataFileStruct.setSi_SampleDilutionFactor((arrayLine.length > 1) ? arrayLine[1] : ""); + } + } + break; + case 4:{ + if (StrUtil.equalsIgnoreCase(arrayLine[0], "Data File")) { + _npsDataFileStruct.setOf_DataFile((arrayLine.length > 1) ? arrayLine[1] : ""); + } + else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Method File")) { + _npsDataFileStruct.setOf_MethodFile((arrayLine.length > 1) ? arrayLine[1] : ""); + } + else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Batch File")) { + _npsDataFileStruct.setOf_BatchFile((arrayLine.length > 1) ? arrayLine[1] : ""); + }else if (StrUtil.equalsIgnoreCase(arrayLine[0], "Tuning File")) { + _npsDataFileStruct.setOf_TuningFile((arrayLine.length > 1) ? arrayLine[1] : ""); + } + } + break; + case 5: + { + System.out.println("这个节点没有数据"); + } + break; + case 6: + { + int dataNum = 0; + //如果是该节下面的第一行,则表示的是数据条数 + if (StrUtil.equalsIgnoreCase(arrayLine[0], "# of IDs")) { + if (arrayLine.length > 1) { + dataNum = Integer.parseInt(arrayLine[1]); + _npsDataFileStruct.setMqr_DataCount(dataNum); + } + } + else if (StrUtil.equalsIgnoreCase(arrayLine[0], "ID#")) { + // 如果第一个值是“ID#”,那么这行就是表数据的表头 + //_npsDataFileStruct.getMqrDataMap(). + List dataHeaderFieldList=Arrays.asList(arrayLine); + _npsDataFileStruct.setMqrDataHeaderList(dataHeaderFieldList); + } + else { + NPSTestDetailDataStruct dataObj=generateQuantitativeObj(arrayLine); + _npsDataFileStruct.getChildDataList().add(dataObj); + } + } + break; + } + + } + //构建定量结果表对象 + private static NPSTestDetailDataStruct generateQuantitativeObj(String[] rowData){ + NPSTestDetailDataStruct npsDataFileStructChild=new NPSTestDetailDataStruct(); + npsDataFileStructChild.setId(rowData[0]); + npsDataFileStructChild.setName(rowData[1]); + npsDataFileStructChild.setType(rowData[2]); + npsDataFileStructChild.setMass(rowData[4]); + if (rowData[5].equals("Not Identified")) { + // 如果文件中存在这个信息,则证明这条数据是未检出的, 下面的值都默认设置为0 + npsDataFileStructChild.setNotIdentified(true); + npsDataFileStructChild.setRetTime(-999); + npsDataFileStructChild.setStartTime(-999); + npsDataFileStructChild.setEndTime(-999); + npsDataFileStructChild.setArea(-999); + npsDataFileStructChild.setStdRetTime(-999); + npsDataFileStructChild.setSn(-999); + npsDataFileStructChild.setAbundanceRatio(-999);//设置检材丰度比 + npsDataFileStructChild.setAbundanceRatio_std(-999);//设置标准物质丰度比 + npsDataFileStructChild.setErrorRange(-999);//设置丰度比偏差 + npsDataFileStructChild.setAbundanceRatioError(-999);//设置偏差范围 + npsDataFileStructChild.setWithinError("/");//设置是否在误差范围内 + npsDataFileStructChild.setIsBasePeak(1);//设置他是基峰 + } else { + npsDataFileStructChild.setRetTime(Double.parseDouble(rowData[5])); + npsDataFileStructChild.setStartTime(Double.parseDouble(rowData[6])); + npsDataFileStructChild.setEndTime(Double.parseDouble(rowData[7])); + npsDataFileStructChild.setArea(Double.parseDouble(rowData[9])); + npsDataFileStructChild.setStdRetTime(Double.parseDouble(rowData[14])); + npsDataFileStructChild.setSn(Double.parseDouble(rowData[52])); + } + + return npsDataFileStructChild; + } + //构建定性结果表对象 + private void generateQualitativeObj(){ + + } + //构造定性结果表 +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/SewageDataFileUtil.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/SewageDataFileUtil.java new file mode 100644 index 0000000..fda310b --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/SewageDataFileUtil.java @@ -0,0 +1,157 @@ +package digital.laboratory.platform.inspection.utils.datafile; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.druid.sql.visitor.functions.If; +import digital.laboratory.platform.inspection.utils.datafile.hair.HairSewageCompoundData; +import lombok.extern.slf4j.Slf4j; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author xy + * @version 1.0 + * @title HairDataFileUtil 毛发数据的文件解析工具类 + * @description + * @create 2024/1/29 14:37 + */ +@Slf4j +public class SewageDataFileUtil { + public static Map> readDataFromText(String dataText) throws Exception { + ByteArrayInputStream tInputStringStream = new ByteArrayInputStream(dataText.getBytes()); + BufferedReader reader = new BufferedReader(new InputStreamReader(tInputStringStream)); + String currentLineContent = "";//当前行 + int sampleCount = 0; + Map> retMap = new HashMap<>();//某种化合物的 10个样本的该化合物含量数据 + + String compoundName = ""; + List fieldList = null; + boolean clearTab = true; + ArrayList sewageCompoundDataList = new ArrayList<>(); + while ((currentLineContent = reader.readLine()) != null) { + //如果该行是空行,直接跳到下一行 + if (StrUtil.isBlank(currentLineContent)) { + continue; + } + String[] arrayLine = currentLineContent.split("\t", -1); + if (arrayLine[0].equals("Index")) { + fieldList = Arrays.asList(arrayLine); + continue; + } + if (arrayLine[4].endsWith("2")) { + continue; + } + List hairSewageCompoundDataList = new ArrayList<>(); + + HairSewageCompoundData hairSewageCompoundData = new HairSewageCompoundData(); + hairSewageCompoundData.setCompoundName(arrayLine[3]); + hairSewageCompoundData.setFieldList(fieldList); // 表头 + hairSewageCompoundData.setIndexNo(Integer.parseInt(arrayLine[0]));// + hairSewageCompoundData.setSampleName(arrayLine[1]); + hairSewageCompoundData.setIdName(arrayLine[1]); + try { + hairSewageCompoundData.setRtTime(StrUtil.isBlank(arrayLine[11]) ? 0 : Double.parseDouble(arrayLine[11])); // 保留时间 + } catch (Exception e) { + hairSewageCompoundData.setRtTime(0.0); // 保留时间 + } + try { + hairSewageCompoundData.setArea1(StrUtil.isBlank(arrayLine[10]) ? 0 : Double.parseDouble(arrayLine[10])); + } catch (Exception e) { + hairSewageCompoundData.setArea1(0.0); + } + try { + hairSewageCompoundData.setArea(StrUtil.isBlank(arrayLine[9]) ? 0 : Double.parseDouble(arrayLine[9])); + } catch (Exception e) { + hairSewageCompoundData.setArea(0.0); + } + try { + hairSewageCompoundData.setRatioActual(StrUtil.isBlank(arrayLine[15]) ? 0 : Double.parseDouble(arrayLine[15])); + } catch (Exception e) { + hairSewageCompoundData.setRatioActual(0.0); + } + hairSewageCompoundData.setRatioPred(0.0); + try { + // 浓度的数组下标是13 + hairSewageCompoundData.setConcentration(String.valueOf(Double.parseDouble(arrayLine[13]))); + } catch (Exception e) { + hairSewageCompoundData.setConcentration("0"); + } + hairSewageCompoundData.setTrace1(""); + hairSewageCompoundData.setQuanTrace(""); + hairSewageCompoundData.setPrimaryFlags(""); + hairSewageCompoundData.setRatioFlag(""); + hairSewageCompoundDataList.add(hairSewageCompoundData); + sewageCompoundDataList.addAll(hairSewageCompoundDataList); +// if (retMap.containsKey(hairSewageCompoundData.getCompoundName())) { +// List sewageCompoundDataList = retMap.get(hairSewageCompoundData.getCompoundName()); +// sewageCompoundDataList.add(hairSewageCompoundData); +// retMap.put(hairSewageCompoundData.getCompoundName(), sewageCompoundDataList); +// }else { +// retMap.put(hairSewageCompoundData.getCompoundName(), hairSewageCompoundDataList); +// } +// String[] arrayLineTemp = currentLineContent.split("\t",-1); +// String[] arrayLine = null; +// if (clearTab || arrayLineTemp[0].startsWith("Compound")) { +// arrayLine = Arrays.stream(arrayLineTemp).filter(s -> StrUtil.isNotBlank(s)).toArray(String[]::new); +// } else { +// arrayLine = arrayLineTemp; +// } +// if(arrayLine.length==1){ +// //说明这一行就是一个标题 +// //arrayLine[0].indexOf("Compound")!=-1&&arrayLine[0].indexOf(":")!=-1 +// if(arrayLine[0].startsWith("Compound")){ +// //如果条件成立,就是化合物名称 +// compoundName=arrayLine[0].split(":")[1].trim(); +// // 标识后面的不用在去清除制表符\t +// clearTab = false; +// hairSewageCompoundDataList = new ArrayList<>(); +// +// sampleCount=0; +// } +// }else if(arrayLine.length>1){ +// //说明现在是某种化合物数据了 +// if(arrayLine[2].equals("Name")){ +// //说明是表头行 +// fieldList= Arrays.asList(arrayLine); +// //hairSewageCompoundData.setFieldList(fieldList); +// }else{ +// sampleCount++; +// //说明是数据行 +// hairSewageCompoundData =new HairSewageCompoundData(); +// +// hairSewageCompoundData.setCompoundName(compoundName); +// hairSewageCompoundData.setFieldList(fieldList); // 表头 +// hairSewageCompoundData.setIndexNo(Integer.parseInt(arrayLine[1]));// +// hairSewageCompoundData.setSampleName(arrayLine[2]); +// hairSewageCompoundData.setIdName(arrayLine[3]); +// hairSewageCompoundData.setRtTime(StrUtil.isBlank(arrayLine[4])?0:Double.parseDouble(arrayLine[4])); // 保留时间 +// hairSewageCompoundData.setArea1(StrUtil.isBlank(arrayLine[5])?0:Double.parseDouble(arrayLine[5])); +// hairSewageCompoundData.setArea(StrUtil.isBlank(arrayLine[6])?0:Double.parseDouble(arrayLine[6])); +// hairSewageCompoundData.setRatioActual(StrUtil.isBlank(arrayLine[7])?0:Double.parseDouble(arrayLine[7])); +// hairSewageCompoundData.setRatioPred(StrUtil.isBlank(arrayLine[8])?0:Double.parseDouble(arrayLine[8])); +// hairSewageCompoundData.setConcentration(arrayLine[10]); // 溶液浓度 +// hairSewageCompoundData.setTrace1(arrayLine[13]); +// hairSewageCompoundData.setQuanTrace(arrayLine[14]); +// hairSewageCompoundData.setPrimaryFlags(arrayLine[15]); +// hairSewageCompoundData.setRatioFlag(arrayLine[16]); +// +// hairSewageCompoundDataList.add(hairSewageCompoundData); +// retMap.put(compoundName, hairSewageCompoundDataList); +// } +// +// } + } + Map> map = updateInfo(sewageCompoundDataList); + log.info("此次一共解析出{}种化合物,包含{}个检材样本", map.size(), sampleCount); + return map; + } + + public static Map> updateInfo(List hairSewageCompoundDataList) { + Map> map = hairSewageCompoundDataList.stream().collect(Collectors.groupingBy(item -> item.getCompoundName())); + return map; + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/hair/HairDataStruct.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/hair/HairDataStruct.java new file mode 100644 index 0000000..95f7fed --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/hair/HairDataStruct.java @@ -0,0 +1,20 @@ +package digital.laboratory.platform.inspection.utils.datafile.hair; + +import java.util.List; +import java.util.Map; + +/** + * @author xy + * @version 1.0 + * @title HairDataStruct 毛发案件检验数据的数据结构 + * @description + * @create 2024/1/29 12:05 + * 毛发案件的检验结果数据,每行的数据用 /t分割 + * + */ + +public class HairDataStruct { + private String fileIdentifier;//文件标识 用于标识是那种格式的文件 + private String printDate;//打印时间 + private Map> hairCompoundDataList;//化合物数据列表 +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/hair/HairSewageCompoundData.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/hair/HairSewageCompoundData.java new file mode 100644 index 0000000..5a7cb84 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/hair/HairSewageCompoundData.java @@ -0,0 +1,35 @@ +package digital.laboratory.platform.inspection.utils.datafile.hair; + +import lombok.Data; + +import java.util.List; + +/** + * @author xy + * @version 1.0 + * @title HairSewageCompoundData 毛发化合物数据,这个相当于是每个检材的某一种化合物的数据情况 + * 比如:MDMB-4en-PINACA 这个化合物,每种检材检出的情况 + * @description + * @create 2024/1/29 14:18 + */ +@Data +public class HairSewageCompoundData { + private List fieldList; + private String compoundName; + private Integer indexNo;//序号 + private String sampleName;// 样本名称 + private String idName;// + private Double rtTime;//保留时间 + private String quanTrace;// + private Double area;//峰面积 + private String trace1; + private Double area1; + private Double ratioActual;//实际丰度比 + private Double ratioPred;//预计丰度比 + private String ratioFlag; + private String primaryFlags; + private String concentration;//溶液浓度 ng/mL + + //离子丰度比偏差范围 + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/nps/NPSDataFileStruct.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/nps/NPSDataFileStruct.java new file mode 100644 index 0000000..68be469 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/nps/NPSDataFileStruct.java @@ -0,0 +1,55 @@ +package digital.laboratory.platform.inspection.utils.datafile.nps; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author xy + * @version 1.0 + * @title NPSDataFileStruct NPS 数据文件结构 + * @description + * @create 2024/1/24 10:44 + */ +@Data +public class NPSDataFileStruct { + //Header部份的属性 + private String header_DataFileName; + private String header_OutputDate; + private String header_OutputTime; + //File Information 部份的属性 + private String fi_FileType; + private String fi_FileGenerated; + private String fi_FileGeneratedBy; + private String fi_FileModified; + private String fi_FileModifiedBy; + //Sample Information 部份的属性 + private String si_SampleOperatorName; + private String si_SampleAnalyzed; + private String si_SampleType; + private String si_SampleLevel; + private String si_SampleName; + private String si_SampleId; + private String si_SampleDilutionFactor; + //Original Files 部份的属性 + private String of_DataFile; + private String of_MethodFile; + private String of_BatchFile; + private String of_TuningFile; + //MS Quantitative Results 部份的属性 + private Integer mqr_Index=0; + private Integer mqr_DataCount; + private List mqrDataHeaderList; + private Map mqrDataMap; + private List childDataList=new ArrayList<>(); + private int currentSection;//当前节点 的索引号 index + + public void calcMqrIndex(){ + this.mqr_Index=this.mqr_Index+1; + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/nps/NPSTestDetailDataStruct.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/nps/NPSTestDetailDataStruct.java new file mode 100644 index 0000000..037b389 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/datafile/nps/NPSTestDetailDataStruct.java @@ -0,0 +1,32 @@ +package digital.laboratory.platform.inspection.utils.datafile.nps; + +import lombok.Data; + +/** + * @author xy + * @version 1.0 + * @title NPS详细数据结构 + * @description + * @create 2024/1/24 11:08 + */ +@Data +public class NPSTestDetailDataStruct{ + private String id; + private String name; + private String type; + private String mass;//mz 质荷比 + private double retTime;//保留时间 + private double startTime; + private double endTime; + private double area;//峰面积 + private double stdRetTime; + private double sn; + private double abundanceRatio;//丰度比,如果是基峰,我们设置为1,丰度比的公式为自己的峰面积/基峰峰面积 + private double abundanceRatio_std;// 标准物质的丰度比 + private double abundanceRatioError;//丰度比偏差,如果是基峰不需要比,公式是 (自己的丰度比-标准品的MZ对应丰度比)/标准品的MZ对应丰度比 + private double errorRange;//误差范围 + private String withinError ;//丰度比偏差是否在误差范围内 + private int isBasePeak;//是否是基峰,0 不是基峰 1 是基峰 + private boolean notIdentified = false; // 标记从文件中读取的数据是不是有not identified, 默认 false 没有 + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/AxisYVal.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/AxisYVal.java new file mode 100644 index 0000000..a32222b --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/AxisYVal.java @@ -0,0 +1,30 @@ +package digital.laboratory.platform.inspection.utils.sewagereport; + +import lombok.Getter; +import lombok.Setter; +import org.apache.poi.xddf.usermodel.XDDFColor; + +/** + * Y周坐标值 + * + * @author liuxn + * @date 2022/10/27 + */ +@Setter +@Getter +public class AxisYVal { + + /** + * Y轴数据、与X轴数据数量保持一致 + */ + private Number[] val; + /** + * Y轴数据 图例 + */ + private String title; + /** + * Y 周颜色 + */ + private XDDFColor color; + // todo 其他属性配置 +} \ No newline at end of file diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/BarLineChartForm.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/BarLineChartForm.java new file mode 100644 index 0000000..c500f68 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/BarLineChartForm.java @@ -0,0 +1,31 @@ +package digital.laboratory.platform.inspection.utils.sewagereport; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * 柱状+折线 + * + * @author liuxn + * @date 2022/10/27 + */ +@Setter +@Getter +public class BarLineChartForm extends ChartForm { + + /** + * X轴数据 + */ + private List xData; + /** + * 柱状数据 支持多组 + */ + private List yBarData; + /** + * 折线数据 支持多组 + */ + private List yLineData; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/ChartForm.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/ChartForm.java new file mode 100644 index 0000000..510da08 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/ChartForm.java @@ -0,0 +1,27 @@ +package digital.laboratory.platform.inspection.utils.sewagereport; + +import lombok.Getter; +import lombok.Setter; + +/** + * 图表属性 + * + * @author liuxn + * @date 2022/10/27 + */ +@Setter +@Getter +public class ChartForm { + /** + * 图表标题 + */ + private String title; + /** + * X轴标题 + */ + private String xTitle; + /** + * Y轴标题 + */ + private String yTitle; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/PieChartForm.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/PieChartForm.java new file mode 100644 index 0000000..6a4d423 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/PieChartForm.java @@ -0,0 +1,27 @@ +package digital.laboratory.platform.inspection.utils.sewagereport; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * 饼状图 + * + * @author liuxn + * @date 2022/10/27 + */ +@Setter +@Getter +public class PieChartForm extends ChartForm { + /** + * X轴 图例 + */ + private List xData; + + /** + * 饼状数据 + */ + private AxisYVal yData; + +} \ No newline at end of file diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/TableCreateUtils.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/TableCreateUtils.java new file mode 100644 index 0000000..a413ad5 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/TableCreateUtils.java @@ -0,0 +1,675 @@ +package digital.laboratory.platform.inspection.utils.sewagereport; + +import cn.hutool.core.collection.CollUtil; +import com.deepoove.poi.util.TableTools; +import digital.laboratory.platform.inspection.dto.RegionalDrugConsumptionDTO; +import org.apache.poi.xwpf.usermodel.*; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; + +import java.math.BigInteger; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** +* date: 2024/4/26 14:04 +* @author: Chen +* @since JDK 1.8 +* Description: 污水样本分析报告各类表格生成工具类, 设置word纸张方向api +*/ +public class TableCreateUtils { + + public static final String SUBSECTIONONE = "v"; + + public static final String SUBSECTIONTWO = "landscape"; // 纸张方向为横向 + + /** + * 分段 + * @param xwpfDocument 要生成的word文档对象 + * @param result SUBSECTIONONE / SUBSECTIONTWO + */ + public static void subsection(XWPFDocument xwpfDocument, String result) { + CTDocument1 doc = xwpfDocument.getDocument(); + CTBody body = doc.getBody(); + CTP ctp = body.addNewP(); + CTPPr ctpPr = ctp.addNewPPr(); + CTSectPr ctSectPr = ctpPr.addNewSectPr(); + changeOrientation(ctSectPr, result); + } + + /** + * 陕西省各行政区主要毒品总消费量表 + * @param document 生成表格的文档对象 + * @param rows 表格的行数 + * @param cols 表格的列数 + * @param nameList 表格的表头名称 + * @param dataList 表格数据列表 + */ + public static void fetchRegionalDrugConsumptionTable(XWPFDocument document, int rows, int cols, List nameList, List dataList) { + + // 创建一个rows行cols列的表格 + XWPFTable table = getXwpfTable(document, rows, cols); + + // 给表格设置边框 + setTableBorderAttributes(table); + + // 遍历表格设置属性 + List tableRowList = table.getRows(); + setTableCellAttribute(tableRowList); + // 合并单元格 + int mergeCount = tableRowList.get(0).getTableCells().size() / 2; + TableTools.mergeCellsHorizonal(table, 0, 1, mergeCount); + TableTools.mergeCellsHorizonal(table, 0, 2, mergeCount + 1); + + //垂直合并第一列 + TableTools.mergeCellsVertically(table, 0, 0, 1); + // 填充表格数据 + for (XWPFTableRow tableRow : table.getRows()) { + switch (table.getRows().indexOf(tableRow)) { + case 0: + tableRow.getCell(0).setText("行政区"); + tableRow.getCell(1).setText("千人均消费量(毫克/千人/天)"); + tableRow.getCell(2).setText("总消费量(克/天)"); + break; + case 1: + int size = tableRow.getTableCells().size(); + for (int i = 1; i < size; i++) { + // 因为第一列的单元格被合并了,所以从第二个开始 + tableRow.getCell(i).setText(nameList.get((i - 1) % nameList.size())); + } + break; + } + } + // 填充数据 + for (int i = 0; i < dataList.size(); i++) { + RegionalDrugConsumptionDTO dto = dataList.get(i); + XWPFTableRow tableRow = table.getRow(i + 2); + tableRow.getCell(0).setText(dto.getRegional()); + // 千人均消费量(毫克/千人/天) + tableRow.getCell(1).setText(dto.getPccHeroin()); + tableRow.getCell(2).setText(dto.getPccMa()); + tableRow.getCell(3).setText(dto.getPccK()); + tableRow.getCell(4).setText(dto.getPccMdma()); + tableRow.getCell(5).setText(dto.getPccCoc()); + tableRow.getCell(6).setText(dto.getPccFen()); + tableRow.getCell(7).setText(dto.getPccTotal()); + + // 总消费量(克/天) + tableRow.getCell(8).setText(dto.getTcHeroin()); + tableRow.getCell(9).setText(dto.getTcMa()); + tableRow.getCell(10).setText(dto.getTcK()); + tableRow.getCell(11).setText(dto.getTcMdma()); + tableRow.getCell(12).setText(dto.getTcCoc()); + tableRow.getCell(13).setText(dto.getTcFen()); + tableRow.getCell(14).setText(dto.getTcTotal()); + + } + } + + /** + * 陕西省各污水厂服务区及各行政区毒品千人均消费量表 + * @param document 生成表格的文档对象 + * @param rows 表格的行数 + * @param cols 表格的列数 + * @param nameList 表格的表头名称 + * @param dataMap 表格数据列表 第一个元素是 行政区 2 区县 + */ + public static void fetchServiceAreaDrugConsumptionPerThousandTable(XWPFDocument document, int rows, int cols, List nameList, Map>> dataMap) { + + // 创建一个一行两列 + XWPFTable table = document.createTable(rows, cols); +// table.setWidth("100%"); + // 创建表格后,添加grid 网格,grid 规定了表格每一列的宽度,对后面合并单元格有作用 + CTTblGrid grid = table.getCTTbl().addNewTblGrid(); + // grid 的宽度单位是 twips, twip 是 point 的 1/20。一英寸有 1440 twips, 一英寸 2.54厘米, + // 假设我们的表格第一列 4cm,第二列 8cm,那么需要先除以 2.54 得到英寸再乘以 1440 得到 twips。 + for (int i = 0; i < cols; i++) { + if (i == 1) { + grid.addNewGridCol().setW(BigInteger.valueOf((long) (3 / 2.54 * 1440))); + } else { + grid.addNewGridCol().setW(BigInteger.valueOf((long) (1.5 / 2.54 * 1440))); + } + } + + // 给表格设置边框 + setTableBorderAttributes(table); + List tableRows = table.getRows(); // 或row元素 + for (XWPFTableRow tableRow : tableRows) { + for (XWPFTableCell tableCell : tableRow.getTableCells()) { + int indexOf = tableRows.indexOf(tableRow); + int indexOfCell = tableRow.getTableCells().indexOf(tableCell); + if (indexOf == 1 || indexOf == 0) { + tableCell.getCTTc().addNewTcPr().addNewTcBorders(); + tableCell.setColor("b5d9fc"); // 填充单元格颜色 91,155,213 5b9bd5 b5d9fc + } + if (indexOfCell == 1) { + tableCell.setWidth(Long.toString((long) (3 / 2.54 * 1440))); + } else { + tableCell.setWidth(Long.toString((long) (1.5 / 2.54 * 1440))); + } + tableCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); + tableCell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER); + } + } + + // 先垂直合并第9列 0,1单元格, 因为先操作水平合并后,表格结构发生改变不好操作 + TableTools.mergeCellsVertically(table, cols -1, 0, 1); + // 水平合并 第一行 2到8列 + TableTools.mergeCellsHorizonal(table, 0, 2, 8); + //垂直合并第一列 + TableTools.mergeCellsVertically(table, 0, 0, 1); + // 垂直合并第二列 0,1单元格 + TableTools.mergeCellsVertically(table, 1, 0, 1); + // 垂直合并剩下的第一列 1 到最后一行 + TableTools.mergeCellsVertically(table, 0, 2, tableRows.size() - 1); + + for (XWPFTableRow tableRow : tableRows) { + switch (tableRows.indexOf(tableRow)) { + case 0: + tableRow.getCell(0).setText("行政区"); + tableRow.getCell(1).setText("区/县"); + tableRow.getCell(2).setText("千人均消费量(毫克/千人/天)"); + tableRow.getCell(3).setText("备注"); + break; + case 1: + int size = tableRow.getTableCells().size(); + for (int i = 2; i < size -1; i++) { + // 因为第一列的单元格被合并了,所以从第二个开始 + tableRow.getCell(i).setText(nameList.get((i -2) % nameList.size())); + } + break; + } + } + // 填充表格数据 + dataMap.forEach((k,v) -> { + // 前两行是表头,所以从第三行开始 + tableRows.get(2).getCell(0).setText(k); + for (int i = 0; i < v.size(); i++) { + List rowDataList = v.get(i); + XWPFTableRow xwpfTableRow = tableRows.get(i + 2); + for (int j = 0; j < rowDataList.size(); j++) { + xwpfTableRow.getCell(j + 1).setText(rowDataList.get(j).toString()); + } + } + }); + + } + + /** + * 陕西省各市毒品千人均消费量具体增长率/下降率表 + * @param document + * @param rows + * @param cols + * @param cityNameList + * @param dataList + */ + public static void fetchCityDrugConsumptionGrowthRatesTable(XWPFDocument document, int rows, int cols, List cityNameList, List> dataList) { + + // 创建一个一行两列 + XWPFTable table = getXwpfTable(document, rows, cols); + + // 给表格设置边框 + setTableBorderAttributes(table); + List tableRows = table.getRows(); // 或row元素 + for (XWPFTableRow tableRow : tableRows) { + for (XWPFTableCell tableCell : tableRow.getTableCells()) { + int indexOf = tableRows.indexOf(tableRow); + if (indexOf == 0) { + tableCell.setColor("bdd7ee"); // 填充单元格颜色 + } + if (indexOf == 0 && tableRow.getTableCells().indexOf(tableCell) == 0) { + tableCell.setText("行政区"); + for (XWPFParagraph row1Cell1Paragraph : tableCell.getParagraphs()) { + row1Cell1Paragraph.setAlignment(ParagraphAlignment.CENTER); + row1Cell1Paragraph.setVerticalAlignment(TextAlignment.TOP); + } + XWPFParagraph xwpfParagraph = tableCell.addParagraph(); + xwpfParagraph.createRun().addBreak(); + xwpfParagraph.createRun().addBreak(); + xwpfParagraph.createRun().setText("增长/下降"); + xwpfParagraph.setAlignment(ParagraphAlignment.CENTER); + xwpfParagraph.setVerticalAlignment(TextAlignment.BOTTOM); + + // 设置对角线 + CTTcPr tcPr = tableCell.getCTTc().getTcPr(); + CTTcBorders ctTcBorders = tcPr.isSetTcBorders() ? tcPr.getTcBorders() : tcPr.addNewTcBorders(); + CTBorder ctBorder = ctTcBorders.isSetTl2Br() ? ctTcBorders.getTl2Br() : ctTcBorders.addNewTl2Br(); + ctBorder.setVal(STBorder.SINGLE); + ctBorder.setSz(BigInteger.valueOf(4)); + ctBorder.setSpace(BigInteger.valueOf(0)); + ctBorder.setColor("auto"); + tableCell.setWidth(Long.toString((long) (5 / 2.54 * 1440))); + } else { + tableCell.setWidth(Long.toString((long) (2 / 2.54 * 1440))); + tableCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); + tableCell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER); + } + } + } + for (XWPFTableRow row : tableRows) { + int indexOfRow = tableRows.indexOf(row); + switch (indexOfRow) { + case 0: + for (int i = 1; i < row.getTableCells().size(); i++) { + XWPFTableCell cell = row.getCell(i); + cell.setText(cityNameList.get(i - 1)); + } + break; + default: + // 填充表格数据 + XWPFTableRow xwpfTableRow = tableRows.get(indexOfRow); + List list = dataList.get(indexOfRow - 1); + for (int i = 0; i < xwpfTableRow.getTableCells().size(); i++) { + xwpfTableRow.getCell(i).setText(list.get(i).toString()); + } + break; + } + } + + } + + + /** + * xxxx年mm月陕西省毒品滥用情况分析中各类毒品表生成 + * 表4 陕西省污水处理厂冰毒浓度排名表 + * 表5 陕西省污水处理厂吗啡检测情况 + * @param document + * @param rows + * @param cols + * @param tableName1List + * @param tableName2List + * @param dataList + */ + public static void fetchCityDrugAbuseConditionAnalysisTable(XWPFDocument document, int rows, int cols, + List tableName1List, List tableName2List, List> dataList) { + // 创建一个一行两列 + XWPFTable table = document.createTable(rows, cols); +// table.setWidth("100%"); + // 创建表格后,添加grid 网格,grid 规定了表格每一列的宽度,对后面合并单元格有作用 + CTTblGrid grid = table.getCTTbl().addNewTblGrid(); + // grid 的宽度单位是 twips, twip 是 point 的 1/20。一英寸有 1440 twips, 一英寸 2.54厘米, + // 假设我们的表格第一列 4cm,第二列 8cm,那么需要先除以 2.54 得到英寸再乘以 1440 得到 twips。 + for (int i = 0; i < cols; i++) { + if (i % 2 == 1) { + grid.addNewGridCol().setW(BigInteger.valueOf((long) (4 / 2.54 * 1440))); + } else { + grid.addNewGridCol().setW(BigInteger.valueOf((long) (2 / 2.54 * 1440))); + } + } + // 给表格设置边框 + setTableBorderAttributes(table); + + List tableRows = table.getRows(); + + for (XWPFTableRow tableRow : tableRows) { + for (XWPFTableCell tableCell : tableRow.getTableCells()) { + int indexOf = tableRows.indexOf(tableRow); + int indexOfCell = tableRow.getTableCells().indexOf(tableCell); + if (indexOf == 1 || indexOf == 0) { + tableCell.setColor("bdd7ee"); // 填充单元格颜色 + } + if (indexOfCell % 2 == 1) { + tableCell.setWidth(Long.toString((long) (4 / 2.54 * 1440))); + } else { + tableCell.setWidth(Long.toString((long) (2 / 2.54 * 1440))); + } + tableCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); + tableCell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER); + } + } + +// for (String colName : tableName1List) { +// 潜在的逻辑错误:如果tableName1List中有重复的元素,那么indexOf将总是返回第一次出现的索引,这可能导致某些合并操作被错误地重复执行,而不是针对每个唯一的索引执行一次。 +// int indexOf = tableName1List.indexOf(colName); +// switch (indexOf) { +// case 0: { +// TableTools.mergeCellsHorizonal(table, 0, 1, 2); +// break; +// } +// case 1: { +// TableTools.mergeCellsHorizonal(table, 0, 2, 3); +// break; +// } +// case 2: { +// TableTools.mergeCellsHorizonal(table, 0, 3, 4); +// break; +// } +// case 3: { +// TableTools.mergeCellsHorizonal(table, 0, 4, 5); +// break; +// } +// case 4: { +// TableTools.mergeCellsHorizonal(table, 0, 5, 6); +// break; +// } +// } +// } + // 根据tableName1List的大小合并表头单元格 + for (int i = 0; i < tableName1List.size(); i++) { + TableTools.mergeCellsHorizonal(table, 0, i + 1, i + 2); + } +// TableTools.mergeCellsHorizonal(table, 0, 1, 2); +// TableTools.mergeCellsHorizonal(table, 0, 2, 3); +// TableTools.mergeCellsHorizonal(table, 0, 3, 4); +// TableTools.mergeCellsHorizonal(table, 0, 4, 5); +// TableTools.mergeCellsHorizonal(table, 0, 5, 6); + + //垂直合并第一列 + TableTools.mergeCellsVertically(table, 0, 0, 1); + + for (XWPFTableRow tableRow : tableRows) { + int indexOfRow = tableRows.indexOf(tableRow); + switch (indexOfRow) { + case 0: + tableRow.getCell(0).setText("序号"); + List tableCells = tableRow.getTableCells(); + for (int i = 1; i < tableCells.size() && i <= tableName1List.size(); i++) { + tableRow.getCell(i).setText(tableName1List.get(i -1)); + } + break; + case 1: + int size = tableRow.getTableCells().size(); + for (int i = 1; i < size; i++) { + // 因为第一列的单元格被合并了,所以从第二个开始 + tableRow.getCell(i).setText(tableName2List.get((i -1) % tableName2List.size())); + } + break; + default: + // 数据填充 + if (CollUtil.isNotEmpty(dataList)) { + XWPFTableRow xwpfTableRow = tableRows.get(indexOfRow); + List list = dataList.get(indexOfRow - 2); + for (int i = 0; i < xwpfTableRow.getTableCells().size() && i < list.size(); i++) { + xwpfTableRow.getCell(i).setText(list.get(i).toString()); + } + } + break; + } + } + } + + /** + * 附表:陕西省各污水厂监测点主要毒品及其代谢物每日浓度表 + * @param document + * @param rows + * @param cols + * @param tableName2List + * @param dataMap + */ + public static void fetchDailyDrugAndMetaboliteConcentrationTable(XWPFDocument document, int rows, int cols, + List tableName2List, Map>> dataMap) { + + XWPFTable table = document.createTable(rows, cols); +// table.setWidth("100%"); + // 创建表格后,添加grid 网格,grid 规定了表格每一列的宽度,对后面合并单元格有作用 + CTTblGrid grid = table.getCTTbl().addNewTblGrid(); + // grid 的宽度单位是 twips, twip 是 point 的 1/20。一英寸有 1440 twips, 一英寸 2.54厘米, + // 假设我们的表格第一列 4cm,第二列 8cm,那么需要先除以 2.54 得到英寸再乘以 1440 得到 twips。 + for (int i = 0; i < table.getRows().get(0).getTableCells().size(); i++) { + if (i == 1) { + grid.addNewGridCol().setW(BigInteger.valueOf((long) (4 / 2.54 * 1440))); + } else { + grid.addNewGridCol().setW(BigInteger.valueOf((long) (2 / 2.54 * 1440))); + } + } + // 设置表格边框属性 + setTableBorderAttributes(table); + + List tableRows = table.getRows(); + for (XWPFTableRow tableRow : tableRows) { + for (XWPFTableCell tableCell : tableRow.getTableCells()) { + int indexOf = tableRows.indexOf(tableRow); + int indexOfCell = tableRow.getTableCells().indexOf(tableCell); + if (indexOf == 1 || indexOf == 0) { + tableCell.setColor("5b9bd5"); // 填充单元格颜色 + } + if (indexOfCell == 1) { + // 第二列因为是污水厂,所以调大点 + tableCell.setWidth(Long.toString((long) (4 / 2.54 * 1440))); + } else { + tableCell.setWidth(Long.toString((long) (2 / 2.54 * 1440))); + } + tableCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); + XWPFParagraph xwpfParagraph = tableCell.getParagraphs().get(0); + xwpfParagraph.setAlignment(ParagraphAlignment.CENTER); + + } + } + + //垂直合并第一列 + TableTools.mergeCellsVertically(table, 0, 0, 1); + TableTools.mergeCellsVertically(table, 1, 0, 1); + TableTools.mergeCellsVertically(table, 2, 0, 1); + TableTools.mergeCellsVertically(table, 16, 0, 1); + // 水平合并 ,这里的代码顺序不能变更,会影响代码的执行 + TableTools.mergeCellsHorizonal(table, 0, 3, 17-2); + // 合并单元格并填充数据 + mergeTableCellAndFillData(dataMap, table); + +// List tableName2List = new ArrayList<>(Arrays.asList("可替宁","可待因","MDA","MDMA","可卡因","苯甲酰爱康宁","吗啡","O6-单乙酰吗啡","甲基苯丙胺","苯丙胺","氯胺酮","去甲氯胺酮","芬太尼")); + for (XWPFTableRow tableRow : table.getRows()) { + switch (table.getRows().indexOf(tableRow)) { + case 0: + tableRow.getCell(0).setText("行政区"); + tableRow.getCell(1).setText("污水处理厂"); + tableRow.getCell(2).setText("采样时间"); + tableRow.getCell(3).setText("浓度(纳克/升)"); + tableRow.getCell(4).setText(""); + break; + case 1: + int size = tableRow.getTableCells().size(); + for (int i = 3; i < size-1; i++) { + // 因为第一列的单元格被合并了,所以从第二个开始 + tableRow.getCell(i).setText(tableName2List.get((i -3) % tableName2List.size())); + } + break; + } + } + + } + + /** + * 表3 陕西省第二季度各行政区污水厂检出依托咪酯统计表 + * @param document 生成表格的文档对象 + * @param rows 表格的行数 + * @param cols 表格的列数 + * @param tableDataList 表格数据列表 + */ + public static void fetchEtomidateDetectedStatisticalTable(XWPFDocument document, int rows, int cols, List> tableDataList) { + XWPFTable table = document.createTable(rows, cols); +// table.setWidth("100%"); + // 创建表格后,添加grid 网格,grid 规定了表格每一列的宽度,对后面合并单元格有作用 + CTTblGrid grid = table.getCTTbl().addNewTblGrid(); + // grid 的宽度单位是 twips, twip 是 point 的 1/20。一英寸有 1440 twips, 一英寸 2.54厘米, + // 假设我们的表格第一列 4cm,第二列 8cm,那么需要先除以 2.54 得到英寸再乘以 1440 得到 twips。 + for (int i = 0; i < 8; i++) { + if (i == 7) { + grid.addNewGridCol().setW(BigInteger.valueOf((long) (10 / 2.54 * 1440))); + } else { + grid.addNewGridCol().setW(BigInteger.valueOf((long) (2 / 2.54 * 1440))); + } + } + + // 给表格设置边框 + setTableBorderAttributes(table); + + List tableRows = table.getRows(); + for (XWPFTableRow tableRow : tableRows) { + for (XWPFTableCell tableCell : tableRow.getTableCells()) { + int indexOf = tableRows.indexOf(tableRow); + int indexOfCell = tableRow.getTableCells().indexOf(tableCell); + if (indexOf == 0) { + tableCell.setColor("bdd7ee"); // 填充单元格颜色 + } + if (indexOfCell != 7) { + tableCell.setWidth(Long.toString((long) (3 / 2.54 * 1440))); + tableCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); + tableCell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER); + } else { + tableCell.setWidth(Long.toString((long) (12 / 2.54 * 1440))); + tableCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.BOTH); + tableCell.getParagraphs().get(0).setAlignment(ParagraphAlignment.LEFT); + } + } + } + + for (int i = 0; i < tableRows.size(); i++) { + List tableCells = tableRows.get(i).getTableCells(); + List list = tableDataList.get(i); + for (int j = 0; j < tableCells.size(); j++) { + tableCells.get(j).setText(list.get(j).toString()); + } + } + } + + + /** + * 创建word表格 + * @param document + * @param rows + * @param cols + * @return + */ + private static XWPFTable getXwpfTable(XWPFDocument document, int rows, int cols) { + // 创建一个一行两列 + XWPFTable table = document.createTable(rows, cols); +// table.setWidth("100%"); + // 创建表格后,添加grid 网格,grid 规定了表格每一列的宽度,对后面合并单元格有作用 + CTTblGrid grid = table.getCTTbl().addNewTblGrid(); + // grid 的宽度单位是 twips, twip 是 point 的 1/20。一英寸有 1440 twips, 一英寸 2.54厘米, + // 假设我们的表格第一列 4cm,第二列 8cm,那么需要先除以 2.54 得到英寸再乘以 1440 得到 twips。 + for (int i = 0; i < cols; i++) { + grid.addNewGridCol().setW(BigInteger.valueOf((long) (2 / 2.54 * 1440))); + } + return table; + } + + /** + * 根据市的数据量合并单元格和填充数据 + * @param dataMap + * @param table + */ + private static void mergeTableCellAndFillData(Map>> dataMap, XWPFTable table) { + // 根据数据合并单元格 + AtomicInteger fromRow = new AtomicInteger(2);// 数据开始插入行,比如说表格有0,1两行表头,所以从 第三行 2表头开始 + // 合并单元格 数据填充 + dataMap.forEach((k, v) -> { + int toRow = fromRow.get() + v.size(); + if (toRow == table.getRows().size()) { + // 如果是最后一次数据合并,则 -1 + toRow = toRow -1; // 防止下标越界, + } + if (v.size() != 1) { + // 只有当数据量大于1时才需要合并第一列的单元格 + TableTools.mergeCellsVertically(table, 0, fromRow.get(), toRow); + } + XWPFTableRow tableRow = table.getRow(fromRow.get()); + tableRow.getCell(0).setText(k); + Map>> groupBySewagePlant = new HashMap<>(); + for (List list : v) { + if (groupBySewagePlant.containsKey(list.get(0).toString())) { + groupBySewagePlant.get(list.get(0)).add(list); + } else { + groupBySewagePlant.put(list.get(0).toString(), new ArrayList<>(Arrays.asList(list))); + } + } + // 取分好类的数据 + List keyList = new ArrayList<>(groupBySewagePlant.keySet()); + int startRow = fromRow.get(); + for (String s : keyList) { + List> dataMapBySewagePlantList = groupBySewagePlant.get(s); + if (dataMapBySewagePlantList.size() == 2) { + TableTools.mergeCellsVertically(table, 1, startRow, startRow + 1); + + for (int count = 0; count < dataMapBySewagePlantList.size(); count++) { + List list = dataMapBySewagePlantList.get(count); + + XWPFTableRow tableDataRow = table.getRow(startRow + count); + if (count == 0) { + tableDataRow.getCell(1).setText(s.toString()); + } + // 从2开始的原因是 第一个 是行政区, 第二个是污水厂 + for (int cellIndex = 2; cellIndex < tableDataRow.getTableCells().size(); cellIndex++) { + tableDataRow.getCell(cellIndex).setText(list.get(cellIndex - 1).toString()); + } + } + + startRow = startRow + 2; + } else { + XWPFTableRow tableDataRow = table.getRow(startRow); + List list = dataMapBySewagePlantList.get(0); + // 从2开始的原因是 第一个 是行政区, 第二个是污水厂 + for (int cellIndex = 1; cellIndex < tableDataRow.getTableCells().size(); cellIndex++) { + tableDataRow.getCell(cellIndex).setText(list.get(cellIndex - 1).toString()); + } + startRow++; + } + } + fromRow.getAndAdd(v.size()); + }); + } + + + /** + * 设置表格边框属性 + * @param table + */ + private static void setTableBorderAttributes(XWPFTable table) { + table.setLeftBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000"); + table.setRightBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000"); + table.setTopBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000"); + table.setBottomBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000"); + table.setInsideHBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000"); + table.setInsideVBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000"); + } + + /** + * 设置纸张方向 + * @param section + * @param orientation 字符串方向 + */ + private static void changeOrientation(CTSectPr section, String orientation) { + CTPageSz pageSize = section.isSetPgSz() ? section.getPgSz() : section.addNewPgSz(); + // 设置页边距 + CTPageMar ctPageMar = section.isSetPgMar() ? section.getPgMar() : section.addNewPgMar(); + if (orientation.equals(SUBSECTIONTWO)) { + pageSize.setOrient(STPageOrientation.LANDSCAPE); + pageSize.setW(BigInteger.valueOf(842 * 20)); + pageSize.setH(BigInteger.valueOf(595 * 20)); + // 设置页边距 +// CTPageMar ctPageMar = section.isSetPgMar() ? section.getPgMar() : section.addNewPgMar(); + ctPageMar.setLeft(new BigInteger((28 * 20) + "")); + ctPageMar.setTop(new BigInteger((28 * 20) + "")); + ctPageMar.setRight(new BigInteger((28 * 20) + "")); + ctPageMar.setBottom(new BigInteger((28 * 20) + "")); + } else { + pageSize.setOrient(STPageOrientation.PORTRAIT); + pageSize.setH(BigInteger.valueOf(842 * 20)); + pageSize.setW(BigInteger.valueOf(595 * 20)); + // 设置页边距 为 上 1.28厘米 左 右 下都是2.4厘米 1 厘米等于28磅 +// CTPageMar ctPageMar = section.isSetPgMar() ? section.getPgMar() : section.addNewPgMar(); +// ctPageMar.setLeft(new BigInteger((67 * 20) + "")); +// ctPageMar.setTop(new BigInteger((36 * 20) + "")); +// ctPageMar.setRight(new BigInteger((67 * 20) + "")); +// ctPageMar.setBottom(new BigInteger((67 * 20) + "")); + } + } + + /** + * 根据表格的所有行遍历单元格设置单元格属性 + * @param tableRowList + */ + private static void setTableCellAttribute(List tableRowList) { + for (XWPFTableRow tableRow : tableRowList) { + for (XWPFTableCell tableCell : tableRow.getTableCells()) { + int indexOf = tableRowList.indexOf(tableRow); + if (indexOf == 1 || indexOf == 0) { + tableCell.setColor("bdd7ee"); // 填充单元格颜色 + } + tableCell.setWidth(Long.toString((long) (2 / 2.54 * 1440))); + tableCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); + tableCell.getParagraphs().get(0).setAlignment(ParagraphAlignment.CENTER); + } + } + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/TableForm.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/TableForm.java new file mode 100644 index 0000000..e3f2fd7 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/TableForm.java @@ -0,0 +1,40 @@ +package digital.laboratory.platform.inspection.utils.sewagereport; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * 表格数据 + * + * @author liuxn + * @date 2022/10/27 + */ +@Setter +@Getter +public class TableForm { + //表头数据 + private List headerList; + + //表头数据 + private List header2List; + /** + * 表格数据 + */ + private List> rowDataList; + + //todo 表格其他属性 + + @Setter + @Getter + public static class CellData { + //单元格值 + private String val; + // todo 其他单元格属性 + + public CellData(String val) { + this.val = val; + } + } +} \ No newline at end of file diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/WordUtils.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/WordUtils.java new file mode 100644 index 0000000..a8b2ce0 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/utils/sewagereport/WordUtils.java @@ -0,0 +1,917 @@ +package digital.laboratory.platform.inspection.utils.sewagereport; + +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellReference; +import org.apache.poi.util.Units; +import org.apache.poi.xddf.usermodel.chart.*; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.apache.poi.xwpf.usermodel.*; +import org.apache.xmlbeans.XmlException; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTDLbls; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.math.BigInteger; +import java.net.URLEncoder; +import java.util.List; + +/** +* date: 2024/4/26 11:58 +* @author: Chen +* @since JDK 1.8 +* Description: 封装的一下poi接口,有生成图表的接口, 创建标题的接口, 创建段落的 +*/ +@Slf4j +public class WordUtils { + + + /** + * 设置模板样式, 比如标题 + * @param document + * @param templateStylePath + */ + public static void setDocumentStyle(XWPFDocument document, String templateStylePath) { + // word整体样式 + // 读取模板文档 + XWPFDocument template = null; + // 获得模板文档的整体样式 + CTStyles wordStyles = null; + try { + template = new XWPFDocument(new FileInputStream(templateStylePath)); + wordStyles = template.getStyle(); + } catch (XmlException e) { + e.printStackTrace(); + log.error("模板样式读取失败!"); + } catch (IOException e) { + e.printStackTrace(); + log.error("模板样式读取失败!"); + } + // 获取新建文档对象的样式 + XWPFStyles newStyles = document.createStyles(); + // 关键行// 修改设置文档样式为静态块中读取到的样式 + newStyles.setStyles(wordStyles); + } + + /** + * 设置模板样式, 比如标题 + * @param document + * @param inputStream + */ + public static void setDocumentStyle(XWPFDocument document, InputStream inputStream) { + // word整体样式 + // 读取模板文档 + XWPFDocument template = null; + // 获得模板文档的整体样式 + CTStyles wordStyles = null; + try { +// OPCPackage open = OPCPackage.open(inputStream); + template = new XWPFDocument(inputStream); + wordStyles = template.getStyle(); + } catch (XmlException e) { + e.printStackTrace(); + log.error("模板样式读取失败!"); + } catch (IOException e) { + e.printStackTrace(); + log.error("模板样式读取失败!"); + } + // 获取新建文档对象的样式 + XWPFStyles newStyles = document.createStyles(); + // 关键行// 修改设置文档样式为静态块中读取到的样式 + newStyles.setStyles(wordStyles); + } + + /** + * 创建文件首页内容 + * @param document + * @param docTitle + * @param fontFamily 字体 + * @param breakSize 换行行数 + * @param fontSize 字体大小 + */ + public static void createDocHomePage(XWPFDocument document, String docTitle, String fontFamily,int breakSize, int fontSize) { + //新建一个标题段落对象(就是一段文字) + XWPFParagraph titleParagraph = document.createParagraph(); + //样式居中 + titleParagraph.setAlignment(ParagraphAlignment.CENTER); + //创建文本对象 + XWPFRun titleFun = titleParagraph.createRun(); + //设置标题的名字 + titleFun.setText(docTitle); + if (StrUtil.isNotBlank(fontFamily)) { + titleFun.setFontFamily(fontFamily); + } + //加粗 + titleFun.setBold(true); + //设置颜色 + titleFun.setColor("000000"); + //字体大小 + titleFun.setFontSize(fontSize); + for (int i = 0; i < breakSize; i++) { + //换行 + titleFun.addBreak(); + } + } + + + /** + * 创建文件标题 + * + * @param document 文档 + * @param docTitle 完档标题 + */ + public static void createDocTitle(XWPFDocument document, String docTitle, boolean isBreak) { + //新建一个标题段落对象(就是一段文字) + XWPFParagraph titleParagraph = document.createParagraph(); + titleParagraph.setStyle("1"); + //样式居中 + titleParagraph.setAlignment(ParagraphAlignment.CENTER); + //创建文本对象 + XWPFRun titleFun = titleParagraph.createRun(); + //设置标题的名字 + titleFun.setText(docTitle); + //加粗 + titleFun.setBold(true); + //设置颜色 + titleFun.setColor("000000"); + //字体大小 + titleFun.setFontSize(16); + if (isBreak) { + //换行 + titleFun.addBreak(); + } + } + + /*** + * 创建段落标题 , 无标题设置 + * @param document 文档 + * @param parTitle 段落标题 + * @param isBreak 是否换行 + */ + public static void createParagraphTitle(XWPFDocument document, String parTitle, boolean isBreak) { + XWPFParagraph titleParagraph = document.createParagraph(); + + setParagraphTitleProperty(parTitle, isBreak, titleParagraph); + } + + + /*** + * 创建段落标题 有标题设置 + * @param document 文档 + * @param parTitle 段落标题 + * @param isBreak 是否换行 + * @param styleLevel 标题等级 + */ + public static void createParagraphTitle(XWPFDocument document, String parTitle, boolean isBreak, Integer styleLevel) { + XWPFParagraph titleParagraph = document.createParagraph(); + // 设置标题等级 + titleParagraph.setStyle(styleLevel.toString()); + + setParagraphTitleProperty(parTitle, isBreak, titleParagraph); + } + + /** + * 创建word文档段落, 可以选择设置tab的数量 + * + * @param document 文档 + * @param align ParagraphAlignment.LEFT 居左 + * @param paragraph 内容 + * @param isBreak 是否换行 + * @param tabCount 需要tab的数量 + */ + public static void createParagraphCustomTab(XWPFDocument document, ParagraphAlignment align, String paragraph, boolean isBreak, int firstLintIndent, int tabCount) { + XWPFParagraph titleParagraph = document.createParagraph(); + titleParagraph.setAlignment(align); + XWPFRun titleFun = titleParagraph.createRun(); + titleFun.setFontSize(12); + for (int i = 0; i < tabCount; i++) { + titleFun.addTab(); + } + titleFun.setFontFamily("宋体"); + titleFun.setText(paragraph); + titleFun.setColor("000000"); + titleParagraph.setFirstLineIndent(firstLintIndent); + // 设置段落行距 + setSingleLineSpacing(titleParagraph); + //换行 + if (isBreak) { + titleFun.addBreak(); + } + } + + /** + * 创建word文档段落 + * + * @param document 文档 + * @param align ParagraphAlignment.LEFT 居左 + * @param paragraph 内容 + * @param isBreak 是否换行 + */ + public static void createParagraph(XWPFDocument document, ParagraphAlignment align, String paragraph, boolean isBreak, int firstLintIndent) { + XWPFParagraph titleParagraph = document.createParagraph(); + titleParagraph.setAlignment(align); + XWPFRun titleFun = titleParagraph.createRun(); + titleFun.setFontSize(12); + + titleFun.addTab(); + + titleFun.setFontFamily("宋体"); + titleFun.setText(paragraph); + titleFun.setColor("000000"); + titleParagraph.setFirstLineIndent(firstLintIndent); + // 设置段落行距 + setSingleLineSpacing(titleParagraph); + //换行 + if (isBreak) { + titleFun.addBreak(); + } + } + + /** + * 创建word文档高亮段落 + * + * @param document 文档 + * @param align ParagraphAlignment.LEFT 居左 + * @param paragraph 内容 + * @param isBreak 是否换行 + */ + public static void createHighLightParagraph(XWPFDocument document, ParagraphAlignment align, String paragraph, boolean isBreak, int firstLintIndent) { + XWPFParagraph titleParagraph = document.createParagraph(); + titleParagraph.setAlignment(align); + XWPFRun titleFun = titleParagraph.createRun(); + highLight(titleParagraph, titleFun); + titleFun.setFontSize(12); + + titleFun.addTab(); + + titleFun.setFontFamily("宋体"); + titleFun.setText(paragraph); + titleFun.setColor("000000"); + titleParagraph.setFirstLineIndent(firstLintIndent); + // 设置段落行距 + setSingleLineSpacing(titleParagraph); + //换行 + if (isBreak) { + titleFun.addBreak(); + } + } + + /** + * 设置高亮属性 + * @param p + * @param run + */ + private static void highLight(XWPFParagraph p, XWPFRun run) { + CTRPr pRpr; + if (run.getCTR() != null) { + pRpr = run.getCTR().getRPr(); + if (pRpr == null) { + pRpr = run.getCTR().addNewRPr(); + } + } else { + pRpr = p.getCTP().addNewR().addNewRPr(); + } + CTHighlight highlight = pRpr.addNewHighlight(); + highlight.setVal(STHighlightColor.RED); + } + + + /** + * 设置段落行距 + * @param paragraph + */ + public static void setSingleLineSpacing(XWPFParagraph paragraph) { + CTP ctp = paragraph.getCTP(); + CTPPr ppr = ctp.isSetPPr() ? ctp.getPPr() : ctp.addNewPPr(); + CTSpacing spacing = ppr.isSetSpacing()? ppr.getSpacing() : ppr.addNewSpacing(); + spacing.setAfter(BigInteger.valueOf(10)); + spacing.setBefore(BigInteger.valueOf(0)); + //注意设置行距类型为 EXACT + spacing.setLineRule(STLineSpacingRule.EXACT); + //1磅数是20 + spacing.setLine(BigInteger.valueOf(480)); + + + } + + /** + * 创建word文档段落, 一部分加粗加粗, 一部分正常 + * + * @param document 文档 + * @param align ParagraphAlignment.LEFT 居左 + * @param paragraphBold 要加粗的内容 + * @param paragraph 不加粗的内容 + * @param isBreak 是否换行 + */ + public static void createParagraphAndBold(XWPFDocument document, ParagraphAlignment align, String paragraphBold, String paragraph, boolean isBreak, int firstLintIndent) { + XWPFParagraph titleParagraph = document.createParagraph(); + titleParagraph.setAlignment(align); + XWPFRun titleFun = titleParagraph.createRun(); + /** + * + 字体大小 磅值 + 五号 9pt + 小四 12pt + 四号 14pt + 三号 16pt + 小二 18pt + 二号 22pt + 一号 26pt + 小初 36pt + + */ + titleFun.setFontSize(12); // 小四 + titleFun.addTab(); + titleFun.setFontFamily("宋体"); + titleFun.setBold(true); + titleFun.setText(paragraphBold); + titleFun.setColor("000000"); + + XWPFRun xwpfRun = titleParagraph.createRun(); + xwpfRun.setFontSize(12); // 小四 +// xwpfRun.addTab(); + xwpfRun.setFontFamily("宋体"); + xwpfRun.setText(paragraph); + xwpfRun.setColor("000000"); + + titleParagraph.setFirstLineIndent(firstLintIndent); + setSingleLineSpacing(titleParagraph); + //换行 + if (isBreak) { + xwpfRun.addBreak(); + } + } + + /** + * 创建word文档段落, 两边是不加粗的内容,中间是需要加粗 + * + * @param document 文档 + * @param align ParagraphAlignment.LEFT 居左 + * @param paragraphBold 要加粗的内容 + * @param paragraph1 不加粗的内容1 + * @param paragraph2 不加粗的内容2 + * @param isBreak 是否换行 + */ + public static void createParagraphAndMiddleBold(XWPFDocument document, ParagraphAlignment align, String paragraphBold, String paragraph1, String paragraph2,boolean isBreak, int firstLintIndent) { + XWPFParagraph titleParagraph = document.createParagraph(); + titleParagraph.setAlignment(align); + titleParagraph.setFirstLineIndent(firstLintIndent); + // 第一部分 不加粗内容 + XWPFRun xwpfRun1 = titleParagraph.createRun(); + xwpfRun1.addTab(); + xwpfRun1.setFontSize(12); // 小四 + xwpfRun1.setFontFamily("宋体"); + xwpfRun1.setText(paragraph1); + xwpfRun1.setColor("000000"); + + // 中间加粗的内容 + XWPFRun titleFun = titleParagraph.createRun(); + /** + * + 字体大小 磅值 + 五号 9pt + 小四 12pt + 四号 14pt + 三号 16pt + 小二 18pt + 二号 22pt + 一号 26pt + 小初 36pt + */ + titleFun.setFontSize(12); // 小四 + titleFun.setFontFamily("宋体"); + titleFun.setBold(true); + titleFun.setText(paragraphBold); + titleFun.setColor("000000"); + // 第二部分不加粗的内容 + XWPFRun xwpfRun = titleParagraph.createRun(); + xwpfRun.setFontSize(12); // 小四 + xwpfRun.setFontFamily("宋体"); + xwpfRun.setText(paragraph2); + xwpfRun.setColor("000000"); + + setSingleLineSpacing(titleParagraph); + //换行 + if (isBreak) { + titleParagraph.createRun().addBreak(); + } + } + + /** + * 创建word文档段落, 两边是加粗的内容,中间是不需要加粗 + * + * @param document 文档 + * @param align ParagraphAlignment.LEFT 居左 + * @param paragraph 不要加粗的内容 + * @param paragraphBold1 加粗的内容1 + * @param paragraphBold2 加粗的内容2 + * @param isBreak 是否换行 + */ + public static void createParagraphAndBothSidesBold(XWPFDocument document, ParagraphAlignment align, String paragraph, String paragraphBold1, String paragraphBold2,boolean isBreak, int firstLintIndent) { + XWPFParagraph titleParagraph = document.createParagraph(); + titleParagraph.setAlignment(align); + titleParagraph.setFirstLineIndent(firstLintIndent); + // 第一部分 加粗内容 + XWPFRun xwpfRun = titleParagraph.createRun(); + xwpfRun.setFontSize(12); // 小四 + xwpfRun.setFontFamily("宋体"); + xwpfRun.addTab(); + xwpfRun.setBold(true); + xwpfRun.setText(paragraphBold1); + xwpfRun.setColor("000000"); + + // 中间不加粗的内容 + XWPFRun titleFun = titleParagraph.createRun(); + /** + * + 字体大小 磅值 + 五号 9pt + 小四 12pt + 四号 14pt + 三号 16pt + 小二 18pt + 二号 22pt + 一号 26pt + 小初 36pt + */ + titleFun.setFontSize(12); // 小四 + titleFun.setFontFamily("宋体"); + titleFun.setText(paragraph); + titleFun.setColor("000000"); + // 第二部分加粗的内容 + XWPFRun xwpfRun2 = titleParagraph.createRun(); + xwpfRun2.setFontSize(12); // 小四 + xwpfRun2.setFontFamily("宋体"); + xwpfRun2.setBold(true); + xwpfRun2.setText(paragraphBold2); + xwpfRun2.setColor("000000"); + + setSingleLineSpacing(titleParagraph); + //换行 + if (isBreak) { + titleParagraph.createRun().addBreak(); + } + } + + /** + * 创建饼图 + * + * @param document 文档 + * @param from 数据 + * @throws Exception + */ + public static void createPieChart(XWPFDocument document, PieChartForm from, String content) throws Exception { + XWPFChart chart = document.createChart(15 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER); + + // 设置图例位置:上下左右 + XDDFChartLegend legend = chart.getOrAddLegend(); + legend.setPosition(LegendPosition.BOTTOM); + legend.setOverlay(false); + chart.setTitleText(from.getTitle()); + chart.setTitleOverlay(false); + int numOfPoints = from.getXData().size(); + String[] categories = from.getXData().toArray(new String[]{}); + XDDFDataSource categoriesData = XDDFDataSourcesFactory.fromArray(categories); + String range = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0)); + AxisYVal yData = from.getYData(); + XDDFNumericalDataSource source = XDDFDataSourcesFactory.fromArray(yData.getVal(), range); + XDDFPieChartData pieChart = (XDDFPieChartData) chart.createData(ChartTypes.PIE, null, null); + pieChart.setVaryColors(true); + XDDFPieChartData.Series series = (XDDFPieChartData.Series) pieChart.addSeries(categoriesData, source); + series.setTitle(yData.getTitle(), setTitleInDataSheet(chart, yData.getTitle(), 0)); + // 设置数据标签显示占比 + series.setShowLeaderLines(true); + CTDLbls dLbls = series.getCTPieSer().getDLbls(); + setCTDlbls(dLbls, false, false,false,false); + chart.plot(pieChart); + setChartFontProperty(document, content); + } + + /** + * 创建表格 + * + * @param document 文档 + * @param from 表格数据 + */ + public static void createTable(XWPFDocument document, TableForm from) { + log.info(">> 开始生成表格"); + XWPFTable table = document.createTable(); + List headerList = from.getHeaderList(); + //创建表头 + XWPFTableRow headerRow = getTableRow(table, 0); + for (int i = 0; i < headerList.size(); i++) { + TableForm.CellData cellData = headerList.get(i); + XWPFTableCell cell = getTableRowCell(headerRow, i); + cell.setText(cellData.getVal()); + } + //表格数据 + List> rowDataList = from.getRowDataList(); + for (int i = 0; i < rowDataList.size(); i++) { + int rowIndex = i + 1; + List cellData = rowDataList.get(i); + XWPFTableRow row = getTableRow(table, rowIndex); + for (int x = 0; x < cellData.size(); x++) { + TableForm.CellData cellD = cellData.get(x); + XWPFTableCell cell = getTableRowCell(row, x); + cell.setText(cellD.getVal()); + } + } + log.info(">> 生成表格 完成"); + + } + + /** + * 生成图表 柱状图+折线+ 柱状折线组合 + * + * @param document 文档 + * @param chartForm 数据 + * @param content 图表名称 + * @param isShowLineVal 折线上是否显示数据 + * @throws Exception + */ + public static void createBarLineCharts(XWPFDocument document, BarLineChartForm chartForm, String content, boolean isShowLineVal) throws Exception { + if (chartForm == null) { + throw new IllegalArgumentException("数据为空"); + } + List xData = chartForm.getXData(); + if (xData == null) { + throw new IllegalArgumentException("X轴数据为空"); + } + List yBarData = chartForm.getYBarData(); + List yLintData = chartForm.getYLineData(); + if (yBarData == null && yLintData == null) { + throw new IllegalArgumentException("柱状数据、折线数据为空"); + } + XWPFChart chart = document.createChart(15 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER); + // 设置图例位置:上下左右 + XDDFChartLegend legend = chart.getOrAddLegend(); + legend.setPosition(LegendPosition.TOP); + legend.setOverlay(false); + // 设置标题 + chart.setTitleText(chartForm.getTitle()); + //标题覆盖 + chart.setTitleOverlay(false); + int numOfPoints = xData.size(); + //初始化X轴数据 + String[] categories = xData.toArray(new String[]{}); + String cat = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0)); + XDDFDataSource categoriesData = XDDFDataSourcesFactory.fromArray(categories, cat, 0); + //初始化X轴 + XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); + bottomAxis.setTitle(chartForm.getXTitle()); + //初始化Y周 + XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT); + leftAxis.setTitle(chartForm.getYTitle()); + leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); + leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN); + int barSize = 0; + if (yBarData != null) { + log.info(">> 开始生成柱状图 "); + // 创建柱状图的类型 + barSize = yBarData.size(); + XDDFBarChartData barChart = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis); + barChart.setBarDirection(BarDirection.COL); + for (int i = 0; i < yBarData.size(); i++) { + setBarProperty(yBarData, chart, numOfPoints, categoriesData, barChart, i); + } + if (yBarData.size() > 1) { + barChart.setBarGrouping(BarGrouping.STACKED); +// barChart.setOverlap((byte)-100);// 满值叠加柱子才不会错位 +// barChart.setGapWidth(500); + // 堆叠柱状图,必须设置为100 不然会柱状图会错位 + chart.getCTChart().getPlotArea().getBarChartArray(0).addNewOverlap().setVal((byte) 100); + } + chart.plot(barChart); + log.info(">> 生成柱状图 完毕 "); + } + + //********************* 折线图 ************************************************* + if (yLintData != null) { + log.info(">> 开始生成折线图 "); + XDDFLineChartData lineChart = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis); + lineChart.setVaryColors(false); + for (int i = 0; i < yLintData.size(); i++) { + int collIndex = i + 1 + barSize; + String range = chart.formatRange(new CellRangeAddress(1, numOfPoints, collIndex, collIndex)); + AxisYVal yVal = yLintData.get(i); + Number[] number = yVal.getVal(); + XDDFNumericalDataSource source = XDDFDataSourcesFactory.fromArray(number, range); + XDDFLineChartData.Series series = (XDDFLineChartData.Series) lineChart.addSeries(categoriesData, source); + series.setTitle(yVal.getTitle(), setTitleInDataSheet(chart, yVal.getTitle(), collIndex)); + series.setMarkerStyle(MarkerStyle.STAR); + series.setMarkerSize((short) 6); + series.setSmooth(Boolean.FALSE); + series.setShowLeaderLines(true); + CTDLbls dLbls = series.getCTLineSer().getDLbls(); + // 控制系列名称是否显示 + setCTDlbls(dLbls,false, isShowLineVal, false, false); + } + + chart.plot(lineChart); + log.info(">> 生成折线图 完毕"); + } + setChartFontProperty(document, content); + } + + /** + * 生成横向柱状图 + * + * @param document word文档 + * @param chartForm 图表数据 + * @throws Exception + */ + public static void createBarCharts(XWPFDocument document, BarLineChartForm chartForm) throws Exception { + if (chartForm == null) { + throw new IllegalArgumentException("数据为空"); + } + List xData = chartForm.getXData(); + if (xData == null) { + throw new IllegalArgumentException("X轴数据为空"); + } + List yBarData = chartForm.getYBarData(); + List yLintData = chartForm.getYLineData(); + if (yBarData == null && yLintData == null) { + throw new IllegalArgumentException("柱状数据、折线数据为空"); + } + XWPFChart chart = document.createChart(15 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER); + // 设置图例位置:上下左右 + XDDFChartLegend legend = chart.getOrAddLegend(); + legend.setPosition(LegendPosition.TOP); + legend.setOverlay(false); + // 设置标题 + chart.setTitleText(chartForm.getTitle()); + //标题覆盖 + chart.setTitleOverlay(false); + int numOfPoints = xData.size(); + //初始化X轴数据 + String[] categories = xData.toArray(new String[]{}); + String cat = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0)); + XDDFDataSource categoriesData = XDDFDataSourcesFactory.fromArray(categories, cat, 0); + //初始化X轴 + XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); + bottomAxis.setTitle(chartForm.getXTitle()); + //初始化Y周 + XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT); + leftAxis.setTitle(chartForm.getYTitle()); + leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); + leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN); + log.info(">> 开始生成柱状图 "); + // 创建柱状图的类型 + XDDFBarChartData barChart = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis); + barChart.setBarDirection(BarDirection.BAR); + for (int i = 0; i < yBarData.size(); i++) { + setBarProperty(yBarData, chart, numOfPoints, categoriesData, barChart, i); + break; + } + if (yBarData.size() > 1) { + barChart.setBarGrouping(BarGrouping.CLUSTERED); + chart.getCTChart().getPlotArea().getBarChartArray(0).addNewOverlap().setVal((byte) 0); + } + chart.plot(barChart); + log.info(">> 生成柱状图 完毕 "); + + + } + + /** + * 浏览器下载 + * + * @param document 文档 + * @param fileName 文件名 + * @throws IOException + */ + public static void save(XWPFDocument document, String fileName) throws IOException { + ServletOutputStream out = null; + try { + if (document == null || fileName == null) { + throw new IllegalArgumentException("参数不能为空"); + } + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes != null) { + ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes; + HttpServletResponse response = servletRequestAttributes.getResponse(); + response.setContentType("application/octet-stream"); + out = response.getOutputStream(); + String encodedFileName; + try { + encodedFileName = URLEncoder.encode(fileName, "UTF-8"); + } catch (UnsupportedEncodingException var20) { + throw new RuntimeException(var20); + } + response.setHeader("Content-Disposition", "attachment;fileName=" + encodedFileName); + document.write(out); + return; + } + log.warn("非web请求,无法操作。"); + } finally { + if (document != null) { + try { + document.close(); + } catch (Exception var19) { + } + } + if (out != null) { + try { + out.close(); + } catch (Exception var18) { + } + } + } + } + + /** + * 另存为 + * + * @param document 文档 + * @param fileName 文件名 + * @param path 文件存储目录 + * @throws IOException + */ + public static void saveAs(XWPFDocument document, String fileName, String path) throws IOException { + FileOutputStream out = null; + try { + if (document == null || fileName == null || path == null) { + throw new IllegalArgumentException("参数不能为空"); + } + File file = new File(path+fileName); + String saveAsPath = file.getCanonicalPath(); + out = new FileOutputStream(file); + log.info("开始另存为word文件[" + saveAsPath + "]", "1"); + document.write(out); + document.close(); + log.info("成功另存为excel文件[" + saveAsPath + "]", "1"); + return; + } finally { + if (document != null) { + try { + document.close(); + } catch (Exception var19) { + } + } + if (out != null) { + try { + out.close(); + } catch (Exception var18) { + } + } + } + } + + ////////// 图表的设置 + + /** + * 为图表设置标题 + * @param chart + * @param title + * @param column + * @return + * @throws Exception + */ + private static CellReference setTitleInDataSheet(XWPFChart chart, String title, int column) throws Exception { + XSSFWorkbook workbook = chart.getWorkbook(); + XSSFSheet sheet = workbook.getSheetAt(0); + XSSFRow row = sheet.getRow(0); + if (row == null) { + row = sheet.createRow(0); + } + XSSFCell cell = row.getCell(column); + if (cell == null) { + cell = row.createCell(column); + } + cell.setCellValue(title); + return new CellReference(sheet.getSheetName(), 0, column, true, true); + } + + /** + * 设置柱状图中柱状的属性 + * @param yBarData + * @param chart + * @param numOfPoints + * @param categoriesData + * @param barChart + * @param i + * @throws Exception + */ + private static void setBarProperty(List yBarData, XWPFChart chart, int numOfPoints, XDDFDataSource categoriesData, XDDFBarChartData barChart, int i) throws Exception { + int collIndex = i + 1; + String range = chart.formatRange(new CellRangeAddress(1, numOfPoints, collIndex, collIndex)); + AxisYVal yVal = yBarData.get(i); + Number[] number = yVal.getVal(); + XDDFNumericalDataSource source = XDDFDataSourcesFactory.fromArray(number, range); + XDDFBarChartData.Series series = (XDDFBarChartData.Series) barChart.addSeries(categoriesData, source); + series.setTitle(yVal.getTitle(), setTitleInDataSheet(chart, yVal.getTitle(), collIndex)); + } + + /** + * 设置图表字体属性 + * @param document + * @param content + */ + private static void setChartFontProperty(XWPFDocument document, String content) { + XWPFParagraph paragraph = document.createParagraph(); + paragraph.setAlignment(ParagraphAlignment.CENTER); + XWPFRun xwpfRun = paragraph.createRun(); + xwpfRun.setFontSize(10); + xwpfRun.setBold(true); + xwpfRun.setFontFamily("宋体"); + xwpfRun.setText(content); + xwpfRun.setColor("000000"); + } + + /** + * 设置图表的属性显示 + * @param dLbls + * @param showSerName 控制系列名称是否显示 + * @param showVal 控制值是否显示 + * @param showCatName 控制分类名称显示 + * @param showLegendKey 控制图例标识 + */ + private static void setCTDlbls(CTDLbls dLbls, boolean showSerName, boolean showVal, boolean showCatName, boolean showLegendKey) { + // 控制系列名称是否显示 + if (dLbls.isSetShowSerName()) { + dLbls.getShowSerName().setVal(showSerName); + } else { + dLbls.addNewShowSerName().setVal(showSerName); + } + // 控制值是否显示 + if (dLbls.isSetShowVal()) { + dLbls.getShowVal().setVal(showVal); + } else { + dLbls.addNewShowVal().setVal(showVal); + } + // 控制分类名称显示 + if (dLbls.isSetShowCatName()) { + dLbls.getShowCatName().setVal(showCatName); + } else { + dLbls.addNewShowCatName().setVal(showCatName); + } + // 控制图例标识 + if (dLbls.isSetShowLegendKey()) { + dLbls.getShowLegendKey().setVal(showLegendKey); + } else { + dLbls.addNewShowLegendKey().setVal(showLegendKey); + } + } + + ///////////////////////// 段落的设置 + /** + * 设置标题属性 + * @param parTitle + * @param isBreak + * @param titleParagraph + */ + private static void setParagraphTitleProperty(String parTitle, boolean isBreak, XWPFParagraph titleParagraph) { + XWPFRun titleFun = titleParagraph.createRun(); + titleFun.setFontFamily("宋体"); + titleParagraph.setAlignment(ParagraphAlignment.LEFT); + titleFun.setText(parTitle); + titleFun.setColor("000000"); + titleFun.setFontSize(14); + titleFun.setBold(true); + //换行 + if (isBreak) { + titleFun.addBreak(); + } + } + + + /////////// 表格的设置 + /** + * 创建单元格 + * @param row + * @param index + * @return + */ + private static XWPFTableCell getTableRowCell(XWPFTableRow row, int index) { + XWPFTableCell cell = row.getCell(index); + if (cell != null) { + return cell; + } + return row.createCell(); + } + + /** + * 创建表格行 + * @param table + * @param index + * @return + */ + private static XWPFTableRow getTableRow(XWPFTable table, int index) { + XWPFTableRow row = table.getRow(index); + if (row != null) { + return row; + } + return table.createRow(); + } +} \ No newline at end of file diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/AssignmentInfoVo.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/AssignmentInfoVo.java new file mode 100644 index 0000000..2211151 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/AssignmentInfoVo.java @@ -0,0 +1,14 @@ +package digital.laboratory.platform.inspection.vo; + +import digital.laboratory.platform.inspection.entity.AssignmentInfo; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import lombok.Data; + +import java.util.List; + +@Data +public class AssignmentInfoVo extends AssignmentInfo { + private List sampleInfoList; + private Integer sampleCount; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/ESTBusinessInfoVO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/ESTBusinessInfoVO.java new file mode 100644 index 0000000..5218ed4 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/ESTBusinessInfoVO.java @@ -0,0 +1,23 @@ +package digital.laboratory.platform.inspection.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 接收通过业务id查询委托表、筛查表、任务表中得到的信息 + */ +@Data +@ApiModel(value = "ESTBusinessInfoVO", description = "接收通过业务id查询委托表、筛查表、任务表中得到的信息") +public class ESTBusinessInfoVO { + + @ApiModelProperty("业务id") + private String id; + + @ApiModelProperty("检材类别(缴获物和生物样本), invivo 生物样本 | inVitro 缴获物") + private String materialType; + + @ApiModelProperty("业务类型") + private String businessType; + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/ProcedureVo.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/ProcedureVo.java new file mode 100644 index 0000000..5ad83cc --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/ProcedureVo.java @@ -0,0 +1,34 @@ +package digital.laboratory.platform.inspection.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class ProcedureVo { + @ApiModelProperty(value = "实验方法") + private boolean testRecordMethod; + + @ApiModelProperty(value = "实验试剂耗材") + private boolean testRecordReagentConsumables; + + @ApiModelProperty(value = "实验标准物质") + private boolean testRecordStandardSubstance; + + @ApiModelProperty(value = "实验仪器设备") + private boolean testRecordInstrument; + + @ApiModelProperty(value = "实验检材") + private boolean sampleInfo; + + @ApiModelProperty(value = "实验前处理") + private boolean pretreatment; + @ApiModelProperty(value = "实验仪器条件") + private boolean setInstrumentConditions; + + @ApiModelProperty(value = "上机") + private boolean embarkation; + @ApiModelProperty(value = "结果分析") + private boolean resultAnalysis; + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/ResultConcentrationVO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/ResultConcentrationVO.java new file mode 100644 index 0000000..c6ebdbd --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/ResultConcentrationVO.java @@ -0,0 +1,22 @@ +package digital.laboratory.platform.inspection.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel(value = "TestRecordSolutionVO", description = "上机步骤中回显检材物列表的VO") +public class ResultConcentrationVO { + + @ApiModelProperty("样本溶液id或者标准溶液id") + private String id; + + @ApiModelProperty("溶液编号") + private String number; + + @ApiModelProperty("检验ID") + private String testId; + + @ApiModelProperty("溶液的结果浓度") + private String resultConcentration; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/SampleInfoVo.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/SampleInfoVo.java new file mode 100644 index 0000000..3c6d3b6 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/SampleInfoVo.java @@ -0,0 +1,9 @@ +package digital.laboratory.platform.inspection.vo; + +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import lombok.Data; + +@Data +public class SampleInfoVo extends SampleInfo { + public String businessTypeName; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestRecordInstrumentConditionVo.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestRecordInstrumentConditionVo.java new file mode 100644 index 0000000..4145ce4 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestRecordInstrumentConditionVo.java @@ -0,0 +1,9 @@ +package digital.laboratory.platform.inspection.vo; + +import digital.laboratory.platform.inspection.entity.TestRecordInstrumentCondition; + +public class TestRecordInstrumentConditionVo extends TestRecordInstrumentCondition { + + private String testSerialNumber; + private String testUserName; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestRecordSolutionVO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestRecordSolutionVO.java new file mode 100644 index 0000000..2635b2d --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestRecordSolutionVO.java @@ -0,0 +1,33 @@ +package digital.laboratory.platform.inspection.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import io.swagger.models.auth.In; +import lombok.Data; +import springfox.documentation.service.ApiListing; + +@Data +@ApiModel(value = "TestRecordSolutionVO", description = "上机步骤中回显检材物列表的VO") +public class TestRecordSolutionVO { + + @ApiModelProperty("样本溶液id或者标准溶液id") + private String id; + + @ApiModelProperty("溶液编号") + private String number; + + @ApiModelProperty("溶液类型名称") + private String typeName; + + @ApiModelProperty("进样次数") + private Integer injectorCount = 1; + + @ApiModelProperty("架号") + private String frameNumber; + + @ApiModelProperty("检验ID") + private String testId; + + @ApiModelProperty("进样盘号位置") + private String injectorLocation; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestRecordStandardSolutionVo.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestRecordStandardSolutionVo.java new file mode 100644 index 0000000..3592b9e --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestRecordStandardSolutionVo.java @@ -0,0 +1,10 @@ +package digital.laboratory.platform.inspection.vo; + +import digital.laboratory.platform.inspection.entity.TestRecordStandardSolution; +import lombok.Data; + +@Data +public class TestRecordStandardSolutionVo extends TestRecordStandardSolution { + + private Integer orderNum; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestResultBusinessVO.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestResultBusinessVO.java new file mode 100644 index 0000000..ff33c4c --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestResultBusinessVO.java @@ -0,0 +1,65 @@ +package digital.laboratory.platform.inspection.vo; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.annotation.JSONField; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import digital.laboratory.platform.inspection.dto.ReportConfigDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 实验结果查询中分页查询, 接收委托表、筛查表、任务表中得到的信息VO + */ +@Data +@TableName(autoResultMap = true) +@ApiModel(value = "TestResultBusinessVO", description = "实验结果查询中分页查询, 接收委托表、筛查表、任务表中得到的信息VO") +public class TestResultBusinessVO { + + @ApiModelProperty("业务id") + private String id; + + @ApiModelProperty("检材类别(缴获物和生物样本), invivo 生物样本 | inVitro 缴获物, 只存在在委托表里, 其他表为空(筛查表,任务表)") + private String materialType; + + @ApiModelProperty("业务类型") + private String businessType; + + @ApiModelProperty("业务类型名称") + private String businessTypeName; + + @ApiModelProperty("案件名称或者任务名称") + private String caseName; + + @ApiModelProperty("类型,1 委托、2 筛查、 3 任务") + private Integer type; + + @ApiModelProperty("录入时间") + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @ApiModelProperty("录入人") + private String createBy; + + @ApiModelProperty("化合物字段") + private String compounds;//[{"compound1":"aaaa","english":"ab-fui"}] + + @ApiModelProperty("生成报告配置") + @TableField(value = "report_config", typeHandler = FastjsonTypeHandler.class) + private JSONArray reportConfig;// + + @ApiModelProperty("化合物字段转json数组") + private JSONArray compoundsJsonArray; + + @ApiModelProperty("业务状态, 0:未分配\n" + + "1:已分配\n" + + "2:实验中\n" + + "3:检验完成\n" + + "4:鉴定完毕") + private Integer status = 3; +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestTemplateVo.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestTemplateVo.java new file mode 100644 index 0000000..59a2d68 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/vo/TestTemplateVo.java @@ -0,0 +1,17 @@ +package digital.laboratory.platform.inspection.vo; + +import digital.laboratory.platform.inspection.entity.TestTemplate; +import lombok.Data; + +import java.util.List; + +@Data +public class TestTemplateVo extends TestTemplate { + + private String authorName; + private List testMethodName; + + private String instrumentConditionUrl; + + private String instrumentConditionFileName; +} diff --git a/dlp-drugtesting-biz/src/main/resources/banner.txt b/dlp-drugtesting-biz/src/main/resources/banner.txt new file mode 100644 index 0000000..5627c50 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +${AnsiColor.BRIGHT_GREEN} + _ _ _ _ _ _ + __| | |_ __ __| |_ __ _ _ __ _| |_ ___ ___| |_(_)_ __ __ _ + / _` | | '_ \ _____ / _` | '__| | | |/ _` | __/ _ \/ __| __| | '_ \ / _` | +| (_| | | |_) |_____| (_| | | | |_| | (_| | || __/\__ \ |_| | | | | (_| | + \__,_|_| .__/ \__,_|_| \__,_|\__, |\__\___||___/\__|_|_| |_|\__, | + |_| |___/ |___/ +检验鉴定系统(Dlp-drugTesting) + +版本: ${version} +创建: ${timestamp} + +${AnsiColor.DEFAULT} diff --git a/dlp-drugtesting-biz/src/main/resources/bootstrap.yml b/dlp-drugtesting-biz/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..aa71aa9 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/resources/bootstrap.yml @@ -0,0 +1,56 @@ +logging: + level: + digital.laboratory.platform.camera.mapper: debug +server: + port: 5240 +mybatis: + mapper-locations: classpath*:mapper/*.xml + +spring: + application: + name: @artifactId@ + cloud: + nacos: + discovery: + server-addr: ${NACOS_HOST:dlp-nacos}:${NACOS_PORT:8848} + config: + server-addr: ${spring.cloud.nacos.discovery.server-addr} + file-extension: yml + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} + profiles: + active: @profiles.active@ + datasource: + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + username: dlp + password: 7990016 + url: jdbc:mysql://dlp-mysql:3306/dlp_inspection_system?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true +# hikari: +# # 指定 Hikari 连接池的最大连接数为 30。这个配置项表示连接池中允许的最大连接数,超过这个数量的连接请求将被阻塞 +# maximum-pool-size: 30 +# data-source-properties: +# # 开启 MySQL JDBC 驱动的批处理功能。设置为 true 可以让 MySQL 驱动在批量操作时使用 rewriteBatchedStatements 特性,提高批量插入的效率。 +# rewriteBatchedStatements: true +# # 启用服务器端预处理语句。设置为 true 时,将使用 MySQL 服务器端的预处理语句功能,可提高性能。 +# useServerPrepStmts: true +# # 启用预处理语句缓存。设置为 true 时,将启用预处理语句缓存功能,可以提高 SQL 语句的执行效率。 +# cachePrepStmts: true +# # 使用本地会话状态。设置为 true 时,将使用本地会话状态来执行 SQL 语句,可能会提高性能。 +# useLocalSessionState: true + servlet: + multipart: + # 默认最大上传文件大小为1M, 单个文件大小 + max-file-size: 20MB + # 默认最大请求大小为10M, 总上传的数据大小 + max-request-size: 50MB + location: /tmp/upload +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + +oss: + endpoint: http://dlp-minio:9000 + accessKey: dlp + secretKey: 87990016 + bucket-name: dlpfiles diff --git a/dlp-drugtesting-biz/src/main/resources/mapper/SampleInfoMapper.xml b/dlp-drugtesting-biz/src/main/resources/mapper/SampleInfoMapper.xml new file mode 100644 index 0000000..06374ea --- /dev/null +++ b/dlp-drugtesting-biz/src/main/resources/mapper/SampleInfoMapper.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dlp-drugtesting-biz/src/main/resources/mapper/SampleInjectorMapper.xml b/dlp-drugtesting-biz/src/main/resources/mapper/SampleInjectorMapper.xml new file mode 100644 index 0000000..a22cd8b --- /dev/null +++ b/dlp-drugtesting-biz/src/main/resources/mapper/SampleInjectorMapper.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + SELECT T.id, + T.number, + T.test_id, + T.result_concentration + FROM (SELECT id, sample_no AS number, test_id, result_concentration + FROM b_test_record_sample_solution + UNION ALL + SELECT id, number, test_id, result_concentration + FROM b_test_record_standard_solution) T + + + + + + diff --git a/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordInstrumentConditionMapper.xml b/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordInstrumentConditionMapper.xml new file mode 100644 index 0000000..c3b1e4a --- /dev/null +++ b/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordInstrumentConditionMapper.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + select ic.*, (select t.test_serial_number from b_test_record t where t.id = ic.test_id) as test_serial_number + from b_test_record_use_condition ic + order by create_time desc + + + + + + + + diff --git a/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordMapper.xml b/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordMapper.xml new file mode 100644 index 0000000..b552352 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordMapper.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select t.*, + (select u.name from dlp_base.sys_user u where u.user_id = t.test_user_id) as test_user_name + from b_test_record t + + + + + + diff --git a/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordSampleDataMapper.xml b/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordSampleDataMapper.xml new file mode 100644 index 0000000..6d923b6 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordSampleDataMapper.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + SELECT T.id, + T.material_type, + T.business_type, + T.case_name, + T.type, + T.compounds, + T.report_config, + T.create_time, + T.create_by, + T.status, + T.task_start_date + FROM (SELECT id, material_type, case_name, business_type, "" AS compounds, "" AS report_config, 10000 AS type, create_time, create_by, status, "" AS task_start_date + FROM b_entrustinfo + UNION ALL + SELECT id, "" AS material_type, case_name, business_type, "" AS compounds, "" AS report_config,30000 AS type, create_time, create_by, 3 AS status, "" AS task_start_date + FROM b_case_screen + UNION ALL + SELECT id, "" AS material_type, task_name AS case_name, business_type, compounds, report_config, 20000 AS type, create_time, create_by, 3 AS status, task_start_date + FROM b_taskinfo) T + + + + + + + + + + + + + + SELECT + rs.id AS sample_data_id, -- 检验数据id + rs.data_result_json, -- 数据json + rs.compound_name, -- 化合物名称 + rs.is_detected, -- 是否检出 + rs.test_id, -- 实验id + rs.name, -- name + ss.sample_no, -- 溶液编号 + si.id AS material_id, -- 检材id + si.sample_name, -- 检材名称 + si.business_id, -- 业务id,可能是委托、任务、筛查 + si.order_no -- 委托中检材的序号 + FROM + `b_test_record_sampledata` rs + LEFT JOIN `b_test_record_sample_solution` ss ON rs.sample_no = ss.sample_no + LEFT JOIN `b_sampleinfo` si ON si.id = ss.material_id OR rs.sample_no = si.accept_no -- 如果溶液关联id 不存在则通过检材受理编号关联 + + + + + + + SELECT + rs.id AS sample_data_id, -- 检验数据id + rs.data_result_json, -- 数据json + rs.compound_name, -- 化合物名称 + rs.is_detected, -- 是否检出 + rs.test_id, -- 实验id + si.accept_no AS sample_no, -- 检材受理编号 + si.id AS material_id, -- 检材id + si.sample_name, -- 检材名称 + rs.sample_concentration, -- 对应的检材化合物浓度 + si.business_id -- 业务id,可能是委托、任务、筛查 + FROM + `b_sampleinfo` si + LEFT JOIN `b_test_record_sampledata` rs ON rs.sample_no = si.accept_no + + + + + + + SELECT + rs.id AS sample_data_id,-- 检验数据id + rs.data_result_json,-- 数据json + rs.compound_name,-- 化合物名称 + rs.is_detected,-- 是否检出 + rs.test_id,-- 实验id + rs.status, -- 任务数据的审核状态 + rs.sample_concentration, -- 对应的检材化合物浓度 + ss.sample_no,-- 溶液编号 + si.id AS material_id,-- 检材id + si.accept_no, -- 检材编号 + si.sample_name,-- 检材名称 + si.business_id, -- 业务id,可能是委托、任务、筛查 + ti.task_name, + ti.business_type, + ti.create_time + FROM + `b_test_record_sampledata` rs + LEFT JOIN `b_test_record_sample_solution` ss ON rs.sample_no = ss.sample_no + LEFT JOIN `b_sampleinfo` si ON si.id = ss.material_id + JOIN b_taskinfo ti ON si.business_id = ti.Id + + + + + diff --git a/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordStandardSolutionMapper.xml b/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordStandardSolutionMapper.xml new file mode 100644 index 0000000..191ceea --- /dev/null +++ b/dlp-drugtesting-biz/src/main/resources/mapper/TestRecordStandardSolutionMapper.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SELECT ts.*, RIGHT (ts.number, 1) as order_num + FROM b_test_record_standard_solution ts + where test_id = #{testId} + order by ts.number asc + + + + + + + + diff --git a/dlp-drugtesting-biz/src/main/resources/mapper/TestTemplateMapper.xml b/dlp-drugtesting-biz/src/main/resources/mapper/TestTemplateMapper.xml new file mode 100644 index 0000000..5bf7278 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/resources/mapper/TestTemplateMapper.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select t.*, + (select u.name from dlp_base.sys_user u where u.user_id = t.author) as author_name + from b_test_template t + + + + + + diff --git a/dlp-drugtesting-biz/src/main/resources/template/templateStyles.docx b/dlp-drugtesting-biz/src/main/resources/template/templateStyles.docx new file mode 100644 index 0000000..38648aa --- /dev/null +++ b/dlp-drugtesting-biz/src/main/resources/template/templateStyles.docx @@ -0,0 +1,5 @@ +标题 1 +标题 2 +标题 3 +标题 4 +标题 5 diff --git a/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/JFreeChartTest.java b/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/JFreeChartTest.java new file mode 100644 index 0000000..8cd5ddc --- /dev/null +++ b/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/JFreeChartTest.java @@ -0,0 +1,424 @@ +//package digital.laboratory.platform.inspection.test; +// +//import com.google.common.collect.Lists; +//import digital.laboratory.platform.inspection.utils.jfreechart.GenerateChartUtil; +//import digital.laboratory.platform.inspection.utils.jfreechart.GeneratePieChartUtil; +//import digital.laboratory.platform.inspection.utils.jfreechart.JFreeChartUtil; +//import org.jfree.chart.ChartFactory; +//import org.jfree.chart.ChartPanel; +//import org.jfree.chart.ChartUtils; +//import org.jfree.chart.JFreeChart; +//import org.jfree.chart.axis.*; +//import org.jfree.chart.labels.ItemLabelAnchor; +//import org.jfree.chart.labels.ItemLabelPosition; +//import org.jfree.chart.labels.StandardCategoryItemLabelGenerator; +//import org.jfree.chart.labels.StandardCategoryToolTipGenerator; +//import org.jfree.chart.plot.CategoryPlot; +//import org.jfree.chart.plot.DatasetRenderingOrder; +//import org.jfree.chart.plot.PlotOrientation; +//import org.jfree.chart.renderer.category.LineAndShapeRenderer; +//import org.jfree.chart.renderer.category.StackedBarRenderer; +//import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +//import org.jfree.chart.ui.TextAnchor; +//import org.jfree.data.category.CategoryDataset; +//import org.jfree.data.category.DefaultCategoryDataset; +//import org.jfree.data.xy.XYSeries; +//import org.jfree.data.xy.XYSeriesCollection; +//import org.junit.jupiter.api.Test; +//import org.springframework.test.context.TestPropertySource; +// +//import javax.swing.*; +//import java.awt.*; +//import java.awt.geom.Ellipse2D; +//import java.awt.geom.Line2D; +//import java.awt.geom.Rectangle2D; +//import java.awt.image.BufferedImage; +//import java.io.File; +//import java.io.IOException; +//import java.text.NumberFormat; +//import java.time.LocalDate; +//import java.time.format.DateTimeFormatter; +//import java.util.*; +//import java.util.List; +// +//public class JFreeChartTest { +// +// // 图片存放地址 +// String filePath = "F:\\ProjectFile\\WorkFile\\LianChuang\\project\\DLP\\dlp-drugtesting\\dlp-drugtesting-biz\\src\\test\\resources\\image" + "\\" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); +// +// @Test +// void testPie() throws Exception { +// // 图例名称 +// List list = Lists.newArrayList("海洛因", "冰毒", "氯胺酮"); +// // 数据比例列表 +// List dataList = Lists.newArrayList(86, 12, 2); +// // 图表背景 +// List colorList = Lists.newArrayList(new Color(11, 144, 232), new Color(232, 188, 11), new Color(161, 84, 234)); +// // 偏离百分比数据 +// List explodePercentList = Lists.newArrayList(0.01, 0.01, 0.01); +// JFreeChart chart = GeneratePieChartUtil.createPieChart("", list, dataList, JFreeChartUtil.createChartTheme("宋体"), +// colorList, explodePercentList); +// +// File file = new File(filePath); +// if (!file.exists()) { +// file.mkdirs(); +// } +// String fileName = System.currentTimeMillis() + "测试图片" + ".jpeg"; +// File file1 = new File(file.getPath() + "/" + fileName); +// +// try { +// if(file1.exists()) { +// file1.delete(); +// } +// ChartUtils.saveChartAsJPEG(file1, chart, 800, 600); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// +// /** +// * 层叠柱状图 +// */ +// @Test +// public void stackedBarChart() throws Exception { +// //x轴名称列表 +// List xAxisNameList = new ArrayList<>(Arrays.asList("西安市", "咸阳市", "宝鸡市", "渭南市", "铜川市", "榆林市", "延安市", "汉中市", "商洛市", "安康市", "杨凌区")); +// //图例名称列表 +// List legendNameList = new ArrayList<>(Arrays.asList("海洛因", "冰毒", "氯胺酮")); +// //数据列表 +// List> dataList = new ArrayList<>(); +// dataList.add(new ArrayList<>(Arrays.asList(17.0, 60.9, 31.2, 19.5, 15.6, 13.6, 19.0, 32.4, 26.8, 21.8, 54.7))); +// dataList.add(new ArrayList<>(Arrays.asList(3.8, 3.1, 0.7, 1.0, 0.7, 0.3, 0.4, 5.6, 0.5, 0.5, 1.0))); +// dataList.add(new ArrayList<>(Arrays.asList(0.6, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0., 0.0))); +// +// // 图表背景 +// List colorList = Lists.newArrayList(new Color(72, 161, 250), new Color(255, 192, 0), new Color(152, 102, 202)); +// +// // 返回outputStream +// //GenerateChartUtil.createStackedBarChart(response.getOutputStream(), "各级变化图", legendNameList, xAxisNameList +// // , dataList, JFreeChartUtil.createChartTheme("宋体"), "y轴", "x轴", 600, 400); +// +// // 返回JFreeChart +// JFreeChart chart = GenerateChartUtil.createStackedBarChart("", legendNameList, xAxisNameList +// , dataList, colorList, JFreeChartUtil.createChartTheme("宋体"), "千人均消费量(毫克/千人/天)", "城市名"); +// //在D盘目录下生成图片 +// File p = new File(filePath); +// if (!p.exists()) { +// p.mkdirs(); +// } +// String imageName = System.currentTimeMillis() + "_层叠柱状图" + ".jpeg"; +// File file = new File(p.getPath() + "/" + imageName); +// try { +// if(file.exists()) { +// file.delete(); +// } +// ChartUtils.saveChartAsJPEG(file, chart, 1200, 1000); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// +// /** +// * 生成折线图 +// */ +// @Test +// public void lineChart() throws Exception { +// +// //x轴名称列表 +// List xAxisNameList = new ArrayList<>(Arrays.asList("2022-03", "2022-06", "2022-09", "2022-12", "2023-02")); +// //图例名称列表 +// List legendNameList = new ArrayList<>(Arrays.asList("综合")); +// //数据列表 +// List> dataList = new ArrayList<>(); +// dataList.add(new ArrayList<>(Arrays.asList(27.5, 22.7, 13.2, 47.6, 20.5))); +// //x轴名称列表 +// /*List xAxisNameList = new ArrayList<>(Arrays.asList("一级", "二级", "三级", "四级", "五级")); +// //图例名称列表 +// List legendNameList = new ArrayList<>(Arrays.asList("李四", "张三","王五")); +// //数据列表 +// List> dataList = new ArrayList<>(); +// dataList.add(new ArrayList<>(Arrays.asList(1, 3, 5, 6, 2))); +// dataList.add(new ArrayList<>(Arrays.asList(2, 1, 3, 4, 5))); +// dataList.add(new ArrayList<>(Arrays.asList(5, 8, 4, 6, 4)));*/ +// +// // 返回outputStream +// //GenerateChartUtil.createLineChart(response.getOutputStream(), "各级变化图", legendNameList, xAxisNameList +// // , dataList, JFreeChartUtil.createChartTheme("宋体"), "y轴", "x轴", 600, 400); +// +// JFreeChart chart = GenerateChartUtil.createLineChart("各级变化图", legendNameList, xAxisNameList +// , dataList, JFreeChartUtil.createChartTheme("宋体"), "y轴", "x轴"); +// //在D盘目录下生成图片 +// File p = new File(filePath); +// if (!p.exists()) { +// p.mkdirs(); +// } +// String imageName = System.currentTimeMillis() + "_折线图" + ".jpeg"; +// File file = new File(p.getPath() + "/" + imageName); +// try { +// if(file.exists()) { +// file.delete(); +// } +// ChartUtils.saveChartAsJPEG(file, chart, 800, 600); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// +// /** +// * 生成综合图表 -- 折线层叠图 +// */ +// @Test +// void combinedChartExample() throws Exception { +// +// //x轴名称列表 +// List xAxisNameList = new ArrayList<>(Arrays.asList("2022-03", "2022-06", "2022-09", "2022-12", "2023-02")); +// //图例名称列表 +// List legendNameList = new ArrayList<>(Arrays.asList("海洛因", "冰毒", "氯胺酮")); +// // 图表背景 +// List colorList = Lists.newArrayList(new Color(72, 161, 250), new Color(221, 61, 61), new Color(146, 210, 80)); // , new Color(152,102,202)); +// +// //数据列表 +// List> dataList = new ArrayList<>(); +// dataList.add(new ArrayList<>(Arrays.asList(24.5, 19.5, 12.1, 46.5, 18))); +// dataList.add(new ArrayList<>(Arrays.asList(3, 3.3, 1.1, 1.1, 2.5))); +// dataList.add(new ArrayList<>(Arrays.asList(0.0, 0.0, 0.0, 0.0, 0.3))); +// +// JFreeChart stackedBarChart = GenerateChartUtil.createStackedBarChart("", legendNameList, xAxisNameList +// , dataList, colorList, JFreeChartUtil.createChartTheme("宋体"), "千人均消费量(毫克/千人/天)", ""); +// +// // 折线图 +// //图例名称列表 +// List legendNameList2 = new ArrayList<>(Arrays.asList("综合")); +// //数据列表 +// List dataList2 = new ArrayList<>(Arrays.asList(27.5, 22.7, 13.2, 47.6, 20.5)); +// +// +// CategoryDataset dataset2 = createDataset2(xAxisNameList, legendNameList2, dataList2); +// +// // 获取图表绘图区域对象 +// CategoryPlot plot = stackedBarChart.getCategoryPlot(); +//// plot.setBackgroundPaint(new Color(0xEE, 0xEE, 0xFF)); +//// plot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_RIGHT); +// +// +// // 将折线图添加到层叠柱状图上 +// plot.setDataset(1, dataset2); +// plot.mapDatasetToRangeAxis(1, 1); +// +// final CategoryAxis domainAxis = plot.getDomainAxis(); +// domainAxis.setCategoryLabelPositions(CategoryLabelPositions.STANDARD); +// final ValueAxis axis2 = new NumberAxis("综合千人均消费量(毫克/千人/天)"); +// axis2.setLabelFont(new Font("新宋体", Font.BOLD, 20)); +// plot.setRangeAxis(1, axis2); +// +// final LineAndShapeRenderer renderer2 = getLineAndShapeRenderer(); +// plot.setRenderer(1, renderer2); +// plot.setDatasetRenderingOrder(DatasetRenderingOrder.REVERSE); +// +// //在D盘目录下生成图片 +// File p = new File(filePath); +// if (!p.exists()) { +// p.mkdirs(); +// } +// String imageName = System.currentTimeMillis() + "_组合图" + ".jpeg"; +// File file = new File(p.getPath() + "/" + imageName); +// try { +// if(file.exists()) { +// file.delete(); +// } +// ChartUtils.saveChartAsJPEG(file, stackedBarChart, 1200, 1000); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// +// private static LineAndShapeRenderer getLineAndShapeRenderer() { +// final LineAndShapeRenderer renderer2 = new LineAndShapeRenderer(); //setToolTipGenerator +// renderer2.setDefaultToolTipGenerator(new StandardCategoryToolTipGenerator()); +// /// 数据标签的设置 +// renderer2.setDefaultItemLabelsVisible(true); +// renderer2.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator(StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING, +// NumberFormat.getInstance())); +// renderer2.setDefaultItemLabelFont(new Font("SansSerif", Font.PLAIN, 20)); // 数据标签的字体大小 +// // 位置 +// renderer2.setDefaultPositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE1, TextAnchor.BOTTOM_CENTER)); +// renderer2.setSeriesStroke(0, new BasicStroke(5.0f)); // 设置第一条折线的宽度为2.0 +// // 设置第一条折线的折线点大小 +// renderer2.setSeriesShapesVisible(0, true); // 设置显示折现点 +// renderer2.setSeriesShape(0, new Ellipse2D.Double(-15.0, -15.0, 15.0, 15.0)); // 设置折线点的大小 +// // 设置折线的颜色 +// renderer2.setSeriesPaint(0, new Color(152,102,202)); +// renderer2.setLegendShape(0, new Rectangle2D.Double(0, 0, 60.0, 20.0)); // 设置图例项的大小 +// return renderer2; +// } +// +// @Test +// void combinedChartExample2() throws Exception { +// // 获取柱状图数据 +// List xAxisNameList = Arrays.asList("2022-03", "2022-06", "2022-09", "2022-12", "2023-02"); +// List legendNameList = Arrays.asList("海洛因", "冰毒", "氯胺酮", "综合"); +// List colorList = Arrays.asList(new Color(146, 210, 80), new Color(221, 61, 61), new Color(72, 161, 250), new Color(152, 102, 202)); +// List> dataList = new ArrayList<>(); +// dataList.add(Arrays.asList(24.5, 19.5, 12.1, 46.5, 18.0)); +// dataList.add(Arrays.asList(0.0, 0.0, 0.0, 0.0, 0.0)); +// dataList.add(Arrays.asList(3.0, 3.3, 1.1, 1.1, 2.5)); +// +// JFreeChart stackedBarChart = GenerateChartUtil.createStackedBarChart("", legendNameList, xAxisNameList, dataList, colorList, JFreeChartUtil.createChartTheme("宋体"), "千人均消费量(毫克/千人/天)", ""); +// +// // 折线图数据 +// List> dataList2 = new ArrayList<>(); +// dataList2.add(Arrays.asList(27.5, 22.7, 13.2, 47.6, 20.5)); +// +// JFreeChart lineChart = GenerateChartUtil.createLineChart("", legendNameList, xAxisNameList, dataList2, JFreeChartUtil.createChartTheme("宋体"), "千人均消费量(毫克/千人/天)", ""); +// +// // 创建组合图表 +// /*CategoryPlot plot = stackedBarChart.getCategoryPlot(); +// plot.setDataset(1, lineChart.getCategoryPlot().getDataset()); +// plot.mapDatasetToRangeAxis(1, 1); +// +// LineAndShapeRenderer lineRenderer = new LineAndShapeRenderer(); +// plot.setRenderer(1, lineRenderer);*/ +// +// // 在指定目录下生成图片 +// File p = new File(filePath); +// if (!p.exists()) { +// p.mkdirs(); +// } +// String imageName = System.currentTimeMillis() + "_组合图" + ".jpeg"; +// File file = new File(p.getPath() + "/" + imageName); +// try { +// if (file.exists()) { +// file.delete(); +// } +// ChartUtils.saveChartAsJPEG(file, stackedBarChart, 1200, 1000); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// +// +// private CategoryDataset createDataset2(List xAxisNameList, List legendNameList, List dataList) { +// +// // row keys... +// final String series1 = "Fourth"; +// +// // column keys... +// final String category1 = "Category 1"; +// final String category2 = "Category 2"; +// final String category3 = "Category 3"; +// final String category4 = "Category 4"; +// final String category5 = "Category 5"; +// final String category6 = "Category 6"; +// final String category7 = "Category 7"; +// final String category8 = "Category 8"; +// +// // create the dataset... +// final DefaultCategoryDataset dataset = new DefaultCategoryDataset(); +// for (int i = 0; i < dataList.size(); i++) { +// dataset.addValue(dataList.get(i), legendNameList.get(0), xAxisNameList.get(i)); +// } +//// dataset.addValue(15.0, series1, category1); +//// dataset.addValue(24.0, series1, category2); +//// dataset.addValue(31.0, series1, category3); +//// dataset.addValue(25.0, series1, category4); +//// dataset.addValue(56.0, series1, category5); +//// dataset.addValue(37.0, series1, category6); +//// dataset.addValue(77.0, series1, category7); +//// dataset.addValue(18.0, series1, category8); +// +// return dataset; +// +// } +// @Test +// void testFHTOJT() { +// // 创建层叠柱状图数据集 +// DefaultCategoryDataset barDataset = new DefaultCategoryDataset(); +// barDataset.addValue(24.5, "海洛因", "2022-03"); +// barDataset.addValue(19.5, "海洛因", "2022-06"); +// barDataset.addValue(12.1, "海洛因", "2022-09"); +// barDataset.addValue(46.5, "海洛因", "2022-12"); +// barDataset.addValue(18.0, "海洛因", "2023-02"); +// +// barDataset.addValue(0.0, "冰毒", "2022-03"); +// barDataset.addValue(0.0, "冰毒", "2022-06"); +// barDataset.addValue(0.0, "冰毒", "2022-09"); +// barDataset.addValue(0.0, "冰毒", "2022-12"); +// barDataset.addValue(0.3, "冰毒", "2023-02"); +// +// barDataset.addValue(3.0, "氯胺酮", "2022-03"); +// barDataset.addValue(3.3, "氯胺酮", "2022-06"); +// barDataset.addValue(1.1, "氯胺酮", "2022-09"); +// barDataset.addValue(1.1, "氯胺酮", "2022-12"); +// barDataset.addValue(2.5, "氯胺酮", "2023-02"); +// +// // 创建折线图数据集 +// DefaultCategoryDataset lineDataset = new DefaultCategoryDataset(); +// lineDataset.addValue(27.5, "综合", "2022-03"); +// lineDataset.addValue(22.7, "综合", "2022-06"); +// lineDataset.addValue(13.2, "综合", "2022-09"); +// lineDataset.addValue(47.6, "综合", "2022-12"); +// lineDataset.addValue(20.5, "综合", "2023-02"); +// +// // 创建层叠柱状图 +// JFreeChart barChart = ChartFactory.createStackedBarChart( +// "千人均消费量(毫克/千人/天)", +// "时间", +// "消费量", +// barDataset, +// PlotOrientation.VERTICAL, +// true, +// true, +// false +// ); +// +// // 创建折线图 +// JFreeChart lineChart = ChartFactory.createLineChart( +// "", +// "时间", +// "消费量", +// lineDataset, +// PlotOrientation.VERTICAL, +// true, +// true, +// false +// ); +// +// // 将折线图数据集和渲染器添加到层叠柱状图中 +// CategoryPlot plot = barChart.getCategoryPlot(); +// plot.setDataset(1, lineChart.getCategoryPlot().getDataset()); +// plot.mapDatasetToRangeAxis(1, 1); +// +// LineAndShapeRenderer lineRenderer = new LineAndShapeRenderer(); +// plot.setRenderer(1, lineRenderer); +// +// // 保存图表为 JPEG 文件 +// File file = new File(filePath + "\\"+ "CombinedChart.jpeg"); +// try { +// ChartUtils.saveChartAsJPEG(file, barChart, 1200, 1000); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// +// @Test +// void randomGetColor() { +// Random random = new Random(); +// +// Set colors = new HashSet<>(); +// int count = 10; // 生成 10 种不同的颜色 +// +// while (colors.size() < count) { +// int red = random.nextInt(256); +// int green = random.nextInt(256); +// int blue = random.nextInt(256); +// +// Color color = new Color(red, green, blue); +// colors.add(color); +// } +// +// for (Color color : colors) { +// System.out.println("RGB: " + color.getRed() + ", " + color.getGreen() + ", " + color.getBlue()); +// } +// } +// +//} diff --git a/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/LcTest.java b/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/LcTest.java new file mode 100644 index 0000000..997eccf --- /dev/null +++ b/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/LcTest.java @@ -0,0 +1,58 @@ +package digital.laboratory.platform.inspection.test; +/** + @title LcTest + @description + @author xy + @version 1.0 + @create 2023/12/14 17:10 + */ + +import digital.laboratory.platform.inspection.test.entity.UserInfo; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +public class LcTest { + @Test + void test1(){ + boolean t1=false; + String t2=""; + t2=t1 ? "123":"234"; + System.out.println(t2); + } + @Test + void test2(){ + List testList1=new ArrayList<>(); + testList1.add("11"); + testList1.add("12"); + testList1.add("13"); + String tmp=getListFisrt(testList1); + System.out.println("输出的数据"+tmp); + } + @Test + void test3(){ + for (MyEnumTest value : MyEnumTest.values()) { + System.out.println(value.getTypeName()+" 是 "+value.getTypeDes()); + } + } + @Test + void test4(){ + UserInfo userInfo=new UserInfo(); + userInfo.setUserName("张三"); + userInfo.setId("1111"); + UserInfo userInfo1=setOtherProperty(userInfo); + System.out.println("用户的属性如下:"+userInfo1.getUserName()+"//"+userInfo1.getId()+"//"+userInfo1.getSex()+"//"+userInfo1.getAge()); + } + private UserInfo setOtherProperty(UserInfo userInfo){ + userInfo.setSex("男人"); + userInfo.setAge(39); + return userInfo; + } + private T getListFisrt(List data) { + if (data == null || data.size() == 0) { + return null; + } + return data.get(0); + } +} diff --git a/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/MyEnumTest.java b/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/MyEnumTest.java new file mode 100644 index 0000000..41712c2 --- /dev/null +++ b/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/MyEnumTest.java @@ -0,0 +1,30 @@ +package digital.laboratory.platform.inspection.test; + +import lombok.Data; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * @author xy + * @version 1.0 + * @title MyEnumTest + * @description + * @create 2024/1/8 16:44 + */ +public enum MyEnumTest{ + SMALL("小杯","小孩子喝"), MEDIUM("中杯","中孩子喝"), LARGE("大杯","大孩子喝"); + private final String typeName; + private final String typeDes; + MyEnumTest(String _typeName,String _typeDes){ + this.typeName=_typeName; + this.typeDes=_typeDes; + } + + public String getTypeDes() { + return typeDes; + } + + public String getTypeName() { + return typeName; + } +} diff --git a/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/entity/UserInfo.java b/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/entity/UserInfo.java new file mode 100644 index 0000000..321dcb5 --- /dev/null +++ b/dlp-drugtesting-biz/src/test/java/digital/laboratory/platform/inspection/test/entity/UserInfo.java @@ -0,0 +1,18 @@ +package digital.laboratory.platform.inspection.test.entity; + +import lombok.Data; + +/** + * @author xy + * @version 1.0 + * @title UserInfo + * @description + * @create 2024/2/20 9:44 + */ +@Data +public class UserInfo { + private String id; + private String userName; + private int age; + private String sex; +} diff --git a/doc/检验鉴定系统 -- 数据文件解析方式.md b/doc/检验鉴定系统 -- 数据文件解析方式.md new file mode 100644 index 0000000..3c67c67 --- /dev/null +++ b/doc/检验鉴定系统 -- 数据文件解析方式.md @@ -0,0 +1,138 @@ +# 检验鉴定系统 -- 数据文件解析方式 + +## 20240415 + +### 毛发案件 + +#### 使用的仪器 + +**沃特斯** + +#### 源文件表头意思 + + # Name ID RT Quan Trace Area 1?Trace 1?Area + 1?Ratio (Actual) 1?Ratio (Pred) 1?Ratio Flag %Dev + Primary Flags ng/mL Std. Conc 2?Trace 2?Area + 2?Ratio (Actual) 2?Ratio (Pred) 2?Ratio Flag + +**Name** -> 数据流水号,目前也存储在数据库表`b_test_record_sampledata.name` ,存储该字段的原因是因为在实验中一个检材可能取两次数据,方便生成检验记录表时,给检材加标识 `-1、-2` 等 + +**ID** -> 这个字段可能有检材、标准品、空白溶液等。标准品在文件中的标识是 `STD`、检材的标识是系统中检材的受理编号、质控溶液的标识 `QC` 、空白溶液的是 `BLK`、 `ACN` 是用来清洗针管等 + +**RT** -> 数据文件中保留时间字段 + +**Quan Trace 和 1?Trace** -> 定性离子对 + +**Area 和 1?Area** -> 峰面积 + +**1?Ratio (Actual)** -> 离子丰度比,其计算公式是 `1?Area` / `Area` + +**1?Ratio (Pred)** -> 对比的标准品离子丰度比 + +**1?Ratio Flag** -> 标记是否检出, YES 未检出 NO检出 + +**ng/mL** -> 检材或者标准品浓度 + +余下的字段目前未用到 + + + +### NPS案件 + +#### 使用的仪器 + +**岛津** + +#### 源文件字段意思 + +``` +[Header] +Data File Name D:\20231019山西临猗\2023-76-4_8.qgd +Output Date 2023/10/27 +Output Time 9:39:02 + +[File Information] +Type 数据文件 +Generated 2023/10/24 18:45:06 +Generated by Admin +Modified 2023/10/27 9:39:02 +Modified by Admin + +[Sample Information] +Operator Name Admin +Analyzed 2023/10/24 18:52:13 +Type 未知物 +Level 1 +Sample Name 4号毒品疑似物 +Sample ID 2023-0072-1 +ISTD Amount 1 1 +ISTD Amount 2 1 +ISTD Amount 3 1 +ISTD Amount 4 1 +ISTD Amount 5 1 +ISTD Amount 6 1 +ISTD Amount 7 1 +ISTD Amount 8 1 +ISTD Amount 9 1 +ISTD Amount 10 1 +ISTD Amount 11 1 +ISTD Amount 12 1 +ISTD Amount 13 1 +ISTD Amount 14 1 +ISTD Amount 15 1 +ISTD Amount 16 1 +ISTD Amount 17 1 +ISTD Amount 18 1 +ISTD Amount 19 1 +ISTD Amount 20 1 +ISTD Amount 21 1 +ISTD Amount 22 1 +ISTD Amount 23 1 +ISTD Amount 24 1 +ISTD Amount 25 1 +ISTD Amount 26 1 +ISTD Amount 27 1 +ISTD Amount 28 1 +ISTD Amount 29 1 +ISTD Amount 30 1 +ISTD Amount 31 1 +ISTD Amount 32 1 +Sample Amount 1 +Dilution Factor 1 +Vial# 5 +Injection Volume 1 +Injection Count 1 +Bar Code + +[Original Files] +Data File D:\20231019山西临猗\2023-76-4_8.qgd +Method File D:\20231019山西临猗\海洛因方法+数据处理.qgm +Batch File D:\20231019山西临猗\2023-1026-test.qgb +Report Format File +Tuning File C:\GCMSsolution\System\Tune1\20231024-N-#1.qgt + +[File Description] + + +[MS Quantitative Results] +# of IDs 4 +ID# Name Type ISTD Group# Mass Ret.Time Start Time End Time A/H Area Height Conc. Mode Peak# Std.Ret.Time Calibration Curve 3rd 2nd 1st Constant Ref.Ion Area Ref.Ion Height Ref.Ion Set Ratio Ref.Ion Ratio Recovery SI Ref.Ion1 m/z Ref.Ion1 Area Ref.Ion1 Height Ref.Ion1 Set Ratio Ref.Ion1 Ratio Ref.Ion2 m/z Ref.Ion2 Area Ref.Ion2 Height Ref.Ion2 Set Ratio Ref.Ion2 Ratio Ref.Ion3 m/z Ref.Ion3 Area Ref.Ion3 Height Ref.Ion3 Set Ratio Ref.Ion3 Ratio Ref.Ion4 m/z Ref.Ion4 Area Ref.Ion4 Height Ref.Ion4 Set Ratio Ref.Ion4 Ratio Ref.Ion5 m/z Ref.Ion5 Area Ref.Ion5 Height Ref.Ion5 Set Ratio Ref.Ion5 Ratio Ret. Index S/N Unit Description Threshold Tailing Ref.Ion1 S/N Ref.Ion2 S/N Ref.Ion3 S/N Ref.Ion4 S/N Ref.Ion5 S/N ISTD Name ISTD Area ISTD Height ISTD Ret.Time Noise +1 Heroin 目标物 1 327.00 10.727 10.640 10.950 1.970 142994 72693 0.00000 Auto 4 10.695 线性 0 0 0 0 0 0 0 0.00 0.00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 521.57 ppm 0.00000 1.126 139.374 +2 Heroin 目标物 1 369.00 10.726 10.680 11.170 1.950 93699 48039 0.00000 Auto 9 10.695 线性 0 0 0 0 0 0 0 0.00 0.00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1010.38 ppm 0.00000 1.119 47.545 +3 Heroin 目标物 1 310.00 10.665 10.630 10.675 2.200 130 59 0.00000 Auto 13 10.695 线性 0 0 0 0 0 0 0 0.00 0.00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.32 ppm 0.00000 -- 44.735 +4 Heroin 目标物 1 268.00 10.727 10.640 11.085 1.960 93834 47994 0.00000 Auto 18 10.695 线性 0 0 0 0 0 0 0 0.00 0.00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 648.39 ppm 0.00000 1.115 74.020 + +[MC Peak Table] +``` + + + +**Type** -> 表明是标准品还是要检测的样品,    `未知物` 待检测的样品,`Standard` 标准品 + +**Sample Name** -> 检材样品的名称 + +**Sample ID** -> 检材样品的编号 + +**Name** -> 所要检测的化合物名称 + +**Mass** ->本次检测的质荷比 diff --git a/doc/污水检验鉴定系统文档.docx b/doc/污水检验鉴定系统文档.docx new file mode 100644 index 0000000..8651e3d --- /dev/null +++ b/doc/污水检验鉴定系统文档.docx @@ -0,0 +1,127 @@ + 污水检验鉴定系统文档 +简介:本文档将介绍污水检验鉴定系统,该系统能够通过实验人员进行实验导出的污水检材实验数据,自动化地抓取化合物浓度数据,并利用消费量公式进行计算,得出各化合物的消费量信息。随后,系统根据消费量情况自动生成污水任务季度报表,提供了对污水情况的全面评估和监控。 +功能概述: + 实验数据导入:系统能够接收实验人员导出的污水检材实验数据,确保数据的及时性和准确性。 + 化合物浓度抓取:系统自动抓取实验数据中的化合物浓度信息,减少人工干预,提高数据处理效率。 + 消费量计算:根据预设的消费量公式,系统对各化合物的浓度数据进行计算,得出相应的消费量信息。 + 报表生成:系统根据消费量情况自动生成污水任务季度报表,包括各化合物的消费量情况、趋势分析等内容,为决策提供参考依据。 +消费量报表实现原理: + 化合物浓度抓取:通过仪器设备导出的实验数据,会得到每个检材对应每种化合物定量以及定性的两条数据,我们取化合物名称,也就是Component Name列后缀为-1的数据中的浓度(Calculated Concentration)为定量结果。 + + 消费量计算:在获得样本各种化合物定量结果后,我们会通过一系列消费量计算公式,计算出消费量报表,下面将详细的解释消费量报表中的各个数据的计算过程: + 消费量计算报表表头 + + + + 样品编号、污水厂名称、所在地(省)、所在地(市)、所在地(区/县)、采样时间、污水厂服务人口(万人)、生活污水占比、流量(万立方米/天)由大数据平台或送检人员填报所得 + 人均人均日吸烟(支):由大数据平台统计 + 可替宁排泄量(mg/千人天):人均日吸烟(支)x 0.14 x 1000 + 测算人口:可替宁(ng/L)x 流量(万立方米/天)x 10 x 生活污水占比 / 可替宁排泄量(mg/千人天) + 可替宁(ng/L)、可待因(ng/L)、MDA(ng/L)、MDMA(ng/L)、可卡因(ng/L)、苯甲酰爱康宁(ng/L)、吗啡(ng/L)、O6-单乙酰吗啡(ng/L)、甲基苯丙胺(ng/L)、苯丙胺(ng/L)、氯胺酮(ng/L)、去甲氯胺酮(ng/L)、四氢大麻酸(ng/L)浓度均从仪器导出实验数据中抓取保存 + 化合物对应仪器数据中Component Name名称对照表格 + 可替宁 + 可待因 + mda + cotinine + codeine + mda + mdma + 可卡因 + 苯甲酰爱康宁 + mdma + cocaine + benzoylecgonine + 吗啡 + O6-单乙酰吗啡 + 甲基苯丙胺 + morphine + 6-acetylmorphine + methamphetamine + 苯丙胺 + 氯胺酮 + 去甲氯胺酮 + amphetamine + ketamine + norketamine + 四氢大麻酸 + 芬太尼 + 依托咪酯 + thc + fentanyl + etomidate + 吗啡负荷量(mg/千人﹒天):吗啡(ng/L)x 流量(万立方米/天)x 10 / 测算人口(千人) + 可待因负荷量(mg/千人﹒天):可待因(ng/L)x 流量(万立方米/天)x 10 / 测算人口(千人) + 可待因转化为吗啡负荷量(mg/千人﹒天):可待因负荷量(mg/千人﹒天)x 0.065 / (0.3 x 1.05),注:可待因转化为吗啡的比例为6.5%,可待因的排泄率为30%,1.05为可待因与吗啡的分子量比,计算公式如下: + + 医用吗啡负荷量(mg/千人﹒天):等于1,根据文献取平均值 + MA/AM:甲基苯丙胺(ng/L)/ 苯丙胺(ng/L) + K/NK :氯胺酮(ng/L)/ 去甲氯胺酮(ng/L) + 人均消耗量(mg/千人﹒天)Heroin :(吗啡负荷量(mg/千人﹒天)- 可待因转化为吗啡负荷量(mg/千人﹒天)- 医用吗啡负荷量(mg/千人﹒天)) x 3.07,注:计算海洛因的消费量时要减去可待因转化的吗啡以及医用吗啡 + 人均消耗量(mg/千人﹒天)MA :甲基苯丙胺(ng/L)或 苯丙胺(ng/L)x 流量(万立方米/天)x 10 x 2.33或46.6 / 测算人口(千人),注:AM=0时,冰毒消费量用MA计算。AM!=0时,若MA/AM≦20,冰毒消费量用MA计算,若MA/AM>20,冰毒消费量用AM计算 + 人均消耗量(mg/千人﹒天)K :氯胺酮(ng/L)或去甲氯胺酮(ng/L)x 流量(万立方米/天)x 10 x 5或26.6 / 测算人口(千人),注:NK=0时,氯胺酮消费量用K计算。NK!=0时,若K/NK≦6,氯胺酮消费量用K计算,若K/NK>6,氯胺酮消费量用NK计算 + 人均消耗量(mg/千人﹒天)MDMA :MDMA(ng/L)x 流量(万立方米/天)x 10 x 4.44 / 测算人口(千人) + 人均消耗量(mg/千人﹒天)COC :苯甲酰爱康宁(ng/L)x 流量(万立方米/天)x 10 x 2.33 / 测算人口(千人) + 人均消耗量(mg/千人﹒天)THC :四氢大麻酸(ng/L)x 流量(万立方米/天) x 10 x 152 / 测算人口(千人) + 消费量折算系数 + + 总消耗量 :对应化合物的人均消费量 x 当地测算人口 + (化合物)人均消耗量 :各区县总消耗量之和 / 各区县测算人口之和 + 人均总消耗量 :所有化合物人均消费量之和 + +污水报告实现原理: +表1 陕西省各行政区主要毒品总消费量表 + + 计算每个地市的各类毒品总均消费量(克/天)的方式是筛选出属于整个地市的所有检材,把每个检材计算得到得各类毒品千人均消费量 乘以 检材对应地区的测试人口数,然后把所有结果累加起来得到的, 最后除以1000毫克转克。比如说西安市的海洛因的总消费量 = ((检材1海洛因的千人均消费量 * 检材1对应地区的测试人口)+ (检材2海洛因的千人均消费量 * 检材2对应地区的测试人口)......)/ 1000。 + 计算每个地市的综合总消费量 = 海洛因总消费量 + 冰毒总消费量 + ......;这里千人均消费量一样的计算方式 = 海洛因千人均消费量 + 冰毒千人均消费量...... + 计算每个地市的千人均消费量 = ((该地市检材1海洛因的千人均消费量 * 该地市检材1对应地区的测试人口)+ (该地市检材2海洛因的千人均消费量 *该地市 检材2对应地区的测试人口)......)/ (该地市检材1的测算人口 + 该地市检材2的测算人口 + ......) + 全省千人均消费量 = 各地市对应毒品千人均消费量之和 / 地市数量; + 全省的综合千人均消费量 = 全省各类毒品千人均消费量之和;(全省总消费量计算方法相同) + +图1 陕西省常见毒品消费结构图 + + 在该扇形统计图中的数据是根据该类毒品全省的总消费量在全省综合总消费量的比例,为0的毒品则不统计。 + +图2 陕西省各行政区毒品千人均消费量 + 在该统计图中显示的数据来自于前面表1 陕西省各行政区主要毒品总消费量表中计算出的每个地市的毒品千人均消费量。 + 在该统计图中,即使有某个地市的所有毒品千人均消费量都为0也会在柱状图中显示。 + +图3 陕西省毒品千人均消费量变化趋势 + + 在该统计图中我们会根据时间获取当前任务之前的四个任务来做比较;。 + 图中的数据是取全省的各类毒品千人均消费量和综合千人均消费量 + +当前任务千人均消费量的同比环比 + 当前任务的同比 = (当前任务的综合千人均消费量 - 上一年同季度任务的综合千人均消费量 )/ 上一年同季度任务的综合千人均消费量 * 100%; + 当前任务的同、环比比 = (当前任务的综合千人均消费量 - 上一季度任务的综合千人均消费量 )/ 上一季度任务的综合千人均消费量 * 100%; + 海洛因和冰毒的同比环比计算方式也是一样的。同比 = (当前任务的海洛因千人均消费量 - 上一年同季度任务的海洛因千人均消费量 )/ 上一年同季度任务的海洛因千人均消费量 * 100%; + +表2 陕西省各污水厂服务区及各行政区毒品千人均消费量表 + + 计算各区县或污水厂的各类毒品千人均消费量 = ((该区县检材1海洛因的千人均消费量 * 该区县检材1对应地区的测试人口)+ (该区县检材2海洛因的千人均消费量 *该区县检材2对应地区的测试人口)......)/ (该区县检材1的测算人口 + 该区县检材2的测算人口 + ......) + 是否存在不合格样品是根据当前区县的所有检材中是否存在可替宁浓度低于500ng/L,存在则有不合格样品 + +表4 陕西省污水处理厂冰毒浓度排名表 + 取对应任务中各个地区污水厂中检出甲基苯丙胺浓度排名前15的地区 +常见毒品以及代谢物和人口标记物的选择 + 在这里可以选择报告中的常见毒品以及代谢物和人口标记物,会出现在报告中的地方有两个地方用到 + 第一个 + + 第二个,会出现在这个附表中的表头 + + +各毒品滥用现状描述 + 在上述图片所显示得毒品滥用中,冰毒、海洛因的描述和上面图片所显示的大致一样,改变的只有年月、检出的污水厂占的比例、千人均消费量以及总消费量等数据。 + 氯胺酮、可卡因、摇头丸等毒品的滥用描述则有两种情况,如果是有多个样品检出则采用图片中氯胺酮的描述,只有一个样品检出则采用可卡因的描述 + 如果所有样品中都没有检出某个毒品则采用摇头丸等未检出的描述 + +控制依托咪酯相关表格和毒品滥用描述的生成 + + +1.在生成报告的弹框中可以选择当前报告是否去生成依托咪酯相关的信息,如依托咪酯的毒品滥用现状、各行政区依托咪酯统计表 + + + +报告中需要自定义修改的两处地方 + + 这里中的描述需要去根据总消费量变化趋势和千人均消费量变化趋势去描述,所以这里需要当前用户生成时,在onlyoffice中预览时或下载到本地进行修改。 + diff --git a/doc/消费量报表规则.md b/doc/消费量报表规则.md new file mode 100644 index 0000000..a678470 --- /dev/null +++ b/doc/消费量报表规则.md @@ -0,0 +1,84 @@ +# 消费量报表规则 + +1. 样本编号 + +2. 污水处理厂名称 + +3. 所在地(省) + +4. 所在地(市) + +5. 所在地(区/县) + +6. 采样时间 + +7. 污水厂服务人口(万人) + +8. 生活污水占比 + +9. 流量(万立方米/天) + +10. 人均日吸烟(支)注:各省数值不同,可查询实验大数据平台左侧导航栏地区信息 + +11. 可替宁排泄量(mg/千人天)= 人均日吸烟(支)* 0.14 * 1000 +12. 测算人口(千人)= 可替宁(ng/L) * 流量(万立方米/天) * 10 * 生活污水占比 / 可替宁排泄量(mg/千人天) + + 注:将ng/L转化为mg/L,换算率为1000000,10000立方米等于10,000,000L,而1mg等于1000000ng,简单描述为,通过流量乘以污水占比计算出总流量,然后乘以可替宁浓度,再换算为mg,可得出该地区每天的可替宁总质量,然后除以 可替宁排泄量(千人),可大致推算出测算人口 + + + +13. | 可替宁(ng/L) | 可待因(ng/L) | MDA(ng/L) | MDMA(ng/L) | 可卡因(ng/L) | 苯甲酰爱康宁(ng/L) | 吗啡(ng/L) | O6-单乙酰吗啡(ng/L) | 甲基苯丙胺(ng/L) | 苯丙胺(ng/L) | 氯胺酮(ng/L) | 去甲氯胺酮(ng/L) | 四氢大麻酸(ng/L) | + | -------------- | -------------- | ----------- | ------------ | -------------- | -------------------- | ------------ | --------------------- | ------------------ | -------------- | -------------- | ------------------ | ------------------ | + | | | | | | | | | | | | | | + + 以上为实验所得的污水化合物浓度 + + +14. 吗啡负荷量(mg/千人﹒天)= 吗啡(ng/L) * 流量(万立方米/天)* 10 / 测算人口(千人) + 备注:通过检测污水中吗啡的浓度,乘以总流量,得到该地区每天产生的吗啡总质量,再除以测算人口,可大致计算吗啡负荷量(mg/千人﹒天),计算公式如下: + + ![image-20240417101958546](../dlp-drugtesting-biz/assets/image-20240417101958546.png) + +15. 可待因负荷量(mg/千人﹒天)= 可待因(ng/L)* 流量(万立方米/天)* 10 / 测算人口(千人) + + 备注:通过检测污水中吗啡的浓度,乘以总流量,得到该地区每天产生的吗啡总质量,再除以测算人口,可大致计算吗啡负荷量(mg/千人﹒天) + +16. 可待因转化为吗啡负荷量(mg/千人﹒天) = 可待因负荷量(mg/千人﹒天) * 0.065 / (0.3 * 1.05) + 备注:可待因转化为吗啡的比例为6.5%,可待因的排泄率为30%,1.05为可待因与吗啡的分子量比,计算公式如下: + + ![image-20240417101824328](../dlp-drugtesting-biz/assets/image-20240417101824328.png) + +17. 医用吗啡负荷量(mg/千人﹒天)= 1 是根据文献取平均值 + +18. MA/AM = 甲基苯丙胺(ng/L)/ 苯丙胺(ng/L)Excel中红色区域代表MA/AM>20 + +19. K/NK = 氯胺酮(ng/L)/ 去甲氯胺酮(ng/L) Excel中红色区域代表K/NK>6 + +20. 人均消耗量(mg/千人﹒天)Heroin = (吗啡负荷量(mg/千人﹒天)- 可待因转化为吗啡负荷量(mg/千人﹒天)- 医用吗啡负荷量(mg/千人﹒天)) * 3.07 + + 备注:计算海洛因的消费量时要减去可待因转化的吗啡以及医用吗啡 + + 消费量折算系数如下: + + ![image-20240417102214943](../dlp-drugtesting-biz/assets/image-20240417102214943.png) + +21. 人均消耗量(mg/千人﹒天)MA = 甲基苯丙胺(ng/L)或 苯丙胺(ng/L)* 流量(万立方米/天) * 10 * 2.33或46.6 / 测算人口(千人) + + 备注:注:AM=0时,冰毒消费量用MA计算。AM≠0时,若MA/AM≦20,冰毒消费量用MA计算,若MA/AM>20,冰毒消费量用AM计算。 AM为苯丙胺(ng/L),MA为甲基苯丙胺,用样本中甲基苯丙胺或苯丙胺的浓度乘以总流量,再换算为mg,得到该地区每天产生的冰毒总量,乘以对应系数,再除以测算人口,得到人均消费量。 + +22. 人均消耗量(mg/千人﹒天)K = 氯胺酮(ng/L)或去甲氯胺酮(ng/L) * 流量(万立方米/天) * 10 * 5或26.6 / 测算人口(千人) + + 备注:NK=0时,氯胺酮消费量用K计算。NK≠0时,若K/NK≦6,氯胺酮消费量用K计算,若K/NK>6,氯胺酮消费量用NK计算。K为氯胺酮,NK为去甲氯胺酮 + +23. 人均消耗量(mg/千人﹒天)MDMA = MDMA(ng/L) * 流量(万立方米/天) * 10 * 4.44 / 测算人口(千人) + +24. 人均消耗量(mg/千人﹒天)COC = 苯甲酰爱康宁(ng/L) * 流量(万立方米/天) * 10 * 2.33 / 测算人口(千人) + +25. 人均消耗量(mg/千人﹒天)THC = 四氢大麻酸(ng/L) * 流量(万立方米/天) * 10 * 152 / 测算人口(千人) + +26. 总消耗量:对应化合物的人均消费量 * 当地测算人口 + +27. (化合物)人均消耗量:各区县总消耗量之和 / 各区县测算人口之和 + +28. 人均总消耗量:所有化合物人均消费量之和 + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2b59f03 --- /dev/null +++ b/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + digital.laboratory.platform + DigitalLaboratoryPlatform + 2022.10.11-snapshots + + dlp-drugtesting + 2022.10.11-snapshots + pom + dlp-drugtesting + + UTF-8 + + + dlp-drugtesting-api + dlp-drugtesting-biz + +