修改送检导入模板
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
* 导出可上传至禁毒大数据平台文件
|
||||
*
|
||||
* @param excelDTO 导出参数
|
||||
* @param response HttpServletResponse对象,用于将生成的excel文件写入响应中
|
||||
* @param response HttpServletResponse对象,用于将生成的excel文件写入响应中
|
||||
*/
|
||||
@Override
|
||||
public void exportForBigDataPlatform(ResultExcelDTO excelDTO, HttpServletResponse response) throws IOException {
|
||||
@@ -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++) {
|
||||
|
||||
Row row = sheet.createRow(i);
|
||||
|
||||
// 第一行:表头
|
||||
if (i == 0) {
|
||||
Row row = sheet.createRow(i);
|
||||
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,63 +415,164 @@ 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) {
|
||||
// 构建检材对象
|
||||
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("重量/体积")));
|
||||
material.setUnit(datum.get("单位"));
|
||||
String formDesc = datum.get("性状描述");
|
||||
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("提取地点"));
|
||||
List<String> errorMessages = new ArrayList<>(); // 用于收集错误信息
|
||||
|
||||
// 检测结果解析
|
||||
String[] drugs = datum.get("筛查目标物").split("、");
|
||||
buildMatchedDrugs(drugLiteMap, material, drugs);
|
||||
// 设置委托类型
|
||||
material.setType(String.valueOf(entrustment.getEntrustmentType()));
|
||||
if (entrustment.getEntrustmentType() == 0) {
|
||||
material.setTypeName("常规毒品");
|
||||
} else {
|
||||
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.setBiologyGender(datum.get("性别"));
|
||||
material.setAnalysisOption(AnalysisOptionEnums.fromDesc(datum.get("检验项目")).getCode());
|
||||
entrustmentIdentificationMaterialService.setMaterialIdentificationNo(material, cj);
|
||||
material.setSample1No(sampleService.getNewSampleNo(material.getImNo(), 1));
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
Map<String, String> datum = data.get(i);
|
||||
int rowNum = i + 1; // 实际行号用于报错提示
|
||||
|
||||
entrustmentIdentificationMaterialList.add(material);
|
||||
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("疑似物种类"));
|
||||
|
||||
// 2. 数值转换校验 (防止 Integer.valueOf 报错)
|
||||
material.setRtSampleQuantity(convertToInt(datum.get("留存样个数"), "留存样个数", rowNum));
|
||||
material.setQuantity(convertToBigDecimal(datum.get("重量/体积"), "重量/体积", rowNum));
|
||||
material.setUnit(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.setDrawPlace(datum.get("提取地点"));
|
||||
|
||||
String screeningObj = datum.getOrDefault("筛查目标物", "");
|
||||
String[] drugs = screeningObj.split("、");
|
||||
buildMatchedDrugs(drugLiteMap, material, drugs);
|
||||
|
||||
material.setType(String.valueOf(entrustment.getEntrustmentType()));
|
||||
if (entrustment.getEntrustmentType() == 0) {
|
||||
material.setTypeName("常规毒品");
|
||||
} else {
|
||||
material.setTypeName("生物样本");
|
||||
material.setBiologyType(EntrustBiologyType.isExist(formDesc).getDesc());
|
||||
}
|
||||
|
||||
material.setOrderNo(orderNo);
|
||||
material.setImEntrustNumber(String.valueOf(orderNo));
|
||||
orderNo++;
|
||||
|
||||
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 + "数值格式错误"); }
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建匹配筛查目标物毒品列表
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user