3 天以前 2d107e5c57fccb1ae1bfcc8b59389fbd0e2c67a5
feat(staff): 添加在职员工导入功能

- 新增在职员工导入模板下载接口
- 实现员工导入数据验证和处理逻辑
- 添加岗位和部门映射验证功能
- 创建专门的导入DTO类用于Excel处理
- 实现重复员工编号检测机制
- 添加详细的导入错误提示信息
- 集成事务管理确保数据一致性
已添加1个文件
已修改2个文件
201 ■■■■■ 文件已修改
src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/dto/StaffOnJobImportDto.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java
@@ -1,9 +1,11 @@
package com.ruoyi.staff.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.staff.dto.StaffOnJobImportDto;
import com.ruoyi.staff.dto.StaffOnJobDto;
import com.ruoyi.staff.pojo.StaffContract;
import com.ruoyi.staff.pojo.StaffOnJob;
@@ -108,6 +110,13 @@
    /**
     * åœ¨èŒå‘˜å·¥å¯¼å…¥
     */
    @PostMapping("/downloadTemplate")
    @Log(title = "在职员工导入模板下载", businessType = BusinessType.EXPORT)
    public void downloadTemplate(HttpServletResponse response) {
        ExcelUtil<StaffOnJobImportDto> util = new ExcelUtil<>(StaffOnJobImportDto.class);
        util.importTemplateExcel(response, "在职员工导入模板");
    }
    @PostMapping("/import")
    @Log(title = "在职员工导入", businessType = BusinessType.IMPORT)
    public AjaxResult importData(@RequestPart("file") MultipartFile file) {
src/main/java/com/ruoyi/staff/dto/StaffOnJobImportDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
package com.ruoyi.staff.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class StaffOnJobImportDto {
    @Excel(name = "员工编号", cellType = Excel.ColumnType.STRING, sort = 1)
    private String staffNo;
    @Excel(name = "员工姓名", sort = 2)
    private String staffName;
    @Excel(name = "性别", sort = 3, combo = {"男", "女"})
    private String sex;
    @Excel(name = "籍贯", sort = 4)
    private String nativePlace;
    @Excel(name = "岗位", sort = 5, prompt = "请填写系统中已存在的岗位名称")
    private String postName;
    @Excel(name = "部门", sort = 6, prompt = "请填写系统中已存在的部门名称")
    private String deptName;
    @Excel(name = "现住址", sort = 7)
    private String adress;
    @Excel(name = "第一学历", sort = 8)
    private String firstStudy;
    @Excel(name = "专业", sort = 9)
    private String profession;
    @Excel(name = "年龄", sort = 11)
    private String age;
    @Excel(name = "联系电话", cellType = Excel.ColumnType.STRING, sort = 12)
    private String phone;
    @Excel(name = "紧急联系人", sort = 13)
    private String emergencyContact;
    @Excel(name = "紧急联系人联系电话", cellType = Excel.ColumnType.STRING, sort = 14)
    private String emergencyContactPhone;
    @Excel(name = "合同年限", sort = 15)
    private String contractTerm;
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "合同开始日期", width = 30, dateFormat = "yyyy-MM-dd", sort = 16)
    private Date contractStartTime;
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "合同结束日期", width = 30, dateFormat = "yyyy-MM-dd", sort = 17)
    private Date contractEndTime;
}
src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
@@ -6,10 +6,14 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.dto.WordDateDto;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysPost;
import com.ruoyi.project.system.mapper.SysDeptMapper;
import com.ruoyi.project.system.mapper.SysPostMapper;
import com.ruoyi.staff.dto.StaffOnJobImportDto;
import com.ruoyi.staff.dto.StaffOnJobDto;
import com.ruoyi.staff.mapper.StaffContractMapper;
import com.ruoyi.staff.mapper.StaffLeaveMapper;
@@ -26,6 +30,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
@@ -35,6 +40,8 @@
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@AllArgsConstructor
@Service
@@ -44,6 +51,8 @@
    private StaffOnJobMapper staffOnJobMapper;
    @Autowired
    private SysPostMapper sysPostMapper;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
    private StaffContractMapper staffContractMapper;
