package cn.wisenergy.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.wisenergy.common.utils.DateUtil;
import cn.wisenergy.common.utils.ExcelUtils;
import cn.wisenergy.common.utils.exception.BASE_RESP_CODE_ENUM;
import cn.wisenergy.common.utils.exception.BaseCustomException;
import cn.wisenergy.mapper.*;
import cn.wisenergy.model.app.WorkHoliday;
import cn.wisenergy.model.app.WorkProject;
import cn.wisenergy.model.app.WorkUser;
import cn.wisenergy.model.dto.*;
import cn.wisenergy.model.enums.*;
import cn.wisenergy.service.StatisticsService;
import cn.wisenergy.service.WorkProjectService;
import cn.wisenergy.service.WorkUserService;
import cn.wisenergy.service.utils.UserRoleLevelUtils;
import com.alibaba.excel.util.StringUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * @description:
 * @author: nh
 * @create: 2021-01-19 17:19
 **/

@Service
@Slf4j
public class StatisticsServiceImpl implements StatisticsService {
    @Autowired
    private WorkUserService workUserService;

    @Autowired
    private WorkTimeOrderMapper workTimeOrderMapper;

    @Autowired
    private WorkUserDeptMapper workUserDeptMapper;

    @Autowired
    private WorkProjectService workProjectService;

    @Autowired
    private WorkHolidayMapper workHolidayMapper;

    @Autowired
    private WorkUserMapper workUserMapper;

    @Autowired
    private UserRoleLevelUtils userRoleLevelUtils;

    @Autowired
    private WorkProjectTimeCostMapper workProjectTimeCostMapper;

    @Autowired
    private WorkUserProjectMapper workUserProjectMapper;

    private final static Integer EXCEL_WIDTH = 1000 * 6;

    private final static Integer DEFAULT_DEPT_ID = 1;

    @Override
    public PageInfo getDayWorkTimeOfMonth(GetMonthlyCollectParam param) {
        log.info("StatisticsServiceImpl[]getMonthlyCollect[]input.param" + param);
        if (param == null) {
            throw new BaseCustomException(BASE_RESP_CODE_ENUM.INPUT_PARAM_IS_NULL);
        }
        //管理员用户
        List<Integer> role = userRoleLevelUtils.getRole(param.getUserId());
        if (!role.contains(ManagerEnum.IS_SYSTEM_MANAGER.getCode())) {
            throw new BaseCustomException(BASE_RESP_CODE_ENUM.THE_USER_NOT_MANAGER_PLASE_MANAGER_LOGIN);
        }
        //默认时间为当月
        Integer year = param.getYear();
        Integer month = param.getMonth();
        if (StringUtils.isEmpty(param.getYear()) || StringUtils.isEmpty(param.getMonth())) {
            Date now = new Date();
            year = DateUtil.getYear(now);
            month = DateUtil.getMonth(now) + 1;
        }
        //默认部门主键为1
        Integer deptId = param.getDeptId();
        if (param.getDeptId() == null) {
            deptId = DEFAULT_DEPT_ID;
        }
        //默认当前页码为1，每页数量为10
        if (param.getCurrentPage() == null) {
            param.setCurrentPage(1);
        }
        if (param.getSize() == null) {
            param.setSize(10);
        }

        // 分页获取部门下所有员工主键
        PageHelper.startPage(param.getCurrentPage(), param.getSize());
        List<Integer> userIds = workUserDeptMapper.listByDeptIdAndStatus(deptId);
        PageInfo pageInfo = new PageInfo(userIds);
        // 获取用户姓名、部门名称
        List<StatisticsTableDto> statisticsTableDtos = workUserMapper.getStatisticsTableDtos(userIds);
        // 获取用户当月每天工时信息
        List<DayWorkTimeAndType> dayWorkTimeAndTypes = workTimeOrderMapper.listByDateAndUserId(year, month, userIds);

        // 将工单集合与对应用户信息封装在一起
        Iterator<StatisticsTableDto> statisticsTableDtoIterator = statisticsTableDtos.iterator();
        while (statisticsTableDtoIterator.hasNext()) {
            StatisticsTableDto statisticsTableDto = statisticsTableDtoIterator.next();
            // 存放一位用户一个月中每天的工时信息
            ArrayList<DayWorkTimeAndType> dayWorkTimeAndTypes1 = new ArrayList<>();
            // 查询出的工时信息遍历
            Iterator<DayWorkTimeAndType> workTimeAndTypeIterator = dayWorkTimeAndTypes.iterator();
            while (workTimeAndTypeIterator.hasNext()) {
                DayWorkTimeAndType dayWorkTimeAndType = workTimeAndTypeIterator.next();
                if (dayWorkTimeAndType.getUserId().equals(statisticsTableDto.getUserId())) {
                    dayWorkTimeAndTypes1.add(dayWorkTimeAndType);
                }
            }
            statisticsTableDto.setDayWorkTimeAndTypeList(dayWorkTimeAndTypes1);
        }
        pageInfo.setList(statisticsTableDtos);
        return pageInfo;
    }

