|
|
|
@ -3,6 +3,7 @@ package digital.laboratory.platform.entrustment.service.impl; |
|
|
|
|
import cn.hutool.core.collection.CollUtil; |
|
|
|
|
import cn.hutool.core.date.LocalDateTimeUtil; |
|
|
|
|
import cn.hutool.core.util.StrUtil; |
|
|
|
|
import cn.hutool.json.JSONObject; |
|
|
|
|
import com.alibaba.fastjson.JSONArray; |
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
|
|
|
@ -32,18 +33,20 @@ import digital.laboratory.platform.entrustment.vo.DetectionRateVO; |
|
|
|
|
import digital.laboratory.platform.entrustment.vo.EntrustMaterialCheckoutResultVO; |
|
|
|
|
import digital.laboratory.platform.entrustment.vo.EntrustmentIdentificationMaterialVO; |
|
|
|
|
import digital.laboratory.platform.entrustment.vo.SuspectDetectionVO; |
|
|
|
|
import digital.laboratory.platform.othersys.utils.HttpsUtils; |
|
|
|
|
import digital.laboratory.platform.sys.entity.Area; |
|
|
|
|
import digital.laboratory.platform.sys.entity.DrugLite; |
|
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
|
import org.apache.poi.ss.usermodel.*; |
|
|
|
|
import org.apache.poi.ss.util.CellRangeAddress; |
|
|
|
|
import org.apache.poi.xssf.usermodel.*; |
|
|
|
|
import org.springframework.beans.BeanUtils; |
|
|
|
|
import org.springframework.http.*; |
|
|
|
|
import org.springframework.stereotype.Service; |
|
|
|
|
import springfox.documentation.spring.web.json.Json; |
|
|
|
|
import org.springframework.web.client.RestClientException; |
|
|
|
|
|
|
|
|
|
import javax.annotation.Resource; |
|
|
|
|
import javax.servlet.http.HttpServletResponse; |
|
|
|
|
import java.io.BufferedOutputStream; |
|
|
|
|
import java.io.ByteArrayInputStream; |
|
|
|
|
import java.io.ByteArrayOutputStream; |
|
|
|
|
import java.io.IOException; |
|
|
|
@ -67,6 +70,7 @@ import java.util.stream.Collectors; |
|
|
|
|
* @createDate 2024-12-30 16:16:25 |
|
|
|
|
*/ |
|
|
|
|
@Service |
|
|
|
|
@Slf4j |
|
|
|
|
public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<EntrustMaterialCheckoutResultMapper, EntrustMaterialCheckoutResult> |
|
|
|
|
implements EntrustMaterialCheckoutResultService { |
|
|
|
|
|
|
|
|
@ -1122,10 +1126,16 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus |
|
|
|
|
.map(r -> buildResultVO(r, materialMap)) |
|
|
|
|
.sorted(Comparator.comparingInt(EntrustMaterialCheckoutResultVO::getOrderNo)) |
|
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean push = pushToDatabase(suspects, resultVOS, entrustment, caseEvent, user); |
|
|
|
|
if (entrustment.getEntrustmentType() == 0) { |
|
|
|
|
push = this.pushQualitativeReportData(entrustment, user); |
|
|
|
|
} |
|
|
|
|
if (push) { |
|
|
|
|
entrustment.setPlatformFlag(true); |
|
|
|
|
entrustmentService.updateById(entrustment); |
|
|
|
|
} |
|
|
|
|
// 数据推送至目标数据库
|
|
|
|
|
return pushToDatabase(suspects, resultVOS, entrustment, caseEvent, user); |
|
|
|
|
return push; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private EntrustMaterialCheckoutResultVO buildResultVO(EntrustMaterialCheckoutResult result, Map<String, EntrustmentIdentificationMaterial> materialMap) { |
|
|
|
@ -1241,12 +1251,239 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
entrustment.setPlatformFlag(true); |
|
|
|
|
entrustmentService.updateById(entrustment); |
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public boolean pushQualitativeReportData(Entrustment entrust, DLPUser dlpUser) { |
|
|
|
|
JSONObject jsonObject = this.buildQualitativeReportJsonPayload(entrust, dlpUser); |
|
|
|
|
log.info("推送定性报告数据, 受理编号: {}, 请求数据: {}", entrust.getAcceptNo(), jsonObject); |
|
|
|
|
try { |
|
|
|
|
ResponseEntity<String> response = exchangeRemoteApi(jsonObject, "http://83.3.9.45/thirdparty/report-generate/dingXingReport/v1"); |
|
|
|
|
if (response.getStatusCode().is2xxSuccessful() && response.getBody().contains("\"status\":200")) { |
|
|
|
|
log.info("推送定性报告数据成功, 受理编号: {}, 响应: {}", entrust.getAcceptNo(), response.getBody()); |
|
|
|
|
return true; |
|
|
|
|
} else { |
|
|
|
|
log.warn("推送定性报告数据失败, 受理编号: {}, 状态码: {}, 响应: {}", |
|
|
|
|
entrust.getAcceptNo(), response.getStatusCode(), response.getBody()); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} catch (RestClientException e) { |
|
|
|
|
log.error("推送定性报告数据到 LabsCare 失败, 受理编号: {}", entrust.getAcceptNo(), e); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 通过POST请求与远程API进行交互 |
|
|
|
|
* |
|
|
|
|
* @param jsonObject 包含请求数据的JSONObject对象 |
|
|
|
|
* @param url 远程API的URL |
|
|
|
|
* @return ResponseEntity<String> 包含远程API响应数据的ResponseEntity对象 |
|
|
|
|
*/ |
|
|
|
|
private ResponseEntity<String> exchangeRemoteApi(JSONObject jsonObject, String url) { |
|
|
|
|
HttpHeaders headers = new HttpHeaders(); |
|
|
|
|
headers.setContentType(MediaType.APPLICATION_JSON); // 设置为 application/json
|
|
|
|
|
HttpEntity<JSONObject> requestEntity = new HttpEntity<>(jsonObject, headers); |
|
|
|
|
ResponseEntity<String> response = HttpsUtils |
|
|
|
|
.genRestTemplate() |
|
|
|
|
.exchange( |
|
|
|
|
url, |
|
|
|
|
HttpMethod.POST, |
|
|
|
|
requestEntity, |
|
|
|
|
String.class |
|
|
|
|
); |
|
|
|
|
return response; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 构建推送定性报告的json数据 |
|
|
|
|
* |
|
|
|
|
* @param entrust 委托信息 |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
private JSONObject buildQualitativeReportJsonPayload(Entrustment entrust, DLPUser dlpUser) { |
|
|
|
|
|
|
|
|
|
List<EntrustmentIdentificationMaterial> materialList = entrustmentIdentificationMaterialService.lambdaQuery() |
|
|
|
|
.eq(EntrustmentIdentificationMaterial::getEntrustmentId, entrust.getId()) |
|
|
|
|
.list(); |
|
|
|
|
|
|
|
|
|
CaseEvent caseEvent = caseEventService.getById(entrust.getCaseId()); |
|
|
|
|
|
|
|
|
|
String[] splitAcceptNo = entrust.getAcceptNo().split("-"); |
|
|
|
|
// 封装推送定性报告数据
|
|
|
|
|
JSONObject jsonObject = new JSONObject(); |
|
|
|
|
jsonObject.set("jcxz", buildMaterialCharacterDesc(materialList)); // 检材性状描述
|
|
|
|
|
jsonObject.set("jiandingwenshuhao", String.format("[%s]%s号", splitAcceptNo[0], splitAcceptNo[1])); // 鉴定文书号
|
|
|
|
|
jsonObject.set("jdyq", entrust.getEntrustRequirement()); // 鉴定要求
|
|
|
|
|
jsonObject.set("jyaq", caseEvent.getCaseBrief()); // 简要案情
|
|
|
|
|
jsonObject.set("jyy1qm", dlpUser.getName()); // 检测人
|
|
|
|
|
jsonObject.set("jyyr2qm", dlpUser.getName()); // 检测人
|
|
|
|
|
jsonObject.set("jyy1zc", "#NULL#"); // 检验人1专业技术资格或职称
|
|
|
|
|
jsonObject.set("jyy2zc", "#NULL#"); // 检验人2专业技术资格或职称
|
|
|
|
|
jsonObject.set("qfrq", "#NULL#"); |
|
|
|
|
jsonObject.set("qrcode", "#NULL#"); // 二维码地址
|
|
|
|
|
jsonObject.set("sjr1List", CollUtil.newArrayList(entrust.getDeliverer1Name(), entrust.getDeliverer2Name())); // 送检人
|
|
|
|
|
jsonObject.set("slrq", entrust.getAcceptTime().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"))); |
|
|
|
|
jsonObject.set("wtdw", entrust.getClientOrgName()); // 委托单位
|
|
|
|
|
jsonObject.set("zrqm", "#NULL#"); // 授权签字人
|
|
|
|
|
jsonObject.set("zrzc", "#NULL#"); // 授权签字人专业技术资格或职称
|
|
|
|
|
|
|
|
|
|
// 定性检验报告样品 检测信息
|
|
|
|
|
JSONObject inspectDataInfo = new JSONObject(); |
|
|
|
|
inspectDataInfo.set("dxff", "《疑似毒品中 2-氟苯丙胺等 388种麻醉药品和精神药品的定性检验 气相色谱-质谱法》(JD/Y JY01.07-2024)"); |
|
|
|
|
inspectDataInfo.set("jysj", entrust.getAcceptTime().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"))); |
|
|
|
|
inspectDataInfo.set("outStr", this.buildResultStr(entrust.getId())); |
|
|
|
|
cn.hutool.json.JSONArray gauging = new cn.hutool.json.JSONArray(); |
|
|
|
|
gauging.add(inspectDataInfo); |
|
|
|
|
// 定性检验报告样品信息
|
|
|
|
|
JSONObject sampleJson = new JSONObject(); |
|
|
|
|
sampleJson.put("gauging", gauging); |
|
|
|
|
cn.hutool.json.JSONArray sampleArrayJSON = new cn.hutool.json.JSONArray(); |
|
|
|
|
sampleArrayJSON.add(sampleJson); |
|
|
|
|
jsonObject.set("sample", sampleArrayJSON); |
|
|
|
|
return jsonObject; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public String buildResultStr(String entrustId) { |
|
|
|
|
List<EntrustMaterialCheckoutResult> list = this.lambdaQuery() |
|
|
|
|
.eq(EntrustMaterialCheckoutResult::getEntrustId, entrustId) |
|
|
|
|
.isNotNull(EntrustMaterialCheckoutResult::getQualitativeResult) |
|
|
|
|
.list(); |
|
|
|
|
|
|
|
|
|
Set<String> idList = list.stream() |
|
|
|
|
.map(EntrustMaterialCheckoutResult::getId) |
|
|
|
|
.collect(Collectors.toSet()); |
|
|
|
|
|
|
|
|
|
Map<String, EntrustMaterialCheckoutResult> resultMap = list.stream() |
|
|
|
|
.collect(Collectors.toMap(EntrustMaterialCheckoutResult::getId, Function.identity())); |
|
|
|
|
|
|
|
|
|
List<EntrustmentIdentificationMaterial> materialList = entrustmentIdentificationMaterialService.lambdaQuery() |
|
|
|
|
.in(EntrustmentIdentificationMaterial::getId, idList) |
|
|
|
|
.list(); |
|
|
|
|
|
|
|
|
|
materialList.sort(Comparator.comparing(sample -> extractTailNumber(sample.getAcceptNo()))); |
|
|
|
|
|
|
|
|
|
// drugName -> List<orderNo>
|
|
|
|
|
Map<String, List<Integer>> drugToOrderNos = new HashMap<>(); |
|
|
|
|
|
|
|
|
|
for (EntrustmentIdentificationMaterial material : materialList) { |
|
|
|
|
List<DrugLite> drugLites = DrugLiteConvert.getDrugLites(resultMap.get(material.getId()).getQualitativeResult()); |
|
|
|
|
Integer orderNo = material.getOrderNo(); |
|
|
|
|
for (DrugLite drug : drugLites) { |
|
|
|
|
drugToOrderNos |
|
|
|
|
.computeIfAbsent(drug.getName(), k -> new ArrayList<>()) |
|
|
|
|
.add(orderNo); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 按每个药品对应的最小 orderNo 进行排序,确保先输出最小号的药品
|
|
|
|
|
List<Map.Entry<String, List<Integer>>> entries = new ArrayList<>(drugToOrderNos.entrySet()); |
|
|
|
|
entries.sort(Comparator.comparingInt(e -> Collections.min(e.getValue()))); |
|
|
|
|
|
|
|
|
|
StringBuilder sb = new StringBuilder(); |
|
|
|
|
for (Map.Entry<String, List<Integer>> entry : entries) { |
|
|
|
|
String drugName = entry.getKey(); |
|
|
|
|
List<Integer> orderNos = entry.getValue(); |
|
|
|
|
Collections.sort(orderNos); |
|
|
|
|
|
|
|
|
|
sb.append("从"); |
|
|
|
|
|
|
|
|
|
if (isConsecutive(orderNos) && orderNos.size() >= 2) { |
|
|
|
|
sb.append(orderNos.get(0)).append("号和").append(orderNos.get(orderNos.size() - 1)).append("号检材中"); |
|
|
|
|
} else { |
|
|
|
|
sb.append(orderNos.stream() |
|
|
|
|
.map(no -> no + "号检材") |
|
|
|
|
.collect(Collectors.joining("、"))) |
|
|
|
|
.append("中"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sb.append("检出").append(drugName).append(","); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 去掉最后一个逗号,添加句号
|
|
|
|
|
if (sb.length() > 0 && sb.charAt(sb.length() - 1) == ',') { |
|
|
|
|
sb.setCharAt(sb.length() - 1, '。'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return sb.toString(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private boolean isConsecutive(List<Integer> list) { |
|
|
|
|
for (int i = 1; i < list.size(); i++) { |
|
|
|
|
if (list.get(i) - list.get(i - 1) != 1) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public String buildMaterialCharacterDesc(List<EntrustmentIdentificationMaterial> materialList) { |
|
|
|
|
if (CollUtil.isEmpty(materialList)) { |
|
|
|
|
return StrUtil.EMPTY; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 按尾号排序(提取编号尾号进行比较)
|
|
|
|
|
materialList.sort(Comparator.comparing(sample -> extractTailNumber(sample.getAcceptNo()))); |
|
|
|
|
|
|
|
|
|
List<String> descriptions = new ArrayList<>(); |
|
|
|
|
int start = -1, prev = -1; |
|
|
|
|
String prevForm = null; |
|
|
|
|
List<String> mergedOrderNos = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
// 遍历排序后的检材编号,合并相邻且性状相同的编号
|
|
|
|
|
for (EntrustmentIdentificationMaterial material : materialList) { |
|
|
|
|
int current = extractTailNumber(material.getAcceptNo()); // 提取尾号
|
|
|
|
|
String form = material.getForm(); |
|
|
|
|
|
|
|
|
|
if (start == -1) { // 初始化
|
|
|
|
|
start = prev = current; |
|
|
|
|
prevForm = form; |
|
|
|
|
} else if (current == prev + 1 && form.equals(prevForm)) { |
|
|
|
|
// 只有连续尾号 + 相同性状才能合并
|
|
|
|
|
prev = current; |
|
|
|
|
} else { |
|
|
|
|
// 遇到新性状或不连续尾号,存储前一段描述
|
|
|
|
|
mergedOrderNos.add(formatRange(start, prev) + "检材为" + prevForm); |
|
|
|
|
start = prev = current; |
|
|
|
|
prevForm = form; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// 处理最后一组数据
|
|
|
|
|
mergedOrderNos.add(formatRange(start, prev) + "检材为" + prevForm); |
|
|
|
|
|
|
|
|
|
// **如果只有一个检材,省略编号**
|
|
|
|
|
if (mergedOrderNos.size() == 1 && materialList.size() == 1) { |
|
|
|
|
return "检材为" + prevForm + "。"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return String.join(";", mergedOrderNos) + "。"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 生成编号范围的字符串 |
|
|
|
|
* |
|
|
|
|
* @param start 起始编号 |
|
|
|
|
* @param end 结束编号 |
|
|
|
|
* @return 生成的范围字符串,例如 "1号至3号" 或 "5号" |
|
|
|
|
*/ |
|
|
|
|
private String formatRange(int start, int end) { |
|
|
|
|
return (start == end) ? start + "号" : start + "号至" + end + "号"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 提取检材编号的尾号(即最后一个 `-` 之后的数值) |
|
|
|
|
* |
|
|
|
|
* @param orderNo 检材编号(格式:2025-89-13) |
|
|
|
|
* @return 尾号(示例:返回 13) |
|
|
|
|
*/ |
|
|
|
|
private int extractTailNumber(String orderNo) { |
|
|
|
|
String[] parts = orderNo.split("-"); |
|
|
|
|
return (parts.length > 0) ? Integer.parseInt(parts[parts.length - 1]) : 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 推送嫌疑人毒检结果任务 |
|
|
|
|
* |
|
|
|
@ -1827,7 +2064,6 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|