package jnpf.personnels.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableMap;
import com.tencentcloudapi.faceid.v20180301.models.IdCardVerificationResponse;
import io.seata.spring.annotation.GlobalTransactional;
import jnpf.account.PTenantAccountApi;
import jnpf.authority.utils.PermissionsEnums;
import jnpf.authority.utils.PermissionsUtils;
import jnpf.base.ActionResult;
import jnpf.base.UserInfo;
import jnpf.base.entity.SuperBaseEntity;
import jnpf.base.vo.PageListVO;
import jnpf.certificate.service.CertificateInstanceService;
import jnpf.engine.FlowTaskApi;
import jnpf.engine.entity.FlowTaskEntity;
import jnpf.model.certificate.vo.app.HealthCertificateDetailVO;
import jnpf.model.cultivate.CultivatePage;
import jnpf.model.enums.*;
import jnpf.model.personnels.bo.ExportRosterOneVo;
import jnpf.model.personnels.bo.FtbRosterImportTemplateBO;
import jnpf.model.personnels.dto.audit.FtbPersonnelsAuditDto;
import jnpf.model.personnels.dto.emp.FtbEmpAddNewDTO;
import jnpf.model.personnels.dto.emp.FtbEmpConfirmDTO;
import jnpf.model.personnels.dto.emp.FtbEmpEntryDTO;
import jnpf.model.personnels.dto.emp.FtbEmpQueryDTO;
import jnpf.model.personnels.dto.oa.RequestForOA;
import jnpf.model.personnels.dto.regular.FtbPersonnelsRegularCreateDTO;
import jnpf.model.personnels.dto.salary.FtbPersonnelsSalaryInfo;
import jnpf.model.personnels.dto.staff.field.ExportFormTypeDto;
import jnpf.model.personnels.dto.staff.growth.AddGrowthLogDto;
import jnpf.model.personnels.dto.staff.registerform.ProbationPeriodDto;
import jnpf.model.personnels.dto.staff.roster.FtbPersonnelsStaffRosterDto;
import jnpf.model.personnels.dto.staff.roster.StaffBaseInfoDto;
import jnpf.model.personnels.dto.staff.roster.WorkerGroupDataDto;
import jnpf.model.personnels.dto.staff.salarylog.AddSalaryChangeLogDto;
import jnpf.model.personnels.po.*;
import jnpf.model.personnels.req.roster.UserAccountDto;
import jnpf.model.personnels.vo.emp.FtbEmpAddNewVO;
import jnpf.model.personnels.vo.emp.FtbEmpConfirmVO;
import jnpf.model.personnels.vo.emp.FtbEmpEntryVO;
import jnpf.model.personnels.vo.emp.FtbEmpResultVO;
import jnpf.model.personnels.vo.employeetype.FtbPersonnelsEmployeeTypeVO;
import jnpf.model.personnels.vo.salary.UserInfoWithSalary;
import jnpf.permission.V2GradesApi;
import jnpf.permission.V2OrganizeApi;
import jnpf.permission.V2PositionApi;
import jnpf.permission.V2UserApi;
import jnpf.permission.dto.v2.UserBoundInfoDTO;
import jnpf.permission.dto.v2.grades.QueryGradeListDTO;
import jnpf.permission.dto.v2.organzie.QueryOrganizeListTargetTypesDTO;
import jnpf.permission.dto.v2.user.QueryListUserDTO;
import jnpf.permission.dto.v2.user.QueryUserBoundDTO;
import jnpf.permission.dto.v2.user.SaveUserDTO;
import jnpf.permission.dto.v2.user.UpdateUserDTO;
import jnpf.permission.entity.UserCopyEntity;
import jnpf.permission.entity.UserEntity;
import jnpf.permission.eum.JobStatusEnum;
import jnpf.permission.eum.v2.OrganizeCategoryEnums;
import jnpf.permission.eum.v2.UserWorkStatusEnums;
import jnpf.permission.vo.v2.grades.GradeVO;
import jnpf.permission.vo.v2.organzie.OrganizeGeneralDetailVO;
import jnpf.permission.vo.v2.position.PositionBaseInfoVO;
import jnpf.permission.vo.v2.position.PositionVO;
import jnpf.permission.vo.v2.user.UserBoundInfoVO;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.permission.vo.v2.user.UserPageListVO;
import jnpf.personnels.config.EnvironmentParamConfig;
import jnpf.personnels.mapper.FtbPersonnelsRegistrationFormFieldOptionMapper;
import jnpf.personnels.mapper.FtbPersonnelsStaffEmploymentApplyMapper;
import jnpf.personnels.mapper.FtbPersonnelsStaffRegistrationFormDataMapper;
import jnpf.personnels.msg.PersonnelsConsumerSourceMsg;
import jnpf.personnels.service.*;
import jnpf.personnels.utils.*;
import jnpf.salary.QuerySalaryApi;
import jnpf.util.*;
import jnpf.util.context.ThreadContext;
import jnpf.util.excel.EasyExcelUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author: peng.hao
 * @create: 2025/4/7
 */
@Slf4j
@Service
public class FtbPersonnelsEmEntryServiceImpl implements FtbPersonnelsEmEntryService {

    @Resource
    FtbPersonnelsStaffEmploymentApplyMapper applyMapper;

    @Autowired
    V2UserApi v2UserApi;

    @Autowired
    V2OrganizeApi v2OrganizeApi;

    @Autowired
    V2PositionApi v2PositionApi;

    @Autowired
    V2GradesApi v2GradesApi;

    @Autowired
    private PTenantAccountApi pTenantAccountApi;

    @Resource
    private FtbPersonnelsStaffRosterService rosterService;

    @Autowired
    private FtbPersonnelsStaffRegistrationFormDataService registrationFormDataService;

    @Autowired
    private FtbPersonnelsStaffGrowthLogService growthLogService;

    @Autowired
    private FtbPersonnelsStaffSalaryChangeLogService salaryChangeLogService;

    @Autowired
    PersonnelOrgUtils personnelOrgUtils;

    @Autowired
    private FtbPersonnelsRegularManagementService regularManagementService;

    @Autowired
    private PersonnelAsyncServiceUtils personnelAsyncServiceUtils;

    @Autowired
    private SmsSendUtil smsSendUtil;

    @Resource
    private PermissionsUtils permissionsUtils;

    @Resource
    private FtbPersonnlesIMUtils ftbPersonnlesIMUtils;

    @Resource
    FtbPersonnelsSalaryService personnelSalaryService;

    @Resource
    FtbPersonnelsBlacklistService ftbPersonnelsBlacklistService;

    @Resource
    ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    FlowTaskApi flowTaskApi;

    @Resource
    private FtbPersonnelsEmployeeTypeService employeeTypeService;

    @Resource
    private FtbPersonnelsRegistrationFormFieldOptionMapper formFieldOptionMapper;

    @Autowired
    QuerySalaryApi querySalaryApi;

    @Resource
    PersonnelsConsumerSourceMsg secondmentConsumerSourceMsg;

    @Autowired
    EnvironmentParamConfig environmentParamConfig;


    @Autowired
    private SmsConfig smsConfig;


    @Autowired
    private RosterExportUtils rosterExportUtils;

    @Autowired
    private FtbPersonnelsRegistrationFormFieldOptionService fieldOptionService;

    @Autowired
    PersonnelIdCardVerificationUtils idCardVerificationUtils;

    @Resource
    private CertificateInstanceService certificateInstanceService;

    private static final String DEFAULT_USER_LOGO = "001.png";

    @Override
    public PageListVO<FtbEmpEntryVO> pageLists(FtbEmpEntryDTO empEntryDTO, String app) {
        Page<FtbEmpEntryVO> page = empEntryDTO.coverCultivatePage();
        Boolean isAdministrator = UserProvider.getUser().getIsAdministrator();
        if(!isAdministrator){
            List<UserWorkStatusEnums> workStatusEnums = Arrays.stream(UserWorkStatusEnums.values()).filter(v -> v.getCode().equals(UserWorkStatusEnums.RESIGNED.getCode())).collect(Collectors.toList());
            List<String> userIds = permissionsUtils.getPersonnelUserIdDataPermissions(UserProvider.getUser().getUserId(),workStatusEnums);
            if (userIds != null && userIds.isEmpty()) return CultivatePage.coverPageList(page);
            if (CollUtil.isNotEmpty(userIds)) {
                empEntryDTO.setUserIds(userIds);
            }
        }
        String keyWords = empEntryDTO.getKeyWords();
        if (StringUtils.isNotEmpty(keyWords)){
            LambdaQueryWrapper<FtbPersonnelsStaffRegistrationFormData> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(FtbPersonnelsStaffRegistrationFormData::getFormFieldId,"idCardNum");
            queryWrapper.like(FtbPersonnelsStaffRegistrationFormData::getValue,keyWords);
            List<FtbPersonnelsStaffRegistrationFormData> formData = registrationFormDataService.list(queryWrapper);
            List<String> phones = formData.stream().filter(v -> StringUtils.isNotEmpty(v.getValue())).map(FtbPersonnelsStaffRegistrationFormData::getPhone).distinct().collect(Collectors.toList());
            if (CollUtil.isNotEmpty(phones)){
                empEntryDTO.setPhoneNumbers(phones);
            }
        }
        String state = empEntryDTO.getState();
        if(StringUtils.isNotEmpty(state)){
            String[] split = state.split(",");
            List<String> stringList = new ArrayList<>(Arrays.asList(split));
            boolean contains = stringList.contains("6");
            if(contains){
                stringList.removeIf("6"::equals);
                empEntryDTO.setStates(stringList);
                empEntryDTO.setIsManually(true);
            }else {
                empEntryDTO.setStates(stringList);
            }
        }
        // 健康证状态筛选
        if (empEntryDTO.getHealthCertificateStatus() != null) {
            List<String> healthCertificateUserIds = certificateInstanceService.getHealthCertificateUserIdsByStatus(empEntryDTO.getHealthCertificateStatus());
            if (CollUtil.isNotEmpty(healthCertificateUserIds)) {
                empEntryDTO.setUserIds(healthCertificateUserIds);
            }
        }
        page = applyMapper.pageLists(page,empEntryDTO);
        List<FtbEmpEntryVO> records = page.getRecords();
        Predicate<FtbEmpEntryVO> predicate = v -> ObjectUtil.isNotNull(v.getCheckStatus()) &&  v.getCheckStatus() == 0  && v.getIsNeedCheck() == 0;
        List<String> orgIds = records.stream().filter(predicate).map(FtbEmpEntryVO::getCurrOrgId).collect(Collectors.toList());
        ActionResult<List<OrganizeGeneralDetailVO>> listActionResult = v2OrganizeApi.organizesByOrganizeIds(orgIds);
        Map<String, OrganizeGeneralDetailVO> detailVOMap = new HashMap<>();
        if (listActionResult != null && listActionResult.getCode() == 200){
            List<OrganizeGeneralDetailVO> list = listActionResult.getData();
            detailVOMap = list.stream().collect(Collectors.toMap(OrganizeGeneralDetailVO::getId, item -> item, (v1, v2) -> v1));
        }
        String tenantId = UserProvider.getUser().getTenantId();
        List<String> currPositionId = records.stream().filter(predicate).map(FtbEmpEntryVO::getCurrPositionId).collect(Collectors.toList());
        ActionResult<List<PositionBaseInfoVO>> actionResult = v2PositionApi.listPositionBaseInfoByIds(currPositionId, tenantId);
        Map<String, PositionBaseInfoVO> positionBaseInfoVOMap = new HashMap<>();
        if (actionResult != null && actionResult.getCode() == 200){
            List<PositionBaseInfoVO> list = actionResult.getData();
            positionBaseInfoVOMap = list.stream().collect(Collectors.toMap(PositionBaseInfoVO::getId, item -> item, (v1, v2) -> v1));
        }
        List<String> currRankID = records.stream().filter(predicate).map(FtbEmpEntryVO::getCurrRankID).collect(Collectors.toList());
        Map<String, GradeVO> gradeVOMap = new HashMap<>();
        if (CollUtil.isNotEmpty(currRankID)){
            ActionResult<List<GradeVO>> gradeActionResult = v2GradesApi.listGradeByIds(currRankID, tenantId);
            if (gradeActionResult != null && gradeActionResult.getCode() == 200){
                List<GradeVO> list = gradeActionResult.getData();
                gradeVOMap = list.stream().collect(Collectors.toMap(GradeVO::getId, item -> item, (v1, v2) -> v1));
            }
        }
        List<String> currShopIds = records.stream().map(FtbEmpEntryVO::getCurrShopId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(currShopIds)){
            QueryOrganizeListTargetTypesDTO targetTypesDTO = new QueryOrganizeListTargetTypesDTO();
            targetTypesDTO.setOrganizeIds(currShopIds);
            ActionResult<List<OrganizeGeneralDetailVO>> currShopIdsList = v2OrganizeApi.listOrganizeByTargetTypes(targetTypesDTO);
            if (currShopIdsList != null && currShopIdsList.getCode() == 200){
                List<OrganizeGeneralDetailVO> list = currShopIdsList.getData();
                detailVOMap.putAll(list.stream().collect(Collectors.toMap(OrganizeGeneralDetailVO::getId, item -> item, (v1, v2) -> v1)));
            }
        }
        Map<String, OrganizeGeneralDetailVO> finalDetailVOMap = detailVOMap;
        Map<String, PositionBaseInfoVO> finalPositionBaseInfoVOMap = positionBaseInfoVOMap;
        Map<String, GradeVO> finalGradeVOMap = gradeVOMap;
        List<String> phones = records.stream().map(FtbEmpEntryVO::getPhone).collect(Collectors.toList());
        if(CollUtil.isEmpty(phones)) return CultivatePage.coverPageList(page);
        Map<String, List<FtbPersonnelsStaffRegistrationFormData>> fieldValueListWithPhone = registrationFormDataService.queryFormFieldValueListWithPhone(phones);
        String userId = UserProvider.getUser().getUserId();
        // 列表集合获取用户Id集合
        List<String> userIds = records.stream().map(FtbEmpEntryVO::getUserId).collect(Collectors.toList());
        // 根据用户Id获取健康证详情
        Map<String, HealthCertificateDetailVO> healthCertificateVOMap = certificateInstanceService.getHealthCertificateDetails(userIds)
                .stream().collect(Collectors.toMap(HealthCertificateDetailVO::getUserId, item -> item, (v1, v2) -> v1));
        records.forEach(item->{
            // 办理状态替换
            if(item.getIsNeedCheck() == 1){
                item.setApprovalStatus(6);
                item.setApprovalStatusName("手动办理");
            }else {
                item.setApprovalStatus(item.getCheckStatus());
                transformData(item);
            }
            if (ObjectUtil.isNotEmpty(item.getActualStartDateDate())){
                String format = DateUtil.format(item.getActualStartDateDate(), "yyyy-MM-dd");
                item.setActualStartDate(format);
            }
            if (ObjectUtil.isNotEmpty(item.getCheckStatus()) && item.getIsNeedCheck() == 0 && item.getCheckStatus() == 0){
                // 组织替换
                if (finalDetailVOMap.containsKey(item.getCurrOrgId())) item.setCurrOrgName(finalDetailVOMap.get(item.getCurrOrgId()).getName());
                // 岗位替换
                if (finalPositionBaseInfoVOMap.containsKey(item.getCurrPositionId())) item.setCurrPositionName(finalPositionBaseInfoVOMap.get(item.getCurrPositionId()).getFullName());
                // 职级替换
                if (finalGradeVOMap.containsKey(item.getCurrRankID())) item.setCurrRankName(finalGradeVOMap.get(item.getCurrRankID()).getName());
                // 班组替换
                if (finalDetailVOMap.containsKey(item.getCurrShopId())) item.setCurrShopName(finalDetailVOMap.get(item.getCurrShopId()).getName());
            }
            if (!CollUtil.isEmpty(fieldValueListWithPhone) && fieldValueListWithPhone.containsKey(item.getPhone())){
                FtbPersonnelsStaffRegistrationFormData formData = fieldValueListWithPhone.get(item.getPhone()).stream().filter(v -> "idCardNum".equals(v.getFormFieldId())).findFirst().orElse(null);
                item.setIdCard(formData != null && StringUtils.isNotEmpty(formData.getValue()) ? formData.getValue() : StringUtils.isEmpty(item.getIdCard()) ? "" : item.getIdCard());
            }
            if (StringUtils.isNotEmpty(item.getTaskInfoId())) {
                FlowTaskEntity byTaskId = flowTaskApi.findByTaskId(item.getTaskInfoId());
                if (ObjectUtil.isNotEmpty(byTaskId) &&  byTaskId.getCreatorUserId().equals(userId)) {
                    item.setCurrentSponsor(1);
                } else {
                    item.setCurrentSponsor(0);
                }
            }
            // 健康证状态回显
            if (healthCertificateVOMap.containsKey(item.getUserId())) {
                item.setHealthCertificateStatus(healthCertificateVOMap.get(item.getUserId()).getStatus());
                item.setHealthCertificateStatusName(healthCertificateVOMap.get(item.getUserId()).getStatusDesc());
            }
        });
        return CultivatePage.coverPageList(page);
    }


