feat(credit): 调整涉案金额和采购金额为字符串类型并优化Excel导入功能

- 将多个实体类中的involvedAmount字段由BigDecimal改为String类型
- 将CreditCustomer和CreditSupplier中的金额及日期字段调整为String类型
- 移除Excel导入时对金额字段的手动BigDecimal解析
- 增强ExcelImportSupport支持指定sheet索引读取功能
- 为CreditCustomer新增完整的Excel导入和模板下载接口
- 新增CreditCustomerImportParam用于导入数据映
This commit is contained in:
2025-12-22 10:16:56 +08:00
parent 42ebdf5653
commit 0c6cb13ca7
40 changed files with 228 additions and 57 deletions

View File

@@ -263,7 +263,7 @@ public class CreditBreachOfTrustController extends BaseController {
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setCaseNumber(param.getCaseNumber());
entity.setCauseOfAction(param.getCauseOfAction());
entity.setInvolvedAmount(ImportHelper.parseBigDecimal(param.getInvolvedAmount(), "涉案金额"));
entity.setInvolvedAmount(param.getInvolvedAmount());
entity.setCourtName(param.getCourtName());
entity.setDataStatus(param.getDataStatus());
entity.setComments(param.getComments());

View File

@@ -267,7 +267,7 @@ public class CreditCaseFilingController extends BaseController {
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setCaseNumber(param.getCaseNumber());
entity.setCauseOfAction(param.getCauseOfAction());
entity.setInvolvedAmount(ImportHelper.parseBigDecimal(param.getInvolvedAmount(), "涉案金额"));
entity.setInvolvedAmount(param.getInvolvedAmount());
entity.setCourtName(param.getCourtName());
entity.setDataStatus(param.getDataStatus());
entity.setComments(param.getComments());

View File

@@ -141,7 +141,7 @@ public class CreditCompetitorController extends BaseController {
try {
ExcelImportSupport.ImportResult<CreditCompetitorImportParam> importResult = ExcelImportSupport.read(
file, CreditCompetitorImportParam.class, this::isEmptyImportRow);
file, CreditCompetitorImportParam.class, this::isEmptyImportRow,2);
List<CreditCompetitorImportParam> list = importResult.getData();
int usedTitleRows = importResult.getTitleRows();
int usedHeadRows = importResult.getHeadRows();

View File

@@ -267,7 +267,7 @@ public class CreditCourtAnnouncementController extends BaseController {
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setCaseNumber(param.getCaseNumber());
entity.setCauseOfAction(param.getCauseOfAction());
entity.setInvolvedAmount(ImportHelper.parseBigDecimal(param.getInvolvedAmount(), "涉案金额"));
entity.setInvolvedAmount(param.getInvolvedAmount());
entity.setCourtName(param.getCourtName());
entity.setDataStatus(param.getDataStatus());
entity.setComments(param.getComments());

View File

@@ -267,7 +267,7 @@ public class CreditCourtSessionController extends BaseController {
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setCaseNumber(param.getCaseNumber());
entity.setCauseOfAction(param.getCauseOfAction());
entity.setInvolvedAmount(ImportHelper.parseBigDecimal(param.getInvolvedAmount(), "涉案金额"));
entity.setInvolvedAmount(param.getInvolvedAmount());
entity.setCourtName(param.getCourtName());
entity.setDataStatus(param.getDataStatus());
entity.setComments(param.getComments());

View File

@@ -5,15 +5,23 @@ import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.credit.entity.CreditCustomer;
import com.gxwebsoft.credit.param.CreditCustomerImportParam;
import com.gxwebsoft.credit.param.CreditCustomerParam;
import com.gxwebsoft.credit.service.CreditCustomerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
@@ -116,4 +124,139 @@ public class CreditCustomerController extends BaseController {
return fail("删除失败");
}
/**
* 批量导入客户
*/
@PreAuthorize("hasAuthority('credit:creditCustomer:save')")
@Operation(summary = "批量导入客户")
@PostMapping("/import")
public ApiResult<List<String>> importBatch(@RequestParam("file") MultipartFile file) {
List<String> errorMessages = new ArrayList<>();
int successCount = 0;
try {
ExcelImportSupport.ImportResult<CreditCustomerImportParam> importResult = ExcelImportSupport.read(
file, CreditCustomerImportParam.class, this::isEmptyImportRow,4);
List<CreditCustomerImportParam> list = importResult.getData();
int usedTitleRows = importResult.getTitleRows();
int usedHeadRows = importResult.getHeadRows();
if (CollectionUtils.isEmpty(list)) {
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
}
User loginUser = getLoginUser();
Integer currentUserId = loginUser != null ? loginUser.getUserId() : null;
Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;
for (int i = 0; i < list.size(); i++) {
CreditCustomerImportParam param = list.get(i);
try {
CreditCustomer item = convertImportParamToEntity(param);
if (item.getUserId() == null && currentUserId != null) {
item.setUserId(currentUserId);
}
if (item.getTenantId() == null && currentTenantId != null) {
item.setTenantId(currentTenantId);
}
if (item.getStatus() == null) {
item.setStatus(0);
}
if (item.getRecommend() == null) {
item.setRecommend(0);
}
if (item.getDeleted() == null) {
item.setDeleted(0);
}
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
if (ImportHelper.isBlank(item.getName())) {
errorMessages.add("" + excelRowNumber + "行:客户不能为空");
continue;
}
boolean saved = creditCustomerService.save(item);
if (!saved) {
CreditCustomer existing = creditCustomerService.lambdaQuery()
.eq(CreditCustomer::getName, item.getName())
.one();
if (existing != null) {
item.setId(existing.getId());
if (creditCustomerService.updateById(item)) {
successCount++;
continue;
}
}
} else {
successCount++;
continue;
}
errorMessages.add("" + excelRowNumber + "行:保存失败");
} catch (Exception e) {
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
errorMessages.add("" + excelRowNumber + "行:" + e.getMessage());
e.printStackTrace();
}
}
if (errorMessages.isEmpty()) {
return success("成功导入" + successCount + "条数据", null);
} else {
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "", errorMessages);
}
} catch (Exception e) {
e.printStackTrace();
return fail("导入失败:" + e.getMessage(), null);
}
}
/**
* 下载客户导入模板
*/
@Operation(summary = "下载客户导入模板")
@GetMapping("/import/template")
public void downloadTemplate(HttpServletResponse response) throws IOException {
List<CreditCustomerImportParam> templateList = new ArrayList<>();
CreditCustomerImportParam example = new CreditCustomerImportParam();
example.setName("示例客户");
example.setStatusTxt("合作中");
example.setPrice("88.8");
example.setPublicDate("2024-01-01");
example.setDataSource("公开渠道");
example.setComments("备注信息");
templateList.add(example);
Workbook workbook = ExcelImportSupport.buildTemplate("客户导入模板", "客户", CreditCustomerImportParam.class, templateList);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=credit_customer_import_template.xlsx");
workbook.write(response.getOutputStream());
workbook.close();
}
private boolean isEmptyImportRow(CreditCustomerImportParam param) {
if (param == null) {
return true;
}
return ImportHelper.isBlank(param.getName())
&& ImportHelper.isBlank(param.getStatusTxt())
&& ImportHelper.isBlank(param.getPrice());
}
private CreditCustomer convertImportParamToEntity(CreditCustomerImportParam param) {
CreditCustomer entity = new CreditCustomer();
entity.setName(param.getName());
entity.setStatusTxt(param.getStatusTxt());
entity.setPrice(param.getPrice());
entity.setPublicDate(param.getPublicDate());
entity.setDataSource(param.getDataSource());
entity.setComments(param.getComments());
return entity;
}
}

View File

@@ -267,7 +267,7 @@ public class CreditDeliveryNoticeController extends BaseController {
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setCaseNumber(param.getCaseNumber());
entity.setCauseOfAction(param.getCauseOfAction());
entity.setInvolvedAmount(ImportHelper.parseBigDecimal(param.getInvolvedAmount(), "涉案金额"));
entity.setInvolvedAmount(param.getInvolvedAmount());
entity.setCourtName(param.getCourtName());
entity.setDataStatus(param.getDataStatus());
entity.setComments(param.getComments());

View File

@@ -267,7 +267,7 @@ public class CreditFinalVersionController extends BaseController {
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setCaseNumber(param.getCaseNumber());
entity.setCauseOfAction(param.getCauseOfAction());
entity.setInvolvedAmount(ImportHelper.parseBigDecimal(param.getInvolvedAmount(), "涉案金额"));
entity.setInvolvedAmount(param.getInvolvedAmount());
entity.setCourtName(param.getCourtName());
entity.setDataStatus(param.getDataStatus());
entity.setComments(param.getComments());

View File

@@ -267,7 +267,7 @@ public class CreditGqdjController extends BaseController {
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setCaseNumber(param.getCaseNumber());
entity.setCauseOfAction(param.getCauseOfAction());
entity.setInvolvedAmount(ImportHelper.parseBigDecimal(param.getInvolvedAmount(), "涉案金额"));
entity.setInvolvedAmount(param.getInvolvedAmount());
entity.setCourtName(param.getCourtName());
entity.setDataStatus(param.getDataStatus());
entity.setComments(param.getComments());

View File

@@ -230,7 +230,6 @@ public class CreditJudgmentDebtorController extends BaseController {
example.setCode("1234567890");
example.setOccurrenceTime("2024-01-10");
example.setAmount("100000");
example.setCourtName("示例法院");
example.setDataStatus("已公开");
example.setComments("备注信息");
templateList.add(example);
@@ -261,7 +260,6 @@ public class CreditJudgmentDebtorController extends BaseController {
entity.setCode(param.getCode());
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setAmount(ImportHelper.parseBigDecimal(param.getAmount(), "执行标的(元)"));
entity.setCourtName(param.getCourtName());
entity.setDataStatus(param.getDataStatus());
entity.setComments(param.getComments());

View File

@@ -267,7 +267,7 @@ public class CreditJudicialDocumentController extends BaseController {
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setCaseNumber(param.getCaseNumber());
entity.setCauseOfAction(param.getCauseOfAction());
entity.setInvolvedAmount(ImportHelper.parseBigDecimal(param.getInvolvedAmount(), "涉案金额"));
entity.setInvolvedAmount(param.getInvolvedAmount());
entity.setCourtName(param.getCourtName());
entity.setDataStatus(param.getDataStatus());
entity.setComments(param.getComments());

View File

@@ -267,7 +267,7 @@ public class CreditMediationController extends BaseController {
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setCaseNumber(param.getCaseNumber());
entity.setCauseOfAction(param.getCauseOfAction());
entity.setInvolvedAmount(ImportHelper.parseBigDecimal(param.getInvolvedAmount(), "涉案金额"));
entity.setInvolvedAmount(param.getInvolvedAmount());
entity.setCourtName(param.getCourtName());
entity.setDataStatus(param.getDataStatus());
entity.setComments(param.getComments());

View File

@@ -140,8 +140,9 @@ public class CreditRiskRelationController extends BaseController {
int successCount = 0;
try {
// 风险关系数据位于第二个选项卡sheetIndex = 1
ExcelImportSupport.ImportResult<CreditRiskRelationImportParam> importResult = ExcelImportSupport.read(
file, CreditRiskRelationImportParam.class, this::isEmptyImportRow);
file, CreditRiskRelationImportParam.class, this::isEmptyImportRow, 1);
List<CreditRiskRelationImportParam> list = importResult.getData();
int usedTitleRows = importResult.getTitleRows();
int usedHeadRows = importResult.getHeadRows();

View File

@@ -141,7 +141,7 @@ public class CreditSupplierController extends BaseController {
try {
ExcelImportSupport.ImportResult<CreditSupplierImportParam> importResult = ExcelImportSupport.read(
file, CreditSupplierImportParam.class, this::isEmptyImportRow);
file, CreditSupplierImportParam.class, this::isEmptyImportRow,3);
List<CreditSupplierImportParam> list = importResult.getData();
int usedTitleRows = importResult.getTitleRows();
int usedHeadRows = importResult.getHeadRows();
@@ -256,8 +256,8 @@ public class CreditSupplierController extends BaseController {
entity.setSupplier(param.getSupplier());
entity.setStatusTxt(param.getStatusTxt());
entity.setPurchaseAmount(ImportHelper.parseBigDecimal(param.getPurchaseAmount(), "采购金额(万元)"));
entity.setPublicDate(ImportHelper.parseLocalDate(param.getPublicDate(), "公开日期"));
entity.setPurchaseAmount(param.getPurchaseAmount());
entity.setPublicDate(param.getPublicDate());
entity.setDataSource(param.getDataSource());
entity.setComments(param.getComments());

View File

@@ -267,7 +267,7 @@ public class CreditXgxfController extends BaseController {
entity.setOccurrenceTime(param.getOccurrenceTime());
entity.setCaseNumber(param.getCaseNumber());
entity.setCauseOfAction(param.getCauseOfAction());
entity.setInvolvedAmount(ImportHelper.parseBigDecimal(param.getInvolvedAmount(), "涉案金额"));
entity.setInvolvedAmount(param.getInvolvedAmount());
entity.setCourtName(param.getCourtName());
entity.setDataStatus(param.getDataStatus());
entity.setComments(param.getComments());

View File

@@ -41,13 +41,22 @@ public class ExcelImportSupport {
}
public static <T> ImportResult<T> read(MultipartFile file, Class<T> clazz, Predicate<T> emptyRowPredicate) throws Exception {
return read(file, clazz, emptyRowPredicate, 0);
}
/**
* 读取指定 sheet 的 Excel。
*
* @param sheetIndex 目标 sheet 下标,从 0 开始。第二个选项卡传 1。
*/
public static <T> ImportResult<T> read(MultipartFile file, Class<T> clazz, Predicate<T> emptyRowPredicate, int sheetIndex) throws Exception {
List<T> list = null;
int usedTitleRows = 0;
int usedHeadRows = 0;
int[][] tryConfigs = new int[][]{{1, 1}, {0, 1}, {0, 2}, {0, 3}};
for (int[] config : tryConfigs) {
list = filterEmptyRows(importSheet(file, clazz, config[0], config[1]), emptyRowPredicate);
list = filterEmptyRows(importSheet(file, clazz, config[0], config[1], sheetIndex), emptyRowPredicate);
if (!CollectionUtils.isEmpty(list)) {
usedTitleRows = config[0];
usedHeadRows = config[1];
@@ -57,11 +66,11 @@ public class ExcelImportSupport {
return new ImportResult<>(list, usedTitleRows, usedHeadRows);
}
private static <T> List<T> importSheet(MultipartFile file, Class<T> clazz, int titleRows, int headRows) throws Exception {
private static <T> List<T> importSheet(MultipartFile file, Class<T> clazz, int titleRows, int headRows, int sheetIndex) throws Exception {
ImportParams importParams = new ImportParams();
importParams.setTitleRows(titleRows);
importParams.setHeadRows(headRows);
importParams.setStartSheetIndex(0);
importParams.setStartSheetIndex(sheetIndex);
importParams.setSheetNum(1);
return ExcelImportUtil.importExcel(file.getInputStream(), clazz, importParams);
}

View File

@@ -53,7 +53,7 @@ public class CreditBreachOfTrust implements Serializable {
private String causeOfAction;
@Schema(description = "涉案金额")
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -53,7 +53,7 @@ public class CreditCaseFiling implements Serializable {
private String causeOfAction;
@Schema(description = "涉案金额")
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -53,7 +53,7 @@ public class CreditCourtAnnouncement implements Serializable {
private String causeOfAction;
@Schema(description = "涉案金额")
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -53,7 +53,7 @@ public class CreditCourtSession implements Serializable {
private String causeOfAction;
@Schema(description = "涉案金额")
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -36,11 +36,10 @@ public class CreditCustomer implements Serializable {
private String statusTxt;
@Schema(description = "销售金额(万元)")
private BigDecimal price;
private String price;
@Schema(description = "公开日期")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate publicDate;
private String publicDate;
@Schema(description = "数据来源")
private String dataSource;

View File

@@ -53,7 +53,7 @@ public class CreditDeliveryNotice implements Serializable {
private String causeOfAction;
@Schema(description = "涉案金额")
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -53,7 +53,7 @@ public class CreditFinalVersion implements Serializable {
private String causeOfAction;
@Schema(description = "涉案金额")
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -53,7 +53,7 @@ public class CreditGqdj implements Serializable {
private String causeOfAction;
@Schema(description = "涉案金额")
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -53,7 +53,7 @@ public class CreditJudicialDocument implements Serializable {
private String causeOfAction;
@Schema(description = "涉案金额")
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -53,7 +53,7 @@ public class CreditMediation implements Serializable {
private String causeOfAction;
@Schema(description = "涉案金额")
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -36,11 +36,10 @@ public class CreditSupplier implements Serializable {
private String statusTxt;
@Schema(description = "采购金额(万元)")
private BigDecimal purchaseAmount;
private String purchaseAmount;
@Schema(description = "公开日期")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate publicDate;
private String publicDate;
@Schema(description = "数据来源")
private String dataSource;

View File

@@ -53,7 +53,7 @@ public class CreditXgxf implements Serializable {
private String causeOfAction;
@Schema(description = "涉案金额")
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -50,7 +50,7 @@ public class CreditBreachOfTrustParam extends BaseParam {
@Schema(description = "涉案金额")
@QueryField(type = QueryType.EQ)
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -49,8 +49,7 @@ public class CreditCaseFilingParam extends BaseParam {
private String causeOfAction;
@Schema(description = "涉案金额")
@QueryField(type = QueryType.EQ)
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -49,8 +49,7 @@ public class CreditCourtAnnouncementParam extends BaseParam {
private String causeOfAction;
@Schema(description = "涉案金额")
@QueryField(type = QueryType.EQ)
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -49,8 +49,7 @@ public class CreditCourtSessionParam extends BaseParam {
private String causeOfAction;
@Schema(description = "涉案金额")
@QueryField(type = QueryType.EQ)
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -0,0 +1,32 @@
package com.gxwebsoft.credit.param;
import cn.afterturn.easypoi.excel.annotation.Excel;
import lombok.Data;
import java.io.Serializable;
/**
* 客户导入参数
*/
@Data
public class CreditCustomerImportParam implements Serializable {
private static final long serialVersionUID = 1L;
@Excel(name = "客户")
private String name;
@Excel(name = "状态")
private String statusTxt;
@Excel(name = "销售金额(万元)")
private String price;
@Excel(name = "公开日期")
private String publicDate;
@Excel(name = "数据来源")
private String dataSource;
@Excel(name = "备注")
private String comments;
}

View File

@@ -49,8 +49,7 @@ public class CreditDeliveryNoticeParam extends BaseParam {
private String causeOfAction;
@Schema(description = "涉案金额")
@QueryField(type = QueryType.EQ)
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -49,8 +49,7 @@ public class CreditFinalVersionParam extends BaseParam {
private String causeOfAction;
@Schema(description = "涉案金额")
@QueryField(type = QueryType.EQ)
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -49,8 +49,7 @@ public class CreditGqdjParam extends BaseParam {
private String causeOfAction;
@Schema(description = "涉案金额")
@QueryField(type = QueryType.EQ)
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -49,8 +49,7 @@ public class CreditJudicialDocumentParam extends BaseParam {
private String causeOfAction;
@Schema(description = "涉案金额")
@QueryField(type = QueryType.EQ)
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -49,8 +49,7 @@ public class CreditMediationParam extends BaseParam {
private String causeOfAction;
@Schema(description = "涉案金额")
@QueryField(type = QueryType.EQ)
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;

View File

@@ -34,8 +34,7 @@ public class CreditSupplierParam extends BaseParam {
private String statusTxt;
@Schema(description = "采购金额(万元)")
@QueryField(type = QueryType.EQ)
private BigDecimal purchaseAmount;
private String purchaseAmount;
@Schema(description = "公开日期")
private String publicDate;

View File

@@ -49,8 +49,7 @@ public class CreditXgxfParam extends BaseParam {
private String causeOfAction;
@Schema(description = "涉案金额")
@QueryField(type = QueryType.EQ)
private BigDecimal involvedAmount;
private String involvedAmount;
@Schema(description = "法院")
private String courtName;