    @Override
    public List<Object> getMonthlyStatistics(Integer userId) {
        log.info("WorkTimeOrderServiceImpl[]getMonthlyStatistics[]input.param" + userId);
        WorkUser user = workUserService.getById(userId);
        List<Integer> role = userRoleLevelUtils.getRole(user.getId());
        //本月第一天
        Date firstDayOfMonth = DateUtil.getCurrentFirstDayOfMonth();
        //返回数据对象
        List<Object> objects = new ArrayList<>();
        //存放查询条件
        Map<String, Object> map = new HashMap<>();
        //用户是项目或部门级别，查询审批统计
        if (role.contains(ManagerEnum.IS_PROJECT_DIRECTOR.getCode()) || role.contains(ManagerEnum.IS_DEPARTMENT_DIRECTOR.getCode())) {
            //以审批人、审核状态、开始时间查询本月审批数量
            map.put("reviewerId", userId);
            map.put("startDay", firstDayOfMonth);
            Integer completedCount = workTimeOrderMapper.getCountByCondition(map);

            //本月驳回未重报数量
            map.put("status", WorkOrderStatus.TURN_DOWN.getCode());
            Integer rejectAndNotResubmit = workTimeOrderMapper.getCountByCondition(map);

            // 项目级别，获取所管理项目,
            if (role.contains(ManagerEnum.IS_PROJECT_DIRECTOR.getCode())) {
                List<WorkProject> projects = workProjectService.getUserManageProjects(userId);
                if (CollectionUtil.isNotEmpty(projects)) {
                    List<Integer> projectIds = projects.stream().map(WorkProject::getId).collect(Collectors.toList());
                    map.put("projectIds", projectIds);
                }
            }
            // 部门级别
            if (role.contains(ManagerEnum.IS_DEPARTMENT_DIRECTOR.getCode())) {
                map.put("deptId", user.getDeptId());
                //填报项目类型编码
                int[] workOrderTypeArray = {WorkOrderType.EXTERNAL_WORK.getCode(), WorkOrderType.INTERNAL_WORK.getCode(), WorkOrderType.OTHER_NOT_PROJECT_BUSINESS.getCode()};
                map.put("typeArray", workOrderTypeArray);
            }
            //待审核包括：新提交和重新提交的
            List<Integer> statusArray = new ArrayList<>();
            statusArray.add(WorkOrderStatus.WAIT_AUDIT.getCode());
            statusArray.add(WorkOrderStatus.RE_SUBMIT.getCode());
            map.remove("reviewerId");
            map.remove("status");
            //本月未审批数量查询
            map.put("statusArray", statusArray);
            Integer notCompletedCount = workTimeOrderMapper.getCountByCondition(map);
            //所有查询结果封装进对象
            ApprovalStatistics approvalStatistics = new ApprovalStatistics();
            approvalStatistics.setApprovalCount(completedCount);
            approvalStatistics.setRejectNotSubmit(rejectAndNotResubmit);
            approvalStatistics.setNotApprovalCount(notCompletedCount);
            objects.add(approvalStatistics);
        }

        // 填报情况
        // 本月应填报日期
        List<Date> currentMonthWorkDays = this.currentMonthWorkDays(firstDayOfMonth);
        // 本月已填报日期
        List<Date> currentMonthFilledDays = currentMonthFilledDays(userId);
        // 本月未填报日期
        currentMonthWorkDays.removeAll(currentMonthFilledDays);
        int notFilledCount = currentMonthWorkDays.size();
        //本月被现存驳回数
        map.clear();
        map.put("status", StatusEnum.REJECTED.getCode());
        map.put("userId", userId);
        map.put("startDay", firstDayOfMonth);
        Integer countByCondition = workTimeOrderMapper.getCountByCondition(map);

        List<MonthlyWorkingHoursStatistics> monthlyWorkingHoursStatistics = workTimeOrderMapper.statisticsByProjectType(userId, firstDayOfMonth);
        // 如果没填写填报类型其中某项，造对象传前端
        if (monthlyWorkingHoursStatistics.size() < 5) {
            // 获取工时类型（项目或商机）
            List<String> projectTypes = monthlyWorkingHoursStatistics.stream().map(MonthlyWorkingHoursStatistics::getProjectType).collect(Collectors.toList());
            for (ProjectTypeEnum value : ProjectTypeEnum.values()) {
                // 除开请假、调休
                if (!projectTypes.contains(value.getTypeName()) && !value.getTypeName().equals(ProjectTypeEnum.LEAVE.getTypeName()) && !value.getTypeName().equals(ProjectTypeEnum.COMPENSATORY_LEAVE.getTypeName())) {
                    MonthlyWorkingHoursStatistics workingHoursStatistics = new MonthlyWorkingHoursStatistics();
                    workingHoursStatistics.setProjectType(value.getTypeName());
                    workingHoursStatistics.setCount(0);
                    workingHoursStatistics.setWorkTime(0);
                    monthlyWorkingHoursStatistics.add(workingHoursStatistics);
                }
            }
        }

        // 赋值未填报天数、被驳回未重报天
        for (MonthlyWorkingHoursStatistics monthlyWorkingHoursStatistic : monthlyWorkingHoursStatistics) {
            monthlyWorkingHoursStatistic.setNotFilledCount(notFilledCount);
            monthlyWorkingHoursStatistic.setRejectCount(countByCondition);
        }
        objects.add(monthlyWorkingHoursStatistics);
        return objects;
    }

