From 5f612ab2f67b2c6f6894c624a7780799526d566d Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期四, 05 十一月 2026 20:20:05 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_business_新高电力' into dev_business_新高电力

---
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java |  364 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 345 insertions(+), 19 deletions(-)

diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java
index 72fadf6..35a9635 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java
@@ -3,10 +3,17 @@
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.hrm.enums.HrmEmploymentTypeEnum;
+import cn.iocoder.yudao.module.mes.api.cal.MesCalTeamApi;
+import cn.iocoder.yudao.module.mes.api.cal.dto.MesCalTeamRespDTO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeEducationSaveReqVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeEmergencyContactSaveReqVO;
+import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeImportExcelVO;
+import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeImportReqVO;
+import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeImportRespVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeePageReqVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeRespVO;
 import cn.iocoder.yudao.module.hrm.controller.admin.employee.vo.HrmEmployeeSaveReqVO;
@@ -21,6 +28,7 @@
 import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeMapper;
 import cn.iocoder.yudao.module.hrm.dal.mysql.employee.HrmEmployeeWorkHistoryMapper;
 import cn.iocoder.yudao.module.hrm.dal.redis.HrmNoRedisDAO;
+import cn.iocoder.yudao.module.infra.api.config.ConfigApi;
 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 import cn.iocoder.yudao.module.system.api.dept.PostApi;
 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
@@ -29,13 +37,20 @@
 import cn.iocoder.yudao.module.system.api.permission.dto.RoleRespDTO;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserCreateReqDTO;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserSyncReqDTO;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -48,10 +63,11 @@
 /**
  * 鍛樺伐淇℃伅 Service 瀹炵幇绫�
  *
- * @author 鑺嬮亾婧愮爜
+ * @author 瓒呯骇绠$悊鍛�
  */
 @Service
 @Validated
