feat 员工亲属关系

This commit is contained in:
wkc
2026-02-10 10:41:19 +08:00
parent bf19a9daa8
commit 78a9300644
12 changed files with 234 additions and 1170 deletions

View File

@@ -8,6 +8,7 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 员工亲属关系Excel导入导出对象
@@ -46,68 +47,68 @@ public class CcdiStaffFmyRelationExcel implements Serializable {
@DictDropdown(dictType = "ccdi_indiv_gender")
private String gender;
/** 出生日期 */
@ExcelProperty(value = "出生日期", index = 4)
@ColumnWidth(15)
private Date birthDate;
/** 关系人证件类型 */
@ExcelProperty(value = "关系人证件类型*", index = 4)
@ExcelProperty(value = "关系人证件类型*", index = 5)
@ColumnWidth(15)
@DictDropdown(dictType = "ccdi_certificate_type")
@Required
private String relationCertType;
/** 关系人证件号码 */
@ExcelProperty(value = "关系人证件号码*", index = 5)
@ExcelProperty(value = "关系人证件号码*", index = 6)
@ColumnWidth(20)
@Required
private String relationCertNo;
/** 手机号码1 */
@ExcelProperty(value = "手机号码1", index = 6)
@ExcelProperty(value = "手机号码1", index = 7)
@ColumnWidth(15)
private String mobilePhone1;
/** 手机号码2 */
@ExcelProperty(value = "手机号码2", index = 7)
@ExcelProperty(value = "手机号码2", index = 8)
@ColumnWidth(15)
private String mobilePhone2;
/** 微信名称1 */
@ExcelProperty(value = "微信名称1", index = 8)
@ExcelProperty(value = "微信名称1", index = 9)
@ColumnWidth(15)
private String wechatNo1;
/** 微信名称2 */
@ExcelProperty(value = "微信名称2", index = 9)
@ExcelProperty(value = "微信名称2", index = 10)
@ColumnWidth(15)
private String wechatNo2;
/** 微信名称3 */
@ExcelProperty(value = "微信名称3", index = 10)
@ExcelProperty(value = "微信名称3", index = 11)
@ColumnWidth(15)
private String wechatNo3;
/** 详细联系地址 */
@ExcelProperty(value = "详细联系地址", index = 11)
@ExcelProperty(value = "详细联系地址", index = 12)
@ColumnWidth(30)
private String contactAddress;
/** 关系详细描述 */
@ExcelProperty(value = "关系详细描述", index = 12)
@ExcelProperty(value = "关系详细描述", index = 13)
@ColumnWidth(30)
private String relationDesc;
/** 生效日期 */
@ExcelProperty(value = "生效日期", index = 13)
@ExcelProperty(value = "生效日期", index = 14)
@ColumnWidth(15)
private String effectiveDate;
private Date effectiveDate;
/** 失效日期 */
@ExcelProperty(value = "失效日期", index = 14)
@ExcelProperty(value = "失效日期", index = 15)
@ColumnWidth(15)
private String invalidDate;
/** 状态 */
@ExcelProperty(value = "状态", index = 15)
@ColumnWidth(10)
private Integer status;
private Date invalidDate;
/** 备注 */
@ExcelProperty(value = "备注", index = 16)

View File

@@ -0,0 +1,138 @@
package com.ruoyi.ccdi.enums;
import org.apache.commons.lang3.StringUtils;
/**
* 性别枚举
* 用于性别中文标签与英文代码之间的转换
*
* @author ruoyi
* @date 2026-02-10
*/
public enum GenderEnum {
/**
* 男
*/
MALE("", "M"),
/**
* 女
*/
FEMALE("", "F"),
/**
* 其他
*/
OTHER("其他", "O");
private final String chineseLabel;
private final String englishCode;
GenderEnum(String chineseLabel, String englishCode) {
this.chineseLabel = chineseLabel;
this.englishCode = englishCode;
}
public String getChineseLabel() {
return chineseLabel;
}
public String getEnglishCode() {
return englishCode;
}
/**
* 根据中文标签获取枚举
*
* @param chineseLabel 中文标签(男、女、其他)
* @return 对应的枚举值
* @throws IllegalArgumentException 如果标签无效
*/
public static GenderEnum fromChinese(String chineseLabel) {
if (StringUtils.isEmpty(chineseLabel)) {
throw new IllegalArgumentException("性别标签不能为空");
}
for (GenderEnum gender : values()) {
if (gender.chineseLabel.equals(chineseLabel)) {
return gender;
}
}
throw new IllegalArgumentException("无效的性别标签: " + chineseLabel);
}
/**
* 根据英文代码获取枚举
*
* @param englishCode 英文代码M、F、O
* @return 对应的枚举值
* @throws IllegalArgumentException 如果代码无效
*/
public static GenderEnum fromEnglish(String englishCode) {
if (StringUtils.isEmpty(englishCode)) {
throw new IllegalArgumentException("性别代码不能为空");
}
for (GenderEnum gender : values()) {
if (gender.englishCode.equals(englishCode)) {
return gender;
}
}
throw new IllegalArgumentException("无效的性别代码: " + englishCode);
}
/**
* 验证性别值是否有效
* 支持中文标签男、女、其他或英文代码M、F、O
*
* @param value 待验证的值
* @return true-有效false-无效
*/
public static boolean isValid(String value) {
if (StringUtils.isEmpty(value)) {
return false;
}
for (GenderEnum gender : values()) {
if (gender.chineseLabel.equals(value) || gender.englishCode.equals(value)) {
return true;
}
}
return false;
}
/**
* 标准化性别值
* 输入中文标签或英文代码,统一返回英文代码
*
* @param input 输入值(中文或英文)
* @return 英文代码M、F、O
* @throws IllegalArgumentException 如果输入值无效
*/
public static String normalize(String input) {
if (StringUtils.isEmpty(input)) {
throw new IllegalArgumentException("性别值不能为空");
}
// 先尝试按中文匹配
for (GenderEnum gender : values()) {
if (gender.chineseLabel.equals(input)) {
return gender.englishCode;
}
}
// 再尝试按英文匹配(大写)
String upperInput = input.toUpperCase().trim();
for (GenderEnum gender : values()) {
if (gender.englishCode.equals(upperInput)) {
return gender.englishCode;
}
}
throw new IllegalArgumentException("无效的性别值: " + input + ",有效值为:男、女、其他 或 M、F、O");
}
}

View File

@@ -50,4 +50,14 @@ public interface CcdiStaffFmyRelationMapper extends BaseMapper<CcdiStaffFmyRelat
* @return 插入行数
*/
int insertBatch(@Param("list") List<CcdiStaffFmyRelation> list);
/**
* 批量查询已存在的员工亲属关系(用于导入唯一性校验)
*
* @param personIds 员工身份证号列表
* @param relationCertNos 关系人证件号码列表
* @return 已存在的记录列表
*/
List<CcdiStaffFmyRelation> selectExistingRelations(@Param("personIds") List<String> personIds,
@Param("relationCertNos") List<String> relationCertNos);
}