    @Override
    public List<WorkTimeAndCostCollect> getCurrentMonthWorkTimeCollect(Integer userId, String startTime) {
        log.info("StatisticsServiceImpl[]getCurrentMonthWorkTimeCollect[]input.param" + userId + startTime);
        if (userId == null) {
            throw new BaseCustomException(BASE_RESP_CODE_ENUM.INPUT_PARAM_IS_NULL);
        }
        WorkUser user = workUserService.getById(userId);

        // 时间不为空，赋值当月第一天
        if (StringUtil.isNotEmpty(startTime)) {
            Date currentFirstDayOfMonth = DateUtil.getCurrentFirstDayOfMonth();
            startTime = DateUtil.convertDateToYMDStr(currentFirstDayOfMonth);
        }

        // 用户角色
        List<Integer> role = userRoleLevelUtils.getRole(user.getId());
        // 普通用户
        if (role.contains(ManagerEnum.NOT_MANAGER.getCode())) {
            throw new BaseCustomException(BASE_RESP_CODE_ENUM.THE_USER_NOT_MANAGER_PLASE_MANAGER_LOGIN);
        }

        // 查询用户管理的项目
        List<WorkProject> userManageProjects = workProjectService.getUserManageProjects(userId);
        if (CollectionUtil.isEmpty(userManageProjects)) {
            throw new BaseCustomException(BASE_RESP_CODE_ENUM.MANAGER_NOT_PROJECT);
        }
        // 获取项目集合中所有项目的项目主键
        List<Integer> projectIds = userManageProjects.stream().map(WorkProject::getId).collect(Collectors.toList());
        // 查询条件
        Map<String, Object> map = new HashMap<>();
        map.put("projectIds", projectIds);

        // 起始时间为空时不以时间作为查询条件
        if (StringUtil.isNotEmpty(startTime)) {
            map.put("firstDayOfMonth", startTime);
        }

        // 工时类型包含：项目，商机
        List<Integer> types = new ArrayList<>();
        types.add(ProjectTypeEnum.PROJECT.getType());
        types.add(ProjectTypeEnum.BUSINESS_OPPORTUNITY.getType());
        map.put("types", types);

        // 查询项目和商机的工时统计
        List<WorkTimeAndCostCollect> collect = workProjectTimeCostMapper.selectList(map);

        // 部门和中心级别
        if (role.contains(ManagerEnum.IS_DEPARTMENT_DIRECTOR.getCode()) || role.contains(ManagerEnum.IS_CENTRE_DIRECTOR.getCode())) {
            // 请假、调休、外部商务、技术交流,内部培训、技术准备、管理,其他非项目/商机工作
            types.clear();
            map.clear();
            for (ProjectTypeEnum value : ProjectTypeEnum.values()) {
                // 查询条件排除项目和商机
                if (!value.getTypeName().equals(ProjectTypeEnum.PROJECT.getTypeName()) && !value.getTypeName().equals(ProjectTypeEnum.BUSINESS_OPPORTUNITY.getTypeName())) {
                    types.add(value.getType());
                }
            }
            // 用户仅为部门管理
            if (role.contains(ManagerEnum.IS_DEPARTMENT_DIRECTOR.getCode()) && role.size() == 1) {
                map.put("deptId", user.getDeptId());
            }
            map.put("types", types);
            List<WorkTimeAndCostCollect> workTimeAndCostCollect = workTimeOrderMapper.getWorkTimeAndCostCollect(map);
            // 将查询结果封装在一起
            collect.addAll(workTimeAndCostCollect);
            // 获取查询结果中的类型
            List<String> typeList = collect.stream().map(WorkTimeAndCostCollect::getType).collect(Collectors.toList());
            // 如果查询结果不包含查询条件中的类型，造对象传前端
            for (ProjectTypeEnum value : ProjectTypeEnum.values()) {
                if (!typeList.contains(value.getTypeName())) {
                    WorkTimeAndCostCollect workTimeAndCostCollect1 = new WorkTimeAndCostCollect();
                    workTimeAndCostCollect1.setType(value.getTypeName());
                    collect.add(workTimeAndCostCollect1);
                }
            }
        }
        for (WorkTimeAndCostCollect workTimeAndCostCollect : collect) {
            // 类型的总工时
            BigDecimal typeTotalTime = new BigDecimal("0.00");
            List<DeptProjectWorkTimeAndCost> deptProjectWorkTimeAndCosts = workTimeAndCostCollect.getDeptProjectWorkTimeAndCosts();
            if (CollectionUtil.isNotEmpty(deptProjectWorkTimeAndCosts)) {
                for (DeptProjectWorkTimeAndCost deptProjectWorkTimeAndCost : deptProjectWorkTimeAndCosts) {
                    List<ProjectWorkTimeAndCostStatistics> projectWorkTimeAndCostStatistics = deptProjectWorkTimeAndCost.getProjectWorkTimeAndCostStatistics();
                    for (ProjectWorkTimeAndCostStatistics projectWorkTimeAndCostStatistic : projectWorkTimeAndCostStatistics) {
                        typeTotalTime = typeTotalTime.add(projectWorkTimeAndCostStatistic.getTotalTime());
                    }
                }
            }
            workTimeAndCostCollect.setWorkTime(typeTotalTime);
        }
        return collect;
    }

