更新了导出毒品计算Excel会因为重名报错的Bug
This commit is contained in:
+156
-48
@@ -72,6 +72,11 @@ import java.util.stream.Collectors;
|
||||
public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<EntrustMaterialCheckoutResultMapper, EntrustMaterialCheckoutResult>
|
||||
implements EntrustMaterialCheckoutResultService {
|
||||
|
||||
/**
|
||||
* Excel 工作表名最大长度(OOXML 规范:1~31 字符)
|
||||
*/
|
||||
private static final int MAX_SHEET_NAME_LENGTH = 31;
|
||||
|
||||
@Resource
|
||||
private EntrustmentService entrustmentService;
|
||||
|
||||
@@ -688,6 +693,9 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
*/
|
||||
private List<String> getOriginalIdentificationList(List<String> oldResults) {
|
||||
List<String> allResults = new ArrayList<>();
|
||||
if (CollUtil.isEmpty(oldResults)) {
|
||||
return allResults;
|
||||
}
|
||||
for (String oldResult : oldResults) {
|
||||
if (StringUtils.isNotBlank(oldResult)) {
|
||||
if ("委托".equals(oldResult)) {
|
||||
@@ -751,39 +759,34 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 4. 提取所有涉及的毒品名称(去重)
|
||||
Set<String> drugNames = new HashSet<>();
|
||||
// 4. 提取所有涉及的化合物名称,并按"归一化名称"归并分组
|
||||
// 字典里用 "氢可酮*" 标注管制药品,业务上与 "氢可酮" 是同一化合物,这里合并为一组
|
||||
// key = 归一化名称(统计表展示、工作表名都用它),value = 库里的各种原始写法(查询要用原始写法)
|
||||
Map<String, Set<String>> groupedDrugNames = new LinkedHashMap<>();
|
||||
for (EntrustMaterialCheckoutResult result : newResultList) {
|
||||
List<DrugLite> drugLites = DrugLiteConvert.getDrugLites(result.getQualitativeResult());
|
||||
for (DrugLite drugLite : drugLites) {
|
||||
drugNames.add(drugLite.getName());
|
||||
}
|
||||
if (isMetabolite && StringUtils.isNotBlank(result.getMetaboliteResult())) {
|
||||
List<DrugLite> drugLites1 = DrugLiteConvert.getDrugLites(result.getMetaboliteResult());
|
||||
for (DrugLite drugLite : drugLites1) {
|
||||
if (!drugNames.contains(drugLite.getName())) {
|
||||
drugNames.add(drugLite.getName());
|
||||
}
|
||||
}
|
||||
collectDrugNames(groupedDrugNames, result.getQualitativeResult());
|
||||
if (isMetabolite) {
|
||||
collectDrugNames(groupedDrugNames, result.getMetaboliteResult());
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 处理不同毒品名称的数据
|
||||
Map<String, List<EntrustmentIdentificationMaterialVO>> resultMap = new HashMap<>();
|
||||
|
||||
for (String drugName : drugNames) {
|
||||
// 5.1 查询所有含有该毒品的检验结果
|
||||
for (Map.Entry<String, Set<String>> drugGroup : groupedDrugNames.entrySet()) {
|
||||
String drugName = drugGroup.getKey();
|
||||
Set<String> rawDrugNames = drugGroup.getValue();
|
||||
|
||||
// 5.1 查询所有含有该毒品的检验结果(组内每种原始写法各查一次,再按检材 id 去重合并)
|
||||
Map<String, EntrustMaterialCheckoutResult> checkoutResultMap = new LinkedHashMap<>();
|
||||
for (String rawDrugName : rawDrugNames) {
|
||||
List<EntrustMaterialCheckoutResult> resultList = this.list(Wrappers.<EntrustMaterialCheckoutResult>lambdaQuery()
|
||||
.and(queryWrapper -> queryWrapper
|
||||
.like(EntrustMaterialCheckoutResult::getMetaboliteResult, drugName)
|
||||
.like(EntrustMaterialCheckoutResult::getMetaboliteResult, rawDrugName)
|
||||
.or()
|
||||
.like(EntrustMaterialCheckoutResult::getQualitativeResult, drugName))
|
||||
.like(EntrustMaterialCheckoutResult::getQualitativeResult, rawDrugName))
|
||||
.in(EntrustMaterialCheckoutResult::getEntrustId, entrustIdList));
|
||||
|
||||
if (resultList.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isMetabolite) {
|
||||
resultList.forEach(item -> {
|
||||
if (StringUtils.isNotBlank(item.getMetaboliteResult())) {
|
||||
@@ -795,9 +798,15 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
});
|
||||
}
|
||||
|
||||
// 转换为 Map,方便后续查找
|
||||
Map<String, EntrustMaterialCheckoutResult> checkoutResultMap = resultList.stream()
|
||||
.collect(Collectors.toMap(EntrustMaterialCheckoutResult::getId, Function.identity()));
|
||||
// 同一检材可能同时命中组内的多个原始写法,按检材 id 去重
|
||||
for (EntrustMaterialCheckoutResult item : resultList) {
|
||||
checkoutResultMap.putIfAbsent(item.getId(), item);
|
||||
}
|
||||
}
|
||||
|
||||
if (checkoutResultMap.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 5.2 获取相关的鉴定材料
|
||||
Set<String> materialIdSet = checkoutResultMap.keySet();
|
||||
@@ -862,6 +871,46 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集化合物名称并按"归一化名称"归并。
|
||||
*
|
||||
* @param grouped 归并结果:key = 归一化名称,value = 库里的各种原始写法
|
||||
* @param drugResultJson 检出结果 JSON(qualitative_result / metabolite_result)
|
||||
*/
|
||||
private void collectDrugNames(Map<String, Set<String>> grouped, String drugResultJson) {
|
||||
if (StringUtils.isBlank(drugResultJson)) {
|
||||
return;
|
||||
}
|
||||
for (DrugLite drugLite : DrugLiteConvert.getDrugLites(drugResultJson)) {
|
||||
String rawName = drugLite.getName();
|
||||
if (StringUtils.isBlank(rawName)) {
|
||||
continue;
|
||||
}
|
||||
grouped.computeIfAbsent(normalizeDrugName(rawName), key -> new LinkedHashSet<>()).add(rawName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 化合物名称归一化。
|
||||
* <p>
|
||||
* 化合物字典里用星号标注管制药品(如 "氢可酮*",共 52 条),业务上它与不带星号的
|
||||
* "氢可酮" 是同一化合物,所以导出时按下述规则归并:去掉星号 + 去首尾空白。
|
||||
* 归并后同一个化合物在统计表中只占一行、在工作簿中只占一张工作表。
|
||||
* <p>
|
||||
* 注意:只影响"化合物归并/工作表名",明细行"检出结果"列仍按原始名称输出。
|
||||
*
|
||||
* @param drugName 原始化合物名称
|
||||
* @return 归一化后的名称
|
||||
*/
|
||||
private static String normalizeDrugName(String drugName) {
|
||||
if (StringUtils.isBlank(drugName)) {
|
||||
return drugName;
|
||||
}
|
||||
String normalized = drugName.replace("*", "").replace("*", "").trim();
|
||||
// 名称本身全是星号时归一化会变空,退回原始名称,避免出现空的分组键
|
||||
return normalized.isEmpty() ? drugName : normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出Excel
|
||||
*
|
||||
@@ -897,9 +946,17 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
|
||||
Workbook workbook = new XSSFWorkbook();
|
||||
|
||||
// 建表阶段(工作表名、单元格填充)全部包起来:万一某条数据仍触发异常,
|
||||
// 也返回可读的失败提示,而不是 500 并且把已经拼好的表一起丢掉
|
||||
try {
|
||||
createDataSheet(workbook, entrustType, resultData);
|
||||
createStatisticsSheet(workbook, resultDataMap, oldResults, entrustType, startTime, endTime);
|
||||
createDrugSheets(workbook, resultDataMap, entrustType);
|
||||
} catch (Exception e) {
|
||||
log.error("导出检出结果Excel失败: entrustType={}, startTime={}, endTime={}",
|
||||
entrustType, startTime, endTime, e);
|
||||
return R.failed("导出失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
workbook.write(response.getOutputStream());
|
||||
}
|
||||
@@ -908,13 +965,13 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
|
||||
private void createDataSheet(Workbook workbook, Integer entrustType, List<EntrustmentIdentificationMaterialVO> resultData) {
|
||||
// 确定表名
|
||||
String sheetName = (entrustType == 0) ? "常规毒品" : "生物样本";
|
||||
Sheet sheet = workbook.createSheet(sheetName);
|
||||
String sheetName = isBiologySample(entrustType) ? "生物样本" : "常规毒品";
|
||||
Sheet sheet = workbook.createSheet(safeSheetName(workbook, sheetName));
|
||||
|
||||
// 定义表头
|
||||
String[] inVivoHeaders = {"检材类型", "检材编号", "检材名称", "检材性状", "检材质量", "年龄", "性别", "委托单位", "受理日期", "检出结果"};
|
||||
String[] inVitroHeaders = {"检材类型", "检材编号", "检材名称", "检材性状", "检材质量", "委托单位", "受理日期", "检出结果"};
|
||||
String[] headers = (entrustType == 0) ? inVitroHeaders : inVivoHeaders;
|
||||
String[] headers = isBiologySample(entrustType) ? inVivoHeaders : inVitroHeaders;
|
||||
|
||||
// 创建表头行
|
||||
Row headerRow = sheet.createRow(0);
|
||||
@@ -942,7 +999,7 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
}
|
||||
|
||||
private void createStatisticsSheet(Workbook workbook, Map<String, List<EntrustmentIdentificationMaterialVO>> resultDataMap, List<String> oldResults, Integer entrustType, LocalDateTime startTime, LocalDateTime endTime) {
|
||||
Sheet sheet = workbook.createSheet("统计");
|
||||
Sheet sheet = workbook.createSheet(safeSheetName(workbook, "统计"));
|
||||
|
||||
String[] headers = {"化合物种类", "检出数量", "总数量", "检出率"};
|
||||
|
||||
@@ -965,19 +1022,24 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
row.createCell(0).setCellValue(drugName);
|
||||
row.createCell(1).setCellValue(materials.size());
|
||||
row.createCell(2).setCellValue(size);
|
||||
row.createCell(3).setCellValue(String.format("%.2f%%", materials.size() * 100.0 / size));
|
||||
row.createCell(3).setCellValue((size == null || size == 0)
|
||||
? "0.00%"
|
||||
: String.format("%.2f%%", materials.size() * 100.0 / size));
|
||||
}
|
||||
}
|
||||
|
||||
private void createDrugSheets(Workbook workbook, Map<String, List<EntrustmentIdentificationMaterialVO>> resultDataMap, Integer entrustType) {
|
||||
for (Map.Entry<String, List<EntrustmentIdentificationMaterialVO>> entry : resultDataMap.entrySet()) {
|
||||
// String drugName = entry.getKey().replaceAll("[^\u4e00-\u9fa5a-zA-Z0-9]", "");
|
||||
String drugName = entry.getKey();
|
||||
Sheet sheet = workbook.createSheet(drugName);
|
||||
// 工作表名必须净化:化合物字典里存在 "氢可酮*" 这类带 * 的名称(共 52 条)以及含 [ ] 的
|
||||
// IUPAC 名称,直接建表会抛 IllegalArgumentException 导致整份报表导出失败。
|
||||
// 注意只清洗"工作表名",单元格里的检出结果仍保留原始名称。
|
||||
String sheetName = safeSheetName(workbook, entry.getKey());
|
||||
Sheet sheet = workbook.createSheet(sheetName);
|
||||
|
||||
// 定义表头
|
||||
String[] headers = (entrustType == 0) ? new String[]{"检材类型", "检材编号", "检材名称", "检材性状", "检材质量", "委托单位", "受理日期", "检出结果"}
|
||||
: new String[]{"检材类型", "检材编号", "检材名称", "检材性状", "检材质量", "年龄", "性别", "委托单位", "受理日期", "检出结果"};
|
||||
String[] headers = isBiologySample(entrustType)
|
||||
? new String[]{"检材类型", "检材编号", "检材名称", "检材性状", "检材质量", "年龄", "性别", "委托单位", "受理日期", "检出结果"}
|
||||
: new String[]{"检材类型", "检材编号", "检材名称", "检材性状", "检材质量", "委托单位", "受理日期", "检出结果"};
|
||||
|
||||
// 创建表头行
|
||||
Row headerRow = sheet.createRow(0);
|
||||
@@ -995,6 +1057,50 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 委托类型是否为"生物样本"
|
||||
*
|
||||
* @param entrustType 0=常规毒品, 1=生物样本
|
||||
* @return true=生物样本,false(含 entrustType 为空)=常规毒品
|
||||
*/
|
||||
private static boolean isBiologySample(Integer entrustType) {
|
||||
return entrustType != null && entrustType == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成合法且唯一的 Excel 工作表名。
|
||||
* <p>
|
||||
* Excel/OOXML 规范要求工作表名:不能包含 {@code : \ / ? * [ ]} 这 7 个字符、长度 1~31、不能为空、不能重名
|
||||
* (POI 判重不区分大小写,校验不通过会抛 IllegalArgumentException)。
|
||||
* 化合物字典里本身就有带 * 的名称(如 "氢可酮*",共 52 条)和含 [ ] 的 IUPAC 名称,
|
||||
* 所以这里统一做"过滤非法字符 -> 截断 31 字符 -> 空名兜底 -> 重名加后缀(2)(3)…"。
|
||||
*
|
||||
* @param workbook 目标工作簿
|
||||
* @param rawName 原始名称(化合物名称)
|
||||
* @return 可直接用于 createSheet 的合法且唯一的工作表名
|
||||
*/
|
||||
private String safeSheetName(Workbook workbook, String rawName) {
|
||||
String base = StrUtil.isBlank(rawName)
|
||||
? ""
|
||||
: rawName.replaceAll("[\\[\\]:*?/\\\\\\x00-\\x1f\\x7f]", "").trim();
|
||||
if (base.isEmpty()) {
|
||||
base = "未命名";
|
||||
}
|
||||
if (base.length() > MAX_SHEET_NAME_LENGTH) {
|
||||
base = base.substring(0, MAX_SHEET_NAME_LENGTH);
|
||||
}
|
||||
String name = base;
|
||||
int index = 2;
|
||||
while (workbook.getSheet(name) != null) {
|
||||
String suffix = "(" + index++ + ")";
|
||||
String cut = base.length() + suffix.length() > MAX_SHEET_NAME_LENGTH
|
||||
? base.substring(0, MAX_SHEET_NAME_LENGTH - suffix.length())
|
||||
: base;
|
||||
name = cut + suffix;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private void fillRowData(Row row, EntrustmentIdentificationMaterialVO vo, Integer entrustType) {
|
||||
row.createCell(0).setCellValue(vo.getOldIdentificationResult());
|
||||
row.createCell(1).setCellValue(vo.getAcceptNo());
|
||||
@@ -1002,8 +1108,9 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
row.createCell(3).setCellValue(vo.getFormName());
|
||||
row.createCell(4).setCellValue(vo.getQuantity() + vo.getUnit());
|
||||
|
||||
if (entrustType == 1) {
|
||||
row.createCell(5).setCellValue(vo.getMaterialAge() != null || vo.getMaterialAge() != 0 ? vo.getMaterialAge().toString() + "岁" : "未知");
|
||||
if (isBiologySample(entrustType)) {
|
||||
Integer materialAge = vo.getMaterialAge();
|
||||
row.createCell(5).setCellValue(materialAge != null && materialAge != 0 ? materialAge + "岁" : "未知");
|
||||
row.createCell(6).setCellValue(StringUtils.isNotBlank(vo.getBiologyGender()) ? vo.getBiologyGender() : "未知");
|
||||
row.createCell(7).setCellValue(vo.getOrgName());
|
||||
row.createCell(8).setCellValue(LocalDateTimeUtil.format(vo.getAcceptTime(), "yyyy-MM-dd"));
|
||||
@@ -1052,23 +1159,24 @@ public class EntrustMaterialCheckoutResultServiceImpl extends ServiceImpl<Entrus
|
||||
wrapper.ge(Entrustment::getAcceptTime, queryStartTime);
|
||||
}
|
||||
|
||||
ArrayList<String> results = new ArrayList<>();
|
||||
for (String oldResult : oldResults) {
|
||||
if (oldResult.equals("委托")) {
|
||||
results.add("首次鉴定");
|
||||
results.add("补充鉴定");
|
||||
results.add("重新鉴定");
|
||||
} else results.add(oldResult);
|
||||
}
|
||||
// 鉴定情况过滤条件("委托" 等价于首次/补充/重新鉴定)
|
||||
List<String> results = getOriginalIdentificationList(oldResults);
|
||||
|
||||
// 查询符合条件的 Entrustment 记录
|
||||
List<Entrustment> entrusts = entrustmentService.list(wrapper
|
||||
LambdaQueryWrapper<Entrustment> entrustWrapper = wrapper
|
||||
.eq(Entrustment::getEntrustmentType, entrustType)
|
||||
.ge(Entrustment::getStatus, EntrustStatusConstants.ENTRUST_STATUS_ACCEPTED.getStatus())
|
||||
.in(Entrustment::getOldIdentificationResult, results)
|
||||
);
|
||||
.ge(Entrustment::getStatus, EntrustStatusConstants.ENTRUST_STATUS_ACCEPTED.getStatus());
|
||||
// 注意:鉴定情况为空时不能拼 in 条件,否则 MyBatis-Plus 会生成 "IN ()" 造成 SQL 语法错误
|
||||
if (CollUtil.isNotEmpty(results)) {
|
||||
entrustWrapper.in(Entrustment::getOldIdentificationResult, results);
|
||||
}
|
||||
List<Entrustment> entrusts = entrustmentService.list(entrustWrapper);
|
||||
|
||||
List<String> entrustIds = entrusts.stream().map(Entrustment::getId).collect(Collectors.toList());
|
||||
// 没有委托时直接返回 0,同样避免 "IN ()"
|
||||
if (CollUtil.isEmpty(entrustIds)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return entrustmentIdentificationMaterialService.lambdaQuery()
|
||||
.in(EntrustmentIdentificationMaterial::getEntrustmentId, entrustIds)
|
||||
|
||||
+32
-4
@@ -1661,15 +1661,43 @@ public class EntrustmentIdentificationMaterialServiceImpl extends ServiceImpl<En
|
||||
|
||||
@Override
|
||||
public List<EntrustmentIdentificationMaterialVO> sortVoByAcceptNo(List<EntrustmentIdentificationMaterialVO> materials) {
|
||||
materials.sort(Comparator.comparing((EntrustmentIdentificationMaterial m) -> {
|
||||
String[] parts = m.getAcceptNo().split("-");
|
||||
return new int[]{Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Integer.parseInt(parts[2])};
|
||||
}, Comparator.comparingInt((int[] arr) -> arr[0]) // 按年份排序
|
||||
if (materials == null || materials.isEmpty()) {
|
||||
return materials;
|
||||
}
|
||||
materials.sort(Comparator.comparing((EntrustmentIdentificationMaterial m) -> parseAcceptNoSortKey(m.getAcceptNo()),
|
||||
Comparator.comparingInt((int[] arr) -> arr[0]) // 按年份排序
|
||||
.thenComparingInt(arr -> arr[1]) // 按流水号排序
|
||||
.thenComparingInt(arr -> arr[2]))); // 按子流水号排序
|
||||
return materials;
|
||||
}
|
||||
|
||||
/**
|
||||
* 把受理编号(形如 "2025-3-7")解析成排序键 {年, 流水号, 子流水号}。
|
||||
* <p>
|
||||
* 编号为空或格式不符合预期时返回最大值排到最后,避免排序过程中抛
|
||||
* NullPointerException / NumberFormatException 导致接口报错。
|
||||
*
|
||||
* @param acceptNo 受理编号
|
||||
* @return 排序键
|
||||
*/
|
||||
private static int[] parseAcceptNoSortKey(String acceptNo) {
|
||||
if (StrUtil.isNotBlank(acceptNo)) {
|
||||
String[] parts = acceptNo.trim().split("-");
|
||||
if (parts.length == 3) {
|
||||
try {
|
||||
return new int[]{
|
||||
Integer.parseInt(parts[0].trim()),
|
||||
Integer.parseInt(parts[1].trim()),
|
||||
Integer.parseInt(parts[2].trim())
|
||||
};
|
||||
} catch (NumberFormatException ignored) {
|
||||
// 走下面的兜底分支
|
||||
}
|
||||
}
|
||||
}
|
||||
return new int[]{Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE};
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* 根据嫌疑人信息生成委托检材信息
|
||||
|
||||
+71
-16
@@ -362,26 +362,68 @@ public class ExcelOperationServiceImpl implements ExcelOperationService {
|
||||
*/
|
||||
private List<EntrustmentIdentificationMaterial> processHairExcelDataToMaterialEntity(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 + 2; // Excel行号(数据从第2行开始)
|
||||
String idNum = null;
|
||||
String name = null;
|
||||
try {
|
||||
name = datum.get("姓名");
|
||||
// ---------- 1. 姓名必填校验 ----------
|
||||
if (StrUtil.isBlank(name)) {
|
||||
throw new IllegalArgumentException("姓名不能为空");
|
||||
}
|
||||
|
||||
// ---------- 2. 身份证号校验 ----------
|
||||
idNum = datum.get("身份证号");
|
||||
if (StrUtil.isBlank(idNum)) {
|
||||
throw new IllegalArgumentException("身份证号不能为空");
|
||||
}
|
||||
if (idNum.length() != 18) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"身份证号[%s]长度不正确(当前%d位,应为18位),请检查身份证号是否完整",
|
||||
idNum, idNum.length()));
|
||||
}
|
||||
// 性别解析
|
||||
String gender = this.getSexByIdNum(idNum);
|
||||
if (StrUtil.isBlank(gender)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"身份证号[%s]性别解析失败,请检查第17位是否为数字0~9", idNum));
|
||||
}
|
||||
// 年龄解析
|
||||
String ageStr = this.getAgeByIdNum(idNum);
|
||||
if (StrUtil.isBlank(ageStr)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"身份证号[%s]出生日期解析失败,请检查第7~14位是否为合法日期(yyyyMMdd格式),如19900520",
|
||||
idNum));
|
||||
}
|
||||
|
||||
// ---------- 3. 检测结果必填校验 ----------
|
||||
String testResult = datum.get("检测结果");
|
||||
if (StrUtil.isBlank(testResult)) {
|
||||
throw new IllegalArgumentException("检测结果不能为空");
|
||||
}
|
||||
|
||||
// ---------- 4. 采样单位校验 ----------
|
||||
String drawPlace = datum.get("采样单位");
|
||||
if (StrUtil.isBlank(drawPlace)) {
|
||||
throw new IllegalArgumentException("采样单位不能为空");
|
||||
}
|
||||
|
||||
// ---------- 构建检材对象 ----------
|
||||
EntrustmentIdentificationMaterial material = new EntrustmentIdentificationMaterial();
|
||||
material.setEntrustmentId(entrustment.getId());
|
||||
material.setCaseId(entrustment.getCaseId());
|
||||
material.setName(datum.get("姓名") + "毛发");
|
||||
material.setRemark(datum.get("身份证号"));
|
||||
|
||||
// 解析身份证号
|
||||
String idNum = datum.get("身份证号");
|
||||
if (idNum != null && idNum.length() == 18) {
|
||||
material.setBiologyGender(this.getSexByIdNum(idNum));
|
||||
material.setMaterialAge(Integer.valueOf(this.getAgeByIdNum(idNum)));
|
||||
}
|
||||
|
||||
material.setDrawPlace(datum.get("采样单位"));
|
||||
material.setName(name + "毛发");
|
||||
material.setRemark(idNum);
|
||||
material.setBiologyGender(gender);
|
||||
material.setMaterialAge(Integer.valueOf(ageStr));
|
||||
material.setDrawPlace(drawPlace);
|
||||
material.setId(IdWorker.get32UUID().toUpperCase());
|
||||
|
||||
// 检测结果解析
|
||||
String[] drugs = datum.get("检测结果").split("、");
|
||||
String[] drugs = testResult.split("、");
|
||||
buildMatchedDrugs(drugLiteMap, material, drugs);
|
||||
|
||||
// 设置检材默认属性
|
||||
@@ -404,6 +446,17 @@ public class ExcelOperationServiceImpl implements ExcelOperationService {
|
||||
material.setSample1No(sampleService.getNewSampleNo(material.getImNo(), 1));
|
||||
|
||||
entrustmentIdentificationMaterialList.add(material);
|
||||
|
||||
} catch (Exception e) {
|
||||
String idInfo = StrUtil.isNotBlank(idNum) ? (" 证件号[" + idNum + "]") : "";
|
||||
String nameInfo = StrUtil.isNotBlank(name) ? name : "未知";
|
||||
errorMessages.add(String.format("第%d行 姓名[%s]%s: %s", rowNum, nameInfo, idInfo, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// 一次性汇总所有错误返回给用户
|
||||
if (!errorMessages.isEmpty()) {
|
||||
throw new CheckedException("Excel导入校验失败,共" + errorMessages.size() + "处错误:\n" + String.join("\n", errorMessages));
|
||||
}
|
||||
return entrustmentIdentificationMaterialList;
|
||||
}
|
||||
@@ -451,7 +504,7 @@ public class ExcelOperationServiceImpl implements ExcelOperationService {
|
||||
|
||||
// 3. 身份证号业务校验
|
||||
// 条件:生物样本(Type=1) 且 属于指定的鉴定结果类别
|
||||
// 3. 身份证号业务校验及一致性比对
|
||||
// 3. 身份证号业务校验及一致性比对
|
||||
if (entrustment.getEntrustmentType() == 1 && idCardRequiredResults.contains(entrustment.getOldIdentificationResult())) {
|
||||
String idCard = datum.get("身份证号");
|
||||
if (StrUtil.isBlank(idCard)) {
|
||||
@@ -708,7 +761,7 @@ public class ExcelOperationServiceImpl implements ExcelOperationService {
|
||||
int genderCode = Integer.parseInt(idNumber.substring(16, 17));
|
||||
return genderCode % 2 == 0 ? "女" : "男";
|
||||
} catch (Exception e) {
|
||||
|
||||
log.warn("身份证号[{}] 性别解析失败: {}", idNumber, e.getMessage());
|
||||
}
|
||||
}
|
||||
return "";
|
||||
@@ -726,6 +779,8 @@ public class ExcelOperationServiceImpl implements ExcelOperationService {
|
||||
return String.valueOf(age);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warn("身份证号[{}] 年龄解析失败(出生日期[{}-{}]): {}", idNumber,
|
||||
idNumber.substring(6, 10), idNumber.substring(10, 14), e.getMessage());
|
||||
}
|
||||
}
|
||||
return "";
|
||||
|
||||
Reference in New Issue
Block a user