package com.yida.data.attendance.service.impl;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Joiner;
import com.yida.data.attendance.dto.AddAttendanceRuleObjDTO;
import com.yida.data.attendance.dto.AddAttendanceRuleTimeDTO;
import com.yida.data.attendance.dto.AttendanceCountPageDTO;
import com.yida.data.attendance.dto.AttendanceDayReportDTO;
import com.yida.data.attendance.dto.AttendanceResultByDayDTO;
import com.yida.data.attendance.dto.AttendanceResultByStartAndEndTimeDTO;
import com.yida.data.attendance.dto.AttendanceStatusByMonthDTO;
import com.yida.data.attendance.dto.DayReportDataDTO;
import com.yida.data.attendance.dto.ManageListUserDTO;
import com.yida.data.attendance.dto.PageAttendanceRuleDTO;
import com.yida.data.attendance.mapper.AttendanceResultMapper;
import com.yida.data.attendance.service.AttendanceResultService;
import com.yida.data.attendance.service.AttendanceRuleAdminService;
import com.yida.data.attendance.service.AttendanceRuleObjService;
import com.yida.data.attendance.service.AttendanceRuleObjUserService;
import com.yida.data.attendance.service.AttendanceRuleService;
import com.yida.data.attendance.service.AttendanceRuleSpecialDateService;
import com.yida.data.attendance.service.AttendanceRuleTimeService;
import com.yida.data.attendance.service.NoticeService;
import com.yida.data.attendance.vo.AttdanceResultDetailVO;
import com.yida.data.attendance.vo.AttdanceResultTotalVO;
import com.yida.data.attendance.vo.AttdanceResultVO;
import com.yida.data.attendance.vo.AttendanceRuleVO;
import com.yida.data.attendance.vo.AttendanceStatusByMonthVO;
import com.yida.data.attendance.vo.DateStatusVO;
import com.yida.data.attendance.vo.DownLoadAttendanceResultVO;
import com.yida.data.attendance.vo.ManageListUserAttendanceDetailTotalVO;
import com.yida.data.attendance.vo.ManageListUserAttendanceDetailVO;
import com.yida.data.attendance.vo.ManageListUserVO;
import com.yida.data.attendance.vo.StaRecordCountVO;
import com.yida.data.attendance.vo.StaffIdentityVO;
import com.yida.data.attendance.vo.StudentDormAttendanceDayReportExcelVO;
import com.yida.data.attendance.vo.StudentDormAttendanceResultExcelVO;
import com.yida.data.attendance.vo.StudentDormAttendanceResultTotalExcelVO;
import com.yida.data.attendance.vo.UserAttendanceResultByDayVO;
import com.yida.data.attendance.vo.UserAttendanceResultByTimeSlotVO;
import com.yida.data.attendance.vo.UserAttendanceResultDayAndNumVO;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceRecord;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceResult;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceRule;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceRuleAdmin;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceRuleObj;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceRuleObjUser;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceRuleSpecialDate;
import com.yida.data.common.core.entity.attendance.attendance.AttendanceRuleTime;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.system.Dept;
import com.yida.data.common.core.entity.system.enums.RoleEnum;
import com.yida.data.common.core.entity.user.EduStaff;
import com.yida.data.common.core.entity.user.EduStaffDept;
import com.yida.data.common.core.entity.user.EduStudent;
import com.yida.data.common.core.entity.user.EduUserDept;
import com.yida.data.common.core.entity.user.enums.StudentStatusEnum;
import com.yida.data.common.core.entity.user.enums.UserDeptTypeEnum;
import com.yida.data.common.core.enums.EnableStatusEnum;
import com.yida.data.common.core.enums.UserTypeEnum;
import com.yida.data.common.core.enums.attendance.AttendanceModeTypeEnum;
import com.yida.data.common.core.enums.attendance.AttendanceResultEnum;
import com.yida.data.common.core.enums.attendance.AttendanceTypeEnum;
import com.yida.data.common.core.enums.attendance.AttendanceUserTypeEnum;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.common.core.utils.FileUtil;
import com.yida.data.common.service.CommonService;
import com.yida.data.school.dto.userLeave.ListUserRequestDTO;
import com.yida.data.school.feign.leave.RemoteLeaveRequestService;
import com.yida.data.school.vo.userLeave.EduLeaveRequestUserVO;
import com.yida.data.system.feign.RemoteDeptService;
import com.yida.data.user.dto.ListStaffDTO;
import com.yida.data.user.dto.ListStudentDTO;
import com.yida.data.user.feign.RemoteStaffService;
import com.yida.data.user.feign.RemoteStudentService;
import com.yida.data.user.feign.RemoteUserDeptService;

import com.yida.data.user.vo.DownLoadStaffAttendanceRecordVO;
import java.io.File;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