    @Override
    public HSSFWorkbook exportWorkTimeExcel(GetMonthlyCollectParam param) {
        log.info("StatisticsServiceImpl[]exportWorkTimeExcel[]input.param{}" + param);
        PageInfo dayWorkTimeOfMonth = getDayWorkTimeOfMonth(param);
        Date date = DateUtil.convertStrToDate(param.getYear() + "-" + param.getMonth(), "yyyy-MM");
        // 传参的时间当月总天数
        int dayCount = DateUtil.getMonthDaysArray(date).length;
        // 需要导出的信息
        List<StatisticsTableDto> list = dayWorkTimeOfMonth.getList();
        // 创建工作簿
        HSSFWorkbook sheets = new HSSFWorkbook();
        // 创建表
        HSSFSheet sheet = sheets.createSheet("Sheet1");
        // 普通样式对象
        HSSFCellStyle cellStyle = this.createOrdinaryCellStyle(sheets);

        // 节假日样式，底色为绿色,其余样式与普通相同
        HSSFCellStyle cellStyle1 = this.createOrdinaryCellStyle(sheets);
        cellStyle1.setFillForegroundColor(HSSFColor.HSSFColorPredefined.LIGHT_GREEN.getIndex());

        // 当日工时小于8，底色为红色，其余样式与普通相同
        HSSFCellStyle cellStyle2 = this.createOrdinaryCellStyle(sheets);
        cellStyle2.setFillForegroundColor(HSSFColor.HSSFColorPredefined.RED.getIndex());

        // 第一列列宽
        sheet.setColumnWidth(1, EXCEL_WIDTH);
        // 获取本月应上班日期集合
        List<Date> dates = this.currentMonthWorkDays(date);
        List<Integer> days = new ArrayList<>();
        for (Date date1 : dates) {
            days.add(DateUtil.getDay(date1));
        }
        // 创建一行
        HSSFRow row1 = sheet.createRow(0);
        // 给第一行赋值
        row1.createCell(0).setCellValue("序号");
        row1.createCell(1).setCellValue("部门名称");
        row1.createCell(2).setCellValue("姓名");
        for (int i = 1; i <= dayCount; i++) {
            HSSFCell cell = row1.createCell(2 + i);
            cell.setCellValue(i + "日");
            // 如果为节假日
            if (!days.contains(i)) {
                cell.setCellStyle(cellStyle1);
            } else {
                cell.setCellStyle(cellStyle);
            }
        }
        Iterator<StatisticsTableDto> iterator = list.iterator();
        int i = 1;
        while (iterator.hasNext()) {
            StatisticsTableDto next = iterator.next();
            // 创建对应的行
            HSSFRow row_i = sheet.createRow(i);
            // 序号
            row_i.createCell(0).setCellValue(i);
            // 部门名称
            row_i.createCell(1).setCellValue(next.getDeptName());
            // 姓名
            row_i.createCell(2).setCellValue(next.getUserName());
            // 日期与工时集合
            List<DayWorkTimeAndType> timeAndTypes = next.getDayWorkTimeAndTypeList();
            // 在excel中对应日期单元格添加工时
            for (DayWorkTimeAndType timeAndType : timeAndTypes) {
                HSSFCell cell = row_i.getCell(timeAndType.getDay() + 2);
                String cellValue = ExcelUtils.getCellValue(cell, true);
                // 单元格为空则直接写入，否则追加
                if (!StringUtils.isEmpty(cellValue)) {
                    cell.setCellValue(timeAndType.getType() + timeAndType.getWorkTime().toString() + "\n" + cellValue);
                } else {
                    HSSFCell emptyCell = row_i.createCell(timeAndType.getDay() + 2);
                    emptyCell.setCellValue(timeAndType.getType() + timeAndType.getWorkTime().toString());
                }
            }
            // 换行
            i++;
        }
        // 给节假日单元格设置单元格格式
        for (int j = 0; j < list.size(); j++) {
            HSSFRow row = sheet.getRow(j + 1);
            for (int r = 0; r < dayCount; r++) {
                HSSFCell cell = null;
                if (row.getCell(r + 3) == null) {
                    cell = row.createCell(r + 3);
                } else {
                    cell = row.getCell(r + 3);
                }
                // 节假日单元格标绿色
                if (!days.contains(r + 1)) {
                    cell.setCellStyle(cellStyle1);
                }
                // 获取单元格中的工时，当日总工时小于8,则单元格底色为红色
                String cellValue = ExcelUtils.getCellValue(cell, true);
                if (StringUtil.isNotEmpty(cellValue)) {
                    Integer numberOfString = this.getNumberOfString(cellValue);
                    if (numberOfString != null && numberOfString < 8) {
                        cell.setCellStyle(cellStyle2);
                    }
                }
            }
        }
        return sheets;
    }

