package jnpf.personnels.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jnpf.base.ActionResult;
import jnpf.base.vo.PageListVO;
import jnpf.base.vo.PaginationVO;
import jnpf.model.cultivate.CultivatePage;
import jnpf.model.personnels.dto.analysis.FtbPersonnlesAnalysisDTO;
import jnpf.model.personnels.dto.range.RangeDTO;
import jnpf.model.personnels.dto.staff.roster.WorkerGroupDataDto;
import jnpf.model.personnels.po.FtbPersonnelsRegistrationFormField;
import jnpf.model.personnels.po.FtbPersonnelsRegistrationFormFieldOption;
import jnpf.model.personnels.po.FtbPersonnelsStaffRoster;
import jnpf.model.personnels.po.FtbPersonnelsTurnoverManagement;
import jnpf.model.personnels.vo.analysis.*;
import jnpf.model.personnels.vo.range.FtbRangeConfigDIYVO;
import jnpf.model.personnels.vo.range.FtbRangeConfigVO;
import jnpf.permission.V2OrganizeApi;
import jnpf.permission.V2UserApi;
import jnpf.permission.dto.v2.user.QueryPageUserDTO;
import jnpf.permission.eum.v2.OrganizeCategoryEnums;
import jnpf.permission.vo.v2.organzie.OrganizeGeneralDetailVO;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.permission.vo.v2.user.UserPageListVO;
import jnpf.personnels.mapper.*;
import jnpf.personnels.service.FtbPersonnelsOverviewAnalysisService;
import jnpf.personnels.service.FtbPersonnlesInfoConfigService;
import jnpf.personnels.utils.CompanyAgeUtil;
import jnpf.util.RangeConfigUtil;
import jnpf.util.excel.EasyExcelUtils;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.ServletWebRequest;

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

@Service
public class FtbPersonnelsOverviewAnalysisServiceImpl implements FtbPersonnelsOverviewAnalysisService {

    @Resource
    private FtbPersonnelsOverviewAnalysisMapper ftbPersonnelsOverviewAnalysisMapper;
    @Resource
    private FtbPersonnelsStaffRosterMapper ftbPersonnelsStaffRosterMapper;

    @Resource
    private FtbPersonnelsRegistrationFormFieldMapper ftbPersonnelsRegistrationFormFieldMapper;
    @Resource
    private FtbPersonnelsRegistrationFormFieldOptionMapper ftbPersonnelsRegistrationFormFieldOptionMapper;

    @Autowired
    private V2UserApi v2UserApi;

    @Resource
    private V2OrganizeApi v2OrganizeApi;

    @Resource
    private FtbPersonnelsTurnoverManagementMapper turnoverManagementMapper;

    // 在职状态
    public static final List<String> ON_THE_JOB_STATUS = List.of("302", "303", "304", "306");


    @Resource
    private FtbPersonnlesInfoConfigService personnlesInfoConfigService;

