From ecb584aa9ae375990a8c52a4b1722a617892f8ef Mon Sep 17 00:00:00 2001 From: chen <2710907404@qq.com> Date: Tue, 1 Apr 2025 10:44:15 +0800 Subject: [PATCH 1/3] =?UTF-8?q?20250401=20=E6=9B=B4=E6=96=B0=201.=E6=8E=A8?= =?UTF-8?q?=E9=80=81=E7=94=9F=E7=89=A9=E6=A3=80=E6=9D=90=E5=AE=9A=E6=80=A7?= =?UTF-8?q?=E6=A3=80=E9=AA=8C=E8=AE=B0=E5=BD=95=E6=95=B0=E6=8D=AE=E5=88=B0?= =?UTF-8?q?labscare=E5=B9=B3=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inspetion/api/entity/EntrustInfo.java | 17 +- dlp-drugtesting-biz/pom.xml | 6 + .../inspection/config/ApiPathProperties.java | 63 ++++ .../convert/TestRecordReagentConverter.java | 8 + .../TestRecordSampleDataConverter.java | 26 ++ .../event/PushDataToLabsCareEvent.java | 37 ++ .../PushDataToLabsCareEventListener.java | 51 +++ .../service/CommonFeignService.java | 99 +++++ .../service/InspectRecordService.java | 28 ++ .../service/ProcessInspectDataService.java | 8 + .../service/PushDataToLabsCareService.java | 17 + .../service/TestRecordReagentService.java | 8 + .../service/impl/CommonFeignServiceImpl.java | 262 +++++++++++++ .../impl/InspectRecordServiceImpl.java | 11 +- .../impl/ProcessInspectDataServiceImpl.java | 43 ++- .../impl/PushDataToLabsCareServiceImpl.java | 356 ++++++++++++++++++ .../impl/TestRecordReagentServiceImpl.java | 12 + .../impl/TestRecordSampleDataServiceImpl.java | 49 +-- ...TestRecordSampledataExpandServiceImpl.java | 2 + .../threadpool/GlobalThreadPool.java | 52 +++ .../src/main/resources/bootstrap.yml | 8 + 21 files changed, 1091 insertions(+), 72 deletions(-) create mode 100644 dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/config/ApiPathProperties.java create mode 100644 dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/event/PushDataToLabsCareEvent.java create mode 100644 dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/listener/PushDataToLabsCareEventListener.java create mode 100644 dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/CommonFeignService.java create mode 100644 dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/PushDataToLabsCareService.java create mode 100644 dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/CommonFeignServiceImpl.java create mode 100644 dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/PushDataToLabsCareServiceImpl.java create mode 100644 dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/threadpool/GlobalThreadPool.java 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 index 79991e7..d09abb2 100644 --- 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 @@ -6,7 +6,6 @@ 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; @@ -37,16 +36,32 @@ public class EntrustInfo extends BaseEntity { 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 + + @ApiModelProperty("是否推送数据到LabsCare的标识,[EntrustLetter:true 代表推送委托书成功 | ItemConfirmLetter:true 代表推送鉴定事项确认书成功 | BiologyQualitativeRecord:true 代表推送生物定性检验记录成功]" + + "如果这个字段为空则表示失败,如果两个推送都成功,以英文逗号分隔") + private String pushFlag; + + @TableField(exist = false) private String businessTypeName; @TableField(exist = false) diff --git a/dlp-drugtesting-biz/pom.xml b/dlp-drugtesting-biz/pom.xml index 745686f..07b047b 100644 --- a/dlp-drugtesting-biz/pom.xml +++ b/dlp-drugtesting-biz/pom.xml @@ -99,6 +99,12 @@ dlp-admin-api ${dlp.version} + + + digital.laboratory.platform + dlp-othersys-api + ${dlp.version} + digital.laboratory.platform dlp-drugtesting-api diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/config/ApiPathProperties.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/config/ApiPathProperties.java new file mode 100644 index 0000000..5cffa94 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/config/ApiPathProperties.java @@ -0,0 +1,63 @@ +package digital.laboratory.platform.inspection.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 贵阳禁毒-情报平台推送数据配置 + */ +@Component +@ConfigurationProperties(prefix = "gyjd.labscare.api") +public class ApiPathProperties { + /** + * api的ip + */ + private String host; + + /** + * 委托书推送的接口 + */ + private String entrustLetter; + + /** + * 确认书推送接口 + */ + private String confirmLetter; + + /** + * 生物检材定性记录 + */ + private String biologyQualitativeRecord; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public String getEntrustLetter() { + return host + entrustLetter; + } + + public void setEntrustLetter(String entrustLetter) { + this.entrustLetter = entrustLetter; + } + + public String getConfirmLetter() { + return host + confirmLetter; + } + + public void setConfirmLetter(String confirmLetter) { + this.confirmLetter = confirmLetter; + } + + public String getBiologyQualitativeRecord() { + return host + biologyQualitativeRecord; + } + + public void setBiologyQualitativeRecord(String biologyQualitativeRecord) { + this.biologyQualitativeRecord = biologyQualitativeRecord; + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/convert/TestRecordReagentConverter.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/convert/TestRecordReagentConverter.java index 718eb14..11bd127 100644 --- a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/convert/TestRecordReagentConverter.java +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/convert/TestRecordReagentConverter.java @@ -34,6 +34,14 @@ public class TestRecordReagentConverter { return testRecordReagentVO; } + /** + * 实体分页对象转 VO 分页对象 + */ + public static List entityToVOList(List entityList) { + // 将实体列表转换为 VO 列表 + return entityList.stream().map(TestRecordReagentConverter::entityToVO).collect(Collectors.toList()); + } + /** * 实体分页对象转 VO 分页对象 */ diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/convert/TestRecordSampleDataConverter.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/convert/TestRecordSampleDataConverter.java index 541d583..473fb96 100644 --- a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/convert/TestRecordSampleDataConverter.java +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/convert/TestRecordSampleDataConverter.java @@ -1,7 +1,9 @@ package digital.laboratory.platform.inspection.convert; +import digital.laboratory.platform.inspection.constant.TestRecordSampleDataConstant; import digital.laboratory.platform.inspection.dto.SampleInspectDataDTO; import digital.laboratory.platform.inspection.entity.TestRecordSampleData; +import digital.laboratory.platform.inspection.vo.TestRecordSampleDataVO; import java.util.Collections; import java.util.List; @@ -15,6 +17,30 @@ import java.util.stream.Collectors; */ public class TestRecordSampleDataConverter { + public static TestRecordSampleData voToEntity(TestRecordSampleDataVO vo) { + if (vo == null) return null; + TestRecordSampleData testRecordSampleData = new TestRecordSampleData(); + testRecordSampleData.setId(vo.getId()); + testRecordSampleData.setName(vo.getName()); + testRecordSampleData.setSampleNo(vo.getSampleNo()); + testRecordSampleData.setTestId(vo.getTestId()); + testRecordSampleData.setStdConcentration(vo.getStdConcentration()); + testRecordSampleData.setSampleConcentration(vo.getSampleConcentration()); + testRecordSampleData.setCompoundName(vo.getCompoundName()); + testRecordSampleData.setRtTimeWithinError(vo.getRtTimeWithinError()); + testRecordSampleData.setRtTimeError(vo.getRtTimeError()); + testRecordSampleData.setTargetRtTime(vo.getTargetRtTime()); + testRecordSampleData.setStdRtTime(vo.getStdRtTime()); + testRecordSampleData.setIsDetected(vo.getIsDetected().equals(TestRecordSampleDataConstant.IS) ? 1 : 0); + testRecordSampleData.setSampleType(vo.getSampleType()); + testRecordSampleData.setDataJson(vo.getDataJson()); + testRecordSampleData.setDataResultJson(vo.getDataResultJson()); + testRecordSampleData.setStatus(vo.getStatus()); + testRecordSampleData.setCompoundCnName(vo.getCompoundCnName()); + testRecordSampleData.setWhetherCheckOut(vo.getWhetherCheckOut()); + return testRecordSampleData; + } + /** * dot 转 entity * @param dto diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/event/PushDataToLabsCareEvent.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/event/PushDataToLabsCareEvent.java new file mode 100644 index 0000000..c4f304d --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/event/PushDataToLabsCareEvent.java @@ -0,0 +1,37 @@ +package digital.laboratory.platform.inspection.event; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +import java.time.Clock; + +/** + * 推送数据到LabsCare 数据平台上的spring 事件 + */ +@Getter +public class PushDataToLabsCareEvent extends ApplicationEvent { + + /** + * 实验id + */ + private final String testId; + + /** + * 推送的数据类型, 1 鉴定委托书数据 | 2 鉴定事项确认书数据 | 3 生物检材定性记录报告数据 + */ + private final Integer pushType; + + public PushDataToLabsCareEvent(Object source, String testId, Integer pushType) { + super(source); + this.testId = testId; + this.pushType = pushType; + } + + public PushDataToLabsCareEvent(Object source, Clock clock, String testId, Integer pushType) { + super(source, clock); + this.testId = testId; + this.pushType = pushType; + } + + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/listener/PushDataToLabsCareEventListener.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/listener/PushDataToLabsCareEventListener.java new file mode 100644 index 0000000..d6ded28 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/listener/PushDataToLabsCareEventListener.java @@ -0,0 +1,51 @@ +package digital.laboratory.platform.inspection.listener; + + +import digital.laboratory.platform.inspection.event.PushDataToLabsCareEvent; +import digital.laboratory.platform.inspection.service.PushDataToLabsCareService; +import digital.laboratory.platform.inspection.threadpool.GlobalThreadPool; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.concurrent.CompletableFuture; + +/** + * 监听有关推送数据到LabsCare 平台的事件, 采用异步 + */ +@Slf4j +@Component +public class PushDataToLabsCareEventListener implements ApplicationListener { + + @Resource + private PushDataToLabsCareService pushDataToLabsCareService; + + /** + * 处理委托数据推送事件 + * + * @param event 委托数据推送事件对象 + */ + @Override + public void onApplicationEvent(PushDataToLabsCareEvent event) { + CompletableFuture.runAsync(() -> { + // 处理不同的推送类型 + switch (event.getPushType()) { + case 3: // 推送委托书数据 + try { + pushDataToLabsCareService.pushBiologyQualitativeRecordData(event.getTestId()); + } catch (Exception e) { + log.error("实验id为 {} 的生物定性检验记录数据推送失败!", event.getTestId(), e); + } + break; + default: + log.warn("未知的推送类型: {}", event.getPushType()); + break; + } + }, GlobalThreadPool.getInstance()).exceptionally(e -> { + log.error("推送数据到 LabsCare 失败", e); + return null; + }); + } + +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/CommonFeignService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/CommonFeignService.java new file mode 100644 index 0000000..9fbbe33 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/CommonFeignService.java @@ -0,0 +1,99 @@ +package digital.laboratory.platform.inspection.service; + +import com.deepoove.poi.XWPFTemplate; +import digital.laboratory.platform.sys.entity.Area; +import digital.laboratory.platform.sys.entity.SysOrg; +import digital.laboratory.platform.sys.entity.SysUser; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayInputStream; +import java.util.List; +import java.util.Map; + +/** + * 通用的feign请求封装接口服务层接口 + */ +public interface CommonFeignService { + + /** + * 远程调用获取用户机构 + * @param orgId + * @return + */ + SysOrg remoteGetSysOrg(String orgId); + + /** + * 根据权限和机构远程获取用户列表 + * + * @param orgId 组织ID + * @param permission 权限列表 + * @return 用户列表 + */ + List remoteGetUsersByPermission(String orgId, List permission); + + /** + * 通过机构ID远程获取机构所在省市信息 + * + * @param orgId 机构ID + * @return 包含机构所在省市信息的Area对象列表 + * @throws RuntimeException 当根据机构ID获取机构所在省市信息失败时抛出 + */ + List remoteGetProvinceCityInfo(String orgId); + + /** + * 远程调用获取用户信息 + * @param username + * @return + */ + SysUser remoteGetUserByUsername(String username); + + /** + * 远程调用获取用户信息 + * @param userId + * @return + */ + SysUser remoteGetUserById(String userId); + + /** + * 远程调用生成word,并转成pdf + * + * @param template + * @param originalFilename 文件名 + * @param savePath 保存到minio路径 + * @return + * @throws Exception + */ + boolean remoteGenerateWord2PDF(XWPFTemplate template, String originalFilename, String savePath) throws Exception; + + /** + * 远程调用根据文件路径获取文件 + * @param filePath minio上的文件路径 + * @return + * @throws Exception + */ + ByteArrayInputStream remoteGetFile(String filePath) throws Exception; + + /** + * 远程调用根据文件路径获取文件 + * @param filePath minio上的文件路径 + * @param fileName 名称 + * @param httpServletResponse + * @throws Exception + */ + void remoteGetFile(String filePath, String fileName, HttpServletResponse httpServletResponse) throws Exception; + + /** + * 远程调用根据文件路径获取文件列表 + * @param filePath minio上的文件路径 + */ + List remoteGetFileList(String filePath); + + /** + * 远程调用-上传文件 + * @param file 上传的文件对象 + * @param path 上传到minio的位置 + * @return + */ + Map remoteUploadFile(MultipartFile file, String path); +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/InspectRecordService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/InspectRecordService.java index 083abb5..f900c95 100644 --- a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/InspectRecordService.java +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/InspectRecordService.java @@ -1,8 +1,11 @@ package digital.laboratory.platform.inspection.service; import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.inspection.entity.TestRecordSampleData; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; import javax.servlet.http.HttpServletResponse; +import java.util.List; /** * @author ChenJiangBao @@ -21,4 +24,29 @@ public interface InspectRecordService { R buildInspectionRecord(String businessId, String materialType) throws Exception; void previewInspectionRecord(String businessId, String materialType, HttpServletResponse servletResponse) throws Exception; + + /** + * 构建检材性状描述(使用检材编号尾号,并合并连续编号) + *

+ * 规则: + * 1. **提取编号尾号**(如 `2025007001` → `1`) + * 2. **按尾号排序** + * 3. **连续编号 & 物质性状相同时合并** + * 4. **只有一个检材时,省略编号,直接描述** + * 5. **输出格式示例:** + * - `"1号至4号检材为粉状"` + * - `"检材为粉状"`(仅有一个检材时) + * + * @param sampleInfoList 样本信息列表 + * @return 物料特性描述(如果列表为空,则返回空字符串) + */ + String buildMaterialCharacterDesc(List sampleInfoList); + + /** + * 根据传入的TestRecordSampleData列表生成鉴定意见 + * + * @param dataList 包含检验数据的列表 + * @return 检测意见字符串,以“;”分隔 + */ + String buildInspectOpinion(List dataList); } diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/ProcessInspectDataService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/ProcessInspectDataService.java index caaa833..1b74c7e 100644 --- a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/ProcessInspectDataService.java +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/ProcessInspectDataService.java @@ -26,6 +26,14 @@ public interface ProcessInspectDataService { */ String calculateHairCaseIonAbundanceRatioWithinError(double ionAbundanceRatioWithinError, double stdIonAbundanceRatio); + /** + * 根据给定的标准离子丰度比获取生物样本案件离子丰度比相对误差范围内的最大允许相对误差 + * + * @param stdIonAbundanceRatio 标准离子丰度比 + * @return 发案离子丰度比允许的最大误差值 + */ + Double getHairCaseIonAbundanceRatioWithinErrorRange(double stdIonAbundanceRatio); + /** * 计算离子丰度比偏差 * diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/PushDataToLabsCareService.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/PushDataToLabsCareService.java new file mode 100644 index 0000000..fabb8b7 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/PushDataToLabsCareService.java @@ -0,0 +1,17 @@ +package digital.laboratory.platform.inspection.service; + +/** + * @author ChenJiangBao + * @version 1.0 + * @description: 推送数据到labscare平台接口 + * @date 2025/3/31 9:28 + */ +public interface PushDataToLabsCareService { + + /** + * 推送生物检材定性记录 + * @param testId 实验id + */ + void pushBiologyQualitativeRecordData(String testId); + +} 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 index ec473d7..6c83522 100644 --- 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 @@ -1,5 +1,6 @@ package digital.laboratory.platform.inspection.service; +import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; @@ -29,6 +30,13 @@ public interface TestRecordReagentService extends IService { */ TestRecordReagentVO getVOById(String id); + /** + * 根据wrapper获取vo类 + * @param queryWrapper + * @return + */ + List voListByWrapper(Wrapper queryWrapper); + TestRecordReagent addTestRecordReagent(TestRecordReagent testRecordReagent);//添加实验使用方法 TestRecordReagent updateTestRecordReagent(TestRecordReagent testRecordReagent);//修改实验使用方法 diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/CommonFeignServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/CommonFeignServiceImpl.java new file mode 100644 index 0000000..c26f83b --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/CommonFeignServiceImpl.java @@ -0,0 +1,262 @@ +package digital.laboratory.platform.inspection.service.impl; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.io.file.FileNameUtil; +import cn.hutool.core.util.StrUtil; +import com.deepoove.poi.XWPFTemplate; +import digital.laboratory.platform.common.core.constant.CommonConstants; +import digital.laboratory.platform.common.core.util.R; +import digital.laboratory.platform.common.feign.RemoteWord2PDFService; +import digital.laboratory.platform.common.oss.service.OssFile; +import digital.laboratory.platform.inspection.service.CommonFeignService; +import digital.laboratory.platform.sys.dto.UserInfo; +import digital.laboratory.platform.sys.entity.Area; +import digital.laboratory.platform.sys.entity.SysOrg; +import digital.laboratory.platform.sys.entity.SysUser; +import digital.laboratory.platform.sys.feign.RemoteOrgService; +import digital.laboratory.platform.sys.feign.RemoteUserService; +import feign.Response; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayInputStream; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 通用的feign请求封装接口服务层接口 实现类 + */ +@Slf4j +@Service +public class CommonFeignServiceImpl implements CommonFeignService { + + @Resource + private RemoteOrgService remoteOrgService; + + @Resource + private RemoteUserService remoteUserService; + + @Resource + private RemoteWord2PDFService remoteWord2PDFService; + + @Resource + private OssFile ossFile; + + /** + * 根据用户获取远程系统机构信息 + * + * @param orgId 用户信息 + * @return 对应的远程系统机构信息 + * @throws RuntimeException 如果未找到对应的机构信息,则抛出运行时异常 + */ + @Override + public SysOrg remoteGetSysOrg(String orgId) { + SysOrg sysOrg = null; + R r = remoteOrgService.getByIdWithoutToken(orgId); + if (r != null && r.getCode() == CommonConstants.SUCCESS) { + sysOrg = r.getData(); + } else { + throw new RuntimeException(String.format("没有找到 orgId 为 %s 的机构, 请确认用户所属机构的正确性!", orgId)); + } + return sysOrg; + } + + /** + * 取指定环节可用的用户列表 + * 当流程进行到某个环节的时候, 需要某个用户对这个环节进行处理(通过或不通过)。 + * 这里取可用的用户列表 + *

+ * 涉及到的环境有以下几个: + * 1、创建委托及提交 + * 委托的提交者就是委托的创建者。不存在不通过的可能。 + * 2、审核 + * 审核者有几个条件: (1)必须是鉴定中心的工作人员 (2)必须拥有委托审核权限 + * 3、审批 + * 审核者有几个条件: (1)必须是鉴定中心的工作人员 (2)必须拥有委托审批权限 + * 4、送检确认 + * 送检确认者有几个条件: (1)必须与委托的创建者是同一个机构, 或上级机构的人 (2)必须拥有委托送检确认权限 + * 5、受理 + * 受理者有几个条件: (1)必须是鉴定中心的工作人员 (2)必须拥有委托受理权限 + * + * @return + */ + /** + * 根据权限和机构远程获取用户列表 + * + * @param orgId 组织ID + * @param permission 权限列表 + * @return 用户列表 + */ + @Override + public List remoteGetUsersByPermission(String orgId, List permission) { + R> r = remoteUserService.innerGetUsersByPermission(orgId, permission); + if (r != null && r.getCode() == CommonConstants.SUCCESS) { + return r.getData(); + } else { + throw new RuntimeException(String.format("根据权限 [%s] 和 机构id [%s] 远程获取用户列表!", permission, orgId)); + } + } + + /** + * 通过机构ID远程获取机构所在省市信息 + * + * @param orgId 机构ID + * @return 包含机构所在省市信息的Area对象列表 + * @throws RuntimeException 当根据机构ID获取机构所在省市信息失败时抛出 + */ + @Override + public List remoteGetProvinceCityInfo(String orgId) { + List result = null; + R> r = remoteOrgService.fetchProvinceCityInfoByOrgId(orgId); + if (r != null && r.getCode() == CommonConstants.SUCCESS) { + result = r.getData(); + } else { + throw new RuntimeException("根据机构id获取机构所在省市信息失败!"); + } + return result; + } + + /** + * 远程调用或者用户信息 + * @param username + * @return + */ + @Override + public SysUser remoteGetUserByUsername(String username){ + R info = remoteUserService.innerGetUserInfoByUsername(username); + if (info != null && info.getCode() == CommonConstants.FAIL) { + throw new RuntimeException(String.format("获取用户名为 %s 的用户信息失败!", username)); + } + return info.getData().getSysUser(); + } + + /** + * 远程调用获取用户信息 + * @param userId + * @return + */ + @Override + public SysUser remoteGetUserById(String userId){ + R info = remoteUserService.innerGetById(userId); + if (info != null && info.getCode() == CommonConstants.FAIL) { + throw new RuntimeException(String.format("获取用户名id为 %s 的用户信息失败!", userId)); + } + return info.getData(); + } + + @Override + public boolean remoteGenerateWord2PDF(XWPFTemplate template, String originalFilename, String savePath) throws Exception{ + ByteArrayOutputStream fosWord = new ByteArrayOutputStream(); + template.write(fosWord); + template.close(); + + //------------ + ByteArrayInputStream fisWord = new ByteArrayInputStream(fosWord.toByteArray()); + fosWord.close(); + + MockMultipartFile mockMultipartFile = new MockMultipartFile("file", originalFilename + ".docx", "image/jpg", fisWord); + Response response = remoteWord2PDFService.word2pdf(mockMultipartFile); + fisWord.close(); + + + ByteArrayOutputStream outPDF = new ByteArrayOutputStream(); + IoUtil.copy(response.body().asInputStream(), outPDF, IoUtil.DEFAULT_MIDDLE_BUFFER_SIZE); + ByteArrayInputStream isPDF = new ByteArrayInputStream(outPDF.toByteArray()); + outPDF.close(); + + boolean b = ossFile.fileSave(savePath, isPDF); + + isPDF.close(); + + log.info("转换为 PDF 结束"); + return b; + } + + /** + * 远程调用根据文件路径获取文件 + * @param filePath minio上的文件路径 + * @return + * @throws Exception + */ + @Override + public ByteArrayInputStream remoteGetFile(String filePath) throws Exception { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ossFile.fileGet(filePath, bos); + + byte[] templateArray = bos.toByteArray(); + + ByteArrayInputStream bis = new ByteArrayInputStream(templateArray); + bos.close(); + return bis; + } + + /** + * 远程调用根据文件路径获取文件 + * @param filePath minio上的文件路径 + * @param fileName 名称 + * @param httpServletResponse + * @throws Exception + */ + @Override + public void remoteGetFile(String filePath, String fileName, HttpServletResponse httpServletResponse) throws Exception { + ossFile.fileGet(filePath, httpServletResponse.getOutputStream()); + if (StrUtil.isNotBlank(fileName)) { + httpServletResponse.setContentType(fileName); + } + } + + /** + * 远程调用根据文件路径获取文件列表 + * @param filePath minio上的文件路径 + */ + @Override + public List remoteGetFileList(String filePath) { + if (StrUtil.isNotBlank(filePath)) { + List fileNameList = ossFile.fileList(filePath); + List fileList = fileNameList.stream().map(fileName -> { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + try { + ossFile.fileGet(filePath + "/" + fileName, byteArrayOutputStream); + return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()); + } catch (Exception e) { + e.printStackTrace(); + log.error("文件获取失败, 文件路径为: {}", filePath + "/" + fileName); + } + return null; + }).collect(Collectors.toList()); + return fileList; + } else { + throw new RuntimeException("文件路径不能为空!"); + } + } + + /** + * 远程调用-上传文件 + * @param file 上传的文件对象 + * @param path 上传到minio的位置 + * @return + */ + @Override + public Map remoteUploadFile(MultipartFile file, String path) { + boolean r = ossFile.fileUpload(file, path); + if (r) { + HashMap resultData = new HashMap<>(); + resultData.put("fileName", FileNameUtil.getName(file.getOriginalFilename())); + resultData.put("path", path); + log.info("文件上传成功!"); + return resultData; + } else { + String failMsg = String.format("文件名为 %s 的文件上传失败!", file.getOriginalFilename()); + log.error(failMsg); + throw new RuntimeException(failMsg); + } + } +} diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/InspectRecordServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/InspectRecordServiceImpl.java index 6c1cd93..6254cd0 100644 --- a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/InspectRecordServiceImpl.java +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/InspectRecordServiceImpl.java @@ -26,7 +26,6 @@ import digital.laboratory.platform.inspection.vo.IonPairAndCEVO; import digital.laboratory.platform.inspection.vo.TestRecordReagentVO; import digital.laboratory.platform.inspetion.api.entity.EntrustInfo; import digital.laboratory.platform.inspetion.api.entity.SampleInfo; -import digital.laboratory.platform.inspetion.api.entity.TargetObject; import digital.laboratory.platform.inspetion.api.entity.TestRecord; import digital.laboratory.platform.sys.entity.Drug; import digital.laboratory.platform.sys.enums.entrust.EntrustBiologyType; @@ -846,7 +845,8 @@ public class InspectRecordServiceImpl implements InspectRecordService { * @param sampleInfoList 样本信息列表 * @return 物料特性描述(如果列表为空,则返回空字符串) */ - private String buildMaterialCharacterDesc(List sampleInfoList) { + @Override + public String buildMaterialCharacterDesc(List sampleInfoList) { if (CollUtil.isEmpty(sampleInfoList)) { return StrUtil.EMPTY; } @@ -930,6 +930,13 @@ public class InspectRecordServiceImpl implements InspectRecordService { return String.join("、", sampleNumbers); } + /** + * 根据传入的TestRecordSampleData列表生成鉴定意见 + * + * @param dataList 包含检验数据的列表 + * @return 检测意见字符串,以“;”分隔 + */ + @Override public String buildInspectOpinion(List dataList) { if (dataList == null || dataList.isEmpty()) { return ""; diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/ProcessInspectDataServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/ProcessInspectDataServiceImpl.java index 9bbd364..883a9cb 100644 --- a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/ProcessInspectDataServiceImpl.java +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/ProcessInspectDataServiceImpl.java @@ -48,33 +48,34 @@ public class ProcessInspectDataServiceImpl implements ProcessInspectDataService public String calculateHairCaseIonAbundanceRatioWithinError(double ionAbundanceRatioWithinError, double stdIonAbundanceRatio) { // 判断是否在离子丰度比允许的最大偏差范围 - if (stdIonAbundanceRatio > TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_1) { + return setHairCaseWhetherCheckOut( + Math.abs(ionAbundanceRatioWithinError), + getHairCaseIonAbundanceRatioWithinErrorRange(stdIonAbundanceRatio)); + } + + /** + * 根据给定的标准离子丰度比获取生物样本案件离子丰度比相对误差范围内的最大允许相对误差 + * + * @param stdIonAbundanceRatio 标准离子丰度比 + * @return 发案离子丰度比允许的最大误差值 + */ + @Override + public Double getHairCaseIonAbundanceRatioWithinErrorRange(double stdIonAbundanceRatio) { - return setHairCaseWhetherCheckOut( - ionAbundanceRatioWithinError, - TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_1, - TestRecordSampleDataConstant.HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_1); + // 判断是否在离子丰度比允许的最大偏差范围 + if (stdIonAbundanceRatio > TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_1) { + return TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_1; } else if (stdIonAbundanceRatio > TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_2 && stdIonAbundanceRatio <= TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_1) { - return setHairCaseWhetherCheckOut( - ionAbundanceRatioWithinError, - TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_2, - TestRecordSampleDataConstant.HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_2); - + return TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_2; } else if (stdIonAbundanceRatio > TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_3 && stdIonAbundanceRatio <= TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_2) { - return setHairCaseWhetherCheckOut( - ionAbundanceRatioWithinError, - TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_3, - TestRecordSampleDataConstant.HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_3); + return TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_3; } else { - return setHairCaseWhetherCheckOut( - ionAbundanceRatioWithinError, - TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_4, - TestRecordSampleDataConstant.HAIR_CASE_NEGATIVE_MAX_ALLOW_ERROR_4); + return TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_4; } } @@ -166,11 +167,9 @@ public class ProcessInspectDataServiceImpl implements ProcessInspectDataService * * @param ionAbundanceRatioWithinError * @param positive - * @param negative */ - private String setHairCaseWhetherCheckOut(double ionAbundanceRatioWithinError, double positive, double negative) { - if (ionAbundanceRatioWithinError < positive - && ionAbundanceRatioWithinError > negative) { + private String setHairCaseWhetherCheckOut(double ionAbundanceRatioWithinError, double positive) { + if (ionAbundanceRatioWithinError < positive) { return TestRecordSampleDataConstant.IS; } else { return TestRecordSampleDataConstant.NO; diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/PushDataToLabsCareServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/PushDataToLabsCareServiceImpl.java new file mode 100644 index 0000000..6047a25 --- /dev/null +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/PushDataToLabsCareServiceImpl.java @@ -0,0 +1,356 @@ +package digital.laboratory.platform.inspection.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import digital.laboratory.platform.inspection.config.ApiPathProperties; +import digital.laboratory.platform.inspection.constant.TestRecordSampleDataConstant; +import digital.laboratory.platform.inspection.convert.TestRecordSampleDataConverter; +import digital.laboratory.platform.inspection.entity.TestRecordInstrument; +import digital.laboratory.platform.inspection.entity.TestRecordMethod; +import digital.laboratory.platform.inspection.entity.TestRecordReagent; +import digital.laboratory.platform.inspection.entity.TestRecordSampleData; +import digital.laboratory.platform.inspection.mapper.TestRecordSampleDataMapper; +import digital.laboratory.platform.inspection.service.*; +import digital.laboratory.platform.inspection.vo.TestRecordReagentVO; +import digital.laboratory.platform.inspection.vo.TestRecordSampleDataExpandVO; +import digital.laboratory.platform.inspection.vo.TestRecordSampleDataVO; +import digital.laboratory.platform.inspetion.api.entity.EntrustInfo; +import digital.laboratory.platform.inspetion.api.entity.SampleInfo; +import digital.laboratory.platform.inspetion.api.entity.TestRecord; +import digital.laboratory.platform.othersys.utils.HttpsUtils; +import digital.laboratory.platform.sys.entity.Drug; +import digital.laboratory.platform.sys.entity.SysUser; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.*; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClientException; + +import javax.annotation.Resource; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @author ChenJiangBao + * @version 1.0 + * @description: 推送数据到labscare平台接口 + * @date 2025/3/31 9:31 + */ +@Slf4j +@Service +public class PushDataToLabsCareServiceImpl implements PushDataToLabsCareService { + + @Resource + private TestRecordService testRecordService; + + @Resource + private EntrustInfoService entrustInfoService; + + @Resource + private SampleInfoService sampleInfoService; + + @Resource + private TestRecordReagentService testRecordReagentService; + + @Resource + private TestRecordSampleDataMapper testRecordSampleDataMapper; + + @Resource + private TestRecordInstrumentService testRecordInstrumentService; + + @Resource + private TestRecordMethodService testRecordMethodService; + + @Resource + private InspectRecordService inspectRecordService; + + @Resource + private ProcessInspectDataService processInspectDataService; + + @Resource + private CommonFeignService commonFeignService; + + @Resource + private ApiPathProperties apiPathProperties; + + + private final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日"); + + // "#NULL#" 作为空数据的占位符, 对于系统中没有的信息以占位符代替 + public final static String NULL_PLACEHOLDER = "#NULL#"; + + private final static String BIOLOGY_QUALITATIVE_RECORD = "BiologyQualitativeRecord"; + + /** + * 做一个定时推送,对于推送失败的委托进行重新推送, 每天凌晨1点推送 + */ +// @Scheduled(cron = "30 * * * * ?") // 测试 + @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨 2 点执行 + public void timingPushDataToLabsCare() { + // 查询检验鉴定推送失败的委托 + List entrustList = entrustInfoService.list( + Wrappers.lambdaQuery() + .and(wrapper -> wrapper + .eq(EntrustInfo::getPushFlag, "") + .or() + .isNull(EntrustInfo::getPushFlag) + .or() + .like(EntrustInfo::getPushFlag, "false") + ) + ); + if (CollUtil.isEmpty(entrustList)) { + return; + } + Map entrustInfoMap = entrustList.stream().collect(Collectors.toMap(EntrustInfo::getId, Function.identity())); + // 获取所有完成实验的数据 + List testRecordList = testRecordService.list(Wrappers.lambdaQuery() + .eq(TestRecord::getStatus, 5).in(TestRecord::getBusinessId, entrustList.stream() + .map(EntrustInfo::getId).collect(Collectors.toList())) + ); + if (CollUtil.isEmpty(testRecordList)) { + return; + } + + for (TestRecord testRecord : testRecordList) { + EntrustInfo entrustInfo = entrustInfoMap.get(testRecord.getBusinessId()); + String pushFlag = entrustInfo.getPushFlag(); + if (StrUtil.isBlank(pushFlag)) { + pushBiologyQualitativeRecordData(testRecord.getId()); + } else { + List flagList = StrUtil.split(pushFlag, StrUtil.COMMA).stream().filter(str -> str.contains("false")).collect(Collectors.toList()); + for (String flag : flagList) { + if (flag.contains(BIOLOGY_QUALITATIVE_RECORD)) { + pushBiologyQualitativeRecordData(testRecord.getId()); + } else { + + } + } + } + } + } + + /** + * 推送生物检材定性记录 + * @param testId 实验id + */ + @Override + public void pushBiologyQualitativeRecordData(String testId) { + TestRecord testRecord = testRecordService.getById(testId); + if (testRecord == null) { + log.error("实验id为 [{}] 的实验信息查询为空!", testId); + return; + } + // 获取委托信息 + EntrustInfo entrustInfo = entrustInfoService.getById(testRecord.getBusinessId()); + + JSONObject recordJsonPayload = buildBiologyQualitativeRecordJsonPayload(entrustInfo, testRecord); + + String successFlag = BIOLOGY_QUALITATIVE_RECORD + ":true"; + String failureFlag = BIOLOGY_QUALITATIVE_RECORD + ":false"; + try { + ResponseEntity response = exchangeRemoteApi(recordJsonPayload, apiPathProperties.getBiologyQualitativeRecord()); + + if (response.getStatusCode().is2xxSuccessful() && response.getBody().contains("\"status\":200")) { + updatePushFlag(entrustInfo, BIOLOGY_QUALITATIVE_RECORD, successFlag); + log.info("推送生物定性检验记录数据成功, 受理编号: {}, 响应: {}", entrustInfo.getAcceptNo(), response.getBody()); + } else { + updatePushFlag(entrustInfo, BIOLOGY_QUALITATIVE_RECORD, failureFlag); + log.warn("推送生物定性检验记录数据失败, 受理编号: {}, 状态码: {}, 响应: {}", + entrustInfo.getAcceptNo(), response.getStatusCode(), response.getBody()); + } + } catch (RestClientException e) { + log.error("推送生物定性检验记录数据到 LabsCare 失败, 受理编号: {}", entrustInfo.getAcceptNo(), e); + } + } + + private JSONObject buildBiologyQualitativeRecordJsonPayload(EntrustInfo entrustInfo, TestRecord testRecord) { + // 查询封装需要用到的数据 + List sampleInfoList = sampleInfoService + .lambdaQuery() + .in(SampleInfo::getId, testRecord.getSampleTestList()) + .list(); + // 检材转map + Map sampleInfoMap = sampleInfoList.stream().collect(Collectors.toMap(SampleInfo::getAcceptNo, Function.identity())); + // 对受理编号进行分隔 + List splitAcceptNo = StrUtil.split(entrustInfo.getAcceptNo(), "-"); + + // 设置使用的标准物质和试剂 + List references = testRecordReagentService.voListByWrapper(Wrappers.lambdaQuery() + .in(TestRecordReagent::getId, testRecord.getReagentConsumablesList()) + .eq(TestRecordReagent::getCategory, "标准物质")); + // 本次实验使用的标准品 + String stdStr = references.stream().map(TestRecordReagentVO::getReagentConsumableName).collect(Collectors.joining("、")); + + // 获取标准物质对应的毒品成分 + Map drugMap = references.stream().map(TestRecordReagentVO::getDrug).collect(Collectors.toMap(Drug::getEnglishName, Function.identity())); + + // 获取检测人用户信息 + SysUser testUser = commonFeignService.remoteGetUserById(testRecord.getTestUserId()); + + // 检测数据信息 + Map> testDataGroupBySampleNO = testRecordSampleDataMapper + .queryTestRecordSampleDataVOList(Wrappers.lambdaQuery() + .eq(TestRecordSampleData::getTestId, testRecord.getId()) + .eq(TestRecordSampleData::getSampleType, TestRecordSampleDataConstant.SAMPLE_TYPE_ANALYTE) + ) // 数据库查询, 这个是非标准物质的检测数据 + .stream().collect(Collectors.groupingBy(TestRecordSampleDataVO::getSampleNo)); // 根据查询出来的结果进行分组 + + Map stdTestDataMap = testRecordSampleDataMapper + .queryTestRecordSampleDataVOList(Wrappers.lambdaQuery() + .eq(TestRecordSampleData::getTestId, testRecord.getId()) + .eq(TestRecordSampleData::getSampleType, TestRecordSampleDataConstant.SAMPLE_TYPE_STD) + ) // 数据库查询, 这个是非标准物质的检测数据 + .stream().collect(Collectors.toMap(TestRecordSampleDataVO::getCompoundName, Function.identity())); // 根据查询出来的结果进行分组 + + // 查询使用的仪器 + List deviceIdList = testRecord.getDeviceIdList(); + List instruments = CollectionUtils.isEmpty(deviceIdList) + ? Collections.emptyList() + : testRecordInstrumentService.list(Wrappers.lambdaQuery() + .in(TestRecordInstrument::getId, deviceIdList)); + String useInstrumentNameStr = CollectionUtils.isEmpty(instruments) + ? NULL_PLACEHOLDER + : instruments.stream() + .map(TestRecordInstrument::getInstrumentName) + .collect(Collectors.joining(",")); + + // 使用的方法 + List testMethodList = testRecord.getTestMethodList(); + List testRecordMethodList = CollectionUtils.isEmpty(testMethodList) + ? Collections.emptyList() + : testRecordMethodService.list(Wrappers.lambdaQuery() + .in(TestRecordMethod::getId, testMethodList)); + String useMethodNameStr = CollectionUtils.isEmpty(instruments) + ? NULL_PLACEHOLDER + : testRecordMethodList.stream() + .map(TestRecordMethod::getMethodName) + .collect(Collectors.joining(",")); + + // 开始封装数据参数 + JSONObject jsonObject = new JSONObject(); + jsonObject.set("jcxz", inspectRecordService.buildMaterialCharacterDesc(sampleInfoList)); // 检材性状描述 + jsonObject.set("jdwsh", String.format("[%s]%s号", splitAcceptNo.get(0), splitAcceptNo.get(1))); // 鉴定文书号 + jsonObject.set("jysj", testRecord.getTestStartDate().format(formatter)); // 检验时间 + jsonObject.set("jyy1qm", testUser.getName()); // 检测人1 + jsonObject.set( + "jyyq", + String.format("对所送检材中是否含有 %s 成分进行定性检测", stdStr) + ); // 检验要求,根据模板上的值来生成 + jsonObject.set("sjr1", entrustInfo.getDeliver1Name()); // 送检人1 + jsonObject.set("sjr2", entrustInfo.getDeliver2Name()); // 送检人2 + jsonObject.set("slrq", entrustInfo.getAcceptDate().format(formatter)); // 受理日期 + jsonObject.set("sprqm", testUser.getName()); // 检测人2 + jsonObject.set("swmbw", stdStr); // 生物检测目标物 + jsonObject.set("tpfj", NULL_PLACEHOLDER); // 图谱 + jsonObject.set("wtdw", entrustInfo.getEntrustDepartment()); + + // 生物检材定性记录样品信息 + List sampleJsonList = new ArrayList<>(); + testDataGroupBySampleNO.forEach((sampleNo, testDataList) -> { + JSONObject sampleJson = new JSONObject(); + sampleJson.set("caseName", sampleNo); // 样品编号 + + // 该样品编号对应的检测数据信息 + List gauging = testDataList.stream().map(data -> { + JSONObject testDataJson = new JSONObject(); + testDataJson.set("blsjxdwc", data.getRtTimeError()); // 保留时间相对误差(%) + TestRecordSampleDataVO stdData = stdTestDataMap.get(data.getCompoundName()); + testDataJson.set("bzwzblsj", stdData.getTargetRtTime()); // 标准物质保留时间(min) + testDataJson.set("bzwzfdb", stdData.getIonAbundanceRatio()); // 标准物质离子对相对丰度比 + testDataJson.set("bzwzwb", stdData.getCompoundName()); // 标准物质名称 + testDataJson.set("dcypfdb", data.getIonAbundanceRatio()); // 待测样品离子对相对丰度比 + testDataJson.set("dxlzd", data.getExpandList().stream().map(TestRecordSampleDataExpandVO::getQualitativeIonPair).collect(Collectors.joining(","))); // 定性离子对 + testDataJson.set("dxyq", useInstrumentNameStr); // 使用仪器 + testDataJson.set("fdbwc", data.getIonAbundanceRatioError()); // 丰度比相对偏差 + testDataJson.set("ffStr", useMethodNameStr); // 所用的方法 + testDataJson.set("gradientA", NULL_PLACEHOLDER); // 梯度洗脱参考条件-A(%) + testDataJson.set("gradientB", NULL_PLACEHOLDER); // 梯度洗脱参考条件-B(%) + testDataJson.set("gradientTime", NULL_PLACEHOLDER); // 梯度洗脱参考条件-时间(min) + testDataJson.set("jcxz", sampleInfoMap.get(data.getSampleNo()).getForm()); // 检材性状描述 + testDataJson.set("jdwsh", String.format("[%s]%s号", splitAcceptNo.get(0), splitAcceptNo.get(1))); // 鉴定文书号 + testDataJson.set("jdyj", inspectRecordService.buildInspectOpinion(Collections.singletonList(TestRecordSampleDataConverter.voToEntity(data)))); + testDataJson.set("jgpd", data.getWhetherCheckOut()); // 结果判定 + testDataJson.set("jysj", testRecord.getTestStartDate().format(formatter)); // 检验时间 + testDataJson.set("jyyq", String.format("对所送检材中是否含有 %s 成分进行定性检测", stdData.getCompoundCnName())); // 检验要求 + testDataJson.set("mbwblsj", data.getTargetRtTime()); // 目标物保留时间(min) + testDataJson.set("projectName", "定性检测"); // 化合物名称, 对方公司并未标明该字段信息 + // 获取对应的化合物信息 + Drug drug = drugMap.get(data.getCompoundName()); + testDataJson.set("pzdy", StrUtil.join(",", drug.getMainCollisionEnergy(), drug.getMinorCollisionEnergy())); // 碰撞电压 + testDataJson.set("rjwb", NULL_PLACEHOLDER); // 溶剂 + testDataJson.set("sjr1", entrustInfo.getDeliver1Name()); // 送检人1 + testDataJson.set("sjr2", entrustInfo.getDeliver2Name()); // 送检人2 + testDataJson.set("slrq", entrustInfo.getAcceptDate().format(formatter)); // 受理日期 + testDataJson.set("swbzgzyzb", NULL_PLACEHOLDER); // 标准工作溶液制备 + testDataJson.set("swdcypzb", NULL_PLACEHOLDER); // 待测样品制备 + testDataJson.set("swmbw", drug.getName()); // 目标物 + testDataJson.set("swsj", NULL_PLACEHOLDER); // 上机 + testDataJson.set("swyxtj", NULL_PLACEHOLDER); // 液相条件 + testDataJson.set("swzptj", NULL_PLACEHOLDER); // 质谱条件 + testDataJson.set("wjcjgpd", "±" + processInspectDataService.getHairCaseIonAbundanceRatioWithinErrorRange(stdData.getIonAbundanceRatio().doubleValue())); //相对离子丰度比的最大允许相对误差(%) + testDataJson.set("wtdw", entrustInfo.getEntrustDepartment()); + testDataJson.set("wzdy", StrUtil.join(",", drug.getMainDeclusteringPotential(), drug.getMinorDeclusteringPotential())); + return testDataJson; + }).collect(Collectors.toList()); + sampleJson.set("gauging", gauging); // 生物检材定性记录检测信息 + sampleJsonList.add(sampleJson); + }); + jsonObject.set("sample", sampleJsonList); + return jsonObject; + } + + + /** + * 通过POST请求与远程API进行交互 + * + * @param jsonObject 包含请求数据的JSONObject对象 + * @param url 远程API的URL + * @return ResponseEntity 包含远程API响应数据的ResponseEntity对象 + */ + private ResponseEntity exchangeRemoteApi(JSONObject jsonObject, String url) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); // 设置为 application/json + HttpEntity requestEntity = new HttpEntity<>(jsonObject, headers); + ResponseEntity response = HttpsUtils + .genRestTemplate() + .exchange( + url, + HttpMethod.POST, + requestEntity, + String.class + ); + return response; + } + + /** + * 更新推送标志 + * + * @param entrust 委托对象 + * @param pushType 推送类型 EntrustLetter 委托书 | ItemConfirmLetter 事项确认书 + * @param newFlag 新的推送标志 + */ + private void updatePushFlag(EntrustInfo entrust, String pushType, String newFlag) { + List flagList = Optional.ofNullable(StrUtil.split(entrust.getPushFlag(), StrUtil.COMMA)) + .orElse(new ArrayList<>()); + + // 判断是否已有 指定的推送类型,如果有就替换,否则添加 + boolean exists = flagList.stream().anyMatch(flag -> flag.contains(pushType)); + if (exists) { + flagList.replaceAll(flag -> flag.contains(pushType) ? newFlag : flag); + } else { + flagList.add(newFlag); + } + // 更新标识, 防止定时任务那里连续推送数据时推送标识更新出错 + entrust.setPushFlag(String.join(",", flagList)); + // 更新数据库 + entrustInfoService.update(Wrappers.lambdaUpdate() + .eq(EntrustInfo::getId, entrust.getId()) + .set(EntrustInfo::getPushFlag, String.join(",", flagList))); + } + +} 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 index 4307a28..1c7c750 100644 --- 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 @@ -1,5 +1,6 @@ package digital.laboratory.platform.inspection.service.impl; +import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.IdWorker; @@ -66,6 +67,17 @@ public class TestRecordReagentServiceImpl extends ServiceImpl voListByWrapper(Wrapper queryWrapper) { + return TestRecordReagentConverter.entityToVOList(super.list(queryWrapper)); + } + @Override public TestRecordReagent addTestRecordReagent(TestRecordReagent testRecordReagent) { if (StringUtils.isBlank(testRecordReagent.getId())) { 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 index 8e1d39b..12b201f 100644 --- 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 @@ -28,6 +28,7 @@ import digital.laboratory.platform.inspection.enums.StdSolutionNum; import digital.laboratory.platform.inspection.enums.TaskTestDataStatus; import digital.laboratory.platform.inspection.event.AuditDataExecutionEvent; import digital.laboratory.platform.inspection.event.FinishTestExecutionEvent; +import digital.laboratory.platform.inspection.event.PushDataToLabsCareEvent; import digital.laboratory.platform.inspection.mapper.SampleInjectorMapper; import digital.laboratory.platform.inspection.mapper.TestRecordSampleDataMapper; import digital.laboratory.platform.inspection.query.AnalysisTestResultPageQuery; @@ -250,20 +251,6 @@ public class TestRecordSampleDataServiceImpl extends ServiceImpl list = baseMapper.queryTestRecordSampleDataVOList(Wrappers.lambdaQuery() .eq(TestRecordSampleData::getTestId, testId) .last("ORDER BY compound_name, 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 list; } @@ -279,19 +266,6 @@ public class TestRecordSampleDataServiceImpl extends ServiceImpl 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 page; } @@ -733,6 +707,7 @@ public class TestRecordSampleDataServiceImpl extends ServiceImpl 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数组 * diff --git a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordSampledataExpandServiceImpl.java b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordSampledataExpandServiceImpl.java index b7bf3be..ada80bf 100644 --- a/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordSampledataExpandServiceImpl.java +++ b/dlp-drugtesting-biz/src/main/java/digital/laboratory/platform/inspection/service/impl/TestRecordSampledataExpandServiceImpl.java @@ -283,6 +283,8 @@ public class TestRecordSampledataExpandServiceImpl extends ServiceImpl(100), // 任务队列 + Executors.defaultThreadFactory(), // 线程工厂 + new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略 + ); + + // 私有化构造方法,防止外部实例化 + private GlobalThreadPool() {} + + // 获取全局线程池实列 + public static ExecutorService getInstance() { + return THREAD_POOL; + } + + // 关闭线程池 + public static void shutdown() { + THREAD_POOL.shutdown(); + } + + // 在应用关闭前执行 + @PreDestroy + public void destroy() { + log.info("Spring 应用关闭,正在关闭线程池..."); + shutdown(); + try { + if (!THREAD_POOL.awaitTermination(60, TimeUnit.SECONDS)) { + THREAD_POOL.shutdownNow(); + } + } catch (InterruptedException e) { + THREAD_POOL.shutdownNow(); + } + } +} diff --git a/dlp-drugtesting-biz/src/main/resources/bootstrap.yml b/dlp-drugtesting-biz/src/main/resources/bootstrap.yml index aa71aa9..a733490 100644 --- a/dlp-drugtesting-biz/src/main/resources/bootstrap.yml +++ b/dlp-drugtesting-biz/src/main/resources/bootstrap.yml @@ -54,3 +54,11 @@ oss: accessKey: dlp secretKey: 87990016 bucket-name: dlpfiles +# 贵阳禁毒情报平台推送数据配置 +gyjd: + labscare: + api: + host: http://lc2203.cdn.labscare.com + entrust-letter: /thirdparty/report-generate/jianDingWeiTuoShuReport/v1 + confirm-letter: /thirdparty/report-generate/jianDingShiXiangQueRenShuReport/v1 + biology-qualitative-record: /thirdparty/report-generate/shenWuJianCaiDingXingJiLuReport/v1 From 74ad1cb56e9f5500472fa5bca9535cf7f8215439 Mon Sep 17 00:00:00 2001 From: chen <2710907404@qq.com> Date: Tue, 1 Apr 2025 10:45:06 +0800 Subject: [PATCH 2/3] =?UTF-8?q?20250401=20=E6=9B=B4=E6=96=B0=201.=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E6=8E=A8=E9=80=81=E7=94=9F=E7=89=A9=E6=A3=80=E6=9D=90?= =?UTF-8?q?=E5=AE=9A=E6=80=A7=E6=A3=80=E9=AA=8C=E8=AE=B0=E5=BD=95=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=88=B0labscare=E5=B9=B3=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/inspection/DlpDrugTestingApplication.java | 1 + .../service/impl/TestRecordSampleDataServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) 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 index 31492dc..d6adc05 100644 --- 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 @@ -13,6 +13,7 @@ import org.springframework.scheduling.annotation.EnableAsync; import java.util.Arrays; +// todo @EnableScheduling // 开启定时任务 @Configuration @EnableDLPSwagger2 @EnableDLPFeignClients 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 index 12b201f..13cad06 100644 --- 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 @@ -707,7 +707,7 @@ public class TestRecordSampleDataServiceImpl extends ServiceImpl Date: Tue, 1 Apr 2025 11:27:11 +0800 Subject: [PATCH 3/3] =?UTF-8?q?20250401=20=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inspection/service/impl/TestRecordSampleDataServiceImpl.java | 1 + 1 file changed, 1 insertion(+) 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 index 13cad06..604f206 100644 --- 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 @@ -705,6 +705,7 @@ public class TestRecordSampleDataServiceImpl extends ServiceImpl