    // 将字符串中的1到9的数字相加
    private Integer getNumberOfString(String value) {
        value = value.trim();
        if (StringUtil.isEmpty(value)) {
            return null;
        }
        Integer sum = 0;
        for (int i = 0; i < value.length(); i++) {
            if (value.charAt(i) >= 48 && value.charAt(i) <= 57) {
                sum += value.charAt(i) - 48;
            }
        }
        return sum;
    }

    @Override
    public List<UserWorkTimeStatisticsByProject> getUserWorkTimeStatisticsReport(Integer userId, String startDate, String endDate, Integer status) {
        log.info("StatisticsServiceImpl[]getUserWorkTimeStatisticsReport[]");
        List<Integer> role = userRoleLevelUtils.getRole(userId);
        if (role.contains(ManagerEnum.NOT_MANAGER.getCode())) {
            throw new BaseCustomException(BASE_RESP_CODE_ENUM.THE_USER_NOT_MANAGER_PLASE_MANAGER_LOGIN);
        }
        // 默认统计截至时间为前一天
        if (StringUtil.isEmpty(endDate)) {
            endDate = DateUtil.convertDateToYMDStr(new Date());
        }
        // 获取用户负责项目主键集合
        List<WorkProject> userManageProjects = workProjectService.getUserManageProjects(userId);
        // 管理项目为空则提前结束
        if (CollectionUtil.isEmpty(userManageProjects)) {
            return null;
        }
        // 提取项目主键
        List<Integer> projectIds = userManageProjects.stream().map(WorkProject::getId).collect(Collectors.toList());

        List<UserWorkTimeStatisticsByProject> userWorkTimeStatisticsByProjects = new ArrayList<>();
        // 返回结果集合第一个元素是用户管理项目的集合
        UserWorkTimeStatisticsByProject userWorkTimeStatisticsByProject = new UserWorkTimeStatisticsByProject();
        List<ProjectWorkTimeAndType> projectWorkTimeAndTypes = new ArrayList<>();
        for (WorkProject userManageProject : userManageProjects) {
            // 项目加班工时对象
            ProjectWorkTimeAndType projectWorkTimeAndType = createProjectWorkTimeAndType(userManageProject);
            projectWorkTimeAndType.setIsOvertime("正常");
            projectWorkTimeAndTypes.add(projectWorkTimeAndType);
            // 项目正常工时对象
            projectWorkTimeAndType = createProjectWorkTimeAndType(userManageProject);
            projectWorkTimeAndType.setIsOvertime("加班");
            projectWorkTimeAndTypes.add(projectWorkTimeAndType);
        }
        // 添加表头：外部商务/技术交流、内部培训/技术准备/管理、其他非项目/商机工作
        List<ProjectWorkTimeAndType> projectWorkTimeAndTypeListByType = createProjectWorkTimeAndTypeListByType();
        projectWorkTimeAndTypes.addAll(projectWorkTimeAndTypeListByType);

        // 管理项目组成人员主键,如果用户仅为项目级别管理人员，则为空
        List<Integer> userIds = null;
        if (role.contains(ManagerEnum.IS_DEPARTMENT_DIRECTOR.getCode()) || role.contains(ManagerEnum.IS_CENTRE_DIRECTOR.getCode())) {
            userIds = workUserProjectMapper.selectUserIdByProjectIds(projectIds);
        }

        // 查询人员项目工时统计
        List<UserWorkTimeStatisticsByProject> userProjectWorkTimeStatistics = workTimeOrderMapper.getUserProjectWorkTimeStatistics(startDate, endDate, status, projectIds, userIds);

        // 取出单人的项目工时统计
        for (UserWorkTimeStatisticsByProject userProjectWorkTimeStatistic : userProjectWorkTimeStatistics) {
            int totalTime = 0;
            List<ProjectWorkTimeAndType> projectWorkTimeAndType1 = userProjectWorkTimeStatistic.getProjectWorkTimeAndType();
            // 遍历一个人所有项目统计，计算所有项目所有工时总和
            for (ProjectWorkTimeAndType projectWorkTimeAndType : projectWorkTimeAndType1) {
                totalTime += projectWorkTimeAndType.getWorkTime();
                // 计算项目的所有人员工时总和
                for (ProjectWorkTimeAndType workTimeAndType : projectWorkTimeAndTypes) {
                    // 项目统计数据
                    if (workTimeAndType.getProjectName() != null && workTimeAndType.getProjectName().equals(projectWorkTimeAndType.getProjectName()) && workTimeAndType.getIsOvertime().equals(projectWorkTimeAndType.getIsOvertime())) {
                        workTimeAndType.setWorkTime(workTimeAndType.getWorkTime() + projectWorkTimeAndType.getWorkTime());
                    } else if (workTimeAndType.getProjectType() != null && workTimeAndType.getProjectType().equals(projectWorkTimeAndType.getProjectType()) && workTimeAndType.getIsOvertime().equals(projectWorkTimeAndType.getIsOvertime())) {
                        workTimeAndType.setWorkTime(workTimeAndType.getWorkTime() + projectWorkTimeAndType.getWorkTime());
                    }
                }
            }
            userProjectWorkTimeStatistic.setTotalTime(totalTime);
        }
        // 返回结果第一条数据是所有项目的名称和工时总计
        userWorkTimeStatisticsByProject.setProjectWorkTimeAndType(projectWorkTimeAndTypes);
        userWorkTimeStatisticsByProjects.add(userWorkTimeStatisticsByProject);
        // 将项目名称集合与人员工时统计封装在一起
        userWorkTimeStatisticsByProjects.addAll(userProjectWorkTimeStatistics);
        return userWorkTimeStatisticsByProjects;
    }

