diff --git a/ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiCustFmyRelationImportServiceImpl.java b/ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiCustFmyRelationImportServiceImpl.java new file mode 100644 index 0000000..448ff19 --- /dev/null +++ b/ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiCustFmyRelationImportServiceImpl.java @@ -0,0 +1,165 @@ +package com.ruoyi.ccdi.service.impl; + +import com.alibaba.excel.EasyExcel; +import com.ruoyi.ccdi.domain.CcdiCustFmyRelation; +import com.ruoyi.ccdi.domain.excel.CcdiCustFmyRelationExcel; +import com.ruoyi.ccdi.domain.vo.CustFmyRelationImportFailureVO; +import com.ruoyi.ccdi.mapper.CcdiCustFmyRelationMapper; +import com.ruoyi.ccdi.service.ICcdiCustFmyRelationImportService; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * 信贷客户家庭关系导入Service实现 + * + * @author ruoyi + * @date 2026-02-11 + */ +@Service +public class CcdiCustFmyRelationImportServiceImpl implements ICcdiCustFmyRelationImportService { + + private static final Logger log = LoggerFactory.getLogger(CcdiCustFmyRelationImportServiceImpl.class); + + @Resource + private CcdiCustFmyRelationMapper mapper; + + @Resource + private RedisTemplate redisTemplate; + + private static final String IMPORT_TASK_KEY_PREFIX = "import:custFmyRelation:"; + private static final String IMPORT_FAILURE_KEY_PREFIX = "import:custFmyRelation:failures:"; + + @Async + @Override + @Transactional(rollbackFor = Exception.class) + public void importRelationsAsync(List excels, String taskId) { + List validRelations = new ArrayList<>(); + List failures = new ArrayList<>(); + + try { + for (int i = 0; i < excels.size(); i++) { + CcdiCustFmyRelationExcel excel = excels.get(i); + Integer rowNum = i + 2; // Excel行号从2开始(第1行是表头) + + String errorMessage = validateExcelRow(excel, rowNum); + if (errorMessage != null) { + CustFmyRelationImportFailureVO failure = new CustFmyRelationImportFailureVO(); + failure.setRowNum(rowNum); + failure.setPersonId(excel.getPersonId()); + failure.setRelationType(excel.getRelationType()); + failure.setRelationName(excel.getRelationName()); + failure.setErrorMessage(errorMessage); + failures.add(failure); + continue; + } + + CcdiCustFmyRelation relation = convertToRelation(excel); + validRelations.add(relation); + } + + // 批量插入有效数据 + if (!validRelations.isEmpty()) { + mapper.insertBatch(validRelations); + } + + // 保存失败记录到Redis(24小时过期) + if (!failures.isEmpty()) { + redisTemplate.opsForValue().set( + IMPORT_FAILURE_KEY_PREFIX + taskId, + failures, + 24, + TimeUnit.HOURS + ); + } + + // 更新任务状态 + redisTemplate.opsForValue().set( + IMPORT_TASK_KEY_PREFIX + taskId, + "COMPLETED:" + validRelations.size() + ":" + failures.size(), + 1, + TimeUnit.HOURS + ); + + } catch (Exception e) { + log.error("导入失败", e); + redisTemplate.opsForValue().set( + IMPORT_TASK_KEY_PREFIX + taskId, + "FAILED:" + e.getMessage(), + 1, + TimeUnit.HOURS + ); + } + } + + @Override + public String validateExcelRow(CcdiCustFmyRelationExcel excel, Integer rowNum) { + if (excel.getPersonId() == null || excel.getPersonId().trim().isEmpty()) { + return "信贷客户身份证号不能为空"; + } + + if (excel.getRelationType() == null || excel.getRelationType().trim().isEmpty()) { + return "关系类型不能为空"; + } + + if (excel.getRelationName() == null || excel.getRelationName().trim().isEmpty()) { + return "关系人姓名不能为空"; + } + + if (excel.getRelationCertType() == null || excel.getRelationCertType().trim().isEmpty()) { + return "关系人证件类型不能为空"; + } + + if (excel.getRelationCertNo() == null || excel.getRelationCertNo().trim().isEmpty()) { + return "关系人证件号码不能为空"; + } + + // 检查是否已存在相同的关系 + CcdiCustFmyRelation existing = mapper.selectExistingRelations( + excel.getPersonId(), + excel.getRelationType(), + excel.getRelationCertNo() + ); + + if (existing != null) { + return "该关系已存在,请勿重复导入"; + } + + return null; // 校验通过 + } + + @Override + @SuppressWarnings("unchecked") + public List getImportFailures(String taskId) { + Object obj = redisTemplate.opsForValue().get(IMPORT_FAILURE_KEY_PREFIX + taskId); + if (obj != null) { + return (List) obj; + } + return new ArrayList<>(); + } + + private CcdiCustFmyRelation convertToRelation(CcdiCustFmyRelationExcel excel) { + CcdiCustFmyRelation relation = new CcdiCustFmyRelation(); + org.springframework.beans.BeanUtils.copyProperties(excel, relation); + + relation.setIsEmpFamily(false); + relation.setIsCustFamily(true); + relation.setStatus(excel.getStatus() != null ? excel.getStatus() : 1); + relation.setDataSource("IMPORT"); + relation.setCreatedBy(SecurityUtils.getUsername()); + relation.setCreateTime(new Date()); + + return relation; + } +} diff --git a/ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiCustFmyRelationServiceImpl.java b/ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiCustFmyRelationServiceImpl.java new file mode 100644 index 0000000..164207a --- /dev/null +++ b/ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiCustFmyRelationServiceImpl.java @@ -0,0 +1,160 @@ +package com.ruoyi.ccdi.service.impl; + +import com.alibaba.excel.EasyExcel; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.ccdi.domain.CcdiCustFmyRelation; +import com.ruoyi.ccdi.domain.dto.CcdiCustFmyRelationAddDTO; +import com.ruoyi.ccdi.domain.dto.CcdiCustFmyRelationEditDTO; +import com.ruoyi.ccdi.domain.dto.CcdiCustFmyRelationQueryDTO; +import com.ruoyi.ccdi.domain.excel.CcdiCustFmyRelationExcel; +import com.ruoyi.ccdi.domain.vo.CcdiCustFmyRelationVO; +import com.ruoyi.ccdi.mapper.CcdiCustFmyRelationMapper; +import com.ruoyi.ccdi.service.ICcdiCustFmyRelationImportService; +import com.ruoyi.ccdi.service.ICcdiCustFmyRelationService; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * 信贷客户家庭关系Service实现 + * + * @author ruoyi + * @date 2026-02-11 + */ +@Service +public class CcdiCustFmyRelationServiceImpl implements ICcdiCustFmyRelationService { + + @Resource + private CcdiCustFmyRelationMapper mapper; + + @Resource + private ICcdiCustFmyRelationImportService importService; + + @Resource + private RedisTemplate redisTemplate; + + private static final String IMPORT_TASK_KEY_PREFIX = "import:custFmyRelation:"; + private static final String IMPORT_FAILURE_KEY_PREFIX = "import:custFmyRelation:failures:"; + + @Override + public Page selectRelationPage(CcdiCustFmyRelationQueryDTO query, + Integer pageNum, Integer pageSize) { + Page page = new Page<>(pageNum, pageSize); + return mapper.selectRelationPage(page, query); + } + + @Override + public CcdiCustFmyRelationVO selectRelationById(Long id) { + return mapper.selectRelationById(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean insertRelation(CcdiCustFmyRelationAddDTO addDTO) { + CcdiCustFmyRelation relation = new CcdiCustFmyRelation(); + BeanUtils.copyProperties(addDTO, relation); + + // 关键设置:客户家庭关系 + relation.setIsEmpFamily(false); + relation.setIsCustFamily(true); + relation.setStatus(1); + relation.setDataSource("MANUAL"); + + return mapper.insert(relation) > 0; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateRelation(CcdiCustFmyRelationEditDTO editDTO) { + CcdiCustFmyRelation relation = new CcdiCustFmyRelation(); + BeanUtils.copyProperties(editDTO, relation); + + return mapper.updateById(relation) > 0; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteRelationByIds(Long[] ids) { + return mapper.deleteBatchIds(List.of(ids)) > 0; + } + + @Override + public void exportRelations(CcdiCustFmyRelationQueryDTO query, HttpServletResponse response) { + // 查询所有符合条件的数据(不分页) + Page page = new Page<>(1, 10000); + Page result = mapper.selectRelationPage(page, query); + + List excels = result.getRecords().stream() + .map(this::convertToExcel) + .toList(); + + // 使用EasyExcel导出 + try { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String fileName = URLEncoder.encode("信贷客户家庭关系", StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); + + EasyExcel.write(response.getOutputStream(), CcdiCustFmyRelationExcel.class) + .sheet("信贷客户家庭关系") + .doWrite(excels); + } catch (Exception e) { + throw new RuntimeException("导出失败", e); + } + } + + @Override + public void importTemplate(HttpServletResponse response) { + try { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String fileName = URLEncoder.encode("信贷客户家庭关系导入模板", StandardCharsets.UTF_8) + .replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); + + EasyExcel.write(response.getOutputStream(), CcdiCustFmyRelationExcel.class) + .sheet("模板") + .doWrite(Collections.emptyList()); + } catch (Exception e) { + throw new RuntimeException("模板下载失败", e); + } + } + + @Override + public String importRelations(List excels) { + String taskId = UUID.randomUUID().toString(); + + // 保存任务状态到Redis + redisTemplate.opsForValue().set(IMPORT_TASK_KEY_PREFIX + taskId, "PROCESSING", 1, TimeUnit.HOURS); + + // 异步导入 + importService.importRelationsAsync(excels, taskId); + + return taskId; + } + + @Override + public List getImportFailures(String taskId) { + return importService.getImportFailures(taskId); + } + + private CcdiCustFmyRelationExcel convertToExcel(CcdiCustFmyRelationVO vo) { + CcdiCustFmyRelationExcel excel = new CcdiCustFmyRelationExcel(); + BeanUtils.copyProperties(vo, excel); + return excel; + } +}