/**
 * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
 * <p>
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl.html
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.xiaoniu.subsystem.business.controller;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.xiaoniu.common.core.result.R;
import com.xiaoniu.common.core.utils.BeanUtil;
import com.xiaoniu.common.core.utils.DateUtils;
import com.xiaoniu.common.core.utils.poi.ExcelUtil;
import com.xiaoniu.common.log.annotation.Log;
import com.xiaoniu.common.log.enums.BusinessType;
import com.xiaoniu.subsystem.business.domain.Project;
import com.xiaoniu.subsystem.business.domain.ProjectPersonnelInfo;
import com.xiaoniu.subsystem.business.domain.dto.*;
import com.xiaoniu.subsystem.business.domain.vo.*;
import com.xiaoniu.subsystem.business.service.IProjectPersonnelInfoService;
import com.xiaoniu.subsystem.business.service.IProjectService;
import com.xiaoniu.subsystem.business.service.IWaitDoneService;
import com.xiaoniu.subsystem.system.domain.SysDictData;
import com.xiaoniu.subsystem.system.domain.Unit;
import com.xiaoniu.subsystem.system.service.ISysDictDataService;
import com.xiaoniu.subsystem.system.service.IUnitService;
import com.xiaoniu.subsystem.system.utils.IdCardCheckUtils;
import com.xiaoniu.subsystem.system.utils.MobileNumberValidator;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.xiaoniu.common.security.utils.SecurityUtils.*;

/**
 * 计划人员信息表 控制器
 *
 * @author sst
 * @since 2024-11-26
 */
@RestController
@AllArgsConstructor
@RequestMapping("/projectpersonnelinfo")
@Tag(name = "计划人员信息表", description = "计划人员信息表接口")
public class ProjectPersonnelInfoController {

    private IProjectPersonnelInfoService projectPersonnelInfoService;
    private IProjectService projectService;
    private ISysDictDataService dictDataService;
    private IUnitService unitService;
    private IWaitDoneService waitDoneService;

    /**
     * 详情
     */
    @GetMapping("/detail")
    @ApiOperationSupport(order = 1)
    @Operation(summary = "详情", description = "传入projectPersonnelInfo")
    public R<PersonnelInfoVO> detail(@Parameter(description = "主键", required = true)
                                     @RequestParam Long projectPersonnelInfoId) {
        ProjectPersonnelInfo detail = projectPersonnelInfoService.getById(projectPersonnelInfoId);
        if (null != detail) {
            List<ProjectPersonnelInfo> list = projectPersonnelInfoService.list(
                    new LambdaQueryWrapper<ProjectPersonnelInfo>()
                            .eq(ProjectPersonnelInfo::getIdCard, detail.getIdCard()));
            return R.data(BeanUtil.copy(detail, PersonnelInfoVO.class)
                    .setInfoVOS(BeanUtil.copy(list, ProjectPersonnelInfoVO.class)));
        }
        return R.data(BeanUtil.copy(detail, PersonnelInfoVO.class));
    }

    /**
     * 分页 计划人员信息表
     */
    @GetMapping("/page")
    @ApiOperationSupport(order = 2)
    @Operation(summary = "分页", description = "传入projectPersonnelInfo")
    public R<IPage<ProjectPersonnelInfoVO>> page(@Validated ProjectPersonnelPageDTO dto) {
        List<Project> list = projectService.list(
                new LambdaQueryWrapper<Project>().eq(Project::getCreateDept, getUnitId()));
        if (CollectionUtils.isEmpty(list)) {
            return R.data(new Page<>(dto.getPageNum(), dto.getPageSize()));
        }
        List<Long> longs = new ArrayList<Long>();
        getLongList(list, longs);
        IPage<ProjectPersonnelInfo> pages = projectPersonnelInfoService.page(
                new Page<>(dto.getPageNum(), dto.getPageSize()), set(dto)
                        .eq(ProjectPersonnelInfo::getIsReport, "1")
                        .in(CollectionUtils.isNotEmpty(longs), ProjectPersonnelInfo::getProjectId, longs));
        return R.data(BeanUtil.copy(pages, ProjectPersonnelInfoVO.class));
    }