    @Override
    public List<ProjectStatisticsByMonth> getProjectStatistics(Integer userId, Integer deptId, Integer year, Integer projectId) {
        log.info("StatisticsServiceImpl[]getProjectStatistics[]input.param" + userId + deptId + year + projectId);
        // 权限判断
        List<Integer> role = userRoleLevelUtils.getRole(userId);
        if (!role.contains(ManagerEnum.IS_CENTRE_DIRECTOR.getCode())) {
            throw new BaseCustomException(BASE_RESP_CODE_ENUM.NO_AUTHORITY);
        }
        // 默认查询时间为当前
        if (year == null) {
            year = DateUtil.getYear(new Date());
        }
        // 部门主键和项目主键不能同时为空
        if (deptId == null && projectId == null) {
            throw new BaseCustomException(BASE_RESP_CODE_ENUM.INPUT_PARAM_IS_NULL);
        }

        // 部门主键参数不为空，查询部门下所有项目统计信息。部门主键为空时，查询项目编号参数为主键的项目统计信息
        List<ProjectStatisticsByMonth> projectStatisticsByMonths = workProjectTimeCostMapper.selectListByMonth(year, deptId, projectId);
        if (CollectionUtil.isEmpty(projectStatisticsByMonths)) {
            return null;
        }
        // 部门主键不为空时，日期格式只有某月。为空时，日期格式为某年统计的第一个月为某年某月，其余为某月
        this.conversionDateFormat(projectStatisticsByMonths, deptId);

        // 计算合计，存放所有项目所有月份合计
        ProjectStatisticsByMonth projectStatisticsByMonthTotal = new ProjectStatisticsByMonth();
        List<ProjectStatisticsByMonth.StatisticsDateAndWorkTime> statisticsDateAndWorkTimeList = new ArrayList<>(13);
        // 设置合计时间1到12月和项目合计
        for (int i = 1; i <= 12; i++) {
            ProjectStatisticsByMonth.StatisticsDateAndWorkTime statisticsDateAndWorkTime = this.createStatisticsDateAndWorkTime(i + "月");
            statisticsDateAndWorkTimeList.add(statisticsDateAndWorkTime);
        }
        ProjectStatisticsByMonth.StatisticsDateAndWorkTime statisticsDateAndWorkTime1 = this.createStatisticsDateAndWorkTime("项目合计");
        statisticsDateAndWorkTimeList.add(statisticsDateAndWorkTime1);

        // 遍历所有项目的统计
        for (ProjectStatisticsByMonth projectStatisticsByMonth : projectStatisticsByMonths) {
            // 一个项目统计中的所有月份工时和成本信息
            BigDecimal totalTime = new BigDecimal("0.00");
            BigDecimal cost = new BigDecimal("0.00");
            for (ProjectStatisticsByMonth.StatisticsDateAndWorkTime statisticsDateAndWorkTimes : projectStatisticsByMonth.getStatisticsDateAndWorkTimes()) {
                // 某月的所有项目的工时统计，查询某个项目全声明周期数据时不统计
                if (deptId != null) {
                    for (ProjectStatisticsByMonth.StatisticsDateAndWorkTime statisticsDateAndWorkTime : statisticsDateAndWorkTimeList) {
                        if (statisticsDateAndWorkTime.getDate().equals(statisticsDateAndWorkTimes.getDate())) {
                            statisticsDateAndWorkTime.setCost(statisticsDateAndWorkTime.getCost().add(statisticsDateAndWorkTimes.getCost()));
                            statisticsDateAndWorkTime.setTotalTime(statisticsDateAndWorkTime.getTotalTime().add(statisticsDateAndWorkTimes.getTotalTime()));
                        }
                    }
                }
                cost = cost.add(statisticsDateAndWorkTimes.getCost());
                totalTime = totalTime.add(statisticsDateAndWorkTimes.getTotalTime());
            }
            // 所有项目的所有月的合计,
            for (ProjectStatisticsByMonth.StatisticsDateAndWorkTime statisticsDateAndWorkTime : statisticsDateAndWorkTimeList) {
                ProjectStatisticsByMonth.StatisticsDateAndWorkTime statisticsDateAndWorkTime2 = statisticsDateAndWorkTimeList.get(statisticsDateAndWorkTimeList.size() - 1);
                statisticsDateAndWorkTime2.setTotalTime(statisticsDateAndWorkTime2.getTotalTime().add(statisticsDateAndWorkTime.getTotalTime()));
                statisticsDateAndWorkTime2.setCost(statisticsDateAndWorkTime2.getCost().add(statisticsDateAndWorkTime.getCost()));
            }

            ProjectStatisticsByMonth.StatisticsDateAndWorkTime statisticsDateAndWorkTime = new ProjectStatisticsByMonth.StatisticsDateAndWorkTime();
            statisticsDateAndWorkTime.setDate("项目合计");
            statisticsDateAndWorkTime.setCost(cost);
            statisticsDateAndWorkTime.setTotalTime(totalTime);
            // 将统计的结果放在一个项目统计集合的末尾
            projectStatisticsByMonth.getStatisticsDateAndWorkTimes().add(statisticsDateAndWorkTime);
        }
        if (deptId != null) {
            projectStatisticsByMonthTotal.setStatisticsDateAndWorkTimes(statisticsDateAndWorkTimeList);
            projectStatisticsByMonthTotal.setProjectName("合计");
            projectStatisticsByMonths.add(projectStatisticsByMonthTotal);
        }

        return projectStatisticsByMonths;
    }

