package com.yeejoin.amos.boot.module.tcm.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
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.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Sets;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.entity.BaseEntity;
import com.yeejoin.amos.boot.biz.common.entity.DataDictionary;
import com.yeejoin.amos.boot.biz.common.excel.ExcelUtil;
import com.yeejoin.amos.boot.biz.common.service.impl.DataDictionaryServiceImpl;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.boot.biz.common.utils.SnowflakeIdUtil;
import com.yeejoin.amos.boot.module.common.api.dto.UserPermissionDto;
import com.yeejoin.amos.boot.module.tcm.api.dto.*;
import com.yeejoin.amos.boot.module.tcm.api.entity.*;
import com.yeejoin.amos.boot.module.tcm.api.enums.EquipmentClassifityEnum;
import com.yeejoin.amos.boot.module.tcm.api.enums.PersonManageRoleEnum;
import com.yeejoin.amos.boot.module.tcm.api.enums.TwoStipulateGroupEnum;
import com.yeejoin.amos.boot.module.tcm.api.enums.UnitTypeEnum;
import com.yeejoin.amos.boot.module.tcm.api.mapper.TzsBaseIndividualityMapper;
import com.yeejoin.amos.boot.module.tcm.api.mapper.TzsUserEquipMapper;
import com.yeejoin.amos.boot.module.tcm.api.mapper.TzsUserInfoMapper;
import com.yeejoin.amos.boot.module.tcm.api.service.ITzsUserInfoService;
import com.yeejoin.amos.boot.module.tcm.api.vo.SortVo;
import com.yeejoin.amos.boot.module.tcm.api.vo.TzsUserInfoVo;
import com.yeejoin.amos.boot.module.tcm.api.vo.UserInfoVo;
import com.yeejoin.amos.boot.module.tcm.flc.biz.service.impl.RegUnitInfoServiceImpl;
import com.yeejoin.amos.component.feign.config.InnerInvokException;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.component.feign.utils.FeignUtil;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.amos.feign.privilege.model.CompanyModel;
import com.yeejoin.amos.feign.privilege.model.GroupModel;
import com.yeejoin.amos.feign.privilege.model.RoleModel;
import com.yeejoin.amos.feign.privilege.util.DesUtil;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.typroject.tyboot.component.emq.EmqKeeper;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.rdbms.service.BaseService;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;
import org.typroject.tyboot.core.restful.utils.ResponseHelper;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class TzsUserInfoServiceImpl extends BaseService<TzsUserInfoDto, TzsUserInfo, TzsUserInfoMapper> implements ITzsUserInfoService {

    // 企业人员角色
    private final String USER_ROLE = "QYRYJS";
    // 企业人员用户组
    private final String ROLE_GROUP = "QYRYYHZ";
    // 两个规定用户组-对应企业人员的人员类型前缀
    private final String QYRYGW = "QYRYGW";
    // 两个规定用户组-对应企业人员的人员类型前缀
    private final String QYRYGW_NAME = "企业人员类型";
    // 平台用户锁定状态
    private final String UNLOCK = "UNLOCK";
    private final String LOCK = "LOCK";
    private final String TOTALTYPESTEMPLATE = "{\"records\":[{\"name\":\"人员总数（人）\",\"value\":%s}]}";
    @Autowired
    DataDictionaryServiceImpl iDataDictionaryService;
    @Autowired
    TzBaseEnterpriseInfoServiceImpl baseEnterpriseInfoService;
    @Autowired
    TzsBaseIndividualityServiceImpl individualityService;
    @Autowired
    TzsBaseIndividualityMapper individualityMapper;
    @Autowired
    private TzsUserInfoMapper tzsUserInfoMapper;
    @Autowired
    private TzsUserEquipMapper tzsUserEquipMapper;
    @Autowired
    private TzsUserEquipServiceImpl tzsUserEquipService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private TzsUserQualificationsServiceImpl tzsUserQualificationsService;
    @Autowired
    private TzsUserPermissionServiceImpl tzsUserPermissionServiceImpl;
    @Autowired
    private EmqKeeper emqKeeper;

    @Autowired
    private RegUnitInfoServiceImpl regUnitInfoService;

    private static Map<String, String> statusColorMap = new HashMap<>();

    static {
        statusColorMap.put("无资质要求", "#868686");
        statusColorMap.put("资质超期", "#FF0000");
        statusColorMap.put("资质临期", "#FC9700");
        statusColorMap.put("正常", "#18B100");
    }


    private static Map<String, List<String>> menuMap = new HashMap<>();

    static {
        // 业务办理人员管理
        menuMap.put("ywblry", Collections.singletonList("6616"));
        // 主要负责人管理
        menuMap.put("zyfzr", Collections.singletonList("6548"));
        // 作业人员管理
        menuMap.put("zyry", Collections.singletonList("6552"));
        // 检测人员管理
        menuMap.put("jcry", Collections.singletonList("66152"));
        // 安全总监管理
        menuMap.put("aqzj", Collections.singletonList("6547"));
        // 质量保证体系人员管理
        menuMap.put("zlbztxry", Collections.singletonList("6619"));
        // 质量安全员管理
        menuMap.put("zlaqy", Collections.singletonList("6551"));
        // 质量安全总监管理
        menuMap.put("zlaqzj", Collections.singletonList("6550"));
        // 安全员管理
        menuMap.put("aqy", Collections.singletonList("6549"));
        // 检验人员管理
        menuMap.put("jyry", Collections.singletonList("66151"));
        // 其他人员管理
        menuMap.put("qtry", Arrays.asList("6546", "6617", "6553"));
    }

    @Autowired
    private Validator validator;


    @Autowired
    SnowflakeIdUtil sequence;

    /**
     * 排序  ：页面列表排序功能支持，将 "字段,ascend" 或 "字段,descend" 转化为对应JSONObject
     *
     * @param sort "字段,ascend" 或 "字段,descend"
     * @return JSONObject
     */
    public SortVo sortFieldConversion(String sort) {
        Optional<String> optionalSort = Optional.ofNullable(sort);
        Optional<SortVo> optionalSortMap = optionalSort.filter(s -> !s.isEmpty())
                .map(s -> {
                    String[] sortParts = s.split(",");
                    if (sortParts.length == 2) {
                        String field = sortParts[0];
                        String sortSituation = sortParts[1].contains("asc") ? "ASC" : "DESC";
                        return SortVo.builder()
                                .field(convertToUnderline(field))
                                .sortType(sortSituation)
                                .build();
                    }
                    return null;
                });
        return optionalSortMap.orElse(null);
    }

    /**
     * 驼峰转下划线
     *
     * @param str
     * @return
     */
    public static String convertToUnderline(String str) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append("_").append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    @Override
    public Page<TzsUserInfoDto> page(TzsUserInfoDto dto, Page<TzsUserInfoDto> page, String sort) {
        SortVo sortMap = this.sortFieldConversion(sort);
        // dto.setMenuTypeUnderPost(menuMap.get(dto.getMenuType()));
        Page<TzsUserInfoDto> tzsUserInfoDtoPage = tzsUserInfoMapper.selectPageMessage(page, dto, sortMap);
        tzsUserInfoDtoPage.getRecords().forEach(item -> {
            if (!ObjectUtils.isEmpty(item.getProfile())) {
                List<CommonFile> commonFiles = JSON.parseArray(item.getProfile(), CommonFile.class);
                if (!ObjectUtils.isEmpty(commonFiles)) {
                    item.setProfile(commonFiles.get(0).getUrl());
                }
            }
            if (!ObjectUtils.isEmpty(item.getBirthday())) {
                int age = getAge(item.getBirthday());
                item.setAge(Math.max(age, 0));
            }
        });
        return tzsUserInfoDtoPage;
    }

    // 判断字符串是否为合法的 JSON 格式
    public boolean isJSONValid(String test) {
        try {
            JSON.parseArray(test);
            return true;
        } catch (Exception ex) {
            return false;
        }
    }

    public String setPostName(String postKey) {
        JSONArray dictIds = JSON.parseArray(postKey);
        if (dictIds == null || dictIds.isEmpty()) {
            return "";
        }
        LambdaQueryWrapper<DataDictionary> lambda = new QueryWrapper<DataDictionary>().lambda();
        lambda.in(DataDictionary::getSequenceNbr, dictIds);
        List<DataDictionary> dataDictionaries = iDataDictionaryService.getByTypeAndDesc(QYRYGW, QYRYGW_NAME);
        List<DataDictionary> postDataList = dataDictionaries.stream().filter(d -> dictIds.stream().anyMatch(id -> id.toString().equals(d.getCode()))).collect(Collectors.toList());
        return postDataList.stream().map(DataDictionary::getName).collect(Collectors.joining(","));
    }


    private int getAge(Date birth) {
        Calendar cal = Calendar.getInstance();
        int thisYear = cal.get(Calendar.YEAR);
        int thisMonth = cal.get(Calendar.MONTH);
        int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);

        cal.setTime(birth);
        int birthYear = cal.get(Calendar.YEAR);
        int birthMonth = cal.get(Calendar.MONTH);
        int birthdayOfMonth = cal.get(Calendar.DAY_OF_MONTH);

        int age = thisYear - birthYear;

        // 未足月
        if (thisMonth <= birthMonth) {
            // 当月
            if (thisMonth == birthMonth) {
                // 未足日
                if (dayOfMonth < birthdayOfMonth) {
                    age--;
                }
            } else {
                age--;
            }
        }
        return age;
    }

    @Override
    public void addQualificationsMessage(String userId, List<TzsUserQualifications> list) {
        list.forEach(item -> {
            item.setUserInfoId(userId);
        });
        tzsUserQualificationsService.saveOrUpdateBatch(list);
    }

    @Override
    public void updateQualificationsMessage(String userId, List<TzsUserQualifications> list) {
        LambdaQueryWrapper<TzsUserQualifications> lambda = new QueryWrapper<TzsUserQualifications>().lambda();
        lambda.eq(TzsUserQualifications::getUserInfoId, userId);
        tzsUserQualificationsService.getBaseMapper().delete(lambda);
        addQualificationsMessage(userId, list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(Object[] ids1) {
        LambdaQueryWrapper<TzsUserInfo> lambda = new QueryWrapper<TzsUserInfo>().lambda();
        lambda.in(TzsUserInfo::getSequenceNbr, ids1);
        TzsUserInfo tzsUserInfo = new TzsUserInfo();
        tzsUserInfo.setIsDelete(true);
        tzsUserInfoMapper.update(tzsUserInfo, lambda);
        List<TzsUserInfo> tzsUserInfos = tzsUserInfoMapper.selectList(lambda);
        for (TzsUserInfo userInfo : tzsUserInfos) {
            tzsUserEquipMapper.delete(new QueryWrapper<TzsUserEquip>().eq("user_seq", userInfo.getSequenceNbr()));
            if (!ObjectUtils.isEmpty(userInfo.getAmosUserId())) {
                Privilege.agencyUserClient.multDeleteUser(userInfo.getAmosUserId());
                deleteGroupAndPersonRelation(userInfo.getPostName(), userInfo.getAmosUserId());
            }
        }
    }


    @Override
    public void deleteGroupAndPersonRelation(String postName, String amosUserId) {
        String[] split = postName.split(",");
        for (String s : split) {
            if (!ObjectUtils.isEmpty(TwoStipulateGroupEnum.getId.get(s))) {
                Privilege.groupUserClient.deleteGroupUser(TwoStipulateGroupEnum.getId.get(s), amosUserId);
            }
        }
    }

    // 企业自查询 ＋ 监管单位查看 都用到该接口
    @Override
    public Map<String, Object> getDetail(Long id, ReginParams reginParams) {
        // 为了处理以下场景
        // 1：没有单位限制的时候添加了所有类型的人员，现在有了单位类型限制的情况下更新不了原先人员
        // 2：多种单位类型的企业编辑另一种单位类型下的人员
        // 监管机构查看所有
        List<String> unitTypeAllPostCode;
        if (!reginParams.getCompany().getCompanyType().equals("监管机构")) {
            unitTypeAllPostCode = this.postByUnitType(reginParams.getCompany()).stream().map(DataDictionary::getCode).collect(Collectors.toList());
        } else {
            unitTypeAllPostCode = this.getAllUserType().stream().map(DataDictionary::getCode).collect(Collectors.toList());
        }
        Map<String, Object> maps = new HashMap<>();
        TzsUserInfo tzsUserInfo = tzsUserInfoMapper.selectById(id);
        TzsUserInfoVo tzsUserInfoVo = new TzsUserInfoVo();
        BeanUtils.copyProperties(tzsUserInfo, tzsUserInfoVo, "identification", "profile", "post", "permissionItem", "appointDoc");
        if (!ObjectUtils.isEmpty(tzsUserInfo.getPost())) {
            tzsUserInfoVo.setPost(JSON.parseArray(tzsUserInfo.getPost()));
        }
        Optional.ofNullable(tzsUserInfo.getNewPost())
                .map(JSON::parseArray)
                .map(array -> array.stream()
                        .map(String::valueOf)
                        .filter(unitTypeAllPostCode::contains)
                        .collect(Collectors.toList()))
                .filter(list -> !list.isEmpty())
                .map(item -> JSONArray.parseArray(JSON.toJSONString(item)))
                .ifPresent(tzsUserInfoVo::setNewPost);
        Optional.ofNullable(tzsUserInfo.getSubPost())
                .filter(post -> !ObjectUtils.isEmpty(post))
                .map(JSON::parseArray)
                .ifPresent(tzsUserInfoVo::setSubPost);
        if (!ObjectUtils.isEmpty(tzsUserInfo.getEquipType())) {
            JSONArray equipTypeJSONArray = JSON.parseArray(tzsUserInfo.getEquipType());
            tzsUserInfoVo.setEquipType(equipTypeJSONArray);
            if (CollUtil.isNotEmpty(equipTypeJSONArray)) {
                StringBuilder equipTypeName = new StringBuilder();
                for (Object o : equipTypeJSONArray) {
                    String s = EquipmentClassifityEnum.getName.get(o);
                    if (StringUtils.isEmpty(s)) {
                        s = String.valueOf(o);
                    }
                    equipTypeName.append(s);
                    equipTypeName.append(",");
                }
                tzsUserInfoVo.setEquipTypeName(equipTypeName.substring(0, equipTypeName.length() - 1));
            }
        }
        tzsUserInfoVo.setIdentification(ObjectUtils.isEmpty(tzsUserInfo.getIdentification()) ? null : JSON.parseArray(tzsUserInfo.getIdentification()));
        tzsUserInfoVo.setProfile(ObjectUtils.isEmpty(tzsUserInfo.getProfile()) ? null : JSON.parseArray(tzsUserInfo.getProfile()));
        tzsUserInfoVo.setAppointDoc(ObjectUtils.isEmpty(tzsUserInfo.getAppointDoc()) ? null : JSON.parseArray(tzsUserInfo.getAppointDoc()));
        tzsUserInfoVo.setPracticeRegistration(ObjectUtils.isEmpty(tzsUserInfo.getPracticeRegistration()) ? null : JSON.parseArray(tzsUserInfo.getPracticeRegistration()));
        tzsUserInfoVo.setLaborContract(ObjectUtils.isEmpty(tzsUserInfo.getLaborContract()) ? null : JSON.parseArray(tzsUserInfo.getLaborContract()));
        tzsUserInfoVo.setOtherAccessories(ObjectUtils.isEmpty(tzsUserInfo.getOtherAccessories()) ? null : JSON.parseArray(tzsUserInfo.getOtherAccessories()));
        String companyType = getUnitType();
        tzsUserInfoVo.setCompanyType(companyType.contains("个人主体") ? "individual" : "no-individual");
        Map<String, Object> userInfoMap = BeanUtil.beanToMap(tzsUserInfoVo);
//        userInfoMap.putAll(this.getPermissionDataJson(tzsUserInfo.getPermissionData()));
        // 填充资质信息
        Map<? extends String, ?> permissions = tzsUserPermissionServiceImpl.queryForSubFormByUserSeq(String.valueOf(tzsUserInfo.getSequenceNbr()));
        userInfoMap.putAll(permissions);
        maps.put("userInfo", userInfoMap);
        return maps;
    }

    private Map<? extends String, ?> getPermissionDataJson(String permissionData) {
        if (permissionData != null) {
            return JSON.parseObject(permissionData);
        }
        return new JSONObject();
    }

    @Override
    public boolean BindAccount(Map<String, Object> map) {
        String loginName = map.get("userName").toString();
        String pwd = map.get("password").toString();
        String sequenceNbr = map.get("sequenceNbr").toString();
        String roles = map.get("role").toString();
        String status = map.get("status").toString();
        String roleGroupCode = map.get("roleGroup").toString();
        TzsUserInfo tzsUserInfo = tzsUserInfoMapper.selectById(sequenceNbr);

        FeignClientResult<AgencyUserModel> userResult = null;
        try {
            AgencyUserModel agencyUserModel = new AgencyUserModel();
            agencyUserModel.setUserName(loginName);
            agencyUserModel.setRealName(tzsUserInfo.getName());
            agencyUserModel.setLockStatus(status);
            agencyUserModel.setPassword(pwd);
            agencyUserModel.setRePassword(pwd);
            agencyUserModel.setAgencyCode("tzs");
            agencyUserModel.setMobile(tzsUserInfo.getPhone());
            agencyUserModel.setEmail(tzsUserInfo.getEmail());

            ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
            if (ObjectUtils.isEmpty(reginParams)) {
                return false;
            }
            Long companySeq = reginParams.getCompany().getSequenceNbr();
            List<String> appCodesSet = reginParams.getUserModel().getAppCodes();
            List<RoleModel> allRoleList = new ArrayList<>();
            List<Long> roleIds = new ArrayList<>();
            DataDictionary unitType = iDataDictionaryService
                    .getOne(new LambdaQueryWrapper<DataDictionary>().eq(DataDictionary::getCode, roles).eq(DataDictionary::getType, USER_ROLE));
            String role = unitType.getExtend() != null ? unitType.getExtend() : "";
            for (String s : role.split(",")) {
                RoleModel roleModel = Privilege.roleClient.seleteOne(Long.valueOf(s)).getResult();
                allRoleList.add(roleModel);
            }
            allRoleList.forEach(r -> {
                if (!roleIds.contains(r.getSequenceNbr())) {
                    roleIds.add(r.getSequenceNbr());
                }
            });

            // 添加人员管理角色

            String post = tzsUserInfo.getPost();
            if (post.contains(PersonManageRoleEnum.code.getId().toString())) {
                String companyType = tzsUserInfoMapper.selectCompanyTypeById(companySeq);
                setBizOperateUserRole(companyType, roleIds);
            }

            Map<Long, List<Long>> roleSeqMap = new HashMap<>();
            Map<Long, List<RoleModel>> orgRoles = new HashMap<>();
            roleSeqMap.put(companySeq, roleIds);
            orgRoles.put(companySeq, allRoleList);
            agencyUserModel.setAppCodes(new ArrayList<>(appCodesSet));
            agencyUserModel.setOrgRoles(orgRoles);
            agencyUserModel.setOrgRoleSeqs(roleSeqMap);
            userResult = Privilege.agencyUserClient.create(agencyUserModel);
            if (userResult.getStatus() == 200) {

                tzsUserInfo.setAmosUserId(userResult.getResult().getUserId());
                tzsUserInfo.setAmosUserName(userResult.getResult().getUserName());
                tzsUserInfo.setLockStatus(status);
                // 绑定企业整改用户组
                List<String> userIds = new ArrayList<>();
                userIds.add(userResult.getResult().getUserId());
                DataDictionary roleGroup = iDataDictionaryService
                        .getOne(new LambdaQueryWrapper<DataDictionary>().eq(DataDictionary::getCode, roleGroupCode).eq(DataDictionary::getType, ROLE_GROUP));
                if (!ObjectUtils.isEmpty(roleGroup) && roleGroup.getExtend() != null) {
                    Privilege.groupUserClient.create(Long.valueOf(roleGroup.getExtend()), userIds);
                }
                // 绑定两个规定用户组
                post = post.replace("[", "").replace("]", "").replace("\"", "");
                for (String code : post.split(",")) {
                    bind2PermissionGroup(userIds, code);
                }
                tzsUserInfoMapper.updateById(tzsUserInfo);
            }
            return true;
        } catch (Exception e) {
            if (userResult != null && userResult.getResult() != null
                    && StringUtils.isNotEmpty(userResult.getResult().getUserId())) {
                Privilege.agencyUserClient.multDeleteUser(userResult.getResult().getUserId());
            }
            log.error(e.getMessage(), e);
            throw new BadRequest(e.getMessage());
        }

    }

    @Override
    public String startOrStopAccount(Map<String, Object> map) {
        Long sequenceNbr = Long.valueOf(map.get("sequenceNbr").toString());
        String amosUserId = map.get("amosUserId").toString();
        String lockStatus = null;
        FeignClientResult<List<String>> userResult = null;
        if (UNLOCK.equals(map.get("lockStatus"))) {
            userResult = Privilege.agencyUserClient.lockUsers(amosUserId);
            lockStatus = 200 == userResult.getStatus() ? LOCK : UNLOCK;
        } else {
            userResult = Privilege.agencyUserClient.unlockUsers(amosUserId);
            lockStatus = 200 == userResult.getStatus() ? UNLOCK : LOCK;
        }
        if (!ObjectUtils.isEmpty(lockStatus)) {
            TzsUserInfo tzsUserInfo = new TzsUserInfo();
            tzsUserInfo.setSequenceNbr(sequenceNbr);
            tzsUserInfo.setLockStatus(lockStatus);
            tzsUserInfoMapper.updateById(tzsUserInfo);
        }
        return userResult.getResult().get(0);
    }

    @Override
    public List<Map<String, Object>> getEquipmentType(String creditCode) {
        ArrayList<Map<String, Object>> maps = new ArrayList<>();
        LambdaQueryWrapper<TzBaseEnterpriseInfo> lambda = new QueryWrapper<TzBaseEnterpriseInfo>().lambda();
        lambda.eq(TzBaseEnterpriseInfo::getUseCode, creditCode);
        List<TzBaseEnterpriseInfo> tzBaseEnterpriseInfos = baseEnterpriseInfoService.getBaseMapper().selectList(lambda);
        if (!ObjectUtils.isEmpty(tzBaseEnterpriseInfos) && !ObjectUtils.isEmpty(tzBaseEnterpriseInfos.get(0).getEquipCategory())) {
            String equipCategory = tzBaseEnterpriseInfos.get(0).getEquipCategory();
            JSONArray objects = JSON.parseArray(equipCategory);
            for (Object object : objects) {
                HashMap<String, Object> map = new HashMap<>();
                map.put("code", object);
                map.put("name", EquipmentClassifityEnum.getEnumByCode(object.toString()).getName());
                maps.add(map);
            }
            return maps;
        }
        return new ArrayList<>();
    }

    @Override
    public Map<String, Integer> getArrangementStatistic(String companyCode) {
        return tzsUserInfoMapper.getArrangementStatistic(companyCode);
    }

    public String getUnitType() {
        List<CompanyModel> companyModels = FeignUtil.remoteCall(() -> Privilege.companyClient.queryListByChild(RequestContext.getExeUserId()));
        if (companyModels.isEmpty()) {
            return "";
        }
        return companyModels.get(0).getCompanyType();
    }

    @Override
    public Map<String, Object> getCompanyType() {
        Map<String, Object> result = new HashMap<>();
        result.put("companyType", null);
        List<CompanyModel> companyModels = FeignUtil.remoteCall(() -> Privilege.companyClient.queryListByChild(RequestContext.getExeUserId()));
        if (companyModels.isEmpty()) {
            return result;
        }
        result.put("creditCode", companyModels.get(0).getCompanyCode());
        boolean productCompany = false;
        boolean useCompany = false;
        boolean installCompany = false;
        boolean inspectionCompany = false;
        for (CompanyModel companyModel : companyModels) {
            String companyType = companyModel.getCompanyType();
            if (companyType.contains("使用单位") || companyType.contains("个人主体")) {
                useCompany = true;
            }
            if (companyType.contains("充装单位") || companyType.contains("安装改造维修单位") || companyType.contains("制造单位") || companyType.contains("设计单位")) {
                productCompany = true;
            }
            if (companyType.contains("安装改造维修单位")) {
                installCompany = true;
            }
            if (companyType.contains("检验检测机构")) {
                inspectionCompany = true;
            }
        }
        StringBuilder companyType = new StringBuilder();
        if (useCompany) {
            companyType.append("use-");
        }
        if (productCompany) {
            companyType.append("pro-");
        }

        if (installCompany) {
            companyType.append("install-");
        }
        if (inspectionCompany) {
            companyType.append("inspection");
        }
        result.put("companyType", companyType);
        return result;
    }

    @Override
    public Map<String, Object> getCompanyTypeForRedis(ReginParams selectedOrgInfo) {
        Map<String, Object> result = new HashMap<>();
        result.put("companyType", null);
        CompanyBo company = selectedOrgInfo.getCompany();
        if (ObjectUtils.isEmpty(company)) {
            return result;
        }
        result.put("creditCode", company.getCompanyCode());
        boolean productCompany = false;
        boolean useCompany = false;
        boolean installCompany = false;
        boolean inspectionCompany = false;
        String companyType = company.getCompanyType();
        if (companyType.contains("使用单位") || companyType.contains("个人主体")) {
            useCompany = true;
        }
        if (companyType.contains("充装单位") || companyType.contains("安装改造维修单位") || companyType.contains("制造单位") || companyType.contains("设计单位")) {
            productCompany = true;
        }
        if (companyType.contains("安装改造维修单位")) {
            installCompany = true;
        }
        if (companyType.contains("检验检测机构")) {
            inspectionCompany = true;
        }
        StringBuilder companyTypeStr = new StringBuilder();
        if (useCompany) {
            companyTypeStr.append("use-");
        }
        if (productCompany) {
            companyTypeStr.append("pro-");
        }

        if (installCompany) {
            companyTypeStr.append("install-");
        }
        if (inspectionCompany) {
            companyTypeStr.append("inspection");
        }
        result.put("companyType", companyTypeStr);
        return result;
    }

    @Override
    public Page<TzsEquipListDto> getEquipList(String type, String userSeq, TzsEquipListDto dto, Page<TzsEquipListDto> page) {
        List<CompanyModel> companyModels = FeignUtil.remoteCall(() -> Privilege.companyClient.queryListByChild(RequestContext.getExeUserId()));
        if (companyModels.isEmpty()) {
            throw new BadRequest("未指定人员归属单位信息");
        }
        String companyCode = companyModels.get(0).getCompanyCode();
        Page<TzsEquipListDto> tzsUserInfoDtoPage;
        tzsUserInfoDtoPage = tzsUserInfoMapper.getAllEquipList(page, type, companyCode, userSeq, dto);
        return tzsUserInfoDtoPage;
    }

    @Override
    public Boolean equipBind(String type, String userSeq, String creditCode, Map<String, Object> map) {
        Object recordList = map.get("ids");
        List<String> ids = (List<String>) recordList;
        List<TzsUserEquip> tzsUserEquipList = new ArrayList<>();
        boolean flag = false;
        if ("bind".equals(type)) {
            for (String equipId : ids) {
                TzsUserEquip tzsUserEquip = new TzsUserEquip();
                tzsUserEquip.setEquipId(equipId);
                tzsUserEquip.setUserSeq(userSeq);
                tzsUserEquip.setCreditCode(creditCode);
                tzsUserEquipList.add(tzsUserEquip);
            }
            flag = tzsUserEquipService.saveBatch(tzsUserEquipList);
        } else if ("untie".equals(type)) {
            int num = tzsUserEquipMapper.delete(new QueryWrapper<TzsUserEquip>().eq("user_seq", userSeq).in("equip_id", ids));
            flag = num > 0 ? true : flag;
        }
        return flag;
    }

    @Override
    public List<TzsUserInfo> getSafetyList(String companyCode) {
        return tzsUserInfoMapper.selectList(new QueryWrapper<TzsUserInfo>().eq("unit_code", companyCode).eq("is_delete", false).like("post", 6549));
    }

    @Override
    public List<Map<String, Object>> getGroupList() {
        FeignClientResult<Collection<GroupModel>> collectionFeignClientResult = Privilege.groupClient.selectForList(1712370734598221825L, null);
        Collection<GroupModel> GroupModelResult = collectionFeignClientResult.getResult();
        List<GroupModel> collect = GroupModelResult.stream().filter(e -> "twoStipulate".equals(e.getGroupDesc())).collect(Collectors.toList());
        List<Map<String, Object>> result = new ArrayList<>();
        for (GroupModel groupModel : collect) {
            Map<String, Object> map = new HashMap<>();
            map.put("groupName", groupModel.getGroupName());
            map.put("sequenceNbr", groupModel.getSequenceNbr());
            result.add(map);
        }
        return result;
    }

    @Override
    public Map<String, Object> getPersonType() {
        String userId = RequestContext.getExeUserId();
        if (ObjectUtils.isEmpty(userId)) {
            return null;
        }
        String postName = tzsUserInfoMapper.selectPostNameByUserId(userId);
        Map<String, Object> result = new HashMap<>();
        result.put("postName", ObjectUtils.isEmpty(postName) ? null : postName);
        return result;
    }

    @Override
    public List<GroupAndPersonInfoDto> getGroupAndPersonInfo(Long groupId) {

        List<GroupAndPersonInfoDto> result = new ArrayList<>();
        List<GroupAndPersonInfoDto> groupAndPersonInfoDtoList = tzsUserInfoMapper.getUnitInfoByUserId(groupId);
        DataDictionary dataDictionary = iDataDictionaryService.getByExtend(groupId.toString(), QYRYGW);
        for (GroupAndPersonInfoDto groupAndPersonInfoDto : groupAndPersonInfoDtoList) {
            if (!ObjectUtils.isEmpty(groupAndPersonInfoDto)) {
                groupAndPersonInfoDto.setGroupName(ObjectUtils.isEmpty(dataDictionary) ? null : dataDictionary.getName());
                String[] UnitType = groupAndPersonInfoDto.getUnitType().split(",");
                if (UnitType.length > 0) {
                    StringBuilder unitTypeCode = new StringBuilder();
                    for (String s : UnitType) {
                        unitTypeCode.append(UnitTypeEnum.getCode.get(s)).append(",");
                    }
                    groupAndPersonInfoDto.setUnitTypeCode(unitTypeCode.substring(0, unitTypeCode.length() - 1));
                } else {
                    groupAndPersonInfoDto.setUnitTypeCode(UnitTypeEnum.getCode.get(UnitType));
                }

                if (!ObjectUtils.isEmpty(groupAndPersonInfoDto.getEquipCategory())) {
                    String EquipCategory = groupAndPersonInfoDto.getEquipCategory()
                            .replace("[", "")
                            .replace("]", "")
                            .replace("\"", "");
                    List<String> equipCategoryList = Arrays.asList(EquipCategory.split(","));
                    if (equipCategoryList.size() > 0) {
                        StringBuilder equipCategoryCode = new StringBuilder();
                        StringBuilder equipCategory = new StringBuilder();
                        for (String s : equipCategoryList) {
                            equipCategoryCode.append(s).append(",");
                            equipCategory.append(EquipmentClassifityEnum.getName.get(s)).append(",");
                        }
                        groupAndPersonInfoDto.setEquipCategory(equipCategory.substring(0, equipCategory.length() - 1));
                        groupAndPersonInfoDto.setEquipCategoryCode(equipCategoryCode.substring(0, equipCategoryCode.length() - 1));
                    } else {
                        groupAndPersonInfoDto.setEquipCategory(EquipmentClassifityEnum.getName.get(equipCategoryList.get(0)));
                        groupAndPersonInfoDto.setEquipCategoryCode(equipCategoryList.get(0));
                    }
                } else {
                    groupAndPersonInfoDto.setEquipCategory(null);
                    groupAndPersonInfoDto.setEquipCategoryCode(null);
                }
                result.add(groupAndPersonInfoDto);
            }
        }
        return result;
    }

    @Override
    public Boolean createUnitPerson() {
        List<TzsUserInfo> result = tzsUserInfoMapper.getUnitPersonInfo();
        return this.saveBatch(result);
    }


    @Override
    public void testGroup(String groupSeq) {
        List<String> userIds = tzsUserInfoMapper.selectUserIds();
        Privilege.groupUserClient.create(Long.valueOf(groupSeq), userIds);
    }


    @Override
    public List<Map<String, Object>> getUserAllPostType() {
        // 需求3309 提出展示所有人员类型供用户选择
        List<String> type = new ArrayList<>(Arrays.asList(
                "QYRYGW",
                "QYRYGW-SYDW",
                "QYRYGW-SCDW",
                "QYRYGW-INSTALL",
                "QYRYGW-INSPECTION"
        ));
        // if ("detail".equals(formType)) {
        //     type.addAll(Arrays.asList(
        //             "QYRYGW-SYDW",
        //             "QYRYGW-SCDW",
        //             "QYRYGW-INSTALL",
        //             "QYRYGW-INSPECTION"
        //     ));
        // } else {
        //     if (unitType.contains("use")) {
        //         type.add("QYRYGW-SYDW");
        //     }
        //     if (unitType.contains("pro")) {
        //         type.add("QYRYGW-SCDW");
        //     }
        //     if (unitType.contains("install")) {
        //         type.add("QYRYGW-INSTALL");
        //         type.add("QYRYGW-INSPECTION");
        //     }
        //     if (unitType.contains("inspection")) {
        //         type.add("QYRYGW-INSPECTION");
        //         type.add("QYRYGW-SCDW");
        //     }
        // }
        return tzsUserInfoMapper.getUserTypeList(type);
    }


    @Override
    public List<DataDictionary> getSubPostByParentsIds(String postIds) {
        return iDataDictionaryService.lambdaQuery()
                .in(DataDictionary::getParent, new ArrayList<>(Arrays.asList(postIds.split(","))))
                .eq(DataDictionary::getIsDelete, Boolean.FALSE)
                .orderByAsc(DataDictionary::getSortNum)
                .list();
    }

    /**
     * 人员转出
     *
     * @param userSeqNbrs 用户seqNbrs，逗号分隔
     * @return res
     */
    @Override
    public Boolean personnelTransferOut(String userSeqNbrs) {
        List<Long> seqNbrs = new ArrayList<>(Arrays.asList(userSeqNbrs.split(","))).stream().map(Long::parseLong).collect(Collectors.toList());
        // 逻辑删除用户+标识转出操作时间
        this.update(new LambdaUpdateWrapper<TzsUserInfo>()
                .set(TzsUserInfo::getIsDelete, Boolean.TRUE)
                .set(TzsUserInfo::getTransferOut, "1")
                .set(TzsUserInfo::getTransferOutTime, new Date())
                .in(TzsUserInfo::getSequenceNbr, seqNbrs));
        // 逻辑删除系统账号
        String deleteUserIds = this.baseMapper.selectList(new LambdaQueryWrapper<TzsUserInfo>()
                        .isNotNull(TzsUserInfo::getAmosUserId)
                        .isNotNull(TzsUserInfo::getAmosUserName)
                        .select(TzsUserInfo::getAmosUserId)
                        .in(TzsUserInfo::getSequenceNbr, seqNbrs))
                .stream()
                .map(TzsUserInfo::getAmosUserId)
                .collect(Collectors.joining(","));
        Optional.of(deleteUserIds)
                .filter(ids -> !ObjectUtils.isEmpty(ids))
                .ifPresent(ids -> Privilege.agencyUserClient.multDeleteUser(ids));
        return Boolean.TRUE;
    }

    @Override
    public JSONObject statisticsOfPersonnelTypes(String type) {
        ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
        String companyCode = reginParams.getCompany().getCompanyCode();
        if ("total".equals(type)) {
            int total = tzsUserInfoMapper.selectList(new LambdaQueryWrapper<TzsUserInfo>()
                    .select(TzsUserInfo::getSequenceNbr)
                    .eq(TzsUserInfo::getUnitCode, companyCode)
                    .eq(TzsUserInfo::getIsDelete, Boolean.FALSE)
            ).size();
            return JSONObject.parseObject(String.format(TOTALTYPESTEMPLATE, total));
        } else if ("subType".equals(type)) {
            ArrayList<JSONObject> jsonObjects = this.getSubTypeCount(companyCode);
            return new JSONObject().fluentPut("records", jsonObjects);
        }
        return null;
    }

    @Override
    public JSONObject statisticsOfPersonnelTypesByPatentCode(String parentId) {
        ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
        String companyCode = reginParams.getCompany().getCompanyCode();

        DataDictionary dictionary = iDataDictionaryService.getBaseMapper().selectOne(new LambdaQueryWrapper<DataDictionary>().select(DataDictionary::getCode, DataDictionary::getName).eq(DataDictionary::getCode, parentId));
        ArrayList<String> seriesData = new ArrayList<>();
        ArrayList<String> axisData = new ArrayList<>();
        iDataDictionaryService.getBaseMapper().selectList(new LambdaQueryWrapper<DataDictionary>()
                        .select(DataDictionary::getName, DataDictionary::getCode)
                        .eq(DataDictionary::getParent, parentId))
                .forEach(item -> {
                    axisData.add(item.getName() + "(人)");
                    int size = tzsUserInfoMapper.selectList(new LambdaQueryWrapper<TzsUserInfo>()
                            .select(TzsUserInfo::getSequenceNbr)
                            .eq(TzsUserInfo::getUnitCode, companyCode)
                            .like(TzsUserInfo::getSubPost, item.getCode())
                            .eq(TzsUserInfo::getIsDelete, Boolean.FALSE)
                    ).size();
                    seriesData.add(Objects.toString(size));
                });

        return new JSONObject().fluentPut("records", Arrays.asList(new JSONObject()
                .fluentPut("name", dictionary.getName() + "(人)")
                .fluentPut("value", tzsUserInfoMapper.selectList(new LambdaQueryWrapper<TzsUserInfo>()
                        .select(TzsUserInfo::getSequenceNbr)
                        .eq(TzsUserInfo::getUnitCode, companyCode)
                        .like(TzsUserInfo::getNewPost, dictionary.getCode())
                        .eq(TzsUserInfo::getIsDelete, Boolean.FALSE)
                ).size())
                .fluentPut("seriesData", seriesData)
                .fluentPut("axisData", axisData)));
    }

    private ArrayList<JSONObject> getSubTypeCount(String companyCode) {
        List<DataDictionary> allUserType = this.getAllUserType();
        ArrayList<JSONObject> jsonObjects = new ArrayList<>();
        allUserType.forEach(item -> {
            String postCode = item.getCode();
            int size = tzsUserInfoMapper.selectList(new LambdaQueryWrapper<TzsUserInfo>()
                    .select(TzsUserInfo::getSequenceNbr)
                    .eq(TzsUserInfo::getUnitCode, companyCode)
                    .like(TzsUserInfo::getNewPost, postCode)
                    .eq(TzsUserInfo::getIsDelete, Boolean.FALSE)
            ).size();
            jsonObjects.add(new JSONObject().fluentPut("name", item.getName() + "(人)").fluentPut("value", size));
        });
        return jsonObjects;
    }

    public List<LinkedHashMap> screenData(List<LinkedHashMap> result, List<LinkedHashMap> data, String id) {
        if (!ObjectUtils.isEmpty(result)) {
            return result;
        }
        List<LinkedHashMap> list = data.stream().filter(item -> item.get("sequenceNbr").toString().equals(id)).collect(Collectors.toList());
        if (!ObjectUtils.isEmpty(list)) {
            return list;
        }
        for (LinkedHashMap item : data) {
            if (!ObjectUtils.isEmpty(item.get("children"))) {
                List<LinkedHashMap> children = screenData(result, (List<LinkedHashMap>) item.get("children"), id);
                if (!ObjectUtils.isEmpty(children)) {
                    result = children;
                    break;
                }
            }
        }
        return result;
    }

    @Override
    public TzIndividualityDto getIndividualityInfo() {
        ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
        AgencyUserModel userModel = reginParams.getUserModel();
        CompanyBo companyBo = reginParams.getCompany();
        TzIndividualityDto individuality = new TzIndividualityDto();
        TzBaseEnterpriseInfoDto baseEnterpriseInfoDto = baseEnterpriseInfoService.getInfoByUseCode(companyBo.getCompanyCode());
        if (!ValidationUtil.isEmpty(baseEnterpriseInfoDto)) {
            individuality = individualityMapper.getIndividualityInfo(baseEnterpriseInfoDto.getSequenceNbr());
            individuality.setPhone(userModel.getMobile());
            individuality.setGoverningBody(baseEnterpriseInfoDto.getGoverningBody());
            individuality.setAddress(baseEnterpriseInfoDto.getAddress());
        }
        return individuality;
    }

    @Transactional
    @Override
    public TzIndividualityDto updateIndividualityInfo(TzIndividualityDto individualityDto) {
        TzsBaseIndividuality individuality = new TzsBaseIndividuality();
        TzBaseEnterpriseInfo baseEnterpriseInfo = baseEnterpriseInfoService.getById(individualityDto.getEnterpriseId());
        if (!ValidationUtil.isEmpty(baseEnterpriseInfo)) {
            BeanUtils.copyProperties(individualityDto, individuality);
            // 更新tz_base_individuality信息
            individuality.setRealName(individualityDto.getName());
            individualityService.saveOrUpdate(individuality);

            // 更新tz_base_enterprise_info信息
            baseEnterpriseInfo.setAddress(individualityDto.getAddress());
            baseEnterpriseInfo.setContactPhone(individualityDto.getPhone());
            baseEnterpriseInfo.setUseContact(individualityDto.getName());
            baseEnterpriseInfoService.updateById(baseEnterpriseInfo);
            // 更新privilege_agency_user手机号
            ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
            AgencyUserModel userModel = reginParams.getUserModel();
            if (!userModel.getMobile().equals(individualityDto.getPhone())) {
                userModel.setMobile(individualityDto.getPhone());
                Privilege.agencyUserClient.modifyMobile(userModel, userModel.getUserId());
            }
        }
        return individualityDto;
    }

    public Page<UserPermissionDto> getUserByPermission(long current, long size, String type, UserPermissionDto filter, String sort) {
        Page<UserPermissionDto> permissionDtoPage = new Page<>(current, size);
        List<String> post = this.getPostByType(type);
        SortVo sortMap = this.sortFieldConversion(sort);
        Page<UserPermissionDto> result = this.getBaseMapper().queryUserByPermissionPage(permissionDtoPage, post, filter, sortMap);
        result.getRecords().forEach(d -> {
            if (StringUtils.isNotEmpty(d.getIdentificationStr())) {
                // 照片赋值
                List<CommonFile> commonFiles = JSON.parseArray(d.getIdentificationStr(), CommonFile.class);
                if (!ObjectUtils.isEmpty(commonFiles)) {
                    d.setPhotoUrl(commonFiles.get(0).getUrl());
                }
            }
            // 人员类型枚举转name
            d.setPost(this.isJSONValid(d.getPost()) ? d.getPost() : "[\"" + d.getPost() + "\"]");
            d.setPostName(this.setPostName(d.getPost()));
            d.setPermissionStatus(this.castNoPermissionData(type, d.getPermissionStatus()));
        });
        return result;
    }

    private String castNoPermissionData(String type, String permissionStatus) {
        // 历史数据处理：之前检验人员、检测人员、作业人员资质为非必输，调整为必输后，数据为空时打标记为<资质不全>
        if ((type.equals("jy") || type.equals("jc") || type.equals("zyry")) && "无资质要求".equals(permissionStatus)) {
            return "资质不全";
        }
        return permissionStatus;
    }

    public List<UserPermissionDto> getUserPermissionOfCurrentLogin(UserPermissionDto filter) {
        List<UserPermissionDto> result = this.getBaseMapper().queryUserByPermissionOfOneCompany(filter);
        result.forEach(d -> {
            if (StringUtils.isNotEmpty(d.getIdentificationStr())) {
                // String转json
                d.setIdentification(JSON.parseArray(d.getIdentificationStr()));
                // 照片赋值
                List<CommonFile> commonFiles = JSON.parseArray(d.getIdentificationStr(), CommonFile.class);
                if (!ObjectUtils.isEmpty(commonFiles)) {
                    d.setPhotoUrl(commonFiles.get(0).getUrl());
                }
            }
            d.setPermissionStatusColor(statusColorMap.getOrDefault(d.getPermissionStatus(), "#868686"));
            // 人员类型枚举转name
            d.setPost(this.isJSONValid(d.getPost()) ? d.getPost() : "[\"" + d.getPost() + "\"]");
            d.setPostName(this.setPostName(d.getPost()));
        });
        return result;
    }

    private List<String> getPostByType(String type) {
        switch (type) {
            case "jy":
                return Collections.singletonList("66151");
            case "jc":
                return Collections.singletonList("66152");
            case "zyry":
                return Collections.singletonList("6552");
            case "qt":
                return Arrays.asList("6549", "6548", "6547", "6546", "6551", "6550", "6616", "6553", "6617");
            default:
                return this.getAllUserType().stream().map(DataDictionary::getCode).collect(Collectors.toList());
        }
    }

    public List<UserPermissionDto> getUserPermissionByCompanySeq(Long comSeq) {
        TzBaseEnterpriseInfo enterpriseInfo = baseEnterpriseInfoService.getById(comSeq);
        return getUserPermissionOfCurrentLogin(UserPermissionDto.builder().cityCode(enterpriseInfo.getUseUnitCode()).build());
    }

    @Transactional(rollbackFor = Exception.class)
    public TzsUserInfoDto saveUserInfo(TzsUserInfoDto tzsUserInfo) {
        ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
        if (ObjectUtils.isEmpty(reginParams)) {
            return null;
        }
        CompanyBo companyModel = reginParams.getCompany();
        if (ObjectUtils.isEmpty(companyModel)) {
            throw new BadRequest("未指定人员归属单位信息");
        }

        if (tzsUserInfoMapper.selectCount(new LambdaQueryWrapper<TzsUserInfo>()
                .eq(TzsUserInfo::getCertificateType, tzsUserInfo.getCertificateType())
                .eq(TzsUserInfo::getCertificateNum, tzsUserInfo.getCertificateNum())
                .eq(TzsUserInfo::getUnitCode, companyModel.getCompanyCode())
                .eq(TzsUserInfo::getIsDelete, false)) > 0) {
            throw new BadRequest("本单位下用户证件号码重复，请核对！");
        }

        if (tzsUserInfoMapper.selectCount(new LambdaQueryWrapper<TzsUserInfo>()
                .eq(TzsUserInfo::getCertificateType, tzsUserInfo.getCertificateType())
                .eq(TzsUserInfo::getCertificateNum, tzsUserInfo.getCertificateNum())
                .ne(TzsUserInfo::getUnitCode, companyModel.getCompanyCode())
                .eq(TzsUserInfo::getIsDelete, false)) > 0) {
            throw new BadRequest("该用户已被其他单位绑定，请联系原单位转出！");
        }

        if (tzsUserInfoMapper.selectCount(new LambdaQueryWrapper<TzsUserInfo>()
                .eq(TzsUserInfo::getUnitCode, companyModel.getCompanyCode())
                .eq(TzsUserInfo::getPhone, tzsUserInfo.getPhone())
                .eq(TzsUserInfo::getIsDelete, false)) > 0) {
            throw new BadRequest("本单位下用户联系电话重复，请核对！");
        }

        if (tzsUserInfoMapper.selectCount(new LambdaQueryWrapper<TzsUserInfo>()
                .ne(TzsUserInfo::getUnitCode, companyModel.getCompanyCode())
                .eq(TzsUserInfo::getPhone, tzsUserInfo.getPhone())
                .eq(TzsUserInfo::getIsDelete, false)) > 0) {
            throw new BadRequest("该用户手机号已被其他单位人员绑定！");
        }

        tzsUserInfo.setUnitName(companyModel.getCompanyName());
        tzsUserInfo.setUnitCode(companyModel.getCompanyCode());
        tzsUserInfo.setAppointDoc(tzsUserInfo.getAppointDoc());
        tzsUserInfo.setRecDate(new Date());
        // 兼容前端只传一个值，并且非json类型的情况
        JSONArray postArray = JSONArray.parseArray(this.isJSONValid(tzsUserInfo.getNewPost()) ? tzsUserInfo.getNewPost() : "[\"" + tzsUserInfo.getNewPost() + "\"]");
        tzsUserInfo.setNewPost(JSONArray.toJSONString(postArray));
        // 兼容 人员类型为【作业人员】且 【作业项目】含有【电梯修理】项目的为【维保人员】post为“6618”
        JSONArray permissionData6552 = tzsUserInfo.getPermissionData6552();
        if (!permissionData6552.isEmpty() && postArray.contains("6552")) {
            JSONObject jsonObject = permissionData6552.getJSONObject(0);
            JSONArray jobItem = jsonObject.getJSONArray("jobItem");
            if (jobItem != null && jobItem.contains("电梯修理")) {
                postArray.add("6618");
            }
        }
        tzsUserInfo.setPost(JSONArray.toJSONString(postArray));
        tzsUserInfo.setPostName(this.setPostName(tzsUserInfo.getNewPost()));
        // 兼容前端只传一个值，并且非json类型的情况
        JSONArray subPostArray = JSONArray.parseArray(this.isJSONValid(tzsUserInfo.getSubPost()) ? tzsUserInfo.getSubPost() : "[\"" + tzsUserInfo.getSubPost() + "\"]");
        this.subtypeIntegrityCheck(postArray, subPostArray);
        if (subPostArray != null) {
            tzsUserInfo.setSubPost(JSONArray.toJSONString(subPostArray));
            String subPostNames = iDataDictionaryService.lambdaQuery()
                    .in(DataDictionary::getCode, subPostArray)
                    .orderByAsc(DataDictionary::getSortNum)
                    .select(DataDictionary::getName)
                    .list()
                    .stream()
                    .map(DataDictionary::getName)
                    .collect(Collectors.joining(","));
            tzsUserInfo.setSubPostName(subPostNames);
        }
        tzsUserInfo.setCreateDate(new Date());
        tzsUserInfo = this.createWithModel(tzsUserInfo);
        // 保存资质
        tzsUserPermissionServiceImpl.savePermissionData(tzsUserInfo);
        return tzsUserInfo;
    }

    /**
     * 子类型完整性校验
     *
     * @param postArray
     * @param subPostArray
     */
    private void subtypeIntegrityCheck(JSONArray postArray, JSONArray subPostArray) {
        if (subPostArray == null || subPostArray.isEmpty()) {
            subPostArray = new JSONArray();
        }
        Set<String> postCodes = postArray.stream()
                .map(String::valueOf)
                .collect(Collectors.toSet());
        Map<String, String> postNameMap = iDataDictionaryService.lambdaQuery()
                .select(DataDictionary::getCode, DataDictionary::getName)
                .in(DataDictionary::getCode, postCodes)
                .like(DataDictionary::getType, "QYRYGW")
                .list()
                .stream()
                .collect(Collectors.toMap(DataDictionary::getCode, DataDictionary::getName));

        Set<String> subPostSet = subPostArray.stream()
                .map(String::valueOf)
                .collect(Collectors.toSet());

        postArray.forEach(item -> {
            String post = String.valueOf(item);
            String postName = postNameMap.getOrDefault(post, "未知类型");

            List<DataDictionary> subPostList = getSubPostByParentsIds(post);
            if (CollectionUtils.isEmpty(subPostList)) return;

            boolean hasSubtypeSelected = subPostList.stream()
                    .map(DataDictionary::getCode)
                    .anyMatch(subPostSet::contains);

            if (!hasSubtypeSelected) {
                throw new BadRequest(String.format("%s 未勾选子类型", postName));
            }
        });
    }

    @Transactional(rollbackFor = Exception.class)
    public TzsUserInfoDto updateUserInfo(Long rowId, TzsUserInfoDto tzsUserInfoDto) {

        ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
        if (ObjectUtils.isEmpty(reginParams)) {
            return null;
        }
        CompanyBo companyModel = reginParams.getCompany();
        if (ObjectUtils.isEmpty(companyModel)) {
            throw new BadRequest("未指定人员归属单位信息");
        }

        if (tzsUserInfoMapper.selectCount(new LambdaQueryWrapper<TzsUserInfo>()
                .eq(TzsUserInfo::getCertificateType, tzsUserInfoDto.getCertificateType())
                .ne(TzsUserInfo::getSequenceNbr, rowId)
                .eq(TzsUserInfo::getCertificateNum, tzsUserInfoDto.getCertificateNum())
                .eq(TzsUserInfo::getUnitCode, companyModel.getCompanyCode())
                .eq(TzsUserInfo::getIsDelete, false)) > 0) {
            throw new BadRequest("本单位下用户证件号码重复，请核对！");
        }

        if (tzsUserInfoMapper.selectCount(new LambdaQueryWrapper<TzsUserInfo>()
                .eq(TzsUserInfo::getCertificateType, tzsUserInfoDto.getCertificateType())
                .eq(TzsUserInfo::getCertificateNum, tzsUserInfoDto.getCertificateNum())
                .ne(TzsUserInfo::getUnitCode, companyModel.getCompanyCode())
                .eq(TzsUserInfo::getIsDelete, false)) > 0) {
            throw new BadRequest("该用户已被其他单位绑定，请联系原单位转出！");
        }

        if (tzsUserInfoMapper.selectCount(new LambdaQueryWrapper<TzsUserInfo>()
                .eq(TzsUserInfo::getUnitCode, companyModel.getCompanyCode())
                .ne(TzsUserInfo::getSequenceNbr, rowId)
                .eq(TzsUserInfo::getPhone, tzsUserInfoDto.getPhone())
                .eq(TzsUserInfo::getIsDelete, false)) > 0) {
            throw new BadRequest("本单位下用户联系电话重复，请核对！");
        }

        if (tzsUserInfoMapper.selectCount(new LambdaQueryWrapper<TzsUserInfo>()
                .ne(TzsUserInfo::getUnitCode, companyModel.getCompanyCode())
                .eq(TzsUserInfo::getPhone, tzsUserInfoDto.getPhone())
                .eq(TzsUserInfo::getIsDelete, false)) > 0) {
            throw new BadRequest("该用户手机号已被其他单位人员绑定！");
        }

        // 删除人员与组的关系
        QueryWrapper<TzsUserInfo> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("sequence_nbr", rowId);
        queryWrapper2.eq("is_delete", false);
        TzsUserInfo selectOne = tzsUserInfoMapper.selectOne(queryWrapper2);
        if (!ObjectUtils.isEmpty(selectOne.getAmosUserId())) {
            this.deleteGroupAndPersonRelation(selectOne.getPostName(), selectOne.getAmosUserId());
        }

        tzsUserInfoDto.setUnitName(companyModel.getCompanyName());
        tzsUserInfoDto.setUnitCode(companyModel.getCompanyCode());
        tzsUserInfoDto.setSequenceNbr(rowId);
        tzsUserInfoDto.setRecDate(new Date());
        // 兼容前端只传一个值，并且非json类型的情况
        JSONArray postArray = JSONArray.parseArray(this.isJSONValid(tzsUserInfoDto.getNewPost()) ? tzsUserInfoDto.getNewPost() : "[\"" + tzsUserInfoDto.getNewPost() + "\"]");
        tzsUserInfoDto.setNewPost(JSONArray.toJSONString(postArray));
        // 兼容 人员类型为【作业人员】且 【作业项目】含有【电梯修理】项目的为【维保人员】post为“6618”
        JSONArray permissionData6552 = tzsUserInfoDto.getPermissionData6552();
        if (!permissionData6552.isEmpty() && postArray.contains("6552")) {
            JSONObject jsonObject = permissionData6552.getJSONObject(0);
            JSONArray jobItem = jsonObject.getJSONArray("jobItem");
            if (jobItem != null && jobItem.contains("电梯修理")) {
                postArray.add("6618");
            }
        }
        tzsUserInfoDto.setPost(JSONArray.toJSONString(postArray));
        String postName = this.setPostName(tzsUserInfoDto.getNewPost());
        tzsUserInfoDto.setPostName(postName);
        if (!ObjectUtils.isEmpty(selectOne.getAmosUserId())) {
            // 添加新的人员与组的关系
            String[] split = postName.split(",");
            List<String> ids = new ArrayList<>();
            ids.add(selectOne.getAmosUserId());
            for (String s : split) {
                if (!ObjectUtils.isEmpty(TwoStipulateGroupEnum.getId.get(s))) {
                    Privilege.groupUserClient.create(TwoStipulateGroupEnum.getId.get(s), ids);
                }
            }
        }
        // 兼容前端只传一个值，并且非json类型的情况
        JSONArray subPostArray = JSONArray.parseArray(this.isJSONValid(tzsUserInfoDto.getSubPost()) ? tzsUserInfoDto.getSubPost() : "[\"" + tzsUserInfoDto.getSubPost() + "\"]");
        this.subtypeIntegrityCheck(postArray, subPostArray);
        if (subPostArray != null) {
            tzsUserInfoDto.setSubPost(JSONArray.toJSONString(subPostArray));
            String subPostNames = iDataDictionaryService.lambdaQuery()
                    .in(DataDictionary::getCode, subPostArray)
                    .orderByAsc(DataDictionary::getSortNum)
                    .select(DataDictionary::getName)
                    .list()
                    .stream()
                    .map(DataDictionary::getName)
                    .collect(Collectors.joining(","));
            tzsUserInfoDto.setSubPostName(subPostNames);
        }
        // 更新资质
        tzsUserPermissionServiceImpl.updatePermissionData(tzsUserInfoDto);
        tzsUserInfoDto.setQrCodeState("1");
        this.updateWithModel(tzsUserInfoDto);
        // 更新人员信息同步平台
        syncNewPost(tzsUserInfoDto);
        return tzsUserInfoDto;
    }

    public List<DataDictionary> getAllUserType() {
        List<String> type = new ArrayList<>(Arrays.asList(
                "QYRYGW",
                "QYRYGW-SYDW",
                "QYRYGW-SCDW",
                "QYRYGW-INSTALL",
                "QYRYGW-INSPECTION"
        ));
        return iDataDictionaryService.lambdaQuery()
                .select(DataDictionary::getName, DataDictionary::getCode)
                .eq(DataDictionary::getIsDelete, false)
                .isNull(DataDictionary::getParent)
                .in(DataDictionary::getType, type)
                .list();
    }

    /**
     * 人员列表列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void userInfoExport(HttpServletResponse response, List<String> ids) {
        List<UserInfoVo> exportData = tzsUserInfoMapper.queryUserInfoInIds(ids);
        ExcelUtil.createTemplate(response, "人员列表数据", "人员列表", exportData, UserInfoVo.class, null, false);
    }

    private List<String> checkFieldIsValid(List<UserImportDto> userItems) {
        List<String> errors = new ArrayList<>();
        // 1.必输校验
        for (int i = 0; i < userItems.size(); i++) {
            UserImportDto userImportDto = userItems.get(i);
            Set<ConstraintViolation<UserImportDto>> violations = validator.validate(userImportDto);
            for (ConstraintViolation<UserImportDto> violation : violations) {
                errors.add("非法数据，第" + (i + 1) + "行" + violation.getMessage());
            }
        }
        if (!errors.isEmpty()) {
            return errors;
        }
        // 2.手机号重复检验，手机号全局唯一,不同单位下的手机号不能相同 todo 新写判断逻辑
        Map<String, Set<String>> phoneCheckRepeatCount = new HashMap<>();
        userItems.forEach(v -> {
            if (phoneCheckRepeatCount.containsKey(v.getPhone())) {
                phoneCheckRepeatCount.get(v.getPhone()).add(v.getUnitCode());
            } else {
                Set<String> set = new HashSet<>();
                set.add(v.getUnitCode());
                phoneCheckRepeatCount.put(v.getPhone(), set);
            }
        });
        phoneCheckRepeatCount.forEach(((k, v) -> {
            if (v.size() > 1) {
                String phone = k.split("_")[0];
                errors.add(String.format("非法数据，存在手机号%s，在多个单位统一信用代码：%s下共用，请检查后进行上传！", phone, StringUtils.join(v, ",")));
            }
        }));
        // 3.手机号重复检验，手机号全局唯一,不同单位下的手机号不能相同 todo 新写判断逻辑
        Map<String, Set<String>> certNoCheckRepeatCount = new HashMap<>();
        userItems.forEach(v -> {
            if (certNoCheckRepeatCount.containsKey(v.getPhone())) {
                certNoCheckRepeatCount.get(v.getPhone()).add(v.getCertificateNum());
            } else {
                Set<String> set = new HashSet<>();
                set.add(v.getCertificateNum());
                certNoCheckRepeatCount.put(v.getPhone(), set);
            }
        });
        // 3.手机号相同，但是证件号码存在多个-非法数据
        certNoCheckRepeatCount.forEach(((k, v) -> {
            if (v.size() > 1) {
                String phone = k.split("_")[0];
                errors.add(String.format("非法数据，存在多个证件号码：%s，共用相同的手机号%s，请检查后进行上传！", StringUtils.join(v, ","), phone));
            }
        }));
        return errors;
    }

    private final String DOWN_LOAD_START_TEMP = "{\"id\":\"%s\",\"status\":\"starting\",\"fileName\":\"%s\",\"time\":\"%s\"}";
    private final String DOWNLOAD_TOPIC = "/topic/download/excel/%s";
    private final String BUCKET_NAME = "upload";
    private final String UPLOAD_PATH = "/tzs/excelTempFile";

    /**
     * 开始下载 发送消息
     */
    public void startDownLoadMsg(String fileName, String uuid) {
        try {
            emqKeeper.getMqttClient().publish(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()),
                    String.format(DOWN_LOAD_START_TEMP, uuid, fileName, new Date().getTime()).getBytes(StandardCharsets.UTF_8),
                    2, false);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }
    /**
     * 发送主题消息，给企业推送excel 结束下载提醒
     *
     * @param topic      主体格式为： /download/excel/${token}
     * @param jsonObject 文件名称 + excel文件路径（minio）
     */
    public void sendDownLoadExcelMsg(String topic, JSONObject jsonObject) {
        try {
            emqKeeper.getMqttClient().publish(topic, JSONObject.toJSONString(jsonObject).getBytes(StandardCharsets.UTF_8), 2, false);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 上传excel文件到minio服务器
     *
     * @param templateExcelFile 文件
     * @return minio文件路径
     */
    private String uploadExcelFile(MultipartFile templateExcelFile) {
        FeignClientResult<Map<String, String>> uploadResult = Systemctl.fileStorageClient.updateBucketFile(templateExcelFile, BUCKET_NAME, UPLOAD_PATH);

        String urlString = "";
        if (uploadResult != null && uploadResult.getResult() != null) {
            for (String s : uploadResult.getResult().keySet()) {
                urlString = s;
            }
        }
        return urlString;
    }


    /**
     * 企业人员导入
     *
     * @param multipartFile 导入的文件
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseModel<?> importCompanyUser(MultipartFile multipartFile, ReginParams reginParams) {
        CompanyBo company = reginParams.getCompany();
        List<CompanyUserImportDto> dataList = new ArrayList<>();
        ArrayList<String> sheetError = new ArrayList();
        // 用于手机号唯一判断 key：姓名-身份证号 value ：手机号
        // key保证数据唯一性
        Map<String, String> phoneOnly = new HashMap<>();
        Map<String, String> certificateNumOnly = new HashMap<>();
        try {
            InputStream inputStream = multipartFile.getInputStream();
            ExcelReader excelReader = EasyExcel.read(inputStream).build();
            List<ReadSheet> sheetList = excelReader.excelExecutor().sheetList(); // 获取所有 sheet
            for (ReadSheet readSheet : sheetList) {
                String sheetName = readSheet.getSheetName();
                int sheetNo = readSheet.getSheetNo();
                // 忽略 sheet页：企业人员录入限制（参考）
                if (sheetName.contains("企业人员录入限制")) {
                    continue;
                }
                // 人员信息 sheet页
                if (sheetName.contains("人员信息")) {
                    EasyExcel.read(multipartFile.getInputStream(), CompanyUserImportDto.class, new AnalysisEventListener<CompanyUserImportDto>() {
                        @Override
                        public void invoke(CompanyUserImportDto data, AnalysisContext context) {
                            companyUserCheckField(sheetError, sheetName, dataList, data, context.readRowHolder().getRowIndex() + 1, phoneOnly, certificateNumOnly, company);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext context) {
                        }
                    }).headRowNumber(2).sheet(sheetNo, sheetName).doRead();
                }

                // 检验资质信息 sheet页
                if (sheetName.contains("检验资质信息")) {
                    EasyExcel.read(multipartFile.getInputStream(), CompanyUserImportDto.InspectQualification.class, new AnalysisEventListener<CompanyUserImportDto.InspectQualification>() {
                        @Override
                        public void invoke(CompanyUserImportDto.InspectQualification data, AnalysisContext context) {
                            companyUserInspectCheckField(sheetError, sheetName, dataList, data, context.readRowHolder().getRowIndex() + 1);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext context) {
                        }
                    }).headRowNumber(2).sheet(sheetNo, sheetName).doRead();
                }

                // 检测资质信息 sheet页
                if (sheetName.contains("检测资质信息")) {
                    EasyExcel.read(multipartFile.getInputStream(), CompanyUserImportDto.TestingQualification.class, new AnalysisEventListener<CompanyUserImportDto.TestingQualification>() {
                        @Override
                        public void invoke(CompanyUserImportDto.TestingQualification data, AnalysisContext context) {
                            companyUserTestCheckField(sheetError, sheetName, dataList, data, context.readRowHolder().getRowIndex() + 1);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext context) {
                        }
                    }).headRowNumber(2).sheet(sheetNo, sheetName).doRead();
                }

                // 作业人员资质信息 sheet页
                if (sheetName.contains("作业人员资质信息")) {
                    EasyExcel.read(multipartFile.getInputStream(), CompanyUserImportDto.OperatorQualifications.class, new AnalysisEventListener<CompanyUserImportDto.OperatorQualifications>() {
                        @Override
                        public void invoke(CompanyUserImportDto.OperatorQualifications data, AnalysisContext context) {
                            companyUserOperatorQuaCheckField(sheetError, sheetName, dataList, data, context.readRowHolder().getRowIndex() + 1);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext context) {
                        }
                    }).headRowNumber(2).sheet(sheetNo, sheetName).doRead();
                }
            }
            // 存在检验不通过的数据则返回错误信息，不在向下写入库
            if (!sheetError.isEmpty()) {
                sendErrorContext(sheetError);
            }
            // 3.数据入库
            dataList.forEach(data -> {
                TzsUserInfoDto dto = new TzsUserInfoDto();
                BeanUtils.copyProperties(data, dto);
                dto.setCreateDate(new Date());
                try {
                    this.saveUserInfo(dto);
                } catch (Exception e) {
                    sheetError.add(dto.getName() + "-" + dto.getCertificateNum() + ":" + e.getMessage());
                }
            });
            // 第二次捕获save中的异常
            if (!sheetError.isEmpty()) {
                sendErrorContext(sheetError);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return ResponseHelper.buildResponse("success");
    }

    private void sendErrorContext(ArrayList<String> sheetError) throws IOException {
        // 发送错误文件
        String uuid = UUID.randomUUID().toString();
        startDownLoadMsg("人员导入错误文件", uuid);
        File tempFile = File.createTempFile("errors", ".txt");
        try (FileWriter writer = new FileWriter(tempFile)) {
            for (String error : sheetError) {
                writer.write(error + System.lineSeparator());
            }
        }
        byte[] fileContent = Files.readAllBytes(tempFile.toPath());
        MultipartFile mockMultipartFile = new MockMultipartFile("errors.txt", "errors.txt", "text/plain", fileContent);
        String urlString = this.uploadExcelFile(mockMultipartFile);
        sendDownLoadExcelMsg(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), new JSONObject()
                .fluentPut("id", uuid)
                .fluentPut("status", "done")
                .fluentPut("fileName", "人员导入错误文件")
                .fluentPut("url", urlString)
                .fluentPut("time", new Date().getTime()));
        tempFile.delete();
        throw new BadRequest("校验出错，请查看错误文件！");
    }

    private void companyUserCheckField(ArrayList<String> sheetError, String sheetName, List<CompanyUserImportDto> dataList,
                                       CompanyUserImportDto userItems, int excelRowNum, Map<String, String> phoneOnly, Map<String, String> certificateNumOnly,
                                       CompanyBo company) {
        ArrayList<String> errors = new ArrayList<>();
        // 1.必输校验
        Set<ConstraintViolation<CompanyUserImportDto>> violations = validator.validate(userItems);
        for (ConstraintViolation<CompanyUserImportDto> violation : violations) {
            errors.add("第" + excelRowNum + "行，错误信息->" + violation.getMessage());
        }

        // 2.手机号重复检验，手机号在本单位下唯一
        String key = userItems.getName() + "-" + userItems.getCertificateNum();
        // 2.1 当前上传数据比较
        if (!ValidationUtil.isEmpty(phoneOnly.get(key))) {
            errors.add("第" + excelRowNum + "行，错误信息->" + "手机号与" + key + "重复");
        } else if (!this.baseMapper.selectList(new LambdaQueryWrapper<TzsUserInfo>()
                .select(TzsUserInfo::getSequenceNbr)
                .eq(TzsUserInfo::getPhone, userItems.getPhone())
                .eq(TzsUserInfo::getUnitCode, company.getCompanyCode())
                .eq(TzsUserInfo::getIsDelete, Boolean.FALSE)).isEmpty()) { //2.2 本单位人员比较
            errors.add("第" + excelRowNum + "行，错误信息->" + "手机号已经绑定本单位人员");
        } else {
            phoneOnly.put(key, userItems.getPhone());
        }
        // 3.身份证重复检验，身份证在本单位下唯一
        // 3.1 当前上传数据比较
        if (!ValidationUtil.isEmpty(certificateNumOnly.get(userItems.getCertificateNum()))) {
            errors.add("第" + excelRowNum + "行，错误信息->" + "证件编号与" + userItems.getName() + "重复");
        } else if (!this.baseMapper.selectList(new LambdaQueryWrapper<TzsUserInfo>()
                .select(TzsUserInfo::getSequenceNbr)
                .eq(TzsUserInfo::getCertificateNum, userItems.getCertificateNum())
                .eq(TzsUserInfo::getUnitCode, company.getCompanyCode())
                .eq(TzsUserInfo::getIsDelete, Boolean.FALSE)).isEmpty()) { //2.2 本单位人员比较
            errors.add("第" + excelRowNum + "行，错误信息->" + "证件编号已经绑定本单位人员");
        } else {
            certificateNumOnly.put(userItems.getCertificateNum(), userItems.getName());
        }
        // 4.登录账号的单位类型和人员类型校验
        Map<String, String> allPostNames = this.postByUnitType(company).stream().collect(Collectors.toMap(DataDictionary::getName, DataDictionary::getCode));
        String postNameStr = userItems.getPost();
        if (!ValidationUtil.isEmpty(postNameStr)) {
            List<String> postNameList = Arrays.asList(postNameStr.replace("，", ",").replace("-", ",").replace("\n","").split(","));
            // postNameList 中，不存在于 allPostNames 中的元素
            List<String> notExistPosts = postNameList.stream()
                    .filter(p -> !allPostNames.containsKey(p))
                    .collect(Collectors.toList());
            if (!notExistPosts.isEmpty()) {
                errors.add("第" + excelRowNum + "行，错误信息->" + "不可以录入以下人员类型的数据：" + String.join(",", notExistPosts));
            }
            // 人员类型为："质量保证体系人员", "设计人员", "检查人员"时候，子类型为必填
            List<String> mustHasSub = Arrays.asList("质量保证体系人员", "设计人员", "检查人员", "作业人员");
            List<String> mustPost = postNameList.stream().filter(mustHasSub::contains).collect(Collectors.toList());
            if (!mustPost.isEmpty() && ValidationUtil.isEmpty(userItems.getSubPost())) {
                errors.add("第" + excelRowNum + "行，错误信息->" + "以下人员类型必须包含对应子类型：" + String.join(",", mustPost));
            }
            // 转化post
            userItems.setNewPost(new JSONArray(postNameList.stream().map(allPostNames::get).filter(Objects::nonNull).collect(Collectors.toList())).toString());
            postNameList.forEach(postName -> {
                // 5.人员类型和人员子类型的匹配
                String subPost = userItems.getSubPost();
                if (!ValidationUtil.isEmpty(subPost)) {
                    String subPostStr = subPost.replace("，", ",").replace("-", ",").replace("\n","");
                    List<String> subPostList = Arrays.asList(subPostStr.split(","));
                    String postCode = this.postByUnitType(company).stream().filter(item -> item.getName().equals(postName)).map(DataDictionary::getCode).findFirst().orElse("");
                    Map<String, String> allSubPostNames = this.subPostByUnitType(company, postCode).stream().collect(Collectors.toMap(DataDictionary::getName, DataDictionary::getCode));
                    if (ValidationUtil.isEmpty(allSubPostNames)) {
                        return;
                    }
                    // postList 中，不存在于 allPostNames 中的元素
                    List<String> notExistSubPosts = subPostList.stream()
                            .filter(p -> !allSubPostNames.containsKey(p))
                            .collect(Collectors.toList());
                    if (!notExistSubPosts.isEmpty()) {
                        errors.add("第" + excelRowNum + "行，错误信息->" + "不可以录入以下人员类型的数据：" + String.join(",", notExistSubPosts));
                    }
                    // 转化subPost
                    userItems.setSubPost(new JSONArray(subPostList.stream().map(allSubPostNames::get).collect(Collectors.toList())).toString());
                }
            });
        }

        if (!errors.isEmpty()) {
            sheetError.add(sheetName + "sheet页，" + errors);
        }
        // 汇总用户信息
        dataList.add(userItems);
    }

    /**
     * 检验资质信息
     */
    private void companyUserInspectCheckField(ArrayList<String> sheetError, String sheetName, List<CompanyUserImportDto> dataList,
                                              CompanyUserImportDto.InspectQualification inspectItem, int excelRowNum) {
        ArrayList<String> errors = new ArrayList<>();
        // 1.必输校验
        Set<ConstraintViolation<CompanyUserImportDto.InspectQualification>> violations = validator.validate(inspectItem);
        for (ConstraintViolation<CompanyUserImportDto.InspectQualification> violation : violations) {
            errors.add("第" + excelRowNum + "行，错误信息->" + violation.getMessage());
        }
        if (!errors.isEmpty()) {
            sheetError.add(sheetName + "sheet页，" + errors);
        }
        if (!ValidationUtil.isEmpty(inspectItem.getCertificateNum())) {
            dataList.forEach(data -> {
                if (!ValidationUtil.isEmpty(data.getCertificateNum()) && data.getCertificateNum().equals(inspectItem.getCertificateNum())) {
                    JSONArray permissionData66151 = data.getPermissionData66151();
                    permissionData66151.add(inspectItem);
                    data.setPermissionData66151(permissionData66151);
                }
            });
        }
    }

    /**
     * 检测资质信息
     */
    private void companyUserTestCheckField(ArrayList<String> sheetError, String sheetName, List<CompanyUserImportDto> dataList,
                                           CompanyUserImportDto.TestingQualification testQua, int excelRowNum) {
        ArrayList<String> errors = new ArrayList<>();
        // 1.必输校验
        Set<ConstraintViolation<CompanyUserImportDto.TestingQualification>> violations = validator.validate(testQua);
        for (ConstraintViolation<CompanyUserImportDto.TestingQualification> violation : violations) {
            errors.add("第" + excelRowNum + "行，错误信息->" + violation.getMessage());
        }
        if (!errors.isEmpty()) {
            sheetError.add(sheetName + "sheet页，" + errors);
        }
        if (!ValidationUtil.isEmpty(testQua.getCertificateNum())) {
            dataList.forEach(data -> {
                if (!ValidationUtil.isEmpty(data.getCertificateNum()) && data.getCertificateNum().equals(testQua.getCertificateNum())) {
                    JSONArray permissionData66152 = data.getPermissionData66152();
                    permissionData66152.add(testQua);
                    data.setPermissionData66152(permissionData66152);
                }
            });
        }
    }

    /**
     * 作业人员资质信息
     */
    private void companyUserOperatorQuaCheckField(ArrayList<String> sheetError, String sheetName, List<CompanyUserImportDto> dataList,
                                                  CompanyUserImportDto.OperatorQualifications OperatorQua, int excelRowNum) {
        ArrayList<String> errors = new ArrayList<>();
        // 1.必输校验
        Set<ConstraintViolation<CompanyUserImportDto.OperatorQualifications>> violations = validator.validate(OperatorQua);
        for (ConstraintViolation<CompanyUserImportDto.OperatorQualifications> violation : violations) {
            errors.add("第" + excelRowNum + "行，错误信息->" + violation.getMessage());
        }
        if (!errors.isEmpty()) {
            sheetError.add(sheetName + "sheet页，" + errors);
        }
        if (!ValidationUtil.isEmpty(OperatorQua.getCertificateNum())) {
            dataList.forEach(data -> {
                if (!ValidationUtil.isEmpty(data.getCertificateNum()) && data.getCertificateNum().equals(OperatorQua.getCertificateNum())) {
                    JSONArray permissionData6552 = data.getPermissionData6552();
                    JSONArray objects = new JSONArray();
                    objects.add(OperatorQua.getJobItemStr());
                    OperatorQua.setJobItem(objects);
                    permissionData6552.add(OperatorQua);
                    data.setPermissionData6552(permissionData6552);
                }
            });
        }
    }

//    private Map<Long, CompanyUserImportDto> saveCompanyUserImportData2Db(Set<CompanyUserImportDto> userSet) {
//        List<TzsUserInfo> userInfos = userSet.parallelStream().map(dto -> {
//            TzsUserInfo userInfo = new TzsUserInfo();
//            userInfo.setRecUserId(RequestContext.getExeUserId());
//            userInfo.setRecDate(new Date());
//            userInfo.setName(dto.getName());
//            userInfo.setSequenceNbr(dto.getSeq());
//            userInfo.setGender(dto.getGender());
//            userInfo.setEmail(dto.getEmail());
//            userInfo.setPhone(dto.getPhone());
//            userInfo.setAddress(dto.getAddress());
//            Set<String> postSet = dto.getUnitTypePostMap().values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
//            // TODO 无资质导入，默认post = newPost
//            userInfo.setPost(JSON.toJSONString(postSet));
//            // TODO 无资质导入，默认post = newPost
//            userInfo.setNewPost(JSON.toJSONString(postSet));
//            String postName = this.setPostName(userInfo.getNewPost());
//            userInfo.setPostName(postName);
//            userInfo.setBirthday(dto.getBirthday());
//            userInfo.setEducation(dto.getEducation());
//            userInfo.setSpeciality(dto.getSpeciality());
//            userInfo.setUnitName(dto.getUnitName());
//            userInfo.setCertificateNum(dto.getCertificateNum());
//            userInfo.setCertificateType(dto.getCertificateType());
//            userInfo.setIsDelete(false);
//            userInfo.setLockStatus(UNLOCK);
//            userInfo.setUnitCode(dto.getUnitCode());
//            userInfo.setEquipType(dto.getEquipType());
//            userInfo.setJobTitle(dto.getJobTitle());
//            userInfo.setEquipType(JSON.toJSONString(dto.getEquipTypeList()));
//            return userInfo;
//        }).collect(Collectors.toList());
//        super.saveOrUpdateBatch(userInfos);
//        return userInfos.stream().collect(Collectors.toMap(BaseEntity::getSequenceNbr, Function.identity()));
//    }

    private void createAmosUserWithCompanyImport(Map<Long, TzsUserInfo> userInfoMap, Set<UserImportDto> userSet) {
        // 1.公共数据处理
        //   1.1公司缓存
        Map<String, CompanyModel> companyCodeCompanyMap = new ConcurrentHashMap<>();
        Map<Long, UserImportDto> userSeqImportDataMap = userSet.stream().collect(Collectors.toMap(UserImportDto::getSeq, Function.identity()));
        //   1.2单位类型下角色缓存
        List<DataDictionary> unitTypeList = regUnitInfoService.setAndGetUnitTypeList();
        Map<String, DataDictionary> dataDictionaryMap = unitTypeList.stream().collect(Collectors.toMap(DataDictionary::getName, Function.identity(), (k1, k2) -> k1));
        //   1.3通用角色-普通用户处理
        List<RoleModel> allRoleList = getCommonRoleModels();
        // 2.用户创建
        //  2.1创建前检验-单位类型是否合法（用户的单位类型不能大于所在公司的注册时的单位类型）
        userInfoMap.forEach((k, v) -> {
            checkOneUser(v, userSeqImportDataMap.get(k), companyCodeCompanyMap);
        });
        //  2.2创建
        userInfoMap.forEach((k, v) -> {
            createOneUser(v, userSeqImportDataMap.get(k), companyCodeCompanyMap, dataDictionaryMap, allRoleList);
        });
        // 3.绑定用户到用户组
        this.bindUserToGroup(userInfoMap.values());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseModel<?> importUserBatch(MultipartFile multipartFile) {
        Map<Long, TzsUserInfo> userInfoMap = new HashMap<>();
        try {
            List<UserImportDto> userItems = ExcelUtil.readFirstSheetExcel(multipartFile, UserImportDto.class, 2);
            // 1.数据检验
            List<String> errors = checkFieldIsValid(userItems);
            // 1.1存在检验不通过的数据则进行提示，不在向下写入库
            if (!errors.isEmpty()) {
                return ResponseHelper.buildResponse(errors);
            }
            // 2.数据处理
            // 2.1数据合并:按照手机号数据去重合并
            Set<UserImportDto> userSet = new HashSet<>(userItems);
            // 2.2合并构造单位类型+人员类型，处理一个人有多个单位类型+多个人员类型
            this.buildMergeFields(userItems, userSet);
            // 3.数据入库
            // 3.1业务库入库
            userInfoMap = this.saveImportData2Db(userSet);
            // 3.2部分类型用户平台创建人员
            this.createAmosUser(userInfoMap, userSet);
        } catch (Exception e) {
            if (!userInfoMap.values().isEmpty()) {
                List<String> userIds = userInfoMap.values().stream().map(TzsUserInfo::getAmosUserId).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
                for (String userId : userIds) {
                    // 单个删除，平台接口删除时，判断了有才能删除，匹配删除可能存在某个用户不存在导致删除失败
                    try {
                        Privilege.agencyUserClient.multDeleteUser(userId);
                    } catch (Exception e1) {
                        log.error("删除用户：{}，失败:{}！", userId, e1.getMessage());
                    }
                }
            }
            throw new RuntimeException(e);
        }
        return ResponseHelper.buildResponse("succese");
    }

    private void createAmosUser(Map<Long, TzsUserInfo> userInfoMap, Set<UserImportDto> userSet) {
        // 1.公共数据处理
        //   1.1公司缓存
        Map<String, CompanyModel> companyCodeCompanyMap = new ConcurrentHashMap<>();
        Map<Long, UserImportDto> userSeqImportDataMap = userSet.stream().collect(Collectors.toMap(UserImportDto::getSeq, Function.identity()));
        //   1.2单位类型下角色缓存
        List<DataDictionary> unitTypeList = regUnitInfoService.setAndGetUnitTypeList();
        Map<String, DataDictionary> dataDictionaryMap = unitTypeList.stream().collect(Collectors.toMap(DataDictionary::getName, Function.identity(), (k1, k2) -> k1));
        //   1.3通用角色-普通用户处理
        List<RoleModel> allRoleList = getCommonRoleModels();
        // 2.用户创建
        //  2.1创建前检验-单位类型是否合法（用户的单位类型不能大于所在公司的注册时的单位类型）
        userInfoMap.forEach((k, v) -> {
            checkOneUser(v, userSeqImportDataMap.get(k), companyCodeCompanyMap);
        });
        //  2.2创建
        userInfoMap.forEach((k, v) -> {
            createOneUser(v, userSeqImportDataMap.get(k), companyCodeCompanyMap, dataDictionaryMap, allRoleList);
        });
        // 3.绑定用户到用户组
        this.bindUserToGroup(userInfoMap.values());
    }

    private void bindUserToGroup(Collection<TzsUserInfo> values) {
        List<String> userIds = values.stream().map(TzsUserInfo::getAmosUserId).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
        try {
            if (!userIds.isEmpty()) {
                // 绑定企业整改用户组
                String roleGroupCode = "6596";
                DataDictionary roleGroup = iDataDictionaryService
                        .getOne(new LambdaQueryWrapper<DataDictionary>().eq(DataDictionary::getCode, roleGroupCode).eq(DataDictionary::getType, ROLE_GROUP));
                if (!ObjectUtils.isEmpty(roleGroup) && roleGroup.getExtend() != null) {
                    Privilege.groupUserClient.create(Long.valueOf(roleGroup.getExtend()), userIds);
                }
                // 绑定两个规定用户组
                for (TzsUserInfo userInfo : values) {
                    String newPost = userInfo.getPost();
                    List<String> posts = Optional.ofNullable(JSONArray.parseArray(newPost, String.class)).orElse(new ArrayList<>());
                    for (String code : posts) {
                        bind2PermissionGroup(Collections.singletonList(userInfo.getAmosUserId()), code);
                    }
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BadRequest(e.getMessage());
        }
    }

    /**
     * 两个规定用户组绑定
     *
     * @param userIds 用户id
     * @param post    人员类型
     */
    private void bind2PermissionGroup(List<String> userIds, String post) {
        // post    name            用户组id
        // 6549	  安全员	        1712372048442978305
        // 6548	  主要负责人	    1712372027123331074
        // 6547	  安全总监	    1712372007611428865
        // 6546	  普通员工	    1712371988107915266
        // 6552	  作业人员	    1712372137114759170
        // 6551	  质量安全员	    1712372116055158786
        // 6550	  质量安全总监	1712372080231608322
        DataDictionary groupId = iDataDictionaryService.getOne(new LambdaQueryWrapper<DataDictionary>().eq(DataDictionary::getCode, post).likeRight(DataDictionary::getType, QYRYGW));
        if (!ObjectUtils.isEmpty(groupId) && groupId.getExtend() != null) {
            Privilege.groupUserClient.create(Long.valueOf(groupId.getExtend()), userIds);
        }
    }

    private List<RoleModel> getCommonRoleModels() {
        String commonRule = "1554";
        List<RoleModel> allRoleList = new ArrayList<>();
        DataDictionary unitType = iDataDictionaryService.getOne(new LambdaQueryWrapper<DataDictionary>().eq(DataDictionary::getCode, commonRule).eq(DataDictionary::getType, USER_ROLE));
        String role = unitType.getExtend() != null ? unitType.getExtend() : "";
        for (String s : role.split(",")) {
            RoleModel roleModel = Privilege.roleClient.seleteOne(Long.valueOf(s)).getResult();
            allRoleList.add(roleModel);
        }
        return allRoleList;
    }

    private Map<Long, TzsUserInfo> saveImportData2Db(Set<UserImportDto> userSet) {
        List<TzsUserInfo> userInfos = userSet.parallelStream().map(dto -> {
            TzsUserInfo userInfo = new TzsUserInfo();
            userInfo.setRecUserId(RequestContext.getExeUserId());
            userInfo.setRecDate(new Date());
            userInfo.setName(dto.getName());
            userInfo.setSequenceNbr(dto.getSeq());
            userInfo.setGender(dto.getGender());
            userInfo.setEmail(dto.getEmail());
            userInfo.setPhone(dto.getPhone());
            userInfo.setAddress(dto.getAddress());
            Set<String> postSet = dto.getUnitTypePostMap().values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
            // TODO 无资质导入，默认post = newPost
            userInfo.setPost(JSON.toJSONString(postSet));
            // TODO 无资质导入，默认post = newPost
            userInfo.setNewPost(JSON.toJSONString(postSet));
            String postName = this.setPostName(userInfo.getNewPost());
            userInfo.setPostName(postName);
            userInfo.setBirthday(dto.getBirthday());
            userInfo.setEducation(dto.getEducation());
            userInfo.setSpeciality(dto.getSpeciality());
            userInfo.setUnitName(dto.getUnitName());
            userInfo.setCertificateNum(dto.getCertificateNum());
            userInfo.setCertificateType(dto.getCertificateType());
            userInfo.setIsDelete(false);
            userInfo.setLockStatus(UNLOCK);
            userInfo.setUnitCode(dto.getUnitCode());
            userInfo.setEquipType(dto.getEquipType());
            userInfo.setJobTitle(dto.getJobTitle());
            userInfo.setEquipType(JSON.toJSONString(dto.getEquipTypeList()));
            return userInfo;
        }).collect(Collectors.toList());
        super.saveOrUpdateBatch(userInfos);
        return userInfos.stream().collect(Collectors.toMap(BaseEntity::getSequenceNbr, Function.identity()));
    }

    private void buildMergeFields(List<UserImportDto> userItems, Set<UserImportDto> userSet) {
        for (UserImportDto userImportDto : userSet) {
            List<UserImportDto> oData = userItems.stream().filter(u -> u.getPhone().equals(userImportDto.getPhone())).collect(Collectors.toList());
            for (UserImportDto user : oData) {
                Map<String, Set<String>> map = userImportDto.getUnitTypePostMap();
                if (map == null) {
                    map = new HashMap<>();
                    map.put(user.getUnitType(), Sets.newHashSet(user.getPost()));
                    userImportDto.setUnitTypePostMap(map);
                } else {
                    map.get(user.getUnitType()).add(user.getPost());
                }
                Set<String> equipTypes = userImportDto.getEquipTypeList();
                if (equipTypes == null) {
                    Set<String> equipTypesNew = new HashSet<>();
                    equipTypesNew.add(user.getEquipType());
                    userImportDto.setEquipTypeList(equipTypesNew);
                } else {
                    equipTypes.add(user.getEquipType());
                }
            }
            userImportDto.getEquipTypeList().remove(null);
            userImportDto.getEquipTypeList().remove("");
            userImportDto.setSeq(sequence.nextId());
        }

    }

    public void checkOneUser(TzsUserInfo tzsUserInfo, UserImportDto userImportDto, Map<String, CompanyModel> companyCodeCompanyMap) {
        CompanyModel companyModel = getCompanyModelUseCache(tzsUserInfo, companyCodeCompanyMap);
        String companyType = companyModel.getCompanyType();
        // 增加约束，增加的人的单位类型不能大于单位的单位类型
        boolean existIllegalUnitType = userImportDto.getUnitTypePostMap().keySet().stream().anyMatch(u -> !companyType.contains(u));
        if (existIllegalUnitType) {
            throw new BadRequest("导入的用户：" + tzsUserInfo.getName() + "，手机号：" + tzsUserInfo.getPhone() + "，公司类型只能为：" + companyType + "之一！");
        }
    }

    public void createOneUser(TzsUserInfo tzsUserInfo, UserImportDto userImportDto, Map<String, CompanyModel> companyCodeCompanyMap, Map<String, DataDictionary> dataDictionaryMap, List<RoleModel> allRoleList) {
        FeignClientResult<AgencyUserModel> userResult = null;
        try {
            CompanyModel companyModel = getCompanyModelUseCache(tzsUserInfo, companyCodeCompanyMap);
            String companyType = companyModel.getCompanyType();
            // 默认的密码
            String passwd = DesUtil.encode("a_" + tzsUserInfo.getPhone(), "qaz");
            // 获取对应单位类型下的引用并去重
            Set<String> appCodesSet = getAppKeys(userImportDto, dataDictionaryMap);
            List<Long> roleIds = new ArrayList<>();
            allRoleList.forEach(r -> {
                if (!roleIds.contains(r.getSequenceNbr())) {
                    roleIds.add(r.getSequenceNbr());
                }
            });
            AgencyUserModel agencyUserModel = new AgencyUserModel();
            agencyUserModel.setUserName(tzsUserInfo.getPhone());
            agencyUserModel.setRealName(tzsUserInfo.getName());
            agencyUserModel.setLockStatus(UNLOCK);
            agencyUserModel.setPassword(passwd);
            agencyUserModel.setRePassword(passwd);
            agencyUserModel.setAgencyCode("tzs");
            agencyUserModel.setMobile(tzsUserInfo.getPhone());
            agencyUserModel.setEmail(tzsUserInfo.getEmail());
            // 添加业务办理人员角色
            String post = tzsUserInfo.getPost();
            if (post.contains(PersonManageRoleEnum.code.getId().toString())) {
                setBizOperateUserRole(companyType, roleIds);
            }
            Map<Long, List<Long>> roleSeqMap = new HashMap<>();
            Map<Long, List<RoleModel>> orgRoles = new HashMap<>();
            roleSeqMap.put(companyModel.getSequenceNbr(), roleIds);
            orgRoles.put(companyModel.getSequenceNbr(), allRoleList);
            agencyUserModel.setAppCodes(new ArrayList<>(appCodesSet));
            agencyUserModel.setOrgRoles(orgRoles);
            agencyUserModel.setOrgRoleSeqs(roleSeqMap);
            userResult = Privilege.agencyUserClient.create(agencyUserModel);
            tzsUserInfo.setAmosUserId(userResult.getResult().getUserId());
            tzsUserInfo.setAmosUserName(userResult.getResult().getUserName());
            tzsUserInfo.setLockStatus(UNLOCK);
            tzsUserInfo.setUnitName(companyModel.getCompanyName());
            tzsUserInfoMapper.updateById(tzsUserInfo);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            // 防止 创建成功后tzsUserInfo.setAmosUserId(userResult.getResult().getUserId()) 报错导致外侧删除不成功，健壮性处理，正常不会出错
            if (userResult != null && userResult.getResult() != null
                    && StringUtils.isNotEmpty(userResult.getResult().getUserId())) {
                Privilege.agencyUserClient.multDeleteUser(userResult.getResult().getUserId());
            }
            if (e instanceof InnerInvokException) {
                String message = e.getLocalizedMessage();
                if (StringUtils.isNotEmpty(message) && message.contains("用户名已存在")) {
                    throw new BadRequest("手机号：" + tzsUserInfo.getPhone() + "已经被使用，请更换！");
                }
            }
            throw new BadRequest(e.getMessage());
        }
    }

    private CompanyModel getCompanyModelUseCache(TzsUserInfo tzsUserInfo, Map<String, CompanyModel> companyCodeCompanyMap) {
        CompanyModel companyModel;
        if (companyCodeCompanyMap.get(tzsUserInfo.getUnitCode()) != null) {
            companyModel = companyCodeCompanyMap.get(tzsUserInfo.getUnitCode());
        } else {
            companyModel = baseEnterpriseInfoService.getBaseMapper().getOneByCompanyCode(tzsUserInfo.getUnitCode());
            if (companyModel == null) {
                throw new BadRequest("单位统一信用代码为：" + tzsUserInfo.getUnitCode() + "的单位还未进行注册，请确认数据是否正确！");
            }
            companyCodeCompanyMap.put(tzsUserInfo.getUnitCode(), companyModel);
        }
        return companyModel;
    }

    private static Set<String> getAppKeys(UserImportDto userImportDto, Map<String, DataDictionary> dataDictionaryMap) {
        Set<String> appCodesSet = new HashSet<>();
        userImportDto.getUnitTypePostMap().forEach((k, v) -> {
            DataDictionary unitType = dataDictionaryMap.get(k);
            String appCode = unitType.getTypeDesc() != null ? unitType.getTypeDesc() : "";
            String[] appCodes = appCode.split(",");
            Collections.addAll(appCodesSet, appCodes);
        });
        return appCodesSet;
    }

    private void setBizOperateUserRole(String companyType, List<Long> roleIds) {
        if (companyType.contains(PersonManageRoleEnum.jyjc.getName())) {
            roleIds.add(PersonManageRoleEnum.jyjc.getId());
        }
        if (companyType.contains(PersonManageRoleEnum.use.getName())) {
            roleIds.add(PersonManageRoleEnum.use.getId());
        }
        if (companyType.contains(PersonManageRoleEnum.agw.getName())) {
            roleIds.add(PersonManageRoleEnum.agw.getId());
        }
    }

    /**
     * 需求3321 人员管理分类调整，删除部分人员子类型对应的历史数据
     *
     * @return 修正数据
     */
    @Override
    public String deletePersonSubtypeHistoricalData() {
        int nums = 0;
        // 要删除的岗位ID
        List<String> subPostsToRemove = Arrays.asList("6711", "6710", "6709", "6712");
        List<TzsUserInfo> tzsUserInfos = this.getBaseMapper().selectList(
                new LambdaQueryWrapper<TzsUserInfo>()
                        .eq(TzsUserInfo::getIsDelete, Boolean.FALSE)
                        .like(TzsUserInfo::getNewPost, "6552")
                        .and(x -> x.like(TzsUserInfo::getSubPost, "6711")
                                .or().like(TzsUserInfo::getSubPost, "6710")
                                .or().like(TzsUserInfo::getSubPost, "6709")
                                .or().like(TzsUserInfo::getSubPost, "6712")
                        )
        );
        // 遍历处理数据
        for (TzsUserInfo userInfo : tzsUserInfos) {
            String subPostJson = userInfo.getSubPost();
            ObjectMapper mapper = new ObjectMapper();
            try {
                List<String> subPosts = mapper.readValue(subPostJson, new TypeReference<List<String>>() {
                });
                // 过滤掉要删除的值
                List<String> updatedSubPosts = subPosts.stream()
                        .filter(val -> !subPostsToRemove.contains(val))
                        .collect(Collectors.toList());
                // 转回 JSON 字符串
                String newSubPostJson = mapper.writeValueAsString(updatedSubPosts);
                userInfo.setSubPost(updatedSubPosts.isEmpty() ? null : newSubPostJson);
                if (updatedSubPosts.isEmpty()) {
                    userInfo.setSubPostName(null);
                } else {
                    String newSubPostNameJson = iDataDictionaryService.lambdaQuery()
                            .in(DataDictionary::getCode, updatedSubPosts)
                            .orderByAsc(DataDictionary::getSortNum)
                            .select(DataDictionary::getName)
                            .list()
                            .stream()
                            .map(DataDictionary::getName)
                            .collect(Collectors.joining(","));
                    userInfo.setSubPostName(newSubPostNameJson);
                }
                this.getBaseMapper().updateById(userInfo);
                ++nums;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return String.format("修正数据 %s 条。", nums);
    }

    @Value("classpath:/json/unitTypeLimitUserType.json")
    private Resource unitTypeLimitUserType;

    private JsonNode postData;

    @PostConstruct
    public void init() {
        try {
            postData = new ObjectMapper().readTree(unitTypeLimitUserType.getInputStream());
        } catch (IOException e) {
            throw new RuntimeException("Failed to read or parse JSON data", e);
        }
    }

    // 接口用于人员详情界面 企业 ＋ 监管单位 都会看到
    @Override
    public List<DataDictionary> postByUnitType(CompanyBo company) {
        ArrayList<String> postDictCodeList = new ArrayList<>();
        if (company.getCompanyType().equals("监管机构")) {
            return this.getAllUserType();
        }
        TzBaseEnterpriseInfo enterpriseInfo = baseEnterpriseInfoService.lambdaQuery()
                .eq(TzBaseEnterpriseInfo::getUseCode, company.getCompanyCode())
                .one();
        List<String> unitTypes = Arrays.asList(enterpriseInfo.getUnitType().split("#"));
        unitTypes.forEach(unitType -> {
            JsonNode companyTypeNode = postData.get(unitType);
            if (companyTypeNode != null && companyTypeNode.isObject()) {
                Iterator<Map.Entry<String, JsonNode>> fields = companyTypeNode.fields();
                while (fields.hasNext()) {
                    Map.Entry<String, JsonNode> entry = fields.next();
                    String postCode = entry.getKey();
                    postDictCodeList.add(postCode); // 主岗位
                }
            }
        });
        return this.getAllUserType().stream()
                .filter(item -> postDictCodeList.contains(item.getCode()))
                .collect(Collectors.toList());
    }

    /**
     * 根据单位类型和父类型查询对应的人员类型子类型
     * * 接口用于人员详情界面 企业 ＋ 监管单位 都会看到
     *
     * @param company    登录人公司信息
     * @param parentCode 父人员类型code
     * @return result
     */
    @Override
    public List<DataDictionary> subPostByUnitType(CompanyBo company, String parentCode) {

        ArrayList<String> parentCodeList = new ArrayList<>(Arrays.asList(parentCode.split(",")));

        if (company.getCompanyType().equals("监管机构")) {
            return iDataDictionaryService.lambdaQuery()
                    .in(DataDictionary::getParent, parentCodeList)
                    .like(DataDictionary::getType, "QYRYGW")
                    .orderByAsc(DataDictionary::getSortNum)
                    .list();
        }

        List<DataDictionary> result = new ArrayList<>();
        // 该注册单位所具有的所有的单位类型下的人员类型
        Map<String, JsonNode> allPostUnderTheUnit = new HashMap<>();
        TzBaseEnterpriseInfo enterpriseInfo = baseEnterpriseInfoService.lambdaQuery()
                .eq(TzBaseEnterpriseInfo::getUseCode, company.getCompanyCode())
                .one();
        List<String> unitTypes = Arrays.asList(enterpriseInfo.getUnitType().split("#"));
        unitTypes.forEach(unitType -> {
            JsonNode companyTypeNode = postData.get(unitType);
            if (companyTypeNode != null && companyTypeNode.isObject()) {
                Iterator<Map.Entry<String, JsonNode>> fields = companyTypeNode.fields();
                while (fields.hasNext()) {
                    Map.Entry<String, JsonNode> entry = fields.next();
                    String postCode = entry.getKey();// 主岗位
                    JsonNode subPostCode = entry.getValue();// 子岗位
                    allPostUnderTheUnit.put(postCode, subPostCode);
                }
            }
        });
        allPostUnderTheUnit.forEach((postCode, subPostCode) -> {
            if (parentCodeList.contains(postCode)) {
                ArrayList<String> subPostDictCodeList = new ArrayList<>();
                if (subPostCode.isArray()) {
                    for (JsonNode subPost : subPostCode) {
                        if (!subPost.isNull()) {
                            subPostDictCodeList.add(subPost.asText()); // 子岗位
                        }
                    }
                }
                // subPostDictCodeList 值不为空说明有限制，按照限制来 ，为空按照父类型code查询所有
                if (!subPostDictCodeList.isEmpty()) {
                    result.addAll(iDataDictionaryService.lambdaQuery()
                            .in(DataDictionary::getCode, subPostDictCodeList)
                            .like(DataDictionary::getType, "QYRYGW")
                            .orderByAsc(DataDictionary::getSortNum)
                            .list());
                } else {
                    result.addAll(iDataDictionaryService.lambdaQuery()
                            .in(DataDictionary::getParent, postCode)
                            .like(DataDictionary::getType, "QYRYGW")
                            .orderByAsc(DataDictionary::getSortNum)
                            .list());
                }
            }
        });
        return result;
    }

    @Override
    public TzIndividualityDto individualityByCompanyCode(String companyCode) {
        TzIndividualityDto individuality = new TzIndividualityDto();
        TzBaseEnterpriseInfoDto baseEnterpriseInfoDto = baseEnterpriseInfoService.getInfoByUseCode(companyCode);
        if (!ValidationUtil.isEmpty(baseEnterpriseInfoDto)) {
            individuality = individualityMapper.getIndividualityInfo(baseEnterpriseInfoDto.getSequenceNbr());
            individuality.setPhone(baseEnterpriseInfoDto.getContactPhone());
            individuality.setGoverningBody(baseEnterpriseInfoDto.getGoverningBody());
            individuality.setAddress(baseEnterpriseInfoDto.getAddress());
        }
        return individuality;
    }

    @Transactional (rollbackFor = Exception.class)
    @Override
    public TzIndividualityDto personalInfoUpdateById(Map<String, Object> map) {
        TzsBaseIndividuality individuality = individualityMapper.selectById(Long.valueOf(map.get("sequenceNbr").toString()));
        TzBaseEnterpriseInfo baseEnterpriseInfo = baseEnterpriseInfoService.getBaseMapper().selectById(individuality.getEnterpriseId());

        baseEnterpriseInfo.setContactPhone(ObjectUtils.isEmpty(map.get("phone")) ? null : (String) map.get("phone"));
        baseEnterpriseInfo.setGoverningBody(ObjectUtils.isEmpty(map.get("governingBody")) ? null : (String) map.get("governingBody"));
        baseEnterpriseInfo.setAddress(ObjectUtils.isEmpty(map.get("address")) ? null : (String) map.get("address"));
        individuality.setRealName(ObjectUtils.isEmpty(map.get("name")) ? null : (String) map.get("name"));
        individuality.setExpirationDateStart(ObjectUtils.isEmpty(map.get("expirationDateStart")) ? null : (String) map.get("expirationDateStart"));
        individuality.setExpirationDateEnd(ObjectUtils.isEmpty(map.get("expirationDateEnd")) ? null : (String) map.get("expirationDateEnd"));
        individuality.setCredentialsNum(ObjectUtils.isEmpty(map.get("credentialsNum")) ? null : (String) map.get("credentialsNum"));
        individuality.setCredentialsType(ObjectUtils.isEmpty(map.get("credentialsType")) ? null : (String) map.get("credentialsType"));
        individuality.setIdentificationPhoto(ObjectUtils.isEmpty(map.get("identificationPhoto")) ? null : JSON.toJSONString(map.get("identificationPhoto")));
        individuality.setExpirationDateType(ObjectUtils.isEmpty(map.get("expirationDateType")) ? null : (String) map.get("expirationDateType"));

        individualityMapper.updateById(individuality);
        baseEnterpriseInfoService.updateById(baseEnterpriseInfo);

        TzIndividualityDto individualityDto = new TzIndividualityDto();
        BeanUtils.copyProperties(individuality, individualityDto);
        return individualityDto;
    }

    private void syncNewPost(TzsUserInfoDto tzsUserInfoDto) {
        System.out.println(tzsUserInfoDto);
        // tzs_user_info;
        if (ValidationUtil.isEmpty(tzsUserInfoDto.getAmosUserId())) {
            return;
        }
        FeignClientResult<AgencyUserModel> userFeignClientResult = Privilege.agencyUserClient.queryByUserId(tzsUserInfoDto.getAmosUserId());
        if (userFeignClientResult == null || userFeignClientResult.getResult() == null) {
            return;
        }
        ReginParams reginParams = JSON.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
        if (ObjectUtils.isEmpty(reginParams)) {
            return ;
        }
        List<DataDictionary> dataDictionaries = iDataDictionaryService.lambdaQuery()
                              .in(DataDictionary::getType, Arrays.asList("QYRYJS", "QYRYYHZ"))
                              .eq(DataDictionary::getIsDelete, false).list();

        List<DataDictionary> qyrygwList = dataDictionaries.stream().filter(item -> "QYRYJS".equals(item.getType())).collect(Collectors.toList());
        List<DataDictionary> qyryyhzList = dataDictionaries.stream().filter(item -> "QYRYYHZ".equals(item.getType())).collect(Collectors.toList());

        String roles = qyrygwList.get(0).getCode();
        String roleGroupCode = qyryyhzList.get(0).getCode();

        Long companySeq = reginParams.getCompany().getSequenceNbr();
        List<String> appCodesSet = reginParams.getUserModel().getAppCodes();
        List<RoleModel> allRoleList = new ArrayList<>();
        List<Long> roleIds = new ArrayList<>();
        DataDictionary unitType = iDataDictionaryService.getOne(new LambdaQueryWrapper<DataDictionary>().eq(DataDictionary::getCode, roles).eq(DataDictionary::getType, USER_ROLE));
        String role = unitType.getExtend() != null ? unitType.getExtend() : "";
        for (String s : role.split(",")) {
            RoleModel roleModel = Privilege.roleClient.seleteOne(Long.valueOf(s)).getResult();
            allRoleList.add(roleModel);
        }
        allRoleList.forEach(r -> {
            if (!roleIds.contains(r.getSequenceNbr())) {
                roleIds.add(r.getSequenceNbr());
            }
        });
        // 添加人员管理角色
        String post = tzsUserInfoDto.getPost();
        if (post.contains(PersonManageRoleEnum.code.getId().toString())) {
            CompanyModel companyModel = Optional.ofNullable(Privilege.companyClient.seleteOne(companySeq)).map(FeignClientResult::getResult).orElse(null);
            if (!ValidationUtil.isEmpty(companyModel)) {
                String companyType = companyModel.getCompanyType();
                setBizOperateUserRole(companyType, roleIds);
            }
        }
        Map<Long, List<Long>> roleSeqMap = new HashMap<>();
        Map<Long, List<RoleModel>> orgRoles = new HashMap<>();
        roleSeqMap.put(companySeq, roleIds);
        orgRoles.put(companySeq, allRoleList);

        AgencyUserModel agencyUserModel = userFeignClientResult.getResult();
        agencyUserModel.setAppCodes(new ArrayList<>(appCodesSet));
        agencyUserModel.setOrgRoles(orgRoles);
        agencyUserModel.setOrgRoleSeqs(roleSeqMap);
        FeignClientResult<AgencyUserModel> userResult = Privilege.agencyUserClient.update(agencyUserModel, tzsUserInfoDto.getAmosUserId());
        if (userResult.getStatus() == 200) {
            // 绑定企业整改用户组
            List<String> userIds = new ArrayList<>();
            userIds.add(userResult.getResult().getUserId());
            DataDictionary roleGroup = iDataDictionaryService
                    .getOne(new LambdaQueryWrapper<DataDictionary>().eq(DataDictionary::getCode, roleGroupCode).eq(DataDictionary::getType, ROLE_GROUP));
            if (!ObjectUtils.isEmpty(roleGroup) && roleGroup.getExtend() != null) {
                Privilege.groupUserClient.create(Long.valueOf(roleGroup.getExtend()), userIds);
            }
            // 绑定两个规定用户组
            post = post.replace("[", "").replace("]", "").replace("\"", "");
            for (String code : post.split(",")) {
                DataDictionary groupId = iDataDictionaryService.getOne(new LambdaQueryWrapper<DataDictionary>().eq(DataDictionary::getCode, code).likeRight(DataDictionary::getType, QYRYGW));
                if (!ObjectUtils.isEmpty(groupId) && groupId.getExtend() != null) {
                    Privilege.groupUserClient.deleteGroupUser(Long.valueOf(groupId.getExtend()), userResult.getResult().getUserId());
                    Privilege.groupUserClient.create(Long.valueOf(groupId.getExtend()), userIds);
                }
            }
        }
    }
}