/**
 * 考勤-考勤结果 Service实现
 *
 * @date 2023-08-09 11:37:25
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class AttendanceResultServiceImpl extends ServiceImpl
    <AttendanceResultMapper, AttendanceResult> implements AttendanceResultService {

    private final AttendanceRuleService attendanceRuleService;
    private final AttendanceRuleTimeService attendanceRuleTimeService;
    private final AttendanceRuleSpecialDateService attendanceRuleSpecialDateService;
    private final AttendanceRuleAdminService attendanceRuleAdminService;
    private final AttendanceRuleObjService attendanceRuleObjService;
    private final AttendanceRuleObjUserService attendanceRuleObjUserService;

    private final RemoteStudentService remoteStudentService;
    private final RemoteStaffService remoteStaffService;
    private final RemoteLeaveRequestService remoteLeaveRequestService;
    private final RemoteUserDeptService remoteUserDeptService;
    private final RemoteDeptService remoteDeptService;
    private final CommonService commonService;
    private final RedisService redisService;
    private final NoticeService noticeService;

    @Value("${febs.uploadUrl}")
    private String uploadUrl;

    @Autowired
    ApplicationContext applicationContext;

    @Override
    public void addResult(AttendanceRecord record) {
        AttendanceResult result = getOne(Wrappers.lambdaQuery(new AttendanceResult())
            .eq(AttendanceResult::getRuleId, record.getRuleId())
            .eq(AttendanceResult::getRuleTimeId, record.getRuleTimeId())
            .eq(AttendanceResult::getUserId, record.getUserId())
            .eq(AttendanceResult::getUserType, record.getUserType())
            .eq(AttendanceResult::getAttendanceDate, record.getCreateTime().toLocalDate()));

        if (ObjectUtil.isNull(result)) {
            result = new AttendanceResult();
            AttendanceRuleVO rule = attendanceRuleService.getRule(record.getRuleId());
            AttendanceRuleTime ruleTime = attendanceRuleTimeService.getById(record.getRuleTimeId());

            result.setSchoolId(record.getSchoolId());
            result.setAttType(rule.getType());
            result.setUserType(record.getUserType());
            result.setUserId(record.getUserId());
            result.setRuleId(record.getRuleId());
            result.setRuleTimeId(record.getRuleTimeId());
            result.setAttendanceDate(record.getCreateTime().toLocalDate());
            result.setStartStiTime(ruleTime.getStartTime());
            result.setEndStiTime(ruleTime.getEndTime());
        }

        if (ObjectUtil.equals(record.getRuleTimeType(), AttendanceTypeEnum.WORK_ON.getValue())) {
            //如果是自由打卡模式，已打卡状态为正常，此次为正常则更新记录，不正常则不记录
            if (ObjectUtil.equals(result.getAttType(), AttendanceModeTypeEnum.FREE.getValue()) && ObjectUtil
                .equals(result.getStartStatus(),
                    AttendanceResultEnum.NORMAL.getValue())) {
                if (ObjectUtil.equals(record.getStatus(), AttendanceResultEnum.NORMAL.getValue())) {
                    result.setStartRealTime(record.getCreateTime().toLocalTime());
                    result.setStartStatus(record.getStatus());
                    result.setStartPicUrl(record.getPicUrl());
                }
            } else {
                result.setStartRealTime(record.getCreateTime().toLocalTime());
                result.setStartStatus(record.getStatus());
                result.setStartPicUrl(record.getPicUrl());
            }
            if (!ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), result.getStartStatus())) {
                //计算迟到分钟数
                result.setStartLateTime(Duration.between(result.getStartStiTime(), result.getStartRealTime()).toMinutes());
            }
        }
        if (ObjectUtil.equals(record.getRuleTimeType(), AttendanceTypeEnum.WORK_OFF.getValue())) {
            result.setEndRealTime(record.getCreateTime().toLocalTime());
            result.setEndStatus(record.getStatus());
            result.setEndPicUrl(record.getPicUrl());
            if (ObjectUtil.equals(AttendanceResultEnum.ABNORMAL.getValue(), result.getEndStatus())) {
                //计算迟到分钟数
                result.setEndLeaveTime(Duration.between(result.getEndRealTime(), result.getEndStiTime()).toMinutes());
            }
        }

        saveOrUpdate(result);
    }

    @Override
    public IPage<AttdanceResultVO> listResultPage(AttendanceCountPageDTO dto) {
        Long topDeptId = FebsUtil.getTopDeptId();

        Map<Long, List<EduStaff>> staffMap = new HashMap<>();
        Map<Long, List<EduStudent>> studentMap = new HashMap<>();

        List<Long> userIdList = new ArrayList<>();
        //先查找出学生或者教职工
        if (ObjectUtil.equals(dto.getType(), AttendanceUserTypeEnum.STAFF.getValue())) {
            ListStaffDTO param = new ListStaffDTO();
            param.setSchoolId(topDeptId);
            param.setMobile(dto.getNameOrNumber());
            param.setDeptId(dto.getDeptId());
            List<EduStaff> staffList = remoteStaffService.listStaff(param).getData();
            param.setMobile(null);
            param.setName(dto.getNameOrNumber());
            List<EduStaff> staffListOth = remoteStaffService.listStaff(param).getData();
            staffList.addAll(staffListOth);
            if (CollUtil.isNotEmpty(staffList)) {
                staffMap = staffList.stream().collect(Collectors.groupingBy(EduStaff::getId));
                userIdList = staffList.stream().map(EduStaff::getId)
                    .collect(Collectors.toList());
            } else {
                return new Page<>();
            }
        } else {
            //查询权限对应的班级的学生
            List<EduStudent> studentList = new ArrayList<>();
            String rolePerms = FebsUtil.getCurrentUser().getRolePerms();
            if (rolePerms.contains(RoleEnum.ROLE_SCHOOL_PRINCIPAL.getValue())) {
                ListStudentDTO param = new ListStudentDTO();
                param.setSchoolId(topDeptId);
                param.setCampusId(dto.getCampusId());
                param.setSectionId(dto.getSectionId());
                param.setGradeId(dto.getGradeId());
                param.setClassId(dto.getClassId());
                param.setStuName(dto.getNameOrNumber());
                param.setIsQueryParent(false);
                param.setIsQuerySchoolName(false);
                studentList = remoteStudentService.listStudent(param).getData();
            } else {
                if (ObjectUtil.isNull(dto.getCampusId()) && ObjectUtil.isNull(dto.getSectionId()) && ObjectUtil
                    .isNull(dto.getGradeId()) && ObjectUtil.isNull(dto.getClassId())) {
                    List<Long> classIdList = remoteStaffService.listClassIdByStaffId().getData();
                    ListStudentDTO param = new ListStudentDTO();
                    param.setClassIds(classIdList);
                    param.setIsQueryParent(false);
                    param.setIsQuerySchoolName(false);
                    param.setStuName(dto.getNameOrNumber());
                    studentList = remoteStudentService.listStudent(param).getData();
                } else {
                    ListStudentDTO param = new ListStudentDTO();
                    param.setSchoolId(topDeptId);
                    param.setCampusId(dto.getCampusId());
                    param.setSectionId(dto.getSectionId());
                    param.setGradeId(dto.getGradeId());
                    param.setClassId(dto.getClassId());
                    param.setStuName(dto.getNameOrNumber());
                    param.setIsQueryParent(false);
                    param.setIsQuerySchoolName(false);
                    studentList = remoteStudentService.listStudent(param).getData();
                }
            }
            if (CollUtil.isNotEmpty(studentList)) {
                studentMap = studentList.stream().collect(Collectors.groupingBy(EduStudent::getId));
                userIdList = studentList.stream().map(EduStudent::getId)
                    .collect(Collectors.toList());
            } else {
                return new Page<>();
            }
        }

        dto.setUserIdList(userIdList);
        IPage<AttdanceResultVO> attdanceResultVOIPage = baseMapper.listResultPage(dto.toPage(), dto);
        List<AttdanceResultVO> records = attdanceResultVOIPage.getRecords();
        for (AttdanceResultVO attdanceResultVO : records) {
            if (ObjectUtil.equals(dto.getType(), AttendanceUserTypeEnum.STAFF.getValue())) {
                //教职工
                List<EduStaff> staffList = staffMap.get(attdanceResultVO.getUserId());
                attdanceResultVO.setName(staffList.get(0).getName());
                attdanceResultVO.setNumber(staffList.get(0).getMobile());
                List<EduStaffDept> staffDept = commonService.getStaffById(attdanceResultVO.getUserId()).getStaffDept();
                attdanceResultVO
                    .setDeptName(
                        CollUtil.isEmpty(staffDept) ? commonService.getStaffById(attdanceResultVO.getUserId()).getSchoolName()
                            : staffDept.get(0).getDeptName());
            } else {
                //学生
                attdanceResultVO.setName(studentMap.get(attdanceResultVO.getUserId()).get(0).getStuName());
                attdanceResultVO.setNumber(studentMap.get(attdanceResultVO.getUserId()).get(0).getStuNumber());
                attdanceResultVO.setDeptName(
                    studentMap.get(attdanceResultVO.getUserId()).get(0).getCampusName() + "-" + studentMap
                        .get(attdanceResultVO.getUserId()).get(0).getGradeName() + "-" + studentMap
                        .get(attdanceResultVO.getUserId()).get(0).getClassName());
            }
        }
        return attdanceResultVOIPage;
    }

    @Override
    public AttdanceResultTotalVO total(AttendanceCountPageDTO dto) {
        Long topDeptId = FebsUtil.getTopDeptId();

        Map<Long, List<EduStaff>> staffMap = new HashMap<>();
        Map<Long, List<EduStudent>> studentMap = new HashMap<>();

        List<Long> userIdList = new ArrayList<>();
        //先查找出学生或者教职工
        if (ObjectUtil.equals(dto.getType(), AttendanceUserTypeEnum.STAFF.getValue())) {
            ListStaffDTO param = new ListStaffDTO();
            param.setSchoolId(topDeptId);
            param.setMobile(dto.getNameOrNumber());
            param.setDeptId(dto.getDeptId());
            List<EduStaff> staffList = remoteStaffService.listStaff(param).getData();
            param.setMobile(null);
            param.setName(dto.getNameOrNumber());
            List<EduStaff> staffListOth = remoteStaffService.listStaff(param).getData();
            staffList.addAll(staffListOth);
            if (CollUtil.isNotEmpty(staffList)) {
                userIdList = staffList.stream().map(EduStaff::getId)
                    .collect(Collectors.toList());
            } else {
                return null;
            }
        } else {
            //查询权限对应的班级的学生
            List<EduStudent> studentList = new ArrayList<>();
            String rolePerms = FebsUtil.getCurrentUser().getRolePerms();
            if (rolePerms.contains(RoleEnum.ROLE_SCHOOL_PRINCIPAL.getValue())) {
                ListStudentDTO param = new ListStudentDTO();
                param.setSchoolId(topDeptId);
                param.setCampusId(dto.getCampusId());
                param.setSectionId(dto.getSectionId());
                param.setGradeId(dto.getGradeId());
                param.setClassId(dto.getClassId());
                param.setStuName(dto.getNameOrNumber());
                param.setIsQueryParent(false);
                param.setIsQuerySchoolName(false);
                studentList = remoteStudentService.listStudent(param).getData();
            } else {
                if (ObjectUtil.isNull(dto.getCampusId()) && ObjectUtil.isNull(dto.getSectionId()) && ObjectUtil
                    .isNull(dto.getGradeId()) && ObjectUtil.isNull(dto.getClassId())) {
                    List<Long> classIdList = remoteStaffService.listClassIdByStaffId().getData();
                    ListStudentDTO param = new ListStudentDTO();
                    param.setClassIds(classIdList);
                    param.setIsQueryParent(false);
                    param.setIsQuerySchoolName(false);
                    param.setStuName(dto.getNameOrNumber());
                    studentList = remoteStudentService.listStudent(param).getData();
                } else {
                    ListStudentDTO param = new ListStudentDTO();
                    param.setSchoolId(topDeptId);
                    param.setCampusId(dto.getCampusId());
                    param.setSectionId(dto.getSectionId());
                    param.setGradeId(dto.getGradeId());
                    param.setClassId(dto.getClassId());
                    param.setStuName(dto.getNameOrNumber());
                    param.setIsQueryParent(false);
                    param.setIsQuerySchoolName(false);
                    studentList = remoteStudentService.listStudent(param).getData();
                }
            }
            if (CollUtil.isNotEmpty(studentList)) {
                userIdList = studentList.stream().map(EduStudent::getId)
                    .collect(Collectors.toList());
            } else {
                return null;
            }
        }
        dto.setUserIdList(userIdList);
        List<AttdanceResultDetailVO> attdanceResultDetailVOList = baseMapper.findAttandanceTotal(dto);

        //请假
        ListUserRequestDTO requestDTO = new ListUserRequestDTO();
        requestDTO.setRequestType(dto.getType());
        requestDTO.setStartTime(dto.getStartDate().atTime(00, 00, 01));
        requestDTO.setEndTime(dto.getEndDate().atTime(23, 59, 59));
        List<EduLeaveRequestUserVO> eduLeaveRequestUserVOList = remoteLeaveRequestService.findList(requestDTO)
            .getData();

        int missNumber = attdanceResultDetailVOList.stream().filter(a -> ObjectUtil.isNull(a.getStartStatus()))
            .collect(Collectors.toList()).size();
        int normalNumber = attdanceResultDetailVOList.stream()
            .filter(a -> ObjectUtil.equals(a.getStartStatus(), AttendanceResultEnum.NORMAL.getValue()))
            .collect(Collectors.toList()).size();
        int lateNumber = attdanceResultDetailVOList.stream()
            .filter(a -> ObjectUtil.equals(a.getStartStatus(), AttendanceResultEnum.LATE_DORM.getValue()))
            .collect(Collectors.toList()).size();
        int abLateNumber = attdanceResultDetailVOList.stream()
            .filter(a -> ObjectUtil.equals(a.getStartStatus(), AttendanceResultEnum.AB_LATE_DORM.getValue()))
            .collect(Collectors.toList()).size();
        return AttdanceResultTotalVO.builder().normalNumber(normalNumber)
            .missNumber(missNumber).lateNumber(lateNumber)
            .abLateNumber(abLateNumber).leaveNumber(eduLeaveRequestUserVOList.size()).build();
    }

    @Override
    public void downLocalAttendanceResult(AttendanceCountPageDTO dto, String uuid) {
        String rolePerms = FebsUtil.getCurrentUser().getRolePerms();
        List<Long> userIdList = new ArrayList<>();
        if (rolePerms.contains(RoleEnum.ROLE_SCHOOL_PRINCIPAL.getValue())) {
            ListStudentDTO param = new ListStudentDTO();
            param.setSchoolId(dto.getSchoolId());
            param.setCampusId(dto.getCampusId());
            param.setSectionId(dto.getSectionId());
            param.setGradeId(dto.getGradeId());
            param.setClassId(dto.getClassId());
            param.setStuName(dto.getNameOrNumber());
            param.setIsQueryParent(false);
            param.setIsQuerySchoolName(false);
            userIdList = remoteStudentService.listStudent(param).getData().stream().map(EduStudent::getId)
                .collect(Collectors.toList());
        } else {
            if (ObjectUtil.isNull(dto.getCampusId()) && ObjectUtil.isNull(dto.getSectionId()) && ObjectUtil
                .isNull(dto.getGradeId()) && ObjectUtil.isNull(dto.getClassId())) {
                List<Long> classIdList = remoteStaffService.listClassIdByStaffId().getData();
                ListStudentDTO param = new ListStudentDTO();
                param.setClassIds(classIdList);
                param.setIsQueryParent(false);
                param.setIsQuerySchoolName(false);
                param.setStuName(dto.getNameOrNumber());
                userIdList = remoteStudentService.listStudent(param).getData().stream().map(EduStudent::getId)
                    .collect(Collectors.toList());
            } else {
                ListStudentDTO param = new ListStudentDTO();
                param.setSchoolId(dto.getSchoolId());
                param.setCampusId(dto.getCampusId());
                param.setSectionId(dto.getSectionId());
                param.setGradeId(dto.getGradeId());
                param.setClassId(dto.getClassId());
                param.setStuName(dto.getNameOrNumber());
                param.setIsQueryParent(false);
                param.setIsQuerySchoolName(false);
                userIdList = remoteStudentService.listStudent(param).getData().stream().map(EduStudent::getId)
                    .collect(Collectors.toList());
            }
        }
        dto.setUserIdList(userIdList);
        AttendanceResultServiceImpl bean = applicationContext
            .getBean(AttendanceResultServiceImpl.class);

        bean.dealAttendanceReultData(dto, uuid);
    }


    @Override
    public void downLocalAttendanceDayReport(AttendanceDayReportDTO dto, String uuid) {
        String rolePerms = FebsUtil.getCurrentUser().getRolePerms();
        List<Long> userIdList = new ArrayList<>();
        if (rolePerms.contains(RoleEnum.ROLE_SCHOOL_PRINCIPAL.getValue())) {
            ListStudentDTO param = new ListStudentDTO();
            param.setSchoolId(dto.getSchoolId());
            param.setIsQueryParent(false);
            param.setIsQuerySchoolName(false);
            userIdList = remoteStudentService.listStudent(param).getData().stream().map(EduStudent::getId)
                .collect(Collectors.toList());
        } else {
            List<Long> classIdList = remoteStaffService.listClassIdByStaffId().getData();
            ListStudentDTO param = new ListStudentDTO();
            param.setClassIds(classIdList);
            param.setIsQueryParent(false);
            param.setIsQuerySchoolName(false);
            userIdList = remoteStudentService.listStudent(param).getData().stream().map(EduStudent::getId)
                .collect(Collectors.toList());
        }
        dto.setUserIdList(userIdList);

        AttendanceResultServiceImpl bean = applicationContext
            .getBean(AttendanceResultServiceImpl.class);
        bean.dealAttendanceReportData(dto, uuid);
    }

    @Async
    void dealAttendanceReportData(AttendanceDayReportDTO dto, String uuid) {

        long durationDays = dto.getStartAttendanceDate().until(dto.getEndAttendanceDate(), ChronoUnit.DAYS);

        log.info("相差天数{}", durationDays);

        String fileName = FileUtil.getLocalUploadAddress() + uuid + ".xls";
        File file = new File(fileName);
        try {
            log.info("开始导出考勤日报/周报/月报");
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            List<List<String>> campusExportDataList = new ArrayList<>();
            List<List<String>> sectionExportDataList = new ArrayList<>();
            List<List<String>> gradeExportDataList = new ArrayList<>();
            List<List<String>> classExportDataList = new ArrayList<>();
            List<AttendanceResult> resultList = new ArrayList<>();

            if (CollUtil.isNotEmpty(dto.getUserIdList())) {
                resultList = list(Wrappers.lambdaQuery(new AttendanceResult())
                    .in(AttendanceResult::getUserId, dto.getUserIdList())
                    .eq(AttendanceResult::getUserType, dto.getUserType())
                    .between(AttendanceResult::getAttendanceDate, dto.getStartAttendanceDate(), dto.getEndAttendanceDate())
                    .orderByAsc(AttendanceResult::getUserId));

                for (AttendanceResult result : resultList) {
                    if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), result.getUserType())) {
                        EduStudent student = commonService.getStudentById(result.getUserId());
                        if (ObjectUtil.isNotNull(student)) {
                            result.setCampusName(student.getCampusName());
                            result.setSectionName(student.getSectionName());
                            result.setGradeName(student.getGradeName());
                            result.setClassName(student.getClassName());
                        }
                    } else {
                        EduStaff staff = commonService.getStaffById(result.getUserId());
                        if (ObjectUtil.isNotNull(staff)) {
                            List<EduStaffDept> staffDept = staff.getStaffDept();
                            if (CollUtil.isEmpty(staffDept)) {
                                result.setCampusName(staff.getSchoolName());
                            } else {
                                List<String> deptNameList = staffDept.stream().map(EduStaffDept::getDeptName)
                                    .collect(Collectors.toList());
                                result.setCampusName(Joiner.on("/").join(deptNameList));
                            }
                        }
                    }
                }

                Map<String, List<AttendanceResult>> campusMap = resultList.stream()
                    .collect(Collectors.groupingBy(AttendanceResult::getCampusName));

                String startAttendanceDate = LocalDateTimeUtil.format(dto.getStartAttendanceDate(), "yyyy-MM-dd");
                String endAttendanceDate = LocalDateTimeUtil.format(dto.getEndAttendanceDate(), "yyyy-MM-dd");

                List<AttendanceResult> finalResultList = resultList;
                campusMap.forEach((k, v) -> {
                    List<String> cam_singleDataList = dealSingleExcelData(startAttendanceDate, endAttendanceDate, k, "-", "-",
                        "-", v);
                    campusExportDataList.add(cam_singleDataList);
                    Map<String, List<AttendanceResult>> sectionMap = v.stream()
                        .collect(Collectors.groupingBy(AttendanceResult::getSectionName));
                    sectionMap.forEach((s, l) -> {
                        List<String> sec_singleDataList = dealSingleExcelData(startAttendanceDate, endAttendanceDate, k, s, "-",
                            "-", l);
                        sectionExportDataList.add(sec_singleDataList);
                        Map<String, List<AttendanceResult>> gradeMap = l.stream()
                            .collect(Collectors.groupingBy(AttendanceResult::getGradeName));
                        gradeMap.forEach((g, n) -> {
                            List<String> grade_singleDataList = dealSingleExcelData(startAttendanceDate, endAttendanceDate, k, s,
                                g, "-", n);
                            gradeExportDataList.add(grade_singleDataList);
                            Map<String, List<AttendanceResult>> classMap = n.stream()
                                .collect(Collectors.groupingBy(AttendanceResult::getClassName));
                            classMap.forEach((c, m) -> {
                                List<String> class_singleDataList = dealSingleExcelData(startAttendanceDate, endAttendanceDate, k,
                                    s, g, c, m);
                                classExportDataList.add(class_singleDataList);

                                DownLoadAttendanceResultVO vo = (DownLoadAttendanceResultVO) redisService
                                    .hget(CachePrefixConstant.ATTENDANCE_DAY_REPORT_DOWNLOAD, uuid);

                                redisService
                                    .hset(CachePrefixConstant.ATTENDANCE_DAY_REPORT_DOWNLOAD, uuid,
                                        DownLoadAttendanceResultVO.builder()
                                            .key(uuid)
                                            .finish(0)
                                            .totalNum(finalResultList.size())
                                            .currentNum(ObjectUtil.isNull(vo) ? 1 : vo.getCurrentNum() + 1).build());
                            });
                        });
                    });
                });
            }

            ExcelWriter excelWriter = EasyExcel.write(file).excelType(ExcelTypeEnum.XLSX).build();
            WriteSheet writeSheet0 = EasyExcel.writerSheet(0, durationDays == 0 ? "日报-校区" : durationDays > 7 ? "月报-校区" : "周报-校区")
                .head(StudentDormAttendanceDayReportExcelVO.class).build();
            WriteSheet writeSheet1 = EasyExcel.writerSheet(1, durationDays == 0 ? "日报-学段" : durationDays > 7 ? "月报-学段" : "周报-学段")
                .head(StudentDormAttendanceDayReportExcelVO.class).build();
            WriteSheet writeSheet2 = EasyExcel.writerSheet(2, durationDays == 0 ? "日报-年级" : durationDays > 7 ? "月报-年级" : "周报-年级")
                .head(StudentDormAttendanceDayReportExcelVO.class).build();
            WriteSheet writeSheet3 = EasyExcel.writerSheet(3, durationDays == 0 ? "日报-班级" : durationDays > 7 ? "月报-班级" : "周报-班级")
                .head(StudentDormAttendanceDayReportExcelVO.class).build();
            excelWriter.write(campusExportDataList, writeSheet0);
            excelWriter.write(sectionExportDataList, writeSheet1);
            excelWriter.write(gradeExportDataList, writeSheet2);
            excelWriter.write(classExportDataList, writeSheet3);
            excelWriter.finish();

            // 上传文件到媒资
            String fileUrl = com.yida.data.common.core.utils.FileUtil.uploadFileToMediaServer(uploadUrl, file);
            redisService
                .hset(CachePrefixConstant.ATTENDANCE_DAY_REPORT_DOWNLOAD, uuid, DownLoadAttendanceResultVO.builder()
                    .key(uuid)
                    .finish(1)
                    .filePath(fileUrl)
                    .totalNum(CollUtil.isEmpty(resultList) ? 100 : resultList.size())
                    .currentNum(CollUtil.isEmpty(resultList) ? 100 : resultList.size()).build());

            stopWatch.stop();
            log.info("导出考勤日报总共耗时: {}", stopWatch.getTotalTimeSeconds() + "秒");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //删除本地文件
            if (cn.hutool.core.io.FileUtil.exist(file)) {
                cn.hutool.core.io.FileUtil.del(file);
            }
        }
    }

    List<String> dealSingleExcelData(String startAttendanceDate, String endAttendanceDate, String campusName, String sectionName,
        String gradeName, String className,
        List<AttendanceResult> resultList) {
        List<String> singleDataList = new ArrayList<>();
        singleDataList.add(ObjectUtil.equals(startAttendanceDate, endAttendanceDate) ? startAttendanceDate
            : (startAttendanceDate + " 至 " + endAttendanceDate));

        singleDataList.add(campusName);
        singleDataList.add(sectionName);
        singleDataList.add(gradeName);
        singleDataList.add(className);
        //应该打卡人数
        Map<Long, List<AttendanceResult>> userMap = resultList.stream()
            .collect(Collectors.groupingBy(AttendanceResult::getUserId));
        singleDataList.add(String.valueOf(userMap.size()));

        //实际打卡人数
        List<AttendanceResult> dakaAttendanceResultList = resultList.stream()
            .filter(a -> !(ObjectUtil.isNull(a.getStartStatus()) && ObjectUtil.isNull(a.getEndStatus())))
            .collect(Collectors.toList());
        Map<Long, List<AttendanceResult>> dakaUserMap = dakaAttendanceResultList.stream()
            .collect(Collectors.groupingBy(AttendanceResult::getUserId));
        singleDataList.add(String.valueOf(dakaUserMap.size()));

        //请假人数
        ListUserRequestDTO requestDTO = new ListUserRequestDTO();
        requestDTO.setRequestType(UserTypeEnum.PARENT_USER_TYPE.getType());
        requestDTO.setUserIdList(resultList.stream().map(AttendanceResult::getUserId).collect(Collectors.toList()));
        requestDTO
            .setStartTime(LocalDateTimeUtil.parse(startAttendanceDate, "yyyy-MM-dd").toLocalDate().atTime(00, 00, 00));
        requestDTO.setEndTime(LocalDateTimeUtil.parse(endAttendanceDate, "yyyy-MM-dd").toLocalDate().atTime(23, 23, 59));
        List<EduLeaveRequestUserVO> eduLeaveRequestUserVOList = remoteLeaveRequestService.findList(requestDTO)
            .getData();
        Map<Long, List<EduLeaveRequestUserVO>> eduRequestMap = eduLeaveRequestUserVOList.stream()
            .collect(Collectors.groupingBy(EduLeaveRequestUserVO::getUserId));
        singleDataList.add(String.valueOf(eduRequestMap.size()));

        //正常打卡人数
        List<AttendanceResult> abnormalAttendanceResultList = resultList.stream().filter(
            a -> ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), a.getAttType()) ? !(ObjectUtil
                .equals(AttendanceResultEnum.NORMAL.getValue(), a.getStartStatus()) && ObjectUtil
                .equals(AttendanceResultEnum.NORMAL.getValue(), a.getEndStatus()))
                : !ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), a.getStartStatus())).collect(Collectors.toList());
        Map<Long, List<AttendanceResult>> abnormalUserMap = abnormalAttendanceResultList.stream()
            .collect(Collectors.groupingBy(AttendanceResult::getUserId));
        singleDataList.add(String.valueOf((int) (userMap.size() - abnormalUserMap.size())));

        //旷宿人数
        List<AttendanceResult> missAttendanceResultList = resultList.stream().filter(
            a -> ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), a.getAttType()) ? (ObjectUtil
                .isNull(a.getStartStatus()) && ObjectUtil.isNull(a.getEndStatus()))
                : ObjectUtil.isNull(a.getStartStatus())).collect(Collectors.toList());
        Map<Long, List<AttendanceResult>> missUserMap = missAttendanceResultList.stream()
            .collect(Collectors.groupingBy(AttendanceResult::getUserId));

        Integer missNum = 0;
        if (missUserMap.size() > eduRequestMap.size()) {
            missNum = missUserMap.size() - eduRequestMap.size();
        }
        singleDataList.add(String.valueOf(missNum));

        //晚归打卡人数
        List<AttendanceResult> lateAttendanceResultList = resultList.stream().filter(
            a -> ObjectUtil.equals(AttendanceResultEnum.LATE_DORM.getValue(), a.getStartStatus())).collect(Collectors.toList());
        Map<Long, List<AttendanceResult>> lateUserMap = lateAttendanceResultList.stream()
            .collect(Collectors.groupingBy(AttendanceResult::getUserId));
        singleDataList.add(String.valueOf(lateUserMap.size()));

        //异常晚归打卡人数
        List<AttendanceResult> abLateAttendanceResultList = resultList.stream().filter(
            a -> ObjectUtil.equals(AttendanceResultEnum.AB_LATE_DORM.getValue(), a.getStartStatus()))
            .collect(Collectors.toList());
        Map<Long, List<AttendanceResult>> abLateUserMap = lateAttendanceResultList.stream()
            .collect(Collectors.groupingBy(AttendanceResult::getUserId));
        singleDataList.add(String.valueOf(abLateUserMap.size()));

        //出勤率
        singleDataList.add(String.format("%.2f", dakaUserMap.size() / (double) userMap.size()));

//        //应打卡次数
//        List<AttendanceResult> freeModeList = resultList.stream()
//            .filter(a -> ObjectUtil.equals(AttendanceModeTypeEnum.FREE.getValue(), a.getAttType())).collect(
//                Collectors.toList());
//
//        List<AttendanceResult> fixModeList = resultList.stream()
//            .filter(a -> ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), a.getAttType())).collect(
//                Collectors.toList());
//
//        singleDataList.add(String.valueOf(freeModeList.size() + (fixModeList.size() * 2)));
//
//        //实际打卡次数
//        List<AttendanceResult> freeModeDakaList = freeModeList.stream()
//            .filter(a -> ObjectUtil.isNotNull(a.getStartStatus()))
//            .collect(Collectors.toList());
//
//        List<AttendanceResult> fixModeStartDakaList = fixModeList.stream()
//            .filter(a -> ObjectUtil.isNotNull(a.getStartStatus()))
//            .collect(Collectors.toList());
//
//        List<AttendanceResult> fixModeEndDakaList = fixModeList.stream()
//            .filter(a -> ObjectUtil.isNotNull(a.getEndStatus()))
//            .collect(Collectors.toList());
//
//        singleDataList
//            .add(String.valueOf(freeModeDakaList.size() + fixModeStartDakaList.size() + fixModeEndDakaList.size()));
//
//        //正常打卡次数
//        List<AttendanceResult> freeModeNormalList = freeModeList.stream()
//            .filter(a -> ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), a.getStartStatus()))
//            .collect(Collectors.toList());
//
//        List<AttendanceResult> fixModeStartNormalList = fixModeList.stream()
//            .filter(a -> ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), a.getStartStatus()))
//            .collect(Collectors.toList());
//
//        List<AttendanceResult> fixModeEndNormalList = fixModeList.stream()
//            .filter(a -> ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), a.getEndStatus()))
//            .collect(Collectors.toList());
//        singleDataList
//            .add(String
//                .valueOf(freeModeNormalList.size() + fixModeStartNormalList.size() + fixModeEndNormalList.size()));
//
//        //旷宿次数
//        List<AttendanceResult> freeModeMissList = freeModeList.stream()
//            .filter(a -> ObjectUtil.isNull(a.getStartStatus()))
//            .collect(Collectors.toList());
//
//        List<AttendanceResult> fixModeStartMissList = fixModeList.stream()
//            .filter(a -> ObjectUtil.isNull(a.getStartStatus()))
//            .collect(Collectors.toList());
//
//        List<AttendanceResult> fixModeEndMissList = fixModeList.stream()
//            .filter(a -> ObjectUtil.isNull(a.getEndStatus()))
//            .collect(Collectors.toList());
//
//        singleDataList
//            .add(String
//                .valueOf(freeModeMissList.size() + fixModeStartMissList.size() + fixModeEndMissList.size()));
//
//        //晚归打卡次数
//        List<AttendanceResult> freeModeLateList = freeModeList.stream()
//            .filter(a -> ObjectUtil.equals(AttendanceResultEnum.LATE_DORM, a.getStartStatus()))
//            .collect(Collectors.toList());
//        singleDataList.add(String.valueOf(freeModeLateList.size()));
//
//        //异常晚归打卡次数
//        List<AttendanceResult> freeModeAbLateList = freeModeList.stream()
//            .filter(a -> ObjectUtil.equals(AttendanceResultEnum.AB_LATE_DORM, a.getStartStatus()))
//            .collect(Collectors.toList());
//        singleDataList.add(String.valueOf(freeModeAbLateList.size()));
//
//        //打卡率
//        singleDataList.add(String.format("%.2f",
//            (freeModeDakaList.size() + fixModeStartDakaList.size() + fixModeEndDakaList.size())
//                / (double) freeModeList.size() + (fixModeList.size() * 2)));

        return singleDataList;
    }

    @Async
    void dealAttendanceReultData(AttendanceCountPageDTO dto, String uuid) {
        String fileName = FileUtil.getLocalUploadAddress() + uuid + ".xls";
        File file = new File(fileName);
        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            //查询考勤结果
            //查询权限对应的班级的学生
            List<List<String>> exportDataList = new ArrayList<>();
            List<List<String>> exportDataListSheet0 = new ArrayList<>();
            List<Long> userIdList = dto.getUserIdList();
            List<EduStudent> studentList = new ArrayList<>();
            List<AttendanceResult> resultList = new ArrayList<>();
            if (CollUtil.isNotEmpty(studentList)) {
                userIdList = studentList.stream().map(EduStudent::getId)
                    .collect(Collectors.toList());
            }
            if (CollUtil.isNotEmpty(userIdList)) {
                resultList = list(Wrappers.lambdaQuery(new AttendanceResult())
                    .in(AttendanceResult::getUserId, userIdList)
                    .eq(AttendanceResult::getUserType, dto.getType())
                    .eq(ObjectUtil.isNotNull(dto.getRuleId()), AttendanceResult::getRuleId, dto.getRuleId())
                    .between(AttendanceResult::getAttendanceDate, dto.getStartDate(), dto.getEndDate())
                    .orderByAsc(AttendanceResult::getUserId));

                Map<Long, List<AttendanceResult>> resultMap = resultList.stream()
                    .collect(Collectors.groupingBy(AttendanceResult::getUserId));

                if (CollUtil.isNotEmpty(resultList)) {
                    for (int i = 0; i < resultList.size(); i++) {
                        AttendanceResult result = resultList.get(i);
                        EduStudent student = commonService.getStudentById(result.getUserId());
                        if (ObjectUtil.isNull(student)) {
                            continue;
                        }
                        //更新进度缓存
                        redisService
                            .hset(CachePrefixConstant.STUDENT_DORM_ATTENDANCE_RESULT_DOWNLOAD, uuid,
                                DownLoadAttendanceResultVO.builder()
                                    .key(uuid)
                                    .finish(0)
                                    .totalNum(resultList.size() + resultMap.size())
                                    .currentNum(i + 1).build());
                        //封装单行数据
                        List<String> singleDataList = new ArrayList<>();

                        singleDataList.add(student.getStuName());
                        singleDataList.add(student.getStuNumber());
                        singleDataList.add(student.getCampusName());
                        singleDataList.add(student.getSectionName());
                        singleDataList.add(student.getGradeName());
                        singleDataList.add(student.getClassName());
                        AttendanceRuleVO rule = attendanceRuleService.getRule(result.getRuleId());
                        singleDataList.add(rule.getName());
                        singleDataList.add(result.getAttendanceDate().toString());
                        singleDataList.add(FebsUtil.convertWeekCN(result.getAttendanceDate().getDayOfWeek().getValue()));
                        singleDataList.add(
                            rule.getTimeDTOList().get(0).getStartTime() + "-" + rule.getTimeDTOList().get(0).getEndTime() + "-"
                                + rule.getTimeDTOList().get(0).getLastTime());
                        singleDataList.add(ObjectUtil.isNull(result.getStartStatus()) ? "旷宿"
                            : AttendanceResultEnum.getName(result.getStartStatus()));
                        singleDataList
                            .add(ObjectUtil.isNull(result.getStartRealTime()) ? "-" : result.getStartRealTime().toString());
                        exportDataList.add(singleDataList);
                    }
                }

                for (Entry<Long, List<AttendanceResult>> entry : resultMap.entrySet()) {
                    Long r = entry.getKey();
                    List<AttendanceResult> n = entry.getValue();

                    DownLoadAttendanceResultVO vo = (DownLoadAttendanceResultVO) redisService
                        .hget(CachePrefixConstant.STUDENT_DORM_ATTENDANCE_RESULT_DOWNLOAD, uuid);

                    redisService
                        .hset(CachePrefixConstant.STUDENT_DORM_ATTENDANCE_RESULT_DOWNLOAD, uuid,
                            DownLoadAttendanceResultVO.builder()
                                .key(uuid)
                                .finish(0)
                                .totalNum(resultList.size() + resultMap.size())
                                .currentNum(vo.getCurrentNum() + 1).build());

                    EduStudent student = commonService.getStudentById(r);
                    if (ObjectUtil.isNull(student)) {
                        continue;
                    }
                    //封装单行数据
                    List<String> singleDataList = new ArrayList<>();

                    singleDataList.add(student.getStuName());
                    singleDataList.add(student.getStuNumber());
                    singleDataList.add(student.getCampusName());
                    singleDataList.add(student.getSectionName());
                    singleDataList.add(student.getGradeName());
                    singleDataList.add(student.getClassName());

                    int missDay = n.stream().filter(k -> ObjectUtil.isNull(k.getStartStatus())).collect(Collectors.toList())
                        .size();
                    int normalDay = n.stream()
                        .filter(k -> ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), k.getStartStatus()))
                        .collect(Collectors.toList()).size();
                    int lateDay = n.stream()
                        .filter(k -> ObjectUtil.equals(AttendanceResultEnum.LATE_DORM.getValue(), k.getStartStatus()))
                        .collect(Collectors.toList()).size();
                    int abLateDay = n.stream()
                        .filter(k -> ObjectUtil.equals(AttendanceResultEnum.AB_LATE_DORM.getValue(), k.getStartStatus()))
                        .collect(Collectors.toList()).size();

                    singleDataList.add(String.valueOf(n.size()));
                    singleDataList.add(String.valueOf(normalDay + lateDay + abLateDay));
                    singleDataList.add(String.valueOf(normalDay));
                    singleDataList.add(String.valueOf(missDay));
                    singleDataList.add(String.valueOf(lateDay));
                    singleDataList.add(String.valueOf(abLateDay));
                    exportDataListSheet0.add(singleDataList);
                }

            }
            // 导出数据
            ExcelWriter excelWriter = EasyExcel.write(file).excelType(ExcelTypeEnum.XLSX).build();
            WriteSheet writeSheet0 = EasyExcel.writerSheet(0, "考勤汇总").head(StudentDormAttendanceResultTotalExcelVO.class).build();
            WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "考勤详情").head(StudentDormAttendanceResultExcelVO.class).build();
            excelWriter.write(exportDataListSheet0, writeSheet0);
            excelWriter.write(exportDataList, writeSheet1);
            excelWriter.finish();
//            EasyExcel.write(file)
//                .excelType(ExcelTypeEnum.XLSX)
//                // 这里放入动态头
//                .head(StudentDormAttendanceResultExcelVO.class).sheet("学生宿舍考勤")
//                // 当然这里数据也可以用 List<List<String>> 去传入
//                .doWrite(exportDataList);
            // 上传文件到媒资
            String fileUrl = com.yida.data.common.core.utils.FileUtil.uploadFileToMediaServer(uploadUrl, file);
            redisService
                .hset(CachePrefixConstant.STUDENT_DORM_ATTENDANCE_RESULT_DOWNLOAD, uuid, DownLoadAttendanceResultVO.builder()
                    .key(uuid)
                    .finish(1)
                    .filePath(fileUrl)
                    .totalNum(CollUtil.isEmpty(resultList) ? 100 : resultList.size())
                    .currentNum(CollUtil.isEmpty(resultList) ? 100 : resultList.size()).build());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //删除本地文件
            if (cn.hutool.core.io.FileUtil.exist(file)) {
                cn.hutool.core.io.FileUtil.del(file);
            }
        }
    }

    @Override
    public IPage<AttdanceResultDetailVO> listResultDetailPage(AttendanceCountPageDTO dto) {
        Long topDeptId = FebsUtil.getTopDeptId();
        Map<Long, List<EduStaff>> staffMap = new HashMap<>();
        Map<Long, List<EduStudent>> studentMap = new HashMap<>();
        List<Long> userIdList = new ArrayList<>();
        //先查找出学生或者教职工
        if (ObjectUtil.equals(dto.getType(), AttendanceUserTypeEnum.STAFF.getValue())) {
            ListStaffDTO param = new ListStaffDTO();
            param.setSchoolId(topDeptId);
            param.setMobile(dto.getNameOrNumber());
            param.setDeptId(dto.getDeptId());
            List<EduStaff> staffList = remoteStaffService.listStaff(param).getData();

            param.setMobile(null);
            param.setName(dto.getNameOrNumber());
            List<EduStaff> staffListOth = remoteStaffService.listStaff(param).getData();
            staffList.addAll(staffListOth);

            if (CollUtil.isNotEmpty(staffList)) {
                staffMap = staffList.stream().collect(Collectors.groupingBy(EduStaff::getId));
                userIdList = staffList.stream().map(EduStaff::getId)
                    .collect(Collectors.toList());
            } else {
                return new Page<>();
            }
        } else {
            //查询权限对应的班级的学生
            List<EduStudent> studentList = new ArrayList<>();
            String rolePerms = FebsUtil.getCurrentUser().getRolePerms();
            if (rolePerms.contains(RoleEnum.ROLE_SCHOOL_PRINCIPAL.getValue())) {
                ListStudentDTO param = new ListStudentDTO();
                param.setSchoolId(topDeptId);
                param.setCampusId(dto.getCampusId());
                param.setSectionId(dto.getSectionId());
                param.setGradeId(dto.getGradeId());
                param.setClassId(dto.getClassId());
                param.setStuName(dto.getNameOrNumber());
                param.setIsQueryParent(false);
                param.setIsQuerySchoolName(false);
                studentList = remoteStudentService.listStudent(param).getData();
            } else {
                if (ObjectUtil.isNull(dto.getCampusId()) && ObjectUtil.isNull(dto.getSectionId()) && ObjectUtil
                    .isNull(dto.getGradeId()) && ObjectUtil.isNull(dto.getClassId())) {
                    List<Long> classIdList = remoteStaffService.listClassIdByStaffId().getData();
                    ListStudentDTO param = new ListStudentDTO();
                    param.setClassIds(classIdList);
                    param.setIsQueryParent(false);
                    param.setIsQuerySchoolName(false);
                    param.setStuName(dto.getNameOrNumber());
                    studentList = remoteStudentService.listStudent(param).getData();
                } else {
                    ListStudentDTO param = new ListStudentDTO();
                    param.setSchoolId(topDeptId);
                    param.setCampusId(dto.getCampusId());
                    param.setSectionId(dto.getSectionId());
                    param.setGradeId(dto.getGradeId());
                    param.setClassId(dto.getClassId());
                    param.setStuName(dto.getNameOrNumber());
                    param.setIsQueryParent(false);
                    param.setIsQuerySchoolName(false);
                    studentList = remoteStudentService.listStudent(param).getData();
                }
            }
            if (CollUtil.isNotEmpty(studentList)) {
                studentMap = studentList.stream().collect(Collectors.groupingBy(EduStudent::getId));
                userIdList = studentList.stream().map(EduStudent::getId)
                    .collect(Collectors.toList());
            } else {
                return new Page<>();
            }
        }
        dto.setUserIdList(userIdList);
        //分页查询出人员
        IPage<AttdanceResultDetailVO> attdanceResultDetailVOIPage = baseMapper.listUserPage(dto.toPage(), dto);

        if (CollUtil.isEmpty(attdanceResultDetailVOIPage.getRecords())) {
            return new Page<>();
        }
        AttendanceCountPageDTO newParam = new AttendanceCountPageDTO();
        newParam.setStatus(dto.getStatus());
        newParam.setRuleId(dto.getRuleId());
        newParam.setUserIdList(attdanceResultDetailVOIPage.getRecords().stream().map(AttdanceResultDetailVO::getUserId).collect(
            Collectors.toList()));
        newParam.setStartDate(dto.getStartDate());
        newParam.setEndDate(dto.getEndDate());

        List<AttdanceResultDetailVO> attdanceResultDetailVOS = baseMapper.listResultDetailPage(newParam);

        for (AttdanceResultDetailVO attdanceResultDetailVO : attdanceResultDetailVOS) {
            AttendanceRuleVO rule = attendanceRuleService.getRule(attdanceResultDetailVO.getRuleId());
            AttendanceRuleTime ruleTime = attendanceRuleTimeService.getById(attdanceResultDetailVO.getRuleTimeId());
            attdanceResultDetailVO.setRuleName(ObjectUtil.isNull(rule) ? "未知规则" : rule.getName());
            attdanceResultDetailVO.setModelType(ObjectUtil.isNull(rule) ? 0 : rule.getType());
            attdanceResultDetailVO
                .setRuleTimeName(ObjectUtil.isNull(ruleTime) ? "未知时段" : (ruleTime.getStartTime() + "-" + ruleTime.getEndTime()));
            if (ObjectUtil.equals(dto.getType(), AttendanceUserTypeEnum.STAFF.getValue())) {
                //教职工
                List<EduStaff> staffList = staffMap.get(attdanceResultDetailVO.getUserId());
                attdanceResultDetailVO.setName(staffList.get(0).getName());
                attdanceResultDetailVO.setNumber(staffList.get(0).getMobile());
                List<EduStaffDept> staffDept = commonService.getStaffById(attdanceResultDetailVO.getUserId()).getStaffDept();
                attdanceResultDetailVO
                    .setDeptName(
                        CollUtil.isEmpty(staffDept) ? commonService.getStaffById(attdanceResultDetailVO.getUserId())
                            .getSchoolName()
                            : staffDept.get(0).getDeptName());
            } else {
                //学生
                attdanceResultDetailVO.setName(studentMap.get(attdanceResultDetailVO.getUserId()).get(0).getStuName());
                attdanceResultDetailVO.setNumber(studentMap.get(attdanceResultDetailVO.getUserId()).get(0).getStuNumber());
                attdanceResultDetailVO
                    .setDeptName(studentMap.get(attdanceResultDetailVO.getUserId()).get(0).getGradeName() + "-" + studentMap
                        .get(attdanceResultDetailVO.getUserId()).get(0).getClassName());
            }

            //判断是否考勤
            List<AttendanceRuleSpecialDate> specialDateList = attendanceRuleSpecialDateService
                .list(Wrappers.lambdaQuery(new AttendanceRuleSpecialDate())
                    .eq(AttendanceRuleSpecialDate::getRuleId, attdanceResultDetailVO.getRuleId()));

            if (rule.getWeek().contains(LocalDate.now().getDayOfWeek().getValue() + "")) {
                //在打卡时间段内，1判断是否含有特殊日期，2判断是否请假
                if (CollUtil.isNotEmpty(specialDateList)) {
                    List<AttendanceRuleSpecialDate> noNeedSpDateList = specialDateList.stream()
                        .filter(date -> date.getType().equals(0))
                        .collect(Collectors.toList());

                    if (CollUtil.isNotEmpty(noNeedSpDateList)) {
                        attdanceResultDetailVO.setNeedAttendance(0);
                    } else {
                        //判断请假
                        ListUserRequestDTO requestDTO = new ListUserRequestDTO();
                        requestDTO.setRequestType(dto.getType());
                        requestDTO.setUserIdList(Arrays.asList(attdanceResultDetailVO.getUserId()));
                        requestDTO.setStartTime(attdanceResultDetailVO.getAttendanceDate().atTime(ruleTime.getStartTime()));
                        requestDTO.setEndTime(attdanceResultDetailVO.getAttendanceDate().atTime(ruleTime.getEndTime()));
                        List<EduLeaveRequestUserVO> eduLeaveRequestUserVOList = remoteLeaveRequestService.findList(requestDTO)
                            .getData();
                        if (CollUtil.isNotEmpty(eduLeaveRequestUserVOList)) {
                            attdanceResultDetailVO.setNeedAttendance(1);
                        } else {
                            attdanceResultDetailVO.setNeedAttendance(0);
                        }
                    }
                } else {
                    attdanceResultDetailVO.setNeedAttendance(0);
                }
            } else {
                //未在打卡时间段内，判断是否又特殊日期需要打卡
                if (CollUtil.isNotEmpty(specialDateList)) {
                    List<AttendanceRuleSpecialDate> needSpDateList = specialDateList.stream()
                        .filter(date -> date.getType().equals(1))
                        .collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(needSpDateList)) {
                        attdanceResultDetailVO.setNeedAttendance(0);
                    } else {
                        attdanceResultDetailVO.setNeedAttendance(1);
                    }
                } else {
                    attdanceResultDetailVO.setNeedAttendance(1);
                }
            }
        }
        attdanceResultDetailVOIPage.setRecords(attdanceResultDetailVOS);
        return attdanceResultDetailVOIPage;
    }

    @Override
    public List<DateStatusVO> getUserAttendanceStatusByMonth(AttendanceStatusByMonthDTO dto) {
        List<DateStatusVO> dateStatusVOList = new ArrayList<>();
        if (redisService.hasKey(
            CachePrefixConstant.ATTENDANCE_DATE_STATUS + dto.getUserType() + dto.getUserId() + dto.getAttendanceStartDate() + dto
                .getAttendanceEndDate())) {
            String s = (String) redisService.get(
                CachePrefixConstant.ATTENDANCE_DATE_STATUS + dto.getUserType() + dto.getUserId() + dto.getAttendanceStartDate()
                    + dto
                    .getAttendanceEndDate());
            dateStatusVOList = JSON.parseArray(s, DateStatusVO.class);
        } else {
            dateStatusVOList = initStatusByDate(Collections.singletonList(dto.getUserId()), dto.getUserType(),
                dto.getAttendanceStartDate(),
                dto.getAttendanceEndDate());
            if (CollUtil.isNotEmpty(dateStatusVOList)) {
                redisService.set(
                    CachePrefixConstant.ATTENDANCE_DATE_STATUS + dto.getUserType() + dto.getUserId() + dto
                        .getAttendanceStartDate()
                        + dto
                        .getAttendanceEndDate(), JSONObject.toJSON(dateStatusVOList).toString(), 300L);
            }
        }

        return dateStatusVOList;
    }

    @Override
    public List<UserAttendanceResultByDayVO> getUserAttendanceResultByDay(AttendanceResultByDayDTO attendanceResultByDayDTO) {

        List<UserAttendanceResultByDayVO> attendanceResultByDayVOList = new ArrayList<>();
        //1:查询用户对应考勤规则
        List<AttendanceRuleVO> ruleVOList = attendanceRuleService
            .findByUserIdAndUserType(attendanceResultByDayDTO.getUserId(), attendanceResultByDayDTO.getUserType());
        for (AttendanceRuleVO attendanceRuleVO : ruleVOList) {
            //查询考勤结果
            UserAttendanceResultByDayVO attendanceResultByDayVO = new UserAttendanceResultByDayVO();
            attendanceResultByDayVO.setRule(attendanceRuleVO);

            List<AttendanceResult> resultList = list(Wrappers.lambdaQuery(new AttendanceResult())
                .eq(AttendanceResult::getAttendanceDate, attendanceResultByDayDTO.getAttendanceDate())
                .eq(AttendanceResult::getRuleId, attendanceRuleVO.getId())
                .eq(AttendanceResult::getUserId, attendanceResultByDayDTO.getUserId()));

            for (AttendanceResult result : resultList) {
                if (ObjectUtil.isNull(result.getStartStatus())) {
                    ListUserRequestDTO requestDTO = new ListUserRequestDTO();
                    requestDTO.setRequestType(attendanceResultByDayDTO.getUserType());
                    requestDTO.setUserIdList(Collections.singletonList(result.getUserId()));
                    requestDTO.setStartTime(attendanceResultByDayDTO.getAttendanceDate().atTime(result.getStartStiTime()));
                    requestDTO.setEndTime(attendanceResultByDayDTO.getAttendanceDate().atTime(result.getEndStiTime()));
                    List<EduLeaveRequestUserVO> requestUserVOList = remoteLeaveRequestService.findList(requestDTO).getData();
                    if (CollUtil.isNotEmpty(requestUserVOList)) {
                        result.setStartStatus(6);
                    }
                }
            }

            attendanceResultByDayVO.setResult(resultList);
            //计算累计时长
            Long seconds = new Long(0L);
            for (AttendanceResult result : resultList) {
                if (ObjectUtil.isNotNull(result.getStartRealTime()) && ObjectUtil.isNotNull(result.getEndRealTime())) {
                    seconds += Duration.between(result.getStartRealTime(), result.getEndRealTime()).getSeconds();
                }
            }
            attendanceResultByDayVO.setAttendanceTime(seconds / 60);
            attendanceResultByDayVOList.add(attendanceResultByDayVO);
        }
        return attendanceResultByDayVOList;
    }

    @Override
    public UserAttendanceResultByTimeSlotVO getUserAttendanceResultByTimeSlot(AttendanceResultByStartAndEndTimeDTO dto) {

        List<AttendanceResult> resultList = list(Wrappers.lambdaQuery(new AttendanceResult())
            .eq(AttendanceResult::getUserId, dto.getUserId())
            .eq(AttendanceResult::getUserType, dto.getUserType())
            .between(AttendanceResult::getAttendanceDate, dto.getAttendanceStartDate(), dto.getAttendanceEndDate()));

        Map<LocalDate, List<AttendanceResult>> totalMap = resultList.stream()
            .collect(Collectors.groupingBy(AttendanceResult::getAttendanceDate));
        //总天数
        Integer totalDays = totalMap.size();
        //异常天数
        AtomicReference<Integer> abNormalDays = new AtomicReference<>(0);
        //正常天数
        AtomicReference<Integer> normalDays = new AtomicReference<>(0);
        //迟到次数
        AtomicReference<Integer> lateTimes = new AtomicReference<>(0);
        //早退次数
        AtomicReference<Integer> leaveTimes = new AtomicReference<>(0);
        //缺卡次数
        AtomicReference<Integer> missTimes = new AtomicReference<>(0);

        List<UserAttendanceResultDayAndNumVO> lateList = new ArrayList<>();

        List<UserAttendanceResultDayAndNumVO> leaveList = new ArrayList<>();

        List<UserAttendanceResultDayAndNumVO> missList = new ArrayList<>();

        totalMap.forEach((k, v) -> {

            //按考勤规则
            Map<Long, List<AttendanceResult>> collect = v.stream().collect(Collectors.groupingBy(AttendanceResult::getRuleId));

            collect.forEach((r, n) -> {
                //判断规则类型
                AttendanceRuleVO ruleVO = (AttendanceRuleVO) redisService
                    .hget(CachePrefixConstant.ATTENDANCE_RULE_DATA, String.valueOf(r));
                if (ObjectUtil.isNull(ruleVO)) {
                    ruleVO = attendanceRuleService.getRule(r);
                    if (ObjectUtil.isNotNull(ruleVO)) {
                        redisService.hset(CachePrefixConstant.ATTENDANCE_RULE_DATA, String.valueOf(r), ruleVO);
                    }
                }
                if (ObjectUtil.equals(AttendanceModeTypeEnum.FREE.getValue(), ruleVO.getType())) {
                    //自由打卡
                    UserAttendanceResultDayAndNumVO missVO = new UserAttendanceResultDayAndNumVO();
                    //当日上班缺卡
                    List<AttendanceResult> startMissList = v.stream().filter(
                        s -> s.getStartStatus() == null).collect(
                        Collectors.toList());

                    if (startMissList.size() > 0) {
                        abNormalDays.getAndSet(abNormalDays.get() + 1);
                    } else {
                        normalDays.getAndSet(normalDays.get() + 1);
                    }
                    int missNum = 0;
                    if (startMissList.size() > 0) {
                        missTimes.getAndSet(missTimes.get() + startMissList.size());
                        missVO.setAttendanceDate(k);
                        missNum += startMissList.size();
                    }
                    missVO.setNum(missNum);
                    if (ObjectUtil.isNotNull(missVO)) {
                        missList.add(missVO);
                    }
                } else {
                    UserAttendanceResultDayAndNumVO lateVO = new UserAttendanceResultDayAndNumVO();
                    UserAttendanceResultDayAndNumVO leaveVO = new UserAttendanceResultDayAndNumVO();
                    UserAttendanceResultDayAndNumVO missVO = new UserAttendanceResultDayAndNumVO();
                    //当日迟到
                    List<AttendanceResult> currentLateList = v.stream().filter(
                        s -> ObjectUtil.equals(AttendanceResultEnum.ABNORMAL.getValue(), s.getStartStatus())).collect(
                        Collectors.toList());
                    //当日早退
                    List<AttendanceResult> currentLeaveList = v.stream().filter(
                        s -> ObjectUtil.equals(AttendanceResultEnum.ABNORMAL.getValue(), s.getEndStatus())).collect(
                        Collectors.toList());
                    //当日上班缺卡
                    List<AttendanceResult> startMissList = v.stream().filter(
                        s -> s.getStartStatus() == null).collect(
                        Collectors.toList());
                    //当日下班缺卡
                    List<AttendanceResult> endMissList = v.stream().filter(
                        s -> s.getEndStatus() == null).collect(
                        Collectors.toList());

                    if (currentLateList.size() > 0 || currentLeaveList.size() > 0 || startMissList.size() > 0
                        || endMissList.size() > 0) {
                        abNormalDays.getAndSet(abNormalDays.get() + 1);
                    } else {
                        normalDays.getAndSet(normalDays.get() + 1);
                    }

                    if (currentLateList.size() > 0) {
                        lateTimes.getAndSet(lateTimes.get() + currentLateList.size());
                        lateVO.setAttendanceDate(k);
                        lateVO.setNum(currentLateList.size());
                        lateList.add(lateVO);
                    }
                    if (currentLeaveList.size() > 0) {
                        leaveTimes.getAndSet(leaveTimes.get() + currentLeaveList.size());
                        leaveVO.setAttendanceDate(k);
                        leaveVO.setNum(currentLeaveList.size());
                        leaveList.add(leaveVO);
                    }
                    int missNum = 0;
                    if (startMissList.size() > 0) {
                        missTimes.getAndSet(missTimes.get() + startMissList.size());
                        missVO.setAttendanceDate(k);
                        missNum += startMissList.size();
                    }
                    if (endMissList.size() > 0) {
                        missTimes.getAndSet(missTimes.get() + endMissList.size());
                        missVO.setAttendanceDate(k);
                        missNum += endMissList.size();
                    }
                    missVO.setNum(missNum);
                    if (ObjectUtil.isNotNull(missVO)) {
                        missList.add(missVO);
                    }
                }
            });
        });

        //请假
        ListUserRequestDTO requestDTO = new ListUserRequestDTO();
        requestDTO.setRequestType(dto.getUserType());
        requestDTO.setUserIdList(Collections.singletonList(dto.getUserId()));
        requestDTO.setStartTime(dto.getAttendanceStartDate().atTime(LocalTime.of(00, 00, 01)));
        requestDTO.setEndTime(dto.getAttendanceEndDate().atTime(LocalTime.of(23, 59, 59)));
        List<EduLeaveRequestUserVO> data = remoteLeaveRequestService.findList(requestDTO).getData();

        return UserAttendanceResultByTimeSlotVO.builder().totalDays(totalDays)
            .normalDays(normalDays.get())
            .abNormalDays(abNormalDays.get())
            .lateList(lateList).leaveList(leaveList).missList(missList).lateTimes(lateTimes.get()).leaveTimes(leaveTimes.get())
            .missTimes(missTimes.get()).requestTimes(data.size()).build();
    }

    @Override
    public List<DateStatusVO> findTotalUserStatus(ManageListUserDTO dto) {
        if (redisService.hasKey(
            CachePrefixConstant.ATTENDANCE_MANAGE_DATE_STATUS + dto.getSearchUserType() + dto.getUserId() + dto
                .getAttendanceStartDate() + dto
                .getAttendanceEndDate())) {
            String s = (String) redisService.get(
                CachePrefixConstant.ATTENDANCE_MANAGE_DATE_STATUS + dto.getSearchUserType() + dto.getUserId() + dto
                    .getAttendanceStartDate()
                    + dto
                    .getAttendanceEndDate());
            List<DateStatusVO> dateStatusVOList = JSON.parseArray(s, DateStatusVO.class);

            return dateStatusVOList;
        }

        //查询管理人员
        AttendanceRuleAdmin param = new AttendanceRuleAdmin();
        param.setUserType(dto.getSearchUserType());
        param.setStaffId(dto.getUserId());
        List<AttendanceRuleAdmin> adminList = attendanceRuleAdminService.findList(param);

        if (CollUtil.isEmpty(adminList)) {
            log.info("【】职工无管理人员", dto.getUserId());
            return new ArrayList<>();
        }
        //排除未启用规则
        List<Long> deptIdList = new ArrayList<>();
        for (AttendanceRuleAdmin admin : adminList) {
            AttendanceRule attendanceRule = attendanceRuleService.getById(admin.getRuleId());
            if (ObjectUtil.equals(EnableStatusEnum.ENABLE_STATUS.getStatus(), attendanceRule.getStatus())) {
                deptIdList.add(admin.getDeptId());
            }
        }
        if (CollUtil.isEmpty(deptIdList)) {
            log.info("【】职工无管理人员", dto.getUserId());
            return new ArrayList<>();
        }
        //查询部门下的人员
        List<Long> userIdList = initUserIdList(adminList, dto.getSearchUserType());

        List<DateStatusVO> dateStatusVOList = initStatusByDate(userIdList, dto.getSearchUserType(), dto.getAttendanceStartDate(),
            dto.getAttendanceEndDate());

        if (CollUtil.isNotEmpty(dateStatusVOList)) {
            redisService.set(
                CachePrefixConstant.ATTENDANCE_MANAGE_DATE_STATUS + dto.getSearchUserType() + dto.getUserId() + dto
                    .getAttendanceStartDate()
                    + dto
                    .getAttendanceEndDate(), JSONObject.toJSON(dateStatusVOList).toString());
        }

        return dateStatusVOList;
    }

    @Override
    public List<ManageListUserVO> findManageListUserVO(ManageListUserDTO dto) {
        List<ManageListUserVO> returnList = new ArrayList<>();
        //查询用户管理部门
        AttendanceRuleAdmin param = new AttendanceRuleAdmin();
        param.setUserType(dto.getSearchUserType());
        param.setStaffId(dto.getUserId());
        List<AttendanceRuleAdmin> adminList = attendanceRuleAdminService.findList(param);

        Map<Long, List<AttendanceRuleAdmin>> adminMap = adminList.stream()
            .collect(Collectors.groupingBy(AttendanceRuleAdmin::getDeptId));
        adminMap.forEach((k, v) -> {
            ManageListUserVO manageListUserVO = new ManageListUserVO();
            if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), dto.getSearchUserType())) {
                //部门信息
                if (k > 0) {
                    EduUserDept userDept = commonService.getUserDept(k);
                    if (ObjectUtil.isNotNull(userDept)) {
                        manageListUserVO.setDeptName(userDept.getDeptName());
                        manageListUserVO.setDeptType(userDept.getDeptType());
                        manageListUserVO.setDeptId(userDept.getDeptId());
                    }
                } else {
                    //学校部门
                    Dept dept = commonService.getDept(-k);
                    if (ObjectUtil.isNotNull(dept)) {
                        manageListUserVO.setDeptName(dept.getDeptName());
                        manageListUserVO.setDeptId(dept.getDeptId());
                    }
                }

            } else {
                //部门信息
                Dept dept = commonService.getDept(k);
                if (ObjectUtil.isNotNull(dept)) {
                    manageListUserVO.setDeptName(dept.getDeptName());
                    manageListUserVO.setDeptId(dept.getDeptId());
                }
            }
            List<Long> userIdList = new ArrayList<>();
            //正常数据
            Map<Long, List<AttendanceResult>> normalMap = new HashMap<>();
            Map<Long, List<AttendanceResult>> abNormalMap = new HashMap<>();
            Map<Long, List<AttendanceResult>> lateMap = new HashMap<>();
            Map<Long, List<AttendanceResult>> leaveMap = new HashMap<>();
            Map<Long, List<AttendanceResult>> missMap = new HashMap<>();

            for (AttendanceRuleAdmin admin : v) {
                AttendanceRule attendanceRule = attendanceRuleService.getById(admin.getRuleId());
                if (ObjectUtil.equals(EnableStatusEnum.NOT_ENABLE_STATUS.getStatus(), attendanceRule.getStatus())) {
                    continue;
                }
                List<AttendanceRuleTime> timeList = attendanceRuleTimeService.list(Wrappers.lambdaQuery(new AttendanceRuleTime())
                    .eq(AttendanceRuleTime::getRuleId, attendanceRule.getId()));

                if (CollUtil.isEmpty(timeList)) {
                    continue;
                }
                userIdList.addAll(initUserIdList(Arrays.asList(admin), dto.getSearchUserType()));

                if (CollUtil.isNotEmpty(userIdList)) {
                    List<AttendanceResult> studentResultList = list(Wrappers.lambdaQuery(new AttendanceResult())
                        .eq(AttendanceResult::getRuleId, admin.getRuleId())
                        .between(AttendanceResult::getAttendanceDate, dto.getAttendanceStartDate(), dto.getAttendanceEndDate())
                        .eq(AttendanceResult::getUserType, dto.getSearchUserType())
                        .in(AttendanceResult::getUserId, userIdList));
                    //正常数据
                    normalMap.putAll(studentResultList.stream().filter(
                        attendanceResult -> ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), attendanceRule.getType()) ? (
                            ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), attendanceResult.getStartStatus())
                                && ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), attendanceResult.getEndStatus()))
                            : ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), attendanceResult.getStartStatus()))
                        .collect(Collectors.groupingBy(AttendanceResult::getUserId)));

                    //异常数据
                    abNormalMap.putAll(studentResultList.stream().filter(
                        attendanceResult -> ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), attendanceRule.getType())
                            ? (!(ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), attendanceResult.getStartStatus())
                            && ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), attendanceResult.getEndStatus())))
                            : !ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), attendanceResult.getStartStatus()))
                        .collect(Collectors.groupingBy(AttendanceResult::getUserId)));

                    //迟到数据
                    lateMap.putAll(studentResultList.stream().filter(
                        attendanceResult -> ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), attendanceRule.getType())
                            && ObjectUtil.equals(AttendanceResultEnum.ABNORMAL.getValue(), attendanceResult.getStartStatus()))
                        .collect(Collectors.groupingBy(AttendanceResult::getUserId)));

                    //早退数据
                    leaveMap.putAll(studentResultList.stream().filter(
                        attendanceResult -> ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), attendanceRule.getType())
                            && ObjectUtil.equals(AttendanceResultEnum.ABNORMAL.getValue(), attendanceResult.getEndStatus()))
                        .collect(Collectors.groupingBy(AttendanceResult::getUserId)));

                    //缺卡数据
                    missMap.putAll(studentResultList.stream().filter(
                        attendanceResult -> ObjectUtil.equals(AttendanceModeTypeEnum.FREE.getValue(), attendanceRule.getType())
                            ? ObjectUtil.equals(null, attendanceResult.getStartStatus())
                            : (ObjectUtil.equals(null, attendanceResult.getStartStatus()) || ObjectUtil
                                .equals(null, attendanceResult.getEndStatus())))
                        .collect(Collectors.groupingBy(AttendanceResult::getUserId)));

                }
                manageListUserVO.setTotalNum(userIdList.stream().distinct().collect(Collectors.toList()).size());
                manageListUserVO.setNormalNum(normalMap.size());

                manageListUserVO.setLateUserNum(lateMap.size());
                manageListUserVO.setLeaveUserNum(leaveMap.size());

                //TODO 请假人数
                ListUserRequestDTO requestDTO = new ListUserRequestDTO();
                requestDTO.setRequestType(dto.getSearchUserType());
                requestDTO.setUserIdList(userIdList);
                requestDTO.setStartTime(dto.getAttendanceStartDate().atTime(timeList.get(0).getStartTime()));
                requestDTO.setEndTime(dto.getAttendanceEndDate().atTime(timeList.get(0).getEndEffectiveEndTime()));
                List<EduLeaveRequestUserVO> leaveRequestUserVOList = remoteLeaveRequestService.findList(requestDTO).getData();
                manageListUserVO.setRequestUserNum(
                    leaveRequestUserVOList.stream().collect(Collectors.groupingBy(EduLeaveRequestUserVO::getUserId)).size());

                if (leaveRequestUserVOList.size() >= missMap.size()) {
                    manageListUserVO.setMissUserNum(0);
                } else {
                    manageListUserVO.setMissUserNum(missMap.size() - leaveRequestUserVOList.size());
                }
                if (leaveRequestUserVOList.size() >= abNormalMap.size()) {
                    manageListUserVO.setAbNormalNum(0);
                } else {
                    manageListUserVO.setAbNormalNum(abNormalMap.size() - leaveRequestUserVOList.size());
                }

            }
            returnList.add(manageListUserVO);
        });

        return returnList;
    }

    @Override
    public cn.hutool.json.JSONObject findManageListUserDetailVO(ManageListUserDTO dto) {
        //管理人员
        List<Long> userIdList = new ArrayList<>();
        if (ObjectUtil.isNull(dto.getDeptId())) {
            AttendanceRuleAdmin param = new AttendanceRuleAdmin();
            param.setUserType(dto.getSearchUserType());
            param.setStaffId(dto.getUserId());
            List<AttendanceRuleAdmin> adminList = attendanceRuleAdminService.findList(param);

            if (ObjectUtil.isNotNull(dto.getRuleId())) {
                adminList = adminList.stream()
                    .filter(attendanceRuleAdmin -> attendanceRuleAdmin.getRuleId().equals(dto.getRuleId()))
                    .collect(Collectors.toList());
            }
            userIdList = initUserIdList(adminList, dto.getSearchUserType());
        } else {
            if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), dto.getSearchUserType())) {
                //按照家校部门查询
                List<EduStudent> eduStudentList = new ArrayList<>();
                ListStudentDTO listStudentDTO = new ListStudentDTO();
                listStudentDTO.setIsQueryUserDept(false);
                listStudentDTO.setIsQueryParent(false);
                listStudentDTO.setIsQuerySchoolName(false);
                //部门学校
                if (ObjectUtil.equals(UserDeptTypeEnum.CLASS_TYPE.getValue(), dto.getDeptType())) {
                    listStudentDTO.setClassId(dto.getDeptId());
                } else if (ObjectUtil.equals(UserDeptTypeEnum.GRADE_TYPE.getValue(), dto.getDeptType())) {
                    listStudentDTO.setGradeId(dto.getDeptId());
                } else if (ObjectUtil.equals(UserDeptTypeEnum.SECTION_TYPE.getValue(), dto.getDeptType())) {
                    listStudentDTO.setSectionId(dto.getDeptId());
                } else if (ObjectUtil.equals(UserDeptTypeEnum.CAMPUS_TYPE.getValue(), dto.getDeptType())) {
                    listStudentDTO.setCampusId(dto.getDeptId());
                } else {
                    listStudentDTO.setSchoolId(dto.getDeptId());
                }
                eduStudentList = remoteStudentService.listStudent(listStudentDTO).getData();
                userIdList = eduStudentList.stream().map(EduStudent::getId).collect(Collectors.toList());
            } else {
                //职工
                userIdList = remoteStaffService.listStaffByDeptId(dto.getDeptId(), null, null).getData();
            }
        }

        if (CollUtil.isEmpty(userIdList)) {
            return null;
        }
        dto.setUserIdList(userIdList);

        IPage<ManageListUserAttendanceDetailVO> manageListUserDetailVO = baseMapper.findManageListUserDetailVO(dto.toPage(), dto);
        List<ManageListUserAttendanceDetailVO> records = manageListUserDetailVO.getRecords();
        List<AttendanceRuleTime> timeList = new ArrayList<>();
        for (ManageListUserAttendanceDetailVO record : records) {
            if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), dto.getSearchUserType())) {
                EduStudent student = commonService.getStudentById(record.getUserId());
                if (ObjectUtil.isNotNull(student)) {
                    record.setUserName(student.getStuName());
                    record.setStudentType(student.getType());
                    record.setAvatar(student.getAvatar());
                    record.setDeptName(student.getCampusName() + "/" + student.getSectionName() + "/" + student.getClassName());
                    record.setDormName(
                        ObjectUtil.isNotNull(student.getDormName()) && ObjectUtil.isNotNull(student.getDormRoomName()) ?
                            (student.getDormName() + "/" + student.getDormRoomName()) : null);
                }
            } else {
                EduStaff staff = commonService.getStaffById(record.getUserId());
                if (ObjectUtil.isNotNull(staff)) {
                    record.setUserName(staff.getName());
                    record.setDeptName(staff.getStaffDept().get(0).getDeptName());
                    record.setAvatar(staff.getAvatar());
                }
            }
            record.setUserType(dto.getSearchUserType());

            //默认1个时间段
            timeList = attendanceRuleTimeService.list(Wrappers.lambdaQuery(new AttendanceRuleTime())
                .eq(AttendanceRuleTime::getRuleId, record.getRuleId()));

            //判断请假
            if (record.getMissNum() > 0) {
                ListUserRequestDTO requestDTO = new ListUserRequestDTO();
                requestDTO.setRequestType(record.getUserType());
                requestDTO.setUserIdList(Arrays.asList(record.getUserId()));
                requestDTO.setStartTime(dto.getAttendanceStartDate().atTime(timeList.get(0).getStartTime()));
                requestDTO.setEndTime(dto.getAttendanceEndDate().atTime(timeList.get(0).getEndEffectiveEndTime()));
                List<EduLeaveRequestUserVO> requestUserVOList = remoteLeaveRequestService.findList(requestDTO).getData();
                if (CollUtil.isNotEmpty(requestUserVOList)) {
                    record.setMissNum(0);
                    record.setRequestNum(1);
                }
            }
        }
        cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(manageListUserDetailVO);
        //查询异常总数
        //请假总人数
        ListUserRequestDTO requestDTO = new ListUserRequestDTO();
        requestDTO.setRequestType(dto.getSearchUserType());
        requestDTO.setUserIdList(userIdList);
        requestDTO.setStartTime(dto.getAttendanceStartDate().atTime(timeList.get(0).getStartTime()));
        requestDTO.setEndTime(dto.getAttendanceEndDate().atTime(timeList.get(0).getEndEffectiveEndTime()));
        List<EduLeaveRequestUserVO> requestUserVOList = remoteLeaveRequestService.findList(requestDTO).getData();
        int requestNum = requestUserVOList.stream().collect(Collectors.groupingBy(EduLeaveRequestUserVO::getUserId)).size();

        jsonObject.set("errorNum", baseMapper.findManageListUserDetailVOErrorNum(dto) - requestNum);
        return jsonObject;
    }

    @Override
    public ManageListUserAttendanceDetailTotalVO findManageListUserDetailTotalVO(ManageListUserDTO dto) {
        ManageListUserAttendanceDetailTotalVO vo = new ManageListUserAttendanceDetailTotalVO();
        List<Long> userIdList = new ArrayList<>();
        if (ObjectUtil.isNull(dto.getDeptId())) {
            AttendanceRuleAdmin param = new AttendanceRuleAdmin();
            param.setUserType(dto.getSearchUserType());
            param.setStaffId(dto.getUserId());
            List<AttendanceRuleAdmin> adminList = attendanceRuleAdminService.findList(param);
            if (ObjectUtil.isNotNull(dto.getRuleId())) {
                adminList = adminList.stream()
                    .filter(attendanceRuleAdmin -> attendanceRuleAdmin.getRuleId().equals(dto.getRuleId()))
                    .collect(Collectors.toList());
            }
            userIdList = initUserIdList(adminList, dto.getSearchUserType());
        } else {
            if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), dto.getSearchUserType())) {
                //按照家校部门查询
                List<EduStudent> eduStudentList = new ArrayList<>();
                ListStudentDTO listStudentDTO = new ListStudentDTO();
                listStudentDTO.setIsQueryUserDept(false);
                listStudentDTO.setIsQueryParent(false);
                listStudentDTO.setIsQuerySchoolName(false);
                //部门学校
                if (ObjectUtil.equals(UserDeptTypeEnum.CLASS_TYPE.getValue(), dto.getDeptType())) {
                    listStudentDTO.setClassId(dto.getDeptId());
                } else if (ObjectUtil.equals(UserDeptTypeEnum.GRADE_TYPE.getValue(), dto.getDeptType())) {
                    listStudentDTO.setGradeId(dto.getDeptId());
                } else if (ObjectUtil.equals(UserDeptTypeEnum.SECTION_TYPE.getValue(), dto.getDeptType())) {
                    listStudentDTO.setSectionId(dto.getDeptId());
                } else if (ObjectUtil.equals(UserDeptTypeEnum.CAMPUS_TYPE.getValue(), dto.getDeptType())) {
                    listStudentDTO.setCampusId(dto.getDeptId());
                } else {
                    listStudentDTO.setSchoolId(dto.getDeptId());
                }
                eduStudentList = remoteStudentService.listStudent(listStudentDTO).getData();
                userIdList = eduStudentList.stream().map(EduStudent::getId).collect(Collectors.toList());
            } else {
                //职工
                userIdList = remoteStaffService.listStaffByDeptId(dto.getDeptId(), null, null).getData();
            }
        }
        if (CollUtil.isEmpty(userIdList)) {
            vo.setTotalNum(0);
            vo.setAbNormalNum(0);
        } else {
            vo.setTotalNum(userIdList.size());
            dto.setUserIdList(userIdList);
            dto.setAttendanceStatus(0);
            IPage<ManageListUserAttendanceDetailVO> manageListUserDetailVO = baseMapper
                .findManageListUserDetailVO(new Page(1, -1), dto);
            vo.setAbNormalNum(userIdList.size() - manageListUserDetailVO.getRecords().size());
        }
        return vo;
    }

    @Override
    public List findManageUserDeptTree(Long userId, Integer searchUserType) {

        AttendanceRuleAdmin param = new AttendanceRuleAdmin();
        param.setUserType(searchUserType);
        param.setStaffId(userId);
        List<AttendanceRuleAdmin> adminList = attendanceRuleAdminService.findList(param);
        List<Long> collect = adminList.stream().map(AttendanceRuleAdmin::getDeptId).distinct().collect(Collectors.toList());
        if (CollUtil.isEmpty(collect)) {
            return null;
        }
        if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), searchUserType)) {
            //家校部门树
            //查询用户管理部门
            return remoteUserDeptService
                .getUserDeptTree(collect).getData();
        } else {
            //职能部门树
            return remoteDeptService
                .getDeptTree(collect).getData();
        }
    }

    @Override
    public StaffIdentityVO findStaffIdentity(Long staffId) {
        StaffIdentityVO vo = new StaffIdentityVO();
        //学生管理员

        AttendanceRuleAdmin param = new AttendanceRuleAdmin();
        param.setStaffId(staffId);
        List<AttendanceRuleAdmin> adminList = attendanceRuleAdminService.findList(param);

        if (CollUtil.isEmpty(adminList)) {
            vo.setManageStudent(false);
            vo.setManageStaff(false);
        }
        //排除未启用规则
//        List<AttendanceRuleAdmin> realAdminList = new ArrayList<>();
//        for (AttendanceRuleAdmin admin : adminList) {
//            AttendanceRule attendanceRule = attendanceRuleService.getById(admin.getRuleId());
//            if (ObjectUtil.isNull(attendanceRule) || ObjectUtil
//                .equals(EnableStatusEnum.NOT_ENABLE_STATUS.getStatus(), attendanceRule.getStatus())) {
//                continue;
//            } else {
//                realAdminList.add(admin);
//            }
//        }
//        if (CollUtil.isEmpty(realAdminList)) {
//            vo.setManageStudent(false);
//            vo.setManageStaff(false);
//        }
        List<AttendanceRuleAdmin> parentAdminList = adminList.stream().filter(
            attendanceRuleAdmin -> ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), attendanceRuleAdmin.getUserType()))
            .collect(
                Collectors.toList());

        List<AttendanceRuleAdmin> staffAdminList = adminList.stream().filter(
            attendanceRuleAdmin -> ObjectUtil.equals(UserTypeEnum.STAFF_USER_TYPE.getType(), attendanceRuleAdmin.getUserType()))
            .collect(
                Collectors.toList());

        if (CollUtil.isNotEmpty(parentAdminList)) {
            vo.setManageStudent(true);
        }

        if (CollUtil.isNotEmpty(staffAdminList)) {
            vo.setManageStaff(true);
        }
        return vo;
    }


    @Override
    public void initUserAttendance() {
        log.info("开始初始化学校的考勤数据");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        //查询具有考勤规则的学校
        PageAttendanceRuleDTO dto = new PageAttendanceRuleDTO();
        dto.setStatus(EnableStatusEnum.ENABLE_STATUS.getStatus());
        List<AttendanceRuleVO> ruleVOList = attendanceRuleService.listRule(dto);

        for (AttendanceRuleVO attendanceRuleVO : ruleVOList) {
            if (LocalDate.now().isBefore(attendanceRuleVO.getStartDate()) || LocalDate.now()
                .isAfter(attendanceRuleVO.getEndDate())) {
                continue;
            }
            if (CollUtil.isEmpty(attendanceRuleVO.getTimeDTOList())) {
                continue;
            }
//            if (!attendanceRuleVO.getWeek().contains(String.valueOf(LocalDate.now().getDayOfWeek().getValue()))) {
//                continue;
//            }
            //移除学生信息
            attendanceRuleObjUserService.remove(Wrappers.lambdaQuery(new AttendanceRuleObjUser())
                .eq(AttendanceRuleObjUser::getRuleId, attendanceRuleVO.getId()));

            List<EduStudent> eduStudentList = new ArrayList<>();
            List<EduStaff> eduStaffList = new ArrayList<>();
            List<AddAttendanceRuleObjDTO> attendanceRuleObjList = attendanceRuleVO.getAttendanceRuleObjList();
            //循环处理数据
            log.info("开始处理学校：【{}】,考勤规则：【{}】的考勤数据", attendanceRuleVO.getSchoolId(), attendanceRuleVO.getName());
            if (ObjectUtil.equals(AttendanceUserTypeEnum.STAFF.getValue(), attendanceRuleVO.getUserType())) {
                //教职工打卡
                //查询规则下的教职工
                for (AddAttendanceRuleObjDTO objDTO : attendanceRuleObjList) {
                    ListStaffDTO param = new ListStaffDTO();
                    param.setDeptId(objDTO.getDeptId());
                    List<EduStaff> eduStaffs = remoteStaffService.listStaff(param).getData();
                    for (EduStaff eduStaff : eduStaffs) {
                        EduStaffDept staffDept = new EduStaffDept();
                        staffDept.setDeptId(objDTO.getDeptId());
                        eduStaff.setStaffDept(Collections.singletonList(staffDept));
                        eduStaffList.add(eduStaff);
                    }
                }
            } else {
                for (AddAttendanceRuleObjDTO attendanceRuleObj : attendanceRuleObjList) {
                    //判断班级是否存在
                    EduUserDept eduUserDept = remoteUserDeptService.getByDeptId(attendanceRuleObj.getDeptId()).getData();
                    if (ObjectUtil.isNull(eduUserDept)) {
                        attendanceRuleObjUserService.remove(Wrappers.lambdaQuery(new AttendanceRuleObjUser())
                            .eq(AttendanceRuleObjUser::getDeptId, attendanceRuleObj.getDeptId())
                            .eq(AttendanceRuleObjUser::getRuleId, attendanceRuleVO.getId()));
                        attendanceRuleObjService.removeById(attendanceRuleObj.getId());
                        continue;
                    }
                    //查询实际人员
                    ListStudentDTO listStudentDTO = new ListStudentDTO();
                    listStudentDTO.setIsQueryUserDept(false);
                    listStudentDTO.setIsQueryParent(false);
                    listStudentDTO.setIsQuerySchoolName(false);
                    listStudentDTO.setSchoolId(attendanceRuleVO.getSchoolId());
                    listStudentDTO.setClassId(attendanceRuleObj.getDeptId());
                    List<EduStudent> allEduStudentList = remoteStudentService.listStudent(listStudentDTO).getData();

                    if (ObjectUtil.equals(AttendanceUserTypeEnum.STUDENT_TO_DORM.getValue(), attendanceRuleVO.getUserType())) {
                        allEduStudentList = allEduStudentList.stream().filter(student -> ObjectUtil.equals(1, student.getType())
                            && (ObjectUtil.isNull(student.getStudentStatus()) || (ObjectUtil.isNotNull(student.getStatus())
                            && ObjectUtil
                            .equals(StudentStatusEnum.ZAIDU.getStatus(), student.getStudentStatus()))))
                            .collect(Collectors.toList());
                    }

                    eduStudentList.addAll(allEduStudentList);
//                    List<AttendanceRuleObjUser> list = attendanceRuleObjUserService
//                        .list(Wrappers.lambdaQuery(new AttendanceRuleObjUser())
//                            .eq(AttendanceRuleObjUser::getDeptId, attendanceRuleObj.getDeptId())
//                            .eq(AttendanceRuleObjUser::getRuleId, attendanceRuleVO.getId())
//                            .eq(AttendanceRuleObjUser::getUserType, UserTypeEnum.PARENT_USER_TYPE.getType())
//                        );
//                    for (AttendanceRuleObjUser user : list) {
//                        EduStudent student = remoteStudentService.getStudentNoPermission(user.getUserId()).getData();
//                        if (ObjectUtil.isNotNull(student)) {
//                            if (ObjectUtil
//                                .equals(AttendanceUserTypeEnum.STUDENT_TO_DORM.getValue(), attendanceRuleVO.getUserType())) {
//                                //宿舍考勤
//                                if (ObjectUtil.equals(1, student.getType())) {
//                                    //住宿
//                                    eduStudentList.add(student);
//                                } else {
//                                    //移除学生信息
//                                    attendanceRuleObjUserService.remove(Wrappers.lambdaQuery(new AttendanceRuleObjUser())
//                                        .eq(AttendanceRuleObjUser::getRuleId, attendanceRuleVO.getId())
//                                        .eq(AttendanceRuleObjUser::getUserId, user.getUserId()));
//                                }
//                            } else {
//                                eduStudentList.add(student);
//                            }
//                        } else {
//                            //移除学生信息
//                            attendanceRuleObjUserService.remove(Wrappers.lambdaQuery(new AttendanceRuleObjUser())
//                                .eq(AttendanceRuleObjUser::getRuleId, attendanceRuleVO.getId())
//                                .eq(AttendanceRuleObjUser::getUserId, user.getUserId()));
//                        }
//                    }
                }
            }
            List<AttendanceResult> resultList = new ArrayList<>();
            List<AttendanceRuleObjUser> objUserList = new ArrayList<>();
            if (CollUtil.isNotEmpty(eduStudentList)) {
                for (EduStudent eduStudent : eduStudentList) {
                    //增加考勤人员
                    AttendanceRuleObjUser objUser = new AttendanceRuleObjUser();
                    objUser.setUserId(eduStudent.getId());
                    objUser.setUserName(eduStudent.getStuName());
                    objUser.setUserType(UserTypeEnum.PARENT_USER_TYPE.getType());
                    objUser.setRuleId(attendanceRuleVO.getId());
                    objUser.setDeptId(eduStudent.getClassId());
                    objUserList.add(objUser);
                    //增加考勤结果记录
                    AttendanceResult result = new AttendanceResult();
                    result.setAttType(attendanceRuleVO.getType());
                    result.setUserType(ObjectUtil.equals(AttendanceUserTypeEnum.STAFF.getValue(), attendanceRuleVO.getUserType())
                        ? AttendanceUserTypeEnum.STAFF.getValue() : AttendanceUserTypeEnum.STUDENT_TO_SCHOOL.getValue());
                    result.setUserId(eduStudent.getId());
                    result.setSchoolId(eduStudent.getSchoolId());
                    result.setRuleId(attendanceRuleVO.getId());
                    for (AddAttendanceRuleTimeDTO ruleTimeDTO : attendanceRuleVO.getTimeDTOList()) {
                        //判断今日是否含有记录
                        long count = count(Wrappers.lambdaQuery(new AttendanceResult())
                            .eq(AttendanceResult::getAttendanceDate, LocalDate.now())
                            .eq(AttendanceResult::getUserId, eduStudent.getId())
                            .eq(AttendanceResult::getRuleId, attendanceRuleVO.getId())
                            .eq(AttendanceResult::getRuleTimeId, ruleTimeDTO.getId()));
                        if (count == 0) {
                            result.setRuleTimeId(ruleTimeDTO.getId());
                            result.setStartStiTime(ruleTimeDTO.getStartTime());
                            result.setEndStiTime(ruleTimeDTO.getEndTime());
                            result.setAttendanceDate(LocalDate.now());
                            resultList.add(result);
                        }
                    }
                }
            }
            if (CollUtil.isNotEmpty(eduStaffList)) {
                for (EduStaff staff : eduStaffList) {
                    AttendanceRuleObjUser objUser = new AttendanceRuleObjUser();
                    objUser.setUserId(staff.getId());
                    objUser.setUserName(staff.getName());
                    objUser.setUserType(UserTypeEnum.STAFF_USER_TYPE.getType());
                    objUser.setRuleId(attendanceRuleVO.getId());
                    objUser.setDeptId(CollUtil.isNotEmpty(staff.getStaffDept()) ? staff.getStaffDept().get(0).getDeptId() : null);
                    objUserList.add(objUser);

                    AttendanceResult result = new AttendanceResult();
                    result.setAttType(attendanceRuleVO.getType());
                    result.setUserType(ObjectUtil.equals(AttendanceUserTypeEnum.STAFF.getValue(), attendanceRuleVO.getUserType())
                        ? AttendanceUserTypeEnum.STAFF.getValue() : AttendanceUserTypeEnum.STUDENT_TO_SCHOOL.getValue());
                    result.setUserId(staff.getId());
                    result.setSchoolId(staff.getSchoolId());
                    result.setRuleId(attendanceRuleVO.getId());
                    for (AddAttendanceRuleTimeDTO ruleTimeDTO : attendanceRuleVO.getTimeDTOList()) {
                        long count = count(Wrappers.lambdaQuery(new AttendanceResult())
                            .eq(AttendanceResult::getAttendanceDate, LocalDate.now())
                            .eq(AttendanceResult::getUserId, staff.getId())
                            .eq(AttendanceResult::getRuleId, attendanceRuleVO.getId())
                            .eq(AttendanceResult::getRuleTimeId, ruleTimeDTO.getId()));
                        if (count == 0) {
                            result.setRuleTimeId(ruleTimeDTO.getId());
                            result.setStartStiTime(ruleTimeDTO.getStartTime());
                            result.setEndStiTime(ruleTimeDTO.getEndTime());
                            result.setAttendanceDate(LocalDate.now());
                            resultList.add(result);
                        }
                    }
                }
            }
            if (CollUtil.isNotEmpty(resultList) && attendanceRuleVO.getWeek()
                .contains(String.valueOf(LocalDate.now().getDayOfWeek().getValue()))) {
                //批量保存
                saveBatch(resultList);
            }
            if (CollUtil.isNotEmpty(objUserList)) {
                //批量保存
                attendanceRuleObjUserService.saveBatch(objUserList);
            }
        }
        stopWatch.stop();
        log.info("每日初始化考勤总共耗时: {}", stopWatch.getTotalTimeSeconds() + "秒");
    }

    @Override
    public void initAttendanceReport(Long schoolId, LocalDate currentDate) {
        //查询学校
        log.info("开始统计学生考勤数据");
        List<Dept> schoolList = new ArrayList<>();
        if (Objects.isNull(schoolId)) {
            // 查询所有绑定了企业微信的学校信息
            schoolList = remoteDeptService.listSchoolBySchoolType(Dept.TYPE_QYWX).getData();
        } else {
            Dept school = remoteDeptService.getInfoByIdNoPermission(schoolId).getData();
            schoolList.add(school);
        }

        if (CollUtil.isNotEmpty(schoolList)) {
            schoolList.forEach(school -> {
                //判断学校是否包含宿舍考勤
                List<AttendanceRule> ruleList = attendanceRuleService.list(Wrappers.lambdaQuery(new AttendanceRule())
                    .eq(AttendanceRule::getSchoolId, school.getDeptId())
                    .eq(AttendanceRule::getUserType, AttendanceUserTypeEnum.STUDENT_TO_DORM.getValue()));
                if (CollUtil.isNotEmpty(ruleList)) {
                    log.info("开始统计学校{}的学生考勤数据", school.getDeptName());
                }
            });
        }

        //每日
        LocalDate now = LocalDate.now();
        AttendanceCountPageDTO dto = new AttendanceCountPageDTO();
        dto.setStartDate(now);
        dto.setEndDate(now);
        IPage<AttdanceResultVO> attdanceResultVOIPage = baseMapper.listResultPage(new Page(1, -1), dto);

    }

    @Override
    public void lateReport(Integer mode, Integer userType, Long ruleId, Long ruleTimeId, List<Long> staffIds, Integer isManager) {
//        mode 0=推动至教职工，1=推送至学生家长
        AttendanceRule rule = attendanceRuleService.getById(ruleId);
        if (ObjectUtil.isNull(rule) || !ObjectUtil.equals(EnableStatusEnum.ENABLE_STATUS.getStatus(), rule.getStatus())) {
            log.info("【{}】规则已停用，不推送迟到报告", rule.getName());
            return;
        }
        if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), userType)) {
            //今日还未打卡的全部学生
            List<AttendanceResult> resultList = list(Wrappers.lambdaQuery(new AttendanceResult())
                .eq(AttendanceResult::getRuleId, ruleId)
                .eq(AttendanceResult::getRuleTimeId, ruleTimeId)
                .eq(AttendanceResult::getAttendanceDate, LocalDate.now())
                .isNull(AttendanceResult::getStartStatus));
            //学生
            if (mode == 1) {
                //发送学生家长
                for (AttendanceResult result : resultList) {
                    //逐个推送至学生家长
                }
            } else {
                //发送教职工 ，汇总推送给管理员
                //自定义需要发送的职工
                long lateMinute = Duration.between(resultList.get(0).getEndStiTime(), LocalTime.now()).toMinutes();
                if (CollUtil.isNotEmpty(staffIds)) {
                    for (Long staffId : staffIds) {
                        noticeService.sendStudentAttendanceLateReportToStaff(resultList, staffId, rule, lateMinute);
                    }
                }
                //发送管理员
                if (ObjectUtil.equals(1, isManager)) {
                    AttendanceRuleAdmin admin = new AttendanceRuleAdmin();
                    admin.setRuleId(ruleId);
                    List<AttendanceRuleAdmin> adminList = attendanceRuleAdminService.findList(admin);
                    for (AttendanceRuleAdmin attendanceRuleAdmin : adminList) {
                        List<Long> deptIdList = new ArrayList<>();
                        EduUserDept userDept = commonService.getUserDept(attendanceRuleAdmin.getDeptId());
                        if (ObjectUtil.equals(UserDeptTypeEnum.CLASS_TYPE.getValue(), userDept.getDeptType())) {
                            deptIdList = Arrays.asList(userDept.getDeptId());
                        } else {
                            //查看班级
                            deptIdList = remoteUserDeptService
                                .findChildIdByParentAndTypeNoPermission(attendanceRuleAdmin.getDeptId(), 1)
                                .getData().stream().map(EduUserDept::getDeptId).collect(
                                    Collectors.toList());
                        }

                        List<Long> mangerUserIdList = attendanceRuleObjUserService
                            .list(Wrappers.lambdaQuery(new AttendanceRuleObjUser())
                                .in(AttendanceRuleObjUser::getDeptId, deptIdList)
                                .eq(AttendanceRuleObjUser::getRuleId, ruleId)).stream().map(AttendanceRuleObjUser::getUserId)
                            .collect(
                                Collectors.toList());

                        List<AttendanceResult> mangerResultList = resultList.stream()
                            .filter(result -> mangerUserIdList.contains(result.getUserId())).collect(Collectors.toList());
                        if (CollUtil.isNotEmpty(mangerResultList)) {
                            log.info("【{}】管理员发送迟到规则【{}】的提醒报告", attendanceRuleAdmin.getStaffId(), rule.getName());
                            noticeService
                                .sendStudentAttendanceLateReportToStaff(mangerResultList, attendanceRuleAdmin.getStaffId(),
                                    rule,
                                    lateMinute);
                        }
                    }
                }
            }
        } else {
            //
        }
    }

    //    * @param mode       0=推动至教职工，1=推送至学生家长
    //     * @param userType   0=职工，1=学生
    @Override
    public void dayReport(Integer mode, Integer userType, Long ruleId) {
        AttendanceRule rule = attendanceRuleService.getById(ruleId);
        if (ObjectUtil.isNull(rule) || !ObjectUtil.equals(EnableStatusEnum.ENABLE_STATUS.getStatus(), rule.getStatus())) {
            log.error("【{}】规则已停用，不推送日报", rule.getName());
            return;
        }
        //今日异常打卡人员
        List<AttendanceResult> resultList = list(Wrappers.lambdaQuery(new AttendanceResult())
            .eq(AttendanceResult::getRuleId, ruleId)
            .eq(AttendanceResult::getAttendanceDate, LocalDate.now())
            .isNull(AttendanceResult::getStartStatus));

        if (ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), rule.getType())) {
            //固定打卡
            resultList.addAll(list(Wrappers.lambdaQuery(new AttendanceResult())
                .eq(AttendanceResult::getRuleId, ruleId)
                .eq(AttendanceResult::getAttendanceDate, LocalDate.now())
                .isNotNull(AttendanceResult::getStartStatus)
                .isNull(AttendanceResult::getEndStatus)));
        }

        if (mode == 1) {
            //TODO 发送给家长端
        } else {
            //查询规则管理员
            AttendanceRuleAdmin admin = new AttendanceRuleAdmin();
            admin.setRuleId(ruleId);
            List<AttendanceRuleAdmin> adminList = attendanceRuleAdminService.findList(admin);
            Map<Long, List<AttendanceRuleAdmin>> adminMap = adminList.stream()
                .collect(Collectors.groupingBy(AttendanceRuleAdmin::getStaffId));
            for (Entry<Long, List<AttendanceRuleAdmin>> entry : adminMap.entrySet()) {
                Boolean isLeader = false; //是否为校领导
                Long k = entry.getKey();
                List<AttendanceRuleAdmin> v = entry.getValue();
                List<DayReportDataDTO> dayReportDataDTOList = new ArrayList<>();
                for (AttendanceRuleAdmin attendanceRuleAdmin : v) {
                    DayReportDataDTO dto = new DayReportDataDTO();
                    List<Long> deptIdList = new ArrayList<>();
                    if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), userType)) {
                        EduUserDept userDept = commonService.getUserDept(attendanceRuleAdmin.getDeptId());
                        dto.setDeptName(ObjectUtil.isNull(userDept) ? "未知班级" : userDept.getDeptName());
                        if (ObjectUtil.equals(UserDeptTypeEnum.CLASS_TYPE.getValue(), userDept.getDeptType())) {
                            deptIdList = Arrays.asList(userDept.getDeptId());
                        } else {
                            //查看班级
                            deptIdList = remoteUserDeptService
                                .findChildIdByParentAndTypeNoPermission(attendanceRuleAdmin.getDeptId(), 1)
                                .getData().stream().map(EduUserDept::getDeptId).collect(
                                    Collectors.toList());
                            isLeader = true;
                        }
                    } else {
                        Dept dept = commonService.getDept(attendanceRuleAdmin.getDeptId());
                        dto.setDeptName(ObjectUtil.isNull(dept) ? "未知部门" : dept.getDeptName());
                        deptIdList = Arrays.asList(dept.getDeptId());
                    }

                    //管理总人数
                    if (CollUtil.isEmpty(deptIdList)) {
                        dto.setTotalNum(0);
                        dto.setAbNum(0);
                        dto.setRequestNum(0);
                    } else {
                        List<Long> mangerUserIdList = attendanceRuleObjUserService
                            .list(Wrappers.lambdaQuery(new AttendanceRuleObjUser())
                                .in(AttendanceRuleObjUser::getDeptId, deptIdList)
                                .eq(AttendanceRuleObjUser::getRuleId, ruleId)).stream().map(AttendanceRuleObjUser::getUserId)
                            .collect(
                                Collectors.toList());

                        //未打卡人数
                        List<AttendanceResult> mangerResultList =
                            CollUtil.isEmpty(mangerUserIdList) ? new ArrayList<>() : resultList.stream()
                                .filter(result -> mangerUserIdList.contains(result.getUserId())).collect(Collectors.toList());

                        dto.setTotalNum(mangerUserIdList.size());
                        dto.setAbNum(mangerResultList.size());

                        //查询请假人数
                        if (CollUtil.isEmpty(mangerUserIdList)) {
                            dto.setRequestNum(0);
                        } else {
                            ListUserRequestDTO requestDTO = new ListUserRequestDTO();
                            requestDTO.setRequestType(userType);
                            requestDTO.setStartTime(LocalDate.now().atTime(LocalTime.of(00, 00, 01)));
                            requestDTO.setEndTime(LocalDate.now().atTime(LocalTime.of(23, 59, 59)));
                            requestDTO.setUserIdList(mangerUserIdList);
                            List<EduLeaveRequestUserVO> requestUserVOList = remoteLeaveRequestService.findList(requestDTO)
                                .getData();
                            dto.setRequestNum(
                                requestUserVOList.stream().collect(Collectors.groupingBy(EduLeaveRequestUserVO::getUserId))
                                    .size());
                        }
                        dayReportDataDTOList.add(dto);
                    }
                }
                noticeService.sendAttendanceDayReportToStaff(k, dayReportDataDTOList, rule, userType, isLeader);
            }


        }

//        if (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), userType)) {
//            //学生考勤
//            //今日未打卡学生
//            List<AttendanceResult> resultList = list(Wrappers.lambdaQuery(new AttendanceResult())
//                .eq(AttendanceResult::getRuleId, ruleId)
//                .eq(AttendanceResult::getAttendanceDate, LocalDate.now())
//                .isNull(AttendanceResult::getStartStatus));
//
//            if (ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), rule.getType())) {
//                //固定打卡
//                resultList.addAll(list(Wrappers.lambdaQuery(new AttendanceResult())
//                    .eq(AttendanceResult::getRuleId, ruleId)
//                    .eq(AttendanceResult::getAttendanceDate, LocalDate.now())
//                    .isNull(AttendanceResult::getEndStatus)));
//            }
//            if (mode == 1) {
//                //TODO 发送给家长端
//            } else {
//                //查询规则管理员
//                AttendanceRuleAdmin admin = new AttendanceRuleAdmin();
//                admin.setRuleId(ruleId);
//                List<AttendanceRuleAdmin> adminList = attendanceRuleAdminService.findList(admin);
//
//                Map<Long, List<AttendanceRuleAdmin>> adminMap = adminList.stream()
//                    .collect(Collectors.groupingBy(AttendanceRuleAdmin::getStaffId));
//
//                adminMap.forEach((k, v) -> {
//                    List<DayReportDataDTO> dayReportDataDTOList = new ArrayList<>();
//                    for (AttendanceRuleAdmin attendanceRuleAdmin : v) {
//                        DayReportDataDTO dto = new DayReportDataDTO();
//                        List<Long> deptIdList = new ArrayList<>();
//                        EduUserDept userDept = commonService.getUserDept(attendanceRuleAdmin.getDeptId());
//                        dto.setDeptName(userDept.getDeptName());
//
//                        if (ObjectUtil.equals(UserDeptTypeEnum.CLASS_TYPE.getValue(), userDept.getDeptType())) {
//                            deptIdList = Arrays.asList(userDept.getDeptId());
//
//                        } else {
//                            //查看班级
//                            deptIdList = remoteUserDeptService
//                                .findChildIdByParentAndTypeNoPermission(attendanceRuleAdmin.getDeptId(), 1)
//                                .getData().stream().map(EduUserDept::getDeptId).collect(
//                                    Collectors.toList());
//                        }
//
//                        //管理总人数
//                        List<Long> mangerUserIdList = attendanceRuleObjUserService
//                            .list(Wrappers.lambdaQuery(new AttendanceRuleObjUser())
//                                .in(AttendanceRuleObjUser::getDeptId, deptIdList)
//                                .eq(AttendanceRuleObjUser::getRuleId, ruleId)).stream().map(AttendanceRuleObjUser::getUserId)
//                            .collect(
//                                Collectors.toList());
//
//                        //未打卡人数
//                        List<AttendanceResult> mangerResultList = resultList.stream()
//                            .filter(result -> mangerUserIdList.contains(result.getUserId())).collect(Collectors.toList());
//
//                        dto.setTotalNum(mangerUserIdList.size());
//                        dto.setAbNum(mangerResultList.size());
//                        dayReportDataDTOList.add(dto);
//                    }
//                    noticeService.sendStudentAttendanceDayReportToStaff(k, dayReportDataDTOList, rule);
//                });
//            }
//        }
    }


    @Override
    public StaRecordCountVO staRecordCount(LocalDate startDate, LocalDate endDate, List<Long> schoolIds) {
        List<AttendanceResult> list = list(Wrappers.lambdaQuery(new AttendanceResult())
            .in(AttendanceResult::getSchoolId, schoolIds)
            .between(AttendanceResult::getAttendanceDate, startDate, endDate));

        Map<Long, List<AttendanceResult>> studentFixNormal = list.stream()
            .filter(r -> ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), r.getUserType())
                && ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), r.getAttType())
                && ObjectUtil.equals(AttendanceResultEnum.NORMAL, r.getStartStatus())
                && ObjectUtil.equals(AttendanceResultEnum.NORMAL, r.getEndStatus()))
            .collect(Collectors.groupingBy(AttendanceResult::getUserId));

        Map<Long, List<AttendanceResult>> studentFixAbNormal = list.stream()
            .filter(r -> (ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), r.getUserType())
                && ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), r.getAttType()))
                && !(ObjectUtil.equals(AttendanceResultEnum.NORMAL, r.getStartStatus()) && ObjectUtil
                .equals(AttendanceResultEnum.NORMAL, r.getEndStatus())))
            .collect(Collectors.groupingBy(AttendanceResult::getUserId));

        Map<Long, List<AttendanceResult>> studentFreeNormal = list.stream()
            .filter(r -> ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), r.getUserType())
                && ObjectUtil.equals(AttendanceModeTypeEnum.FREE.getValue(), r.getAttType())
                && ObjectUtil.equals(AttendanceResultEnum.NORMAL, r.getStartStatus()))
            .collect(Collectors.groupingBy(AttendanceResult::getUserId));

        Map<Long, List<AttendanceResult>> studentFreeAbNormal = list.stream()
            .filter(r -> ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), r.getUserType())
                && ObjectUtil.equals(AttendanceModeTypeEnum.FREE.getValue(), r.getAttType())
                && !ObjectUtil.equals(AttendanceResultEnum.NORMAL, r.getStartStatus()))
            .collect(Collectors.groupingBy(AttendanceResult::getUserId));

        Map<Long, List<AttendanceResult>> studentFixLate = list.stream()
            .filter(r -> ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), r.getUserType())
                && ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), r.getAttType())
                && ObjectUtil.equals(AttendanceResultEnum.ABNORMAL.getValue(), r.getStartStatus()))
            .collect(Collectors.groupingBy(AttendanceResult::getUserId));

//
//        Map<Long, List<AttendanceResult>> studentFixLate = list.stream()
//            .filter(r -> ObjectUtil.equals(UserTypeEnum.PARENT_USER_TYPE.getType(), r.getUserType())
//                && ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), r.getAttType())
//                && ObjectUtil.equals(AttendanceResultEnum.ABNORMAL.getValue(), r.getStartStatus()))
//            .collect(Collectors.groupingBy(AttendanceResult::getUserId));

//        private Integer studentNormal;
//
//        private Integer studentLate;
//
//        private Integer studentNotArrive;
//
//        private Integer studentRequest;
//
//        private Integer staffNormal;
//
//        private Integer staffLate;
//
//        private Integer staffNotArrive;
        return null;
    }


    private List<Long> initUserIdList(List<AttendanceRuleAdmin> adminList, Integer userType) {
        List<Long> userIdList = new ArrayList<>();
        //查询用户ID集合
        for (AttendanceRuleAdmin admin : adminList) {
            List<AttendanceRuleObj> objList = attendanceRuleObjService.findList(admin.getDeptId(), admin.getRuleId());
            userIdList.addAll(attendanceRuleObjUserService
                .list(Wrappers.lambdaQuery(new AttendanceRuleObjUser())
                    .in(AttendanceRuleObjUser::getDeptId, objList.stream().map(AttendanceRuleObj::getDeptId).collect(
                        Collectors.toList()))
                    .eq(AttendanceRuleObjUser::getUserType, userType)
                    .eq(AttendanceRuleObjUser::getRuleId, admin.getRuleId())).stream().map(AttendanceRuleObjUser::getUserId)
                .collect(Collectors.toList()));

        }
        return userIdList.stream().distinct().collect(Collectors.toList());
    }


    /**
     * @return
     */
    private List<DateStatusVO> initStatusByDate(List<Long> userIdList, Integer userType, LocalDate attendanceStartDate,
        LocalDate attendanceEndDate) {

        List<AttendanceStatusByMonthVO> attendanceStatusByMonthVOList = baseMapper
            .findAttendanceStatus(userType, userIdList, attendanceStartDate, attendanceEndDate);

        for (AttendanceStatusByMonthVO attendanceStatusVO : attendanceStatusByMonthVOList) {
            //判断总的状态
            //先判断是否需要打卡
            AttendanceRuleVO rule = attendanceRuleService.getRule(attendanceStatusVO.getRuleId());

            if (attendanceStatusVO.getDate().isAfter(LocalDate.now())) {
                attendanceStatusVO.setStatus(4); //大于当前日期
                continue;
            }

            if (ObjectUtil.isNotNull(rule) && !rule.getWeek()
                .contains(String.valueOf(LocalDate.now().getDayOfWeek().getValue()))) {
                attendanceStatusVO.setStatus(3); //非考勤日不参与打卡
                continue;
            }
            //请假状态
            if (userIdList.size() == 1) {
                if (!(ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), attendanceStatusVO.getStartStatus()) &&
                    ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), attendanceStatusVO.getEndStatus()))) {
                    AddAttendanceRuleTimeDTO ruleTime = attendanceRuleTimeService.get(attendanceStatusVO.getRuleTimeId());
                    if (ObjectUtil.isNotNull(ruleTime)) {
                        ListUserRequestDTO requestDTO = new ListUserRequestDTO();
                        requestDTO.setRequestType(userType);
                        requestDTO.setUserIdList(Arrays.asList(userIdList.get(0)));
                        requestDTO.setStartTime(attendanceStatusVO.getDate().atTime(ruleTime.getStartTime()));
                        requestDTO.setEndTime(attendanceStatusVO.getDate().atTime(ruleTime.getEndTime()));
                        List<EduLeaveRequestUserVO> requestUserVOList = remoteLeaveRequestService.findList(requestDTO).getData();
                        if (CollUtil.isNotEmpty(requestUserVOList)) {
                            attendanceStatusVO.setStatus(2);
                            continue;
                        }
                    }
                }
            }
            if (ObjectUtil.equals(AttendanceModeTypeEnum.FIX.getValue(), attendanceStatusVO.getAttType()) ?
                (ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), attendanceStatusVO.getStartStatus()) &&
                    ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), attendanceStatusVO.getEndStatus()))
                : ObjectUtil.equals(AttendanceResultEnum.NORMAL.getValue(), attendanceStatusVO.getStartStatus())) {
                attendanceStatusVO.setStatus(0);
            } else {
                attendanceStatusVO.setStatus(1);
            }

        }
        List<DateStatusVO> retList = new ArrayList<>();
        Map<LocalDate, List<AttendanceStatusByMonthVO>> listMap = attendanceStatusByMonthVOList.stream()
            .collect(Collectors.groupingBy(AttendanceStatusByMonthVO::getDate));

        listMap.forEach((k, v) -> {
            DateStatusVO vo = new DateStatusVO();
            vo.setDate(k);
            List<AttendanceStatusByMonthVO> abNomalList = v.stream()
                .filter(n -> ObjectUtil.equals(AttendanceResultEnum.ABNORMAL.getValue(), n.getStatus()))
                .collect(Collectors.toList());
            if (abNomalList.size() > 0) {
                vo.setStatus(AttendanceResultEnum.ABNORMAL.getValue());
            } else {
                vo.setStatus(v.get(0).getStatus());
            }
            retList.add(vo);
        });

        if (CollUtil.isNotEmpty(retList)) {
            Collections.reverse(retList);
        }
        return retList;
    }

}