    //获取一个月应上班日期，如果是当月，时间截至到当天
    public List<Date> currentMonthWorkDays(Date date) {
        log.info("StatisticsServiceImpl[]currentMonthWorkDays[]input.method");
        // 时间为本月,起始时间为参数时间当月第一天，截至时间为当天。否则，截至时间为当月最后一天
        Date startDate = DateUtil.getFirstDayOfMonth(date);
        Date endDate = null;
        // 当前时间
        Date now = new Date();
        if (DateUtil.getYear(date) == DateUtil.getYear(now) && DateUtil.getMonth(date) == DateUtil.getMonth(now)) {
            endDate = now;
        } else {
            endDate = DateUtil.getLastDayOfMonth(date);
        }
        // 当月月第一天到截止时间的日期集合
        List<Date> workDays = DateUtil.getDatesBetweenTwoDate(startDate, endDate);

        //除去周末
        Iterator<Date> iterator = workDays.iterator();
        while (iterator.hasNext()) {
            Date next = iterator.next();
            int week = DateUtil.getWeek(next);
            // week为7是星期六，1是星期天
            if (week == 7 || week == 1) {
                iterator.remove();
            }
        }
        //获取当月的节日和周末上班日期
        List<WorkHoliday> specialDates = workHolidayMapper.getByDate(startDate, endDate);
        if (CollectionUtil.isEmpty(specialDates)) {
            return workDays;
        }
        for (WorkHoliday specialDate : specialDates) {
            List<Date> isWorkDays = DateUtil.getDatesBetweenTwoDate(specialDate.getDayStart(), specialDate.getDayEnd());
            //获取的是工作日
            if (specialDate.getDayType().equals(HolidayTypeEnum.WORKING_DAY.getCode())) {
                //在本月应上班集合中加上这天，一般都是放假前后的周末调整上班
                workDays.addAll(isWorkDays);
            } else {
                //否则就除去假日
                workDays.removeAll(isWorkDays);
            }
        }
        return workDays;
    }

    //获取用户本月已填报的日期
    public List<Date> currentMonthFilledDays(Integer userId) {
        log.info("StatisticsServiceImpl[]currentMonthFilledDays[]input.method");
        Date firstDayOfMonth = DateUtil.getCurrentFirstDayOfMonth();
        List<Date> currentMonthFilledDays = workTimeOrderMapper.getDaysByDateAndStatus(firstDayOfMonth, userId);
        return currentMonthFilledDays;
    }

    // 设置单元格基本样式
    HSSFCellStyle createOrdinaryCellStyle(HSSFWorkbook sheets) {
        HSSFCellStyle cellStyle = sheets.createCellStyle();
        // 设置全填充
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        // 垂直、水平中心对齐
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setBorderBottom(BorderStyle.THIN);
        //设置下边框的边框线颜色（颜色和上述的颜色对照表是一样的）
        cellStyle.setBottomBorderColor(IndexedColors.SKY_BLUE.getIndex());
        cellStyle.setBorderLeft(BorderStyle.THIN);
        //左边框
        cellStyle.setLeftBorderColor(IndexedColors.SKY_BLUE.getIndex());
        cellStyle.setBorderTop(BorderStyle.THIN);
        //上边框
        cellStyle.setRightBorderColor(IndexedColors.SKY_BLUE.getIndex());
        cellStyle.setBorderRight(BorderStyle.THIN);
        //右边框
        cellStyle.setTopBorderColor(IndexedColors.SKY_BLUE.getIndex());
        // 自动换行
        cellStyle.setWrapText(true);
        return cellStyle;
    }