+@Slf4j
 public class HrmEmployeeServiceImpl implements HrmEmployeeService {
 
     @Resource
@@ -72,6 +88,18 @@
     private AdminUserApi adminUserApi;
     @Resource
     private RoleApi roleApi;
+    @Resource
+    private MesCalTeamApi mesCalTeamApi;
+    @Resource
+    private ConfigApi configApi;
+
+    /**
+     * 鐢ㄦ埛鍒濆瀵嗙爜鐨勭郴缁熷弬鏁伴厤缃」
+     */
+    private static final String USER_INIT_PASSWORD_KEY = "system.user.init-password";
+    @Resource
+    @Lazy // 鑷敞鍏ラ渶寤惰繜鍔犺浇锛屽惁鍒� bean 琚唬鐞嗗寘瑁呭悗娉ㄥ叆鍘熷鐗堟湰瀵艰嚧鍚姩澶辫触
+    private HrmEmployeeService self;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -80,10 +108,8 @@
         deptApi.validateDeptList(Collections.singleton(createReqVO.getDeptId()));
         // 2. 鏍¢獙宀椾綅
         postApi.validPostList(Collections.singleton(createReqVO.getPostId()));
-        // 3. 鏍¢獙鎵嬫満鍙锋槸鍚﹀凡瀛樺湪
-        if (employeeMapper.selectByPhone(createReqVO.getPhone()) != null) {
-            throw exception(EMPLOYEE_PHONE_EXISTS);
-        }
+        // 3. 鏍¢獙鎵嬫満鍙锋槸鍚﹀凡瀛樺湪锛堝苟閲婃斁杞垹闄ゅ巻鍙茶褰曞崰鐢ㄧ殑鎵嬫満鍙凤級
+        validatePhoneUniqueAndReleaseStale(null, createReqVO.getPhone());
         // 4. 鍚屾鍒涘缓绯荤粺鐢ㄦ埛
         AdminUserCreateReqDTO userCreateReqDTO = new AdminUserCreateReqDTO();
         userCreateReqDTO.setUsername(createReqVO.getPhone());
@@ -91,7 +117,8 @@
         userCreateReqDTO.setDeptId(createReqVO.getDeptId());
         userCreateReqDTO.setPostIds(Collections.singleton(createReqVO.getPostId()));
         userCreateReqDTO.setMobile(createReqVO.getPhone());
-        userCreateReqDTO.setPassword(createReqVO.getPhone());
+        // 鍒濆瀵嗙爜锛氫紭鍏堢敤瀵煎叆/鏂板鏃舵寚瀹氱殑瀵嗙爜锛屽惁鍒欒鍙栫郴缁熷弬鏁帮紱涓よ�呴兘娌℃湁鍒欐姤閿�
+        userCreateReqDTO.setPassword(resolveInitialPassword(createReqVO.getPassword()));
         userCreateReqDTO.setSex(createReqVO.getGender());
         userCreateReqDTO.setEmail(createReqVO.getEmail());
         userCreateReqDTO.setRemark(createReqVO.getRemark());
@@ -113,30 +140,66 @@
         employeeMapper.insert(employee);
         Long employeeId = employee.getId();
         // 7. 鍚屾娣诲姞鏁欒偛缁忓巻
-        if (CollUtil.isNotEmpty(createReqVO.getEducationList())) {
-            createReqVO.getEducationList().forEach(educationVO -> {
+        if (CollUtil.isNotEmpty(createReqVO.getEducations())) {
+            createReqVO.getEducations().forEach(educationVO -> {
                 HrmEmployeeEducationDO education = BeanUtils.toBean(educationVO, HrmEmployeeEducationDO.class);
                 education.setEmployeeId(employeeId);
                 educationMapper.insert(education);
             });
         }
         // 8. 鍚屾娣诲姞宸ヤ綔缁忓巻
-        if (CollUtil.isNotEmpty(createReqVO.getWorkHistoryList())) {
-            createReqVO.getWorkHistoryList().forEach(workHistoryVO -> {
+        if (CollUtil.isNotEmpty(createReqVO.getWorkHistories())) {
+            createReqVO.getWorkHistories().forEach(workHistoryVO -> {
                 HrmEmployeeWorkHistoryDO workHistory = BeanUtils.toBean(workHistoryVO, HrmEmployeeWorkHistoryDO.class);
                 workHistory.setEmployeeId(employeeId);
                 workHistoryMapper.insert(workHistory);
             });
         }
         // 9. 鍚屾娣诲姞绱ф�ヨ仈绯讳汉
-        if (CollUtil.isNotEmpty(createReqVO.getEmergencyContactList())) {
-            createReqVO.getEmergencyContactList().forEach(emergencyContactVO -> {
+        if (CollUtil.isNotEmpty(createReqVO.getEmergencyContacts())) {
+            createReqVO.getEmergencyContacts().forEach(emergencyContactVO -> {
                 HrmEmployeeEmergencyContactDO emergencyContact = BeanUtils.toBean(emergencyContactVO, HrmEmployeeEmergencyContactDO.class);
                 emergencyContact.setEmployeeId(employeeId);
                 emergencyContactMapper.insert(emergencyContact);
             });
         }
         return employeeId;
+    }
+
+    /**
+     * 缁熶竴鎵嬫満鍙峰敮涓�鎬ф牎楠�
+     *
+     * <p>鑳屾櫙锛歨rm_employee.uk_phone 鏄缓鍦� phone 鍒椾笂鐨勫敮涓�绱㈠紩锛堜笉鍚� deleted锛夛紝
+     * 鍥犳銆屽凡杞垹闄や絾鎵嬫満鍙锋湭娓呯┖銆嶇殑鍘嗗彶妗f浼氶暱鏈熷崰鐫�杩欎釜鎵嬫満鍙枫��
+     * 姝ゆ椂 MyBatis-Plus 鐨� selectByPhone 鍥犻�昏緫鍒犻櫎杩囨护鏌ヤ笉鍒板畠锛岄鏍¢獙閫氳繃锛�
+     * 浣嗗啓搴撴椂鏁版嵁搴撲粛浼氭姏 DuplicateKeyException锛屾帴鍙h〃鐜颁负 500銆岀郴缁熷紓甯搞�嶃��</p>
+     *
+     * <p>澶勭悊绛栫暐锛堜笉鏀瑰簱缁撴瀯锛夛細
+     * 1. 鑻ユ墜鏈哄彿琚�屽凡杞垹闄ゃ�嶇殑鍘嗗彶璁板綍鍗犵敤 鈫� 鑷姩娓呯┖璇ュ巻鍙茶褰曠殑鎵嬫満鍙凤紝閲婃斁鍞竴绱㈠紩锛�
+     * 2. 鑻ヨ銆屾湭鍒犻櫎銆嶇殑鍏朵粬鍛樺伐鍗犵敤 鈫� 鎶涗笟鍔″紓甯搞�屾墜鏈哄彿宸插瓨鍦ㄣ�嶏紝涓嶅啀杩斿洖 500銆�</p>
+     *
+     * @param selfId 褰撳墠姝e湪鏂板/淇敼鐨勫憳宸ョ紪鍙凤紙鏂板浼� null锛夛紱鍛戒腑鑷韩鏃惰烦杩�
+     * @param phone  寰呮牎楠岀殑鎵嬫満鍙�
+     */
+    private void validatePhoneUniqueAndReleaseStale(Long selfId, String phone) {
+        if (StrUtil.isBlank(phone)) {
+            return;
+        }
+        // 1. 閲婃斁琚蒋鍒犻櫎鍘嗗彶璁板綍鍗犵敤鐨勬墜鏈哄彿
+        HrmEmployeeDO staleHolder = employeeMapper.selectByPhoneIncludeDeleted(phone);
+        if (staleHolder != null && !Objects.equals(staleHolder.getId(), selfId)
+                && Boolean.TRUE.equals(staleHolder.getDeleted())) {
+            employeeMapper.update(null, new LambdaUpdateWrapper<HrmEmployeeDO>()
+                    .eq(HrmEmployeeDO::getId, staleHolder.getId())
+                    .set(HrmEmployeeDO::getPhone, null));
+            log.info("[validatePhoneUniqueAndReleaseStale][閲婃斁鍘嗗彶杞垹闄ゅ憳宸�({})鍗犵敤鐨勬墜鏈哄彿]",
+                    staleHolder.getId());
+        }
+        // 2. 鏍¢獙鏄惁浠嶈娲昏穬鍛樺伐鍗犵敤
+        HrmEmployeeDO exist = employeeMapper.selectByPhone(phone);
+        if (exist != null && !Objects.equals(exist.getId(), selfId)) {
+            throw exception(EMPLOYEE_PHONE_EXISTS);
+        }
     }
 
     private String generateUniqueEmployeeNo() {
@@ -148,6 +211,7 @@
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void updateEmployee(HrmEmployeeSaveReqVO updateReqVO) {
         // 鏍¢獙瀛樺湪
         HrmEmployeeDO employee = validateEmployeeExists(updateReqVO.getId());
@@ -155,26 +219,142 @@
         deptApi.validateDeptList(Collections.singleton(updateReqVO.getDeptId()));
         // 鏍¢獙宀椾綅
         postApi.validPostList(Collections.singleton(updateReqVO.getPostId()));
-        // 鏍¢獙鎵嬫満鍙锋槸鍚﹀凡瀛樺湪锛堝鏋滄墜鏈哄彿鏈夊彉鏇达級
-        if (!Objects.equals(employee.getPhone(), updateReqVO.getPhone())
-                && employeeMapper.selectByPhone(updateReqVO.getPhone()) != null) {
-            throw exception(EMPLOYEE_PHONE_EXISTS);
+        // 鏍¢獙鎵嬫満鍙锋槸鍚﹀凡瀛樺湪锛堝鏋滄墜鏈哄彿鏈夊彉鏇达紱骞堕噴鏀捐蒋鍒犻櫎鍘嗗彶璁板綍鍗犵敤鐨勬墜鏈哄彿锛�
+        if (!Objects.equals(employee.getPhone(), updateReqVO.getPhone())) {
+            validatePhoneUniqueAndReleaseStale(updateReqVO.getId(), updateReqVO.getPhone());
         }
-        // 鏇存柊
+        // 鏇存柊鍛樺伐涓昏〃
         HrmEmployeeDO updateObj = BeanUtils.toBean(updateReqVO, HrmEmployeeDO.class);
         // roleIds 瀛樺偍涓� JSON
         if (CollUtil.isNotEmpty(updateReqVO.getRoleIds())) {
             updateObj.setRoleIds(JSONUtil.toJsonStr(updateReqVO.getRoleIds()));
         }
         employeeMapper.updateById(updateObj);
+        Long employeeId = updateReqVO.getId();
+
+        // 鍚屾绯荤粺鐢ㄦ埛瀵嗙爜锛氫粎褰撴樉寮忓~鍐欎簡瀵嗙爜鏃舵墠鏇存柊锛屾湭濉啓淇濇寔鍘熷瘑鐮佷笉鍙�
+        if (StrUtil.isNotBlank(updateReqVO.getPassword()) && employee.getUserId() != null) {
+            adminUserApi.updateUserPassword(employee.getUserId(), updateReqVO.getPassword());
+        }
+
+        // 鍚屾绯荤粺璐﹀彿鍙搴斿瓧娈碉紙濮撳悕 / 鎵嬫満鍙� / 閮ㄩ棬 / 鎬у埆 / 閭锛�
+        if (employee.getUserId() != null) {
+            syncSystemUserForEmployee(employee, updateReqVO);
+        }
+
+        // 鍚屾鏁欒偛缁忓巻
+        if (updateReqVO.getEducations() != null) syncEducationList(employeeId, updateReqVO.getEducations());
+        // 鍚屾宸ヤ綔缁忓巻
+        if (updateReqVO.getWorkHistories() != null) syncWorkHistoryList(employeeId, updateReqVO.getWorkHistories());
+        // 鍚屾绱ф�ヨ仈绯讳汉
+        if (updateReqVO.getEmergencyContacts() != null) syncEmergencyContactList(employeeId, updateReqVO.getEmergencyContacts());
+    }
+
+    /**
+     * 鍛樺伐淇敼鍚庯紝鎶婂彲涓�涓�瀵瑰簲鐨勫瓧娈靛悓姝ュ埌绯荤粺璐﹀彿銆�
+     *
+     * 鍙悓姝ワ細濮撳悕鈫旀樀绉般�佹墜鏈哄彿鈫攎obile銆侀儴闂ㄣ�佹�у埆銆侀偖绠便��
+     * 鐧诲綍鍚� username銆佸矖浣嶃�佽鑹层�佺姸鎬佷笉鍚屾銆�
+     * 鍚屾澶辫触鏃跺洖婊氬憳宸ユ洿鏂帮紝閬垮厤鍛樺伐鍜岀郴缁熻处鍙蜂笉涓�鑷淬��
+     */
+    private void syncSystemUserForEmployee(HrmEmployeeDO employee, HrmEmployeeSaveReqVO reqVO) {
+        try {
+            AdminUserSyncReqDTO dto = new AdminUserSyncReqDTO();
+            dto.setUserId(employee.getUserId());
+            dto.setNickname(reqVO.getName() != null ? reqVO.getName() : employee.getName());
+            dto.setMobile(reqVO.getPhone() != null ? reqVO.getPhone() : employee.getPhone());
+            dto.setDeptId(reqVO.getDeptId() != null ? reqVO.getDeptId() : employee.getDeptId());
+            dto.setSex(reqVO.getGender() != null ? reqVO.getGender() : employee.getGender());
+            dto.setEmail(reqVO.getEmail() != null ? reqVO.getEmail() : employee.getEmail());
+            adminUserApi.updateUserForEmployee(dto);
+        } catch (Exception ex) {
+            log.warn("[updateEmployee] 鍛樺伐璐﹀彿鍚屾澶辫触锛屽憳宸ョ紪鍙�={}", employee.getId());
+            throw exception(EMPLOYEE_USER_SYNC_FAILED);
+        }
+    }
+
+    private void syncEducationList(Long employeeId, List<HrmEmployeeEducationSaveReqVO> newList) {
+        educationMapper.deleteByEmployeeId(employeeId);
+        if (CollUtil.isNotEmpty(newList)) {
+            newList.forEach(vo -> {
+                HrmEmployeeEducationDO education = BeanUtils.toBean(vo, HrmEmployeeEducationDO.class);
+                education.setId(null);
+                education.setEmployeeId(employeeId);
+                educationMapper.insert(education);
+            });
+        }
+    }
+
+    private void syncWorkHistoryList(Long employeeId, List<HrmEmployeeWorkHistorySaveReqVO> newList) {
+        workHistoryMapper.deleteByEmployeeId(employeeId);
+        if (CollUtil.isNotEmpty(newList)) {
+            newList.forEach(vo -> {
+                HrmEmployeeWorkHistoryDO workHistory = BeanUtils.toBean(vo, HrmEmployeeWorkHistoryDO.class);
+                workHistory.setId(null);
+                workHistory.setEmployeeId(employeeId);
+                workHistoryMapper.insert(workHistory);
+            });
+        }
+    }
+
+    private void syncEmergencyContactList(Long employeeId, List<HrmEmployeeEmergencyContactSaveReqVO> newList) {
+        emergencyContactMapper.deleteByEmployeeId(employeeId);
+        if (CollUtil.isNotEmpty(newList)) {
+            newList.forEach(vo -> {
+                HrmEmployeeEmergencyContactDO emergencyContact = BeanUtils.toBean(vo, HrmEmployeeEmergencyContactDO.class);
+                emergencyContact.setId(null);
+                emergencyContact.setEmployeeId(employeeId);
+                emergencyContactMapper.insert(emergencyContact);
+            });
+        }
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void deleteEmployee(Long id) {
         // 鏍¢獙瀛樺湪
-        validateEmployeeExists(id);
-        // 鍒犻櫎
+        HrmEmployeeDO employee = validateEmployeeExists(id);
+        // 1. 鑱斿姩鍒犻櫎绯荤粺璐﹀彿锛堜笉鍙戝竷浜嬩欢锛岄伩鍏嶅洖鐜級
+        deleteLinkedSystemUser(employee);
+        // 2. 绾ц仈鍒犻櫎瀛愯〃
+        educationMapper.deleteByEmployeeId(id);
+        workHistoryMapper.deleteByEmployeeId(id);
+        emergencyContactMapper.deleteByEmployeeId(id);
+        // 3. 杞垹闄ゅ墠閲婃斁鍞竴绾︽潫瀛楁锛岄伩鍏嶅巻鍙叉暟鎹暱鏈熷崰鐢� uk_phone / uk_user_id锛�
+        //    瀵艰嚧鍚庣画鏂版。妗堜娇鐢ㄥ悓涓�鎵嬫満鍙锋垨缁戝畾鍚屼竴璐﹀彿鏃舵挒鏁版嵁搴撳敮涓�绱㈠紩锛堣〃鐜颁负 500锛�
+        //    娉細employee_no 涓� NOT NULL 涓� uk_employee_no 鏈惈 deleted锛岃繖閲屼笉缃┖锛�
+        //    浣嗘妸 user_id 缃┖鍙噴鏀� uk_user_id锛涙墜鏈哄彿缃┖鍙噴鏀� uk_phone銆�
+        employeeMapper.update(null, new LambdaUpdateWrapper<HrmEmployeeDO>()
+                .eq(HrmEmployeeDO::getId, id)
+                .set(HrmEmployeeDO::getPhone, null)
+                .set(HrmEmployeeDO::getUserId, null));
+        // 4. 鍒犻櫎鍛樺伐
         employeeMapper.deleteById(id);
+    }
+
+    /**
+     * 鍒犻櫎鍛樺伐鏃惰仈鍔ㄥ垹闄ゅ叾绯荤粺璐﹀彿銆�
+     *
+     * 瀹堝崼锛�
+     * 1. 鏈粦瀹氳处鍙� -> 璺宠繃
+     * 2. 鍐呯疆 admin锛坕d=1锛� -> 璺宠繃
+     * 3. 鍚屼竴璐﹀彿琚鏉″憳宸ユ。妗堝紩鐢� -> 璺宠繃锛堜竴鍛樺伐涓�璐﹀彿绾﹀畾涓嬩笉搴斿嚭鐜帮級
+     */
+    private void deleteLinkedSystemUser(HrmEmployeeDO employee) {
+        Long userId = employee.getUserId();
+        if (userId == null) {
+            return;
+        }
+        if (Long.valueOf(1L).equals(userId)) {
+            log.warn("[deleteEmployee][鍛樺伐({}) 缁戝畾鐨勬槸鍐呯疆绠$悊鍛樿处鍙�({})锛屼笉鑷姩鍒犻櫎璐﹀彿]", employee.getId(), userId);
+            return;
+        }
+        Long count = employeeMapper.selectCount(HrmEmployeeDO::getUserId, userId);
+        if (count != null && count > 1) {
+            log.warn("[deleteEmployee][璐﹀彿({}) 鍏宠仈浜� {} 鏉″憳宸ユ。妗堬紝涓嶈嚜鍔ㄥ垹闄よ处鍙穄", userId, count);
+            return;
+        }
+        adminUserApi.deleteUserSilently(userId);
     }
 
     private HrmEmployeeDO validateEmployeeExists(Long id) {
@@ -221,6 +401,17 @@
             List<RoleRespDTO> roles = roleApi.getRoleList(respVO.getRoleIds());
             if (CollUtil.isNotEmpty(roles)) {
                 respVO.setRoleNames(roles.stream().map(RoleRespDTO::getName).collect(Collectors.joining(",")));
+            }
+        }
+        // 濉厖鐢ㄥ伐鎬ц川鍚嶇О
+        if (employee.getEmploymentType() != null) {
+            respVO.setEmploymentTypeName(HrmEmploymentTypeEnum.getNameByType(employee.getEmploymentType()));
+        }
+        // 濉厖鎵�灞炵彮缁勫悕绉�
+        if (employee.getTeamId() != null) {
+            List<MesCalTeamRespDTO> teams = mesCalTeamApi.getTeamList(Collections.singleton(employee.getTeamId()));
+            if (CollUtil.isNotEmpty(teams)) {
+                respVO.setTeamName(teams.get(0).getName());
             }
         }
         return respVO;
@@ -272,4 +463,139 @@
         return employeeMapper.selectByUserId(userId);
     }
 
+    @Override
+    public HrmEmployeeDO getEmployeeByName(String name) {
+        return employeeMapper.selectByName(name);
+    }
+
+    @Override
+    public List<HrmEmployeeDO> getEmployeeListByName(String name) {
+        return employeeMapper.selectListByName(name);
+    }
+
+    @Override
+    public HrmEmployeeImportRespVO importEmployeeList(List<HrmEmployeeImportExcelVO> rows, HrmEmployeeImportReqVO req) {
+        if (CollUtil.isEmpty(rows)) throw exception(EMPLOYEE_IMPORT_LIST_IS_EMPTY);
+        Map<String, List<DeptRespDTO>> depts = deptApi.getDeptList().stream()
+                .filter(v -> StrUtil.isNotBlank(v.getName())).collect(Collectors.groupingBy(v -> v.getName().trim()));
+        Map<String, List<PostRespDTO>> posts = postApi.getPostList().stream()
+                .filter(v -> StrUtil.isNotBlank(v.getName())).collect(Collectors.groupingBy(v -> v.getName().trim()));
+        Map<String, List<RoleRespDTO>> roles = roleApi.getRoleList().stream()
+                .filter(v -> StrUtil.isNotBlank(v.getName())).collect(Collectors.groupingBy(v -> v.getName().trim()));
+        HrmEmployeeImportRespVO result = HrmEmployeeImportRespVO.builder()
+                .createNames(new ArrayList<>()).updateNames(new ArrayList<>()).failureNames(new LinkedHashMap<>()).build();
+        Set<String> phones = new LinkedHashSet<>();
+        boolean hasData = false;
+        for (int i = 0; i < rows.size(); i++) {
+            HrmEmployeeImportExcelVO row = rows.get(i);
+            if (row == null || cn.hutool.core.bean.BeanUtil.beanToMap(row).values().stream()
+                    .noneMatch(v -> v != null && (!(v instanceof String) || StrUtil.isNotBlank((String) v)))) continue;
+            hasData = true;
+            String label = "绗�" + (i + 2) + "琛�" + (StrUtil.isBlank(row.getName()) ? "" : "锛�" + row.getName().trim() + "锛�");
+            try {
+                if (StrUtil.isBlank(row.getName()) || StrUtil.isBlank(row.getPhone()) || row.getHireDate() == null) {
+                    throw exception(EMPLOYEE_IMPORT_INVALID, "鍛樺伐濮撳悕銆佹墜鏈哄彿鍜屽叆鑱屾棩鏈熶笉鑳戒负绌�");
+                }
+                row.setName(row.getName().trim()); row.setPhone(row.getPhone().trim());
+                if (!phones.add(row.getPhone())) throw exception(EMPLOYEE_IMPORT_INVALID, "鏂囦欢鍐呮墜鏈哄彿閲嶅");
+                if (StrUtil.isBlank(row.getDeptName()) || StrUtil.isBlank(row.getPostName())) {
+                    throw exception(EMPLOYEE_IMPORT_INVALID, "閮ㄩ棬鍜屽矖浣嶄笉鑳戒负绌�");
+                }
+                List<DeptRespDTO> deptMatches = depts.get(row.getDeptName().trim());
+                List<PostRespDTO> postMatches = posts.get(row.getPostName().trim());
+                if (deptMatches == null || deptMatches.size() != 1) throw exception(EMPLOYEE_IMPORT_INVALID, "閮ㄩ棬鍚嶇О涓嶅瓨鍦ㄦ垨涓嶅敮涓�");
+                if (postMatches == null || postMatches.size() != 1) throw exception(EMPLOYEE_IMPORT_INVALID, "宀椾綅鍚嶇О涓嶅瓨鍦ㄦ垨涓嶅敮涓�");
+                Set<Long> roleIds = new LinkedHashSet<>();
+                if (StrUtil.isNotBlank(row.getRoleNames())) {
+                    for (String value : row.getRoleNames().split("[,锛宂")) {
+                        String name = value.trim();
+                        if (name.isEmpty()) continue;
+                        List<RoleRespDTO> matches = roles.get(name);
+                        if (matches == null || matches.size() != 1) throw exception(EMPLOYEE_IMPORT_INVALID, "瑙掕壊鍚嶇О涓嶅瓨鍦ㄦ垨涓嶅敮涓�锛�" + name);
+                        roleIds.add(matches.get(0).getId());
+                    }
+                }
+                HrmEmployeeSaveReqVO save = buildImportSaveReqVO(row, deptMatches.get(0).getId(), postMatches.get(0).getId(), roleIds);
+                // 瀵煎叆鍓嶅厛閲婃斁琚蒋鍒犻櫎鍘嗗彶璁板綍鍗犵敤鐨勬墜鏈哄彿锛岄伩鍏嶆暣琛屽鍏ュ洜鍞竴绱㈠紩鍐茬獊澶辫触
+                validatePhoneUniqueAndReleaseStale(null, row.getPhone());
+                HrmEmployeeDO existing = employeeMapper.selectByPhone(row.getPhone());
+                if (existing == null) {
+                    if (row.getGender() == null) throw exception(EMPLOYEE_IMPORT_FIELD_REQUIRED, "鎬у埆");
+                    self.createEmployee(save);
+                    result.getCreateNames().add(label);
+                } else {
+                    if (!Boolean.TRUE.equals(req.getUpdateSupport())) throw exception(EMPLOYEE_PHONE_EXISTS);
+                    if (StrUtil.isNotBlank(row.getPassword())) throw exception(EMPLOYEE_IMPORT_INVALID, "瑕嗙洊宸叉湁鍛樺伐鏃跺垵濮嬪瘑鐮侀』鐣欑┖锛屽瘑鐮佽鍦ㄨ处鍙风鐞嗕腑淇敼");
+                    if (!roleIds.isEmpty()) throw exception(EMPLOYEE_IMPORT_INVALID, "瑕嗙洊鍛樺伐鏃朵笉鏀寔淇敼鐢ㄦ埛瑙掕壊锛岃鐣欑┖骞跺湪璐﹀彿绠$悊涓淮鎶�");
+                    if (!Objects.equals(existing.getPostId(), save.getPostId())) throw exception(EMPLOYEE_IMPORT_INVALID, "瑕嗙洊鍛樺伐鏃舵殏涓嶆敮鎸佸彉鏇村矖浣嶏紝璇峰厛澶勭悊璐﹀彿宀椾綅閰嶇疆");
+                    save.setId(existing.getId());
+                    if (row.getGender() == null) save.setGender(existing.getGender());
+                    if (row.getEmployeeStatus() == null) save.setEmployeeStatus(existing.getEmployeeStatus());
+                    self.updateEmployee(save);
+                    result.getUpdateNames().add(label);
+                }
+            } catch (ServiceException ex) {
+                result.getFailureNames().put(label, ex.getMessage());
+            } catch (RuntimeException ex) {
+                log.warn("[importEmployeeList] 鍛樺伐瀵煎叆澶辫触锛岃鍙�={}", i + 2);
+                result.getFailureNames().put(label, "淇濆瓨鎴栬处鍙峰悓姝ュけ璐ワ紝璇锋鏌ヨ琛屾暟鎹強璐﹀彿閰嶇疆");
+            }
+        }
+        if (!hasData) throw exception(EMPLOYEE_IMPORT_LIST_IS_EMPTY);
+        return result;
+    }
+
+
+    /**
+     * 瑙f瀽鍛樺伐鍒濆瀵嗙爜锛�
+     * 1. 瀵煎叆/鏂板鏃舵樉寮忔寚瀹氫簡瀵嗙爜锛屼紭鍏堜娇鐢紱
+     * 2. 鏈寚瀹氬垯璇诲彇绯荤粺鍙傛暟 {@code system.user.init-password}锛�
+     * 3. 涓よ�呴兘娌℃湁鏃舵槑纭姤閿欙紝閬垮厤鎮勬倓鐢ㄦ墜鏈哄彿绛夊急鍙d护鍏滃簳銆�
+     */
+    private String resolveInitialPassword(String specifiedPassword) {
+        if (StrUtil.isNotBlank(specifiedPassword)) {
+            return specifiedPassword;
+        }
+        String initPassword = configApi.getConfigValueByKey(USER_INIT_PASSWORD_KEY);
+        if (StrUtil.isBlank(initPassword)) {
+            throw exception(EMPLOYEE_INIT_PASSWORD_NOT_CONFIGURED);
+        }
+        return initPassword;
+    }
+
+    private HrmEmployeeSaveReqVO buildImportSaveReqVO(HrmEmployeeImportExcelVO importEmployee,
+                                                      Long deptId, Long postId, Set<Long> roleIds) {
+        if (StrUtil.isBlank(importEmployee.getName())) {
+            throw exception(EMPLOYEE_IMPORT_FIELD_REQUIRED, "鍛樺伐濮撳悕");
+        }
+        if (StrUtil.isBlank(importEmployee.getPhone())) {
+            throw exception(EMPLOYEE_IMPORT_FIELD_REQUIRED, "鎵嬫満鍙�");
+        }
+        if (importEmployee.getHireDate() == null) {
+            throw exception(EMPLOYEE_IMPORT_FIELD_REQUIRED, "鍏ヨ亴鏃ユ湡");
+        }
+        HrmEmployeeSaveReqVO reqVO = new HrmEmployeeSaveReqVO();
+        reqVO.setName(importEmployee.getName());
+        reqVO.setGender(importEmployee.getGender() != null ? importEmployee.getGender() : 1); // 榛樿鐢�
+        reqVO.setPhone(importEmployee.getPhone());
+        reqVO.setPassword(importEmployee.getPassword());
+        reqVO.setDeptId(deptId);
+        reqVO.setPostId(postId);
+        reqVO.setRoleIds(CollUtil.isEmpty(roleIds) ? null : new ArrayList<>(roleIds));
+        reqVO.setHireDate(importEmployee.getHireDate());
+        reqVO.setEmployeeStatus(importEmployee.getEmployeeStatus() != null
+                ? importEmployee.getEmployeeStatus() : 1); // 榛樿鍦ㄨ亴
+        reqVO.setEmail(importEmployee.getEmail());
+        reqVO.setBirthday(importEmployee.getBirthday());
+        reqVO.setIdCard(importEmployee.getIdCard());
+        reqVO.setNation(importEmployee.getNation());
+        reqVO.setMarriageStatus(importEmployee.getMarriageStatus());
+        reqVO.setAge(importEmployee.getAge());
+        reqVO.setEducation(importEmployee.getEducation());
+        reqVO.setPoliticalStatus(importEmployee.getPoliticalStatus());
+        reqVO.setRemark(importEmployee.getRemark());
+        return reqVO;
+    }
+
+
 }
\ No newline at end of file

--
Gitblit v1.9.3