feat(credit): 优化信用消限记录导入功能支持多模板兼容

- 新增 application-glt.yml 生产环境配置文件
- 重构 CreditXgxf 实体类字段顺序和命名规范
- 添加上游多公司导出模板的备用字段映射支持
- 实现 Excel 表头括号后缀清理和标准化逻辑
- 增加备用字段(申请执行人、被执行人)的兼容性处理
- 完善导入参数转换逻辑确保模板兼容性
- 添加单元测试验证多模板字段映射正确性
This commit is contained in:
2026-02-14 09:55:43 +08:00
parent bd3202830c
commit c5a942b4fc
6 changed files with 193 additions and 39 deletions

View File

@@ -478,20 +478,28 @@ public class CreditXgxfController extends BaseController {
private CreditXgxf convertImportParamToEntity(CreditXgxfImportParam param) {
CreditXgxf entity = new CreditXgxf();
// Template compatibility: some upstream multi-company exports use alternate headers for the same columns.
String plaintiffAppellant = !ImportHelper.isBlank(param.getPlaintiffAppellant())
? param.getPlaintiffAppellant()
: param.getPlaintiffAppellant2();
String appellee = !ImportHelper.isBlank(param.getAppellee())
? param.getAppellee()
: param.getAppellee2();
String courtName = !ImportHelper.isBlank(param.getCourtName())
? param.getCourtName()
: param.getCourtName2();
entity.setCaseNumber(param.getCaseNumber());
entity.setType(param.getType());
entity.setDataType(param.getDataType());
entity.setPlaintiffAppellant(param.getPlaintiffAppellant());
entity.setAppellee(param.getAppellee());
entity.setPlaintiffAppellant(plaintiffAppellant);
entity.setAppellee(appellee);
entity.setOtherPartiesThirdParty(param.getOtherPartiesThirdParty());
entity.setPlaintiffAppellant(param.getPlaintiffAppellant());
entity.setDataStatus(param.getDataStatus());
entity.setAppellee(param.getAppellee());
// 兼容不同模板字段:如果 *2 有值则以 *2 为准写入主字段
entity.setInvolvedAmount(param.getInvolvedAmount());
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setCourtName(param.getCourtName());
entity.setCourtName(courtName);
entity.setReleaseDate(param.getReleaseDate());
entity.setComments(param.getComments());

View File

@@ -330,7 +330,7 @@ public class ExcelImportSupport {
return null;
}
// Remove common invisible whitespace characters, including full-width space.
return text
String normalized = text
.replace("", "/")
.replace(" ", "")
.replace("\t", "")
@@ -339,6 +339,10 @@ public class ExcelImportSupport {
.replace("\u00A0", "")
.replace(" ", "")
.trim();
// Some upstream templates append explanations in brackets, e.g. "原告/上诉人(申请执行人)".
// Strip bracketed suffixes so Easypoi can match the canonical header name.
normalized = normalized.replaceAll("[\\((【\\[].*?[\\))】\\]]", "");
return normalized.trim();
}
private static <T> List<T> filterEmptyRows(List<T> rawList, Predicate<T> emptyRowPredicate) {

View File

@@ -30,51 +30,51 @@ public class CreditXgxf implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "案号")
private String caseNumber;
@Schema(description = "链接地址")
private String url;
@Schema(description = "数据类型")
private String type;
@Schema(description = "限消令对象")
private String dataType;
@Schema(description = "限制法定代表人")
@Schema(description = "原告/上诉人")
private String plaintiffAppellant;
@Schema(description = "申请人")
private String appellee;
@Schema(description = "原告/上诉人")
private String plaintiffUser;
@Schema(description = "被告/被上诉人")
private String defendantUser;
@Schema(description = "涉案金额(元)")
private String involvedAmount;
@Schema(description = "立案日期")
private String occurrenceTime;
@Schema(description = "执行法院")
private String courtName;
@Schema(description = "发布日期")
private String releaseDate;
private String appellee;
@Schema(description = "其他当事人/第三人")
private String otherPartiesThirdParty;
@Schema(description = "案由")
private String causeOfAction;
@Schema(description = "发生时间")
private String occurrenceTime;
@Schema(description = "案号")
private String caseNumber;
@Schema(description = "涉案金额")
private String involvedAmount;
@Schema(description = "法院")
private String courtName;
@Schema(description = "数据状态")
private String dataStatus;
@Schema(description = "限消令对象")
private String dataType;
@Schema(description = "原告/上诉人2")
private String plaintiffUser;
@Schema(description = "被告/被上诉人2")
private String defendantUser;
@Schema(description = "发布日期")
private String releaseDate;
@Schema(description = "案由")
private String causeOfAction;
@Schema(description = "企业ID")
private Integer companyId;

View File

@@ -22,13 +22,21 @@ public class CreditXgxfImportParam implements Serializable {
@Excel(name = "限消令对象")
private String dataType;
@Schema(description = "原告/上诉人")
@Excel(name = "原告/上诉人")
private String plaintiffAppellant;
@Schema(description = "告/上诉人")
// Some upstream multi-company exports use "申请执行人" instead of "原告/上诉人".
@Excel(name = "申请执行人")
private String plaintiffAppellant2;
@Excel(name = "被告/被上诉人")
private String appellee;
@Schema(description = "其他当事人/第三人")
// Some upstream multi-company exports use "被执行人" instead of "被告/被上诉人".
@Excel(name = "被执行人")
private String appellee2;
@Excel(name = "其他当事人/第三人")
private String otherPartiesThirdParty;
@Excel(name = "涉案金额")
@@ -49,7 +57,7 @@ public class CreditXgxfImportParam implements Serializable {
@Excel(name = "数据状态")
private String dataStatus;
@Excel(name = "法院")
@Excel(name = "执行法院")
private String courtName2;
}

View File

@@ -0,0 +1,83 @@
# 生产环境配置
# 数据源配置
spring:
datasource:
url: jdbc:mysql://1Panel-mysql-XsWW:3306/modules?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: modules
password: tYmmMGh5wpwXR3ae
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
remove-abandoned: true
# redis
redis:
database: 0
host: 1Panel-redis-GmNr
port: 6379
password: redis_t74P8C
# 日志配置
logging:
file:
name: websoft-modules.log
level:
root: WARN
com.gxwebsoft: ERROR
com.baomidou.mybatisplus: ERROR
socketio:
host: 0.0.0.0 #IP地址
# MQTT配置
mqtt:
enabled: true # 启用MQTT服务
host: tcp://132.232.214.96:1883
username: swdev
password: Sw20250523
client-id-prefix: hjm_car_
topic: /SW_GPS/#
qos: 2
connection-timeout: 10
keep-alive-interval: 20
auto-reconnect: true
# 框架配置
config:
# 文件服务器
file-server: https://file-s209.shoplnk.cn
# 生产环境接口
server-url: https://glt-server.websoft.top/api
upload-path: /www/wwwroot/file.ws
# 阿里云OSS云存储
endpoint: https://oss-cn-shenzhen.aliyuncs.com
accessKeyId: LTAI4GKGZ9Z2Z8JZ77c3GNZP
accessKeySecret: BiDkpS7UXj72HWwDWaFZxiXjNFBNCM
bucketName: oss-gxwebsoft
bucketDomain: https://oss.wsdns.cn
aliyunDomain: https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com
# 生产环境证书配置
certificate:
load-mode: VOLUME # 生产环境从Docker挂载卷加载
cert-root-path: /www/wwwroot/file.ws
# 支付配置缓存
payment:
cache:
# 支付配置缓存键前缀,生产环境使用 Payment:1* 格式
key-prefix: "Payment:1"
# 缓存过期时间(小时)
expire-hours: 24
# 阿里云翻译配置
aliyun:
translate:
access-key-id: LTAI5tEsyhW4GCKbds1qsopg
access-key-secret: zltFlQrYVAoq2KMFDWgLa3GhkMNeyO
endpoint: mt.cn-hangzhou.aliyuncs.com
wechatpay:
transfer:
scene-id: 1005
scene-report-infos-json: '[{"info_type":"岗位类型","info_content":"配送员"},{"info_type":"报酬说明","info_content":"12月份配送费"}]'

View File

@@ -0,0 +1,51 @@
package com.gxwebsoft.credit.controller;
import com.gxwebsoft.credit.entity.CreditXgxf;
import com.gxwebsoft.credit.param.CreditXgxfImportParam;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import static org.junit.jupiter.api.Assertions.assertEquals;
class CreditXgxfImportMappingTest {
private static CreditXgxf convert(CreditXgxfImportParam param) throws Exception {
CreditXgxfController controller = new CreditXgxfController();
Method m = CreditXgxfController.class.getDeclaredMethod("convertImportParamToEntity", CreditXgxfImportParam.class);
m.setAccessible(true);
return (CreditXgxf) m.invoke(controller, param);
}
@Test
void mapsAlternateUpstreamHeadersForParties() throws Exception {
CreditXgxfImportParam param = new CreditXgxfImportParam();
param.setCaseNumber("2024示例案号");
param.setPlaintiffAppellant2("申请执行人A");
param.setAppellee2("被执行人B");
param.setCourtName2("执行法院C");
CreditXgxf entity = convert(param);
assertEquals("申请执行人A", entity.getPlaintiffAppellant());
assertEquals("被执行人B", entity.getAppellee());
assertEquals("执行法院C", entity.getCourtName());
}
@Test
void prefersCanonicalHeadersWhenBothPresent() throws Exception {
CreditXgxfImportParam param = new CreditXgxfImportParam();
param.setCaseNumber("2024示例案号");
param.setPlaintiffAppellant("原告A");
param.setPlaintiffAppellant2("申请执行人A");
param.setAppellee("被告B");
param.setAppellee2("被执行人B");
param.setCourtName("法院C");
param.setCourtName2("执行法院C");
CreditXgxf entity = convert(param);
assertEquals("原告A", entity.getPlaintiffAppellant());
assertEquals("被告B", entity.getAppellee());
assertEquals("法院C", entity.getCourtName());
}
}