diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiBaseStaffController.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiBaseStaffController.java index a8a358eb..7626c7f3 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiBaseStaffController.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiBaseStaffController.java @@ -7,7 +7,6 @@ import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffQueryDTO; import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffAssetInfoExcel; import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffExcel; import com.ruoyi.info.collection.domain.vo.*; -import com.ruoyi.info.collection.service.ICcdiBaseStaffAssetImportService; import com.ruoyi.info.collection.service.ICcdiBaseStaffImportService; import com.ruoyi.info.collection.service.ICcdiBaseStaffService; import com.ruoyi.info.collection.utils.EasyExcelUtil; @@ -47,9 +46,6 @@ public class CcdiBaseStaffController extends BaseController { @Resource private ICcdiBaseStaffImportService importAsyncService; - @Resource - private ICcdiBaseStaffAssetImportService baseStaffAssetImportService; - /** * 查询员工列表 */ @@ -161,14 +157,7 @@ public class CcdiBaseStaffController extends BaseController { return error("至少需要一条数据"); } - BaseStaffImportSubmitResultVO result = new BaseStaffImportSubmitResultVO(); - if (hasStaffRows) { - result.setStaffTaskId(baseStaffService.importBaseStaff(staffList)); - } - if (hasAssetRows) { - result.setAssetTaskId(baseStaffAssetImportService.importAssetInfo(assetList)); - } - result.setMessage(buildImportSubmitMessage(hasStaffRows, hasAssetRows)); + BaseStaffImportSubmitResultVO result = baseStaffService.importBaseStaffWithAssets(staffList, assetList); return AjaxResult.success("导入任务已提交,正在后台处理", result); } @@ -215,13 +204,4 @@ public class CcdiBaseStaffController extends BaseController { return getDataTable(pageData, failures.size()); } - private String buildImportSubmitMessage(boolean hasStaffRows, boolean hasAssetRows) { - if (hasStaffRows && hasAssetRows) { - return "已提交员工信息和员工资产信息导入任务"; - } - if (hasStaffRows) { - return "已提交员工信息导入任务"; - } - return "已提交员工资产信息导入任务"; - } } diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiStaffFmyRelationController.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiStaffFmyRelationController.java index 1eff571a..89b657cc 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiStaffFmyRelationController.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiStaffFmyRelationController.java @@ -10,7 +10,6 @@ import com.ruoyi.info.collection.domain.vo.CcdiStaffFmyRelationVO; import com.ruoyi.info.collection.domain.vo.ImportStatusVO; import com.ruoyi.info.collection.domain.vo.StaffFmyRelationImportFailureVO; import com.ruoyi.info.collection.domain.vo.StaffFmyRelationImportSubmitResultVO; -import com.ruoyi.info.collection.service.ICcdiAssetInfoImportService; import com.ruoyi.info.collection.service.ICcdiStaffFmyRelationImportService; import com.ruoyi.info.collection.service.ICcdiStaffFmyRelationService; import com.ruoyi.info.collection.utils.EasyExcelUtil; @@ -51,9 +50,6 @@ public class CcdiStaffFmyRelationController extends BaseController { @Resource private ICcdiStaffFmyRelationImportService relationImportService; - @Resource - private ICcdiAssetInfoImportService assetInfoImportService; - /** * 查询员工亲属关系列表 */ @@ -157,15 +153,7 @@ public class CcdiStaffFmyRelationController extends BaseController { return error("至少需要一条数据"); } - StaffFmyRelationImportSubmitResultVO result = new StaffFmyRelationImportSubmitResultVO(); - if (hasRelationRows) { - result.setRelationTaskId(relationService.importRelation(relationList)); - } - if (hasAssetRows) { - result.setAssetTaskId(assetInfoImportService.importAssetInfo(assetList)); - } - result.setMessage(buildImportSubmitMessage(hasRelationRows, hasAssetRows)); - + StaffFmyRelationImportSubmitResultVO result = relationService.importRelationWithAssets(relationList, assetList); return AjaxResult.success("导入任务已提交,正在后台处理", result); } @@ -211,13 +199,4 @@ public class CcdiStaffFmyRelationController extends BaseController { return getDataTable(pageData, failures.size()); } - private String buildImportSubmitMessage(boolean hasRelationRows, boolean hasAssetRows) { - if (hasRelationRows && hasAssetRows) { - return "已提交员工亲属关系和亲属资产信息导入任务"; - } - if (hasRelationRows) { - return "已提交员工亲属关系导入任务"; - } - return "已提交亲属资产信息导入任务"; - } } diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiAssetInfoImportService.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiAssetInfoImportService.java index d2f52af1..e0beff43 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiAssetInfoImportService.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiAssetInfoImportService.java @@ -5,6 +5,8 @@ import com.ruoyi.info.collection.domain.vo.AssetImportFailureVO; import com.ruoyi.info.collection.domain.vo.ImportStatusVO; import java.util.List; +import java.util.Map; +import java.util.Set; /** * 亲属资产信息异步导入 服务层 @@ -31,6 +33,19 @@ public interface ICcdiAssetInfoImportService { */ void importAssetInfoAsync(List excelList, String taskId, String userName); + /** + * 同步执行亲属资产导入,可附加同一文件亲属关系Sheet成功导入的归属映射 + * + * @param excelList Excel实体列表 + * @param taskId 任务ID + * @param userName 用户名 + * @param extraOwnerMappings 附加归属映射,key为亲属证件号,value为归属员工证件号集合 + */ + void importAssetInfoSync(List excelList, + String taskId, + String userName, + Map> extraOwnerMappings); + /** * 查询导入状态 * diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffAssetImportService.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffAssetImportService.java index 990d1df6..ec253028 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffAssetImportService.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffAssetImportService.java @@ -5,6 +5,8 @@ import com.ruoyi.info.collection.domain.vo.BaseStaffAssetImportFailureVO; import com.ruoyi.info.collection.domain.vo.ImportStatusVO; import java.util.List; +import java.util.Map; +import java.util.Set; /** * 员工资产信息异步导入 服务层 @@ -31,6 +33,19 @@ public interface ICcdiBaseStaffAssetImportService { */ void importAssetInfoAsync(List excelList, String taskId, String userName); + /** + * 同步执行员工资产导入,可附加同一文件员工Sheet成功导入的归属映射 + * + * @param excelList Excel实体列表 + * @param taskId 任务ID + * @param userName 用户名 + * @param extraOwnerMappings 附加归属映射,key为资产持有人证件号,value为归属员工证件号集合 + */ + void importAssetInfoSync(List excelList, + String taskId, + String userName, + Map> extraOwnerMappings); + /** * 查询导入状态 * diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffImportService.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffImportService.java index a2b15508..a326770f 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffImportService.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffImportService.java @@ -5,6 +5,7 @@ import com.ruoyi.info.collection.domain.vo.ImportFailureVO; import com.ruoyi.info.collection.domain.vo.ImportStatusVO; import java.util.List; +import java.util.Set; /** * @Author: wkc @@ -19,6 +20,15 @@ public interface ICcdiBaseStaffImportService { */ void importBaseStaffAsync(List excelList, String taskId); + /** + * 同步执行员工导入并返回本轮成功员工身份证号 + * + * @param excelList Excel数据列表 + * @param taskId 任务ID + * @return 成功导入的身份证号集合 + */ + Set importBaseStaffSync(List excelList, String taskId); + /** * 查询导入状态 * diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffService.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffService.java index 400804e1..53d0560e 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffService.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffService.java @@ -4,7 +4,9 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffAddDTO; import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffEditDTO; import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffQueryDTO; +import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffAssetInfoExcel; import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffExcel; +import com.ruoyi.info.collection.domain.vo.BaseStaffImportSubmitResultVO; import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffOptionVO; import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffVO; @@ -83,6 +85,16 @@ public interface ICcdiBaseStaffService { */ String importBaseStaff(List excelList); + /** + * 导入员工信息和员工资产双Sheet数据 + * + * @param staffList 员工信息Sheet + * @param assetList 员工资产Sheet + * @return 提交结果 + */ + BaseStaffImportSubmitResultVO importBaseStaffWithAssets(List staffList, + List assetList); + /** * 查询员工下拉列表 * 支持按员工ID或姓名模糊搜索,只返回在职员工 diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiStaffFmyRelationImportService.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiStaffFmyRelationImportService.java index f07ff882..8dac3f3e 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiStaffFmyRelationImportService.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiStaffFmyRelationImportService.java @@ -5,6 +5,7 @@ import com.ruoyi.info.collection.domain.vo.ImportStatusVO; import com.ruoyi.info.collection.domain.vo.StaffFmyRelationImportFailureVO; import java.util.List; +import java.util.Map; /** * 员工亲属关系异步导入 服务层 @@ -23,6 +24,16 @@ public interface ICcdiStaffFmyRelationImportService { */ void importRelationAsync(List excelList, String taskId, String userName); + /** + * 同步执行员工亲属关系导入并返回本轮成功关系映射 + * + * @param excelList Excel实体列表 + * @param taskId 任务ID + * @param userName 用户名 + * @return key为亲属证件号,value为归属员工证件号 + */ + Map importRelationSync(List excelList, String taskId, String userName); + /** * 查询导入失败记录 * diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiStaffFmyRelationService.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiStaffFmyRelationService.java index b11d1e87..f85e73dd 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiStaffFmyRelationService.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiStaffFmyRelationService.java @@ -4,8 +4,10 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.info.collection.domain.dto.CcdiStaffFmyRelationAddDTO; import com.ruoyi.info.collection.domain.dto.CcdiStaffFmyRelationEditDTO; import com.ruoyi.info.collection.domain.dto.CcdiStaffFmyRelationQueryDTO; +import com.ruoyi.info.collection.domain.excel.CcdiAssetInfoExcel; import com.ruoyi.info.collection.domain.excel.CcdiStaffFmyRelationExcel; import com.ruoyi.info.collection.domain.vo.CcdiStaffFmyRelationVO; +import com.ruoyi.info.collection.domain.vo.StaffFmyRelationImportSubmitResultVO; import java.util.List; @@ -81,4 +83,14 @@ public interface ICcdiStaffFmyRelationService { * @return 任务ID */ String importRelation(List excelList); + + /** + * 导入员工亲属关系和亲属资产双Sheet数据 + * + * @param relationList 员工亲属关系Sheet + * @param assetList 亲属资产Sheet + * @return 提交结果 + */ + StaffFmyRelationImportSubmitResultVO importRelationWithAssets(List relationList, + List assetList); } diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiAssetInfoImportServiceImpl.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiAssetInfoImportServiceImpl.java index 3dc26e1b..edd45f0e 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiAssetInfoImportServiceImpl.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiAssetInfoImportServiceImpl.java @@ -82,6 +82,15 @@ public class CcdiAssetInfoImportServiceImpl implements ICcdiAssetInfoImportServi @Async @Transactional public void importAssetInfoAsync(List excelList, String taskId, String userName) { + importAssetInfoSync(excelList, taskId, userName, Map.of()); + } + + @Override + @Transactional + public void importAssetInfoSync(List excelList, + String taskId, + String userName, + Map> extraOwnerMappings) { List successList = new ArrayList<>(); List failures = new ArrayList<>(); @@ -92,6 +101,7 @@ public class CcdiAssetInfoImportServiceImpl implements ICcdiAssetInfoImportServi .toList(); Map> ownerMap = buildOwnerMap(personIds); + mergeOwnerMappings(ownerMap, extraOwnerMappings); for (int i = 0; i < excelList.size(); i++) { CcdiAssetInfoExcel excel = excelList.get(i); @@ -189,6 +199,18 @@ public class CcdiAssetInfoImportServiceImpl implements ICcdiAssetInfoImportServi } } + private void mergeOwnerMappings(Map> result, Map> mappings) { + if (mappings == null || mappings.isEmpty()) { + return; + } + for (Map.Entry> entry : mappings.entrySet()) { + if (StringUtils.isEmpty(entry.getKey()) || entry.getValue() == null || entry.getValue().isEmpty()) { + continue; + } + result.computeIfAbsent(entry.getKey(), key -> new java.util.LinkedHashSet<>()).addAll(entry.getValue()); + } + } + private void validateExcel(CcdiAssetInfoExcel excel) { if (StringUtils.isEmpty(excel.getPersonId())) { throw new RuntimeException("亲属证件号不能为空"); diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffAssetImportServiceImpl.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffAssetImportServiceImpl.java index 3f7aa3c4..09c6d3a2 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffAssetImportServiceImpl.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffAssetImportServiceImpl.java @@ -81,6 +81,15 @@ public class CcdiBaseStaffAssetImportServiceImpl implements ICcdiBaseStaffAssetI @Async @Transactional public void importAssetInfoAsync(List excelList, String taskId, String userName) { + importAssetInfoSync(excelList, taskId, userName, Map.of()); + } + + @Override + @Transactional + public void importAssetInfoSync(List excelList, + String taskId, + String userName, + Map> extraOwnerMappings) { List successList = new ArrayList<>(); List failures = new ArrayList<>(); @@ -91,6 +100,7 @@ public class CcdiBaseStaffAssetImportServiceImpl implements ICcdiBaseStaffAssetI .toList(); Map> ownerMap = buildOwnerMap(personIds); + mergeOwnerMappings(ownerMap, extraOwnerMappings); Set existingAssetKeys = buildExistingAssetKeys(personIds); Set importedAssetKeys = new java.util.LinkedHashSet<>(); @@ -207,6 +217,18 @@ public class CcdiBaseStaffAssetImportServiceImpl implements ICcdiBaseStaffAssetI } } + private void mergeOwnerMappings(Map> result, Map> mappings) { + if (mappings == null || mappings.isEmpty()) { + return; + } + for (Map.Entry> entry : mappings.entrySet()) { + if (StringUtils.isEmpty(entry.getKey()) || entry.getValue() == null || entry.getValue().isEmpty()) { + continue; + } + result.computeIfAbsent(entry.getKey(), key -> new java.util.LinkedHashSet<>()).addAll(entry.getValue()); + } + } + private void validateExcel(CcdiBaseStaffAssetInfoExcel excel) { if (StringUtils.isEmpty(excel.getPersonId())) { throw new RuntimeException("员工身份证号不能为空"); diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffImportServiceImpl.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffImportServiceImpl.java index bf594c61..18715af3 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffImportServiceImpl.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffImportServiceImpl.java @@ -23,6 +23,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.*; @@ -51,6 +52,12 @@ public class CcdiBaseStaffImportServiceImpl implements ICcdiBaseStaffImportServi @Override @Async public void importBaseStaffAsync(List excelList, String taskId) { + importBaseStaffSync(excelList, taskId); + } + + @Override + @Transactional + public Set importBaseStaffSync(List excelList, String taskId) { long startTime = System.currentTimeMillis(); // 记录导入开始 @@ -153,6 +160,11 @@ public class CcdiBaseStaffImportServiceImpl implements ICcdiBaseStaffImportServi long duration = System.currentTimeMillis() - startTime; ImportLogUtils.logImportComplete(log, taskId, "员工基础信息", excelList.size(), result.getSuccessCount(), result.getFailureCount(), duration); + + return newRecords.stream() + .map(CcdiBaseStaff::getIdCard) + .filter(StringUtils::isNotEmpty) + .collect(Collectors.toCollection(LinkedHashSet::new)); } /** diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffServiceImpl.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffServiceImpl.java index 435e3c66..99485933 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffServiceImpl.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffServiceImpl.java @@ -6,15 +6,19 @@ import com.ruoyi.info.collection.domain.CcdiBaseStaff; import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffAddDTO; import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffEditDTO; import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffQueryDTO; +import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffAssetInfoExcel; import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffExcel; +import com.ruoyi.info.collection.domain.vo.BaseStaffImportSubmitResultVO; import com.ruoyi.info.collection.domain.vo.CcdiAssetInfoVO; import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffOptionVO; import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffVO; import com.ruoyi.info.collection.enums.EmployeeStatus; import com.ruoyi.info.collection.mapper.CcdiBaseStaffMapper; import com.ruoyi.info.collection.service.ICcdiAssetInfoService; +import com.ruoyi.info.collection.service.ICcdiBaseStaffAssetImportService; import com.ruoyi.info.collection.service.ICcdiBaseStaffImportService; import com.ruoyi.info.collection.service.ICcdiBaseStaffService; +import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import jakarta.annotation.Resource; import org.springframework.beans.BeanUtils; @@ -46,6 +50,12 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService { @Resource private ICcdiAssetInfoService assetInfoService; + @Resource + private ICcdiBaseStaffAssetImportService baseStaffAssetImportService; + + @Resource + private CcdiDualSheetImportOrchestrationService dualSheetImportOrchestrationService; + /** * 查询员工列表 * @@ -218,28 +228,52 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService { @Transactional public String importBaseStaff(List excelList) { String taskId = UUID.randomUUID().toString(); - long startTime = System.currentTimeMillis(); - - // 初始化Redis状态 - String statusKey = "import:baseStaff:" + taskId; - Map statusData = new HashMap<>(); - statusData.put("taskId", taskId); - statusData.put("status", "PROCESSING"); - statusData.put("totalCount", excelList.size()); - statusData.put("successCount", 0); - statusData.put("failureCount", 0); - statusData.put("progress", 0); - statusData.put("startTime", startTime); - statusData.put("message", "正在处理..."); - - redisTemplate.opsForHash().putAll(statusKey, statusData); - redisTemplate.expire(statusKey, 7, java.util.concurrent.TimeUnit.DAYS); + initializeImportStatus("import:baseStaff:", taskId, excelList.size()); importAsyncService.importBaseStaffAsync(excelList, taskId); return taskId; } + @Override + @Transactional + public BaseStaffImportSubmitResultVO importBaseStaffWithAssets(List staffList, + List assetList) { + boolean hasStaffRows = staffList != null && !staffList.isEmpty(); + boolean hasAssetRows = assetList != null && !assetList.isEmpty(); + if (!hasStaffRows && !hasAssetRows) { + throw new RuntimeException("至少需要一条数据"); + } + + BaseStaffImportSubmitResultVO result = new BaseStaffImportSubmitResultVO(); + result.setMessage(buildImportSubmitMessage(hasStaffRows, hasAssetRows)); + + if (hasStaffRows && !hasAssetRows) { + result.setStaffTaskId(importBaseStaff(staffList)); + return result; + } + if (!hasStaffRows) { + result.setAssetTaskId(baseStaffAssetImportService.importAssetInfo(assetList)); + return result; + } + + String staffTaskId = UUID.randomUUID().toString(); + String assetTaskId = UUID.randomUUID().toString(); + initializeImportStatus("import:baseStaff:", staffTaskId, staffList.size()); + initializeImportStatus("import:baseStaffAsset:", assetTaskId, assetList.size()); + + result.setStaffTaskId(staffTaskId); + result.setAssetTaskId(assetTaskId); + dualSheetImportOrchestrationService.importBaseStaffWithAssetsAsync( + staffList, + staffTaskId, + assetList, + assetTaskId, + currentUserName() + ); + return result; + } + /** * 查询员工下拉列表 * 支持按员工ID或姓名模糊搜索,只返回在职员工 @@ -252,6 +286,40 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService { return baseStaffMapper.selectStaffOptions(query); } + private void initializeImportStatus(String keyPrefix, String taskId, int totalCount) { + Map statusData = new HashMap<>(); + statusData.put("taskId", taskId); + statusData.put("status", "PROCESSING"); + statusData.put("totalCount", totalCount); + statusData.put("successCount", 0); + statusData.put("failureCount", 0); + statusData.put("progress", 0); + statusData.put("startTime", System.currentTimeMillis()); + statusData.put("message", "正在处理..."); + + String statusKey = keyPrefix + taskId; + redisTemplate.opsForHash().putAll(statusKey, statusData); + redisTemplate.expire(statusKey, 7, java.util.concurrent.TimeUnit.DAYS); + } + + private String buildImportSubmitMessage(boolean hasStaffRows, boolean hasAssetRows) { + if (hasStaffRows && hasAssetRows) { + return "已提交员工信息和员工资产信息导入任务"; + } + if (hasStaffRows) { + return "已提交员工信息导入任务"; + } + return "已提交员工资产信息导入任务"; + } + + private String currentUserName() { + try { + return SecurityUtils.getUsername(); + } catch (Exception e) { + return "system"; + } + } + /** * 构建查询条件 */ diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiDualSheetImportOrchestrationService.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiDualSheetImportOrchestrationService.java new file mode 100644 index 00000000..04c241bf --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiDualSheetImportOrchestrationService.java @@ -0,0 +1,90 @@ +package com.ruoyi.info.collection.service.impl; + +import com.ruoyi.info.collection.domain.excel.CcdiAssetInfoExcel; +import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffAssetInfoExcel; +import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffExcel; +import com.ruoyi.info.collection.domain.excel.CcdiStaffFmyRelationExcel; +import com.ruoyi.info.collection.service.ICcdiAssetInfoImportService; +import com.ruoyi.info.collection.service.ICcdiBaseStaffAssetImportService; +import com.ruoyi.info.collection.service.ICcdiBaseStaffImportService; +import com.ruoyi.info.collection.service.ICcdiStaffFmyRelationImportService; +import jakarta.annotation.Resource; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 双Sheet导入后台顺序编排。 + */ +@Service +public class CcdiDualSheetImportOrchestrationService { + + @Resource + private ICcdiBaseStaffImportService baseStaffImportService; + + @Resource + private ICcdiBaseStaffAssetImportService baseStaffAssetImportService; + + @Resource + private ICcdiStaffFmyRelationImportService relationImportService; + + @Resource + private ICcdiAssetInfoImportService assetInfoImportService; + + @Async + public void importBaseStaffWithAssetsAsync(List staffList, + String staffTaskId, + List assetList, + String assetTaskId, + String userName) { + Set successIdCards = baseStaffImportService.importBaseStaffSync(staffList, staffTaskId); + baseStaffAssetImportService.importAssetInfoSync( + assetList, + assetTaskId, + userName, + buildSelfOwnerMappings(successIdCards) + ); + } + + @Async + public void importRelationWithAssetsAsync(List relationList, + String relationTaskId, + List assetList, + String assetTaskId, + String userName) { + Map successRelationMappings = relationImportService.importRelationSync(relationList, relationTaskId, userName); + assetInfoImportService.importAssetInfoSync( + assetList, + assetTaskId, + userName, + buildRelationOwnerMappings(successRelationMappings) + ); + } + + private Map> buildSelfOwnerMappings(Set idCards) { + Map> result = new LinkedHashMap<>(); + if (idCards == null || idCards.isEmpty()) { + return result; + } + for (String idCard : idCards) { + result.computeIfAbsent(idCard, key -> new LinkedHashSet<>()).add(idCard); + } + return result; + } + + private Map> buildRelationOwnerMappings(Map relationMappings) { + Map> result = new LinkedHashMap<>(); + if (relationMappings == null || relationMappings.isEmpty()) { + return result; + } + for (Map.Entry entry : relationMappings.entrySet()) { + result.computeIfAbsent(entry.getKey(), key -> new LinkedHashSet<>()).add(entry.getValue()); + } + return result; + } +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiStaffFmyRelationImportServiceImpl.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiStaffFmyRelationImportServiceImpl.java index 5d7e3588..145d81bb 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiStaffFmyRelationImportServiceImpl.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiStaffFmyRelationImportServiceImpl.java @@ -57,6 +57,12 @@ public class CcdiStaffFmyRelationImportServiceImpl implements ICcdiStaffFmyRelat @Async @Transactional public void importRelationAsync(List excelList, String taskId, String userName) { + importRelationSync(excelList, taskId, userName); + } + + @Override + @Transactional + public Map importRelationSync(List excelList, String taskId, String userName) { long startTime = System.currentTimeMillis(); // 记录导入开始 @@ -213,6 +219,15 @@ public class CcdiStaffFmyRelationImportServiceImpl implements ICcdiStaffFmyRelat long duration = System.currentTimeMillis() - startTime; ImportLogUtils.logImportComplete(log, taskId, "员工亲属关系", excelList.size(), result.getSuccessCount(), result.getFailureCount(), duration); + + return newRecords.stream() + .filter(item -> StringUtils.isNotEmpty(item.getRelationCertNo()) && StringUtils.isNotEmpty(item.getPersonId())) + .collect(Collectors.toMap( + CcdiStaffFmyRelation::getRelationCertNo, + CcdiStaffFmyRelation::getPersonId, + (left, right) -> left, + LinkedHashMap::new + )); } /** diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiStaffFmyRelationServiceImpl.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiStaffFmyRelationServiceImpl.java index 29b14b10..9fa485da 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiStaffFmyRelationServiceImpl.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiStaffFmyRelationServiceImpl.java @@ -6,11 +6,14 @@ import com.ruoyi.info.collection.domain.CcdiStaffFmyRelation; import com.ruoyi.info.collection.domain.dto.CcdiStaffFmyRelationAddDTO; import com.ruoyi.info.collection.domain.dto.CcdiStaffFmyRelationEditDTO; import com.ruoyi.info.collection.domain.dto.CcdiStaffFmyRelationQueryDTO; +import com.ruoyi.info.collection.domain.excel.CcdiAssetInfoExcel; import com.ruoyi.info.collection.domain.excel.CcdiStaffFmyRelationExcel; import com.ruoyi.info.collection.domain.vo.CcdiAssetInfoVO; import com.ruoyi.info.collection.domain.vo.CcdiStaffFmyRelationVO; +import com.ruoyi.info.collection.domain.vo.StaffFmyRelationImportSubmitResultVO; import com.ruoyi.info.collection.mapper.CcdiStaffEnterpriseRelationMapper; import com.ruoyi.info.collection.mapper.CcdiStaffFmyRelationMapper; +import com.ruoyi.info.collection.service.ICcdiAssetInfoImportService; import com.ruoyi.info.collection.service.ICcdiAssetInfoService; import com.ruoyi.info.collection.service.ICcdiStaffFmyRelationImportService; import com.ruoyi.info.collection.service.ICcdiStaffFmyRelationService; @@ -51,9 +54,15 @@ public class CcdiStaffFmyRelationServiceImpl implements ICcdiStaffFmyRelationSer @Resource private ICcdiAssetInfoService assetInfoService; + @Resource + private ICcdiAssetInfoImportService assetInfoImportService; + @Resource private CcdiStaffEnterpriseRelationMapper staffEnterpriseRelationMapper; + @Resource + private CcdiDualSheetImportOrchestrationService dualSheetImportOrchestrationService; + /** * 查询员工亲属关系列表 * @@ -207,25 +216,11 @@ public class CcdiStaffFmyRelationServiceImpl implements ICcdiStaffFmyRelationSer // 生成任务ID String taskId = UUID.randomUUID().toString(); - long startTime = System.currentTimeMillis(); // 获取当前用户名 String userName = SecurityUtils.getUsername(); - // 初始化Redis状态 - String statusKey = "import:staffFmyRelation:" + taskId; - Map statusData = new HashMap<>(); - statusData.put("taskId", taskId); - statusData.put("status", "PROCESSING"); - statusData.put("totalCount", excelList.size()); - statusData.put("successCount", 0); - statusData.put("failureCount", 0); - statusData.put("progress", 0); - statusData.put("startTime", startTime); - statusData.put("message", "正在处理..."); - - redisTemplate.opsForHash().putAll(statusKey, statusData); - redisTemplate.expire(statusKey, 7, TimeUnit.DAYS); + initializeImportStatus("import:staffFmyRelation:", taskId, excelList.size()); // 调用异步导入服务 relationImportService.importRelationAsync(excelList, taskId, userName); @@ -233,6 +228,79 @@ public class CcdiStaffFmyRelationServiceImpl implements ICcdiStaffFmyRelationSer return taskId; } + @Override + @Transactional + public StaffFmyRelationImportSubmitResultVO importRelationWithAssets(List relationList, + List assetList) { + boolean hasRelationRows = relationList != null && !relationList.isEmpty(); + boolean hasAssetRows = assetList != null && !assetList.isEmpty(); + if (!hasRelationRows && !hasAssetRows) { + throw new RuntimeException("至少需要一条数据"); + } + + StaffFmyRelationImportSubmitResultVO result = new StaffFmyRelationImportSubmitResultVO(); + result.setMessage(buildImportSubmitMessage(hasRelationRows, hasAssetRows)); + + if (hasRelationRows && !hasAssetRows) { + result.setRelationTaskId(importRelation(relationList)); + return result; + } + if (!hasRelationRows) { + result.setAssetTaskId(assetInfoImportService.importAssetInfo(assetList)); + return result; + } + + String relationTaskId = UUID.randomUUID().toString(); + String assetTaskId = UUID.randomUUID().toString(); + initializeImportStatus("import:staffFmyRelation:", relationTaskId, relationList.size()); + initializeImportStatus("import:assetInfo:", assetTaskId, assetList.size()); + + result.setRelationTaskId(relationTaskId); + result.setAssetTaskId(assetTaskId); + dualSheetImportOrchestrationService.importRelationWithAssetsAsync( + relationList, + relationTaskId, + assetList, + assetTaskId, + currentUserName() + ); + return result; + } + + private void initializeImportStatus(String keyPrefix, String taskId, int totalCount) { + Map statusData = new HashMap<>(); + statusData.put("taskId", taskId); + statusData.put("status", "PROCESSING"); + statusData.put("totalCount", totalCount); + statusData.put("successCount", 0); + statusData.put("failureCount", 0); + statusData.put("progress", 0); + statusData.put("startTime", System.currentTimeMillis()); + statusData.put("message", "正在处理..."); + + String statusKey = keyPrefix + taskId; + redisTemplate.opsForHash().putAll(statusKey, statusData); + redisTemplate.expire(statusKey, 7, TimeUnit.DAYS); + } + + private String buildImportSubmitMessage(boolean hasRelationRows, boolean hasAssetRows) { + if (hasRelationRows && hasAssetRows) { + return "已提交员工亲属关系和亲属资产信息导入任务"; + } + if (hasRelationRows) { + return "已提交员工亲属关系导入任务"; + } + return "已提交亲属资产信息导入任务"; + } + + private String currentUserName() { + try { + return SecurityUtils.getUsername(); + } catch (Exception e) { + return "system"; + } + } + private CcdiAssetInfoVO toAssetInfoVO(CcdiAssetInfo assetInfo) { CcdiAssetInfoVO assetInfoVO = new CcdiAssetInfoVO(); BeanUtils.copyProperties(assetInfo, assetInfoVO); diff --git a/docs/reports/implementation/2026-05-06-staff-asset-import-and-enterprise-autofill-backend-implementation.md b/docs/reports/implementation/2026-05-06-staff-asset-import-and-enterprise-autofill-backend-implementation.md new file mode 100644 index 00000000..b763f6de --- /dev/null +++ b/docs/reports/implementation/2026-05-06-staff-asset-import-and-enterprise-autofill-backend-implementation.md @@ -0,0 +1,43 @@ +# 员工资产导入与实体库自动补入后端实施记录 + +## 基本信息 + +- 实施日期:2026-05-06 +- 实施范围:后端 +- 关联计划:`docs/plans/backend/2026-05-06-staff-asset-import-and-enterprise-autofill-fix-backend-implementation-plan.md` + +## 修改内容 + +### 双 Sheet 导入任务编排 + +- 员工信息维护导入入口改为由服务层统一编排员工主 Sheet 与员工资产 Sheet。 +- 员工亲属关系维护导入入口改为由服务层统一编排亲属关系主 Sheet 与亲属资产 Sheet。 +- 当两个 Sheet 都有数据时,仍返回两个任务 ID,并按主 Sheet 导入成功结果为资产 Sheet 提供同文件内的归属映射。 +- 当只导入资产 Sheet 时,仅生成并返回资产导入任务 ID,不生成员工或亲属关系主任务 ID。 +- 当两个 Sheet 都为空时,保持返回“至少需要一条数据”。 + +### 实体库自动补入 + +- 新增统一的实体库自动补入服务,按统一社会信用代码去重,只插入实体库不存在的记录。 +- 员工企业关系、信贷客户企业关系新增和导入时自动补入实体库。 +- 中介新增、编辑和导入时取消“实体库必须已存在”的阻断校验;实体库缺失时按中介来源自动补入,不要求提供机构名称。 +- 招投标供应商新增、编辑和导入时,对合法统一社会信用代码的供应商自动补入实体库。 +- 新增企业来源枚举 `SUPPLIER`,用于标识供应商来源。 + +## 影响范围 + +- `/ccdi/baseStaff/importData` +- `/ccdi/staffFmyRelation/importData` +- 员工企业关系、信贷客户企业关系、中介、招投标供应商的新增/编辑/导入实体库联动逻辑 +- 实体库基础信息表 `ccdi_enterprise_base_info` + +## 验证记录 + +- 执行 `mvn -pl ccdi-info-collection -am -DskipTests compile`,结果:BUILD SUCCESS。 +- 执行 `mvn -DskipTests compile`,结果:BUILD SUCCESS。 +- 代码路径核对:员工主 Sheet 为空时仅调用员工资产导入服务并返回 `assetTaskId`;亲属关系主 Sheet 为空时仅调用亲属资产导入服务并返回 `assetTaskId`。 + +## 备注 + +- 本次为后端逻辑调整,未修改前端页面代码。 +- 现有前端已按 `staffTaskId` / `relationTaskId` / `assetTaskId` 是否存在分别启动轮询,可直接兼容只返回资产任务 ID 的结果。