@@ -189,15 +198,120 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean importData(MultipartFile file) {
        try {
            ExcelUtil<StaffOnJob> util = new ExcelUtil<>(StaffOnJob.class);
            List<StaffOnJob> staffOnJobs = util.importExcel(file.getInputStream());
            return saveOrUpdateBatch(staffOnJobs);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
            ExcelUtil<StaffOnJobImportDto> util = new ExcelUtil<>(StaffOnJobImportDto.class);
            List<StaffOnJobImportDto> staffOnJobs = util.importExcel(file.getInputStream());
            if (CollectionUtils.isEmpty(staffOnJobs)) {
                throw new BaseException("模板错误或导入数据为空");
        }
            Map<String, SysPost> postMap = buildPostMap();
            Map<String, SysDept> deptMap = buildDeptMap();
            Set<String> importedStaffNos = new HashSet<>();
            for (int i = 0; i < staffOnJobs.size(); i++) {
                StaffOnJobDto staffOnJobDto = buildImportStaff(staffOnJobs.get(i), i + 2, postMap, deptMap, importedStaffNos);
                add(staffOnJobDto);
            }
            return true;
        } catch (Exception e) {
            if (e instanceof BaseException) {
                throw (BaseException) e;
            }
            throw new BaseException("导入失败,请检查模板格式是否正确");
        }
    }
    private StaffOnJobDto buildImportStaff(StaffOnJobImportDto row, int rowNum, Map<String, SysPost> postMap,
                                           Map<String, SysDept> deptMap, Set<String> importedStaffNos) {
        String staffNo = normalizeValue(row.getStaffNo());
        String postName = normalizeValue(row.getPostName());
        String deptName = normalizeValue(row.getDeptName());
        if (StringUtils.isBlank(staffNo)) {
            throw new BaseException("第" + rowNum + "行员工编号不能为空");
        }
        if (!importedStaffNos.add(staffNo)) {
            throw new BaseException("第" + rowNum + "行员工编号重复:" + staffNo);
        }
        if (StringUtils.isBlank(normalizeValue(row.getStaffName()))) {
            throw new BaseException("第" + rowNum + "行员工姓名不能为空");
        }
        if (StringUtils.isBlank(postName)) {
            throw new BaseException("第" + rowNum + "行岗位不能为空");
        }
        if (StringUtils.isBlank(deptName)) {
            throw new BaseException("第" + rowNum + "行部门不能为空");
        }
        if (row.getContractStartTime() == null) {
            throw new BaseException("第" + rowNum + "行合同开始日期不能为空");
        }
        if (row.getContractEndTime() == null) {
            throw new BaseException("第" + rowNum + "行合同结束日期不能为空");
        }
        SysPost post = postMap.get(postName);
        if (post == null) {
            throw new BaseException("第" + rowNum + "行岗位不存在或已停用:" + postName);
        }
        SysDept dept = deptMap.get(deptName);
        if (dept == null) {
            throw new BaseException("第" + rowNum + "行部门不存在或已停用:" + deptName);
        }
        StaffOnJobDto staffOnJobDto = new StaffOnJobDto();
        BeanUtils.copyProperties(row, staffOnJobDto);
        staffOnJobDto.setStaffNo(staffNo);
        staffOnJobDto.setStaffName(normalizeValue(row.getStaffName()));
        staffOnJobDto.setSex(normalizeValue(row.getSex()));
        staffOnJobDto.setNativePlace(normalizeValue(row.getNativePlace()));
        staffOnJobDto.setAdress(normalizeValue(row.getAdress()));
        staffOnJobDto.setFirstStudy(normalizeValue(row.getFirstStudy()));
        staffOnJobDto.setProfession(normalizeValue(row.getProfession()));
        staffOnJobDto.setAge(normalizeValue(row.getAge()));
        staffOnJobDto.setPhone(normalizeValue(row.getPhone()));
        staffOnJobDto.setEmergencyContact(normalizeValue(row.getEmergencyContact()));
        staffOnJobDto.setEmergencyContactPhone(normalizeValue(row.getEmergencyContactPhone()));
        staffOnJobDto.setContractTerm(normalizeValue(row.getContractTerm()));
        staffOnJobDto.setSysPostId(post.getPostId().intValue());
        staffOnJobDto.setSysDeptId(dept.getDeptId().intValue());
        return staffOnJobDto;
    }
    private Map<String, SysPost> buildPostMap() {
        SysPost query = new SysPost();
        query.setStatus("0");
        return buildUniqueMap(sysPostMapper.selectPostList(query), SysPost::getPostName, "岗位");
    }
    private Map<String, SysDept> buildDeptMap() {
        SysDept query = new SysDept();
        query.setStatus("0");
        return buildUniqueMap(sysDeptMapper.selectDeptList(query), SysDept::getDeptName, "部门");
    }
    private <T> Map<String, T> buildUniqueMap(List<T> dataList, Function<T, String> nameGetter, String fieldName) {
        Map<String, List<T>> groupedMap = dataList.stream()
                .filter(Objects::nonNull)
                .filter(item -> StringUtils.isNotBlank(normalizeValue(nameGetter.apply(item))))
                .collect(Collectors.groupingBy(item -> normalizeValue(nameGetter.apply(item))));
        List<String> duplicateNames = groupedMap.entrySet().stream()
                .filter(entry -> entry.getValue().size() > 1)
                .map(Map.Entry::getKey)
                .sorted()
                .collect(Collectors.toList());
        if (!duplicateNames.isEmpty()) {
            throw new BaseException("系统中存在重名" + fieldName + ",无法导入:" + String.join("、", duplicateNames));
        }
        return groupedMap.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().get(0)));
    }
    private String normalizeValue(String value) {
        return value == null ? null : value.trim();
    }