diff --git a/src/main/java/com/gxwebsoft/credit/controller/BatchImportSupport.java b/src/main/java/com/gxwebsoft/credit/controller/BatchImportSupport.java index ea2d2ec..ca07a1d 100644 --- a/src/main/java/com/gxwebsoft/credit/controller/BatchImportSupport.java +++ b/src/main/java/com/gxwebsoft/credit/controller/BatchImportSupport.java @@ -22,6 +22,7 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import java.util.regex.Pattern; /** * credit 模块 Excel 导入批处理支持: @@ -32,6 +33,7 @@ import java.util.function.Supplier; public class BatchImportSupport { private final TransactionTemplate requiresNewTx; + private static final Pattern PARTY_SPLIT_PATTERN = Pattern.compile("[,,;;、\\n\\r\\t/|]+"); public BatchImportSupport(PlatformTransactionManager transactionManager) { TransactionTemplate template = new TransactionTemplate(transactionManager); @@ -71,7 +73,7 @@ public class BatchImportSupport { /** * 按企业名称匹配 CreditCompany(name / matchName) 并回填 companyId。 * - *

默认仅更新 companyId=0 的记录(onlyNull=true);onlyNull=false 时会覆盖更新(仅当 companyId 不同)。

+ *

默认仅更新 companyId 为空/0 的记录(onlyNull=true);onlyNull=false 时会覆盖更新(仅当 companyId 不同)。

* *

注意:为避免跨租户误更新,当 currentTenantId 为空时会按记录自身 tenantId 维度匹配, * tenantId 为空的记录将被跳过并计入 notFound。

@@ -90,15 +92,80 @@ public class BatchImportSupport { BiConsumer hasDataSetter, SFunction tenantIdGetter, Supplier patchFactory) { + // Keep existing API; delegate to the multi-column implementation. + return refreshCompanyIdByCompanyNames(service, + creditCompanyService, + currentTenantId, + onlyNull, + limit, + idGetter, + idSetter, + companyIdGetter, + companyIdSetter, + hasDataGetter, + hasDataSetter, + tenantIdGetter, + patchFactory, + nameGetter); + } + + /** + * 按多列“当事人/企业名称”匹配 CreditCompany(name / matchName) 并回填 companyId。 + * + *

按传入列顺序优先匹配:原告/上诉人 > 被告/被上诉人 > 其他当事人/第三人等。

+ * + *

同一列若匹配到多个不同企业则视为歧义;若最终无法得到唯一 companyId,则跳过并计入 ambiguous/notFound。

+ */ + @SafeVarargs + public final CompanyIdRefreshStats refreshCompanyIdByCompanyNames(IService service, + CreditCompanyService creditCompanyService, + Integer currentTenantId, + Boolean onlyNull, + Integer limit, + SFunction idGetter, + BiConsumer idSetter, + SFunction companyIdGetter, + BiConsumer companyIdSetter, + SFunction hasDataGetter, + BiConsumer hasDataSetter, + SFunction tenantIdGetter, + Supplier patchFactory, + SFunction... nameGetters) { boolean onlyNullFlag = (onlyNull == null) || Boolean.TRUE.equals(onlyNull); + if (nameGetters == null || nameGetters.length == 0) { + return new CompanyIdRefreshStats(false, 0, 0, 0, 0); + } + // 1) 读取待处理数据(仅取必要字段,避免一次性拉全表字段) + @SuppressWarnings({"rawtypes", "unchecked"}) + SFunction[] selectColumns = (SFunction[]) new SFunction[4 + nameGetters.length]; + int colIdx = 0; + selectColumns[colIdx++] = idGetter; + selectColumns[colIdx++] = companyIdGetter; + selectColumns[colIdx++] = hasDataGetter; + selectColumns[colIdx++] = tenantIdGetter; + for (SFunction ng : nameGetters) { + selectColumns[colIdx++] = ng; + } + var query = service.lambdaQuery() - .select(idGetter, nameGetter, companyIdGetter, hasDataGetter, tenantIdGetter) + .select(selectColumns) .eq(currentTenantId != null, tenantIdGetter, currentTenantId) - .isNotNull(nameGetter); + .and(w -> { + // Only process rows that have at least one name column populated. + for (int i = 0; i < nameGetters.length; i++) { + if (i == 0) { + w.isNotNull(nameGetters[i]); + } else { + w.or().isNotNull(nameGetters[i]); + } + } + }); if (onlyNullFlag) { - query.eq(companyIdGetter, 0); + // Historically some tables used 0 as the "unset" companyId, while others left it NULL. + // Treat both as "unset" so refresh won't silently do nothing. + query.and(w -> w.isNull(companyIdGetter).or().eq(companyIdGetter, 0)); } if (limit != null && limit > 0) { query.last("limit " + Math.min(limit, 200000)); @@ -146,9 +213,15 @@ public class BatchImportSupport { LinkedHashMap ambiguousByName = new LinkedHashMap<>(); LinkedHashSet nameSet = new LinkedHashSet<>(); for (T row : tenantRows) { - String name = normalizeCompanyName(row != null ? nameGetter.apply(row) : null); - if (name != null) { - nameSet.add(name); + if (row == null) { + continue; + } + for (SFunction ng : nameGetters) { + for (String name : splitPartyNames(ng.apply(row))) { + if (name != null) { + nameSet.add(name); + } + } } } List allNames = new ArrayList<>(nameSet); @@ -174,20 +247,44 @@ public class BatchImportSupport { // 3.2) 更新当前租户下的数据 companyId for (T row : tenantRows) { - String key = normalizeCompanyName(row != null ? nameGetter.apply(row) : null); - if (key == null) { + if (row == null) { continue; } - Integer amb = ambiguousByName.get(key); - if (amb != null && amb > 0) { - ambiguous++; - continue; + Integer companyId = null; + boolean hasAmbiguousName = false; + for (SFunction ng : nameGetters) { + LinkedHashSet idsForColumn = new LinkedHashSet<>(); + for (String key : splitPartyNames(ng.apply(row))) { + if (key == null) { + continue; + } + Integer amb = ambiguousByName.get(key); + if (amb != null && amb > 0) { + hasAmbiguousName = true; + continue; + } + Integer cid = companyIdByName.get(key); + if (cid != null) { + idsForColumn.add(cid); + } + } + if (idsForColumn.size() == 1) { + companyId = idsForColumn.iterator().next(); + break; + } + if (idsForColumn.size() > 1) { + // Multiple companies matched within one column (e.g. multiple plaintiffs) -> ambiguous. + hasAmbiguousName = true; + } } - Integer companyId = companyIdByName.get(key); if (companyId == null) { - notFound++; + if (hasAmbiguousName) { + ambiguous++; + } else { + notFound++; + } continue; } matched++; @@ -196,7 +293,7 @@ public class BatchImportSupport { Boolean oldHasData = row != null ? hasDataGetter.apply(row) : null; boolean needUpdate; if (onlyNullFlag) { - needUpdate = oldCompanyId != null && oldCompanyId == 0; + needUpdate = (oldCompanyId == null) || oldCompanyId == 0; } else { needUpdate = oldCompanyId == null || !companyId.equals(oldCompanyId); } @@ -710,6 +807,30 @@ public class BatchImportSupport { return v.isEmpty() ? null : v; } + /** + * Split a "party names" cell into normalized company name candidates. + * Supports common separators used in Excel/web copy (comma/semicolon/Chinese list delimiter/newlines). + */ + private static List splitPartyNames(String raw) { + List result = new ArrayList<>(); + String v = normalizeCompanyName(raw); + if (v == null) { + return result; + } + String[] parts = PARTY_SPLIT_PATTERN.split(v); + if (parts == null || parts.length == 0) { + result.add(v); + return result; + } + for (String p : parts) { + String item = normalizeCompanyName(p); + if (item != null) { + result.add(item); + } + } + return result; + } + private static void addCompanyNameMapping(Map idByName, Map ambiguousByName, String key, diff --git a/src/main/java/com/gxwebsoft/credit/controller/CreditGqdjController.java b/src/main/java/com/gxwebsoft/credit/controller/CreditGqdjController.java index b9a7b4f..43b0674 100644 --- a/src/main/java/com/gxwebsoft/credit/controller/CreditGqdjController.java +++ b/src/main/java/com/gxwebsoft/credit/controller/CreditGqdjController.java @@ -145,9 +145,9 @@ public class CreditGqdjController extends BaseController { } /** - * 根据企业名称匹配企业并更新 companyId(匹配 CreditCompany.name / CreditCompany.matchName) + * 根据当事人/企业名称匹配企业并更新 companyId(匹配 CreditCompany.name / CreditCompany.matchName) * - *

默认仅更新 companyId=0 的记录;如需覆盖更新,传 onlyNull=false。

+ *

默认仅更新 companyId 为空/0 的记录;如需覆盖更新,传 onlyNull=false。

*/ @PreAuthorize("hasAuthority('credit:creditGqdj:update')") @OperationLog @@ -160,7 +160,8 @@ public class CreditGqdjController extends BaseController { User loginUser = getLoginUser(); Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null; - BatchImportSupport.CompanyIdRefreshStats stats = batchImportSupport.refreshCompanyIdByCompanyName( + // Match companyId by any party/company-name column (e.g. plaintiff/appellant, defendant/appellee). + BatchImportSupport.CompanyIdRefreshStats stats = batchImportSupport.refreshCompanyIdByCompanyNames( creditGqdjService, creditCompanyService, currentTenantId, @@ -168,13 +169,14 @@ public class CreditGqdjController extends BaseController { limit, CreditGqdj::getId, CreditGqdj::setId, - CreditGqdj::getAppellee, CreditGqdj::getCompanyId, CreditGqdj::setCompanyId, CreditGqdj::getHasData, CreditGqdj::setHasData, CreditGqdj::getTenantId, - CreditGqdj::new + CreditGqdj::new, + CreditGqdj::getPlaintiffAppellant, + CreditGqdj::getAppellee ); if (!stats.anyDataRead) { diff --git a/src/main/java/com/gxwebsoft/credit/controller/CreditXgxfController.java b/src/main/java/com/gxwebsoft/credit/controller/CreditXgxfController.java index e949e6a..2e95ef2 100644 --- a/src/main/java/com/gxwebsoft/credit/controller/CreditXgxfController.java +++ b/src/main/java/com/gxwebsoft/credit/controller/CreditXgxfController.java @@ -603,11 +603,24 @@ public class CreditXgxfController extends BaseController { entity.setCaseNumber(param.getCaseNumber()); entity.setType(param.getType()); entity.setDataType(param.getDataType()); + entity.setPlaintiffUser(param.getPlaintiffUser()); + entity.setDefendantUser(param.getDefendantUser()); + entity.setOtherPartiesThirdParty(param.getOtherPartiesThirdParty()); entity.setPlaintiffAppellant(param.getPlaintiffAppellant()); + entity.setDataStatus(param.getDataStatus()); entity.setAppellee(param.getAppellee()); - entity.setInvolvedAmount(param.getInvolvedAmount()); - entity.setOccurrenceTime(param.getOccurrenceTime()); - entity.setCourtName(param.getCourtName()); + + // 兼容不同模板字段:如果 *2 有值则以 *2 为准写入主字段 + entity.setInvolvedAmount(!ImportHelper.isBlank(param.getInvolvedAmount2()) + ? param.getInvolvedAmount2() + : param.getInvolvedAmount()); + entity.setOccurrenceTime(!ImportHelper.isBlank(param.getOccurrenceTime2()) + ? param.getOccurrenceTime2() + : param.getOccurrenceTime()); + entity.setCourtName(!ImportHelper.isBlank(param.getCourtName2()) + ? param.getCourtName2() + : param.getCourtName()); + entity.setReleaseDate(param.getReleaseDate()); entity.setComments(param.getComments()); diff --git a/src/main/java/com/gxwebsoft/credit/param/CreditBreachOfTrustImportParam.java b/src/main/java/com/gxwebsoft/credit/param/CreditBreachOfTrustImportParam.java index 1dc9c0a..0be1895 100644 --- a/src/main/java/com/gxwebsoft/credit/param/CreditBreachOfTrustImportParam.java +++ b/src/main/java/com/gxwebsoft/credit/param/CreditBreachOfTrustImportParam.java @@ -39,4 +39,7 @@ public class CreditBreachOfTrustImportParam implements Serializable { @Excel(name = "备注") private String comments; +// @Excel(name = "原告/上诉人") +// private String plaintiffAppellant2; + } diff --git a/src/main/java/com/gxwebsoft/credit/param/CreditXgxfImportParam.java b/src/main/java/com/gxwebsoft/credit/param/CreditXgxfImportParam.java index 6a57235..d0eb97d 100644 --- a/src/main/java/com/gxwebsoft/credit/param/CreditXgxfImportParam.java +++ b/src/main/java/com/gxwebsoft/credit/param/CreditXgxfImportParam.java @@ -31,9 +31,15 @@ public class CreditXgxfImportParam implements Serializable { @Excel(name = "涉案金额(元)") private String involvedAmount; + @Excel(name = "涉案金额") + private String involvedAmount2; + @Excel(name = "立案日期") private String occurrenceTime; + @Excel(name = "发生时间") + private String occurrenceTime2; + @Excel(name = "执行法院") private String courtName; @@ -43,4 +49,19 @@ public class CreditXgxfImportParam implements Serializable { @Excel(name = "备注") private String comments; + @Excel(name = "原告/上诉人") + private String plaintiffUser; + + @Excel(name = "被告/被上诉人") + private String defendantUser; + + @Excel(name = "其他当事人/第三人") + private String otherPartiesThirdParty; + + @Excel(name = "数据状态") + private String dataStatus; + + @Excel(name = "法院") + private String courtName2; + }