完成风险明细统一导出功能

This commit is contained in:
wkc
2026-03-30 14:32:41 +08:00
parent 28b846134a
commit ea6bd5213f
16 changed files with 590 additions and 14 deletions

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -98,6 +98,14 @@ public interface CcdiProjectOverviewMapper {
@Param("query") CcdiProjectEmployeeCreditNegativeQueryDTO query
);
/**
* 查询项目员工负面征信导出列表
*
* @param projectId 项目ID
* @return 导出列表
*/
List<CcdiProjectEmployeeCreditNegativeItemVO> selectEmployeeCreditNegativeList(@Param("projectId") Long projectId);
/**
* 查询涉疑交易导出列表
*

View File

@@ -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<CcdiProjectEmployeeCreditNegativeExcel> exportEmployeeCreditNegative(Long projectId) {
return List.of();
}
/**
* 查询项目员工负面征信
*

View File

@@ -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<CcdiProjectSuspiciousTransactionExcel> suspiciousRows = exportSuspiciousTransactions(queryDTO);
List<CcdiProjectEmployeeCreditNegativeExcel> creditRows = exportEmployeeCreditNegative(projectId);
try {
workbookExporter.export(response, projectId, suspiciousRows, creditRows);
} catch (IOException e) {
throw new ServiceException("导出风险明细失败");
}
}
@Override
public List<CcdiProjectEmployeeCreditNegativeExcel> 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;

View File

@@ -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<CcdiProjectSuspiciousTransactionExcel> suspiciousRows,
List<CcdiProjectEmployeeCreditNegativeExcel> 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<CcdiProjectSuspiciousTransactionExcel> 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<CcdiProjectEmployeeCreditNegativeExcel> 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();
}
}

View File

@@ -609,6 +609,25 @@
order by neg.query_date desc, neg.person_id asc
</select>
<select id="selectEmployeeCreditNegativeList"
resultType="com.ruoyi.ccdi.project.domain.vo.CcdiProjectEmployeeCreditNegativeItemVO">
select
coalesce(neg.person_name, result.staff_name) as personName,
neg.person_id as personId,
date_format(neg.query_date, '%Y-%m-%d') as queryDate,
ifnull(neg.civil_cnt, 0) as civilCnt,
ifnull(neg.civil_lmt, 0) as civilLmt,
ifnull(neg.enforce_cnt, 0) as enforceCnt,
ifnull(neg.enforce_lmt, 0) as enforceLmt,
ifnull(neg.adm_cnt, 0) as admCnt,
ifnull(neg.adm_lmt, 0) as admLmt
from ccdi_project_overview_employee_result result
inner join ccdi_credit_negative_info neg
on neg.person_id = result.staff_id_card
where result.project_id = #{projectId}
order by neg.query_date desc, neg.person_id asc
</select>
<select id="selectRiskModelNamesByScope" resultType="java.lang.String">
select
json_unquote(json_extract(result.model_hit_summary_json, concat('$[', idx.idx, '].modelName'))) as model_name