    @Override
    public PersonnelsOverviewEmployeesVO currentEmployees(FtbPersonnlesAnalysisDTO dto) {
        PersonnelsOverviewEmployeesVO personnelsOverviewEmployeesVO = new PersonnelsOverviewEmployeesVO();
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return personnelsOverviewEmployeesVO;
        }
        // 截止月份在职员工
        BigDecimal employedInTheMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        personnelsOverviewEmployeesVO.setData(employedInTheMonth);
        // 同比 （本期数 - 同期数） / 同期数 × 100%
        Date yearOnYearDate = DateUtil.offset(dto.getEndTime(), DateField.YEAR, -1).toJdkDate();
        BigDecimal yearOnYearDateValue = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(yearOnYearDate),
                ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        personnelsOverviewEmployeesVO.setYearOnYearValue(FtbPersonnelsOverviewAnalysisService.computeDivision(employedInTheMonth.subtract(yearOnYearDateValue), yearOnYearDateValue));
        // 环比 （本期数 - 上期数） / 上期数 × 100%
        Date chainDate = DateUtil.offset(dto.getEndTime(), DateField.MONTH, -1).toJdkDate();
        BigDecimal chainDateValue = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(chainDate)
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        personnelsOverviewEmployeesVO.setChainValue(FtbPersonnelsOverviewAnalysisService.computeDivision(employedInTheMonth.subtract(chainDateValue), chainDateValue));
        return personnelsOverviewEmployeesVO;
    }

    @Override
    public PersonnelsOverviewEmployeesVO compositeLife(FtbPersonnlesAnalysisDTO dto) {
        PersonnelsOverviewEmployeesVO personnelsOverviewEmployeesVO = new PersonnelsOverviewEmployeesVO();
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return personnelsOverviewEmployeesVO;
        }
        // 截止月份在职员工
        BigDecimal employedInTheMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        // 员工年龄
        List<String> ages = ftbPersonnelsOverviewAnalysisMapper.employeeAge(userIdListByOrganizeIds, DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS);
        BigDecimal numberOfCurrentPeriod = totalAgeCalculation(ages);
        personnelsOverviewEmployeesVO.setData(FtbPersonnelsOverviewAnalysisService.computeDivisionSb(numberOfCurrentPeriod, employedInTheMonth, 2)
                .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP));
        // 同比 （本期数 - 同期数） / 同期数 × 100%
        Date yearOnYearDate = DateUtil.offset(dto.getEndTime(), DateField.YEAR, -1).toJdkDate();
        List<String> yearOnYearAges = ftbPersonnelsOverviewAnalysisMapper.employeeAge(userIdListByOrganizeIds, DatePattern.NORM_MONTH_FORMAT.format(yearOnYearDate)
                , ON_THE_JOB_STATUS);
        BigDecimal yearOnYearBigDecimal = totalAgeCalculation(yearOnYearAges);
        // 同比在职员工人数
        BigDecimal yearOnYearEmployedEmployees = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(yearOnYearDate)
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        // 同比
        BigDecimal yearOnYearAverageAge = FtbPersonnelsOverviewAnalysisService.percentCustomCalculation(yearOnYearBigDecimal, yearOnYearEmployedEmployees, 2);
        personnelsOverviewEmployeesVO.setYearOnYearValue(FtbPersonnelsOverviewAnalysisService.computeDivision(
                personnelsOverviewEmployeesVO.getData().subtract(yearOnYearAverageAge)
                , yearOnYearAverageAge));
        // 环比 （本期数 - 上期数） / 上期数 × 100%
        Date chainDate = DateUtil.offset(dto.getEndTime(), DateField.MONTH, -1).toJdkDate();
        List<String> chainDateValueAge = ftbPersonnelsOverviewAnalysisMapper.employeeAge(userIdListByOrganizeIds, DatePattern.NORM_MONTH_FORMAT.format(chainDate)
                , ON_THE_JOB_STATUS);
        BigDecimal chainBigDecimal = totalAgeCalculation(chainDateValueAge);
        // 环比在职员工人数
        BigDecimal monthOnMonthEmployment = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(chainDate)
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        // 环比数
        BigDecimal chainNumber = FtbPersonnelsOverviewAnalysisService.percentCustomCalculation(chainBigDecimal, monthOnMonthEmployment, 2);

        personnelsOverviewEmployeesVO.setChainValue(FtbPersonnelsOverviewAnalysisService.computeDivision(
                personnelsOverviewEmployeesVO.getData().subtract(chainNumber)
                , chainNumber));
        return personnelsOverviewEmployeesVO;
    }

    @Override
    public PersonnelsOverviewEmployeesAgeVO averageAge(FtbPersonnlesAnalysisDTO dto) {
        PersonnelsOverviewEmployeesAgeVO personnelsOverviewEmployeesVO = new PersonnelsOverviewEmployeesAgeVO();
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return personnelsOverviewEmployeesVO;
        }
        // 截止月份在职员工
        BigDecimal employedInTheMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        // 截止月份的总司龄天数
        BigDecimal numberOfDaysOfAge = ftbPersonnelsOverviewAnalysisMapper.numberOfDaysOfAge(userIdListByOrganizeIds
                , DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), ON_THE_JOB_STATUS);
        // 平均司龄
        personnelsOverviewEmployeesVO.setData(averageAgeCalculation(numberOfDaysOfAge, employedInTheMonth));
        // 同比 （本期数 - 同期数） / 同期数 × 100%
        Date yearOnYearDate = DateUtil.offset(dto.getEndTime(), DateField.YEAR, -1).toJdkDate();
        BigDecimal yearOnYearDateValue = ftbPersonnelsOverviewAnalysisMapper.numberOfDaysOfAge(userIdListByOrganizeIds
                , DatePattern.NORM_MONTH_FORMAT.format(yearOnYearDate), ON_THE_JOB_STATUS);
        // 同比截止月份员工
        BigDecimal a = FtbPersonnelsOverviewAnalysisService.percentCustomCalculation(numberOfDaysOfAge, employedInTheMonth, 2);
        BigDecimal yearOnYearEmployeesAsOfMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(yearOnYearDate)
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        BigDecimal b = FtbPersonnelsOverviewAnalysisService.percentCustomCalculation(yearOnYearDateValue, yearOnYearEmployeesAsOfMonth, 2);
        personnelsOverviewEmployeesVO.setYearOnYearValue(FtbPersonnelsOverviewAnalysisService.computeDivision(a.subtract(b), b));
        // 环比 （本期数 - 上期数） / 上期数 × 100%
        Date chainDate = DateUtil.offset(dto.getEndTime(), DateField.MONTH, -1).toJdkDate();
        BigDecimal chainDateValue = ftbPersonnelsOverviewAnalysisMapper.numberOfDaysOfAge(userIdListByOrganizeIds
                , DatePattern.NORM_MONTH_FORMAT.format(chainDate), ON_THE_JOB_STATUS);
        // 环比截止月份员工
        BigDecimal employeesAsOfMonthOnMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(chainDate)
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        BigDecimal c = FtbPersonnelsOverviewAnalysisService.percentCustomCalculation(chainDateValue, employeesAsOfMonthOnMonth, 2);
        personnelsOverviewEmployeesVO.setChainValue(FtbPersonnelsOverviewAnalysisService.computeDivision(a.subtract(c), c));
        return personnelsOverviewEmployeesVO;
    }

    @Override
    public List<PersonnelsOverviewProportionVO> genderDistribution(FtbPersonnlesAnalysisDTO dto) {
        List<PersonnelsOverviewProportionVO> result = new ArrayList<>();
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        // 截止月份在职员工
        BigDecimal employedInTheMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        // 男
        BigDecimal male = ftbPersonnelsOverviewAnalysisMapper.genderDistribution(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds, "1");
        PersonnelsOverviewProportionVO malePersonnelsOverviewProportionVO = new PersonnelsOverviewProportionVO();
        malePersonnelsOverviewProportionVO.setDataName("男");
        malePersonnelsOverviewProportionVO.setData(male.intValue());
        malePersonnelsOverviewProportionVO.setPercentage(FtbPersonnelsOverviewAnalysisService.computeDivision(male, employedInTheMonth));
        result.add(malePersonnelsOverviewProportionVO);
        // 女
        BigDecimal female = ftbPersonnelsOverviewAnalysisMapper.genderDistribution(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds, "2");
        PersonnelsOverviewProportionVO femalePersonnelsOverviewProportionVO = new PersonnelsOverviewProportionVO();
        femalePersonnelsOverviewProportionVO.setDataName("女");
        femalePersonnelsOverviewProportionVO.setData(female.intValue());
        femalePersonnelsOverviewProportionVO.setPercentage(FtbPersonnelsOverviewAnalysisService.computeDivision(female, employedInTheMonth));
        result.add(femalePersonnelsOverviewProportionVO);
        return result;
    }

    @Override
    public List<PersonnelsOverviewProportionVO> employeeStatusProportion(FtbPersonnlesAnalysisDTO dto) {
        List<String> resignedEmployeesIds = doEmployeesOfResignOrganization(dto.getOrganizationId());
        // 截止月份入职日期的离职员工数
        BigDecimal resignedEmployees = BigDecimal.ZERO;
        if (CollUtil.isNotEmpty(resignedEmployeesIds)) {
            resignedEmployees = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                    , List.of("305"), resignedEmployeesIds);
        }
        List<PersonnelsOverviewProportionVO> result = List.of(
                new PersonnelsOverviewProportionVO("302", 0, BigDecimal.ZERO, "试用期员工"),
                new PersonnelsOverviewProportionVO("303", 0, BigDecimal.ZERO, "正式员工"),
                new PersonnelsOverviewProportionVO("304", 0, BigDecimal.ZERO, "待离职员工"),
                new PersonnelsOverviewProportionVO("305", resignedEmployees.intValue(), BigDecimal.ZERO, "离职员工"));
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return handleEmployeeStatusProportion(result, List.of(), resignedEmployees);
        }
        // 截止月份在职员工
        BigDecimal employedInTheMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        List<PersonnelsOverviewProportionVO> temp = ftbPersonnelsOverviewAnalysisMapper.employeeStatusProportion(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), userIdListByOrganizeIds);
        temp.add(new PersonnelsOverviewProportionVO("305", resignedEmployees.intValue(), BigDecimal.ZERO, "离职员工"));
        // 数值换算及百分比
        return handleEmployeeStatusProportion(result, temp, employedInTheMonth.add(resignedEmployees));
    }

    @Override
    public List<PersonnelsOverviewProportionVO> proportionOfEmploymentTypes(FtbPersonnlesAnalysisDTO dto) {
        /**
         * 员工类型
         */
        LambdaQueryWrapper<FtbPersonnelsRegistrationFormFieldOption> query = new LambdaQueryWrapper<>();
        query.eq(FtbPersonnelsRegistrationFormFieldOption::getEnabledMark, 0);
        query.eq(FtbPersonnelsRegistrationFormFieldOption::getFormFieldId, "workerType");
        query.orderByAsc(FtbPersonnelsRegistrationFormFieldOption::getCreatorTime);
        List<PersonnelsOverviewProportionVO> result = ftbPersonnelsRegistrationFormFieldOptionMapper.selectList(query)
                .stream()
                .map(a -> new PersonnelsOverviewProportionVO(a.getId(), 0, BigDecimal.ZERO, a.getName()))
                .collect(Collectors.toList());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return handleEmployeeStatusProportion(result, List.of(), BigDecimal.ZERO);
        }
        // 截止月份在职员工
        BigDecimal employedInTheMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        List<PersonnelsOverviewProportionVO> temp = ftbPersonnelsOverviewAnalysisMapper.proportionOfEmploymentTypes(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        // 数值换算及百分比
        return handleEmployeeStatusProportion(result, temp, employedInTheMonth);
    }

    @Override
    public List<PersonnelsOverviewProportionVO> ageDistributionProportion(FtbPersonnlesAnalysisDTO dto) {
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return getAgeDistributions(List.of(AgeDistributionSecond.values()), List.of(), BigDecimal.ZERO);
        }
        Integer configType = personnlesInfoConfigService.queryType(1);
        if (configType == null) {
            throw new RuntimeException("获取年龄配置失败");
        }
        // 1平均 2自定义
        List<RangeDTO> rangeDTOS;
        if (configType  == 1){
            FtbRangeConfigVO configVO = personnlesInfoConfigService.queryInfo(1);
            rangeDTOS = RangeConfigUtil.generateRanges(configVO.getFirstGear(), configVO.getIntervalValue(), configVO.getNumberOfGears(),configVO.getPreviewValue());
        }else {
            List<FtbRangeConfigDIYVO> rangeConfigDIYVOS = personnlesInfoConfigService.queryDiyInfo(1);
            rangeDTOS = rangeConfigDIYVOS.stream().map(v->{
                RangeDTO rangeDTO = new RangeDTO();
                rangeDTO.setStartPrice(v.getStartInterval());
                rangeDTO.setEndPrice(v.getEndInterval());
                rangeDTO.setPriceBandDisplayStr(v.getPreviewValue());
                return rangeDTO;
            }).collect(Collectors.toList());
        }
        // 截止月份在职员工
        BigDecimal employedInTheMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        List<PersonnelsOverviewProportionVO> temp = ftbPersonnelsOverviewAnalysisMapper.ageDistributionProportion(
                        DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), ON_THE_JOB_STATUS, userIdListByOrganizeIds)
                .stream()
                .filter(a -> Objects.nonNull(a) && StrUtil.isNotBlank(a.getDataName()))
                .peek(a -> a.setData(DateUtil.ageOfNow(a.getDataName())))
                .collect(Collectors.toList());
        return rangeDTOS.stream().map(a -> {
            PersonnelsOverviewProportionVO proportionVO = new PersonnelsOverviewProportionVO();
            proportionVO.setDataName(a.getPriceBandDisplayStr());
            Integer startPrice = a.getStartPrice();
            Integer endPrice = a.getEndPrice();
            long count = temp.stream().filter(v -> {
                if (StringUtils.isEmpty(v.getDataName())) return false;
                BigDecimal decimal = BigDecimal.valueOf(v.getData());
                BigDecimal startPriceDecimal = BigDecimal.valueOf(startPrice);
                if (endPrice == null) {
                    if (decimal.compareTo(startPriceDecimal) >= 0) {
                        return true;
                    }
                }else {
                    BigDecimal endPriceDecimal = BigDecimal.valueOf(endPrice);
                    if ( decimal.compareTo(startPriceDecimal) >= 0 && decimal.compareTo(endPriceDecimal) < 0) {
                        // 条件成立时的逻辑
                        return true;
                    }
                }
                // 判断是否在范围内
                return false;
            }).count();
            proportionVO.setData(Math.toIntExact(count));
            proportionVO.setPercentage(FtbPersonnelsOverviewAnalysisService.computeDivision(count, employedInTheMonth));
            return proportionVO;
        }).collect(Collectors.toList());
    }

    @Override
    public List<PersonnelsOverviewProportionVO> ageDistribution(FtbPersonnlesAnalysisDTO dto) {
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return getAgeDistributions(List.of(AgeDistributionFirst.values()), List.of(), BigDecimal.ZERO);
        }
        // 截止月份在职员工
        BigDecimal employedInTheMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        List<PersonnelsOverviewProportionVO> temp = ftbPersonnelsOverviewAnalysisMapper.ageDistribution(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        return getAgeDistributions(List.of(AgeDistributionFirst.values()), temp, employedInTheMonth);
    }

    @Override
    public List<PersonnelsOverviewProportionVO> educationalBackground(FtbPersonnlesAnalysisDTO dto) {
        /**
         * 学历占比
         * 18	初中
         * 19	高中
         * 20	中专
         * 21	大专
         * 22	本科
         * 23	硕士
         * 24	博士
         * 25	其他
         * 33   小学
         */
        List<PersonnelsOverviewProportionVO> result = List.of(
                new PersonnelsOverviewProportionVO("33", 0, BigDecimal.ZERO, "小学"),
                new PersonnelsOverviewProportionVO("18", 0, BigDecimal.ZERO, "初中"),
                new PersonnelsOverviewProportionVO("19", 0, BigDecimal.ZERO, "高中"),
                new PersonnelsOverviewProportionVO("20", 0, BigDecimal.ZERO, "中专"),
                new PersonnelsOverviewProportionVO("21", 0, BigDecimal.ZERO, "大专"),
                new PersonnelsOverviewProportionVO("22", 0, BigDecimal.ZERO, "本科"),
                new PersonnelsOverviewProportionVO("23", 0, BigDecimal.ZERO, "硕士"),
                new PersonnelsOverviewProportionVO("24", 0, BigDecimal.ZERO, "博士"),
                new PersonnelsOverviewProportionVO("25", 0, BigDecimal.ZERO, "其他")
        );
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return handleEmployeeStatusProportion(result, List.of(), BigDecimal.ZERO);
        }
        // 截止月份在职员工
        BigDecimal employedInTheMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        List<PersonnelsOverviewProportionVO> temp = ftbPersonnelsOverviewAnalysisMapper.educationalBackground(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        // 数值换算及百分比
        return handleEmployeeStatusProportion(result, temp, employedInTheMonth);
    }

    @Override
    public List<PersonnelsOverviewProportionVO> departmentHeadcountRatio(FtbPersonnlesAnalysisDTO dto) {
        List<PersonnelsOverviewProportionVO> result = new ArrayList<>();
        ActionResult<List<OrganizeGeneralDetailVO>> listActionResult = v2OrganizeApi.organizesOrHaveChildByOrganizeIds(dto.getOrganizationId(), false, null);
        if (listActionResult == null || CollUtil.isEmpty(listActionResult.getData())) {
            return result;
        }
        List<String> orgIds = listActionResult.getData()
                .stream().filter(a -> OrganizeCategoryEnums.DEPARTMENT.equals(a.getOrganizeCategoryEnums()))
                .map(OrganizeGeneralDetailVO::getId)
                .filter(id -> dto.getOrganizationId().contains(id)).collect(Collectors.toList());
        if (CollUtil.isEmpty(orgIds)) {
            return result;
        }
        ActionResult<List<UserPageListVO>> userPageList = v2UserApi.listTargetOrganizes(orgIds, null,null);
        if (userPageList == null || CollUtil.isEmpty(userPageList.getData())) {
            return result;
        }
        List<String> userIdListByOrganizeIds = userPageList.getData().stream().map(UserPageListVO::getId).collect(Collectors.toList());
        // 在职人员
        List<String> presenceOfPersonnel = ftbPersonnelsOverviewAnalysisMapper.departmentHeadcountRatio(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        // 部门人数分组占比
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(presenceOfPersonnel, null);
        if (actionResult.getCode() != 200) {
            throw new RuntimeException("获取用户信息失败");
        }
        Map<String, Long> departmentProportionMap = actionResult.getData().stream()
                .filter(a -> {
                    if (CollUtil.isNotEmpty(orgIds)) {
                        return orgIds.contains(a.getOrganizeId());
                    }
                    return true;
                })
                .collect(Collectors.groupingBy(a -> a.getOrganizeId() + "#" + a.getOrganizeName()
                        , Collectors.collectingAndThen(
                                Collectors.mapping(UserBoundVO::getId, Collectors.toSet())
                                , a -> Long.valueOf(a.size()))));

        return getPersonnelsOverviewProportionVOS(presenceOfPersonnel, departmentProportionMap);
    }

    @Override
    public List<PersonnelsOverviewProportionVO> proportionOfJobHeadcount(FtbPersonnlesAnalysisDTO dto) {
        List<PersonnelsOverviewProportionVO> result = new ArrayList<>();
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        // 在职人员
        List<String> presenceOfPersonnel = ftbPersonnelsOverviewAnalysisMapper.departmentHeadcountRatio(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        // 岗位人数分组占比
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(presenceOfPersonnel, "");
        if (actionResult.getCode() != 200) {
            throw new RuntimeException("获取用户信息失败");
        }
        Map<String, Long> departmentProportionMap = actionResult.getData().stream()
                .filter(a -> {
                    if (CollUtil.isNotEmpty(dto.getPostId())) {
                        return dto.getPostId().contains(a.getPositionId()) && dto.getOrganizationId().contains(a.getOrganizeId());
                    }
                    return dto.getOrganizationId().contains(a.getOrganizeId());
                })
                .collect(Collectors.groupingBy(a -> a.getPositionId() + "#" + a.getPositionName(), Collectors.counting()));
        return getPersonnelsOverviewProportionVOS(presenceOfPersonnel, departmentProportionMap);
    }

    @NotNull
    private List<PersonnelsOverviewProportionVO> getPersonnelsOverviewProportionVOS(List<String> presenceOfPersonnel, Map<String, Long> departmentProportionMap) {
        return departmentProportionMap.entrySet().stream()
                .map(a -> {
                    PersonnelsOverviewProportionVO personnelsOverviewProportionVO = new PersonnelsOverviewProportionVO();
                    personnelsOverviewProportionVO.setDataName(a.getKey().split("#")[1]);
                    personnelsOverviewProportionVO.setData(a.getValue().intValue());
                    personnelsOverviewProportionVO.setPercentage(FtbPersonnelsOverviewAnalysisService.computeDivision(a.getValue(), presenceOfPersonnel.size()));
                    return personnelsOverviewProportionVO;
                }).collect(Collectors.toList());
    }

    @Override
    public List<PersonnelsOverviewProportionVO> statusOfCurrentEmployees(FtbPersonnlesAnalysisDTO dto) {
        List<PersonnelsOverviewProportionVO> result = new ArrayList<>();
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        long betweenMonth = DateUtil.betweenMonth(dto.getStartTime(), dto.getEndTime(), true);
        for (int i = 0; i <= betweenMonth; i++) {
            PersonnelsOverviewProportionVO personnelsOverviewProportionVO = new PersonnelsOverviewProportionVO();
            Date offsetTime = DateUtil.offset(dto.getStartTime(), DateField.MONTH, i).toJdkDate();
            String month = DatePattern.NORM_MONTH_FORMAT.format(offsetTime);
            personnelsOverviewProportionVO.setDataName(month);
            // 截止月份在职员工
            BigDecimal employedInTheMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(month, ON_THE_JOB_STATUS,
                    userIdListByOrganizeIds);
            personnelsOverviewProportionVO.setData(employedInTheMonth.intValue());
            result.add(personnelsOverviewProportionVO);
        }
        return result;
    }

    @Override
    public List<PersonnelsOverviewProportionVO> seniorityDistribution(FtbPersonnlesAnalysisDTO dto) {
        List<PersonnelsOverviewProportionVO> result = new ArrayList<>();
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        // 在职人员
        List<String> presenceOfPersonnel = ftbPersonnelsOverviewAnalysisMapper.departmentHeadcountRatio(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        Integer configType = personnlesInfoConfigService.queryType(3);
        if (configType == null) {
            throw new RuntimeException("获取工龄配置失败");
        }
        // 1平均 2自定义
        List<RangeDTO> rangeDTOS;
        if (configType  == 1){
            FtbRangeConfigVO configVO = personnlesInfoConfigService.queryInfo(3);
            rangeDTOS = RangeConfigUtil.generateRanges(configVO.getFirstGear(), configVO.getIntervalValue(), configVO.getNumberOfGears(), configVO.getPreviewValue());
        }else {
            List<FtbRangeConfigDIYVO> rangeConfigDIYVOS = personnlesInfoConfigService.queryDiyInfo(3);
            rangeDTOS = rangeConfigDIYVOS.stream().map(v -> {
                RangeDTO rangeDTO = new RangeDTO();
                rangeDTO.setStartPrice(v.getStartInterval());
                rangeDTO.setEndPrice(v.getEndInterval());
                rangeDTO.setPriceBandDisplayStr(v.getPreviewValue());
                return rangeDTO;
            }).collect(Collectors.toList());
        }
        List<BigDecimal> seniorityDistributionList = new ArrayList<>();
        if (CollUtil.isNotEmpty(presenceOfPersonnel)) {
           seniorityDistributionList = ftbPersonnelsOverviewAnalysisMapper.seniorityDistribution(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()),presenceOfPersonnel,ON_THE_JOB_STATUS);
        }
        List<BigDecimal> finalSeniorityDistributionList = seniorityDistributionList;
        return rangeDTOS.stream().map(item -> {
            PersonnelsOverviewProportionVO proportionVO = new PersonnelsOverviewProportionVO();
            proportionVO.setDataName(item.getPriceBandDisplayStr());
            Integer startPrice = item.getStartPrice();
            Integer endPrice = item.getEndPrice();
            long count = finalSeniorityDistributionList.stream().filter(a -> {
                if( endPrice  == null  && a.compareTo(new BigDecimal(startPrice)) >= 0 )  return true;
                // 判断是否在区间内
                if (a.compareTo(new BigDecimal(startPrice)) >= 0 && a.compareTo(new BigDecimal(endPrice)) <= 0) {
                    return true;
                } else {
                    return false;
                }
            }).count();
            proportionVO.setData(Math.toIntExact(count));
            proportionVO.setPercentage(FtbPersonnelsOverviewAnalysisService.computeDivision(count, presenceOfPersonnel.size()));
            return proportionVO;
        }).collect(Collectors.toList());
    }

    @Override
    public List<PersonnelsOverviewProportionVO> insurancePurchaseAnalysis(FtbPersonnlesAnalysisDTO dto) {
        List<PersonnelsOverviewProportionVO> result = new ArrayList<>();
        // 保险购买情况
        LambdaQueryWrapper<FtbPersonnelsRegistrationFormField> formFieldWrapper = Wrappers.lambdaQuery();
        formFieldWrapper.eq(FtbPersonnelsRegistrationFormField::getName, "保险购买情况");
        formFieldWrapper.eq(FtbPersonnelsRegistrationFormField::getEnabledMark, 0);
        formFieldWrapper.last("limit 1");
        FtbPersonnelsRegistrationFormField ftbPersonnelsRegistrationFormFields = ftbPersonnelsRegistrationFormFieldMapper.selectOne(formFieldWrapper);
        if (Objects.isNull(ftbPersonnelsRegistrationFormFields)) {
            return result;
        }
        // 获取保险购买情况下拉选项值
        List<FtbPersonnelsRegistrationFormFieldOption> options = ftbPersonnelsRegistrationFormFieldOptionMapper.selectList(
                Wrappers.<FtbPersonnelsRegistrationFormFieldOption>lambdaQuery()
                        .eq(FtbPersonnelsRegistrationFormFieldOption::getFormFieldId, ftbPersonnelsRegistrationFormFields.getId())
                        .eq(FtbPersonnelsRegistrationFormFieldOption::getEnabledMark, 0));
        result = options.stream()
                .map(a -> new PersonnelsOverviewProportionVO(a.getId(), 0, BigDecimal.ZERO, a.getName()))
                .collect(Collectors.toList());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return handleEmployeeStatusProportion(result, List.of(), BigDecimal.ZERO);
        }
        // 截止月份在职员工
        BigDecimal employedInTheMonth = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonth(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        List<PersonnelsOverviewProportionVO> temp = ftbPersonnelsOverviewAnalysisMapper.insurancePurchaseAnalysis(
                ftbPersonnelsRegistrationFormFields.getId(),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        // 数值换算及百分比
        return handleEmployeeStatusProportion(result, temp, employedInTheMonth);
    }

    @Override
    public List<PersonnelsOverviewProportionVO> proportionOfStoreNumbers(FtbPersonnlesAnalysisDTO dto) {
        List<PersonnelsOverviewProportionVO> result = new ArrayList<>();
        ActionResult<List<OrganizeGeneralDetailVO>> listActionResult = v2OrganizeApi.organizesOrHaveChildByOrganizeIds(dto.getOrganizationId(), false, null);
        if (listActionResult == null || CollUtil.isEmpty(listActionResult.getData())) {
            return result;
        }
        List<String> orgIds = listActionResult.getData()
                .stream().filter(a -> OrganizeCategoryEnums.STORE.equals(a.getOrganizeCategoryEnums()))
                .map(OrganizeGeneralDetailVO::getId)
                .filter(id -> dto.getOrganizationId().contains(id)).collect(Collectors.toList());
        if (CollUtil.isEmpty(orgIds)) {
            return result;
        }
        ActionResult<List<UserPageListVO>> userPageList = v2UserApi.listTargetOrganizes(orgIds, null,null);
        if (userPageList == null || CollUtil.isEmpty(userPageList.getData())) {
            return result;
        }
        List<String> userIdListByOrganizeIds = userPageList.getData().stream().map(UserPageListVO::getId).collect(Collectors.toList());
        // 在职人员
        List<String> presenceOfPersonnel = ftbPersonnelsOverviewAnalysisMapper.departmentHeadcountRatio(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        // 部门人数分组占比
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(presenceOfPersonnel, null);
        if (actionResult.getCode() != 200) {
            throw new RuntimeException("获取用户信息失败");
        }
        Map<String, Long> departmentProportionMap = actionResult.getData().stream()
                .filter(a -> {
                    if (CollUtil.isNotEmpty(orgIds)) {
                        return orgIds.contains(a.getOrganizeId());
                    }
                    return true;
                })
                .collect(Collectors.groupingBy(a -> a.getOrganizeId() + "#" + a.getOrganizeName()
                        , Collectors.collectingAndThen(
                                Collectors.mapping(UserBoundVO::getId, Collectors.toSet())
                                , a -> Long.valueOf(a.size()))));

        return getPersonnelsOverviewProportionVOS(presenceOfPersonnel, departmentProportionMap);
    }

    @Override
    public PageListVO<PersonnelsOverviewEmployeesDetailsVO> statusOfCurrentEmployeesDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<PersonnelsOverviewEmployeesDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        // 在职人员
        List<PersonnelsOverviewEmployeesDetailsVO> presenceOfPersonnel = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonthList(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        if (CollUtil.isEmpty(presenceOfPersonnel)) {
            return result;
        }
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(userIdListByOrganizeIds, "");
        if (actionResult.getCode() != 200) {
            return result;
        }
        Map<String, UserBoundVO> userBoundVOMap = actionResult.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
        // 获取员工类型选项
        LambdaQueryWrapper<FtbPersonnelsRegistrationFormFieldOption> query = new LambdaQueryWrapper<>();
        query.eq(FtbPersonnelsRegistrationFormFieldOption::getEnabledMark, 0);
        query.eq(FtbPersonnelsRegistrationFormFieldOption::getFormFieldId, "workerType");
        List<FtbPersonnelsRegistrationFormFieldOption> options = ftbPersonnelsRegistrationFormFieldOptionMapper.selectList(query);
        Map<String, String> workerTypeMap = options.stream().collect(Collectors.toMap(FtbPersonnelsRegistrationFormFieldOption::getId, FtbPersonnelsRegistrationFormFieldOption::getName));
        presenceOfPersonnel.forEach(a -> {
            UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
            if (Objects.nonNull(userBoundVO)) {
                a.setUserName(userBoundVO.getUserName());
                a.setOrganization(userBoundVO.getOrganizeName());
                a.setJobLevel(userBoundVO.getPositionName());
                a.setJobGrade(userBoundVO.getGradeName());
            }
            if (StrUtil.isNotBlank(a.getEmployeeType())) {
                a.setEmployeeType(workerTypeMap.getOrDefault(a.getEmployeeType(),a.getEmployeeType()));
            }
        });
        result.getPagination().setTotal(presenceOfPersonnel.size());
        // 按照组织排序
        presenceOfPersonnel.sort(Comparator.comparing(PersonnelsOverviewEmployeesDetailsVO::getOrganization));
        result.setList(presenceOfPersonnel);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewEmployeesDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(), presenceOfPersonnel.size());
            return CultivatePage.paginate(presenceOfPersonnel, page);
        }
        return result;
    }

    @Override
    public void statusOfCurrentEmployeesDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<PersonnelsOverviewEmployeesDetailsVO> personnelsOverviewEmployeesDetailsVOPageListVO = statusOfCurrentEmployeesDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "人员概览-在职员工", personnelsOverviewEmployeesDetailsVOPageListVO.getList(), PersonnelsOverviewEmployeesDetailsVO.class);
    }

    @Override
    public PageListVO<PersonnelsOverviewProportionDetailsVO> genderDistributionDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<PersonnelsOverviewProportionDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        List<PersonnelsOverviewProportionDetailsVO> males = ftbPersonnelsOverviewAnalysisMapper.genderDistributionList(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        if (CollUtil.isEmpty(males)) {
            return result;
        }
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(userIdListByOrganizeIds, "");
        if (actionResult.getCode() != 200) {
            return result;
        }
        Map<String, UserBoundVO> userBoundVOMap = actionResult.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
        males.forEach(a -> {
            UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
            if (Objects.nonNull(userBoundVO)) {
                a.setUserName(userBoundVO.getUserName());
                a.setOrganization(userBoundVO.getOrganizeName());
                a.setJobLevel(userBoundVO.getPositionName());
                a.setJobGrade(userBoundVO.getGradeName());
            }
            // 0未知1男2女
            if ("0".equals(a.getGender())) {
                a.setGender("未知");
            } else if ("1".equals(a.getGender())) {
                a.setGender("男");
            } else if ("2".equals(a.getGender())) {
                a.setGender("女");
            }
        });
        result.getPagination().setTotal(males.size());
        // 按照组织排序
        males.sort(Comparator.comparing(PersonnelsOverviewProportionDetailsVO::getOrganization));
        result.setList(males);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewProportionDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(),males.size());
            return CultivatePage.paginate(males, page);
        }
        return result;
    }

    @Override
    public void genderDistributionDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<PersonnelsOverviewProportionDetailsVO> personnelsOverviewProportionDetailsVOPageListVO = genderDistributionDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "人员概览-性别分布", personnelsOverviewProportionDetailsVOPageListVO.getList(), PersonnelsOverviewProportionDetailsVO.class);
    }

    @Override
    public PageListVO<PersonnelsOverviewSituationDetailsVO> employeeStatusProportionDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<PersonnelsOverviewSituationDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        // 离职员工
        List<PersonnelsOverviewSituationDetailsVO> employeesOfResignOrganizationList = doEmployeesOfResignOrganizationList(dto.getOrganizationId());
        if (CollUtil.isNotEmpty(employeesOfResignOrganizationList)) {
            List<String> resignedEmployeesIds = employeesOfResignOrganizationList.stream().map(PersonnelsOverviewSituationDetailsVO::getUserId).collect(Collectors.toList());
            List<PersonnelsOverviewEmployeesDetailsVO> personnelsOverviewEmployeesDetailsVOS = ftbPersonnelsOverviewAnalysisMapper.employeesEmployedInTheMonthList(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                    , List.of("305"), resignedEmployeesIds);
            resignedEmployeesIds = personnelsOverviewEmployeesDetailsVOS.stream().map(PersonnelsOverviewEmployeesDetailsVO::getUserId).collect(Collectors.toList());
            List<String> finalResignedEmployeesIds = resignedEmployeesIds;
            employeesOfResignOrganizationList = employeesOfResignOrganizationList.stream()
                    .filter(a -> finalResignedEmployeesIds.contains(a.getUserId()))
                    .collect(Collectors.toList());
        }
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds) && CollUtil.isEmpty(employeesOfResignOrganizationList)) {
            return result;
        }
        List<PersonnelsOverviewSituationDetailsVO> queryLists = ftbPersonnelsOverviewAnalysisMapper.employeeStatusProportionList(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , userIdListByOrganizeIds);
        if (CollUtil.isNotEmpty(queryLists)) {
            ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(userIdListByOrganizeIds, "");
            if (actionResult.getCode() != 200) {
                return result;
            }
            Map<String, UserBoundVO> userBoundVOMap = actionResult.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
            queryLists.forEach(a -> {
                UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
                if (Objects.nonNull(userBoundVO)) {
                    a.setUserName(userBoundVO.getUserName());
                    a.setOrganization(userBoundVO.getOrganizeName());
                    a.setJobLevel(userBoundVO.getPositionName());
                    a.setJobGrade(userBoundVO.getGradeName());
                }
                // 工作状态，301、预入职  302、试用 303、正式  304、待离职  305 离职 306试岗
                switch (a.getEmployeeStatus()) {
                    case "301":
                        a.setEmployeeStatus("预入职");
                        break;
                    case "302":
                        a.setEmployeeStatus("试用");
                        break;
                    case "303":
                        a.setEmployeeStatus("正式");
                        break;
                    case "304":
                        a.setEmployeeStatus("待离职");
                        break;
                    case "305":
                        a.setEmployeeStatus("离职");
                        break;
                    case "306":
                        a.setEmployeeStatus("试岗");
                        break;
                    default:
                        a.setEmployeeStatus("未知");
                }
            });
        }
        // 离职员工
        if (CollUtil.isNotEmpty(employeesOfResignOrganizationList)) {
            // 员工Id填充
            List<String> userIds = employeesOfResignOrganizationList.stream().map(PersonnelsOverviewSituationDetailsVO::getUserId).collect(Collectors.toList());
            Map<String, String> employeeIDCollection = employeeIDQuery(userIds);
            employeesOfResignOrganizationList.forEach(a -> {
                a.setEmployeeId(employeeIDCollection.getOrDefault(a.getUserId(),""));
                // 已离职
                a.setEmployeeStatus("已离职");
            });
            queryLists.addAll(employeesOfResignOrganizationList);
        }
        result.getPagination().setTotal(queryLists.size());
        // 按照组织排序
        queryLists.sort(Comparator.comparing(PersonnelsOverviewSituationDetailsVO::getOrganization));
        result.setList(queryLists);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewSituationDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(),queryLists.size());
            return CultivatePage.paginate(queryLists, page);
        }
        return result;
    }

    @Override
    public void employeeStatusProportionDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<PersonnelsOverviewSituationDetailsVO> personnelsOverviewSituationDetailsVOPageListVO = employeeStatusProportionDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "人员概览-员工状态分布", personnelsOverviewSituationDetailsVOPageListVO.getList(), PersonnelsOverviewSituationDetailsVO.class);
    }

    @Override
    public PageListVO<PersonnelsOverviewTypeDetailsVO> proportionOfEmploymentTypesDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<PersonnelsOverviewTypeDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        List<PersonnelsOverviewTypeDetailsVO> queryLists = ftbPersonnelsOverviewAnalysisMapper.proportionOfEmploymentTypesList(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        if (CollUtil.isEmpty(queryLists)) {
            return result;
        }
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(userIdListByOrganizeIds, "");
        if (actionResult.getCode() != 200) {
            return result;
        }
        Map<String, UserBoundVO> userBoundVOMap = actionResult.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
        // 获取员工类型选项
        LambdaQueryWrapper<FtbPersonnelsRegistrationFormFieldOption> query = new LambdaQueryWrapper<>();
        query.eq(FtbPersonnelsRegistrationFormFieldOption::getEnabledMark, 0);
        query.eq(FtbPersonnelsRegistrationFormFieldOption::getFormFieldId, "workerType");
        List<FtbPersonnelsRegistrationFormFieldOption> options = ftbPersonnelsRegistrationFormFieldOptionMapper.selectList(query);
        Map<String, String> workerTypeMap = options.stream().collect(Collectors.toMap(FtbPersonnelsRegistrationFormFieldOption::getId, FtbPersonnelsRegistrationFormFieldOption::getName));
        queryLists.forEach(a -> {
            UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
            if (Objects.nonNull(userBoundVO)) {
                a.setUserName(userBoundVO.getUserName());
                a.setOrganization(userBoundVO.getOrganizeName());
                a.setJobLevel(userBoundVO.getPositionName());
                a.setJobGrade(userBoundVO.getGradeName());
            }
            // 员工类型转换
            if (StrUtil.isNotBlank(a.getEmployeeType())) {
                a.setEmployeeType(workerTypeMap.getOrDefault(a.getEmployeeType(), a.getEmployeeType()));
            }
        });
        result.getPagination().setTotal(queryLists.size());
        // 按照组织排序
        queryLists.sort(Comparator.comparing(PersonnelsOverviewTypeDetailsVO::getOrganization));
        result.setList(queryLists);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewTypeDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(), queryLists.size());
            return CultivatePage.paginate(queryLists, page);
        }
        return result;
    }

    @Override
    public void proportionOfEmploymentTypesDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<PersonnelsOverviewTypeDetailsVO> personnelsOverviewTypeDetailsVOPageListVO = proportionOfEmploymentTypesDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "人员概览-员工类型分布", personnelsOverviewTypeDetailsVOPageListVO.getList(), PersonnelsOverviewTypeDetailsVO.class);
    }

    @Override
    public PageListVO<PersonnelsOverviewAgeDetailsVO> ageDistributionProportionDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<PersonnelsOverviewAgeDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        List<PersonnelsOverviewAgeDetailsVO> queryLists = ftbPersonnelsOverviewAnalysisMapper.ageDistributionProportionList(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        if (CollUtil.isEmpty(queryLists)) {
            return result;
        }
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(userIdListByOrganizeIds, "");
        if (actionResult.getCode() != 200) {
            return result;
        }
        Map<String, UserBoundVO> userBoundVOMap = actionResult.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
        queryLists.forEach(a -> {
            UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
            if (Objects.nonNull(userBoundVO)) {
                a.setUserName(userBoundVO.getUserName());
                a.setOrganization(userBoundVO.getOrganizeName());
                a.setJobLevel(userBoundVO.getPositionName());
                a.setJobGrade(userBoundVO.getGradeName());
            }
            // 年龄计算和格式转换
            if (StrUtil.isNotBlank(a.getAge())) {
                try {
                    int age = DateUtil.ageOfNow(a.getAge());
                    a.setAge(String.valueOf(age));
                } catch (Exception e) {
                    // 保持原格式
                }
            }
        });
        result.getPagination().setTotal(queryLists.size());
        // 按照组织排序
        queryLists.sort(Comparator.comparing(PersonnelsOverviewAgeDetailsVO::getOrganization));
        result.setList(queryLists);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewAgeDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(), queryLists.size());
            return CultivatePage.paginate(queryLists, page);
        }
        return result;
    }

    @Override
    public void ageDistributionProportionDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<PersonnelsOverviewAgeDetailsVO> personnelsOverviewAgeDetailsVOPageListVO = ageDistributionProportionDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "人员概览-年龄分布", personnelsOverviewAgeDetailsVOPageListVO.getList(), PersonnelsOverviewAgeDetailsVO.class);
    }

    @Override
    public PageListVO<PersonnelsOverviewCompanyDetailsVO> companyDistributionDetails(FtbPersonnlesAnalysisDTO dto) {
        Date now = new Date();
        PageListVO<PersonnelsOverviewCompanyDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        List<PersonnelsOverviewCompanyDetailsVO> queryLists = ftbPersonnelsOverviewAnalysisMapper.companyDistributionList(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        if (CollUtil.isEmpty(queryLists)) {
            return result;
        }
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(userIdListByOrganizeIds, "");
        if (actionResult.getCode() != 200) {
            return result;
        }
        Map<String, UserBoundVO> userBoundVOMap = actionResult.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
        queryLists.forEach(a -> {
            UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
            if (Objects.nonNull(userBoundVO)) {
                a.setUserName(userBoundVO.getUserName());
                a.setOrganization(userBoundVO.getOrganizeName());
                a.setJobLevel(userBoundVO.getPositionName());
                a.setJobGrade(userBoundVO.getGradeName());
            }
            // 司龄格式转换
            if (StrUtil.isNotBlank(a.getCompanyAge())) {
                a.setCompanyAge(CompanyAgeUtil.calculateServiceAgeShort(DateUtil.parse(a.getCompanyAge()), now));
            }
        });
        result.getPagination().setTotal(queryLists.size());
        // 按照组织排序
        queryLists.sort(Comparator.comparing(PersonnelsOverviewCompanyDetailsVO::getOrganization));
        result.setList(queryLists);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewCompanyDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(), queryLists.size());
            return CultivatePage.paginate(queryLists, page);
        }
        return result;
    }

    @Override
    public void companyDistributionDetailsExport(FtbPersonnlesAnalysisDTO dto) {
        dto.setPageSize(-1);
        PageListVO<PersonnelsOverviewCompanyDetailsVO> personnelsOverviewCompanyDetailsVOPageListVO = companyDistributionDetails(dto);
        try {
            EasyExcelUtils.exportExcel(getResponse(), "人员概览-司龄分布", personnelsOverviewCompanyDetailsVOPageListVO.getList(), PersonnelsOverviewCompanyDetailsVO.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public PageListVO<PersonnelsOverviewSeniorityDetailsVO> seniorityDistributionDetails(FtbPersonnlesAnalysisDTO dto) {
        Date now = new Date();
        PageListVO<PersonnelsOverviewSeniorityDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        List<PersonnelsOverviewSeniorityDetailsVO> queryLists = ftbPersonnelsOverviewAnalysisMapper.seniorityDistributionList(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        if (CollUtil.isEmpty(queryLists)) {
            return result;
        }
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(userIdListByOrganizeIds, "");
        if (actionResult.getCode() != 200) {
            return result;
        }
        Map<String, UserBoundVO> userBoundVOMap = actionResult.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
        queryLists.forEach(a -> {
            UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
            if (Objects.nonNull(userBoundVO)) {
                a.setUserName(userBoundVO.getUserName());
                a.setOrganization(userBoundVO.getOrganizeName());
                a.setJobLevel(userBoundVO.getPositionName());
                a.setJobGrade(userBoundVO.getGradeName());
            }
            // 工龄格式转换
            if (StrUtil.isNotBlank(a.getSeniority())) {
                Date ageWorkAge = DateUtil.parse(a.getSeniority());
                long age = DateUtil.betweenYear(ageWorkAge, now, false);
                a.setSeniority(age + "年");
            }
        });
        result.getPagination().setTotal(queryLists.size());
        // 按照组织排序
        queryLists.sort(Comparator.comparing(PersonnelsOverviewSeniorityDetailsVO::getOrganization));
        result.setList(queryLists);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewSeniorityDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(), queryLists.size());
            return CultivatePage.paginate(queryLists, page);
        }
        return result;
    }

    @Override
    public void seniorityDistributionDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<PersonnelsOverviewSeniorityDetailsVO> personnelsOverviewSeniorityDetailsVOPageListVO = seniorityDistributionDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "人员概览-司龄分布", personnelsOverviewSeniorityDetailsVOPageListVO.getList(), PersonnelsOverviewSeniorityDetailsVO.class);
    }

    @Override
    public PageListVO<PersonnelsOverviewInsuranceDetailsVO> insurancePurchaseAnalysisDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<PersonnelsOverviewInsuranceDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        // 获取保险购买情况字段ID
        LambdaQueryWrapper<FtbPersonnelsRegistrationFormField> formFieldWrapper = Wrappers.lambdaQuery();
        formFieldWrapper.eq(FtbPersonnelsRegistrationFormField::getName, "保险购买情况");
        formFieldWrapper.eq(FtbPersonnelsRegistrationFormField::getEnabledMark, 0);
        formFieldWrapper.last("limit 1");
        FtbPersonnelsRegistrationFormField ftbPersonnelsRegistrationFormFields = ftbPersonnelsRegistrationFormFieldMapper.selectOne(formFieldWrapper);
        if (Objects.isNull(ftbPersonnelsRegistrationFormFields)) {
            return result;
        }
        List<PersonnelsOverviewInsuranceDetailsVO> queryLists = ftbPersonnelsOverviewAnalysisMapper.insurancePurchaseAnalysisList(
                ftbPersonnelsRegistrationFormFields.getId(),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        if (CollUtil.isEmpty(queryLists)) {
            return result;
        }
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(userIdListByOrganizeIds, "");
        if (actionResult.getCode() != 200) {
            return result;
        }
        Map<String, UserBoundVO> userBoundVOMap = actionResult.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
        // 获取保险购买情况选项
        List<FtbPersonnelsRegistrationFormFieldOption> options = ftbPersonnelsRegistrationFormFieldOptionMapper.selectList(
                Wrappers.<FtbPersonnelsRegistrationFormFieldOption>lambdaQuery()
                        .eq(FtbPersonnelsRegistrationFormFieldOption::getFormFieldId, ftbPersonnelsRegistrationFormFields.getId())
                        .eq(FtbPersonnelsRegistrationFormFieldOption::getEnabledMark, 0));
        Map<String, String> insurancePurchaseMap = options.stream().collect(Collectors.toMap(FtbPersonnelsRegistrationFormFieldOption::getId, FtbPersonnelsRegistrationFormFieldOption::getName));
        queryLists.forEach(a -> {
            UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
            if (Objects.nonNull(userBoundVO)) {
                a.setUserName(userBoundVO.getUserName());
                a.setOrganization(userBoundVO.getOrganizeName());
                a.setJobLevel(userBoundVO.getPositionName());
                a.setJobGrade(userBoundVO.getGradeName());
            }
            // 保险购买情况转换
            if (StrUtil.isNotBlank(a.getInsurancePurchase())) {
                a.setInsurancePurchase(insurancePurchaseMap.getOrDefault(a.getInsurancePurchase(), a.getInsurancePurchase()));
            }
        });
        result.getPagination().setTotal(queryLists.size());
        // 按照组织排序
        queryLists.sort(Comparator.comparing(PersonnelsOverviewInsuranceDetailsVO::getOrganization));
        result.setList(queryLists);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewInsuranceDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(), queryLists.size());
            return CultivatePage.paginate(queryLists, page);
        }
        return result;
    }

    @Override
    public void insurancePurchaseAnalysisDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<PersonnelsOverviewInsuranceDetailsVO> personnelsOverviewInsuranceDetailsVOPageListVO = insurancePurchaseAnalysisDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "人员概览-保险购买分析", personnelsOverviewInsuranceDetailsVOPageListVO.getList(), PersonnelsOverviewInsuranceDetailsVO.class);
    }

    @Override
    public PageListVO<PersonnelsOverviewEducationDetailsVO> educationalBackgroundDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<PersonnelsOverviewEducationDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        List<PersonnelsOverviewEducationDetailsVO> queryLists = ftbPersonnelsOverviewAnalysisMapper.educationalBackgroundList(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        if (CollUtil.isEmpty(queryLists)) {
            return result;
        }
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(userIdListByOrganizeIds, "");
        if (actionResult.getCode() != 200) {
            return result;
        }
        Map<String, UserBoundVO> userBoundVOMap = actionResult.getData().stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
        // 学历转换映射
        Map<String, String> educationMap = new HashMap<>();
        educationMap.put("33", "小学");
        educationMap.put("18", "初中");
        educationMap.put("19", "高中");
        educationMap.put("20", "中专");
        educationMap.put("21", "大专");
        educationMap.put("22", "本科");
        educationMap.put("23", "硕士");
        educationMap.put("24", "博士");
        educationMap.put("25", "其他");
        queryLists.forEach(a -> {
            UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
            if (Objects.nonNull(userBoundVO)) {
                a.setUserName(userBoundVO.getUserName());
                a.setOrganization(userBoundVO.getOrganizeName());
                a.setJobLevel(userBoundVO.getPositionName());
                a.setJobGrade(userBoundVO.getGradeName());
            }
            // 学历转换
            if (StrUtil.isNotBlank(a.getEducation())) {
                a.setEducation(educationMap.getOrDefault(a.getEducation(), a.getEducation()));
            }
        });
        result.getPagination().setTotal(queryLists.size());
        // 按照组织排序
        queryLists.sort(Comparator.comparing(PersonnelsOverviewEducationDetailsVO::getOrganization));
        result.setList(queryLists);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewEducationDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(), queryLists.size());
            return CultivatePage.paginate(queryLists, page);
        }
        return result;
    }

    @Override
    public void educationalBackgroundDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<PersonnelsOverviewEducationDetailsVO> personnelsOverviewEducationDetailsVOPageListVO = educationalBackgroundDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "人员概览-学历分布", personnelsOverviewEducationDetailsVOPageListVO.getList(), PersonnelsOverviewEducationDetailsVO.class);
    }

    @Override
    public PageListVO<PersonnelsOverviewDepartmentDetailsVO> departmentHeadcountRatioDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<PersonnelsOverviewDepartmentDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        // 获取组织ID列表
        ActionResult<List<OrganizeGeneralDetailVO>> listActionResult = v2OrganizeApi.organizesOrHaveChildByOrganizeIds(dto.getOrganizationId(), false, null);
        if (listActionResult == null || CollUtil.isEmpty(listActionResult.getData())) {
            return result;
        }
        List<String> storeOrgIds = listActionResult.getData()
                .stream().filter(a -> OrganizeCategoryEnums.DEPARTMENT.equals(a.getOrganizeCategoryEnums()))
                .map(OrganizeGeneralDetailVO::getId)
                .filter(id -> dto.getOrganizationId().contains(id)).collect(Collectors.toList());
        if (CollUtil.isEmpty(storeOrgIds)) {
            return result;
        }
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(storeOrgIds, null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        // 在职人员
        List<String> presenceOfPersonnel = ftbPersonnelsOverviewAnalysisMapper.departmentHeadcountRatio(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        if (CollUtil.isEmpty(presenceOfPersonnel)) {
            return result;
        }
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(presenceOfPersonnel, null);
        if (actionResult.getCode() != 200) {
            return result;
        }
        Map<String, String> employeeIDQuery = employeeIDQuery(presenceOfPersonnel);
        List<PersonnelsOverviewDepartmentDetailsVO> detailsList = new ArrayList<>();
        actionResult.getData()
                .forEach(a -> {
                    PersonnelsOverviewDepartmentDetailsVO detailsVO = new PersonnelsOverviewDepartmentDetailsVO();
                    detailsVO.setUserId(a.getId());
                    detailsVO.setUserName(a.getUserName());
                    detailsVO.setOrganization(a.getOrganizeName());
                    detailsVO.setJobLevel(a.getPositionName());
                    detailsVO.setJobGrade(a.getGradeName());
                    detailsVO.setEmployeeId(employeeIDQuery.getOrDefault(a.getId(),""));
                    detailsList.add(detailsVO);
                });
        result.getPagination().setTotal(detailsList.size());
        // 按照组织排序
        detailsList.sort(Comparator.comparing(PersonnelsOverviewDepartmentDetailsVO::getOrganization));
        result.setList(detailsList);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewDepartmentDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(), detailsList.size());
            return CultivatePage.paginate(detailsList, page);
        }
        return result;
    }

    @Override
    public void departmentHeadcountRatioDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<PersonnelsOverviewDepartmentDetailsVO> personnelsOverviewDepartmentDetailsVOPageListVO = departmentHeadcountRatioDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "人员概览-部门人数分布", personnelsOverviewDepartmentDetailsVOPageListVO.getList(), PersonnelsOverviewDepartmentDetailsVO.class);
    }

    @Override
    public PageListVO<PersonnelsOverviewStoreDetailsVO> proportionOfStoreNumbersDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<PersonnelsOverviewStoreDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        // 获取门店组织ID列表
        ActionResult<List<OrganizeGeneralDetailVO>> listActionResult = v2OrganizeApi.organizesOrHaveChildByOrganizeIds(dto.getOrganizationId(), false, null);
        if (listActionResult == null || CollUtil.isEmpty(listActionResult.getData())) {
            return result;
        }
        List<String> storeOrgIds = listActionResult.getData()
                .stream().filter(a -> OrganizeCategoryEnums.STORE.equals(a.getOrganizeCategoryEnums()))
                .map(OrganizeGeneralDetailVO::getId)
                .filter(id -> dto.getOrganizationId().contains(id)).collect(Collectors.toList());
        if (CollUtil.isEmpty(storeOrgIds)) {
            return result;
        }
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(storeOrgIds, null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        // 在职人员
        List<String> presenceOfPersonnel = ftbPersonnelsOverviewAnalysisMapper.departmentHeadcountRatio(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        if (CollUtil.isEmpty(presenceOfPersonnel)) {
            return result;
        }
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(presenceOfPersonnel, null);
        if (actionResult.getCode() != 200) {
            return result;
        }
        Map<String, String> employeeIDQuery = employeeIDQuery(presenceOfPersonnel);
        List<PersonnelsOverviewStoreDetailsVO> detailsList = new ArrayList<>();
        actionResult.getData()
                .forEach(a -> {
                    PersonnelsOverviewStoreDetailsVO detailsVO = new PersonnelsOverviewStoreDetailsVO();
                    detailsVO.setUserId(a.getId());
                    detailsVO.setUserName(a.getUserName());
                    detailsVO.setOrganization(a.getOrganizeName());
                    detailsVO.setJobLevel(a.getPositionName());
                    detailsVO.setJobGrade(a.getGradeName());
                    detailsVO.setEmployeeId(employeeIDQuery.getOrDefault(a.getId(),""));
                    detailsList.add(detailsVO);
                });
        result.getPagination().setTotal(detailsList.size());
        // 按照组织排序
        detailsList.sort(Comparator.comparing(PersonnelsOverviewStoreDetailsVO::getOrganization));
        result.setList(detailsList);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewStoreDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(), detailsList.size());
            return CultivatePage.paginate(detailsList, page);
        }
        return result;
    }

    @Override
    public void proportionOfStoreNumbersDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<PersonnelsOverviewStoreDetailsVO> personnelsOverviewStoreDetailsVOPageListVO = proportionOfStoreNumbersDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "人员概览-门店人数分布", personnelsOverviewStoreDetailsVOPageListVO.getList(), PersonnelsOverviewStoreDetailsVO.class);
    }

    @Override
    public PageListVO<PersonnelsOverviewJobDetailsVO> proportionOfJobHeadcountDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<PersonnelsOverviewJobDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId(), null);
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        // 在职人员
        List<String> presenceOfPersonnel = ftbPersonnelsOverviewAnalysisMapper.departmentHeadcountRatio(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , ON_THE_JOB_STATUS, userIdListByOrganizeIds);
        if (CollUtil.isEmpty(presenceOfPersonnel)) {
            return result;
        }
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(presenceOfPersonnel, "");
        if (actionResult.getCode() != 200) {
            return result;
        }
        Map<String, String> employeeIDQuery = employeeIDQuery(presenceOfPersonnel);
        List<PersonnelsOverviewJobDetailsVO> detailsList = new ArrayList<>();
        actionResult.getData().stream()
                .filter(a -> {
                    if (CollUtil.isNotEmpty(dto.getPostId())) {
                        return dto.getPostId().contains(a.getPositionId()) && dto.getOrganizationId().contains(a.getOrganizeId());
                    }
                    return dto.getOrganizationId().contains(a.getOrganizeId());
                })
                .forEach(a -> {
                    PersonnelsOverviewJobDetailsVO detailsVO = new PersonnelsOverviewJobDetailsVO();
                    detailsVO.setUserId(a.getId());
                    detailsVO.setUserName(a.getUserName());
                    detailsVO.setOrganization(a.getOrganizeName());
                    detailsVO.setJobLevel(a.getPositionName());
                    detailsVO.setJobGrade(a.getGradeName());
                    detailsVO.setEmployeeId(employeeIDQuery.getOrDefault(a.getId(),""));
                    detailsList.add(detailsVO);
                });
        result.getPagination().setTotal(detailsList.size());
        // 按照组织排序
        detailsList.sort(Comparator.comparing(PersonnelsOverviewJobDetailsVO::getOrganization));
        result.setList(detailsList);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<PersonnelsOverviewJobDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(), detailsList.size());
            return CultivatePage.paginate(detailsList, page);
        }
        return result;
    }

    @Override
    public void proportionOfJobHeadcountDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
       dto.setPageSize(-1);
       PageListVO<PersonnelsOverviewJobDetailsVO> personnelsOverviewJobDetailsVOPageListVO = proportionOfJobHeadcountDetails(dto);
       EasyExcelUtils.exportExcel(getResponse(), "人员概览-岗位人数分布", personnelsOverviewJobDetailsVOPageListVO.getList(), PersonnelsOverviewJobDetailsVO.class);
    }

    /**
     * 所选组织和岗位员工
     */
    private List<String> selectedOrganizationAndPositionEmployees(List<String> organizationId, List<String> postIds) {
        QueryPageUserDTO queryPageUserDTO = new QueryPageUserDTO();
        queryPageUserDTO.setIsPage(false);
        queryPageUserDTO.setOrganizeIds(organizationId);
        queryPageUserDTO.setHaveChildOrganizeId(false);
        ActionResult<PageListVO<UserBoundVO>> pageListVOActionResult = v2UserApi.pagePost(queryPageUserDTO);
        if (pageListVOActionResult.getCode() == 200 && Objects.nonNull(pageListVOActionResult.getData())) {
            return pageListVOActionResult.getData().getList().stream().map(UserBoundVO::getId).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 计算平均司龄
     *
     * @param numberOfDaysOfAge  总司龄天数
     * @param employedInTheMonth 在职员工数
     * @return 平均司龄字符串表示，格式为"年月天"
     * <p>
     * 此方法用于根据总司龄天数和在职员工数计算平均司龄，并以字符串形式返回
     * 如果输入为null或除数/被除数为0，则返回"0"表示无有效数据进行计算
     * 计算过程中，使用四舍五入的方式处理除法运算，并将结果转换为年、月、天的格式
     * 如果计算过程中发生算术异常（如除以零），同样返回"0"
     */
    private String averageAgeCalculation(BigDecimal numberOfDaysOfAge, BigDecimal employedInTheMonth) {
        // 检查输入参数是否为null
        if (numberOfDaysOfAge == null || employedInTheMonth == null) {
            return "0";
        }
        // 除数或被除数为0
        if (numberOfDaysOfAge.compareTo(BigDecimal.ZERO) == 0 || employedInTheMonth.compareTo(BigDecimal.ZERO) == 0) {
            return "0";
        }
        StringBuilder result = new StringBuilder();
        try {
            // 总司龄天数/在职员工=平均司龄天数
            BigDecimal averageAge = numberOfDaysOfAge.divide(employedInTheMonth, 0, RoundingMode.HALF_UP);
            long orginalValue = averageAge.longValue();
            long yearValue = orginalValue / 365;
            orginalValue %= 365;

            // 如果年份不为0，追加到结果字符串
            if (yearValue != 0) {
                result.append(yearValue).append("年");
            }

            // 如果剩余天数为0，直接返回结果
            if (orginalValue == 0) {
                return result.toString();
            }

            // 计算月份和剩余天数
            long monthValue = orginalValue / 30;
            long dayValue = orginalValue % 30;

            // 如果月份不为0，追加到结果字符串
            if (monthValue != 0) {
                result.append(monthValue).append("月");
            }

            // 如果天数不为0，追加到结果字符串
            if (dayValue != 0) {
                result.append(dayValue).append("天");
            }

            return result.toString();
        } catch (ArithmeticException e) {
            // 处理除法异常，返回默认值
            return "0";
        }
    }

    /**
     * 类型占比
     */
    private List<PersonnelsOverviewProportionVO> handleEmployeeStatusProportion(List<PersonnelsOverviewProportionVO> result
            , List<PersonnelsOverviewProportionVO> data, BigDecimal employedInTheMonth) {
        result.forEach(a -> {
            Optional<PersonnelsOverviewProportionVO> overviewProportionVO = data.stream()
                    .filter(b -> a.getDataName().equals(b.getDataName()))
                    .findFirst();
            a.setDataName(a.getDataTranslationValue());
            if (overviewProportionVO.isPresent()) {
                PersonnelsOverviewProportionVO baseData = overviewProportionVO.get();
                a.setData(baseData.getData());
                a.setPercentage(FtbPersonnelsOverviewAnalysisService.computeDivision(baseData.getData(), employedInTheMonth));
            }
        });
        return result;
    }


    interface AgeDistribution {
        /**
         * 定义司龄和年龄计算
         */
        default PersonnelsOverviewProportionVO algorithmDefinition(List<PersonnelsOverviewProportionVO> data, BigDecimal employedInTheMonth) {
            PersonnelsOverviewProportionVO personnelOverviewProportionVO =
                    new PersonnelsOverviewProportionVO(getDataName(), 0, BigDecimal.ZERO, getDataName());
            long count = data.stream().filter(this::calculationLogic).count();
            personnelOverviewProportionVO.setData((int) count);
            personnelOverviewProportionVO.setPercentage(FtbPersonnelsOverviewAnalysisService.computeDivision(count, employedInTheMonth));
            return personnelOverviewProportionVO;
        }

        /**
         * 逻辑判断
         */
        boolean calculationLogic(PersonnelsOverviewProportionVO a);

        /**
         * 汉字转义
         */
        String getDataName();
    }

    /**
     * 获取司龄和年龄计算
     */
    private <T extends AgeDistribution> List<PersonnelsOverviewProportionVO> getAgeDistributions(List<T> data
            , List<PersonnelsOverviewProportionVO> calculatedData, BigDecimal employedInTheMonth) {
        return data.stream()
                .map(a -> a.algorithmDefinition(calculatedData, employedInTheMonth))
                .collect(Collectors.toList());
    }

    @Getter
    @RequiredArgsConstructor
    enum AgeDistributionFirst implements AgeDistribution {
        // 不满3个月
        // 3-6个月
        // 7个月～1年
        // 1～3年
        // 4～5年
        // 6～10年
        // 10年以上
        LESS_THAN_THREE_MONTHS("不满3个月") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() < 30 * 3;
            }
        },
        THREE_TO_SIX_MONTHS("3-6个月") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() >= 30 * 3 && a.getData() < 30 * 6;
            }
        },
        SEVEN_MONTHS_TO_ONE_YEAR("6个月～1年") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() >= 30 * 6 && a.getData() < 365;
            }
        },
        ONE_TO_THREE_YEARS("1～3年") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() >= 365 && a.getData() < 365 * 3;
            }
        },
        FOUR_TO_FIVE_YEARS("3～5年") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() >= 365 * 3 && a.getData() < 365 * 5;
            }
        },
        SIX_TO_TEN_YEARS("5～10年") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() >= 365 * 5 && a.getData() < 365 * 10;
            }
        },
        MORE_THAN_TEN_YEARS("10年以上") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() >= 365 * 10;
            }
        };

        private final String dataName;

    }

    @Getter
    @RequiredArgsConstructor
    enum AgeDistributionSecond implements AgeDistribution {
        /**
         * 25岁以下
         * 25～35岁
         * 36～45岁
         * 46～55岁
         * 55岁以上
         */
        LESS_THAN_25("25岁以下") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() < 25;
            }
        },
        BETWEEN_25_AND_35("25～35岁") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() >= 25 && a.getData() <= 35;
            }
        },
        BETWEEN_36_AND_45("36～45岁") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() > 35 && a.getData() <= 45;
            }
        },
        BETWEEN_46_AND_55("46～55岁") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() > 45 && a.getData() <= 55;
            }
        },
        MORE_THAN_55("55岁以上") {
            @Override
            public boolean calculationLogic(PersonnelsOverviewProportionVO a) {
                return a.getData() > 55;
            }
        };

        private final String dataName;

    }

    /**
     * 获取组织下离职员工ID集合
     *
     * @param orgIds
     * @return
     */
    @SuppressWarnings("Duplicates")
    private List<String> doEmployeesOfResignOrganization(List<String> orgIds) {
        LambdaQueryWrapper<FtbPersonnelsTurnoverManagement> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(FtbPersonnelsTurnoverManagement::getEnableMark, 0);
        wrapper.eq(FtbPersonnelsTurnoverManagement::getWorkingCondition, "305");
        List<FtbPersonnelsTurnoverManagement> managements = turnoverManagementMapper.selectList(wrapper);
        return managements.stream().filter(vo -> StringUtils.isNotEmpty(vo.getOrganizationInfo()))
                .filter(vo -> CollUtil.isNotEmpty(JSONObject.parseArray(vo.getOrganizationInfo(), WorkerGroupDataDto.class)
                        .stream().map(WorkerGroupDataDto::getAffiliatedOrg).collect(Collectors.toList()).stream().filter(orgIds::contains).collect(Collectors.toList()))
                ).map(FtbPersonnelsTurnoverManagement::getUserId).collect(Collectors.toList());
    }

    private List<PersonnelsOverviewSituationDetailsVO> doEmployeesOfResignOrganizationList(List<String> orgIds) {
        LambdaQueryWrapper<FtbPersonnelsTurnoverManagement> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(FtbPersonnelsTurnoverManagement::getEnableMark, 0);
        wrapper.eq(FtbPersonnelsTurnoverManagement::getWorkingCondition, "305");
        List<FtbPersonnelsTurnoverManagement> managements = turnoverManagementMapper.selectList(wrapper);
        return managements.stream().filter(vo -> StringUtils.isNotEmpty(vo.getOrganizationInfo()))
                .filter(vo -> CollUtil.isNotEmpty(JSONObject.parseArray(vo.getOrganizationInfo(), WorkerGroupDataDto.class)
                        .stream().map(WorkerGroupDataDto::getAffiliatedOrg).collect(Collectors.toList()).stream().filter(orgIds::contains).collect(Collectors.toList()))
                ).map(a -> {
                    List<WorkerGroupDataDto> workerGroupDataDtos = JSONObject.parseArray(a.getOrganizationInfo(), WorkerGroupDataDto.class);
                    PersonnelsOverviewSituationDetailsVO vo = new PersonnelsOverviewSituationDetailsVO();
                    vo.setUserId(a.getUserId());
                    vo.setUserName(a.getUserName());
                    if (CollUtil.isNotEmpty(workerGroupDataDtos)) {
                        WorkerGroupDataDto workerGroupDataDto = workerGroupDataDtos.get(0);
                        vo.setOrganization(workerGroupDataDto.getAffiliatedOrgName());
                        vo.setJobLevel(workerGroupDataDto.getAffiliatedPositionName());
                        vo.setJobGrade(workerGroupDataDto.getAffiliatedRankName());
                    }
                    return vo;
                }).collect(Collectors.toList());
    }

    private Map<String,String> employeeIDQuery(List<String> userIds) {
        LambdaQueryWrapper<FtbPersonnelsStaffRoster> wrapper = Wrappers.lambdaQuery();
        wrapper.select(FtbPersonnelsStaffRoster::getUserId,FtbPersonnelsStaffRoster::getSystemWokerId);
        wrapper.in(FtbPersonnelsStaffRoster::getUserId,userIds);
        List<FtbPersonnelsStaffRoster> staffRosters = ftbPersonnelsStaffRosterMapper.selectList(wrapper);
        return staffRosters.stream()
                .filter(a->StrUtil.isNotBlank(a.getSystemWokerId()))
                .collect(Collectors.toMap(FtbPersonnelsStaffRoster::getUserId, FtbPersonnelsStaffRoster::getSystemWokerId));
    }

    private PaginationVO initPaginationVO(CultivatePage dto) {
        PaginationVO pagination = new PaginationVO();
        pagination.setCurrentPage(dto.getCurrentPage());
        pagination.setPageSize(dto.getPageSize());
        pagination.setTotal(0);
        return pagination;
    }

    public static HttpServletResponse getResponse() {
        // 从当前threadlocal中获取到
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return servletRequestAttributes.getResponse();
    }

}
