Files
mp-java/src/main/java/com/gxwebsoft/credit/controller/CreditXgxfController.java
gxwebsoft f8d134a330 feat(controller): 更新批量导入公司ID匹配逻辑
- 将公司名称匹配方法从精确匹配改为包含匹配模式
- 添加当事人角色字段的优先级处理机制:原告/上诉人 > 被告/被上诉人 > 其他当事人/第三人
- 在多个控制器中统一实现新的匹配策略
- 为CreditJudgmentDebtorController添加备用名称字段回退机制
- 移除原有的单一字段匹配参数,改用多角色字段组合匹配
2026-02-06 18:42:04 +08:00

630 lines
28 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.gxwebsoft.credit.controller;
import com.gxwebsoft.common.core.annotation.OperationLog;
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.CreditXgxf;
import com.gxwebsoft.credit.param.CreditXgxfImportParam;
import com.gxwebsoft.credit.param.CreditXgxfParam;
import com.gxwebsoft.credit.service.CreditCompanyService;
import com.gxwebsoft.credit.service.CreditCompanyRecordCountService;
import com.gxwebsoft.credit.service.CreditXgxfService;
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.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 限制高消费控制器
*
* @author 科技小王子
* @since 2025-12-19 19:51:55
*/
@Tag(name = "限制高消费管理")
@RestController
@RequestMapping("/api/credit/credit-xgxf")
public class CreditXgxfController extends BaseController {
@Resource
private CreditXgxfService creditXgxfService;
@Resource
private BatchImportSupport batchImportSupport;
@Resource
private CreditCompanyService creditCompanyService;
@Resource
private CreditCompanyRecordCountService creditCompanyRecordCountService;
@Operation(summary = "分页查询限制高消费")
@GetMapping("/page")
public ApiResult<PageResult<CreditXgxf>> page(CreditXgxfParam param) {
// 使用关联查询
return success(creditXgxfService.pageRel(param));
}
@Operation(summary = "查询全部限制高消费")
@GetMapping()
public ApiResult<List<CreditXgxf>> list(CreditXgxfParam param) {
// 使用关联查询
return success(creditXgxfService.listRel(param));
}
@Operation(summary = "根据id查询限制高消费")
@GetMapping("/{id}")
public ApiResult<CreditXgxf> get(@PathVariable("id") Integer id) {
// 使用关联查询
return success(creditXgxfService.getByIdRel(id));
}
@PreAuthorize("hasAuthority('credit:creditXgxf:save')")
@OperationLog
@Operation(summary = "添加限制高消费")
@PostMapping()
public ApiResult<?> save(@RequestBody CreditXgxf creditXgxf) {
// 记录当前登录用户id
// User loginUser = getLoginUser();
// if (loginUser != null) {
// creditXgxf.setUserId(loginUser.getUserId());
// }
if (creditXgxfService.save(creditXgxf)) {
return success("添加成功");
}
return fail("添加失败");
}
@PreAuthorize("hasAuthority('credit:creditXgxf:update')")
@OperationLog
@Operation(summary = "修改限制高消费")
@PutMapping()
public ApiResult<?> update(@RequestBody CreditXgxf creditXgxf) {
if (creditXgxfService.updateById(creditXgxf)) {
return success("修改成功");
}
return fail("修改失败");
}
@PreAuthorize("hasAuthority('credit:creditXgxf:remove')")
@OperationLog
@Operation(summary = "删除限制高消费")
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (creditXgxfService.removeById(id)) {
return success("删除成功");
}
return fail("删除失败");
}
@PreAuthorize("hasAuthority('credit:creditXgxf:save')")
@OperationLog
@Operation(summary = "批量添加限制高消费")
@PostMapping("/batch")
public ApiResult<?> saveBatch(@RequestBody List<CreditXgxf> list) {
if (creditXgxfService.saveBatch(list)) {
return success("添加成功");
}
return fail("添加失败");
}
@PreAuthorize("hasAuthority('credit:creditXgxf:update')")
@OperationLog
@Operation(summary = "批量修改限制高消费")
@PutMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody BatchParam<CreditXgxf> batchParam) {
if (batchParam.update(creditXgxfService, "id")) {
return success("修改成功");
}
return fail("修改失败");
}
@PreAuthorize("hasAuthority('credit:creditXgxf:remove')")
@OperationLog
@Operation(summary = "批量删除限制高消费")
@DeleteMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
if (creditXgxfService.removeByIds(ids)) {
return success("删除成功");
}
return fail("删除失败");
}
/**
* 根据企业名称匹配企业并更新 companyId匹配 CreditCompany.name / CreditCompany.matchName
*
* <p>默认仅更新 companyId=0 的记录;如需覆盖更新,传 onlyNull=false。</p>
*/
@PreAuthorize("hasAuthority('credit:creditXgxf:update')")
@OperationLog
@Operation(summary = "根据企业名称匹配并更新companyId")
@PostMapping("/company-id/refresh")
public ApiResult<Map<String, Object>> refreshCompanyIdByCompanyName(
@RequestParam(value = "onlyNull", required = false, defaultValue = "true") Boolean onlyNull,
@RequestParam(value = "limit", required = false) Integer limit
) {
User loginUser = getLoginUser();
Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;
// Party columns may contain multiple roles/names; match if any company name is contained in the text.
// Priority: 原告/上诉人 > 被告/被上诉人 > 其他当事人/第三人
BatchImportSupport.CompanyIdRefreshStats stats = batchImportSupport.refreshCompanyIdByCompanyNameContainedInText(
creditXgxfService,
creditCompanyService,
currentTenantId,
onlyNull,
limit,
CreditXgxf::getId,
CreditXgxf::setId,
CreditXgxf::getCompanyId,
CreditXgxf::setCompanyId,
CreditXgxf::getHasData,
CreditXgxf::setHasData,
CreditXgxf::getTenantId,
CreditXgxf::new,
CreditXgxf::getPlaintiffAppellant,
CreditXgxf::getAppellee,
CreditXgxf::getOtherPartiesThirdParty
);
if (!stats.anyDataRead) {
return success("无可更新数据", stats.toMap());
}
return success("更新完成,更新" + stats.updated + "", stats.toMap());
}
/**
* 批量导入限制高消费司法大数据
*/
@PreAuthorize("hasAuthority('credit:creditXgxf:save')")
@Operation(summary = "批量导入限制高消费司法大数据")
@PostMapping("/import")
public ApiResult<List<String>> importBatch(@RequestParam("file") MultipartFile file,
@RequestParam(value = "companyId", required = false) Integer companyId) {
List<String> errorMessages = new ArrayList<>();
int successCount = 0;
Set<Integer> touchedCompanyIds = new HashSet<>();
try {
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "限制高消费", 0);
ExcelImportSupport.ImportResult<CreditXgxfImportParam> importResult = ExcelImportSupport.read(
file, CreditXgxfImportParam.class, this::isEmptyImportRow, sheetIndex);
List<CreditXgxfImportParam> list = importResult.getData();
int usedTitleRows = importResult.getTitleRows();
int usedHeadRows = importResult.getHeadRows();
int usedSheetIndex = importResult.getSheetIndex();
if (CollectionUtils.isEmpty(list)) {
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
}
User loginUser = getLoginUser();
Integer currentUserId = loginUser != null ? loginUser.getUserId() : null;
Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;
// easypoi 默认不会读取单元格超链接地址url 可能挂在“案号”等列的超链接中,或单独提供 url/网址/链接 列。
Map<String, String> urlByCaseNumber = ExcelImportSupport.readUrlByKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "案号");
final int chunkSize = 500;
final int mpBatchSize = 500;
List<CreditXgxf> chunkItems = new ArrayList<>(chunkSize);
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
for (int i = 0; i < list.size(); i++) {
CreditXgxfImportParam param = list.get(i);
try {
CreditXgxf item = convertImportParamToEntity(param);
if (!ImportHelper.isBlank(item.getCaseNumber())) {
String link = urlByCaseNumber.get(item.getCaseNumber().trim());
if (!ImportHelper.isBlank(link)) {
item.setUrl(link.trim());
}
}
if (item.getCompanyId() == null && companyId != null) {
item.setCompanyId(companyId);
}
if (item.getCompanyId() != null && item.getCompanyId() > 0) {
touchedCompanyIds.add(item.getCompanyId());
}
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.getCaseNumber())) {
errorMessages.add("" + excelRowNumber + "行:案号不能为空");
continue;
}
if (item.getCompanyId() != null && item.getCompanyId() > 0) {
touchedCompanyIds.add(item.getCompanyId());
}
chunkItems.add(item);
chunkRowNumbers.add(excelRowNumber);
if (chunkItems.size() >= chunkSize) {
successCount += batchImportSupport.persistChunkWithFallback(
chunkItems,
chunkRowNumbers,
() -> batchImportSupport.upsertBySingleKey(
creditXgxfService,
chunkItems,
CreditXgxf::getId,
CreditXgxf::setId,
CreditXgxf::getCaseNumber,
CreditXgxf::getCaseNumber,
null,
mpBatchSize
),
(rowItem, rowNumber) -> {
boolean saved = creditXgxfService.save(rowItem);
if (!saved) {
CreditXgxf existing = creditXgxfService.lambdaQuery()
.eq(CreditXgxf::getCaseNumber, rowItem.getCaseNumber())
.one();
if (existing != null) {
rowItem.setId(existing.getId());
if (creditXgxfService.updateById(rowItem)) {
return true;
}
}
} else {
return true;
}
String prefix = rowNumber > 0 ? ("" + rowNumber + "行:") : "";
errorMessages.add(prefix + "保存失败");
return false;
},
errorMessages
);
chunkItems.clear();
chunkRowNumbers.clear();
}
} catch (Exception e) {
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
errorMessages.add("" + excelRowNumber + "行:" + e.getMessage());
e.printStackTrace();
}
}
if (!chunkItems.isEmpty()) {
successCount += batchImportSupport.persistChunkWithFallback(
chunkItems,
chunkRowNumbers,
() -> batchImportSupport.upsertBySingleKey(
creditXgxfService,
chunkItems,
CreditXgxf::getId,
CreditXgxf::setId,
CreditXgxf::getCaseNumber,
CreditXgxf::getCaseNumber,
null,
mpBatchSize
),
(rowItem, rowNumber) -> {
boolean saved = creditXgxfService.save(rowItem);
if (!saved) {
CreditXgxf existing = creditXgxfService.lambdaQuery()
.eq(CreditXgxf::getCaseNumber, rowItem.getCaseNumber())
.one();
if (existing != null) {
rowItem.setId(existing.getId());
if (creditXgxfService.updateById(rowItem)) {
return true;
}
}
} else {
return true;
}
String prefix = rowNumber > 0 ? ("" + rowNumber + "行:") : "";
errorMessages.add(prefix + "保存失败");
return false;
},
errorMessages
);
}
creditCompanyRecordCountService.refresh(CreditCompanyRecordCountService.CountType.XGXF, touchedCompanyIds);
if (errorMessages.isEmpty()) {
return success("成功导入" + successCount + "条数据", null);
} else {
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "", errorMessages);
}
} catch (Exception e) {
e.printStackTrace();
return fail("导入失败:" + e.getMessage(), null);
}
}
/**
* 批量导入历史限制高消费(仅解析“历史限制高消费”选项卡)
* 规则案号相同则覆盖更新recommend++ 记录更新次数);案号不存在则插入。
*/
@PreAuthorize("hasAuthority('credit:creditXgxf:save')")
@Operation(summary = "批量导入历史限制高消费司法大数据")
@PostMapping("/import/history")
public ApiResult<List<String>> importHistoryBatch(@RequestParam("file") MultipartFile file,
@RequestParam(value = "companyId", required = false) Integer companyId) {
List<String> errorMessages = new ArrayList<>();
int successCount = 0;
Set<Integer> touchedCompanyIds = new HashSet<>();
try {
int sheetIndex = ExcelImportSupport.findSheetIndex(file, "历史限制高消费");
if (sheetIndex < 0) {
return fail("未读取到数据,请确认文件中存在“历史限制高消费”选项卡且表头与示例格式一致", null);
}
ExcelImportSupport.ImportResult<CreditXgxfImportParam> importResult = ExcelImportSupport.read(
file, CreditXgxfImportParam.class, this::isEmptyImportRow, sheetIndex);
List<CreditXgxfImportParam> list = importResult.getData();
int usedTitleRows = importResult.getTitleRows();
int usedHeadRows = importResult.getHeadRows();
int usedSheetIndex = importResult.getSheetIndex();
if (CollectionUtils.isEmpty(list)) {
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
}
User loginUser = getLoginUser();
Integer currentUserId = loginUser != null ? loginUser.getUserId() : null;
Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;
Map<String, String> urlByCaseNumber = ExcelImportSupport.readUrlByKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "案号");
LinkedHashMap<String, CreditXgxf> latestByCaseNumber = new LinkedHashMap<>();
LinkedHashMap<String, Integer> latestRowByCaseNumber = new LinkedHashMap<>();
for (int i = 0; i < list.size(); i++) {
CreditXgxfImportParam param = list.get(i);
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
try {
CreditXgxf item = convertImportParamToEntity(param);
if (item.getCaseNumber() != null) {
item.setCaseNumber(item.getCaseNumber().trim());
}
if (ImportHelper.isBlank(item.getCaseNumber())) {
errorMessages.add("" + excelRowNumber + "行:案号不能为空");
continue;
}
String link = urlByCaseNumber.get(item.getCaseNumber());
if (!ImportHelper.isBlank(link)) {
item.setUrl(link.trim());
}
if (item.getCompanyId() == null && companyId != null) {
item.setCompanyId(companyId);
}
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.getDeleted() == null) {
item.setDeleted(0);
}
// 历史导入的数据统一标记为“失效”
item.setDataStatus("失效");
latestByCaseNumber.put(item.getCaseNumber(), item);
latestRowByCaseNumber.put(item.getCaseNumber(), excelRowNumber);
} catch (Exception e) {
errorMessages.add("" + excelRowNumber + "行:" + e.getMessage());
e.printStackTrace();
}
}
if (latestByCaseNumber.isEmpty()) {
if (errorMessages.isEmpty()) {
return fail("未读取到数据,请确认模板表头与示例格式一致", null);
}
return success("导入完成成功0条失败" + errorMessages.size() + "", errorMessages);
}
final int chunkSize = 500;
final int mpBatchSize = 500;
List<CreditXgxf> chunkItems = new ArrayList<>(chunkSize);
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
for (Map.Entry<String, CreditXgxf> entry : latestByCaseNumber.entrySet()) {
String caseNumber = entry.getKey();
CreditXgxf item = entry.getValue();
Integer rowNo = latestRowByCaseNumber.get(caseNumber);
chunkItems.add(item);
chunkRowNumbers.add(rowNo != null ? rowNo : -1);
if (chunkItems.size() >= chunkSize) {
successCount += batchImportSupport.persistChunkWithFallback(
chunkItems,
chunkRowNumbers,
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
creditXgxfService,
chunkItems,
CreditXgxf::getId,
CreditXgxf::setId,
CreditXgxf::getCaseNumber,
CreditXgxf::getCaseNumber,
CreditXgxf::getRecommend,
CreditXgxf::setRecommend,
null,
mpBatchSize
),
(rowItem, rowNumber) -> {
if (rowItem.getRecommend() == null) {
rowItem.setRecommend(0);
}
boolean saved = creditXgxfService.save(rowItem);
if (!saved) {
CreditXgxf existing = creditXgxfService.lambdaQuery()
.eq(CreditXgxf::getCaseNumber, rowItem.getCaseNumber())
.select(CreditXgxf::getId, CreditXgxf::getRecommend)
.one();
if (existing != null) {
rowItem.setId(existing.getId());
Integer old = existing.getRecommend();
rowItem.setRecommend(old == null ? 1 : old + 1);
if (creditXgxfService.updateById(rowItem)) {
return true;
}
}
} else {
return true;
}
String prefix = rowNumber > 0 ? ("" + rowNumber + "行:") : "";
errorMessages.add(prefix + "保存失败");
return false;
},
errorMessages
);
chunkItems.clear();
chunkRowNumbers.clear();
}
}
if (!chunkItems.isEmpty()) {
successCount += batchImportSupport.persistChunkWithFallback(
chunkItems,
chunkRowNumbers,
() -> batchImportSupport.upsertBySingleKeyAndIncrementCounterOnUpdate(
creditXgxfService,
chunkItems,
CreditXgxf::getId,
CreditXgxf::setId,
CreditXgxf::getCaseNumber,
CreditXgxf::getCaseNumber,
CreditXgxf::getRecommend,
CreditXgxf::setRecommend,
null,
mpBatchSize
),
(rowItem, rowNumber) -> {
if (rowItem.getRecommend() == null) {
rowItem.setRecommend(0);
}
boolean saved = creditXgxfService.save(rowItem);
if (!saved) {
CreditXgxf existing = creditXgxfService.lambdaQuery()
.eq(CreditXgxf::getCaseNumber, rowItem.getCaseNumber())
.select(CreditXgxf::getId, CreditXgxf::getRecommend)
.one();
if (existing != null) {
rowItem.setId(existing.getId());
Integer old = existing.getRecommend();
rowItem.setRecommend(old == null ? 1 : old + 1);
if (creditXgxfService.updateById(rowItem)) {
return true;
}
}
} else {
return true;
}
String prefix = rowNumber > 0 ? ("" + rowNumber + "行:") : "";
errorMessages.add(prefix + "保存失败");
return false;
},
errorMessages
);
}
creditCompanyRecordCountService.refresh(CreditCompanyRecordCountService.CountType.XGXF, touchedCompanyIds);
if (errorMessages.isEmpty()) {
return success("成功导入" + successCount + "条数据", null);
}
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<CreditXgxfImportParam> templateList = new ArrayList<>();
CreditXgxfImportParam example = new CreditXgxfImportParam();
example.setDataType("限制高消费");
example.setPlaintiffAppellant("原告示例");
example.setAppellee("被告示例");
example.setOccurrenceTime("2024-01-01");
example.setCaseNumber("2024示例案号");
example.setInvolvedAmount("100000");
example.setCourtName("示例法院");
example.setComments("备注信息");
templateList.add(example);
Workbook workbook = ExcelImportSupport.buildTemplate("限制高消费导入模板", "限制高消费", CreditXgxfImportParam.class, templateList);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=credit_xgxf_import_template.xlsx");
workbook.write(response.getOutputStream());
workbook.close();
}
private boolean isEmptyImportRow(CreditXgxfImportParam param) {
if (param == null) {
return true;
}
return ImportHelper.isBlank(param.getCaseNumber());
}
private CreditXgxf convertImportParamToEntity(CreditXgxfImportParam param) {
CreditXgxf entity = new CreditXgxf();
entity.setCaseNumber(param.getCaseNumber());
entity.setType(param.getType());
entity.setDataType(param.getDataType());
entity.setPlaintiffAppellant(param.getPlaintiffAppellant());
entity.setAppellee(param.getAppellee());
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.setReleaseDate(param.getReleaseDate());
entity.setComments(param.getComments());
return entity;
}
}