完成员工亲属实体关联改造并清理旧数据

This commit is contained in:
wkc
2026-04-24 08:55:05 +08:00
parent b7d020c0b2
commit b7db711906
25 changed files with 1298 additions and 219 deletions

View File

@@ -5,6 +5,7 @@ import com.ruoyi.info.collection.domain.dto.CcdiStaffEnterpriseRelationAddDTO;
import com.ruoyi.info.collection.domain.dto.CcdiStaffEnterpriseRelationEditDTO;
import com.ruoyi.info.collection.domain.dto.CcdiStaffEnterpriseRelationQueryDTO;
import com.ruoyi.info.collection.domain.excel.CcdiStaffEnterpriseRelationExcel;
import com.ruoyi.info.collection.domain.vo.CcdiStaffEnterpriseRelationOptionVO;
import com.ruoyi.info.collection.domain.vo.CcdiStaffEnterpriseRelationVO;
import com.ruoyi.info.collection.domain.vo.ImportResultVO;
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
@@ -33,12 +34,12 @@ import java.util.ArrayList;
import java.util.List;
/**
* 员工实体关系信息Controller
* 员工亲属实体关Controller
*
* @author ruoyi
* @date 2026-02-09
*/
@Tag(name = "员工实体关系信息管理")
@Tag(name = "员工亲属实体关管理")
@RestController
@RequestMapping("/ccdi/staffEnterpriseRelation")
public class CcdiStaffEnterpriseRelationController extends BaseController {
@@ -50,9 +51,9 @@ public class CcdiStaffEnterpriseRelationController extends BaseController {
private ICcdiStaffEnterpriseRelationImportService relationImportService;
/**
* 查询员工实体关列表
* 查询员工亲属实体关列表
*/
@Operation(summary = "查询员工实体关列表")
@Operation(summary = "查询员工亲属实体关列表")
@PreAuthorize("@ss.hasPermi('ccdi:staffEnterpriseRelation:list')")
@GetMapping("/list")
public TableDataInfo list(CcdiStaffEnterpriseRelationQueryDTO queryDTO) {
@@ -64,9 +65,20 @@ public class CcdiStaffEnterpriseRelationController extends BaseController {
}
/**
* 获取员工实体关系详细信息
* 查询有效员工亲属下拉列表
*/
@Operation(summary = "获取员工实体关系详细信息")
@Operation(summary = "查询有效员工亲属下拉列表")
@PreAuthorize("@ss.hasPermi('ccdi:staffEnterpriseRelation:list')")
@GetMapping("/familyOptions")
public AjaxResult familyOptions(@RequestParam(required = false) String query) {
List<CcdiStaffEnterpriseRelationOptionVO> list = relationService.selectFamilyOptions(query);
return success(list);
}
/**
* 获取员工亲属实体关联详细信息
*/
@Operation(summary = "获取员工亲属实体关联详细信息")
@Parameter(name = "id", description = "主键ID", required = true)
@PreAuthorize("@ss.hasPermi('ccdi:staffEnterpriseRelation:query')")
@GetMapping(value = "/{id}")
@@ -75,34 +87,34 @@ public class CcdiStaffEnterpriseRelationController extends BaseController {
}
/**
* 新增员工实体关
* 新增员工亲属实体关
*/
@Operation(summary = "新增员工实体关")
@Operation(summary = "新增员工亲属实体关")
@PreAuthorize("@ss.hasPermi('ccdi:staffEnterpriseRelation:add')")
@Log(title = "员工实体关系信息", businessType = BusinessType.INSERT)
@Log(title = "员工亲属实体关", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody CcdiStaffEnterpriseRelationAddDTO addDTO) {
return toAjax(relationService.insertRelation(addDTO));
}
/**
* 修改员工实体关
* 修改员工亲属实体关
*/
@Operation(summary = "修改员工实体关")
@Operation(summary = "修改员工亲属实体关")
@PreAuthorize("@ss.hasPermi('ccdi:staffEnterpriseRelation:edit')")
@Log(title = "员工实体关系信息", businessType = BusinessType.UPDATE)
@Log(title = "员工亲属实体关", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody CcdiStaffEnterpriseRelationEditDTO editDTO) {
return toAjax(relationService.updateRelation(editDTO));
}
/**
* 删除员工实体关
* 删除员工亲属实体关
*/
@Operation(summary = "删除员工实体关")
@Operation(summary = "删除员工亲属实体关")
@Parameter(name = "ids", description = "主键ID数组", required = true)
@PreAuthorize("@ss.hasPermi('ccdi:staffEnterpriseRelation:remove')")
@Log(title = "员工实体关系信息", businessType = BusinessType.DELETE)
@Log(title = "员工亲属实体关", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(relationService.deleteRelationByIds(ids));
@@ -115,16 +127,16 @@ public class CcdiStaffEnterpriseRelationController extends BaseController {
@Operation(summary = "下载导入模板")
@PostMapping("/importTemplate")
public void importTemplate(HttpServletResponse response) {
EasyExcelUtil.importTemplateWithDictDropdown(response, CcdiStaffEnterpriseRelationExcel.class, "员工实体关系信息");
EasyExcelUtil.importTemplateWithDictDropdown(response, CcdiStaffEnterpriseRelationExcel.class, "员工亲属实体关");
}
/**
* 异步导入员工实体关
* 异步导入员工亲属实体关
*/
@Operation(summary = "异步导入员工实体关")
@Operation(summary = "异步导入员工亲属实体关")
@Parameter(name = "file", description = "导入文件", required = true)
@PreAuthorize("@ss.hasPermi('ccdi:staffEnterpriseRelation:import')")
@Log(title = "员工实体关系信息", businessType = BusinessType.IMPORT)
@Log(title = "员工亲属实体关", businessType = BusinessType.IMPORT)
@PostMapping("/importData")
public AjaxResult importData(@Parameter(description = "导入文件") MultipartFile file) throws Exception {
List<CcdiStaffEnterpriseRelationExcel> list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiStaffEnterpriseRelationExcel.class);
@@ -140,9 +152,9 @@ public class CcdiStaffEnterpriseRelationController extends BaseController {
ImportResultVO result = new ImportResultVO();
result.setTaskId(taskId);
result.setStatus("PROCESSING");
result.setMessage("导入任务已提交,正在后台处理");
result.setMessage("员工亲属实体关联导入任务已提交,正在后台处理");
return AjaxResult.success("导入任务已提交,正在后台处理", result);
return AjaxResult.success("员工亲属实体关联导入任务已提交,正在后台处理", result);
}
/**

View File

@@ -10,22 +10,22 @@ import java.io.Serial;
import java.io.Serializable;
/**
* 员工实体关系信息新增DTO
* 员工亲属实体关新增DTO
*
* @author ruoyi
* @date 2026-02-09
*/
@Data
@Schema(description = "员工实体关系信息新增")
@Schema(description = "员工亲属实体关新增")
public class CcdiStaffEnterpriseRelationAddDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/** 身份证号 */
@NotBlank(message = "身份证号不能为空")
@Pattern(regexp = "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$", message = "身份证号格式不正确")
@Schema(description = "身份证号")
/** 亲属身份证号 */
@NotBlank(message = "亲属身份证号不能为空")
@Pattern(regexp = "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$", message = "亲属身份证号格式不正确")
@Schema(description = "亲属身份证号")
private String personId;
/** 关联人在企业的职务 */

View File

@@ -10,13 +10,13 @@ import java.io.Serial;
import java.io.Serializable;
/**
* 员工实体关系信息编辑DTO
* 员工亲属实体关编辑DTO
*
* @author ruoyi
* @date 2026-02-09
*/
@Data
@Schema(description = "员工实体关系信息编辑")
@Schema(description = "员工亲属实体关编辑")
public class CcdiStaffEnterpriseRelationEditDTO implements Serializable {
@Serial
@@ -27,8 +27,8 @@ public class CcdiStaffEnterpriseRelationEditDTO implements Serializable {
@Schema(description = "主键ID")
private Long id;
/** 身份证号 */
@Schema(description = "身份证号(不可修改)")
/** 亲属身份证号 */
@Schema(description = "亲属身份证号(不可修改)")
private String personId;
/** 关联人在企业的职务 */

View File

@@ -7,22 +7,30 @@ import java.io.Serial;
import java.io.Serializable;
/**
* 员工实体关系信息查询DTO
* 员工亲属实体关查询DTO
*
* @author ruoyi
* @date 2026-02-09
*/
@Data
@Schema(description = "员工实体关系信息查询条件")
@Schema(description = "员工亲属实体关查询条件")
public class CcdiStaffEnterpriseRelationQueryDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/** 身份证号 */
@Schema(description = "身份证号")
/** 亲属身份证号 */
@Schema(description = "亲属身份证号")
private String personId;
/** 亲属姓名 */
@Schema(description = "亲属姓名")
private String relationName;
/** 关联员工 */
@Schema(description = "关联员工")
private String staffPersonName;
/** 统一社会信用代码 */
@Schema(description = "统一社会信用代码")
private String socialCreditCode;

View File

@@ -10,23 +10,23 @@ import java.io.Serial;
import java.io.Serializable;
/**
* 员工实体关系信息Excel导入导出对象
* 员工亲属实体关Excel导入导出对象
*
* @author ruoyi
* @date 2026-02-09
*/
@Data
@Schema(description = "员工实体关系信息Excel导入导出对象")
@Schema(description = "员工亲属实体关Excel导入导出对象")
public class CcdiStaffEnterpriseRelationExcel implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/** 身份证号 */
@ExcelProperty(value = "身份证号", index = 0)
/** 亲属身份证号 */
@ExcelProperty(value = "亲属身份证号", index = 0)
@ColumnWidth(20)
@Required
@Schema(description = "身份证号")
@Schema(description = "亲属身份证号")
private String personId;
/** 统一社会信用代码 */

View File

@@ -0,0 +1,37 @@
package com.ruoyi.info.collection.domain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 员工亲属实体关联下拉选项VO
*
* @author ruoyi
* @date 2026-04-23
*/
@Data
@Schema(description = "员工亲属实体关联下拉选项")
public class CcdiStaffEnterpriseRelationOptionVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/** 亲属身份证号 */
@Schema(description = "亲属身份证号")
private String relationCertNo;
/** 亲属姓名 */
@Schema(description = "亲属姓名")
private String relationName;
/** 关联员工身份证号 */
@Schema(description = "关联员工身份证号")
private String staffPersonId;
/** 关联员工姓名 */
@Schema(description = "关联员工姓名")
private String staffPersonName;
}

View File

@@ -9,13 +9,13 @@ import java.io.Serializable;
import java.util.Date;
/**
* 员工实体关系信息VO
* 员工亲属实体关VO
*
* @author ruoyi
* @date 2026-02-09
*/
@Data
@Schema(description = "员工实体关系信息")
@Schema(description = "员工亲属实体关")
public class CcdiStaffEnterpriseRelationVO implements Serializable {
@Serial
@@ -25,13 +25,21 @@ public class CcdiStaffEnterpriseRelationVO implements Serializable {
@Schema(description = "主键ID")
private Long id;
/** 身份证号 */
@Schema(description = "身份证号")
/** 亲属身份证号 */
@Schema(description = "亲属身份证号")
private String personId;
/** 员工姓名 */
@Schema(description = "员工姓名")
private String personName;
/** 亲属姓名 */
@Schema(description = "亲属姓名")
private String relationName;
/** 关联员工身份证号 */
@Schema(description = "关联员工身份证号")
private String staffPersonId;
/** 关联员工姓名 */
@Schema(description = "关联员工姓名")
private String staffPersonName;
/** 关联人在企业的职务 */
@Schema(description = "关联人在企业的职务")

View File

@@ -7,22 +7,26 @@ import java.io.Serial;
import java.io.Serializable;
/**
* 员工实体关系信息导入失败记录VO
* 员工亲属实体关导入失败记录VO
*
* @author ruoyi
* @date 2026-02-09
*/
@Data
@Schema(description = "员工实体关系信息导入失败记录")
@Schema(description = "员工亲属实体关导入失败记录")
public class StaffEnterpriseRelationImportFailureVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/** 身份证号 */
@Schema(description = "身份证号")
/** 亲属身份证号 */
@Schema(description = "亲属身份证号")
private String personId;
/** 亲属姓名 */
@Schema(description = "亲属姓名")
private String relationName;
/** 统一社会信用代码 */
@Schema(description = "统一社会信用代码")
private String socialCreditCode;

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.info.collection.domain.CcdiStaffEnterpriseRelation;
import com.ruoyi.info.collection.domain.dto.CcdiStaffEnterpriseRelationQueryDTO;
import com.ruoyi.info.collection.domain.vo.CcdiStaffEnterpriseRelationOptionVO;
import com.ruoyi.info.collection.domain.vo.CcdiStaffEnterpriseRelationVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -38,6 +39,14 @@ public interface CcdiStaffEnterpriseRelationMapper extends BaseMapper<CcdiStaffE
*/
CcdiStaffEnterpriseRelationVO selectRelationById(@Param("id") Long id);
/**
* 查询有效员工亲属下拉选项
*
* @param query 搜索关键词
* @return 下拉选项
*/
List<CcdiStaffEnterpriseRelationOptionVO> selectFamilyOptions(@Param("query") String query);
/**
* 判断身份证号和统一社会信用代码的组合是否已存在
*
@@ -57,6 +66,14 @@ public interface CcdiStaffEnterpriseRelationMapper extends BaseMapper<CcdiStaffE
*/
Set<String> batchExistsByCombinations(@Param("combinations") List<String> combinations);
/**
* 根据亲属身份证号批量置无效
*
* @param personId 亲属身份证号
* @return 影响行数
*/
int invalidateByFamilyCertNo(@Param("personId") String personId);
/**
* 批量插入员工实体关系数据
*

View File

@@ -7,7 +7,7 @@ import com.ruoyi.info.collection.domain.vo.StaffEnterpriseRelationImportFailureV
import java.util.List;
/**
* 员工实体关系信息异步导入服务层
* 员工亲属实体关异步导入服务层
*
* @author ruoyi
* @date 2026-02-09

View File

@@ -5,6 +5,7 @@ import com.ruoyi.info.collection.domain.dto.CcdiStaffEnterpriseRelationAddDTO;
import com.ruoyi.info.collection.domain.dto.CcdiStaffEnterpriseRelationEditDTO;
import com.ruoyi.info.collection.domain.dto.CcdiStaffEnterpriseRelationQueryDTO;
import com.ruoyi.info.collection.domain.excel.CcdiStaffEnterpriseRelationExcel;
import com.ruoyi.info.collection.domain.vo.CcdiStaffEnterpriseRelationOptionVO;
import com.ruoyi.info.collection.domain.vo.CcdiStaffEnterpriseRelationVO;
import java.util.List;
@@ -42,6 +43,14 @@ public interface ICcdiStaffEnterpriseRelationService {
*/
List<CcdiStaffEnterpriseRelationExcel> selectRelationListForExport(CcdiStaffEnterpriseRelationQueryDTO queryDTO);
/**
* 查询有效员工亲属下拉选项
*
* @param query 搜索关键词
* @return 下拉选项
*/
List<CcdiStaffEnterpriseRelationOptionVO> selectFamilyOptions(String query);
/**
* 查询员工实体关系详情
*

View File

@@ -2,14 +2,14 @@ package com.ruoyi.info.collection.service.impl;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.info.collection.domain.CcdiBaseStaff;
import com.ruoyi.info.collection.domain.CcdiStaffEnterpriseRelation;
import com.ruoyi.info.collection.domain.CcdiStaffFmyRelation;
import com.ruoyi.info.collection.domain.dto.CcdiStaffEnterpriseRelationAddDTO;
import com.ruoyi.info.collection.domain.excel.CcdiStaffEnterpriseRelationExcel;
import com.ruoyi.info.collection.domain.vo.ImportResult;
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
import com.ruoyi.info.collection.domain.vo.StaffEnterpriseRelationImportFailureVO;
import com.ruoyi.info.collection.mapper.CcdiBaseStaffMapper;
import com.ruoyi.info.collection.mapper.CcdiStaffFmyRelationMapper;
import com.ruoyi.info.collection.mapper.CcdiStaffEnterpriseRelationMapper;
import com.ruoyi.info.collection.service.ICcdiStaffEnterpriseRelationImportService;
import com.ruoyi.info.collection.utils.ImportLogUtils;
@@ -29,7 +29,7 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 员工实体关系信息异步导入服务层处理
* 员工亲属实体关异步导入服务层处理
*
* @author ruoyi
* @date 2026-02-09
@@ -47,7 +47,7 @@ public class CcdiStaffEnterpriseRelationImportServiceImpl implements ICcdiStaffE
private RedisTemplate<String, Object> redisTemplate;
@Resource
private CcdiBaseStaffMapper baseStaffMapper;
private CcdiStaffFmyRelationMapper familyRelationMapper;
@Override
@Async
@@ -56,37 +56,48 @@ public class CcdiStaffEnterpriseRelationImportServiceImpl implements ICcdiStaffE
long startTime = System.currentTimeMillis();
// 记录导入开始
ImportLogUtils.logImportStart(log, taskId, "员工实体关", excelList.size(), userName);
ImportLogUtils.logImportStart(log, taskId, "员工亲属实体关", excelList.size(), userName);
List<CcdiStaffEnterpriseRelation> newRecords = new ArrayList<>();
List<StaffEnterpriseRelationImportFailureVO> failures = new ArrayList<>();
// 批量验证员工身份证号是否存在
Set<String> excelPersonIds = excelList.stream()
.map(CcdiStaffEnterpriseRelationExcel::getPersonId)
.filter(StringUtils::isNotEmpty)
.collect(Collectors.toSet());
Set<String> existingPersonIds = new HashSet<>();
Map<String, CcdiStaffFmyRelation> validFamilies = new HashMap<>();
Set<String> knownFamilyCertNos = new HashSet<>();
Map<String, String> familyNameMap = new HashMap<>();
if (!excelPersonIds.isEmpty()) {
ImportLogUtils.logBatchQueryStart(log, taskId, "员工身份证号", excelPersonIds.size());
ImportLogUtils.logBatchQueryStart(log, taskId, "员工亲属关系", excelPersonIds.size());
LambdaQueryWrapper<CcdiBaseStaff> wrapper = new LambdaQueryWrapper<>();
wrapper.select(CcdiBaseStaff::getIdCard)
.in(CcdiBaseStaff::getIdCard, excelPersonIds);
LambdaQueryWrapper<CcdiStaffFmyRelation> wrapper = new LambdaQueryWrapper<>();
wrapper.select(
CcdiStaffFmyRelation::getRelationCertNo,
CcdiStaffFmyRelation::getRelationName,
CcdiStaffFmyRelation::getPersonId,
CcdiStaffFmyRelation::getStatus,
CcdiStaffFmyRelation::getIsEmpFamily
)
.in(CcdiStaffFmyRelation::getRelationCertNo, excelPersonIds);
List<CcdiBaseStaff> existingStaff = baseStaffMapper.selectList(wrapper);
existingPersonIds = existingStaff.stream()
.map(CcdiBaseStaff::getIdCard)
.collect(Collectors.toSet());
List<CcdiStaffFmyRelation> familyRelations = familyRelationMapper.selectList(wrapper);
for (CcdiStaffFmyRelation familyRelation : familyRelations) {
knownFamilyCertNos.add(familyRelation.getRelationCertNo());
familyNameMap.putIfAbsent(familyRelation.getRelationCertNo(), familyRelation.getRelationName());
if (Boolean.TRUE.equals(familyRelation.getIsEmpFamily()) && Integer.valueOf(1).equals(familyRelation.getStatus())) {
validFamilies.putIfAbsent(familyRelation.getRelationCertNo(), familyRelation);
}
}
ImportLogUtils.logBatchQueryComplete(log, taskId, "员工身份证号", existingPersonIds.size());
ImportLogUtils.logBatchQueryComplete(log, taskId, "员工亲属关系", familyRelations.size());
}
// 批量查询已存在的person_id + social_credit_code组合
ImportLogUtils.logBatchQueryStart(log, taskId, "已存在的员工企业关系组合", excelList.size());
ImportLogUtils.logBatchQueryStart(log, taskId, "已存在的员工亲属实体关联组合", excelList.size());
Set<String> existingCombinations = getExistingCombinations(excelList);
ImportLogUtils.logBatchQueryComplete(log, taskId, "员工企业关系组合", existingCombinations.size());
ImportLogUtils.logBatchQueryComplete(log, taskId, "员工亲属实体关联组合", existingCombinations.size());
// 用于跟踪Excel文件内已处理的组合
Set<String> processedCombinations = new HashSet<>();
@@ -103,41 +114,18 @@ public class CcdiStaffEnterpriseRelationImportServiceImpl implements ICcdiStaffE
// 验证数据
validateRelationData(addDTO);
// 身份证号存在性检查(在基本验证之后)
if (!existingPersonIds.contains(excel.getPersonId())) {
throw new RuntimeException(String.format(
"第%d行: 身份证号[%s]不存在于员工信息表中,请先添加员工信息",
i + 1, excel.getPersonId()));
}
CcdiStaffFmyRelation familyRelation = validFamilies.get(excel.getPersonId());
CcdiStaffEnterpriseRelation relation = validateAndBuildEntity(
excel,
familyRelation,
knownFamilyCertNos,
existingCombinations,
processedCombinations,
userName
);
String combination = excel.getPersonId() + "|" + excel.getSocialCreditCode();
CcdiStaffEnterpriseRelation relation = new CcdiStaffEnterpriseRelation();
BeanUtils.copyProperties(excel, relation);
if (existingCombinations.contains(combination)) {
// 组合已存在,直接报错
throw new RuntimeException(String.format("身份证号[%s]和统一社会信用代码[%s]的组合已存在,请勿重复导入",
excel.getPersonId(), excel.getSocialCreditCode()));
} else if (processedCombinations.contains(combination)) {
// Excel文件内部重复
throw new RuntimeException(String.format("身份证号[%s]和统一社会信用代码[%s]的组合在导入文件中重复,已跳过此条记录",
excel.getPersonId(), excel.getSocialCreditCode()));
} else {
relation.setCreatedBy(userName);
relation.setUpdatedBy(userName);
// 设置默认值
relation.setStatus(1);
relation.setIsEmployee(0);
relation.setIsEmpFamily(1);
relation.setIsCustomer(0);
relation.setIsCustFamily(0);
relation.setDataSource("IMPORT");
newRecords.add(relation);
processedCombinations.add(combination); // 标记为已处理
}
newRecords.add(relation);
processedCombinations.add(excel.getPersonId() + "|" + excel.getSocialCreditCode());
// 记录进度
ImportLogUtils.logProgress(log, taskId, i + 1, excelList.size(),
@@ -146,11 +134,12 @@ public class CcdiStaffEnterpriseRelationImportServiceImpl implements ICcdiStaffE
} catch (Exception e) {
StaffEnterpriseRelationImportFailureVO failure = new StaffEnterpriseRelationImportFailureVO();
BeanUtils.copyProperties(excel, failure);
failure.setRelationName(familyNameMap.get(excel.getPersonId()));
failure.setErrorMessage(e.getMessage());
failures.add(failure);
// 记录验证失败日志
String keyData = String.format("身份证号=%s, 统一社会信用代码=%s, 企业名称=%s",
String keyData = String.format("亲属身份证号=%s, 统一社会信用代码=%s, 企业名称=%s",
excel.getPersonId(), excel.getSocialCreditCode(), excel.getEnterpriseName());
ImportLogUtils.logValidationError(log, taskId, i + 1, e.getMessage(), keyData);
}
@@ -166,7 +155,7 @@ public class CcdiStaffEnterpriseRelationImportServiceImpl implements ICcdiStaffE
// 保存失败记录到Redis
if (!failures.isEmpty()) {
try {
String failuresKey = "import:staffEnterpriseRelation:" + taskId + ":failures";
String failuresKey = "import:staffEnterpriseRelation:" + taskId + ":failures";
redisTemplate.opsForValue().set(failuresKey, failures, 7, TimeUnit.DAYS);
ImportLogUtils.logRedisOperation(log, taskId, "保存失败记录", failures.size());
} catch (Exception e) {
@@ -185,7 +174,7 @@ public class CcdiStaffEnterpriseRelationImportServiceImpl implements ICcdiStaffE
// 记录导入完成
long duration = System.currentTimeMillis() - startTime;
ImportLogUtils.logImportComplete(log, taskId, "员工实体关",
ImportLogUtils.logImportComplete(log, taskId, "员工亲属实体关",
excelList.size(), result.getSuccessCount(), result.getFailureCount(), duration);
}
@@ -251,9 +240,9 @@ public class CcdiStaffEnterpriseRelationImportServiceImpl implements ICcdiStaffE
statusData.put("endTime", System.currentTimeMillis());
if ("SUCCESS".equals(status)) {
statusData.put("message", "全部成功!共导入" + result.getTotalCount() + "条数据");
statusData.put("message", "员工亲属实体关联导入全部成功!共导入" + result.getTotalCount() + "条数据");
} else {
statusData.put("message", "成功" + result.getSuccessCount() + "条,失败" + result.getFailureCount() + "");
statusData.put("message", "员工亲属实体关联导入成功" + result.getSuccessCount() + "条,失败" + result.getFailureCount() + "");
}
redisTemplate.opsForHash().putAll(key, statusData);
@@ -297,14 +286,14 @@ public class CcdiStaffEnterpriseRelationImportServiceImpl implements ICcdiStaffE
}
/**
* 验证员工实体关数据
* 验证员工亲属实体关联基础数据
*
* @param addDTO 新增DTO
*/
private void validateRelationData(CcdiStaffEnterpriseRelationAddDTO addDTO) {
// 验证必填字段
if (StringUtils.isEmpty(addDTO.getPersonId())) {
throw new RuntimeException("身份证号不能为空");
throw new RuntimeException("亲属身份证号不能为空");
}
if (StringUtils.isEmpty(addDTO.getSocialCreditCode())) {
throw new RuntimeException("统一社会信用代码不能为空");
@@ -313,9 +302,9 @@ public class CcdiStaffEnterpriseRelationImportServiceImpl implements ICcdiStaffE
throw new RuntimeException("企业名称不能为空");
}
// 验证身份证号格式18位
// 验证亲属身份证号格式18位
if (!addDTO.getPersonId().matches("^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$")) {
throw new RuntimeException("身份证号格式不正确必须为18位有效身份证号");
throw new RuntimeException("亲属身份证号格式不正确必须为18位有效身份证号");
}
// 验证统一社会信用代码格式18位
@@ -331,4 +320,38 @@ public class CcdiStaffEnterpriseRelationImportServiceImpl implements ICcdiStaffE
throw new RuntimeException("企业名称长度不能超过200个字符");
}
}
CcdiStaffEnterpriseRelation validateAndBuildEntity(CcdiStaffEnterpriseRelationExcel excel,
CcdiStaffFmyRelation familyRelation,
Set<String> knownFamilyCertNos,
Set<String> existingCombinations,
Set<String> processedCombinations,
String userName) {
String combination = excel.getPersonId() + "|" + excel.getSocialCreditCode();
if (familyRelation == null) {
if (knownFamilyCertNos.contains(excel.getPersonId())) {
throw new RuntimeException("亲属身份证号[" + excel.getPersonId() + "]不是有效员工亲属,请先维护有效的员工亲属关系");
}
throw new RuntimeException("亲属身份证号[" + excel.getPersonId() + "]不存在,请先维护员工亲属关系");
}
if (existingCombinations.contains(combination)) {
throw new RuntimeException("亲属身份证号[" + excel.getPersonId() + "]和统一社会信用代码[" + excel.getSocialCreditCode() + "]的组合已存在,请勿重复导入");
}
if (processedCombinations.contains(combination)) {
throw new RuntimeException("亲属身份证号[" + excel.getPersonId() + "]和统一社会信用代码[" + excel.getSocialCreditCode() + "]的组合在导入文件中重复,已跳过此条记录");
}
CcdiStaffEnterpriseRelation relation = new CcdiStaffEnterpriseRelation();
BeanUtils.copyProperties(excel, relation);
relation.setCreatedBy(userName);
relation.setUpdatedBy(userName);
relation.setStatus(1);
relation.setIsEmployee(0);
relation.setIsEmpFamily(1);
relation.setIsCustomer(0);
relation.setIsCustFamily(0);
relation.setDataSource("IMPORT");
return relation;
}
}

View File

@@ -3,11 +3,14 @@ package com.ruoyi.info.collection.service.impl;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.info.collection.domain.CcdiStaffEnterpriseRelation;
import com.ruoyi.info.collection.domain.CcdiStaffFmyRelation;
import com.ruoyi.info.collection.domain.dto.CcdiStaffEnterpriseRelationAddDTO;
import com.ruoyi.info.collection.domain.dto.CcdiStaffEnterpriseRelationEditDTO;
import com.ruoyi.info.collection.domain.dto.CcdiStaffEnterpriseRelationQueryDTO;
import com.ruoyi.info.collection.domain.excel.CcdiStaffEnterpriseRelationExcel;
import com.ruoyi.info.collection.domain.vo.CcdiStaffEnterpriseRelationOptionVO;
import com.ruoyi.info.collection.domain.vo.CcdiStaffEnterpriseRelationVO;
import com.ruoyi.info.collection.mapper.CcdiStaffFmyRelationMapper;
import com.ruoyi.info.collection.mapper.CcdiStaffEnterpriseRelationMapper;
import com.ruoyi.info.collection.service.ICcdiStaffEnterpriseRelationImportService;
import com.ruoyi.info.collection.service.ICcdiStaffEnterpriseRelationService;
@@ -37,6 +40,9 @@ public class CcdiStaffEnterpriseRelationServiceImpl implements ICcdiStaffEnterpr
@Resource
private CcdiStaffEnterpriseRelationMapper relationMapper;
@Resource
private CcdiStaffFmyRelationMapper familyRelationMapper;
@Resource
private ICcdiStaffEnterpriseRelationImportService relationImportService;
@@ -86,6 +92,11 @@ public class CcdiStaffEnterpriseRelationServiceImpl implements ICcdiStaffEnterpr
}).collect(Collectors.toList());
}
@Override
public java.util.List<CcdiStaffEnterpriseRelationOptionVO> selectFamilyOptions(String query) {
return relationMapper.selectFamilyOptions(query);
}
/**
* 查询员工实体关系详情
*
@@ -106,16 +117,15 @@ public class CcdiStaffEnterpriseRelationServiceImpl implements ICcdiStaffEnterpr
@Override
@Transactional
public int insertRelation(CcdiStaffEnterpriseRelationAddDTO addDTO) {
// 检查身份证号+统一社会信用代码唯一性
validateEffectiveFamily(addDTO.getPersonId());
if (relationMapper.existsByPersonIdAndSocialCreditCode(addDTO.getPersonId(), addDTO.getSocialCreditCode())) {
throw new RuntimeException("该身份证号和统一社会信用代码组合已存在");
throw new RuntimeException("亲属身份证号和统一社会信用代码组合已存在");
}
CcdiStaffEnterpriseRelation relation = new CcdiStaffEnterpriseRelation();
BeanUtils.copyProperties(addDTO, relation);
// 设置默认值
// 新增时强制设置状态为有效
relation.setStatus(1);
if (relation.getIsEmployee() == null) {
@@ -159,7 +169,7 @@ public class CcdiStaffEnterpriseRelationServiceImpl implements ICcdiStaffEnterpr
updateWrapper.set(editDTO.getRemark() != null, CcdiStaffEnterpriseRelation::getRemark, editDTO.getRemark());
// 注意:以下字段不可修改
// - personId身份证号业务主键
// - personId亲属身份证号,业务主键)
// - socialCreditCode统一社会信用代码业务主键
// - dataSource数据来源系统字段
// - isEmployee是否为员工系统字段
@@ -224,4 +234,28 @@ public class CcdiStaffEnterpriseRelationServiceImpl implements ICcdiStaffEnterpr
return taskId;
}
private CcdiStaffFmyRelation validateEffectiveFamily(String familyCertNo) {
CcdiStaffFmyRelation validFamily = familyRelationMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<CcdiStaffFmyRelation>()
.eq(CcdiStaffFmyRelation::getRelationCertNo, familyCertNo)
.eq(CcdiStaffFmyRelation::getIsEmpFamily, Boolean.TRUE)
.eq(CcdiStaffFmyRelation::getStatus, 1)
.last("LIMIT 1")
);
if (validFamily != null) {
return validFamily;
}
CcdiStaffFmyRelation existingFamily = familyRelationMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<CcdiStaffFmyRelation>()
.select(CcdiStaffFmyRelation::getId)
.eq(CcdiStaffFmyRelation::getRelationCertNo, familyCertNo)
.last("LIMIT 1")
);
if (existingFamily == null) {
throw new RuntimeException("亲属身份证号[" + familyCertNo + "]不存在,请先维护员工亲属关系");
}
throw new RuntimeException("亲属身份证号[" + familyCertNo + "]不是有效员工亲属,请先维护有效的员工亲属关系");
}
}

View File

@@ -3,12 +3,13 @@ package com.ruoyi.info.collection.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.info.collection.domain.CcdiAssetInfo;
import com.ruoyi.info.collection.domain.CcdiStaffFmyRelation;
import com.ruoyi.info.collection.domain.vo.CcdiAssetInfoVO;
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.CcdiStaffFmyRelationExcel;
import com.ruoyi.info.collection.domain.vo.CcdiAssetInfoVO;
import com.ruoyi.info.collection.domain.vo.CcdiStaffFmyRelationVO;
import com.ruoyi.info.collection.mapper.CcdiStaffEnterpriseRelationMapper;
import com.ruoyi.info.collection.mapper.CcdiStaffFmyRelationMapper;
import com.ruoyi.info.collection.service.ICcdiAssetInfoService;
import com.ruoyi.info.collection.service.ICcdiStaffFmyRelationImportService;
@@ -50,6 +51,9 @@ public class CcdiStaffFmyRelationServiceImpl implements ICcdiStaffFmyRelationSer
@Resource
private ICcdiAssetInfoService assetInfoService;
@Resource
private CcdiStaffEnterpriseRelationMapper staffEnterpriseRelationMapper;
/**
* 查询员工亲属关系列表
*
@@ -161,6 +165,9 @@ public class CcdiStaffFmyRelationServiceImpl implements ICcdiStaffFmyRelationSer
CcdiStaffFmyRelation relation = new CcdiStaffFmyRelation();
BeanUtils.copyProperties(editDTO, relation);
int result = relationMapper.updateById(relation);
if (Integer.valueOf(1).equals(existing.getStatus()) && Integer.valueOf(0).equals(editDTO.getStatus())) {
staffEnterpriseRelationMapper.invalidateByFamilyCertNo(existing.getRelationCertNo());
}
assetInfoService.replaceByFamilyIdAndPersonId(editDTO.getPersonId(), editDTO.getRelationCertNo(), editDTO.getAssetInfoList());
return result;
}

View File

@@ -8,7 +8,9 @@
<resultMap type="com.ruoyi.info.collection.domain.vo.CcdiStaffEnterpriseRelationVO" id="CcdiStaffEnterpriseRelationVOResult">
<id property="id" column="id"/>
<result property="personId" column="person_id"/>
<result property="personName" column="person_name"/>
<result property="relationName" column="relation_name"/>
<result property="staffPersonId" column="staff_person_id"/>
<result property="staffPersonName" column="staff_person_name"/>
<result property="relationPersonPost" column="relation_person_post"/>
<result property="socialCreditCode" column="social_credit_code"/>
<result property="enterpriseName" column="enterprise_name"/>
@@ -28,17 +30,28 @@
<!-- 分页查询员工实体关系列表 -->
<select id="selectRelationPage" resultMap="CcdiStaffEnterpriseRelationVOResult">
SELECT
ser.id, ser.person_id, bs.name as person_name, ser.relation_person_post,
ser.id, ser.person_id, sfr.relation_name, sfr.person_id AS staff_person_id, bs.name AS staff_person_name,
ser.relation_person_post,
ser.social_credit_code, ser.enterprise_name, ser.status, ser.remark,
ser.data_source, ser.is_employee, ser.is_emp_family, ser.is_customer,
ser.is_cust_family, ser.created_by, ser.create_time, ser.updated_by,
ser.update_time
FROM ccdi_staff_enterprise_relation ser
LEFT JOIN ccdi_base_staff bs ON ser.person_id = bs.id_card
LEFT JOIN ccdi_staff_fmy_relation sfr
ON ser.person_id = sfr.relation_cert_no
AND sfr.is_emp_family = 1
LEFT JOIN ccdi_base_staff bs ON sfr.person_id = bs.id_card
<where>
<if test="query.personId != null and query.personId != ''">
AND ser.person_id LIKE CONCAT('%', #{query.personId}, '%')
</if>
<if test="query.relationName != null and query.relationName != ''">
AND sfr.relation_name LIKE CONCAT('%', #{query.relationName}, '%')
</if>
<if test="query.staffPersonName != null and query.staffPersonName != ''">
AND (sfr.person_id LIKE CONCAT('%', #{query.staffPersonName}, '%')
OR bs.name LIKE CONCAT('%', #{query.staffPersonName}, '%'))
</if>
<if test="query.socialCreditCode != null and query.socialCreditCode != ''">
AND ser.social_credit_code LIKE CONCAT('%', #{query.socialCreditCode}, '%')
</if>
@@ -55,16 +68,40 @@
<!-- 查询员工实体关系详情 -->
<select id="selectRelationById" resultMap="CcdiStaffEnterpriseRelationVOResult">
SELECT
ser.id, ser.person_id, bs.name as person_name, ser.relation_person_post,
ser.id, ser.person_id, sfr.relation_name, sfr.person_id AS staff_person_id, bs.name AS staff_person_name,
ser.relation_person_post,
ser.social_credit_code, ser.enterprise_name, ser.status, ser.remark,
ser.data_source, ser.is_employee, ser.is_emp_family, ser.is_customer,
ser.is_cust_family, ser.created_by, ser.create_time, ser.updated_by,
ser.update_time
FROM ccdi_staff_enterprise_relation ser
LEFT JOIN ccdi_base_staff bs ON ser.person_id = bs.id_card
LEFT JOIN ccdi_staff_fmy_relation sfr
ON ser.person_id = sfr.relation_cert_no
AND sfr.is_emp_family = 1
LEFT JOIN ccdi_base_staff bs ON sfr.person_id = bs.id_card
WHERE ser.id = #{id}
</select>
<!-- 查询有效员工亲属下拉选项 -->
<select id="selectFamilyOptions" resultType="com.ruoyi.info.collection.domain.vo.CcdiStaffEnterpriseRelationOptionVO">
SELECT
sfr.relation_cert_no AS relationCertNo,
sfr.relation_name AS relationName,
sfr.person_id AS staffPersonId,
bs.name AS staffPersonName
FROM ccdi_staff_fmy_relation sfr
LEFT JOIN ccdi_base_staff bs ON sfr.person_id = bs.id_card
<where>
sfr.is_emp_family = 1
AND sfr.status = 1
<if test="query != null and query != ''">
AND sfr.relation_cert_no LIKE CONCAT('%', #{query}, '%')
</if>
</where>
ORDER BY sfr.create_time DESC
LIMIT 100
</select>
<!-- 判断身份证号和统一社会信用代码的组合是否已存在 -->
<select id="existsByPersonIdAndSocialCreditCode" resultType="boolean">
SELECT COUNT(1) > 0
@@ -84,6 +121,14 @@
</foreach>
</select>
<update id="invalidateByFamilyCertNo">
UPDATE ccdi_staff_enterprise_relation
SET status = 0,
update_time = NOW()
WHERE person_id = #{personId}
AND status != 0
</update>
<!-- 批量插入员工实体关系数据 -->
<insert id="insertBatch">
INSERT INTO ccdi_staff_enterprise_relation