    @Override
    @GlobalTransactional(rollbackFor = Throwable.class)
    public FtbEmpResultVO addNewEmp(FtbEmpAddNewDTO dto) {
        FtbEmpResultVO resultVO = new FtbEmpResultVO();
        // 入职手机号校验
        if (StringUtils.isEmpty(dto.getId())) verifyWhetherTheMobilePhoneNumberIsHired(dto.getPhone());
        if (ftbPersonnelsBlacklistService.hasItBeenBlacklisted(dto.getPhone())) {
            throw new RuntimeException("当前人员处于黑名单中，请将其移出黑名单后再办理入职!");
        }
        // 身份证校验
        verifyWhetherTheIdentityCardNumberIsHired(dto.getIdCard(),dto.getPhone());
        // 主键id 编辑
        // 补充数据
        FtbPersonnelsStaffEmploymentApply apply = FtbEmpAddNewDTO.covert(dto);
        supplementalData(apply,UserProvider.getUser().getTenantId());
        UpdateUserDTO userDTO = new UpdateUserDTO();
        // 动态判断文档是否提交
        LambdaQueryWrapper<FtbPersonnelsStaffRegistrationFormData> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsStaffRegistrationFormData::getPhone,dto.getPhone());
        List<FtbPersonnelsStaffRegistrationFormData> formData = registrationFormDataService.list(queryWrapper);
        if (CollUtil.isNotEmpty(formData) && !formData.isEmpty() && StringUtils.isEmpty(dto.getId())) apply.setIsSubmitForm(1);
        FtbPersonnelsStaffRegistrationFormData idCardNum = formData.stream().filter(v -> v.getFormFieldId().equals("idCardNum")).findFirst().orElse(null);
        // 2次入职的人没有设置身份证 且之前有身份证需要回填
        if (StringUtils.isEmpty(dto.getIdCard())
                && CollUtil.isNotEmpty(formData)
                && idCardNum != null) {
            FtbPersonnelsStaffEmploymentApply employmentApply = null;
            if (StringUtils.isNotEmpty(apply.getId())) {
                employmentApply = applyMapper.selectById(apply.getId());
            }
            if ( employmentApply != null && StringUtils.isNotEmpty(employmentApply.getIdCardNum())){
                apply.setIdCardNum(null);
            } else {
                apply.setIdCardNum(idCardNum.getValue());
            }

        }
        if (StringUtils.isNotEmpty(apply.getIdCardNum())){
            IdCardVerificationResponse idCardVerification = idCardVerificationUtils.idCardVerification(apply.getIdCardNum(), apply.getWorkerName(), UserProvider.getUser().getTenantId());
            idCardVerificationUtils.checkIdCardVerification(idCardVerification);
        }
        String userId = null;
        if (StringUtils.isNotEmpty(apply.getId())){
            FtbPersonnelsStaffEmploymentApply employmentApply = applyMapper.selectById(apply.getId());
            // 比较头像
            if (!employmentApply.getWorkerName().equals(apply.getWorkerName())){
                String userHeadLog = generaDefaultUserHeadLog(employmentApply.getWorkerName());
                apply.setUserHeadLog(userHeadLog);
                userDTO.setHeadIcon(userHeadLog);
            }
            userId = employmentApply.getUserId();
            LambdaUpdateWrapper<FtbPersonnelsStaffEmploymentApply> wrapper = Wrappers.lambdaUpdate();
            if (userId == null) {
                // 生成头像
                String userHeadLog =  generaDefaultUserHeadLog(apply.getWorkerName());
                userId = saveUserInfo(apply, userHeadLog);
                wrapper.set(FtbPersonnelsStaffEmploymentApply::getUserId,userId);
            }
            userDTO.setRealName(apply.getWorkerName());
            UserBoundInfoDTO userBoundInfoDTO = new UserBoundInfoDTO();
            userBoundInfoDTO.setOrganizeId(apply.getCurrOrg());
            userBoundInfoDTO.setPositionId(apply.getCurrPosition());
            userBoundInfoDTO.setGradesId(apply.getCurrRank());
            userBoundInfoDTO.setStoreTeamId(apply.getCurrGroupId());
            userDTO.setBoundInfoDTO(userBoundInfoDTO);
            // 更新用户信息
            v2UserApi.updateUserInfo(userId,userDTO);
            wrapper.eq(FtbPersonnelsStaffEmploymentApply::getId,apply.getId());
            if (apply.getIdCardNum() == null){
                wrapper.set(FtbPersonnelsStaffEmploymentApply::getIdCardNum ,null);
            }
            if (apply.getActualStartDate() == null){
                wrapper.set(FtbPersonnelsStaffEmploymentApply::getActualStartDate ,null);
            }
            applyMapper.update(apply,wrapper);
        }else {
            // 生成头像
            String userHeadLog =  generaDefaultUserHeadLog(apply.getWorkerName());
            userId = saveUserInfo(apply, userHeadLog);
            apply.setUserId(userId);
            apply.setSource(0);
            apply.setStatus(0);
            apply.setUserHeadLog(userHeadLog);
            // 健康证添加
            certificateInstanceService.initHealthCertificate(userId);
            applyMapper.insert(apply);
            sendSms(dto.getPhone(), UserProvider.getUser().getTenantId());
        }
        Map<String, Object> formDataMap = BeanUtil.beanToMap(apply);
        if (apply.getIdCardNum() != null) {
            formDataMap.put("idCardNum", apply.getIdCardNum());
        }else {
            formDataMap.put("idCardNum", "");
        }
        if (apply.getActualStartDate() != null) {
            formDataMap.put("actualStartDate", apply.getActualStartDate());
        }else {
            formDataMap.putIfAbsent("actualStartDate", "");
        }
        formDataMap.put("probationPeriod", "");
        formDataMap.put("workerStatus", "");
        formDataMap.put("workerType", "");
        // 合同状态
        formDataMap.put("contractStatus", "");
        if (apply.getActualStartDate() != null) {
            formDataMap.put("actualStartDate", personnelOrgUtils.dateToString(apply.getActualStartDate(), ""));
        }
        addRunBirthday(formDataMap);
        registrationFormDataService.syncData(formDataMap, dto.getPhone(), "");
        resultVO.setUserId(apply.getUserId());
        resultVO.setRealName(apply.getWorkerName());
        resultVO.setPhone(apply.getPhone());
        resultVO.setIsSubmitForm(apply.getIsSubmitForm());
        attendanceMessageNotifications(apply.getActualStartDate(), apply.getCurrOrg(), userId);
        return resultVO;
    }

    public void sendSms(String phone, String tenantId) {
        // 没有环境参数不发短信
        if (ObjectUtil.isEmpty(environmentParamConfig)) return;
        Boolean isEnableSms = environmentParamConfig.getIsEnableSms();
        if (!isEnableSms) return;
        if (personnelOrgUtils.queryIsSendPhoneMsg(phone)) {
            log.error("今日已经发送了短信");
            return;
        }
        Map<String, Object> map = new LinkedHashMap<>();
        try {
            if (StringUtils.isEmpty(phone)) return;
            log.error("发送短信");
            Map<String, SmsConfig.TenantConfig> tenants = smsConfig.getTenants();
            SmsConfig.TenantConfig tenantConfig;
            String used = tenantId;
            if (tenants.containsKey(tenantId)){
                tenantConfig = tenants.get(tenantId);
            }else {
                used = "common";
                tenantConfig = tenants.get(used);
            }
            String signContent = tenantConfig.getSmsSignContent();
            if (used.equals("common")) {
                map.put("1", signContent);
                map.put("2", getLastFourDigits(phone));
                map.put("3", "0000");
            }
            smsSendUtil.sendSms(List.of(phone), "ACCOUNT_GENERATE", map,tenantId);
            personnelOrgUtils.setTodayIsSendPhoneMsg(phone);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 提取手机号后四位数字
     *
     * @param phoneNumber 完整手机号字符串
     * @return 后四位数字字符串，若输入无效则返回 null
     */
    public static String getLastFourDigits(String phoneNumber) {
        if (phoneNumber == null || phoneNumber.trim().isEmpty()) {
            return null;
        }

        // 清理手机号，只保留数字
        String cleanedNumber = phoneNumber.replaceAll("\\D", "");

        // 检查清理后的号码长度
        if (cleanedNumber.length() < 4) {
            return null;
        }

        // 截取后四位
        return cleanedNumber.substring(cleanedNumber.length() - 4);
    }

    @Override
    public String promoteOnboardingManagement(FtbEmpAddNewDTO dto, String tenantId, String moduleId) {
        if ( StringUtils.isEmpty(dto.getCurrOrgId()) ||  StringUtils.isEmpty(dto.getCurrPositionId()) ) {
            throw new RuntimeException("未获取到正确的组织或岗位，如需办理入职，请前往入职管理新增员工！");
        }
        if (StringUtils.isNotEmpty(dto.getCurrRankId())) {
            ActionResult<GradeVO> gradeVOActionResult = v2GradesApi.infoGradeNoToken(dto.getCurrRankId(),tenantId);
            if (gradeVOActionResult == null || gradeVOActionResult.getData() == null) {
                throw new RuntimeException("未获取到正确的职级，如需办理入职，请前往入职管理新增员工!");
            }
        }
        // 入职手机号校验
        if (dto.getId() == null) verifyWhetherTheMobilePhoneNumberIsHired(dto.getPhone());
        if (ftbPersonnelsBlacklistService.hasItBeenBlacklisted(dto.getPhone())) {
            throw new RuntimeException("当前人员处于黑名单中，请将其移出黑名单后再办理入职!");
        }
        // 身份证校验
        verifyWhetherTheIdentityCardNumberIsHired(dto.getIdCard(),dto.getPhone());
        // 主键id 编辑
        FtbPersonnelsStaffEmploymentApply apply = FtbEmpAddNewDTO.covert(dto);
        supplementalData(apply,tenantId);
        UpdateUserDTO userDTO = new UpdateUserDTO();
        if (StringUtils.isNotEmpty(apply.getIdCardNum())){
            IdCardVerificationResponse idCardVerification = idCardVerificationUtils.idCardVerification(apply.getIdCardNum(), apply.getWorkerName(), UserProvider.getUser().getTenantId());
            idCardVerificationUtils.checkIdCardVerification(idCardVerification);
        }
        String resultUserId = "";
        if (StringUtils.isNotEmpty(apply.getId())){
            FtbPersonnelsStaffEmploymentApply employmentApply = applyMapper.selectById(apply.getId());
            // 比较头像
            if (!employmentApply.getWorkerName().equals(apply.getWorkerName())){
                String userHeadLog = generaDefaultUserHeadLog(employmentApply.getWorkerName());
                apply.setUserHeadLog(userHeadLog);
                userDTO.setHeadIcon(userHeadLog);
            }
            String  userId = employmentApply.getUserId();
            LambdaUpdateWrapper<FtbPersonnelsStaffEmploymentApply> wrapper = Wrappers.lambdaUpdate();
            // 兼容数据
            if (userId == null){
                // 后续处理入职回填userId 生成头像
                String userHeadLog =  generaDefaultUserHeadLog(apply.getWorkerName());
                userId = saveUserInfo(apply, userHeadLog,tenantId);
                wrapper.set(FtbPersonnelsStaffEmploymentApply::getUserId,userId);
                resultUserId = userId;
            }
            userDTO.setRealName(apply.getWorkerName());
            userDTO.setEntryDate(apply.getActualStartDate());
            UserBoundInfoDTO userBoundInfoDTO = new UserBoundInfoDTO();
            userBoundInfoDTO.setOrganizeId(apply.getCurrOrg());
            userBoundInfoDTO.setPositionId(apply.getCurrPosition());
            userBoundInfoDTO.setGradesId(apply.getCurrRank());
            userBoundInfoDTO.setStoreTeamId(apply.getCurrGroupId());
            userBoundInfoDTO.setTenantId(tenantId);
            userDTO.setBoundInfoDTO(userBoundInfoDTO);
            // 更新用户信息
            v2UserApi.updateUserInfo(userId,userDTO);
            wrapper.eq(FtbPersonnelsStaffEmploymentApply::getId,apply.getId());
            if (apply.getIdCardNum() == null)wrapper.set(FtbPersonnelsStaffEmploymentApply::getIdCardNum ,null);
            applyMapper.update(apply,wrapper);
        }else {
            // 生成头像
            apply.setVersionNum(1);
            apply.setStatus(0);
            applyMapper.insert(apply);
            String applyId = apply.getId();
            // 后续处理入职回填userId 生成头像
            String userHeadLog =  generaDefaultUserHeadLog(apply.getWorkerName());
            String  userId = saveUserInfo(apply, userHeadLog,tenantId);
            resultUserId = userId;
            LambdaUpdateWrapper<FtbPersonnelsStaffEmploymentApply> wrapper = Wrappers.lambdaUpdate();
            wrapper.set(FtbPersonnelsStaffEmploymentApply::getUserId,userId);
            wrapper.set(FtbPersonnelsStaffEmploymentApply::getUserHeadLog, userHeadLog);
            wrapper.eq(FtbPersonnelsStaffEmploymentApply::getId, applyId);
            applyMapper.update(null,wrapper);
            threadPoolTaskExecutor.execute(ThreadContext.wrap(()->{
                //Map<String, String> headers = ImmutableMap.of(Constants.AUTHORIZATION.toLowerCase(), token);
                // FeignHolder.set(headers);
                extracted(dto.getWorkerName(), tenantId, userId,apply.getCurrOrg(),moduleId);
            }));

        }
        sendSms(dto.getPhone(), UserProvider.getUser().getTenantId());
        return resultUserId;
    }

    public void extracted(String workerName , String tenantId, String userId, String currOrg, String moduleId) {
        List<String> stringList = permissionsUtils.getUserPersonnelOrganizationIdDataPermissions(userId,
                List.of(PermissionsEnums.PERSONNEL_MANAGEMENT_Button.getValue().split(",")),
                "",
                List.of(PermissionsEnums.PERSONNEL_MANAGEMENT_WEB.getValue(),
                        PermissionsEnums.PERSONNEL_MANAGEMENT_APP.getValue()),
                tenantId,currOrg, moduleId);
        ftbPersonnlesIMUtils.sendMsgWithList(tenantId,stringList, workerName, moduleId);
    }

    /**
     * 查询身份证是否在系统
     * @param idCard
     */
    private void verifyWhetherTheIdentityCardNumberIsHired(String idCard,String phone) {
        if(StringUtils.isEmpty(idCard)) return;
        FtbPersonnelsStaffRegistrationFormDataMapper baseMapper = (FtbPersonnelsStaffRegistrationFormDataMapper) registrationFormDataService.getBaseMapper();
        Integer idCardNum = baseMapper.verifyWhetherTheDataExists(phone, "idCardNum",idCard);
        if (idCardNum > 0) throw new RuntimeException("当前身份证已经存在系统,请勿重复添加!");
    }

    /**
     * 查询手机号是否在已入职列表里面
     * @param phone
     */
    private void verifyWhetherTheMobilePhoneNumberIsHired(String phone ) {
        QueryWrapper<FtbPersonnelsStaffEmploymentApply> ftbPersonnelsStaffEmploymentApplyQueryWrapper = new QueryWrapper<>();
        Long aLong = applyMapper.selectCount(
                ftbPersonnelsStaffEmploymentApplyQueryWrapper.lambda().eq(FtbPersonnelsStaffEmploymentApply::getPhone, phone)
                        .eq(FtbPersonnelsStaffEmploymentApply::getEnabledMark, 0));
        if (aLong > 0) throw new RuntimeException("当前手机号已经存在系统,请勿重复添加!");
        //查询手机号是否在已入职列表里面
        QueryWrapper<FtbPersonnelsStaffRoster> rosterWrapper = new QueryWrapper<>();
        rosterWrapper.lambda().eq(FtbPersonnelsStaffRoster::getPhone, phone).eq(FtbPersonnelsStaffRoster::getEnabledMark, 0);
        FtbPersonnelsStaffRoster oldRosterEntity = rosterService.getOne(rosterWrapper);
        if (ObjectUtil.isNotEmpty(oldRosterEntity)) {
            if (oldRosterEntity.getWorkerStatus().equals("302") || oldRosterEntity.getWorkerStatus().equals("303") || oldRosterEntity.getWorkerStatus().equals("306")) {
                throw new RuntimeException("该员工已办理入职，请勿重复操作!");
            }else if (oldRosterEntity.getWorkerStatus().equals("304")) {
                throw new RuntimeException("该员工已经在离职中!");
            }
        }
    }

    @Override
    @GlobalTransactional(rollbackFor = Throwable.class)
    public void terminateOnboarding(String id) {

        FtbPersonnelsStaffEmploymentApply apply = applyMapper.selectById(id);
        if (apply.getStatus() == 5) {
            throw new RuntimeException("该员工已终止入职，请勿重复操作!");
        }
        String userId = apply.getUserId();
        if (UserProvider.getUser().getUserId().equals(userId)) throw new RuntimeException("不能操作自己!");
        LambdaUpdateWrapper<FtbPersonnelsStaffEmploymentApply> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(FtbPersonnelsStaffEmploymentApply::getId, id);
        wrapper.set(FtbPersonnelsStaffEmploymentApply::getCheckStatus, 5);
        applyMapper.update(new FtbPersonnelsStaffEmploymentApply(),wrapper);
        if(StringUtils.isEmpty(userId)) return;
        v2UserApi.updateUserAccount(userId,UserWorkStatusEnums.ONBOARDING_FAILED);
        // 删除账号
        pTenantAccountApi.deleteUser(userId);
        AuthUtil.kickoutByUserId(userId);
        // 通知考勤人员终止入职
        Map<String, Object> map = new HashMap<>();
        map.put("userId", userId);
        map.put("currOrgId", apply.getCurrOrg());
        map.put("tenantId", UserProvider.getUser().getTenantId());
        secondmentConsumerSourceMsg.sendMessageOnboardingFail(JSONObject.toJSONString(map));
        //删除健康证
        certificateInstanceService.deleteHealthCertificate(userId);
    }

    @Override
    @GlobalTransactional(rollbackFor = Throwable.class)
    public void deleteEmployeeOnboardingRecords(String id) {
        FtbPersonnelsStaffEmploymentApply item = applyMapper.selectById(id);
        LambdaUpdateWrapper<FtbPersonnelsStaffRegistrationFormData> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(FtbPersonnelsStaffRegistrationFormData::getPhone, item.getPhone());
        registrationFormDataService.remove(wrapper);
        applyMapper.deleteById(id);
        String userId = item.getUserId();
        if(StringUtils.isEmpty(userId)) return;
        ActionResult<Boolean> actionResult = v2UserApi.removeUser(userId, null);
        if (actionResult == null || actionResult.getCode() != 200) {
            throw new RuntimeException("删除用户失败!请重试!");
        }
        if(!pTenantAccountApi.deleteUserWithPlatform(userId)){
            throw new RuntimeException("删除用户账号信息失败!请重试!");
        }
        AuthUtil.kickoutByUserId(userId);
    }

    @Override
    @GlobalTransactional(rollbackFor = Throwable.class,timeoutMills = 5*60*1000)
    public void handleJoinJob(FtbEmpConfirmDTO ftbEmpConfirmDTO) {
        if (ftbPersonnelsBlacklistService.hasItBeenBlacklisted(ftbEmpConfirmDTO.getPhone())) {
            throw new RuntimeException("当前人员处于黑名单中，请将其移出黑名单后再办理入职!");
        }
        String  userId = null;
        String currRankId = ftbEmpConfirmDTO.getCurrRankId();
        if (StringUtils.isNotEmpty(currRankId)) {
            QueryUserBoundDTO checkExistByPositionDTO = new QueryUserBoundDTO();
            checkExistByPositionDTO.setOrganizeId(ftbEmpConfirmDTO.getCurrOrgId());
            checkExistByPositionDTO.setPositionId(ftbEmpConfirmDTO.getCurrPositionId());
            checkExistByPositionDTO.setGradeId(currRankId);
            doCheckOrgPositionGradesBoundDTO(checkExistByPositionDTO);

        }
        // 回填入职数据
        FtbPersonnelsStaffEmploymentApply covertToEntity = FtbEmpConfirmDTO.covertToEntity(ftbEmpConfirmDTO);
        covertToEntity.setIsNeedCheck(1);
        FtbPersonnelsStaffEmploymentApply apply = applyMapper.selectById(covertToEntity.getId());
        covertToEntity.setCreatorUserId(apply.getCreatorUserId());
        covertToEntity.setUserId(apply.getUserId());
        // 兼容之前的入职数据
        if (StringUtils.isEmpty(apply.getUserId())){
            String userHeadLog =  generaDefaultUserHeadLog(apply.getWorkerName());
            userId = saveUserInfo(apply, userHeadLog);
            covertToEntity.setUserId(userId);
        }
        if(UserProvider.getUser().getUserId().equals(apply.getUserId())) {
            throw new RuntimeException("员工本人不能为自己办理入职!");
        }
        covertToEntity.setTaskInfoId(null);
        // 补充数据
        supplementalData(covertToEntity,UserProvider.getUser().getTenantId());
        FtbPersonnelsStaffRoster personnelsStaffRoster = buildApplyData(covertToEntity);
        applyMapper.updateById(covertToEntity);
        // 数据入花名册
        FtbPersonnelsStaffEmploymentApply ftbPersonnelsStaffEmploymentApply = applyMapper.selectById(covertToEntity.getId());
        FtbPersonnelsStaffRoster staffRoster = covertRoster(ftbPersonnelsStaffEmploymentApply,
                ftbEmpConfirmDTO,personnelsStaffRoster.getSystemWokerId(),personnelsStaffRoster.getJoinNum());
        if (personnelsStaffRoster.getId() != null){
            staffRoster.setId(personnelsStaffRoster.getId());
            rosterService.updateById(staffRoster);
        }else {
            rosterService.save(staffRoster);
        }
        // 同步更改姓名到组织架构
        UpdateUserDTO userDTO = new UpdateUserDTO();
        userDTO.setRealName(ftbPersonnelsStaffEmploymentApply.getWorkerName());
        v2UserApi.updateUserInfo(ftbPersonnelsStaffEmploymentApply.getUserId(),userDTO);
        // 变更内推池状态
        personnelOrgUtils.sysWorkerStatusToUchisuike(staffRoster.getPhone(), staffRoster.getWorkerStatus());
        // 数据入转正管理
        syncRegular(staffRoster,
                ftbEmpConfirmDTO.getProbationPeriod(),
                ftbEmpConfirmDTO.getProbationPeriodDay(),
                ftbEmpConfirmDTO.getAffiliatedReportsTo(),
                ftbEmpConfirmDTO.getPlanProbationaryDate());
        // 回填扩展数据
        dataSave(staffRoster, ftbEmpConfirmDTO);
        //已经填写了入职登记表，那么就要把之前入职登记表中的数据加上花名册ID
        registrationFormDataService.addRosterIdToFormData(staffRoster.getPhone(), staffRoster.getId());
        // 写入职信息
        //写入入职薪酬
        writeEntryPay(staffRoster);
        //员工成长
        employeeGrowth(staffRoster,
                ftbEmpConfirmDTO.getAffiliatedReportsTo(),
                ftbEmpConfirmDTO.getActualStartDate());
        // 更改员工状态
        synchronizeEmployeeStatus(staffRoster, ftbEmpConfirmDTO.getAffiliatedReportsTo());
        // 同步薪酬数据
        syncSalaryData(covertToEntity);
    }

    private void supplementalData(FtbPersonnelsStaffEmploymentApply covertToEntity,String tenantId) {
        // 主键id 编辑
        ActionResult<OrganizeGeneralDetailVO> actionResult = v2OrganizeApi.organizeInfoByIdNoToken(null, covertToEntity.getCurrOrg(),tenantId);
        if (ObjectUtil.isNotEmpty(actionResult) && ObjectUtil.isNotEmpty(actionResult.getData())) {
            covertToEntity.setCurrOrgName(actionResult.getData().getName());
        }
        if (StringUtils.isNotEmpty(covertToEntity.getCurrGroupId())){
            ActionResult<OrganizeGeneralDetailVO> organizeInfoById = v2OrganizeApi.organizeInfoByIdNoToken(OrganizeCategoryEnums.TEAM, covertToEntity.getCurrGroupId(),tenantId);
            if (ObjectUtil.isNotEmpty(organizeInfoById) && ObjectUtil.isNotEmpty(organizeInfoById.getData())) {
                covertToEntity.setCurrGroupName(organizeInfoById.getData().getName());
            }
        }else {
            covertToEntity.setCurrGroupName("");
        }
        String onboardPostId = covertToEntity.getCurrPosition();
        if (StringUtils.isNotEmpty(onboardPostId)) {
            ActionResult<PositionVO> voActionResult = v2PositionApi.infoPositionNoToken(onboardPostId,tenantId);
            if (ObjectUtil.isNotEmpty(voActionResult) && ObjectUtil.isNotEmpty(voActionResult.getData())) {
                covertToEntity.setCurrPositionName(voActionResult.getData().getFullName());
            }
        }
        String onboardGradeId = covertToEntity.getCurrRank();
        if (StringUtils.isNotEmpty(onboardGradeId)) {
            ActionResult<GradeVO> gradeVOActionResult = v2GradesApi.infoGradeNoToken(onboardGradeId,tenantId);
            if (ObjectUtil.isNotEmpty(gradeVOActionResult) && ObjectUtil.isNotEmpty(gradeVOActionResult.getData())){
                covertToEntity.setCurrRankName(gradeVOActionResult.getData().getFullName());
            }
        }else {
            covertToEntity.setCurrRankName("");
        }
    }


    @Override
    @GlobalTransactional
    public void handleJoinJobOA(FtbEmpConfirmDTO ftbEmpConfirmDTO) {
        QueryWrapper<FtbPersonnelsStaffRoster> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(FtbPersonnelsStaffRoster::getPhone, ftbEmpConfirmDTO.getPhone());
        FtbPersonnelsStaffRoster oldRoster = rosterService.getOne(wrapper);
        if (ObjectUtil.isNotEmpty(oldRoster)) {
            if (ObjectUtil.isNotEmpty(oldRoster.getDepartDate()) &&
                    ( ftbEmpConfirmDTO.getActualStartDate().equals(oldRoster.getDepartDate()) ||
                            ftbEmpConfirmDTO.getActualStartDate().before(oldRoster.getDepartDate()))
            ) {
                throw new RuntimeException("再次入职，入职时间不能早于上次离职时间" + DateUtil.format(oldRoster.getDepartDate(), "yyyy年MM月dd日!"));
            }
        }
        if (ftbEmpConfirmDTO.getActualStartDate().after(new Date())) {
            throw new RuntimeException("实际入职时间不能大于当前时间!");
        }
        if (ObjectUtil.isNotEmpty(ftbEmpConfirmDTO.getEntryMoney()) &&
                ftbEmpConfirmDTO.getEntryMoney().compareTo(BigDecimal.valueOf(100000000)) >= 1){
            throw new RuntimeException("薪资项合计超出上限，请输入合法薪资数据");
        }
        if (ftbPersonnelsBlacklistService.hasItBeenBlacklisted(ftbEmpConfirmDTO.getPhone())) {
            throw new RuntimeException("当前人员处于黑名单中，请将其移出黑名单后再办理入职!");
        }
        LambdaQueryWrapper<FtbPersonnelsStaffEmploymentApply> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsStaffEmploymentApply::getId, ftbEmpConfirmDTO.getId());
        queryWrapper.eq(FtbPersonnelsStaffEmploymentApply::getTaskInfoId, ftbEmpConfirmDTO.getTaskId());
        List<FtbPersonnelsStaffEmploymentApply> applyList = applyMapper.selectList(queryWrapper);
        if (CollUtil.isNotEmpty(applyList))  throw new RuntimeException("该员工已在审批中，请勿重复操作!");
        // 查询员工
        LambdaQueryWrapper<FtbPersonnelsStaffEmploymentApply> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(FtbPersonnelsStaffEmploymentApply::getPhone,ftbEmpConfirmDTO.getPhone() );
        lambdaQueryWrapper.last("limit 1");
        FtbPersonnelsStaffEmploymentApply employmentApply = applyMapper.selectOne(lambdaQueryWrapper);
        // 校验重复操作
        checkWhetherYouHaveBeenHired(employmentApply.getPhone());
        if(UserProvider.getUser().getUserId().equals(employmentApply.getUserId())) {
            throw new RuntimeException("员工本人不能为自己办理入职!");
        }
        // 校验岗位是否还存在
        String currRankId = ftbEmpConfirmDTO.getCurrRankId();
        if (StringUtils.isNotEmpty(currRankId)) {
            QueryUserBoundDTO checkExistByPositionDTO = new QueryUserBoundDTO();
            checkExistByPositionDTO.setPositionId(ftbEmpConfirmDTO.getCurrPositionId());
            checkExistByPositionDTO.setGradeId(currRankId);
            doCheckOrgPositionGradesBoundDTO(checkExistByPositionDTO);
        }
        // 回填入职数据
        FtbPersonnelsStaffEmploymentApply covertToEntity = FtbEmpConfirmDTO.covertToEntity(ftbEmpConfirmDTO);
        // 设置审批状态
        covertToEntity.setIsNeedCheck(0);
        covertToEntity.setCheckStatus(1);
        covertToEntity.setTaskInfoId(ftbEmpConfirmDTO.getTaskId());
        covertToEntity.setId(ftbEmpConfirmDTO.getId());
        // 回填扩展数据
        dataSaveWithOA(ftbEmpConfirmDTO);
        // 补充数据
        supplementalData(covertToEntity,UserProvider.getUser().getTenantId());
        applyMapper.updateById(covertToEntity);
    }

    private void  checkWhetherYouHaveBeenHired(String phone){
        QueryWrapper<FtbPersonnelsStaffRoster> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(FtbPersonnelsStaffRoster::getPhone, phone);
        FtbPersonnelsStaffRoster oldRoster = rosterService.getOne(wrapper);
        if (ObjectUtil.isNotEmpty(oldRoster)) {
            //重复入职
            if (oldRoster.getEnabledMark() == 0 && (oldRoster.getWorkerStatus().equals("302") ||
                    oldRoster.getWorkerStatus().equals("303"))) {
                throw new RuntimeException("该员工已经入职，请勿重复操作");
            } else if (oldRoster.getEnabledMark() == 0 && oldRoster.getWorkerStatus().equals("304")) {
                throw new RuntimeException("该员工已经在离职中");
            }
        }

    }

    /***
     * 构建入职数据校验是否二次入职
     * @param covertToEntity
     * @return
     */
    private FtbPersonnelsStaffRoster buildApplyData(FtbPersonnelsStaffEmploymentApply covertToEntity) {
        QueryWrapper<FtbPersonnelsStaffRoster> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(FtbPersonnelsStaffRoster::getPhone, covertToEntity.getPhone());
        FtbPersonnelsStaffRoster oldRoster = rosterService.getOne(wrapper);
        long count = 0;
        QueryListUserDTO userDTO = new QueryListUserDTO();
        userDTO.setMobilePhone(covertToEntity.getPhone());
        ActionResult<List<UserPageListVO>> copyInfo = v2UserApi.listUser(userDTO);
        if (copyInfo.getCode() == 200 &&  CollUtil.isNotEmpty(copyInfo.getData())) {
            UserPageListVO userPageListVO = copyInfo.getData().stream().findFirst().orElse(new UserPageListVO());
            LambdaQueryWrapper<FtbPersonnelsStaffGrowthLog> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(FtbPersonnelsStaffGrowthLog::getUserId, userPageListVO.getId());
            queryWrapper.in(FtbPersonnelsStaffGrowthLog::getGrowthType,0,3);
            count = growthLogService.count(queryWrapper);
        }
        if (ObjectUtil.isNotEmpty(oldRoster)){
            //重复入职
            if (oldRoster.getEnabledMark() == 0 && (oldRoster.getWorkerStatus().equals("302") ||
                    oldRoster.getWorkerStatus().equals("303"))) {
                throw new RuntimeException("该员工已经入职，请勿重复操作");
            }else if (oldRoster.getEnabledMark() == 0 &&  oldRoster.getWorkerStatus().equals("304")) {
                throw new RuntimeException("该员工已经在离职中");
            }
            if (ObjectUtil.isNotEmpty(oldRoster.getJoinNum())) {
                covertToEntity.setJoinNum(oldRoster.getJoinNum() + 1);
            } else {
                covertToEntity.setJoinNum(1);
            }
            if (ObjectUtil.isNotEmpty(oldRoster.getDepartDate()) &&
                    ( covertToEntity.getActualStartDate().equals(oldRoster.getDepartDate()) ||
                            covertToEntity.getActualStartDate().before(oldRoster.getDepartDate()))

            ){
                throw new RuntimeException("再次入职，入职时间不能早于上次离职时间"+DateUtil.format(oldRoster.getDepartDate(), "yyyy年MM月dd日!"));
            }
            covertToEntity.setSystemWokerId(oldRoster.getSystemWokerId());
            oldRoster.setJoinNum(covertToEntity.getJoinNum());
            return oldRoster;

        }else if (ObjectUtil.isEmpty(oldRoster) && count > 0){
            FtbPersonnelsStaffRoster oldRosterNew = new FtbPersonnelsStaffRoster();
            // 用户被删除了且
            // 生成系统id
            covertToEntity.setSystemWokerId(SelfGrowthUtil.providePersonnelsCustomIDBasedOnTheModule(SelfrowingEnum.STAFF_ROSTER));
            covertToEntity.setJoinNum((int) (count+1));
            oldRosterNew.setSystemWokerId(covertToEntity.getSystemWokerId());
            oldRosterNew.setJoinNum(covertToEntity.getJoinNum());
            return oldRosterNew;
        } else {
            FtbPersonnelsStaffRoster oldRosterNew = new FtbPersonnelsStaffRoster();
            // 生成系统id
            covertToEntity.setSystemWokerId(SelfGrowthUtil.providePersonnelsCustomIDBasedOnTheModule(SelfrowingEnum.STAFF_ROSTER));
            covertToEntity.setJoinNum(1);
            oldRosterNew.setSystemWokerId(covertToEntity.getSystemWokerId());
            oldRosterNew.setJoinNum(covertToEntity.getJoinNum());
            return oldRosterNew;
        }
    }

    @Override
    public FtbEmpConfirmVO onboardingDetails(String id) {
        FtbPersonnelsStaffEmploymentApply item = applyMapper.selectById(id);
        if (item == null) {
            return null;
        }
        return getApplyInfoItem(item);
    }

    @NotNull
    private FtbEmpConfirmVO getApplyInfoItem(FtbPersonnelsStaffEmploymentApply item) {
        FtbEmpConfirmVO dto = FtbEmpConfirmVO.covert(item);
        // 重新获取
        if(item.getCheckStatus() == 3 && StringUtils.isNotEmpty(item.getUserId())){
            ActionResult<UserBoundInfoVO> usersBound = v2UserApi.getUsersBound(item.getUserId(), UserProvider.getUser().getTenantId());
            if (usersBound != null && usersBound.getCode() == 200) {
                UserBoundInfoVO data = usersBound.getData();
                dto.setCurrOrgId(data.getOrganizeId());
                dto.setCurrOrgName(data.getOrganizeName());
                dto.setCurrPositionId(data.getPositionId());
                dto.setCurrPositionName(data.getPositionName());
                dto.setCurrShopId(data.getStoreTeamId());
                dto.setCurrShopName(data.getStoreTeamName());
                dto.setCurrRankId(data.getGradesId());
                dto.setCurrRankName(data.getGradesName());
            }
        }
        dto.setPlanProbationaryDate( personnelOrgUtils.dateToString(item.getPlanProbationaryDate(), ""));
//        if (StringUtils.isNotEmpty(dto.getCurrShopId())) {
//            ActionResult<OrganizeGeneralDetailVO> shopActionResult = v2OrganizeApi.organizeInfoById(null, dto.getCurrShopId());
//            if (shopActionResult != null && shopActionResult.getCode() == 200 && shopActionResult.getData() != null) {
//                dto.setCurrShopName(shopActionResult.getData().getName());
//            }
//        }
        List<String> creatorUserId = Stream.of(item.getCreatorUserId(), dto.getAffiliatedReportsTo()).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
        if (CollUtil.isEmpty(creatorUserId)) return dto;
        ActionResult<List<UserBoundVO>> listActionResult = v2UserApi.getUserPrimaryBoundBatch(creatorUserId, UserProvider.getUser().getTenantId());
        if (listActionResult != null && listActionResult.getCode() == 200) {
            Map<String, UserBoundVO> map = listActionResult.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity(), (k1, k2) -> k1));
            UserBoundVO first = map.get(item.getCreatorUserId());
            if (map.containsKey(item.getCreatorUserId())) {
                dto.setCreateUserName(first.getUserName());
            }
            if ( map.containsKey(dto.getAffiliatedReportsTo())) {
                UserBoundVO second = map.get(dto.getAffiliatedReportsTo());
                dto.setAffiliatedReportsToName(second.getUserName());
            }
        }
        List<FtbPersonnelsEmployeeTypeVO> employeeTypeVOS = employeeTypeService.employeeList();
        LambdaQueryWrapper<FtbPersonnelsRegistrationFormFieldOption> query = new LambdaQueryWrapper<>();
        query.eq(FtbPersonnelsRegistrationFormFieldOption::getFormFieldId, "workerType");
        query.orderByAsc(SuperBaseEntity.SuperCBaseEntity::getCreatorTime);
        List<FtbPersonnelsRegistrationFormFieldOption> ftbPersonnelsRegistrationFormFieldOptions = formFieldOptionMapper.selectList(query);
        if (StringUtils.isNotEmpty(dto.getWorkerType()) &&  CollUtil.isNotEmpty(employeeTypeVOS)){
            dto.setWorkerType(ftbPersonnelsRegistrationFormFieldOptions.stream().filter(item1 -> item1.getId().equals(dto.getWorkerType())).findFirst().get().getName());
        }
        return dto;
    }

    @Override
    @GlobalTransactional
    public void onboardingApprovals(FtbPersonnelsAuditDto personalsSalaryAuditDto) {
        String taskId = personalsSalaryAuditDto.getTaskId();
        LambdaQueryWrapper<FtbPersonnelsStaffEmploymentApply> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(FtbPersonnelsStaffEmploymentApply::getTaskInfoId, taskId);
        Long aLong = applyMapper.selectCount(wrapper);
        if (aLong == 0L || aLong > 1) {
            throw new RuntimeException("审批失败，审批任务不存在!");
        }
        FtbPersonnelsStaffEmploymentApply employmentApply = applyMapper.selectOne(wrapper);
        FtbPersonnelsStaffEmploymentApply updateApply = new FtbPersonnelsStaffEmploymentApply();
        updateApply.setId(employmentApply.getId());
        FtbPersonnelsAuditTaskEnum em = personalsSalaryAuditDto.getFlag().equals("1") ? FtbPersonnelsAuditTaskEnum.EXAMINATION_PASSED :
                FtbPersonnelsAuditTaskEnum.AUDIT_NOT_PASSED;
        updateApply.setCheckStatus(em.getCode());
        // 兼容之前的入职数据
        if (StringUtils.isEmpty(employmentApply.getUserId())){
            String userHeadLog =  generaDefaultUserHeadLog(employmentApply.getWorkerName());
            String userId = saveUserInfo(employmentApply, userHeadLog);
            updateApply.setUserId(userId);
        }
        FtbPersonnelsStaffRoster personnelsStaffRoster = null;
        if (personalsSalaryAuditDto.getFlag().equals("1")) {
            updateApply.setPhone(employmentApply.getPhone());
            updateApply.setActualStartDate(employmentApply.getActualStartDate());
            personnelsStaffRoster = buildApplyData(updateApply);
        }
        applyMapper.updateById(updateApply);
        if (!Objects.equals(em.getCode(), FtbPersonnelsAuditTaskEnum.EXAMINATION_PASSED.getCode())) return;
        // 审批通过后，生成员工rost
        // 数据入花名册
        FtbPersonnelsStaffEmploymentApply staffEmploymentApply = applyMapper.selectById(employmentApply.getId());
        FtbPersonnelsStaffRoster staffRoster = covertRosterWithOA(staffEmploymentApply,personnelsStaffRoster);
        if (personnelsStaffRoster != null && personnelsStaffRoster.getId() != null){
            staffRoster.setId(personnelsStaffRoster.getId());
            rosterService.updateById(staffRoster);
        }else {
            rosterService.save(staffRoster);
        }
        if (!personalsSalaryAuditDto.getFlag().equals("1")) return;
        // 数据入转正管理
        syncRegular(staffRoster,
                staffEmploymentApply.getProbationPeriod(),
                staffEmploymentApply.getProbationPeriodDay(),
                staffEmploymentApply.getAffiliatedReportsTo(),
                employmentApply.getPlanProbationaryDate());
        // 回填扩展数据
        dataSaveWithOAApprovals(staffRoster,employmentApply.getActualStartDate());
        //已经填写了入职登记表，那么就要把之前入职登记表中的数据加上花名册ID
        registrationFormDataService.addRosterIdToFormData(staffRoster.getPhone(), staffRoster.getId());
        // 写入职信息
        //写入入职薪酬
        writeEntryPay(staffRoster);
        //员工成长
        employeeGrowth(staffRoster,
                staffEmploymentApply.getAffiliatedReportsTo(),staffEmploymentApply.getActualStartDate());
        // 更改员工状态
        synchronizeEmployeeStatus(staffRoster, staffEmploymentApply.getAffiliatedReportsTo());
        // 变更内推池状态
        personnelOrgUtils.sysWorkerStatusToUchisuike(staffRoster.getPhone(), staffRoster.getWorkerStatus());
        // 同步薪酬
        syncSalaryData(employmentApply);
    }

    /**
     * 入职的薪酬
     * @param staffRoster
     */
    private void writeEntryPay(FtbPersonnelsStaffRoster staffRoster) {
        AddSalaryChangeLogDto addSalaryChangeLogDto = new AddSalaryChangeLogDto();
        addSalaryChangeLogDto.setUserId(staffRoster.getUserId());
        addSalaryChangeLogDto.setChangeDate(new Date());
        addSalaryChangeLogDto.setSalary(staffRoster.getCurrSalary());
        if (staffRoster.getJoinNum() > 1) {
            addSalaryChangeLogDto.setChangeType(SalaryChangeTypeEnum.REPEAT_JOIN.getCode());
        } else {
            addSalaryChangeLogDto.setChangeType(SalaryChangeTypeEnum.FIRST_JOIN.getCode());
        }
        salaryChangeLogService.addSalaryChangeLog(addSalaryChangeLogDto);
    }

    @Override
    @GlobalTransactional
    public void onboardingWithdrawal(FtbPersonnelsAuditDto personnelsAuditDto) {
        String taskId = personnelsAuditDto.getTaskId();
        LambdaQueryWrapper<FtbPersonnelsStaffEmploymentApply> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(FtbPersonnelsStaffEmploymentApply::getTaskInfoId, taskId);
        FtbPersonnelsStaffEmploymentApply employmentApply = applyMapper.selectOne(wrapper);
        if (null == employmentApply) {
            throw new RuntimeException("撤销失败，审批任务不存在!");
        }
        FtbPersonnelsStaffEmploymentApply updateApply = new FtbPersonnelsStaffEmploymentApply();
        updateApply.setId(employmentApply.getId());
        updateApply.setCheckStatus(FtbPersonnelsAuditTaskEnum.CANCEL.getCode());
        applyMapper.updateById(updateApply);
    }

    @Override
    public FtbEmpAddNewVO queryNewEmp(String id) {
        FtbPersonnelsStaffEmploymentApply apply = applyMapper.selectById(id);
        FtbEmpAddNewVO ftbEmpAddNewVO = FtbEmpAddNewVO.covert(apply);
        List<FtbPersonnelsStaffRegistrationFormData> fieldValueListWithPhone = registrationFormDataService.queryFormFieldValueList(ftbEmpAddNewVO.getPhone(), null);
        Map<String, OrganizeGeneralDetailVO> detailVOMap = new HashMap<>();
        if (StringUtils.isNotEmpty(ftbEmpAddNewVO.getCurrOrgId())){
            ActionResult<List<OrganizeGeneralDetailVO>> listActionResult = v2OrganizeApi.organizesByOrganizeIds(List.of());
            if (listActionResult != null && listActionResult.getCode() == 200){
                List<OrganizeGeneralDetailVO> list = listActionResult.getData();
                detailVOMap = list.stream().collect(Collectors.toMap(OrganizeGeneralDetailVO::getId, item -> item, (v1, v2) -> v1));
            }
        }
        Map<String, PositionBaseInfoVO> positionBaseInfoVOMap = new HashMap<>();
        if (StringUtils.isNotEmpty(ftbEmpAddNewVO.getCurrPositionId())){
            ActionResult<List<PositionBaseInfoVO>> actionResult = v2PositionApi.listPositionBaseInfoByIds(List.of(ftbEmpAddNewVO.getCurrPositionId()), null);
            if (actionResult != null && actionResult.getCode() == 200){
                List<PositionBaseInfoVO> list = actionResult.getData();
                positionBaseInfoVOMap = list.stream().collect(Collectors.toMap(PositionBaseInfoVO::getId, item -> item, (v1, v2) -> v1));
            }
        }
        Map<String, GradeVO> gradeVOMap = new HashMap<>();
        if (StringUtils.isNotEmpty(ftbEmpAddNewVO.getCurrRankId())) {
            ActionResult<List<GradeVO>> gradeActionResult = v2GradesApi.listGradeByIds(List.of(ftbEmpAddNewVO.getCurrRankId()), null);
            if (gradeActionResult != null && gradeActionResult.getCode() == 200) {
                List<GradeVO> list = gradeActionResult.getData();
                gradeVOMap = list.stream().collect(Collectors.toMap(GradeVO::getId, item -> item, (v1, v2) -> v1));
            }
        }
        if (StringUtils.isNotEmpty(ftbEmpAddNewVO.getCurrGroupId()) ) {
            ActionResult<List<OrganizeGeneralDetailVO>> currShopIdsList = v2OrganizeApi.organizesByOrganizeIds(List.of(ftbEmpAddNewVO.getCurrGroupId()));
            if (currShopIdsList != null && currShopIdsList.getCode() == 200) {
                List<OrganizeGeneralDetailVO> list = currShopIdsList.getData();
                detailVOMap.putAll(list.stream().collect(Collectors.toMap(OrganizeGeneralDetailVO::getId, item -> item, (v1, v2) -> v1)));
            }
        }
        // 组织替换
        if (detailVOMap.containsKey(ftbEmpAddNewVO.getCurrOrgId())) ftbEmpAddNewVO.setCurrOrgName(detailVOMap.get(ftbEmpAddNewVO.getCurrOrgId()).getName());
        // 岗位替换
        if (positionBaseInfoVOMap.containsKey(ftbEmpAddNewVO.getCurrPositionId())) ftbEmpAddNewVO.setCurrPositionName(positionBaseInfoVOMap.get(ftbEmpAddNewVO.getCurrPositionId()).getFullName());
        // 职级替换
        if (gradeVOMap.containsKey(ftbEmpAddNewVO.getCurrRankId())) ftbEmpAddNewVO.setCurrRankName(gradeVOMap.get(ftbEmpAddNewVO.getCurrRankId()).getName());
        // 班组替换
        if (detailVOMap.containsKey(ftbEmpAddNewVO.getCurrGroupId())) ftbEmpAddNewVO.setCurrGroupName(detailVOMap.get(ftbEmpAddNewVO.getCurrGroupId()).getName());
        if ( !CollUtil.isEmpty(fieldValueListWithPhone) ){
            FtbPersonnelsStaffRegistrationFormData formData = fieldValueListWithPhone.stream().filter(v -> "idCardNum".equals(v.getFormFieldId())).findFirst().orElse(null);
            ftbEmpAddNewVO.setIdCard(formData != null ? formData.getValue() :null);
        }
        return ftbEmpAddNewVO;
    }

    @Override
    public List<WorkerGroupDataDto> queryCrewsWithEntry(RequestForOA request) {
        LambdaQueryWrapper<FtbPersonnelsStaffEmploymentApply> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsStaffEmploymentApply::getId,request.getPrimaryKeyId());
        queryWrapper.eq(FtbPersonnelsStaffEmploymentApply::getCurrOrg,request.getAffiliatedOrg());
        List<FtbPersonnelsStaffEmploymentApply> apply = applyMapper.selectList(queryWrapper);
        List<WorkerGroupDataDto> collected = apply.stream().filter(v -> StringUtils.isNotEmpty(v.getCurrGroupId())).map(v -> {
            WorkerGroupDataDto dataDto = new WorkerGroupDataDto();
            dataDto.setStoreTeamId(v.getCurrGroupId());
            ActionResult<OrganizeGeneralDetailVO> result = v2OrganizeApi.organizeInfoById(OrganizeCategoryEnums.TEAM, v.getCurrGroupId());
            if (result != null && result.getData() != null) dataDto.setStoreTeamName(result.getData().getName());
            return dataDto;
        }).collect(Collectors.toList());
        return collected;
    }

    @Override
    public List<FtbEmpEntryVO> onboardingList(String phone) {
        List<String> userIds = null;
        if (!UserProvider.getUser().getIsAdministrator()) {
            userIds = permissionsUtils.obtainPersonnelUserIdDataPermissions(UserProvider.getUser().getUserId(), PermissionsEnums.PERSONNEL_MANAGEMENT_WEB.getValue(), "web");
            if (userIds != null && userIds.isEmpty()) return new ArrayList<>();
        }
        return applyMapper.onboardingListOA(phone,userIds);
    }

    @Override
    public void updatePhoneByUserId(String userId, String phone) {
        // 更新
        LambdaUpdateWrapper<FtbPersonnelsStaffEmploymentApply> queryWrapper = Wrappers.lambdaUpdate();
        queryWrapper.set(FtbPersonnelsStaffEmploymentApply::getPhone,phone);
        queryWrapper.eq(FtbPersonnelsStaffEmploymentApply::getUserId,userId);
        applyMapper.update(new FtbPersonnelsStaffEmploymentApply(),queryWrapper);
    }

    @Override
    public List<FtbPersonnelsStaffRosterDto> searchPhoneName(FtbEmpQueryDTO keyword) {
        List<FtbPersonnelsStaffRosterDto> ftbEmpEntryVOS = applyMapper.searchPhoneName(keyword);
        List<String> userIds = ftbEmpEntryVOS.stream().map(FtbPersonnelsStaffRosterDto::getUserId).collect(Collectors.toList());
        ActionResult<List<UserBoundVO>> infoBatch = v2UserApi.getAllUserInfoBatch(userIds, UserProvider.getUser().getTenantId());
        Map<String, UserBoundVO> userBoundVOMap = new HashMap<>();
        if (infoBatch != null && infoBatch.getCode() == 200) {
            userBoundVOMap = infoBatch.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, item -> item, (v1, v2) -> v1));
        }
        Map<String, UserBoundVO> finalUserBoundVOMap = userBoundVOMap;
        ftbEmpEntryVOS.stream().forEach(item -> {
            if (finalUserBoundVOMap.containsKey(item.getUserId())) {
                UserBoundVO userBoundVO = finalUserBoundVOMap.get(item.getUserId());
                item.setCurrOrg(userBoundVO.getOrganizeId());
                item.setCurrOrgName(userBoundVO.getOrganizeName());
                item.setCurrPosition(userBoundVO.getPositionId());
                item.setCurrPositionName(userBoundVO.getPositionName());
                item.setCurrRank(userBoundVO.getGradeId());
                item.setCurrRankName(userBoundVO.getGradeName());
            }
        });
        return ftbEmpEntryVOS;
    }

    @Override
    public void onboardingListExport(FtbEmpEntryDTO req, HttpServletResponse response) throws IOException {
        req.setPageSize(-1);
        PageListVO<FtbEmpEntryVO> pageVo = pageLists(req, "web");
        List<FtbEmpEntryVO> list = pageVo.getList();
        list.forEach(item->{
            if(item.getIsSubmitForm()  == 1) {
                item.setIsSubmitFormName("已提交");
            } else {
                item.setIsSubmitFormName("未提交");
            }
        });
        // 封装数据
        List<String> phones = list.stream().map(FtbEmpEntryVO::getPhone).collect(Collectors.toList());
        Map<String, List<FtbPersonnelsStaffRegistrationFormData>> listWithPhone = registrationFormDataService.queryFormFieldValueListWithPhone(phones);
        List<ExportRosterOneVo> rosterDataList = list.stream().map(v -> {
            FtbPersonnelsStaffRoster staffRoster = new FtbPersonnelsStaffRoster();
            staffRoster.setUserId(v.getUserId());
            staffRoster.setName(v.getWorkerName());
            if ( (v.getCheckStatus() != null && v.getIsNeedCheck() != null)  && ( v.getCheckStatus() == 2 || v.getIsNeedCheck() == 1)){
                staffRoster.setActualStartDate(v.getActualStartDateDate());
            }
            String phone = v.getPhone();
            List<FtbPersonnelsStaffRegistrationFormData> formData = listWithPhone.get(phone);
            if (formData != null) {
                formData.forEach(item -> {
                    if ("actualStartDate".equals(item.getFormFieldId())  &&
                            !( (v.getCheckStatus() != null && v.getIsNeedCheck() != null)
                            && ( v.getCheckStatus() == 2 || v.getIsNeedCheck() == 1)) ){
                        item.setValue("");
                    }
                });
            }
            return new ExportRosterOneVo(staffRoster, formData);
        }).collect(Collectors.toList());
        List<List<String>> excelHeaderList = ExcelHeaderUtil.getExcelHeaderList(FtbEmpEntryVO.class);
        List<List<Object>> lists = rosterExportUtils.extractAnnotatedFieldValues(list,FtbEmpEntryVO.class);
        FtbRosterImportTemplateBO templateBO = new FtbRosterImportTemplateBO();
        templateBO.setHeader(excelHeaderList);
        templateBO.setSheetName("Sheet1");
        templateBO.setData(lists);
        List<ExportFormTypeDto> onboarding = rosterExportUtils.getExportFormTypesWithOnboarding();
        //查询选项
        QueryWrapper<FtbPersonnelsRegistrationFormFieldOption> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(FtbPersonnelsRegistrationFormFieldOption::getEnabledMark, 0)
                .orderByAsc(FtbPersonnelsRegistrationFormFieldOption::getId);
        List<FtbPersonnelsRegistrationFormFieldOption> optionList = fieldOptionService.list(wrapper);
        List<FtbRosterImportTemplateBO> templateBOList = rosterExportUtils.convertToFtbRosterImportTemplateBO(onboarding, optionList, rosterDataList);
        templateBOList.add(templateBO);
        templateBOList.sort(Comparator.comparing(FtbRosterImportTemplateBO::getSheetName));
        EasyExcelUtils.dynamicHeaderGeneration(response, "入职办理列表", templateBOList);
    }

    @SneakyThrows
    private String generaDefaultUserHeadLog(String name) {
        String headLogo = DEFAULT_USER_LOGO;
        ActionResult headResult = pTenantAccountApi.generateDefaultAvatar(name);
        if (null != headResult) {
            headLogo = (String) headResult.getData();
        }
        return headLogo;
    }

    private  void transformData(FtbEmpEntryVO item) {
        Integer checkStatus = item.getCheckStatus();
        switch (checkStatus){
            case 0:
                item.setApprovalStatusName("未办理");
                break;
            case 1:
                item.setApprovalStatusName("审批中");
                break;
            case 2:
                item.setApprovalStatusName("审批通过");
                break;
            case 3:
                item.setApprovalStatusName("审批不通过");
                break;
            case 4:
                item.setApprovalStatusName("已撤销");
                break;
            case 5:
                item.setApprovalStatusName("入职失败");
                break;
            default:
                item.setApprovalStatusName("未知");
                break;
        }
    }

    private FtbPersonnelsStaffRoster covertRosterWithOA(FtbPersonnelsStaffEmploymentApply item, FtbPersonnelsStaffRoster personnelsStaffRoster) {
        if (item == null) {
            return null;
        }
        FtbPersonnelsStaffRoster ftbPersonnelsStaffRoster = new FtbPersonnelsStaffRoster();
        ftbPersonnelsStaffRoster.setPhone(item.getPhone());
        ftbPersonnelsStaffRoster.setName(item.getWorkerName());
        ftbPersonnelsStaffRoster.setUserId(item.getUserId());
        if (personnelsStaffRoster != null && personnelsStaffRoster.getSystemWokerId() != null) {
            ftbPersonnelsStaffRoster.setSystemWokerId(personnelsStaffRoster.getSystemWokerId());
        }
        if (personnelsStaffRoster != null && personnelsStaffRoster.getJoinNum() != null) {
            ftbPersonnelsStaffRoster.setJoinNum(personnelsStaffRoster.getJoinNum());
        }
        ftbPersonnelsStaffRoster.setCurrOrg(item.getCurrOrg());
        ftbPersonnelsStaffRoster.setCurrPosition(item.getCurrPosition());
        ftbPersonnelsStaffRoster.setCurrRank(item.getCurrRank());
        ftbPersonnelsStaffRoster.setCurrGroupId(item.getCurrGroupId());
        ftbPersonnelsStaffRoster.setCurrReportsTo(item.getAffiliatedReportsTo());
        ftbPersonnelsStaffRoster.setContractType(item.getContractType());
        ftbPersonnelsStaffRoster.setIsSubmitForm(item.getIsSubmitForm());
        ftbPersonnelsStaffRoster.setEnabledMark(item.getEnabledMark());
        ftbPersonnelsStaffRoster.setVersionNum(item.getVersionNum());
        ftbPersonnelsStaffRoster.setRegisterImg(item.getRegisterImg());
        ftbPersonnelsStaffRoster.setContractStatus(FContractSignStatus.NOT_INITIATED.getCode());
        ftbPersonnelsStaffRoster.setContractTypeName("");
        ftbPersonnelsStaffRoster.setContractType("");
        ftbPersonnelsStaffRoster.setIsTrialFail(0);
        ftbPersonnelsStaffRoster.setTrialFail("");
        ftbPersonnelsStaffRoster.setIsSignSeparation(0);
        ftbPersonnelsStaffRoster.setEntrySalary(item.getEntryMoney());
        if (StringUtils.isNotEmpty(item.getProbationPeriod()) && item.getProbationPeriod().equals("100")) {
            ftbPersonnelsStaffRoster.setRegularSalary(ftbPersonnelsStaffRoster.getEntrySalary());
            ftbPersonnelsStaffRoster.setActualProbationaryDate(ftbPersonnelsStaffRoster.getActualStartDate());
        }
        ftbPersonnelsStaffRoster.setWorkerType(item.getWorkerType());
        ftbPersonnelsStaffRoster.setWorkerStatus(item.getWorkerStatus());
        ftbPersonnelsStaffRoster.setActualStartDate(item.getActualStartDate());
        ftbPersonnelsStaffRoster.setCreatorTime(new Date());
        return ftbPersonnelsStaffRoster;
    }

    private FtbPersonnelsStaffRoster covertRoster(FtbPersonnelsStaffEmploymentApply item, FtbEmpConfirmDTO ftbEmpConfirmDTO, String systemWokerId, Integer joinNum) {
        if (item == null) {
            return null;
        }
        FtbPersonnelsStaffRoster ftbPersonnelsStaffRoster = new FtbPersonnelsStaffRoster();
        ftbPersonnelsStaffRoster.setPhone(item.getPhone());
        ftbPersonnelsStaffRoster.setName(item.getWorkerName());
        ftbPersonnelsStaffRoster.setUserId(item.getUserId());
        ftbPersonnelsStaffRoster.setSystemWokerId(systemWokerId);
        ftbPersonnelsStaffRoster.setCurrOrg(ftbEmpConfirmDTO.getCurrOrgId());
        ftbPersonnelsStaffRoster.setCurrPosition(ftbEmpConfirmDTO.getCurrPositionId());
        ftbPersonnelsStaffRoster.setCurrRank(ftbEmpConfirmDTO.getCurrRankId());
        ftbPersonnelsStaffRoster.setCurrGroupId(ftbEmpConfirmDTO.getCurrShopId());
        ftbPersonnelsStaffRoster.setCurrReportsTo(ftbEmpConfirmDTO.getAffiliatedReportsTo());
        ftbPersonnelsStaffRoster.setContractType(item.getContractType());
        ftbPersonnelsStaffRoster.setIsSubmitForm(item.getIsSubmitForm());
        ftbPersonnelsStaffRoster.setJoinNum(joinNum);
        ftbPersonnelsStaffRoster.setEnabledMark(item.getEnabledMark());
        ftbPersonnelsStaffRoster.setVersionNum(item.getVersionNum());
        ftbPersonnelsStaffRoster.setRegisterImg(item.getRegisterImg());
        ftbPersonnelsStaffRoster.setTenantId(item.getTenantId());
        ftbPersonnelsStaffRoster.setContractStatus(FContractSignStatus.NOT_INITIATED.getCode());
        ftbPersonnelsStaffRoster.setContractTypeName("");
        ftbPersonnelsStaffRoster.setContractType("");
        ftbPersonnelsStaffRoster.setIsTrialFail(0);
        ftbPersonnelsStaffRoster.setTrialFail("");
        ftbPersonnelsStaffRoster.setIsSignSeparation(0);
        ftbPersonnelsStaffRoster.setEntrySalary(ftbEmpConfirmDTO.getEntryMoney());
        if (StringUtils.isNotEmpty(ftbEmpConfirmDTO.getProbationPeriod()) && ftbEmpConfirmDTO.getProbationPeriod().equals("100")) {
            ftbPersonnelsStaffRoster.setRegularSalary(ftbPersonnelsStaffRoster.getEntrySalary());
            ftbPersonnelsStaffRoster.setActualProbationaryDate(ftbPersonnelsStaffRoster.getActualStartDate());
        }
        ftbPersonnelsStaffRoster.setWorkerType(ftbEmpConfirmDTO.getWorkerType());
        ftbPersonnelsStaffRoster.setWorkerStatus(ftbEmpConfirmDTO.getWorkerStatus());
        ftbPersonnelsStaffRoster.setActualStartDate(ftbEmpConfirmDTO.getActualStartDate());
        ftbPersonnelsStaffRoster.setCreatorTime(new Date());
        return ftbPersonnelsStaffRoster;
    }



    public void dataSave(FtbPersonnelsStaffRoster entity, FtbEmpConfirmDTO req){
        Map<String, Object> formDataMap = BeanUtil.beanToMap(req);
        Map<String, Object> formDataMapEntity = BeanUtil.beanToMap(entity);
        formDataMap.putAll(formDataMapEntity);
        formDataMap.put("planProbationaryDate",personnelOrgUtils.dateToString(req.getPlanProbationaryDate(), ""));
        formDataMap.put("actualStartDate", personnelOrgUtils.dateToString(req.getActualStartDate(), ""));
        ProbationPeriodDto probationPeriodDto = new ProbationPeriodDto(req.getProbationPeriod(), req.getProbationPeriodDay());
        formDataMap.put("probationPeriod", JSONUtil.toJsonStr(probationPeriodDto));
        formDataMap.put("workerName", entity.getName());
        Date now = new Date();
        if (now.after(req.getActualStartDate())) {
            long betweenDay = DateUtil.betweenDay(req.getActualStartDate(), now, false);
            formDataMap.put("companyAge", String.valueOf(betweenDay));
        } else {
            formDataMap.put("companyAge", "0");
        }
        if (entity.getWorkerStatus().equals("303")) {
            formDataMap.put("actualProbationaryDate", personnelOrgUtils.dateToString(entity.getActualStartDate(), ""));
        }
        //清楚合同信息
        formDataMap.put("contractStatus", "500");
        formDataMap.put("contractCompany", "");
        formDataMap.put("contractEffectiveDate", "");
        formDataMap.put("contractName", "");
        formDataMap.put("contractType", "");
        formDataMap.put("contractFile", "");
        formDataMap.put("contractDate", "");
        formDataMap.put("contractDetail", "");
        formDataMap.put("contractTaskId", "");
        registrationFormDataService.syncData(formDataMap, entity.getPhone(), entity.getId());
    }
    private void addRunBirthday(Map<String, Object> formDataMap) {
        // 身份证号码识别出生日期
        if (Objects.nonNull(formDataMap.get("idCardNum")) && StringUtils.isNotEmpty(formDataMap.get("idCardNum").toString())) {
            Date birthday = IdcardUtil.getBirthDate(formDataMap.get("idCardNum").toString()).toJdkDate();
            formDataMap.put("birthday", DateUtil.format(birthday, "yyyy-MM-dd"));
        }
        String birthday = (String) formDataMap.get("birthday");
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(birthday)) {
            Date birth = personnelOrgUtils.stringDateToDate(birthday);
            int age = personnelOrgUtils.calculateAge(personnelOrgUtils.dateToLocalDate(birth));
            String currAge = age + "岁";
            formDataMap.put("age", currAge);
        }
    }

    public void dataSaveWithOA(FtbEmpConfirmDTO req){
        Map<String, Object> formDataMap = BeanUtil.beanToMap(req);
        formDataMap.put("planProbationaryDate",personnelOrgUtils.dateToString(req.getPlanProbationaryDate(), ""));
        formDataMap.put("actualStartDate", personnelOrgUtils.dateToString(req.getActualStartDate(), ""));
        ProbationPeriodDto probationPeriodDto = new ProbationPeriodDto(req.getProbationPeriod(), req.getProbationPeriodDay());
        formDataMap.put("probationPeriod", JSONUtil.toJsonStr(probationPeriodDto));
        formDataMap.put("workerName", req.getName());
        Date now = new Date();
        if (now.after(req.getActualStartDate())) {
            long betweenDay = DateUtil.betweenDay(req.getActualStartDate(), now, false);
            formDataMap.put("companyAge", String.valueOf(betweenDay));
        } else {
            formDataMap.put("companyAge", "0");
        }
        //清楚合同信息
        formDataMap.put("contractStatus", "500");
        formDataMap.put("contractCompany", "");
        formDataMap.put("contractEffectiveDate", "");
        formDataMap.put("contractName", "");
        formDataMap.put("contractType", "");
        formDataMap.put("contractFile", "");
        formDataMap.put("contractDate", "");
        formDataMap.put("contractDetail", "");
        formDataMap.put("contractTaskId", "");
        registrationFormDataService.syncData(formDataMap, req.getPhone(), "");
    }
    public void dataSaveWithOAApprovals(FtbPersonnelsStaffRoster entity, Date actualStartDate){
        Map<String, Object> formDataMap = BeanUtil.beanToMap(entity);
        formDataMap.put("actualStartDate", personnelOrgUtils.dateToString(entity.getActualStartDate(), ""));
        Date now = new Date();
        if (now.after(actualStartDate)) {
            long betweenDay = DateUtil.betweenDay(actualStartDate, now, false);
            formDataMap.put("companyAge", String.valueOf(betweenDay));
        } else {
            formDataMap.put("companyAge", "0");
        }
        if (null != entity.getActualProbationaryDate()) {
            formDataMap.put("actualProbationaryDate", personnelOrgUtils.dateToString(entity.getActualProbationaryDate(), ""));
        }
        registrationFormDataService.syncData(formDataMap, entity.getPhone(), entity.getId());
    }
    private String buildGrowthLogDetail(String currOrg,
                                        String currPosition,
                                        String currRank,
                                        String currReportsTo,
                                        Date actualStartDate) {
        StaffBaseInfoDto dto = new StaffBaseInfoDto();
        dto.setCurrOrg(currOrg);
        ActionResult<OrganizeGeneralDetailVO> result = v2OrganizeApi.organizeInfoById(null, currOrg);
        if (result!= null && result.getCode() == 200) {
            dto.setCurrOrgName(result.getData().getName());
        }
        dto.setCurrPosition(currPosition);
        ActionResult<PositionVO> voActionResult = v2PositionApi.infoPosition(currPosition);
        if (voActionResult!= null && voActionResult.getCode() == 200) {
            dto.setCurrPositionName(voActionResult.getData().getFullName());
        }
        if (StringUtils.isNotEmpty(currRank)) {
            dto.setCurrRank(currRank);
            ActionResult<GradeVO> gradeVOActionResult = v2GradesApi.infoGrade(currRank);
            if (gradeVOActionResult!= null && gradeVOActionResult.getCode() == 200) {
                dto.setCurrRankName(gradeVOActionResult.getData().getName());
            }
        }
        if (StringUtils.isNotEmpty(currReportsTo)) {
            dto.setReportsTo(currReportsTo);
            UserEntity userEntity = personnelOrgUtils.queryUserInfo(currReportsTo);
            if (null != userEntity) {
                dto.setReportsToName(userEntity.getRealName());
            }
        }
        dto.setActualStartDate(actualStartDate);
        return JSONUtil.toJsonStr(dto);
    }
    /**
     * 同步转正管理
     *
     * @param entity
     * @param probationPeriod
     * @param probationPeriodDay
     * @param currReportsTo
     * @param planProbationaryDate
     */
    private void syncRegular(FtbPersonnelsStaffRoster entity,
                             String probationPeriod,
                             String probationPeriodDay,
                             String currReportsTo,
                             Date planProbationaryDate) {
        if (!(("302".equals(entity.getWorkerStatus()) || "306".equals(entity.getWorkerStatus())) && !probationPeriod.equals("100"))) return;
        FtbPersonnelsRegularCreateDTO createDTO = FtbPersonnelsRegularCreateDTO.coverFtbPersonnelsRegularInfoVO(entity);
        ActionResult<List<OrganizeGeneralDetailVO>> infoById = v2OrganizeApi.organizesByOrganizeIds(List.of(entity.getCurrOrg()));
        if (infoById.getCode() == 200) {
            createDTO.setOrgName(infoById.getData().stream().findFirst().get().getName());
        }
        UserBoundVO userEntity = StringUtils.isEmpty(currReportsTo) ? null :  getUserPrimaryBoundVO(v2UserApi.getUserPrimaryBoundBatch(List.of(currReportsTo), null)) ;
        if (userEntity != null) {
            createDTO.setImmediateSuperName(userEntity.getUserName());
            createDTO.setImmediateSuperId(currReportsTo);
        }
        ActionResult<PositionVO> voActionResult = v2PositionApi.infoPosition(createDTO.getRegularPostId());
        if (voActionResult!= null && voActionResult.getCode() == 200) {
            PositionVO positionVO = voActionResult.getData();
            createDTO.setRegularPostName(positionVO.getFullName());
            createDTO.setOnboardPostName(positionVO.getFullName());
        }
        ActionResult<GradeVO> gradeVOActionResult = v2GradesApi.infoGrade(createDTO.getRegularGradeId());
        if (gradeVOActionResult != null && gradeVOActionResult.getData() != null) {
            createDTO.setRegularGradeName(gradeVOActionResult.getData().getFullName());
            createDTO.setOnboardGradeName(gradeVOActionResult.getData().getFullName());
        }
        createDTO.setProbation(probationPeriod);
        createDTO.setProbationPeriodDay(probationPeriodDay);
        // 计划转正日期
        createDTO.setSchedConverDate(planProbationaryDate);
        createDTO.setId(entity.getId());
        regularManagementService.applyForRegularization(createDTO);
    }

    /**
     * 提取数据
     * @param listActionResult
     * @return
     */
    private UserBoundVO getUserPrimaryBoundVO(ActionResult<List<UserBoundVO>> listActionResult) {
        if (listActionResult.getCode() == 200 && listActionResult.getData() != null){
            return listActionResult.getData().get(0);
        }
        return null;
    }

    public void asyncDeleteHistory(List<String> userIds) {
        UserInfo userInfo = UserProvider.getUser();
        String tenantId = userInfo.getTenantId();
        String token = userInfo.getToken();
        if (org.apache.commons.lang3.StringUtils.isEmpty(token)) {
            token = "";
        }
        Map<String, String> headers = ImmutableMap.of(Constants.AUTHORIZATION.toLowerCase(), token);
        personnelAsyncServiceUtils.deleteTurnoverUserHistory(userIds, tenantId, headers);
    }


    public String  saveUserInfo(FtbPersonnelsStaffEmploymentApply apply, String userHeadLog,String... tenantIdS){
        // 生成账号建立关系信息
        SaveUserDTO saveUserDTO = new SaveUserDTO();
        saveUserDTO.setAccount(apply.getPhone());
        saveUserDTO.setRealName(apply.getWorkerName());
        saveUserDTO.setMobilePhone(apply.getPhone());
        saveUserDTO.setWorkerStatus(UserWorkStatusEnums.PRE_ONBOARDING.getCode());
        saveUserDTO.setAccount(apply.getPhone());
        saveUserDTO.setHeadIcon(userHeadLog);
        saveUserDTO.setEntryDate(apply.getActualStartDate());
        UserBoundInfoDTO userBoundInfoDTO = new UserBoundInfoDTO();
        userBoundInfoDTO.setOrganizeId(apply.getCurrOrg());
        userBoundInfoDTO.setPositionId(apply.getCurrPosition());
        userBoundInfoDTO.setGradesId(apply.getCurrRank());
        userBoundInfoDTO.setStoreTeamId(apply.getCurrGroupId());
        saveUserDTO.setBoundInfoDTO(userBoundInfoDTO);
        String tenantId = tenantIdS.length > 0 ? tenantIdS[0] : UserProvider.getUser().getTenantId();
        saveUserDTO.setTenantId(tenantId);
        //解决组织架构分布式事务 行锁问题 不多次调用 组织架构修改用户接口一次完成 提前生成ID 租户->用户
        //生成主账号
        String userId = FtbUtil.getId();
        //判断是否离职
        UserCopyEntity copyInfo = v2UserApi.getUserCopyInfo(saveUserDTO.getMobilePhone());
        if (copyInfo != null && StrUtil.isNotBlank(copyInfo.getId())){
            userId = copyInfo.getId();
        }
        UserAccountDto userAccountDto = new UserAccountDto();
        userAccountDto.setFid(userId);
        userAccountDto.setUserName(apply.getWorkerName());
        userAccountDto.setTenantId(tenantId);
        userAccountDto.setUserMobilePhone(apply.getPhone());
        userAccountDto.setHeadImageUrl(userHeadLog);
        List<UserAccountDto> addUserList = List.of(userAccountDto);
        ActionResult<List<UserAccountDto>> batchAddUserAccount = pTenantAccountApi.batchAddUserAccount(addUserList);
        if(batchAddUserAccount == null || !batchAddUserAccount.getCode().equals(200)){
           // pTenantAccountApi.deleteUser(userId);
            throw new RuntimeException("主账号生成失败");
        }
        UserAccountDto accountDto = batchAddUserAccount.getData().stream().findFirst().orElse(new UserAccountDto());
        saveUserDTO.setId(userId);
        saveUserDTO.setAccount(accountDto.getAccount());
        ActionResult<String> actionResult = v2UserApi.saveUserInfo(saveUserDTO);
        if (actionResult ==null || actionResult.getCode() != 200) {
          //  pTenantAccountApi.deleteUser(userId);
            throw new RuntimeException(actionResult !=null   ? actionResult.getMsg() : "保存用户信息失败！");
        }
        return userId;
    }
    /**
     * 同步薪酬数据
     * @param ftbEmpConfirmDTO
     */
    private void syncSalaryData(FtbPersonnelsStaffEmploymentApply ftbEmpConfirmDTO) {
        // 薪酬信息同步
        String userId = ftbEmpConfirmDTO.getUserId();
        String salaryData = ftbEmpConfirmDTO.getSalaryData();
        if (StringUtils.isEmpty(salaryData) || "null".equals(salaryData) || "[]".equals(salaryData)) return;
        if (ftbEmpConfirmDTO.getIsAdjustSalary() == 1 && StringUtils.isNotEmpty(salaryData)) {
            List<FtbPersonnelsSalaryInfo> salaryItemList = JsonUtil.getJsonToList(salaryData, FtbPersonnelsSalaryInfo.class);
            UserInfoWithSalary userInfoWithSalary = new UserInfoWithSalary();
            ActionResult<OrganizeGeneralDetailVO> actionResult = v2OrganizeApi.organizeInfoById(null, ftbEmpConfirmDTO.getCurrOrg());
            userInfoWithSalary.setFOrgId(ftbEmpConfirmDTO.getCurrOrg());
            if (actionResult != null && actionResult.getCode() == 200) {
                userInfoWithSalary.setFOrgName(actionResult.getData().getName());
            }
            ActionResult<PositionVO> infoPosition = v2PositionApi.infoPosition(ftbEmpConfirmDTO.getCurrPosition());
            userInfoWithSalary.setPostId(ftbEmpConfirmDTO.getCurrPosition());
            if (infoPosition != null && infoPosition.getCode() == 200) {
                userInfoWithSalary.setPostName(infoPosition.getData().getFullName());
            }
            if (StringUtils.isNotEmpty(ftbEmpConfirmDTO.getCurrRank())) {
                ActionResult<GradeVO> gradeVOActionResult = v2GradesApi.infoGrade(ftbEmpConfirmDTO.getCurrRank());
                userInfoWithSalary.setRankId(ftbEmpConfirmDTO.getCurrRank());
                if (gradeVOActionResult != null && gradeVOActionResult.getCode() == 200) {
                    userInfoWithSalary.setRankName(gradeVOActionResult.getData().getFullName());
                }
            }
            String creatorUserId = ftbEmpConfirmDTO.getCreatorUserId();
            LambdaQueryWrapper<FtbPersonnelsStaffRoster> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(FtbPersonnelsStaffRoster::getUserId, creatorUserId);
            FtbPersonnelsStaffRoster serviceOne = rosterService.getOne(queryWrapper);
            if (serviceOne != null)  userInfoWithSalary.setOperatorWorkNo(serviceOne.getSystemWokerId());
            userInfoWithSalary.setTaskId(ftbEmpConfirmDTO.getTaskInfoId());
            // 入职时间
            userInfoWithSalary.setEntryDate(ftbEmpConfirmDTO.getActualStartDate());
            // 工作状态是正式 入职时间 作为转正时间
            if ("303".equals(ftbEmpConfirmDTO.getWorkerStatus())) userInfoWithSalary.setBeComeDate(ftbEmpConfirmDTO.getActualStartDate());
            userInfoWithSalary.setUserTypeId(ftbEmpConfirmDTO.getWorkerType());
            //生效日期取,实际 入职日期
            personnelSalaryService.saveTheChangePayInformation(
                    salaryItemList,
                    userId,
                    ftbEmpConfirmDTO.getActualStartDate(),
                    userInfoWithSalary,
                    "2",//和薪酬沟通传入固定值2
                    ftbEmpConfirmDTO.getReasonsForSalaryAdjustments(),
                    "4", 0,null,ftbEmpConfirmDTO.getPayrollSequenceId());
        }
    }

    /**
     * 同步员工状态
     *
     * @param staffRoster
     * @param
     */
    private void synchronizeEmployeeStatus(FtbPersonnelsStaffRoster staffRoster, String leaderId) {
        if (ObjectUtil.isEmpty(staffRoster)) return;
        String userId = staffRoster.getUserId();
        UpdateUserDTO userDTO = new UpdateUserDTO();
        userDTO.setEntryDate(staffRoster.getActualStartDate());
        userDTO.setWorkerStatus(staffRoster.getWorkerStatus());
        userDTO.setSystemWorkerId(staffRoster.getSystemWokerId());
        UserBoundInfoDTO boundInfoDTO = new UserBoundInfoDTO();
        boundInfoDTO.setOrganizeId(staffRoster.getCurrOrg());
        boundInfoDTO.setPositionId(staffRoster.getCurrPosition());
        boundInfoDTO.setGradesId(staffRoster.getCurrRank());
        boundInfoDTO.setStoreTeamId(staffRoster.getCurrGroupId());
        boundInfoDTO.setLeaderId(leaderId);
        userDTO.setBoundInfoDTO(boundInfoDTO);
        System.out.print(JSONObject.toJSONString(userDTO));
        ActionResult<Boolean> actionResult = v2UserApi.updateUserInfo(userId, userDTO);
        if (actionResult == null || !actionResult.getCode().equals(200)) {
            throw new RuntimeException("更新用户信息失败");
        }
        Arrays.stream(JobStatusEnum.values()).filter(item -> item.getName().equals(staffRoster.getWorkerType())).findFirst().ifPresent(statusEnum ->{
            ActionResult<Boolean> actionResult1 = v2UserApi.updateUserJobStatus(statusEnum, userId);
            if (actionResult1 == null || !actionResult1.getCode().equals(200)) {
                throw new RuntimeException("更新用户状态失败");
            }
        });
        attendanceMessageNotifications(staffRoster.getActualStartDate(), staffRoster.getCurrOrg(), userId);
    }

    /**
     * 考勤消息通知
     * @param entryDate
     * @param organizeId
     * @param userId
     */
    private void attendanceMessageNotifications(Date entryDate,String organizeId,String userId) {
        // 考勤消息通知
        Map<String, Object> hashMap = new HashMap<>();
        hashMap.put("userId", userId);
        hashMap.put("entryDate", entryDate);
        hashMap.put("organizeId", organizeId);
        hashMap.put("tenantId", UserProvider.getUser().getTenantId());
        secondmentConsumerSourceMsg.sendMessageOnboarding(JSONObject.toJSONString(hashMap));
    }

    /**
     * 员工成长
     * @param staffRoster
     * @param affiliatedReportsTo 直属主管
     * @param actualStartDate 入职时间
     */
    private void employeeGrowth(FtbPersonnelsStaffRoster staffRoster,
                                String affiliatedReportsTo,
                                Date actualStartDate) {
        AddGrowthLogDto addGrowthLogDto = new AddGrowthLogDto();
        addGrowthLogDto.setUserId(staffRoster.getUserId());
        addGrowthLogDto.setChangeDate(new Date());
        if (staffRoster.getJoinNum() > 1) {
            addGrowthLogDto.setGrowthType(GrowthLogEnum.REPEAT_JOIN.getCode());
            addGrowthLogDto.setNum(staffRoster.getJoinNum());
        } else {
            addGrowthLogDto.setGrowthType(GrowthLogEnum.FIRST_JOIN.getCode());
        }
        String currRank = staffRoster.getCurrRank();
        String currPosition = staffRoster.getCurrPosition();
        String currOrg = staffRoster.getCurrOrg();

        addGrowthLogDto.setDetail(buildGrowthLogDetail(currOrg, currPosition, currRank,
                affiliatedReportsTo,
                actualStartDate));
        addGrowthLogDto.setEmployeeId(staffRoster.getSystemWokerId());
        addGrowthLogDto.setActualStartDate(actualStartDate);
        // famgch
        LambdaQueryWrapper<FtbPersonnelsStaffGrowthLog> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbPersonnelsStaffGrowthLog::getUserId, staffRoster.getUserId());
        queryWrapper.eq(FtbPersonnelsStaffGrowthLog::getActualStartDate, staffRoster.getActualStartDate());
        queryWrapper.eq(FtbPersonnelsStaffGrowthLog::getGrowthType, 0);
        FtbPersonnelsStaffGrowthLog one = growthLogService.getOne(queryWrapper);
        if (one != null) {
            // 删除已有的
            growthLogService.remove(queryWrapper);
        }
        // 入职的
        growthLogService.addGrowthLog(addGrowthLogDto);
        // 删除历史记录
        asyncDeleteHistory(List.of(staffRoster.getUserId()));
    }

    /**
     * 所属组织-岗位-职等校验
     */
    public void doCheckOrgPositionGradesBoundDTO(QueryUserBoundDTO dto) {
        String positionId = dto.getPositionId();
        QueryGradeListDTO listDTO = new QueryGradeListDTO();
        listDTO.setPositionId(positionId);
        ActionResult<List<GradeVO>> listGrades = v2GradesApi.listGrades(listDTO);
        if (listGrades.getCode() == 200 && CollUtil.isNotEmpty(listGrades.getData())) {
            if (listGrades.getData().stream().noneMatch(v -> v.getId().equals(dto.getGradeId()))) {
                throw new RuntimeException("该员工入职的目标职级不存在，无法继续提交!");
            }
        }
    }
}