    /**
     * 导出
     */
    @GetMapping("/export")
    @ApiOperationSupport(order = 3)
    @Log(title = "人员导出", businessType = BusinessType.EXPORT)
    @Operation(summary = "导出", description = "传入ids")
    public void export(HttpServletResponse response, @Validated ProjectPersonnelPageDTO dto) {
        List<ProjectPersonnelInfo> list = new ArrayList<>();
        if (StringUtils.isNotBlank(dto.getIds())) {
            list.addAll(projectPersonnelInfoService.list(new LambdaQueryWrapper<ProjectPersonnelInfo>()
                    .orderByDesc(ProjectPersonnelInfo::getCreateTime)
                    .in(StringUtils.isNotBlank(dto.getIds()), ProjectPersonnelInfo::getUserId,
                            Arrays.stream(dto.getIds().split(",")).toList())));
        } else {
            List<Long> longs = new ArrayList<Long>();
            if (null != dto.getProjectId()) {
                longs.add(dto.getProjectId());
            }
            List<Project> list1 = projectService.list(
                    new LambdaQueryWrapper<Project>().eq(Project::getCreateDept, getUnitId()));
            getLongList(list1, longs);
            list.addAll(projectPersonnelInfoService.list(set(dto)
                    .eq(ProjectPersonnelInfo::getIsReport, "1")
                    .in(CollectionUtils.isNotEmpty(longs), ProjectPersonnelInfo::getProjectId, longs)));
        }
        List<ProjectPersonnelInfoExcelVO> list1 = new ArrayList<ProjectPersonnelInfoExcelVO>();
        if (CollectionUtils.isNotEmpty(list)) {
            List<SysDictData> data = dictDataService.list(
                    new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, "1"));
            Map<String, String> map = data.stream()
                    .collect(Collectors.toMap(SysDictData::getDictLabel, SysDictData::getDictValue));
            list1.addAll(list.stream().map(l ->
                    Objects.requireNonNull(BeanUtil.copy(l, ProjectPersonnelInfoExcelVO.class))
                            .setMajorTypeName(map.get(l.getMajorType()))).toList());
        }
        ExcelUtil<ProjectPersonnelInfoExcelVO> excelUtil = new ExcelUtil<>(ProjectPersonnelInfoExcelVO.class);
        excelUtil.exportExcel(response, list1, "人员数据");
    }

    /**
     * 新增 计划人员信息表
     */
    @PostMapping("/save")
    @ApiOperationSupport(order = 4)
    @Operation(summary = "新增", description = "传入projectPersonnelInfo")
    public R save(@Valid @RequestBody ProjectPersonnelInfoDTO dto) {
        if (StringUtils.isNotBlank(dto.getPhonenumber())
                && !MobileNumberValidator.isValidPhoneNumber(dto.getPhonenumber())) {
            return R.fail("电话号码有误：" + dto.getPhonenumber() + "，请核对");
        }
        if (StringUtils.isNotBlank(dto.getIdCard())
                && !IdCardCheckUtils.idCardNumberCheck(dto.getIdCard())) {
            return R.fail("身份证号有误：" + dto.getIdCard() + "，请核对");
        }
        if (1 == dto.getType()) {
            Project project = projectService.getOne(new LambdaQueryWrapper<Project>()
                    .eq(Project::getFlightId, dto.getFlightId())
                    .eq(Project::getFlightName, dto.getFlightName())
                    .eq(Project::getTrainingTime, dto.getTrainingTime())
                    .eq(Project::getYear, StringUtils.isBlank(dto.getYear()) ?
                            DateUtils.parseDateToStr("yyyy", dto.getTrainingTime()) : dto.getYear())
                    .in(Project::getIsDistribution, 0, 1, 2)
                    .eq(Project::getCreateDept, dto.getSendingUnitId()));
            if (null == project) {
                return R.fail("送训单位：" + dto.getSendingUnitName()
                        + ",未查询到年度：" + (StringUtils.isBlank(dto.getYear()) ?
                        DateUtils.parseDateToStr("yyyy", dto.getTrainingTime()) : dto.getYear()) +
                        "年,开训时间：" + DateUtils.dateTime(dto.getTrainingTime()) +
                        ",专业（班次）名称：" + dto.getFlightName() + " 的计划,或者计划状态为：已培训/作废,请核对");
            }
            dto.setProjectId(project.getProjectId());
            dto.setIsReport("1");
        }
        ProjectPersonnelInfo personnelInfo = projectPersonnelInfoService.getOne(new LambdaQueryWrapper<ProjectPersonnelInfo>()
                .eq(ProjectPersonnelInfo::getFlightId, dto.getFlightId())
                .eq(ProjectPersonnelInfo::getFlightName, dto.getFlightName())
                .eq(ProjectPersonnelInfo::getTrainingTime, dto.getTrainingTime())
                .eq(ProjectPersonnelInfo::getYear, StringUtils.isBlank(dto.getYear()) ?
                        DateUtils.parseDateToStr("yyyy", dto.getTrainingTime()) : dto.getYear())
                // .eq(ProjectPersonnelInfo::getProjectId, dto.getProjectId())
                .eq(ProjectPersonnelInfo::getIdCard, dto.getIdCard()));
        if (null != personnelInfo) {
            return R.fail("年度：" + (StringUtils.isBlank(dto.getYear()) ?
                    DateUtils.parseDateToStr("yyyy", dto.getTrainingTime()) : dto.getYear()) +
                    ",开训时间：" + DateUtils.dateTime(dto.getTrainingTime()) +
                    ",专业（班次）名称：" + dto.getFlightName() +
                    ",的计划下已存在身份证号：" + dto.getIdCard() + " 的人员，添加单位:" + personnelInfo.getSendingUnitName());
        }
        return R.status(projectPersonnelInfoService.save(
                dto.setYear(StringUtils.isBlank(dto.getYear()) ?
                        DateUtils.parseDateToStr("yyyy", dto.getTrainingTime()) : dto.getYear())
                        .setIsReport(dto.getType().toString())
                        .setStatus(1)
                        .setCreateDept(getUnitId())
                        .setCreateUser(getUserId())
                        .setCreateTime(new Date())));
    }

    /**
     * 修改 计划人员信息表
     */
    @PostMapping("/update")
    @ApiOperationSupport(order = 5)
    @Operation(summary = "修改", description = "传入projectPersonnelInfo")
    public R update(@Valid @RequestBody ProjectPersonnelInfoDTO dto) {
        if (StringUtils.isNotBlank(dto.getPhonenumber())
                && !MobileNumberValidator.isValidPhoneNumber(dto.getPhonenumber())) {
            return R.fail("电话号码有误：" + dto.getPhonenumber() + "，请核对");
        }
        if (StringUtils.isNotBlank(dto.getIdCard())
                && !IdCardCheckUtils.idCardNumberCheck(dto.getIdCard())) {
            return R.fail("身份证号有误：" + dto.getIdCard() + "，请核对");
        }
        if (1 == dto.getType()) {
            Project project = projectService.getOne(new LambdaQueryWrapper<Project>()
                    .eq(Project::getFlightId, dto.getFlightId())
                    .eq(Project::getFlightName, dto.getFlightName())
                    .eq(Project::getTrainingTime, dto.getTrainingTime())
                    .eq(Project::getYear, StringUtils.isBlank(dto.getYear()) ?
                            DateUtils.parseDateToStr("yyyy", dto.getTrainingTime()) : dto.getYear())
                    .in(Project::getIsDistribution, 0, 1, 2)
                    .eq(Project::getCreateDept, dto.getSendingUnitId()));
            if (null == project) {
                return R.fail("送训单位：" + dto.getSendingUnitName()
                        + ",未查询到年度：" + (StringUtils.isBlank(dto.getYear()) ?
                        DateUtils.parseDateToStr("yyyy", dto.getTrainingTime()) : dto.getYear()) +
                        "年,开训时间：" + DateUtils.dateTime(dto.getTrainingTime()) +
                        ",专业（班次）名称：" + dto.getFlightName() + ",的计划,或者计划状态为：已培训/作废,请核对");
            }
            dto.setProjectId(project.getProjectId());
            dto.setIsReport("1");
        }
        ProjectPersonnelInfo personnelInfo = projectPersonnelInfoService.getOne(new LambdaQueryWrapper<ProjectPersonnelInfo>()
                .eq(ProjectPersonnelInfo::getFlightId, dto.getFlightId())
                .eq(ProjectPersonnelInfo::getFlightName, dto.getFlightName())
                .eq(ProjectPersonnelInfo::getTrainingTime, dto.getTrainingTime())
                .eq(ProjectPersonnelInfo::getYear, StringUtils.isBlank(dto.getYear()) ?
                        DateUtils.parseDateToStr("yyyy", dto.getTrainingTime()) : dto.getYear())
                // .eq(ProjectPersonnelInfo::getProjectId, dto.getProjectId())
                .eq(ProjectPersonnelInfo::getIdCard, dto.getIdCard())
                        .ne(ProjectPersonnelInfo::getUserId, dto.getUserId()));
        if (null != personnelInfo) {
            return R.fail("年度：" + (StringUtils.isBlank(dto.getYear()) ?
                    DateUtils.parseDateToStr("yyyy", dto.getTrainingTime()) : dto.getYear()) +
                    ",开训时间：" + DateUtils.dateTime(dto.getTrainingTime()) +
                    ",专业（班次）名称：" + dto.getFlightName() +
                    ",的计划下已存在身份证号：" + dto.getIdCard() + " 的人员，添加单位:" + personnelInfo.getSendingUnitName());
        }
        return R.status(projectPersonnelInfoService.updateById(
                dto.setStatus(1)
                        .setYear(StringUtils.isBlank(dto.getYear()) ?
                                DateUtils.parseDateToStr("yyyy", dto.getTrainingTime()) : dto.getYear())
                        .setUpdateUser(getUserId()).setUpdateTime(new Date())));
    }

    /**
     * 人员统计列表-单位统计
     */
    @GetMapping("/unit/total")
    @ApiOperationSupport(order = 6)
    @Operation(summary = "人员统计列表-单位统计")
    public R<List<UnitTotalVO>> unitTotal(@Parameter(description = "班次名称") @RequestParam(required = false) String flightName,
                                          @Parameter(description = "年度") @RequestParam(required = false) String year) {
        List<UnitTotalVO> unitTotalVOS = new ArrayList<UnitTotalVO>();
        if (StringUtils.equals("admin", getUsername()) || 0 == getUnitId()) {
            return R.data(unitTotalVOS);
        }
        List<Project> list = projectService.list(new LambdaQueryWrapper<Project>()
                .like(StringUtils.isNotBlank(flightName), Project::getFlightName, flightName)
                .eq(StringUtils.isNotBlank(year), Project::getYear, year)
                .eq(Project::getCreateDept, getUnitId()));
        if (CollectionUtils.isEmpty(list)) {
            return R.data(unitTotalVOS);
        }
        Unit unit = unitService.getById(getUnitId());
        List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                .eq(Unit::getParentId, unit.getUnitId()));
        List<Project> list1 = new ArrayList<Project>();
        List<ProjectPersonnelInfo> personnelInfos = new ArrayList<ProjectPersonnelInfo>();
        List<UnitTotalVO> unitTotalVOS1 = new ArrayList<UnitTotalVO>();
        if (CollectionUtils.isNotEmpty(units)) {
            for (Unit u : units) {
                List<Project> projects = projectService.list(new LambdaQueryWrapper<Project>()
                        .like(StringUtils.isNotBlank(flightName), Project::getFlightName, flightName)
                        .eq(StringUtils.isNotBlank(year), Project::getYear, year)
                        .eq(Project::getCreateDept, u.getUnitId()));
                List<Project> projects1 = new ArrayList<Project>();
                List<Unit> uns = unitService.list(new LambdaQueryWrapper<Unit>()
                        .eq(Unit::getParentId, u.getUnitId()));
                if (CollectionUtils.isNotEmpty(units)) {
                    for (Unit u1 : uns) {
                        getUnitProjectVO(u1, flightName, year, projects1);
                    }
                }
                if (CollectionUtils.isNotEmpty(projects1)) {
                    projects.addAll(projects1.stream().filter(p -> 0 == p.getParentId()).toList());
                }
                List<ProjectPersonnelInfo> infoList = projectPersonnelInfoService.list(
                        new LambdaQueryWrapper<ProjectPersonnelInfo>()
                                .eq(ProjectPersonnelInfo::getStatus, 1)
                                .in(CollectionUtils.isNotEmpty(projects), ProjectPersonnelInfo::getProjectId,
                                        projects.stream().map(Project::getProjectId).toList()));
                unitTotalVOS1.add(new UnitTotalVO()
                        .setUnitName(u.getUnitName())
                        .setProjectNnum(projects.stream().map(l ->
                                        BigDecimal.valueOf(Double.parseDouble(StringUtils.isEmpty(l.getShouldAttendance()) ?
                                                "0" : l.getShouldAttendance())))
                                .reduce(BigDecimal.ZERO, BigDecimal::add).intValue())
                        .setActualNum(CollectionUtils.isNotEmpty(infoList) ? infoList.size() : 0)
                        .setAwaitNum(CollectionUtils.isNotEmpty(infoList) ?
                                (int) infoList.stream().filter(l -> new Date().compareTo(l.getTrainingTime()) < 0).count() : 0)
                        .setProceedNum(CollectionUtils.isNotEmpty(infoList) ?
                                (int) infoList.stream().filter(l -> l.getTrainingTime().compareTo(new Date()) < 0
                                        && StringUtils.equals("0", l.getIsFinishSchool())).count() : 0)
                        .setCompleteNum(CollectionUtils.isNotEmpty(infoList) ?
                                (int) infoList.stream().filter(l -> StringUtils.equals("1", l.getIsFinishSchool())).count() : 0)
                        .setOptimalNum(CollectionUtils.isNotEmpty(infoList) ?
                                (int) infoList.stream().filter(l -> StringUtils.equals("1", l.getIsFinishSchool())
                                        && StringUtils.equals("优", l.getEvaluationOrder())).count() : 0));
                list1.addAll(projects);
                personnelInfos.addAll(infoList);
            }
        }
        if (CollectionUtils.isNotEmpty(list1)) {
            list.addAll(list1.stream().filter(p -> 0 == p.getParentId()).toList());
        }
        unitTotalVOS.add(new UnitTotalVO()
                .setUnitName(unit.getUnitName())
                .setProjectNnum(list.stream().map(l ->
                                BigDecimal.valueOf(Double.parseDouble(StringUtils.isEmpty(l.getShouldAttendance()) ?
                                        "0" : l.getShouldAttendance())))
                        .reduce(BigDecimal.ZERO, BigDecimal::add).intValue())
                .setActualNum(CollectionUtils.isNotEmpty(personnelInfos) ? personnelInfos.size() : 0)
                .setAwaitNum(CollectionUtils.isNotEmpty(personnelInfos) ?
                        (int) personnelInfos.stream().filter(
                                l -> new Date().compareTo(l.getTrainingTime()) < 0).count() : 0)
                .setProceedNum(CollectionUtils.isNotEmpty(personnelInfos) ?
                        (int) personnelInfos.stream().filter(
                                l -> l.getTrainingTime().compareTo(new Date()) < 0
                                && StringUtils.equals("0", l.getIsFinishSchool())).count() : 0)
                .setCompleteNum(CollectionUtils.isNotEmpty(personnelInfos) ?
                        (int) personnelInfos.stream().filter(
                                l -> StringUtils.equals("1", l.getIsFinishSchool())).count() : 0)
                .setOptimalNum(CollectionUtils.isNotEmpty(personnelInfos) ?
                        (int) personnelInfos.stream().filter(
                                l -> StringUtils.equals("1", l.getIsFinishSchool())
                                && StringUtils.equals("优", l.getEvaluationOrder())).count() : 0));
        unitTotalVOS.addAll(unitTotalVOS1);
        return R.data(unitTotalVOS);
    }

    /**
     * 删除 计划人员信息表
     */
    @PostMapping("/remove")
    @ApiOperationSupport(order = 7)
    @Operation(summary = "删除", description = "传入ids")
    public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String projectPersonnelInfoIds) {
        return R.status(projectPersonnelInfoService.removeByIds(Arrays.stream(projectPersonnelInfoIds.split(",")).toList()));
    }

    @PostMapping("/import")
    @ApiOperationSupport(order = 8)
    @Log(title = "人员导入", businessType = BusinessType.IMPORT)
    @Operation(summary = "导入")
    public R importData(MultipartFile file,
                        @Parameter(description = "是否支持更新", required = true)
                        @RequestParam boolean updateSupport,
                        @Parameter(description = "导入位置（0计划详情 1参训人员管理）", required = true)
                        @RequestParam Integer type) throws Exception {
        if (0 == type) {
            ExcelUtil<ProjectPersonnelInfoExcelBMDTO> util = new ExcelUtil<>(ProjectPersonnelInfoExcelBMDTO.class);
            List<ProjectPersonnelInfoExcelBMDTO> list = util.importExcel(file.getInputStream());
            if (CollectionUtils.isEmpty(list)) {
                return R.fail("导入计划培训人员信息数据不能为空！");
            }
            List<SysDictData> data = dictDataService.list(
                    new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, "1"));
            Map<String, String> map = data.stream()
                    .collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
            List<ProjectPersonnelInfo> list1 = new ArrayList<>();
            for (ProjectPersonnelInfoExcelBMDTO p : list) {
                if (StringUtils.isBlank(p.getMajorTypeName())) {
                    return R.fail("专业类型不能为空");
                }
                if (StringUtils.isBlank(map.get(p.getMajorTypeName()))) {
                    return R.fail("专业类型：" + p.getMajorTypeName() + ",不存在,请核对");
                }
                list1.add(BeanUtil.copy(p, ProjectPersonnelInfo.class)
                        .setMajorType(map.get(p.getMajorTypeName())));
            }
            return R.success(projectPersonnelInfoService.importData(list1, updateSupport, getUserId(), type));
        }
        ExcelUtil<ProjectPersonnelInfoExcelDTO> util = new ExcelUtil<>(ProjectPersonnelInfoExcelDTO.class);
        List<ProjectPersonnelInfoExcelDTO> list = util.importExcel(file.getInputStream());
        if (CollectionUtils.isEmpty(list)) {
            return R.fail("导入计划培训人员信息数据不能为空！");
        }
        List<SysDictData> data = dictDataService.list(
                new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, "1"));
        Map<String, String> map = data.stream()
                .collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        List<ProjectPersonnelInfo> list1 = new ArrayList<>();
        for (ProjectPersonnelInfoExcelDTO p : list) {
            if (StringUtils.isBlank(p.getMajorTypeName())) {
                return R.fail("专业类型不能为空");
            }
            if (StringUtils.isBlank(map.get(p.getMajorTypeName()))) {
                return R.fail("专业类型：" + p.getMajorTypeName() + ",不存在,请核对");
            }
            list1.add(BeanUtil.copy(p, ProjectPersonnelInfo.class)
                    .setMajorType(map.get(p.getMajorTypeName())));
        }
        return R.success(projectPersonnelInfoService.importData(list1, updateSupport, getUserId(), type));
    }

    @GetMapping("/importTemplate")
    @ApiOperationSupport(order = 9)
    @Operation(summary = "导入模版下载")
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<ProjectPersonnelInfoExcelBMVO> util = new ExcelUtil<>(ProjectPersonnelInfoExcelBMVO.class);
        util.importTemplateExcel(response, "人员导入模版");
    }

    /**
     * 上报机关
     */
    @GetMapping("/reportingAuthority")
    @ApiOperationSupport(order = 10)
    @Operation(summary = "上报机关")
    public R reportingAuthority(@Parameter(description = "计划ID") @RequestParam Long projectId) {
        return R.status(projectPersonnelInfoService.reportingAuthority(projectId));
    }

    /**
     * 审核
     */
    @PostMapping("/examine")
    @ApiOperationSupport(order = 11)
    @Operation(summary = "审核")
    public R examine(@RequestBody @Validated ProjectUserExamineDTO dto) {
        return R.status(projectPersonnelInfoService.examine(dto));
    }

    /**
     * 分页 计划详情分页
     */
    @GetMapping("/examine/page")
    @ApiOperationSupport(order = 12)
    @Operation(summary = "计划详情分页", description = "传入projectPersonnelInfo")
    public R<IPage<ProjectPersonnelInfoVO>> examinePage(@Validated ProjectPersonnelPageDTO dto) {
        List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                .eq(null != dto.getSendingUnitId(), Unit::getParentId, dto.getSendingUnitId())
                .eq(null == dto.getSendingUnitId(), Unit::getParentId, getUnitId()));
        List<Long> longs = new ArrayList<Long>();
        List<Project> projects;
        if (null != dto.getSendingUnitId()) {
            projects = projectService.list(new LambdaQueryWrapper<Project>()
                    .eq(Project::getProjectId, dto.getProjectId()));
            getLongListNew(projects, longs, dto.getSendingUnitId());
            if (CollectionUtils.isEmpty(longs)) {
                return R.data(new Page<>(dto.getPageNum(), dto.getPageSize()));
            }
            projects = projectService.list(new LambdaQueryWrapper<Project>()
                    .eq(Project::getParentId, longs.get(0)));
            getLongList(projects, longs);
        } else {
            longs.add(dto.getProjectId());
            projects = projectService.list(new LambdaQueryWrapper<Project>()
                    .eq(Project::getParentId, dto.getProjectId()));
            getLongList(projects, longs);
        }
        IPage<ProjectPersonnelInfo> pages = projectPersonnelInfoService.page(
                new Page<>(dto.getPageNum(), dto.getPageSize()), setNew(dto)
                        .eq(null != dto.getSendingUnitId() &&
                                        !Objects.equals(getUnitId(), dto.getSendingUnitId()) &&
                                        CollectionUtils.isEmpty(units),
                                ProjectPersonnelInfo::getIsReport, "1")
                        .eq(CollectionUtils.isNotEmpty(units), ProjectPersonnelInfo::getIsReport, "1")
                        .in(CollectionUtils.isNotEmpty(longs), ProjectPersonnelInfo::getProjectId, longs));
        return R.data(BeanUtil.copy(pages, ProjectPersonnelInfoVO.class));
    }

    /**
     * 获取需求报名人数
     */
    @GetMapping("/get/flightIds")
    @ApiOperationSupport(order = 13)
    @Operation(summary = "获取协议/合同班次ids")
    public R<List<Long>> getPeopleNum() {
        List<ProjectPersonnelInfo> list = projectPersonnelInfoService.list(new LambdaQueryWrapper<ProjectPersonnelInfo>()
                .eq(ProjectPersonnelInfo::getCreateDept, getUnitId()));
        if (CollectionUtils.isEmpty(list)) return R.data(Collections.emptyList());
        return R.data(list.stream().map(ProjectPersonnelInfo::getFlightId).toList());
    }

    /**
     * 人员审核导出
     */
    @GetMapping("/examine/export")
    @ApiOperationSupport(order = 13)
    @Log(title = "人员审核导出", businessType = BusinessType.EXPORT)
    @Operation(summary = "人员审核导出", description = "传入ids")
    public void examineExport(HttpServletResponse response, @Validated ProjectPersonnelPageDTO dto) {
        List<ProjectPersonnelInfo> list = new ArrayList<>();
        if (StringUtils.isNotBlank(dto.getIds())) {
            list.addAll(projectPersonnelInfoService.list(new LambdaQueryWrapper<ProjectPersonnelInfo>()
                    .orderByDesc(ProjectPersonnelInfo::getCreateTime)
                    .in(StringUtils.isNotBlank(dto.getIds()), ProjectPersonnelInfo::getUserId,
                            Arrays.stream(dto.getIds().split(",")).toList())));
        } else {
            List<Long> longs = new ArrayList<Long>();
            longs.add(dto.getProjectId());
            List<Project> projects = projectService.list(new LambdaQueryWrapper<Project>()
                    .eq(Project::getParentId, dto.getProjectId()));
            getLongList(projects, longs);
            List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                    .eq(Unit::getParentId, getUnitId()));
            list.addAll(projectPersonnelInfoService.list(set(dto)
                    .eq(CollectionUtils.isNotEmpty(units), ProjectPersonnelInfo::getIsReport, "1")
                    .in(CollectionUtils.isNotEmpty(longs), ProjectPersonnelInfo::getProjectId, longs)));
        }
        List<ProjectPersonnelInfoExcelBMVO> list1 = new ArrayList<ProjectPersonnelInfoExcelBMVO>();
        if (CollectionUtils.isNotEmpty(list)) {
            List<SysDictData> data = dictDataService.list(
                    new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, "1"));
            Map<String, String> map = data.stream()
                    .collect(Collectors.toMap(SysDictData::getDictLabel, SysDictData::getDictValue));
            list1.addAll(list.stream().map(l ->
                    BeanUtil.copy(l, ProjectPersonnelInfoExcelBMVO.class)
                            .setMajorTypeName(map.get(l.getMajorType()))).collect(Collectors.toList()));
        }
        ExcelUtil<ProjectPersonnelInfoExcelBMVO> excelUtil = new ExcelUtil<>(ProjectPersonnelInfoExcelBMVO.class);
        excelUtil.exportExcel(response, list1, "人员数据");
    }

    /**
     * 人员统计列表-年度统计
     */
    @GetMapping("/year/total")
    @ApiOperationSupport(order = 14)
    @Operation(summary = "人员统计列表-年度统计")
    public R<List<YearTotalVO>> yearTotal(@Parameter(description = "班次名称") @RequestParam(required = false) String flightName,
                                          @Parameter(description = "年度") @RequestParam(required = false) String year) {
        List<YearTotalVO> yearTotalVOS = new ArrayList<YearTotalVO>();
        if (StringUtils.equals("admin", getUsername()) || 0 == getUnitId()) {
            return R.data(yearTotalVOS);
        }
        List<Project> list = projectService.list(new LambdaQueryWrapper<Project>()
                .orderByDesc(Project::getYear)
                .like(StringUtils.isNotBlank(flightName), Project::getFlightName, flightName)
                .eq(StringUtils.isNotBlank(year), Project::getYear, year)
                .eq(Project::getCreateDept, getUnitId()));
        if (CollectionUtils.isEmpty(list)) {
            return R.data(yearTotalVOS);
        }
        Unit unit = unitService.getById(getUnitId());
        List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                .eq(Unit::getParentId, unit.getUnitId()));
        List<Project> list1 = new ArrayList<Project>();
        List<ProjectPersonnelInfo> personnelInfos = new ArrayList<ProjectPersonnelInfo>();
        if (CollectionUtils.isNotEmpty(units)) {
            for (Unit u : units) {
                List<Project> projects = projectService.list(new LambdaQueryWrapper<Project>()
                        .like(StringUtils.isNotBlank(flightName), Project::getFlightName, flightName)
                        .eq(StringUtils.isNotBlank(year), Project::getYear, year)
                        .eq(Project::getCreateDept, u.getUnitId()));
                List<Project> projects1 = new ArrayList<Project>();
                List<Unit> uns = unitService.list(new LambdaQueryWrapper<Unit>()
                        .eq(Unit::getParentId, u.getUnitId()));
                if (CollectionUtils.isNotEmpty(units)) {
                    for (Unit u1 : uns) {
                        getUnitProjectVO(u1, flightName, year, projects1);
                    }
                }
                if (CollectionUtils.isNotEmpty(projects1)) {
                    projects.addAll(projects1.stream().filter(p -> 0 == p.getParentId()).toList());
                }
                List<ProjectPersonnelInfo> infoList = projectPersonnelInfoService.list(
                        new LambdaQueryWrapper<ProjectPersonnelInfo>()
                                .eq(ProjectPersonnelInfo::getStatus, 1)
                                .in(CollectionUtils.isNotEmpty(projects), ProjectPersonnelInfo::getProjectId,
                                        projects.stream().map(Project::getProjectId).toList()));
                list1.addAll(projects);
                personnelInfos.addAll(infoList);
            }
        }
        if (CollectionUtils.isNotEmpty(list1)) {
            list.addAll(list1.stream().filter(p -> 0 == p.getParentId()).toList());
        }
        Map<String, List<Project>> listMap = list.stream().collect(Collectors.groupingBy(Project::getYear));
        listMap.keySet().forEach(k -> {
            yearTotalVOS.add(new YearTotalVO()
                    .setYear(k)
                    .setProjectNnum(listMap.get(k).stream().map(s ->
                                    BigDecimal.valueOf(Double.parseDouble(StringUtils.isEmpty(s.getShouldAttendance()) ?
                                            "0" : s.getShouldAttendance())))
                            .reduce(BigDecimal.ZERO, BigDecimal::add).intValue())
                    .setActualNum(CollectionUtils.isNotEmpty(personnelInfos) ? personnelInfos.size() : 0)
                    .setAwaitNum(CollectionUtils.isNotEmpty(personnelInfos) ?
                            (int) personnelInfos.stream().filter(
                                    l -> new Date().compareTo(l.getTrainingTime()) < 0).count() : 0)
                    .setProceedNum(CollectionUtils.isNotEmpty(personnelInfos) ?
                            (int) personnelInfos.stream().filter(
                                    l -> l.getTrainingTime().compareTo(new Date()) < 0
                                    && StringUtils.equals("0", l.getIsFinishSchool())).count() : 0)
                    .setCompleteNum(CollectionUtils.isNotEmpty(personnelInfos) ?
                            (int) personnelInfos.stream().filter(
                                    l -> StringUtils.equals("1", l.getIsFinishSchool())).count() : 0)
                    .setOptimalNum(CollectionUtils.isNotEmpty(personnelInfos) ?
                            (int) personnelInfos.stream().filter(
                                    l -> StringUtils.equals("1", l.getIsFinishSchool())
                                    && StringUtils.equals("优", l.getEvaluationOrder())).count() : 0));
        });
        return R.data(yearTotalVOS);
    }

    /**
     * 计划上报人数查询
     */
    @GetMapping("/project/number")
    @ApiOperationSupport(order = 15)
    @Operation(summary = "计划上报人数查询")
    public R projectNumber(@Parameter(description = "计划ID") @RequestParam Long projectId) {
        return R.data(projectPersonnelInfoService.count(new LambdaQueryWrapper<ProjectPersonnelInfo>()
                .eq(ProjectPersonnelInfo::getProjectId, projectId)));
    }

    /**
     * 计划班次信息列表
     */
    @GetMapping("/project/flight/info")
    @ApiOperationSupport(order = 16)
    @Operation(summary = "计划班次信息列表")
    public R<List<FlightVO>> projectFlightInfo() {
        List<Project> list = projectService.list(new LambdaQueryWrapper<Project>()
                .orderByDesc(Project::getFlightId)
                .in(Project::getIsDistribution, 0, 1, 2)
                .eq(Project::getParentId, 0));
        if (CollectionUtils.isEmpty(list)) {
            return R.data(Collections.emptyList());
        }
        return R.data(BeanUtil.copy(list.stream().map(l ->
                new FlightVO()
                        .setFlightId(l.getFlightId())
                        .setFlightName(l.getFlightName())
                        .setFlightCode(l.getFlightCode())
                        .setTissueUnitId(l.getTrainingUnitId())
                        .setTissueUnitName(l.getTrainingUnitName())
                        .setYear(l.getYear())
                        .setTrainingTime(l.getTrainingTime())
        ).collect(Collectors.toList()), FlightVO.class));
    }

    private LambdaQueryWrapper<ProjectPersonnelInfo> set(ProjectPersonnelPageDTO dto) {
        return new LambdaQueryWrapper<ProjectPersonnelInfo>()
                .orderByDesc(ProjectPersonnelInfo::getYear, ProjectPersonnelInfo::getFlightId, ProjectPersonnelInfo::getTrainingTime)
                .eq(null != dto.getStatus(), ProjectPersonnelInfo::getStatus, dto.getStatus())
                .like(StringUtils.isNotBlank(dto.getUserName()), ProjectPersonnelInfo::getUserName, dto.getUserName())
                .eq(StringUtils.isNotBlank(dto.getTraineeType()), ProjectPersonnelInfo::getTraineeType,
                        dto.getTraineeType())
                .eq(StringUtils.isNotBlank(dto.getSex()), ProjectPersonnelInfo::getSex, dto.getSex())
                .eq(null != dto.getFlightId(), ProjectPersonnelInfo::getFlightId, dto.getFlightId())
                .like(StringUtils.isNotBlank(dto.getFlightName()), ProjectPersonnelInfo::getFlightName,
                        dto.getFlightName())
                .eq(null != dto.getTrainingUnitId(), ProjectPersonnelInfo::getTrainingUnitId, dto.getTrainingUnitId())
                .like(StringUtils.isNotBlank(dto.getTrainingUnitName()),
                        ProjectPersonnelInfo::getTrainingUnitName, dto.getTrainingUnitName())
                .eq(null != dto.getPresentPostId(), ProjectPersonnelInfo::getPresentPostId, dto.getPresentPostId())
                .like(StringUtils.isNotBlank(dto.getPresentPostName()),
                        ProjectPersonnelInfo::getPresentPostName, dto.getPresentPostName())
                .like(StringUtils.isNotBlank(dto.getJob()), ProjectPersonnelInfo::getJob, dto.getJob())
                .eq(StringUtils.isNotBlank(dto.getYear()), ProjectPersonnelInfo::getYear, dto.getYear())
                .like(StringUtils.isNotBlank(dto.getIdCard()), ProjectPersonnelInfo::getIdCard, dto.getIdCard())
                .eq(StringUtils.isNotBlank(dto.getIsFinishSchool()), ProjectPersonnelInfo::getIsFinishSchool,
                        dto.getIsFinishSchool())
                .eq(StringUtils.isNotBlank(dto.getEvaluationOrder()),
                        ProjectPersonnelInfo::getEvaluationOrder, dto.getEvaluationOrder())
                .eq(null != dto.getSendingUnitId(), ProjectPersonnelInfo::getSendingUnitId, dto.getSendingUnitId())
                .like(StringUtils.isNotBlank(dto.getSendingUnitName()),
                        ProjectPersonnelInfo::getSendingUnitName, dto.getSendingUnitName())
                .ge(StringUtils.isNotBlank(dto.getOverallPracticalScoreMin()),
                        ProjectPersonnelInfo::getOverallPracticalScore, dto.getOverallPracticalScoreMin())
                .le(StringUtils.isNotBlank(dto.getOverallPracticalScoreMax()),
                        ProjectPersonnelInfo::getOverallPracticalScore, dto.getOverallPracticalScoreMax())
                .ge(StringUtils.isNotBlank(dto.getTheoreticalAchievementMin()),
                        ProjectPersonnelInfo::getTheoreticalAchievement, dto.getTheoreticalAchievementMin())
                .le(StringUtils.isNotBlank(dto.getTheoreticalAchievementMax()),
                        ProjectPersonnelInfo::getTheoreticalAchievement, dto.getTheoreticalAchievementMax())
                .ge(StringUtils.isNotBlank(dto.getTotalScoreMin()),
                        ProjectPersonnelInfo::getTotalScore, dto.getTotalScoreMin())
                .le(StringUtils.isNotBlank(dto.getTotalScoreMax()),
                        ProjectPersonnelInfo::getTotalScore, dto.getTotalScoreMax());
    }

    private LambdaQueryWrapper<ProjectPersonnelInfo> setNew(ProjectPersonnelPageDTO dto) {
        return new LambdaQueryWrapper<ProjectPersonnelInfo>()
                .orderByDesc(ProjectPersonnelInfo::getYear, ProjectPersonnelInfo::getFlightId, ProjectPersonnelInfo::getTrainingTime)
                .eq(null != dto.getStatus(), ProjectPersonnelInfo::getStatus, dto.getStatus())
                .like(StringUtils.isNotBlank(dto.getUserName()), ProjectPersonnelInfo::getUserName, dto.getUserName())
                .eq(StringUtils.isNotBlank(dto.getTraineeType()), ProjectPersonnelInfo::getTraineeType,
                        dto.getTraineeType())
                .eq(StringUtils.isNotBlank(dto.getSex()), ProjectPersonnelInfo::getSex, dto.getSex())
                .eq(null != dto.getFlightId(), ProjectPersonnelInfo::getFlightId, dto.getFlightId())
                .like(StringUtils.isNotBlank(dto.getFlightName()), ProjectPersonnelInfo::getFlightName,
                        dto.getFlightName())
                .eq(null != dto.getTrainingUnitId(), ProjectPersonnelInfo::getTrainingUnitId, dto.getTrainingUnitId())
                .like(StringUtils.isNotBlank(dto.getTrainingUnitName()),
                        ProjectPersonnelInfo::getTrainingUnitName, dto.getTrainingUnitName())
                .eq(null != dto.getPresentPostId(), ProjectPersonnelInfo::getPresentPostId, dto.getPresentPostId())
                .like(StringUtils.isNotBlank(dto.getPresentPostName()),
                        ProjectPersonnelInfo::getPresentPostName, dto.getPresentPostName())
                .like(StringUtils.isNotBlank(dto.getJob()), ProjectPersonnelInfo::getJob, dto.getJob())
                .eq(StringUtils.isNotBlank(dto.getYear()), ProjectPersonnelInfo::getYear, dto.getYear())
                .like(StringUtils.isNotBlank(dto.getIdCard()), ProjectPersonnelInfo::getIdCard, dto.getIdCard())
                .eq(StringUtils.isNotBlank(dto.getIsFinishSchool()), ProjectPersonnelInfo::getIsFinishSchool,
                        dto.getIsFinishSchool())
                .eq(StringUtils.isNotBlank(dto.getEvaluationOrder()),
                        ProjectPersonnelInfo::getEvaluationOrder, dto.getEvaluationOrder())
                .ge(StringUtils.isNotBlank(dto.getOverallPracticalScoreMin()),
                        ProjectPersonnelInfo::getOverallPracticalScore, dto.getOverallPracticalScoreMin())
                .le(StringUtils.isNotBlank(dto.getOverallPracticalScoreMax()),
                        ProjectPersonnelInfo::getOverallPracticalScore, dto.getOverallPracticalScoreMax())
                .ge(StringUtils.isNotBlank(dto.getTheoreticalAchievementMin()),
                        ProjectPersonnelInfo::getTheoreticalAchievement, dto.getTheoreticalAchievementMin())
                .le(StringUtils.isNotBlank(dto.getTheoreticalAchievementMax()),
                        ProjectPersonnelInfo::getTheoreticalAchievement, dto.getTheoreticalAchievementMax())
                .ge(StringUtils.isNotBlank(dto.getTotalScoreMin()),
                        ProjectPersonnelInfo::getTotalScore, dto.getTotalScoreMin())
                .le(StringUtils.isNotBlank(dto.getTotalScoreMax()),
                        ProjectPersonnelInfo::getTotalScore, dto.getTotalScoreMax());
    }

    private void getLongList(List<Project> list, List<Long> longs) {
        if (CollectionUtils.isNotEmpty(list)) {
            List<Long> longList = list.stream().map(Project::getProjectId).toList();
            longs.addAll(longList);
            List<Project> projectList = projectService.list(new LambdaQueryWrapper<Project>()
                    .in(Project::getParentId, longList));
            getLongList(projectList, longs);
        }
    }

    private void getLongListNew(List<Project> list, List<Long> longs, Long id) {
        if (CollectionUtils.isNotEmpty(list)) {
            List<Project> list1 = list.stream().filter(l -> Objects.equals(l.getCreateDept(), id)).toList();
            if (CollectionUtils.isNotEmpty(list1)) {
                longs.add(list1.get(0).getProjectId());
                return;
            }
            List<Project> projectList = projectService.list(new LambdaQueryWrapper<Project>()
                    .in(Project::getParentId, list.stream().map(Project::getProjectId).toList()));
            getLongListNew(projectList, longs, id);
        }
    }

    private void getUnitProjectVO(Unit unit, String flightName, String year, List<Project> projects) {
        List<Project> list = projectService.list(new LambdaQueryWrapper<Project>()
                .like(StringUtils.isNotBlank(flightName), Project::getFlightName, flightName)
                .eq(StringUtils.isNotBlank(year), Project::getYear, year)
                .eq(Project::getCreateDept, unit.getUnitId()));
        projects.addAll(list);
        List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                .eq(Unit::getParentId, unit.getUnitId()));
        if (CollectionUtils.isNotEmpty(units)) {
            for (Unit u : units) {
                getUnitProjectVO(u, flightName, year, projects);
            }
        }
    }

}
