From 2d107e5c57fccb1ae1bfcc8b59389fbd0e2c67a5 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 29 四月 2026 15:44:02 +0800
Subject: [PATCH] feat(staff): 添加在职员工导入功能

---
 src/main/java/com/ruoyi/staff/dto/StaffOnJobImportDto.java            |   66 ++++++++++++++++
 src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java |  124 +++++++++++++++++++++++++++++-
 src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java    |    9 ++
 3 files changed, 194 insertions(+), 5 deletions(-)

diff --git a/src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java b/src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java
index 8e3d6b6..561b076 100644
--- a/src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java
+++ b/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) {
diff --git a/src/main/java/com/ruoyi/staff/dto/StaffOnJobImportDto.java b/src/main/java/com/ruoyi/staff/dto/StaffOnJobImportDto.java
new file mode 100644
index 0000000..9d7e574
--- /dev/null
+++ b/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;
+
+}
diff --git a/src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java b/src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
index d7abe9b..841247a 100644
--- a/src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
+++ b/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,17 +198,122 @@
     }
 
     @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);
+            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) {
-            e.printStackTrace();
-            return false;
+            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();
+    }
+
 
     @Override
     public String exportCopy(HttpServletResponse response, StaffOnJob staffOnJob) throws Exception {

--
Gitblit v1.9.3