diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java index 4a95a51f..33a3dcc7 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java @@ -144,4 +144,14 @@ public class CcdiProjectOverviewController extends BaseController { new ExcelUtil<>(CcdiProjectSuspiciousTransactionExcel.class); util.exportExcel(response, rows, "涉疑交易明细"); } + + /** + * 导出风险明细 + */ + @PostMapping("/risk-details/export") + @Operation(summary = "导出风险明细") + @PreAuthorize("@ss.hasPermi('ccdi:project:query')") + public void exportRiskDetails(HttpServletResponse response, Long projectId) { + overviewService.exportRiskDetails(response, projectId); + } } diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectEmployeeCreditNegativeExcel.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectEmployeeCreditNegativeExcel.java new file mode 100644 index 00000000..72891926 --- /dev/null +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectEmployeeCreditNegativeExcel.java @@ -0,0 +1,40 @@ +package com.ruoyi.ccdi.project.domain.excel; + +import com.ruoyi.common.annotation.Excel; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 项目员工负面征信导出对象 + */ +@Data +public class CcdiProjectEmployeeCreditNegativeExcel { + + @Excel(name = "员工姓名") + private String personName; + + @Excel(name = "身份证号") + private String personId; + + @Excel(name = "最近征信查询日期") + private String queryDate; + + @Excel(name = "民事案件笔数") + private Integer civilCnt; + + @Excel(name = "民事案件金额") + private BigDecimal civilLmt; + + @Excel(name = "强制执行笔数") + private Integer enforceCnt; + + @Excel(name = "强制执行金额") + private BigDecimal enforceLmt; + + @Excel(name = "行政处罚笔数") + private Integer admCnt; + + @Excel(name = "行政处罚金额") + private BigDecimal admLmt; +} diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java index 8a35a320..46e2a4e4 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java @@ -98,6 +98,14 @@ public interface CcdiProjectOverviewMapper { @Param("query") CcdiProjectEmployeeCreditNegativeQueryDTO query ); + /** + * 查询项目员工负面征信导出列表 + * + * @param projectId 项目ID + * @return 导出列表 + */ + List selectEmployeeCreditNegativeList(@Param("projectId") Long projectId); + /** * 查询涉疑交易导出列表 * diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java index 09770960..0cf16d87 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java @@ -5,6 +5,7 @@ import com.ruoyi.ccdi.project.domain.dto.CcdiProjectPersonAnalysisDetailQueryDTO import com.ruoyi.ccdi.project.domain.dto.CcdiProjectRiskModelPeopleQueryDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiProjectRiskPeopleQueryDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiProjectSuspiciousTransactionQueryDTO; +import com.ruoyi.ccdi.project.domain.excel.CcdiProjectEmployeeCreditNegativeExcel; import com.ruoyi.ccdi.project.domain.excel.CcdiProjectSuspiciousTransactionExcel; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectEmployeeCreditNegativePageVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectPersonAnalysisDetailVO; @@ -14,6 +15,7 @@ import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelPeopleVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskPeopleOverviewVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectSuspiciousTransactionPageVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectTopRiskPeopleVO; +import jakarta.servlet.http.HttpServletResponse; import java.util.List; @@ -100,6 +102,25 @@ public interface ICcdiProjectOverviewService { return List.of(); } + /** + * 统一导出风险明细 + * + * @param response 响应流 + * @param projectId 项目ID + */ + default void exportRiskDetails(HttpServletResponse response, Long projectId) { + } + + /** + * 导出项目员工负面征信 + * + * @param projectId 项目ID + * @return 导出列表 + */ + default List exportEmployeeCreditNegative(Long projectId) { + return List.of(); + } + /** * 查询项目员工负面征信 * diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java index 2a9bd280..e891605e 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java @@ -7,6 +7,7 @@ import com.ruoyi.ccdi.project.domain.dto.CcdiProjectPersonAnalysisDetailQueryDTO import com.ruoyi.ccdi.project.domain.dto.CcdiProjectRiskModelPeopleQueryDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiProjectRiskPeopleQueryDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiProjectSuspiciousTransactionQueryDTO; +import com.ruoyi.ccdi.project.domain.excel.CcdiProjectEmployeeCreditNegativeExcel; import com.ruoyi.ccdi.project.domain.excel.CcdiProjectSuspiciousTransactionExcel; import com.ruoyi.ccdi.project.domain.entity.CcdiProjectOverviewEmployeeResult; import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementListVO; @@ -37,7 +38,9 @@ import com.ruoyi.ccdi.project.mapper.CcdiProjectOverviewEmployeeResultMapper; import com.ruoyi.ccdi.project.mapper.CcdiProjectOverviewMapper; import com.ruoyi.ccdi.project.service.ICcdiProjectOverviewService; import com.ruoyi.common.exception.ServiceException; +import jakarta.servlet.http.HttpServletResponse; import jakarta.annotation.Resource; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; @@ -70,6 +73,9 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi @Resource private CcdiProjectOverviewEmployeeResultBuilder overviewEmployeeResultBuilder; + @Resource + private CcdiProjectRiskDetailWorkbookExporter workbookExporter; + @Override public CcdiProjectOverviewDashboardVO getDashboard(Long projectId) { CcdiProject project = overviewMapper.selectDashboardBaseByProjectId(projectId); @@ -241,6 +247,30 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi return result; } + @Override + public void exportRiskDetails(HttpServletResponse response, Long projectId) { + CcdiProjectSuspiciousTransactionQueryDTO queryDTO = new CcdiProjectSuspiciousTransactionQueryDTO(); + queryDTO.setProjectId(projectId); + queryDTO.setSuspiciousType("ALL"); + + List suspiciousRows = exportSuspiciousTransactions(queryDTO); + List creditRows = exportEmployeeCreditNegative(projectId); + try { + workbookExporter.export(response, projectId, suspiciousRows, creditRows); + } catch (IOException e) { + throw new ServiceException("导出风险明细失败"); + } + } + + @Override + public List exportEmployeeCreditNegative(Long projectId) { + ensureProjectExists(projectId); + + return defaultList(overviewMapper.selectEmployeeCreditNegativeList(projectId)).stream() + .map(this::buildEmployeeCreditNegativeExcelRow) + .toList(); + } + @Override @Transactional(rollbackFor = Exception.class) public void refreshOverviewEmployeeResults(Long projectId, String operator) { @@ -393,6 +423,22 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi return row; } + private CcdiProjectEmployeeCreditNegativeExcel buildEmployeeCreditNegativeExcelRow( + CcdiProjectEmployeeCreditNegativeItemVO item + ) { + CcdiProjectEmployeeCreditNegativeExcel row = new CcdiProjectEmployeeCreditNegativeExcel(); + row.setPersonName(item.getPersonName()); + row.setPersonId(item.getPersonId()); + row.setQueryDate(item.getQueryDate()); + row.setCivilCnt(item.getCivilCnt()); + row.setCivilLmt(item.getCivilLmt()); + row.setEnforceCnt(item.getEnforceCnt()); + row.setEnforceLmt(item.getEnforceLmt()); + row.setAdmCnt(item.getAdmCnt()); + row.setAdmLmt(item.getAdmLmt()); + return row; + } + private String formatRelatedStaff(String relatedStaffName, String relatedStaffCode) { if (relatedStaffName == null || relatedStaffName.isBlank()) { return null; diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporter.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporter.java new file mode 100644 index 00000000..215c722e --- /dev/null +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporter.java @@ -0,0 +1,110 @@ +package com.ruoyi.ccdi.project.service.impl; + +import com.ruoyi.ccdi.project.domain.excel.CcdiProjectEmployeeCreditNegativeExcel; +import com.ruoyi.ccdi.project.domain.excel.CcdiProjectSuspiciousTransactionExcel; +import com.ruoyi.common.utils.file.FileUtils; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; + +/** + * 风险明细工作簿导出器 + */ +@Component +public class CcdiProjectRiskDetailWorkbookExporter { + + private static final String CONTENT_TYPE = + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + + public void export( + HttpServletResponse response, + Long projectId, + List suspiciousRows, + List creditRows + ) throws IOException { + response.setContentType(CONTENT_TYPE); + FileUtils.setAttachmentResponseHeader(response, "风险明细_" + projectId + ".xlsx"); + + try (Workbook workbook = new XSSFWorkbook()) { + writeSuspiciousSheet(workbook.createSheet("涉疑交易明细"), suspiciousRows); + writeCreditSheet(workbook.createSheet("员工负面征信信息"), creditRows); + writeAbnormalAccountSheet(workbook.createSheet("异常账户人员信息")); + workbook.write(response.getOutputStream()); + } + } + + private void writeSuspiciousSheet(Sheet sheet, List rows) { + Row header = sheet.createRow(0); + String[] headers = { "交易时间", "可疑人员", "关联人", "关联员工", "关系", "摘要/交易类型", "交易金额" }; + writeHeader(header, headers); + + for (int i = 0; i < rows.size(); i++) { + CcdiProjectSuspiciousTransactionExcel item = rows.get(i); + Row row = sheet.createRow(i + 1); + row.createCell(0).setCellValue(safeText(item.getTrxDate())); + row.createCell(1).setCellValue(safeText(item.getSuspiciousPersonName())); + row.createCell(2).setCellValue(safeText(item.getRelatedPersonName())); + row.createCell(3).setCellValue(safeText(item.getRelatedStaffDisplay())); + row.createCell(4).setCellValue(safeText(item.getRelationType())); + row.createCell(5).setCellValue(safeText(item.getSummaryAndCashType())); + row.createCell(6).setCellValue(safeNumber(item.getDisplayAmount())); + } + } + + private void writeCreditSheet(Sheet sheet, List rows) { + Row header = sheet.createRow(0); + String[] headers = { + "员工姓名", + "身份证号", + "最近征信查询日期", + "民事案件笔数", + "民事案件金额", + "强制执行笔数", + "强制执行金额", + "行政处罚笔数", + "行政处罚金额" + }; + writeHeader(header, headers); + + for (int i = 0; i < rows.size(); i++) { + CcdiProjectEmployeeCreditNegativeExcel item = rows.get(i); + Row row = sheet.createRow(i + 1); + row.createCell(0).setCellValue(safeText(item.getPersonName())); + row.createCell(1).setCellValue(safeText(item.getPersonId())); + row.createCell(2).setCellValue(safeText(item.getQueryDate())); + row.createCell(3).setCellValue(item.getCivilCnt() == null ? 0 : item.getCivilCnt()); + row.createCell(4).setCellValue(safeNumber(item.getCivilLmt())); + row.createCell(5).setCellValue(item.getEnforceCnt() == null ? 0 : item.getEnforceCnt()); + row.createCell(6).setCellValue(safeNumber(item.getEnforceLmt())); + row.createCell(7).setCellValue(item.getAdmCnt() == null ? 0 : item.getAdmCnt()); + row.createCell(8).setCellValue(safeNumber(item.getAdmLmt())); + } + } + + private void writeAbnormalAccountSheet(Sheet sheet) { + Row header = sheet.createRow(0); + String[] headers = { "账号", "开户人", "银行", "异常类型", "异常发生时间", "状态" }; + writeHeader(header, headers); + } + + private void writeHeader(Row row, String[] headers) { + for (int i = 0; i < headers.length; i++) { + row.createCell(i).setCellValue(headers[i]); + } + } + + private String safeText(String value) { + return value == null ? "" : value; + } + + private double safeNumber(BigDecimal value) { + return value == null ? 0D : value.doubleValue(); + } +} diff --git a/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml b/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml index fc25f307..4fb6687d 100644 --- a/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml +++ b/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml @@ -609,6 +609,25 @@ order by neg.query_date desc, neg.person_id asc + +