    // 返回一个项目工时类型信息对象
    public ProjectWorkTimeAndType createProjectWorkTimeAndType(WorkProject project) {
        ProjectWorkTimeAndType projectWorkTimeAndType = new ProjectWorkTimeAndType();
        projectWorkTimeAndType.setProjectId(project.getId());
        projectWorkTimeAndType.setProjectName(project.getProjectName());
        projectWorkTimeAndType.setWorkTime(0);
        return projectWorkTimeAndType;
    }

    // 生成三种类型的表头
    public List<ProjectWorkTimeAndType> createProjectWorkTimeAndTypeListByType() {
        List<ProjectWorkTimeAndType> list = new ArrayList<>(6);
        ProjectWorkTimeAndType timeAndType;
        // 外部商务、技术交流
        timeAndType = createProjectWorkTimeAndTypeByType(ProjectTypeEnum.EXTERNAL_BUSINESS.getTypeName(), "正常");
        list.add(timeAndType);
        timeAndType = createProjectWorkTimeAndTypeByType(ProjectTypeEnum.EXTERNAL_BUSINESS.getTypeName(), "加班");
        list.add(timeAndType);
        // 内部培训、技术准备、管理
        timeAndType = createProjectWorkTimeAndTypeByType(ProjectTypeEnum.INTERNAL_TRAINING.getTypeName(), "正常");
        list.add(timeAndType);
        timeAndType = createProjectWorkTimeAndTypeByType(ProjectTypeEnum.INTERNAL_TRAINING.getTypeName(), "加班");
        list.add(timeAndType);
        // 其他非项目/商机工作
        timeAndType = createProjectWorkTimeAndTypeByType(ProjectTypeEnum.OTHER_NON_PROJECTS.getTypeName(), "正常");
        list.add(timeAndType);
        timeAndType = createProjectWorkTimeAndTypeByType(ProjectTypeEnum.OTHER_NON_PROJECTS.getTypeName(), "加班");
        list.add(timeAndType);
        return list;
    }

    // 根据类型生成ProjectWorkTimeAndType对象
    public ProjectWorkTimeAndType createProjectWorkTimeAndTypeByType(String type, String isOvertime) {
        ProjectWorkTimeAndType projectWorkTimeAndType = new ProjectWorkTimeAndType();
        projectWorkTimeAndType.setProjectType(type);
        projectWorkTimeAndType.setIsOvertime(isOvertime);
        projectWorkTimeAndType.setWorkTime(0);
        return projectWorkTimeAndType;
    }

    // 根据日期生成ProjectStatisticsByMonth对象
    public ProjectStatisticsByMonth.StatisticsDateAndWorkTime createStatisticsDateAndWorkTime(String date) {
        ProjectStatisticsByMonth.StatisticsDateAndWorkTime statisticsDateAndWorkTime = new ProjectStatisticsByMonth.StatisticsDateAndWorkTime();
        statisticsDateAndWorkTime.setDate(date);
        statisticsDateAndWorkTime.setTotalTime(new BigDecimal("0.00"));
        statisticsDateAndWorkTime.setCost(new BigDecimal("0.00"));
        return statisticsDateAndWorkTime;
    }

    // 部门主键不为空时，日期格式只有某月。为空时，日期格式为某年统计的第一个月为某年某月，其余为某月
    public void conversionDateFormat(List<ProjectStatisticsByMonth> projectStatisticsByMonths, Integer deptId) {
        for (ProjectStatisticsByMonth projectStatisticsByMonth : projectStatisticsByMonths) {
            List<ProjectStatisticsByMonth.StatisticsDateAndWorkTime> statisticsDateAndWorkTimes = projectStatisticsByMonth.getStatisticsDateAndWorkTimes();
            // 部门主键不为空时，日期格式只有某月
            if (deptId != null) {
                for (ProjectStatisticsByMonth.StatisticsDateAndWorkTime statisticsDateAndWorkTime : statisticsDateAndWorkTimes) {
                    String date = statisticsDateAndWorkTime.getDate();
                    StringBuilder stringBuilder = new StringBuilder(date);
                    // 删除年份
                    stringBuilder.delete(0, 5);
                    statisticsDateAndWorkTime.setDate(stringBuilder.toString());
                }
            } else {
                for (int i = statisticsDateAndWorkTimes.size() - 1; i > 0; i--) {
                    String date1 = statisticsDateAndWorkTimes.get(i).getDate();
                    String date2 = statisticsDateAndWorkTimes.get(i - 1).getDate();
                    // 如果不为当年统计数据的第一个月，则删除年份
                    if (date1.charAt(2) == date2.charAt(2) && date1.charAt(3) == date2.charAt(3)) {
                        StringBuilder dateBuilder1 = new StringBuilder(date1);
                        // 删除年份
                        dateBuilder1.delete(0, 5);
                        statisticsDateAndWorkTimes.get(i).setDate(dateBuilder1.toString());
                    }
                }
            }
        }
    }
}