View File

@@ -7,6 +7,7 @@ import com.ruoyi.ccdi.domain.excel.CcdiStaffFmyRelationExcel;
import com.ruoyi.ccdi.domain.vo.ImportResult;
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
import com.ruoyi.ccdi.domain.vo.StaffFmyRelationImportFailureVO;
import com.ruoyi.ccdi.enums.GenderEnum;
import com.ruoyi.ccdi.mapper.CcdiStaffFmyRelationMapper;
import com.ruoyi.ccdi.service.ICcdiStaffFmyRelationImportService;
import com.ruoyi.common.utils.StringUtils;
@@ -44,10 +45,38 @@ public class CcdiStaffFmyRelationImportServiceImpl implements ICcdiStaffFmyRelat
List<CcdiStaffFmyRelation> newRecords = new ArrayList<>();
List<StaffFmyRelationImportFailureVO> failures = new ArrayList<>();
// 用于跟踪Excel文件内已处理的唯一键personId + relationCertNo
// ========== 第一步:批量唯一性校验 ==========
// 1. 提取Excel中所有的personId和relationCertNo
Set<String> excelPersonIds = new HashSet<>();
Set<String> excelRelationCertNos = new HashSet<>();
for (CcdiStaffFmyRelationExcel excel : excelList) {
if (StringUtils.isNotEmpty(excel.getPersonId())) {
excelPersonIds.add(excel.getPersonId());
}
if (StringUtils.isNotEmpty(excel.getRelationCertNo())) {
excelRelationCertNos.add(excel.getRelationCertNo());
}
}
// 2. 批量查询数据库中已存在的记录
Set<String> existingKeys = new HashSet<>();
if (!excelPersonIds.isEmpty() && !excelRelationCertNos.isEmpty()) {
List<CcdiStaffFmyRelation> existingRecords = relationMapper.selectExistingRelations(
new ArrayList<>(excelPersonIds),
new ArrayList<>(excelRelationCertNos)
);
// 3. 构建已存在记录的唯一键集合personId + relationCertNo
for (CcdiStaffFmyRelation existing : existingRecords) {
String key = existing.getPersonId() + "|" + existing.getRelationCertNo();
existingKeys.add(key);
}
}
// ========== 第二步:处理数据 ==========
// 用于跟踪Excel文件内已处理的唯一键
Set<String> processedKeys = new HashSet<>();
// 分类数据
for (int i = 0; i < excelList.size(); i++) {
CcdiStaffFmyRelationExcel excel = excelList.get(i);
@@ -67,17 +96,22 @@ public class CcdiStaffFmyRelationImportServiceImpl implements ICcdiStaffFmyRelat
throw new RuntimeException(String.format("员工[%s]的关系人[%s]在导入文件中重复", excel.getPersonId(), excel.getRelationCertNo()));
}
// 检查是否在数据库中已存在(批量校验的结果)
if (existingKeys.contains(uniqueKey)) {
throw new RuntimeException(String.format("员工[%s]的关系人[%s]已存在", excel.getPersonId(), excel.getRelationCertNo()));
}
// 从已验证和转换过的addDTO创建relation对象
CcdiStaffFmyRelation relation = new CcdiStaffFmyRelation();
BeanUtils.copyProperties(excel, relation);
BeanUtils.copyProperties(addDTO, relation);
relation.setCreatedBy(userName);
relation.setUpdatedBy(userName);
relation.setIsEmpFamily(true);
relation.setIsCustFamily(false);
relation.setDataSource("IMPORT");
if (relation.getStatus() == null) {
relation.setStatus(1);
}
// 显式设置状态为有效status=1
relation.setStatus(1);
newRecords.add(relation);
processedKeys.add(uniqueKey);
@@ -230,8 +264,14 @@ public class CcdiStaffFmyRelationImportServiceImpl implements ICcdiStaffFmyRelat
}
// 验证性别值(如果提供)
if (StringUtils.isNotEmpty(addDTO.getGender()) && !addDTO.getGender().matches("^[MFO]$")) {
throw new RuntimeException("性别只能是M、F或O");
if (StringUtils.isNotEmpty(addDTO.getGender())) {
try {
// 使用GenderEnum进行标准化支持中文男、女、其他和英文M、F、O
String normalizedGender = GenderEnum.normalize(addDTO.getGender());
addDTO.setGender(normalizedGender);
} catch (IllegalArgumentException e) {
throw new RuntimeException("性别只能是:男、女、其他 或 M、F、O");
}
}
}
}

View File

@@ -148,4 +148,21 @@
</foreach>
</insert>
<!-- 批量查询已存在的员工亲属关系(用于导入唯一性校验) -->
<select id="selectExistingRelations" resultType="com.ruoyi.ccdi.domain.CcdiStaffFmyRelation">
SELECT
id, person_id, relation_type, relation_name, gender, birth_date,
relation_cert_type, relation_cert_no
FROM ccdi_staff_fmy_relation
WHERE is_emp_family = 1
AND person_id IN
<foreach collection="personIds" item="personId" open="(" separator="," close=")">
#{personId}
</foreach>
AND relation_cert_no IN
<foreach collection="relationCertNos" item="relationCertNo" open="(" separator="," close=")">
#{relationCertNo}
</foreach>
</select>
</mapper>