除员工外 取消导入更新
This commit is contained in:
@@ -1,23 +1,13 @@
|
||||
package com.ruoyi.ccdi.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiIntermediaryEntityAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiIntermediaryEntityEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiIntermediaryPersonAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiIntermediaryPersonEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiIntermediaryQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.*;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryEntityExcel;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryPersonExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryEntityDetailVO;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryPersonDetailVO;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryVO;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportResultVO;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
||||
import com.ruoyi.ccdi.domain.vo.IntermediaryPersonImportFailureVO;
|
||||
import com.ruoyi.ccdi.domain.vo.IntermediaryEntityImportFailureVO;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryService;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryPersonImportService;
|
||||
import com.ruoyi.ccdi.domain.vo.*;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryEntityImportService;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryPersonImportService;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryService;
|
||||
import com.ruoyi.ccdi.utils.EasyExcelUtil;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
@@ -26,7 +16,6 @@ import com.ruoyi.common.core.page.PageDomain;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.page.TableSupport;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -193,7 +182,7 @@ public class CcdiIntermediaryController extends BaseController {
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:import')")
|
||||
@Log(title = "个人中介", businessType = BusinessType.IMPORT)
|
||||
@PostMapping("/importPersonData")
|
||||
public AjaxResult importPersonData(MultipartFile file, boolean updateSupport) throws Exception {
|
||||
public AjaxResult importPersonData(MultipartFile file) throws Exception {
|
||||
List<CcdiIntermediaryPersonExcel> list = EasyExcelUtil.importExcel(
|
||||
file.getInputStream(), CcdiIntermediaryPersonExcel.class);
|
||||
|
||||
@@ -202,7 +191,7 @@ public class CcdiIntermediaryController extends BaseController {
|
||||
}
|
||||
|
||||
// 提交异步任务
|
||||
String taskId = intermediaryService.importIntermediaryPerson(list, updateSupport);
|
||||
String taskId = intermediaryService.importIntermediaryPerson(list);
|
||||
|
||||
// 立即返回,不等待后台任务完成
|
||||
ImportResultVO result = new ImportResultVO();
|
||||
@@ -220,7 +209,7 @@ public class CcdiIntermediaryController extends BaseController {
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:import')")
|
||||
@Log(title = "实体中介", businessType = BusinessType.IMPORT)
|
||||
@PostMapping("/importEntityData")
|
||||
public AjaxResult importEntityData(MultipartFile file, boolean updateSupport) throws Exception {
|
||||
public AjaxResult importEntityData(MultipartFile file) throws Exception {
|
||||
List<CcdiIntermediaryEntityExcel> list = EasyExcelUtil.importExcel(
|
||||
file.getInputStream(), CcdiIntermediaryEntityExcel.class);
|
||||
|
||||
@@ -229,7 +218,7 @@ public class CcdiIntermediaryController extends BaseController {
|
||||
}
|
||||
|
||||
// 提交异步任务
|
||||
String taskId = intermediaryService.importIntermediaryEntity(list, updateSupport);
|
||||
String taskId = intermediaryService.importIntermediaryEntity(list);
|
||||
|
||||
// 立即返回,不等待后台任务完成
|
||||
ImportResultVO result = new ImportResultVO();
|
||||
|
||||
@@ -6,6 +6,10 @@ import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiStaffRecruitmentExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiStaffRecruitmentVO;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportResultVO;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
||||
import com.ruoyi.ccdi.domain.vo.RecruitmentImportFailureVO;
|
||||
import com.ruoyi.ccdi.service.ICcdiStaffRecruitmentImportService;
|
||||
import com.ruoyi.ccdi.service.ICcdiStaffRecruitmentService;
|
||||
import com.ruoyi.ccdi.utils.EasyExcelUtil;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
@@ -16,6 +20,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.page.TableSupport;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -40,6 +45,9 @@ public class CcdiStaffRecruitmentController extends BaseController {
|
||||
@Resource
|
||||
private ICcdiStaffRecruitmentService recruitmentService;
|
||||
|
||||
@Resource
|
||||
private ICcdiStaffRecruitmentImportService recruitmentImportService;
|
||||
|
||||
/**
|
||||
* 查询招聘信息列表
|
||||
*/
|
||||
@@ -120,15 +128,66 @@ public class CcdiStaffRecruitmentController extends BaseController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入招聘信息
|
||||
* 异步导入招聘信息
|
||||
*/
|
||||
@Operation(summary = "导入招聘信息")
|
||||
@Operation(summary = "异步导入招聘信息")
|
||||
@Parameter(name = "file", description = "导入文件", required = true)
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffRecruitment:import')")
|
||||
@Log(title = "员工招聘信息", businessType = BusinessType.IMPORT)
|
||||
@PostMapping("/importData")
|
||||
public AjaxResult importData(MultipartFile file) throws Exception {
|
||||
public AjaxResult importData(@Parameter(description = "导入文件") MultipartFile file) throws Exception {
|
||||
List<CcdiStaffRecruitmentExcel> list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiStaffRecruitmentExcel.class);
|
||||
String message = recruitmentService.importRecruitment(list);
|
||||
return success(message);
|
||||
|
||||
if (list == null || list.isEmpty()) {
|
||||
return error("至少需要一条数据");
|
||||
}
|
||||
|
||||
// 提交异步任务
|
||||
String taskId = recruitmentService.importRecruitment(list);
|
||||
|
||||
// 立即返回,不等待后台任务完成
|
||||
ImportResultVO result = new ImportResultVO();
|
||||
result.setTaskId(taskId);
|
||||
result.setStatus("PROCESSING");
|
||||
result.setMessage("导入任务已提交,正在后台处理");
|
||||
|
||||
return AjaxResult.success("导入任务已提交,正在后台处理", result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询导入状态
|
||||
*/
|
||||
@Operation(summary = "查询导入状态")
|
||||
@Parameter(name = "taskId", description = "任务ID", required = true)
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffRecruitment:import')")
|
||||
@GetMapping("/importStatus/{taskId}")
|
||||
public AjaxResult getImportStatus(@PathVariable String taskId) {
|
||||
ImportStatusVO statusVO = recruitmentImportService.getImportStatus(taskId);
|
||||
return success(statusVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询导入失败记录
|
||||
*/
|
||||
@Operation(summary = "查询导入失败记录")
|
||||
@Parameter(name = "taskId", description = "任务ID", required = true)
|
||||
@Parameter(name = "pageNum", description = "页码", required = false)
|
||||
@Parameter(name = "pageSize", description = "每页条数", required = false)
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffRecruitment:import')")
|
||||
@GetMapping("/importFailures/{taskId}")
|
||||
public TableDataInfo getImportFailures(
|
||||
@PathVariable String taskId,
|
||||
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize) {
|
||||
|
||||
List<RecruitmentImportFailureVO> failures = recruitmentImportService.getImportFailures(taskId);
|
||||
|
||||
// 手动分页
|
||||
int fromIndex = (pageNum - 1) * pageSize;
|
||||
int toIndex = Math.min(fromIndex + pageSize, failures.size());
|
||||
|
||||
List<RecruitmentImportFailureVO> pageData = failures.subList(fromIndex, toIndex);
|
||||
|
||||
return getDataTable(pageData, failures.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,11 @@ public interface ICcdiIntermediaryEntityImportService {
|
||||
/**
|
||||
* 异步导入实体中介数据
|
||||
*
|
||||
* @param excelList Excel数据列表
|
||||
* @param isUpdateSupport 是否更新已存在的数据
|
||||
* @param taskId 任务ID
|
||||
* @param userName 当前用户名(用于审计字段)
|
||||
* @param excelList Excel数据列表
|
||||
* @param taskId 任务ID
|
||||
* @param userName 当前用户名(用于审计字段)
|
||||
*/
|
||||
void importEntityAsync(List<CcdiIntermediaryEntityExcel> excelList,
|
||||
Boolean isUpdateSupport,
|
||||
String taskId,
|
||||
String userName);
|
||||
|
||||
|
||||
@@ -17,13 +17,11 @@ public interface ICcdiIntermediaryPersonImportService {
|
||||
/**
|
||||
* 异步导入个人中介数据
|
||||
*
|
||||
* @param excelList Excel数据列表
|
||||
* @param isUpdateSupport 是否更新已存在的数据
|
||||
* @param taskId 任务ID
|
||||
* @param userName 当前用户名(用于审计字段)
|
||||
* @param excelList Excel数据列表
|
||||
* @param taskId 任务ID
|
||||
* @param userName 当前用户名(用于审计字段)
|
||||
*/
|
||||
void importPersonAsync(List<CcdiIntermediaryPersonExcel> excelList,
|
||||
Boolean isUpdateSupport,
|
||||
String taskId,
|
||||
String userName);
|
||||
|
||||
|
||||
@@ -101,17 +101,15 @@ public interface ICcdiIntermediaryService {
|
||||
* 导入个人中介数据
|
||||
*
|
||||
* @param list Excel实体列表
|
||||
* @param updateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
String importIntermediaryPerson(java.util.List<com.ruoyi.ccdi.domain.excel.CcdiIntermediaryPersonExcel> list, boolean updateSupport);
|
||||
String importIntermediaryPerson(java.util.List<com.ruoyi.ccdi.domain.excel.CcdiIntermediaryPersonExcel> list);
|
||||
|
||||
/**
|
||||
* 导入实体中介数据
|
||||
*
|
||||
* @param list Excel实体列表
|
||||
* @param updateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
String importIntermediaryEntity(java.util.List<com.ruoyi.ccdi.domain.excel.CcdiIntermediaryEntityExcel> list, boolean updateSupport);
|
||||
String importIntermediaryEntity(java.util.List<com.ruoyi.ccdi.domain.excel.CcdiIntermediaryEntityExcel> list);
|
||||
}
|
||||
|
||||
@@ -17,12 +17,11 @@ public interface ICcdiStaffRecruitmentImportService {
|
||||
/**
|
||||
* 异步导入招聘信息数据
|
||||
*
|
||||
* @param excelList Excel数据列表
|
||||
* @param isUpdateSupport 是否更新已存在的数据
|
||||
* @param taskId 任务ID
|
||||
* @param excelList Excel数据列表
|
||||
* @param taskId 任务ID
|
||||
* @param userName 用户名
|
||||
*/
|
||||
void importRecruitmentAsync(List<CcdiStaffRecruitmentExcel> excelList,
|
||||
Boolean isUpdateSupport,
|
||||
String taskId,
|
||||
String userName);
|
||||
|
||||
|
||||
@@ -42,20 +42,24 @@ public class CcdiIntermediaryEntityImportServiceImpl implements ICcdiIntermediar
|
||||
@Async
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void importEntityAsync(List<CcdiIntermediaryEntityExcel> excelList,
|
||||
Boolean isUpdateSupport,
|
||||
String taskId,
|
||||
String userName) {
|
||||
List<CcdiEnterpriseBaseInfo> validRecords = new ArrayList<>();
|
||||
List<CcdiEnterpriseBaseInfo> newRecords = new ArrayList<>();
|
||||
List<IntermediaryEntityImportFailureVO> failures = new ArrayList<>();
|
||||
|
||||
// 1. 批量查询已存在的统一社会信用代码
|
||||
// 批量查询已存在的统一社会信用代码
|
||||
Set<String> existingCreditCodes = getExistingCreditCodes(excelList);
|
||||
|
||||
// 2. 验证并转换数据
|
||||
for (CcdiIntermediaryEntityExcel excel : excelList) {
|
||||
// 用于检测Excel内部的重复ID
|
||||
Set<String> excelProcessedIds = new HashSet<>();
|
||||
|
||||
// 分类数据
|
||||
for (int i = 0; i < excelList.size(); i++) {
|
||||
CcdiIntermediaryEntityExcel excel = excelList.get(i);
|
||||
|
||||
try {
|
||||
// 验证数据
|
||||
validateEntityData(excel, isUpdateSupport, existingCreditCodes);
|
||||
validateEntityData(excel, existingCreditCodes);
|
||||
|
||||
CcdiEnterpriseBaseInfo entity = new CcdiEnterpriseBaseInfo();
|
||||
BeanUtils.copyProperties(excel, entity);
|
||||
@@ -64,57 +68,41 @@ public class CcdiIntermediaryEntityImportServiceImpl implements ICcdiIntermediar
|
||||
entity.setDataSource("IMPORT");
|
||||
entity.setEntSource("INTERMEDIARY");
|
||||
entity.setCreatedBy(userName);
|
||||
if (existingCreditCodes.contains(excel.getSocialCreditCode()) && isUpdateSupport) {
|
||||
entity.setUpdatedBy(userName);
|
||||
}
|
||||
entity.setUpdatedBy(userName);
|
||||
|
||||
validRecords.add(entity);
|
||||
if (existingCreditCodes.contains(excel.getSocialCreditCode())) {
|
||||
// 统一社会信用代码在数据库中已存在,直接报错
|
||||
throw new RuntimeException(String.format("统一社会信用代码[%s]已存在,请勿重复导入", excel.getSocialCreditCode()));
|
||||
} else if (excelProcessedIds.contains(excel.getSocialCreditCode())) {
|
||||
// 统一社会信用代码在Excel文件内部重复
|
||||
throw new RuntimeException(String.format("统一社会信用代码[%s]在导入文件中重复,已跳过此条记录", excel.getSocialCreditCode()));
|
||||
} else {
|
||||
newRecords.add(entity);
|
||||
excelProcessedIds.add(excel.getSocialCreditCode()); // 标记为已处理
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
failures.add(createFailureVO(excel, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 根据isUpdateSupport选择处理方式
|
||||
int actualSuccessCount = 0;
|
||||
if (isUpdateSupport) {
|
||||
// 更新模式:直接批量导入,数据库自动处理INSERT或UPDATE
|
||||
if (!validRecords.isEmpty()) {
|
||||
actualSuccessCount = saveBatchWithUpsert(validRecords, 500);
|
||||
}
|
||||
} else {
|
||||
// 仅新增模式:先查询已存在的记录,对冲突的抛出异常
|
||||
Set<String> actualExistingCreditCodes = getExistingCreditCodesFromDb(validRecords);
|
||||
List<CcdiEnterpriseBaseInfo> actualNewRecords = new ArrayList<>();
|
||||
|
||||
for (CcdiEnterpriseBaseInfo record : validRecords) {
|
||||
if (actualExistingCreditCodes.contains(record.getSocialCreditCode())) {
|
||||
// 记录到失败列表
|
||||
failures.add(createFailureVO(record, "该统一社会信用代码已存在"));
|
||||
} else {
|
||||
actualNewRecords.add(record);
|
||||
}
|
||||
}
|
||||
|
||||
// 批量插入新记录
|
||||
if (!actualNewRecords.isEmpty()) {
|
||||
int insertCount = saveBatch(actualNewRecords, 500);
|
||||
actualSuccessCount = insertCount;
|
||||
}
|
||||
// 批量插入新数据
|
||||
if (!newRecords.isEmpty()) {
|
||||
saveBatch(newRecords, 500);
|
||||
}
|
||||
|
||||
// 4. 保存失败记录到Redis
|
||||
// 保存失败记录到Redis
|
||||
if (!failures.isEmpty()) {
|
||||
String failuresKey = "import:intermediary-entity:" + taskId + ":failures";
|
||||
redisTemplate.opsForValue().set(failuresKey, failures, 7, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
// 5. 更新最终状态
|
||||
ImportResult result = new ImportResult();
|
||||
result.setTotalCount(excelList.size());
|
||||
result.setSuccessCount(actualSuccessCount);
|
||||
result.setSuccessCount(newRecords.size());
|
||||
result.setFailureCount(failures.size());
|
||||
|
||||
// 更新最终状态
|
||||
String finalStatus = result.getFailureCount() == 0 ? "SUCCESS" : "PARTIAL_SUCCESS";
|
||||
updateImportStatus(taskId, finalStatus, result);
|
||||
}
|
||||
@@ -273,11 +261,9 @@ public class CcdiIntermediaryEntityImportServiceImpl implements ICcdiIntermediar
|
||||
* 验证实体中介数据
|
||||
*
|
||||
* @param excel Excel数据
|
||||
* @param isUpdateSupport 是否支持更新
|
||||
* @param existingCreditCodes 已存在的统一社会信用代码集合
|
||||
*/
|
||||
private void validateEntityData(CcdiIntermediaryEntityExcel excel,
|
||||
Boolean isUpdateSupport,
|
||||
Set<String> existingCreditCodes) {
|
||||
// 验证必填字段:机构名称
|
||||
if (StringUtils.isEmpty(excel.getEnterpriseName())) {
|
||||
@@ -289,18 +275,9 @@ public class CcdiIntermediaryEntityImportServiceImpl implements ICcdiIntermediar
|
||||
throw new RuntimeException("统一社会信用代码不能为空");
|
||||
}
|
||||
|
||||
// 如果统一社会信用代码已存在但未启用更新支持,抛出异常
|
||||
if (existingCreditCodes.contains(excel.getSocialCreditCode()) && !isUpdateSupport) {
|
||||
throw new RuntimeException("该统一社会信用代码已存在");
|
||||
}
|
||||
|
||||
// 如果统一社会信用代码不存在,检查唯一性
|
||||
if (!existingCreditCodes.contains(excel.getSocialCreditCode())) {
|
||||
LambdaQueryWrapper<CcdiEnterpriseBaseInfo> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CcdiEnterpriseBaseInfo::getSocialCreditCode, excel.getSocialCreditCode());
|
||||
if (entityMapper.selectCount(wrapper) > 0) {
|
||||
throw new RuntimeException("该统一社会信用代码已存在");
|
||||
}
|
||||
// 统一社会信用代码格式验证(18位)
|
||||
if (excel.getSocialCreditCode().length() != 18) {
|
||||
throw new RuntimeException("统一社会信用代码必须为18位");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,20 +43,24 @@ public class CcdiIntermediaryPersonImportServiceImpl implements ICcdiIntermediar
|
||||
@Async
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void importPersonAsync(List<CcdiIntermediaryPersonExcel> excelList,
|
||||
Boolean isUpdateSupport,
|
||||
String taskId,
|
||||
String userName) {
|
||||
List<CcdiBizIntermediary> validRecords = new ArrayList<>();
|
||||
List<CcdiBizIntermediary> newRecords = new ArrayList<>();
|
||||
List<IntermediaryPersonImportFailureVO> failures = new ArrayList<>();
|
||||
|
||||
// 1. 批量查询已存在的证件号
|
||||
// 批量查询已存在的证件号
|
||||
Set<String> existingPersonIds = getExistingPersonIds(excelList);
|
||||
|
||||
// 2. 验证并转换数据
|
||||
for (CcdiIntermediaryPersonExcel excel : excelList) {
|
||||
// 用于检测Excel内部的重复ID
|
||||
Set<String> excelProcessedIds = new HashSet<>();
|
||||
|
||||
// 分类数据
|
||||
for (int i = 0; i < excelList.size(); i++) {
|
||||
CcdiIntermediaryPersonExcel excel = excelList.get(i);
|
||||
|
||||
try {
|
||||
// 验证数据
|
||||
validatePersonData(excel, isUpdateSupport, existingPersonIds);
|
||||
validatePersonData(excel, existingPersonIds);
|
||||
|
||||
CcdiBizIntermediary intermediary = new CcdiBizIntermediary();
|
||||
BeanUtils.copyProperties(excel, intermediary);
|
||||
@@ -64,57 +68,41 @@ public class CcdiIntermediaryPersonImportServiceImpl implements ICcdiIntermediar
|
||||
// 设置数据来源和审计字段
|
||||
intermediary.setDataSource("IMPORT");
|
||||
intermediary.setCreatedBy(userName);
|
||||
if (existingPersonIds.contains(excel.getPersonId()) && isUpdateSupport) {
|
||||
intermediary.setUpdatedBy(userName);
|
||||
}
|
||||
intermediary.setUpdatedBy(userName);
|
||||
|
||||
validRecords.add(intermediary);
|
||||
if (existingPersonIds.contains(excel.getPersonId())) {
|
||||
// 证件号码在数据库中已存在,直接报错
|
||||
throw new RuntimeException(String.format("证件号码[%s]已存在,请勿重复导入", excel.getPersonId()));
|
||||
} else if (excelProcessedIds.contains(excel.getPersonId())) {
|
||||
// 证件号码在Excel文件内部重复
|
||||
throw new RuntimeException(String.format("证件号码[%s]在导入文件中重复,已跳过此条记录", excel.getPersonId()));
|
||||
} else {
|
||||
newRecords.add(intermediary);
|
||||
excelProcessedIds.add(excel.getPersonId()); // 标记为已处理
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
failures.add(createFailureVO(excel, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 根据isUpdateSupport选择处理方式
|
||||
int actualSuccessCount = 0;
|
||||
if (isUpdateSupport) {
|
||||
// 更新模式:直接批量导入,数据库自动处理INSERT或UPDATE
|
||||
if (!validRecords.isEmpty()) {
|
||||
actualSuccessCount = saveBatchWithUpsert(validRecords, 500);
|
||||
}
|
||||
} else {
|
||||
// 仅新增模式:先查询已存在的记录,对冲突的抛出异常
|
||||
Set<String> actualExistingPersonIds = getExistingPersonIdsFromDb(validRecords);
|
||||
List<CcdiBizIntermediary> actualNewRecords = new ArrayList<>();
|
||||
|
||||
for (CcdiBizIntermediary record : validRecords) {
|
||||
if (actualExistingPersonIds.contains(record.getPersonId())) {
|
||||
// 记录到失败列表
|
||||
failures.add(createFailureVO(record, "该证件号码已存在"));
|
||||
} else {
|
||||
actualNewRecords.add(record);
|
||||
}
|
||||
}
|
||||
|
||||
// 批量插入新记录
|
||||
if (!actualNewRecords.isEmpty()) {
|
||||
int insertCount = saveBatch(actualNewRecords, 500);
|
||||
actualSuccessCount = insertCount;
|
||||
}
|
||||
// 批量插入新数据
|
||||
if (!newRecords.isEmpty()) {
|
||||
saveBatch(newRecords, 500);
|
||||
}
|
||||
|
||||
// 4. 保存失败记录到Redis
|
||||
// 保存失败记录到Redis
|
||||
if (!failures.isEmpty()) {
|
||||
String failuresKey = "import:intermediary:" + taskId + ":failures";
|
||||
redisTemplate.opsForValue().set(failuresKey, failures, 7, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
// 5. 更新最终状态
|
||||
ImportResult result = new ImportResult();
|
||||
result.setTotalCount(excelList.size());
|
||||
result.setSuccessCount(actualSuccessCount);
|
||||
result.setSuccessCount(newRecords.size());
|
||||
result.setFailureCount(failures.size());
|
||||
|
||||
// 更新最终状态
|
||||
String finalStatus = result.getFailureCount() == 0 ? "SUCCESS" : "PARTIAL_SUCCESS";
|
||||
updateImportStatus(taskId, finalStatus, result);
|
||||
}
|
||||
@@ -273,11 +261,9 @@ public class CcdiIntermediaryPersonImportServiceImpl implements ICcdiIntermediar
|
||||
* 验证个人中介数据
|
||||
*
|
||||
* @param excel Excel数据
|
||||
* @param isUpdateSupport 是否支持更新
|
||||
* @param existingPersonIds 已存在的证件号集合
|
||||
*/
|
||||
private void validatePersonData(CcdiIntermediaryPersonExcel excel,
|
||||
Boolean isUpdateSupport,
|
||||
Set<String> existingPersonIds) {
|
||||
// 验证必填字段:姓名
|
||||
if (StringUtils.isEmpty(excel.getName())) {
|
||||
@@ -294,19 +280,5 @@ public class CcdiIntermediaryPersonImportServiceImpl implements ICcdiIntermediar
|
||||
if (idCardError != null) {
|
||||
throw new RuntimeException("证件号码" + idCardError);
|
||||
}
|
||||
|
||||
// 如果证件号已存在但未启用更新支持,抛出异常
|
||||
if (existingPersonIds.contains(excel.getPersonId()) && !isUpdateSupport) {
|
||||
throw new RuntimeException("该证件号码已存在");
|
||||
}
|
||||
|
||||
// 如果证件号不存在,检查唯一性
|
||||
if (!existingPersonIds.contains(excel.getPersonId())) {
|
||||
LambdaQueryWrapper<CcdiBizIntermediary> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CcdiBizIntermediary::getPersonId, excel.getPersonId());
|
||||
if (intermediaryMapper.selectCount(wrapper) > 0) {
|
||||
throw new RuntimeException("该证件号码已存在");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryVO;
|
||||
import com.ruoyi.ccdi.mapper.CcdiBizIntermediaryMapper;
|
||||
import com.ruoyi.ccdi.mapper.CcdiEnterpriseBaseInfoMapper;
|
||||
import com.ruoyi.ccdi.mapper.CcdiIntermediaryMapper;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryService;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryPersonImportService;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryEntityImportService;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryPersonImportService;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryService;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -24,7 +24,6 @@ import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -258,14 +257,12 @@ public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
|
||||
/**
|
||||
* 导入个人中介数据(异步)
|
||||
*
|
||||
* @param list Excel实体列表
|
||||
* @param updateSupport 是否更新支持
|
||||
* @param list Excel实体列表
|
||||
* @return 任务ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public String importIntermediaryPerson(List<CcdiIntermediaryPersonExcel> list,
|
||||
boolean updateSupport) {
|
||||
public String importIntermediaryPerson(List<CcdiIntermediaryPersonExcel> list) {
|
||||
String taskId = UUID.randomUUID().toString();
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
@@ -288,7 +285,7 @@ public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
|
||||
String userName = SecurityUtils.getUsername();
|
||||
|
||||
// 调用异步方法
|
||||
personImportService.importPersonAsync(list, updateSupport, taskId, userName);
|
||||
personImportService.importPersonAsync(list, taskId, userName);
|
||||
|
||||
return taskId;
|
||||
}
|
||||
@@ -296,14 +293,12 @@ public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
|
||||
/**
|
||||
* 导入实体中介数据(异步)
|
||||
*
|
||||
* @param list Excel实体列表
|
||||
* @param updateSupport 是否更新支持
|
||||
* @param list Excel实体列表
|
||||
* @return 任务ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public String importIntermediaryEntity(List<CcdiIntermediaryEntityExcel> list,
|
||||
boolean updateSupport) {
|
||||
public String importIntermediaryEntity(List<CcdiIntermediaryEntityExcel> list) {
|
||||
String taskId = UUID.randomUUID().toString();
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
@@ -326,7 +321,7 @@ public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
|
||||
String userName = SecurityUtils.getUsername();
|
||||
|
||||
// 调用异步方法
|
||||
entityImportService.importEntityAsync(list, updateSupport, taskId, userName);
|
||||
entityImportService.importEntityAsync(list, taskId, userName);
|
||||
|
||||
return taskId;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.ruoyi.ccdi.service.impl;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.ruoyi.ccdi.domain.CcdiStaffRecruitment;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentAddDTO;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiStaffRecruitmentExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportResult;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
||||
@@ -18,6 +19,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.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -41,54 +43,45 @@ public class CcdiStaffRecruitmentImportServiceImpl implements ICcdiStaffRecruitm
|
||||
|
||||
@Override
|
||||
@Async
|
||||
@Transactional
|
||||
public void importRecruitmentAsync(List<CcdiStaffRecruitmentExcel> excelList,
|
||||
Boolean isUpdateSupport,
|
||||
String taskId,
|
||||
String userName) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
// 初始化Redis状态
|
||||
String statusKey = "import:recruitment:" + taskId;
|
||||
Map<String, Object> 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);
|
||||
|
||||
List<CcdiStaffRecruitment> newRecords = new ArrayList<>();
|
||||
List<CcdiStaffRecruitment> updateRecords = new ArrayList<>();
|
||||
List<RecruitmentImportFailureVO> failures = new ArrayList<>();
|
||||
|
||||
// 批量查询已存在的招聘项目编号
|
||||
Set<String> existingRecruitIds = getExistingRecruitIds(excelList);
|
||||
|
||||
// 用于检测Excel内部的重复ID
|
||||
Set<String> excelProcessedIds = new HashSet<>();
|
||||
|
||||
// 分类数据
|
||||
for (CcdiStaffRecruitmentExcel excel : excelList) {
|
||||
for (int i = 0; i < excelList.size(); i++) {
|
||||
CcdiStaffRecruitmentExcel excel = excelList.get(i);
|
||||
|
||||
try {
|
||||
// 转换为AddDTO进行验证
|
||||
CcdiStaffRecruitmentAddDTO addDTO = new CcdiStaffRecruitmentAddDTO();
|
||||
BeanUtils.copyProperties(excel, addDTO);
|
||||
|
||||
// 验证数据
|
||||
validateRecruitmentData(excel, isUpdateSupport, existingRecruitIds);
|
||||
validateRecruitmentData(addDTO, existingRecruitIds);
|
||||
|
||||
CcdiStaffRecruitment recruitment = new CcdiStaffRecruitment();
|
||||
BeanUtils.copyProperties(excel, recruitment);
|
||||
|
||||
if (existingRecruitIds.contains(excel.getRecruitId())) {
|
||||
if (isUpdateSupport) {
|
||||
recruitment.setUpdatedBy(userName);
|
||||
updateRecords.add(recruitment);
|
||||
} else {
|
||||
throw new RuntimeException("该招聘项目编号已存在");
|
||||
}
|
||||
// 招聘项目编号在数据库中已存在,直接报错
|
||||
throw new RuntimeException(String.format("招聘项目编号[%s]已存在,请勿重复导入", excel.getRecruitId()));
|
||||
} else if (excelProcessedIds.contains(excel.getRecruitId())) {
|
||||
// 招聘项目编号在Excel文件内部重复
|
||||
throw new RuntimeException(String.format("招聘项目编号[%s]在导入文件中重复,已跳过此条记录", excel.getRecruitId()));
|
||||
} else {
|
||||
recruitment.setCreatedBy(userName);
|
||||
recruitment.setUpdatedBy(userName);
|
||||
newRecords.add(recruitment);
|
||||
excelProcessedIds.add(excel.getRecruitId()); // 标记为已处理
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -101,12 +94,7 @@ public class CcdiStaffRecruitmentImportServiceImpl implements ICcdiStaffRecruitm
|
||||
|
||||
// 批量插入新数据
|
||||
if (!newRecords.isEmpty()) {
|
||||
recruitmentMapper.insertBatch(newRecords);
|
||||
}
|
||||
|
||||
// 批量更新已有数据
|
||||
if (!updateRecords.isEmpty() && isUpdateSupport) {
|
||||
recruitmentMapper.updateBatch(updateRecords);
|
||||
saveBatch(newRecords, 500);
|
||||
}
|
||||
|
||||
// 保存失败记录到Redis
|
||||
@@ -115,12 +103,12 @@ public class CcdiStaffRecruitmentImportServiceImpl implements ICcdiStaffRecruitm
|
||||
redisTemplate.opsForValue().set(failuresKey, failures, 7, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
// 更新最终状态
|
||||
ImportResult result = new ImportResult();
|
||||
result.setTotalCount(excelList.size());
|
||||
result.setSuccessCount(newRecords.size() + updateRecords.size());
|
||||
result.setSuccessCount(newRecords.size());
|
||||
result.setFailureCount(failures.size());
|
||||
|
||||
// 更新最终状态
|
||||
String finalStatus = result.getFailureCount() == 0 ? "SUCCESS" : "PARTIAL_SUCCESS";
|
||||
updateImportStatus(taskId, finalStatus, result);
|
||||
}
|
||||
@@ -187,60 +175,59 @@ public class CcdiStaffRecruitmentImportServiceImpl implements ICcdiStaffRecruitm
|
||||
/**
|
||||
* 验证招聘信息数据
|
||||
*/
|
||||
private void validateRecruitmentData(CcdiStaffRecruitmentExcel excel,
|
||||
Boolean isUpdateSupport,
|
||||
private void validateRecruitmentData(CcdiStaffRecruitmentAddDTO addDTO,
|
||||
Set<String> existingRecruitIds) {
|
||||
// 验证必填字段
|
||||
if (StringUtils.isEmpty(excel.getRecruitId())) {
|
||||
if (StringUtils.isEmpty(addDTO.getRecruitId())) {
|
||||
throw new RuntimeException("招聘项目编号不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getRecruitName())) {
|
||||
if (StringUtils.isEmpty(addDTO.getRecruitName())) {
|
||||
throw new RuntimeException("招聘项目名称不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getPosName())) {
|
||||
if (StringUtils.isEmpty(addDTO.getPosName())) {
|
||||
throw new RuntimeException("职位名称不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getPosCategory())) {
|
||||
if (StringUtils.isEmpty(addDTO.getPosCategory())) {
|
||||
throw new RuntimeException("职位类别不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getPosDesc())) {
|
||||
if (StringUtils.isEmpty(addDTO.getPosDesc())) {
|
||||
throw new RuntimeException("职位描述不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandName())) {
|
||||
if (StringUtils.isEmpty(addDTO.getCandName())) {
|
||||
throw new RuntimeException("应聘人员姓名不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandEdu())) {
|
||||
if (StringUtils.isEmpty(addDTO.getCandEdu())) {
|
||||
throw new RuntimeException("应聘人员学历不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandId())) {
|
||||
if (StringUtils.isEmpty(addDTO.getCandId())) {
|
||||
throw new RuntimeException("证件号码不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandSchool())) {
|
||||
if (StringUtils.isEmpty(addDTO.getCandSchool())) {
|
||||
throw new RuntimeException("应聘人员毕业院校不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandMajor())) {
|
||||
if (StringUtils.isEmpty(addDTO.getCandMajor())) {
|
||||
throw new RuntimeException("应聘人员专业不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandGrad())) {
|
||||
if (StringUtils.isEmpty(addDTO.getCandGrad())) {
|
||||
throw new RuntimeException("应聘人员毕业年月不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getAdmitStatus())) {
|
||||
if (StringUtils.isEmpty(addDTO.getAdmitStatus())) {
|
||||
throw new RuntimeException("录用情况不能为空");
|
||||
}
|
||||
|
||||
// 验证证件号码格式
|
||||
String idCardError = IdCardUtil.getErrorMessage(excel.getCandId());
|
||||
String idCardError = IdCardUtil.getErrorMessage(addDTO.getCandId());
|
||||
if (idCardError != null) {
|
||||
throw new RuntimeException("证件号码" + idCardError);
|
||||
}
|
||||
|
||||
// 验证毕业年月格式(YYYYMM)
|
||||
if (!excel.getCandGrad().matches("^((19|20)\\d{2})(0[1-9]|1[0-2])$")) {
|
||||
if (!addDTO.getCandGrad().matches("^((19|20)\\d{2})(0[1-9]|1[0-2])$")) {
|
||||
throw new RuntimeException("毕业年月格式不正确,应为YYYYMM");
|
||||
}
|
||||
|
||||
// 验证录用状态
|
||||
if (AdmitStatus.getDescByCode(excel.getAdmitStatus()) == null) {
|
||||
if (AdmitStatus.getDescByCode(addDTO.getAdmitStatus()) == null) {
|
||||
throw new RuntimeException("录用情况只能填写'录用'、'未录用'或'放弃'");
|
||||
}
|
||||
}
|
||||
@@ -266,4 +253,36 @@ public class CcdiStaffRecruitmentImportServiceImpl implements ICcdiStaffRecruitm
|
||||
|
||||
redisTemplate.opsForHash().putAll(key, statusData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量保存
|
||||
*/
|
||||
private void saveBatch(List<CcdiStaffRecruitment> list, int batchSize) {
|
||||
// 使用真正的批量插入,分批次执行以提高性能
|
||||
for (int i = 0; i < list.size(); i += batchSize) {
|
||||
int end = Math.min(i + batchSize, list.size());
|
||||
List<CcdiStaffRecruitment> subList = list.subList(i, end);
|
||||
|
||||
// 过滤掉已存在的记录,防止主键冲突
|
||||
List<String> recruitIds = subList.stream()
|
||||
.map(CcdiStaffRecruitment::getRecruitId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!recruitIds.isEmpty()) {
|
||||
List<CcdiStaffRecruitment> existingRecords = recruitmentMapper.selectBatchIds(recruitIds);
|
||||
Set<String> existingIds = existingRecords.stream()
|
||||
.map(CcdiStaffRecruitment::getRecruitId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 只插入不存在的记录
|
||||
List<CcdiStaffRecruitment> toInsert = subList.stream()
|
||||
.filter(r -> !existingIds.contains(r.getRecruitId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!toInsert.isEmpty()) {
|
||||
recruitmentMapper.insertBatch(toInsert);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.ruoyi.ccdi.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.CcdiStaffRecruitment;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentAddDTO;
|
||||
@@ -10,19 +9,21 @@ import com.ruoyi.ccdi.domain.excel.CcdiStaffRecruitmentExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiStaffRecruitmentVO;
|
||||
import com.ruoyi.ccdi.enums.AdmitStatus;
|
||||
import com.ruoyi.ccdi.mapper.CcdiStaffRecruitmentMapper;
|
||||
import com.ruoyi.ccdi.service.ICcdiStaffRecruitmentImportService;
|
||||
import com.ruoyi.ccdi.service.ICcdiStaffRecruitmentService;
|
||||
import com.ruoyi.common.utils.IdCardUtil;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
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.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 员工招聘信息 服务层处理
|
||||
@@ -36,6 +37,12 @@ public class CcdiStaffRecruitmentServiceImpl implements ICcdiStaffRecruitmentSer
|
||||
@Resource
|
||||
private CcdiStaffRecruitmentMapper recruitmentMapper;
|
||||
|
||||
@Resource
|
||||
private ICcdiStaffRecruitmentImportService recruitmentImportService;
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* 查询招聘信息列表
|
||||
*
|
||||
@@ -151,149 +158,43 @@ public class CcdiStaffRecruitmentServiceImpl implements ICcdiStaffRecruitmentSer
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入招聘信息数据(批量优化版本)
|
||||
* 导入招聘信息数据(异步)
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @return 结果
|
||||
* @return 任务ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public String importRecruitment(List<CcdiStaffRecruitmentExcel> excelList) {
|
||||
public String importRecruitment(java.util.List<CcdiStaffRecruitmentExcel> excelList) {
|
||||
if (StringUtils.isNull(excelList) || excelList.isEmpty()) {
|
||||
return "至少需要一条数据";
|
||||
throw new RuntimeException("至少需要一条数据");
|
||||
}
|
||||
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
StringBuilder successMsg = new StringBuilder();
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
// 生成任务ID
|
||||
String taskId = UUID.randomUUID().toString();
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
// 第一阶段:数据验证和分类
|
||||
List<CcdiStaffRecruitment> toInsertList = new ArrayList<>();
|
||||
// 获取当前用户名
|
||||
String userName = SecurityUtils.getUsername();
|
||||
|
||||
// 批量收集所有招聘项目编号
|
||||
List<String> recruitIds = new ArrayList<>();
|
||||
// 初始化Redis状态
|
||||
String statusKey = "import:recruitment:" + taskId;
|
||||
Map<String, Object> 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", "正在处理...");
|
||||
|
||||
for (CcdiStaffRecruitmentExcel excel : excelList) {
|
||||
if (StringUtils.isNotEmpty(excel.getRecruitId())) {
|
||||
recruitIds.add(excel.getRecruitId());
|
||||
}
|
||||
}
|
||||
redisTemplate.opsForHash().putAll(statusKey, statusData);
|
||||
redisTemplate.expire(statusKey, 7, TimeUnit.DAYS);
|
||||
|
||||
// 批量查询已存在的招聘项目编号
|
||||
Map<String, CcdiStaffRecruitment> existingRecruitmentMap = new HashMap<>();
|
||||
if (!recruitIds.isEmpty()) {
|
||||
LambdaQueryWrapper<CcdiStaffRecruitment> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.in(CcdiStaffRecruitment::getRecruitId, recruitIds);
|
||||
List<CcdiStaffRecruitment> existingRecruitments = recruitmentMapper.selectList(wrapper);
|
||||
existingRecruitmentMap = existingRecruitments.stream()
|
||||
.collect(Collectors.toMap(CcdiStaffRecruitment::getRecruitId, r -> r));
|
||||
}
|
||||
// 调用异步导入服务
|
||||
recruitmentImportService.importRecruitmentAsync(excelList, taskId, userName);
|
||||
|
||||
// 第二阶段:处理每条数据
|
||||
for (int i = 0; i < excelList.size(); i++) {
|
||||
CcdiStaffRecruitmentExcel excel = excelList.get(i);
|
||||
try {
|
||||
// 验证必填字段和数据格式
|
||||
validateRecruitmentDataBasic(excel);
|
||||
|
||||
CcdiStaffRecruitment recruitment = new CcdiStaffRecruitment();
|
||||
BeanUtils.copyProperties(excel, recruitment);
|
||||
|
||||
// 检查是否已存在
|
||||
CcdiStaffRecruitment existingRecruitment = existingRecruitmentMap.get(excel.getRecruitId());
|
||||
|
||||
// 判断数据状态
|
||||
if (existingRecruitment != null) {
|
||||
// 招聘项目编号已存在,直接报错
|
||||
throw new RuntimeException(String.format("招聘项目编号[%s]已存在,请勿重复导入", excel.getRecruitId()));
|
||||
} else {
|
||||
// 招聘项目编号不存在,新增数据
|
||||
recruitment.setCreatedBy("导入");
|
||||
toInsertList.add(recruitment);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、招聘项目编号 ").append(excel.getRecruitId())
|
||||
.append(" 导入失败:").append(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 第三阶段:批量执行数据库操作
|
||||
if (!toInsertList.isEmpty()) {
|
||||
// 使用自定义批量插入方法
|
||||
recruitmentMapper.insertBatch(toInsertList);
|
||||
successNum += toInsertList.size();
|
||||
}
|
||||
|
||||
// 第四阶段:返回结果(只返回错误信息)
|
||||
if (failureNum > 0) {
|
||||
failureMsg.insert(0, "很抱歉,导入完成!成功 " + successNum + " 条,失败 " + failureNum + " 条,错误如下:");
|
||||
throw new RuntimeException(failureMsg.toString());
|
||||
} else {
|
||||
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据类型:新增 ");
|
||||
successMsg.append(toInsertList.size()).append(" 条");
|
||||
return successMsg.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证招聘信息数据(仅基本字段验证,不进行数据库查询)
|
||||
*/
|
||||
private void validateRecruitmentDataBasic(CcdiStaffRecruitmentExcel excel) {
|
||||
// 验证必填字段
|
||||
if (StringUtils.isEmpty(excel.getRecruitId())) {
|
||||
throw new RuntimeException("招聘项目编号不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getRecruitName())) {
|
||||
throw new RuntimeException("招聘项目名称不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getPosName())) {
|
||||
throw new RuntimeException("职位名称不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getPosCategory())) {
|
||||
throw new RuntimeException("职位类别不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getPosDesc())) {
|
||||
throw new RuntimeException("职位描述不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandName())) {
|
||||
throw new RuntimeException("应聘人员姓名不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandEdu())) {
|
||||
throw new RuntimeException("应聘人员学历不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandId())) {
|
||||
throw new RuntimeException("证件号码不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandSchool())) {
|
||||
throw new RuntimeException("应聘人员毕业院校不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandMajor())) {
|
||||
throw new RuntimeException("应聘人员专业不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandGrad())) {
|
||||
throw new RuntimeException("应聘人员毕业年月不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getAdmitStatus())) {
|
||||
throw new RuntimeException("录用情况不能为空");
|
||||
}
|
||||
|
||||
// 验证证件号码格式
|
||||
String idCardError = IdCardUtil.getErrorMessage(excel.getCandId());
|
||||
if (idCardError != null) {
|
||||
throw new RuntimeException("证件号码" + idCardError);
|
||||
}
|
||||
|
||||
// 验证毕业年月格式(YYYYMM)
|
||||
if (!excel.getCandGrad().matches("^((19|20)\\d{2})(0[1-9]|1[0-2])$")) {
|
||||
throw new RuntimeException("毕业年月格式不正确,应为YYYYMM");
|
||||
}
|
||||
|
||||
// 验证录用状态
|
||||
if (AdmitStatus.getDescByCode(excel.getAdmitStatus()) == null) {
|
||||
throw new RuntimeException("录用情况只能填写'录用'、'未录用'或'放弃'");
|
||||
}
|
||||
return taskId;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user