fix(wms):入库单导入表头字段错位、备注丢失
- 取值向右查找时误把下一个标签/选项说明当值(承运方←Tel:、生产商←客户名称:、监管方式←送货地址:、送货地址←查验选项),现遇疑似标签即停止查找 - 备注:xxx同格书写为全角冒号,原仅按半角:拆分导致备注丢失,现全角/半角兼容 - 表头列遍历上界改用getLastCellNum,防空单元格漏扫尾部列"
This commit is contained in:
+57
-19
@@ -1000,7 +1000,7 @@ public class StockInOrderApplicationService {
|
|||||||
for (int rowIdx = 0; rowIdx < 12; rowIdx++) {
|
for (int rowIdx = 0; rowIdx < 12; rowIdx++) {
|
||||||
Row row = sheet.getRow(rowIdx);
|
Row row = sheet.getRow(rowIdx);
|
||||||
if (row != null) {
|
if (row != null) {
|
||||||
for (int colIdx = 0; colIdx < row.getPhysicalNumberOfCells(); colIdx++) {
|
for (int colIdx = 0; colIdx < row.getLastCellNum(); colIdx++) {
|
||||||
Cell labelCell = row.getCell(colIdx);
|
Cell labelCell = row.getCell(colIdx);
|
||||||
if (labelCell != null) {
|
if (labelCell != null) {
|
||||||
String labelValue = getCellValueAsString(labelCell);
|
String labelValue = getCellValueAsString(labelCell);
|
||||||
@@ -1009,22 +1009,34 @@ public class StockInOrderApplicationService {
|
|||||||
log.info("表头第{}行第{}列: {}", rowIdx + 1, colIdx + 1, labelValue);
|
log.info("表头第{}行第{}列: {}", rowIdx + 1, colIdx + 1, labelValue);
|
||||||
String value = null;
|
String value = null;
|
||||||
|
|
||||||
// 先尝试从同一单元格提取值(如果包含冒号)
|
// 先尝试从同一单元格提取值(兼容全角":"与半角":",如"备注:xxx")
|
||||||
String extractedFromSameCell = null;
|
String extractedFromSameCell = null;
|
||||||
if (labelValue.contains(":")) {
|
String labelKey = labelValue;
|
||||||
String[] parts = labelValue.split(":", 2);
|
int colonIdx = labelValue.indexOf(":");
|
||||||
if (parts.length > 1) {
|
if (colonIdx < 0) {
|
||||||
extractedFromSameCell = parts[1].trim();
|
colonIdx = labelValue.indexOf(":");
|
||||||
|
}
|
||||||
|
if (colonIdx >= 0) {
|
||||||
|
labelKey = labelValue.substring(0, colonIdx).trim();
|
||||||
|
String afterColon = labelValue.substring(colonIdx + 1).trim();
|
||||||
|
// 选项说明类标签(如"车型及车牌:3T、5T、8T、10T"、"海关是否查验货物:是、否")冒号后是选项说明而非实际值
|
||||||
|
if (StringUtils.isNotBlank(afterColon) && !isOptionLabel(labelKey)) {
|
||||||
|
extractedFromSameCell = afterColon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 跳过空单元格,查找下一个非空单元格作为值(最多向后查找10列)
|
// 向右查找下一个非空单元格作为值:遇到疑似标签/选项说明(含冒号或命中标签关键词)直接停止,
|
||||||
|
// 避免把下一个标签(如"承运方:"右侧的"Tel:")或选项说明当成值导致数据错位
|
||||||
String nextCellValue = null;
|
String nextCellValue = null;
|
||||||
for (int searchColIdx = colIdx + 1; searchColIdx < colIdx + 10 && searchColIdx < row.getPhysicalNumberOfCells(); searchColIdx++) {
|
for (int searchColIdx = colIdx + 1; searchColIdx < colIdx + 10 && searchColIdx < row.getLastCellNum(); searchColIdx++) {
|
||||||
Cell valueCell = row.getCell(searchColIdx);
|
Cell valueCell = row.getCell(searchColIdx);
|
||||||
if (valueCell != null) {
|
if (valueCell != null) {
|
||||||
String cellValue = getCellValueAsString(valueCell);
|
String cellValue = getCellValueAsString(valueCell);
|
||||||
if (StringUtils.isNotBlank(cellValue)) {
|
if (StringUtils.isNotBlank(cellValue)) {
|
||||||
|
if (looksLikeLabel(cellValue)) {
|
||||||
|
log.info("表头第{}行,标签'{}'在第{}列,向右第{}列是另一个标签/选项说明'{}',停止查找", rowIdx + 1, labelValue, colIdx + 1, searchColIdx + 1, cellValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
nextCellValue = cellValue;
|
nextCellValue = cellValue;
|
||||||
log.info("表头第{}行,标签'{}'在第{}列,找到值'{}'在第{}列", rowIdx + 1, labelValue, colIdx + 1, nextCellValue, searchColIdx + 1);
|
log.info("表头第{}行,标签'{}'在第{}列,找到值'{}'在第{}列", rowIdx + 1, labelValue, colIdx + 1, nextCellValue, searchColIdx + 1);
|
||||||
break;
|
break;
|
||||||
@@ -1032,19 +1044,10 @@ public class StockInOrderApplicationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 优先使用下一个非空单元格的值(如果存在且不为空)
|
// 优先使用右侧紧邻的实际值,其次使用同一单元格冒号后的值
|
||||||
// 如果下一个单元格为空,且同一单元格有冒号后的值,则使用冒号后的值
|
|
||||||
// 但如果冒号后的值是选项列表(如"3T、5T、8T、10T"),则应该使用下一个单元格的值
|
|
||||||
if (StringUtils.isNotBlank(nextCellValue)) {
|
if (StringUtils.isNotBlank(nextCellValue)) {
|
||||||
// 如果冒号后的值是选项列表(包含顿号、逗号等),优先使用下一个单元格的值
|
value = nextCellValue;
|
||||||
if (extractedFromSameCell != null && (extractedFromSameCell.contains("、") || extractedFromSameCell.contains(","))) {
|
|
||||||
value = nextCellValue;
|
|
||||||
} else {
|
|
||||||
// 否则优先使用下一个单元格的值
|
|
||||||
value = nextCellValue;
|
|
||||||
}
|
|
||||||
} else if (StringUtils.isNotBlank(extractedFromSameCell)) {
|
} else if (StringUtils.isNotBlank(extractedFromSameCell)) {
|
||||||
// 如果下一个单元格为空,使用同一单元格冒号后的值
|
|
||||||
value = extractedFromSameCell;
|
value = extractedFromSameCell;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2285,6 +2288,41 @@ public class StockInOrderApplicationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断表头标签(冒号前的部分)是否为选项说明类标签:
|
||||||
|
* 这类标签冒号后跟的是选项说明(如"车型及车牌:3T、5T、8T、10T"、"海关是否查验货物:是、否")而非实际填写值
|
||||||
|
*/
|
||||||
|
private boolean isOptionLabel(String labelKey) {
|
||||||
|
if (StringUtils.isBlank(labelKey)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return labelKey.contains("车型及车牌") || labelKey.contains("柜号") || labelKey.contains("海关是否查验货物")
|
||||||
|
|| labelKey.contains("是否需要报关") || labelKey.contains("是否需要运输");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断表头单元格文本是否疑似"标签/选项说明"而非实际值:
|
||||||
|
* 包含全角":"或半角":"(如"Tel:"、"客户名称:"),或命中常见标签关键词(如无冒号的"起运/运抵国(地区)")。
|
||||||
|
* 向右查找标签的值时遇到此类单元格应停止查找,避免把标签文本当成值导致导入数据错位。
|
||||||
|
*/
|
||||||
|
private boolean looksLikeLabel(String cellValue) {
|
||||||
|
if (StringUtils.isBlank(cellValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (cellValue.contains(":") || cellValue.contains(":")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String[] labelKeywords = {"委托编号", "客户名称", "联系人", "车型及车牌", "司机签名", "申报地关区", "生产商",
|
||||||
|
"报关员", "送货地址", "进出境关别", "起运/运抵国", "运抵国", "承运方", "柜号", "运输方式", "监管方式",
|
||||||
|
"海关是否查验", "入仓日期", "完成时间", "下单日期", "备注", "Tel", "Fax"};
|
||||||
|
for (String keyword : labelKeywords) {
|
||||||
|
if (cellValue.contains(keyword)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 设置仓库信息
|
* @description 设置仓库信息
|
||||||
* @author ZhouGY
|
* @author ZhouGY
|
||||||
|
|||||||
Reference in New Issue
Block a user