修改送检导入模板

master
杨海航 2 weeks ago
parent 9e0eb79988
commit 59fc40af97
  1. 6
      src/main/java/digital/laboratory/platform/entrustment/dto/CheckoutResultExcelDTO.java
  2. 62
      src/main/java/digital/laboratory/platform/entrustment/service/impl/EntrustMaterialCheckoutResultServiceImpl.java
  3. 153
      src/main/java/digital/laboratory/platform/entrustment/service/impl/ExcelOperationServiceImpl.java

@ -4,6 +4,9 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@ApiModel(value = "CheckoutResultExcelDTO", description = "存储要导出的检出结果excel数据DTO对象")
public class CheckoutResultExcelDTO {
@ -14,6 +17,9 @@ public class CheckoutResultExcelDTO {
@ApiModelProperty("送检日期")
private String deliverTime;
@ApiModelProperty("受理时间")
private LocalDateTime acceptTime;
@ApiModelProperty("送检单位")
private String clientOrgName;

@ -281,40 +281,52 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
private void buildExcel(HttpServletResponse response, List<CheckoutResultExcelDTO> checkoutResultExcelDTOS) throws IOException {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
// 表头导入
// 表头
List<String> head = buildExcelHead();
// 算上表头的行数
int rowCount = checkoutResultExcelDTOS.size() + 1;
for (int i = 0; i < rowCount; i++) {
if (i == 0) {
Row row = sheet.createRow(i);
// 第一行:表头
if (i == 0) {
for (int j = 0; j < head.size(); j++) {
row.createCell(j).setCellValue(head.get(j));
}
} else {
// 开始写入具体数据内容
Row row = sheet.createRow(i);
CheckoutResultExcelDTO excelDTO = checkoutResultExcelDTOS.get(i - 1);
row.createCell(0).setCellValue(excelDTO.getOrder());
row.createCell(1).setCellValue(excelDTO.getDeliverTime());
row.createCell(2).setCellValue(excelDTO.getClientOrgName());
row.createCell(3).setCellValue(excelDTO.getProvinceCollectPlace());
row.createCell(4).setCellValue(excelDTO.getCityCollectPlace());
row.createCell(5).setCellValue(excelDTO.getAcceptNo());
row.createCell(6).setCellValue(excelDTO.getOrderNo());
row.createCell(7).setCellValue(excelDTO.getTypeName());
row.createCell(8).setCellValue(excelDTO.getColor());
row.createCell(9).setCellValue(excelDTO.getFormName());
row.createCell(10).setCellValue(excelDTO.getQualitativeResult());
row.createCell(11).setCellValue(excelDTO.getQuantitativeResult());
row.createCell(12).setCellValue(excelDTO.getOtherResult());
row.createCell(13).setCellValue(excelDTO.getRemark());
continue;
}
// 数据填充
CheckoutResultExcelDTO excelDTO = checkoutResultExcelDTOS.get(i - 1);
row.createCell(0).setCellValue(getValue(excelDTO.getOrder()));
row.createCell(1).setCellValue(getValue(excelDTO.getDeliverTime())); // 已经是 String
row.createCell(2).setCellValue(getValue(excelDTO.getClientOrgName()));
row.createCell(3).setCellValue(getValue(excelDTO.getProvinceCollectPlace()));
row.createCell(4).setCellValue(getValue(excelDTO.getCityCollectPlace()));
row.createCell(5).setCellValue(getValue(excelDTO.getAcceptNo()));
row.createCell(6).setCellValue(getValue(excelDTO.getOrderNo()));
row.createCell(7).setCellValue(getValue(excelDTO.getTypeName()));
row.createCell(8).setCellValue(getValue(excelDTO.getColor()));
row.createCell(9).setCellValue(getValue(excelDTO.getFormName()));
row.createCell(10).setCellValue(getValue(excelDTO.getQualitativeResult()));
row.createCell(11).setCellValue(getValue(excelDTO.getQuantitativeResult()));
row.createCell(12).setCellValue(getValue(excelDTO.getOtherResult()));
row.createCell(13).setCellValue(getValue(excelDTO.getRemark()));
}
// 输出到流
workbook.write(response.getOutputStream());
}
private String getValue(Object obj) {
return obj == null || obj.toString().isEmpty() ? "无" : obj.toString();
}
private List<String> buildExcelHead() {
List<String> headList = new ArrayList<>();
headList.add("序号");
@ -366,6 +378,7 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
excelDTO.setAcceptNo(entrust.getAcceptNo());
excelDTO.setOrderNo(material.getOrderNo());
excelDTO.setTypeName(typeName);
excelDTO.setAcceptTime(material.getAcceptTime());
String formName = material.getFormName();
// 从检材性状描述中提取,因为贵阳没有填颜色, 匹配有色字的信息,例如“白色粉末”中的“白色”,否则取检材形态描述字段的值。
excelDTO.setColor(StrUtil.isBlank(material.getColor()) ? formName.substring(0, formName.indexOf("色") + 1) : material.getColor());
@ -384,6 +397,11 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
}
}
}
checkoutResultExcelDTOList.sort(Comparator.comparing(CheckoutResultExcelDTO::getAcceptTime));
int order = 1;
for (CheckoutResultExcelDTO checkoutResultExcelDTO : checkoutResultExcelDTOList) {
checkoutResultExcelDTO.setOrder(order++);
}
return checkoutResultExcelDTOList;
}
@ -664,6 +682,7 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
/**
* 根据原始鉴定结果获取所有可能的鉴定结果包括委托首次鉴定补充鉴定和重新鉴定的情形
*
* @param oldResults
* @return
*/
@ -845,6 +864,7 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
/**
* 导出Excel
*
* @param response
* @param excelDTO
* @return

@ -35,14 +35,12 @@ import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -417,33 +415,54 @@ public class ExcelOperationServiceImpl implements ExcelOperationService {
* @param cj 案件信息对象
* @return
*/
private List<EntrustmentIdentificationMaterial> processExcelDataToMaterialEntity(List<Map<String, String>> data, Entrustment entrustment, Map<String, DrugLite> drugLiteMap, int orderNo, CaseEvent cj) {
private List<EntrustmentIdentificationMaterial> processExcelDataToMaterialEntity(
List<Map<String, String>> data,
Entrustment entrustment,
Map<String, DrugLite> drugLiteMap,
int orderNo,
CaseEvent cj) {
List<EntrustmentIdentificationMaterial> entrustmentIdentificationMaterialList = new ArrayList<>();
for (Map<String, String> datum : data) {
// 构建检材对象
List<String> errorMessages = new ArrayList<>(); // 用于收集错误信息
for (int i = 0; i < data.size(); i++) {
Map<String, String> datum = data.get(i);
int rowNum = i + 1; // 实际行号用于报错提示
try {
// 1. 基础数据校验
validateField(datum, "疑似物种类", rowNum);
validateField(datum, "提取时间", rowNum);
EntrustmentIdentificationMaterial material = new EntrustmentIdentificationMaterial();
material.setId(IdWorker.get32UUID().toUpperCase());
material.setEntrustmentId(entrustment.getId());
material.setCaseId(entrustment.getCaseId());
material.setName(datum.get("疑似物种类"));
material.setRtSampleQuantity(Integer.valueOf(datum.get("留存样个数")));
material.setQuantity(new BigDecimal(datum.get("重量/体积")));
// 2. 数值转换校验 (防止 Integer.valueOf 报错)
material.setRtSampleQuantity(convertToInt(datum.get("留存样个数"), "留存样个数", rowNum));
material.setQuantity(convertToBigDecimal(datum.get("重量/体积"), "重量/体积", rowNum));
material.setUnit(datum.get("单位"));
String formDesc = datum.get("性状描述");
// 3. 增强日期解析 (支持 yyyy-MM-dd 和 EEE MMM dd ... 格式)
String drawTimeStr = datum.get("提取时间");
material.setDrawTime(flexibleDateParse(drawTimeStr, rowNum));
// 4. 原有业务逻辑
String formDesc = datum.getOrDefault("性状描述", "");
material.setForm(formDesc);
material.setFormName(formDesc);
// 提取颜色
if (StrUtil.isNotBlank(formDesc) && formDesc.contains("色")) {
// 截取“色”之前的部分(包含“色”)
material.setColor(formDesc.substring(0, formDesc.indexOf("色") + 1));
}
material.setDrawTime(LocalDate.parse(datum.get("提取时间"), DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay());
material.setDrawPlace(datum.get("提取地点"));
// 检测结果解析
String[] drugs = datum.get("筛查目标物").split("、");
String screeningObj = datum.getOrDefault("筛查目标物", "");
String[] drugs = screeningObj.split("、");
buildMatchedDrugs(drugLiteMap, material, drugs);
// 设置委托类型
material.setType(String.valueOf(entrustment.getEntrustmentType()));
if (entrustment.getEntrustmentType() == 0) {
material.setTypeName("常规毒品");
@ -451,29 +470,109 @@ public class ExcelOperationServiceImpl implements ExcelOperationService {
material.setTypeName("生物样本");
material.setBiologyType(EntrustBiologyType.isExist(formDesc).getDesc());
}
material.setOrderNo(orderNo);
material.setImEntrustNumber(String.valueOf(orderNo));
orderNo++;
String packageInfo = datum.get("包装信息");
if (packageInfo.equals("完整")) {
material.setPackComplete(true);
} else {
material.setPackComplete(false);
}
String age = datum.get("年龄");
if (StrUtil.isNotBlank(age)) {
material.setMaterialAge(Integer.valueOf(age));
material.setPackComplete("完整".equals(datum.get("包装信息")));
if (StrUtil.isNotBlank(datum.get("年龄"))) {
material.setMaterialAge(convertToInt(datum.get("年龄"), "年龄", rowNum));
}
material.setBiologyGender(datum.get("性别"));
material.setAnalysisOption(AnalysisOptionEnums.fromDesc(datum.get("检验项目")).getCode());
entrustmentIdentificationMaterialService.setMaterialIdentificationNo(material, cj);
material.setSample1No(sampleService.getNewSampleNo(material.getImNo(), 1));
entrustmentIdentificationMaterialList.add(material);
} catch (Exception e) {
errorMessages.add("第" + rowNum + "行处理失败: " + e.getMessage());
}
}
// 5. 如果有错误,抛出异常或返回给前端
if (!errorMessages.isEmpty()) {
throw new RuntimeException("Excel导入校验失败:\n" + String.join("\n", errorMessages));
}
return entrustmentIdentificationMaterialList;
}
/**
* 极度灵活的日期解析器支持 yyyy-MM-dd, yyyy/MM/dd, UTC格式, 以及时间戳
*/
private LocalDateTime flexibleDateParse(String dateStr, int rowNum) {
if (StrUtil.isBlank(dateStr)) return null;
dateStr = dateStr.trim();
// 1. 尝试解析常见的数字分割格式 (2025-10-10, 2025/10/10, 2025.10.10)
String standardizedDate = dateStr.replace("/", "-").replace(".", "-");
if (standardizedDate.matches("\\d{4}-\\d{1,2}-\\d{1,2}.*")) {
try {
// 取前10位进行日期转换
String datePart = standardizedDate.split(" ")[0];
// 考虑月日可能是一位数的情况,这里用 DateTimeFormatter 更稳妥
DateTimeFormatter df = new DateTimeFormatterBuilder()
.appendPattern("yyyy-")
.appendValue(ChronoField.MONTH_OF_YEAR)
.appendLiteral("-")
.appendValue(ChronoField.DAY_OF_MONTH)
.toFormatter();
return LocalDate.parse(datePart, df).atStartOfDay();
} catch (Exception e) {
// 如果正则匹配但解析失败,继续往下走
}
}
// 2. 尝试解析 UTC 格式 (Fri Oct 10 00:00:00 UTC 2025)
if (dateStr.contains("UTC") || dateStr.matches("^[a-zA-Z].*")) {
try {
DateTimeFormatter utcFormatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
return ZonedDateTime.parse(dateStr, utcFormatter).toLocalDateTime();
} catch (Exception e) {
// 继续尝试
}
}
// 3. 尝试解析纯数字时间戳 (部分 Excel 导入框架会把日期转为 Excel 序列天数或 Unix 时间戳)
if (dateStr.matches("^\\d+$")) {
try {
long val = Long.parseLong(dateStr);
// 如果数字很小,可能是 Excel 的天数格式 (比如 45678)
if (val < 100000) {
return LocalDateTime.of(1899, 12, 30, 0, 0).plusDays(val);
}
// 否则视为秒级或毫秒级时间戳
return LocalDateTime.ofInstant(Instant.ofEpochMilli(val > 10000000000L ? val : val * 1000), ZoneId.systemDefault());
} catch (Exception e) {
// 继续尝试
}
}
// 如果所有尝试都失败了,给用户清晰的反馈
throw new IllegalArgumentException("日期格式[" + dateStr + "]无法识别。支持格式: 2025-10-10, 2025/10/10 或标准系统格式");
}
// 辅助转换方法...
private void validateField(Map<String, String> map, String key, int row) {
if (StrUtil.isBlank(map.get(key))) throw new IllegalArgumentException(key + "不能为空");
}
private Integer convertToInt(String val, String fieldName, int row) {
try { return StrUtil.isBlank(val) ? 0 : Integer.valueOf(val); }
catch (Exception e) { throw new IllegalArgumentException(fieldName + "数字格式错误"); }
}
private BigDecimal convertToBigDecimal(String val, String fieldName, int row) {
try { return StrUtil.isBlank(val) ? BigDecimal.ZERO : new BigDecimal(val); }
catch (Exception e) { throw new IllegalArgumentException(fieldName + "数值格式错误"); }
}
/**
* 构建匹配筛查目标物毒品列表
*

Loading…
Cancel
Save