package com.xjrsoft.module.databoard.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.yulichang.toolkit.MPJWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xjrsoft.common.enums.DeleteMark;
import com.xjrsoft.common.enums.GenderDictionaryEnum;
import com.xjrsoft.common.enums.StudyStatusEnum;
import com.xjrsoft.common.model.result.RT;
import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
import com.xjrsoft.common.utils.VoToColumnUtil;
import com.xjrsoft.module.courseTable.entity.CourseTable;
import com.xjrsoft.module.courseTable.service.ICourseTableService;
import com.xjrsoft.module.databoard.dto.StatisticsDetailDto;
import com.xjrsoft.module.databoard.dto.StatisticsDto;
import com.xjrsoft.module.databoard.vo.AttendanceStatisticsVo;
import com.xjrsoft.module.databoard.vo.CourseStatisticsVo;
import com.xjrsoft.module.databoard.vo.HealthStatisticsVo;
import com.xjrsoft.module.databoard.vo.ItemCountAmountVo;
import com.xjrsoft.module.databoard.vo.MeetingStatisticsVo;
import com.xjrsoft.module.databoard.vo.PersonStatisticsVo;
import com.xjrsoft.module.databoard.vo.ProcessStatisticsVo;
import com.xjrsoft.module.databoard.vo.ReimbursementStatisticsVo;
import com.xjrsoft.module.databoard.vo.RepairStatisticsVo;
import com.xjrsoft.module.databoard.vo.VisitorStatisticsVo;
import com.xjrsoft.module.outint.entity.VisitorOutInRecord;
import com.xjrsoft.module.outint.service.IVisitorOutInRecordService;
import com.xjrsoft.module.student.dto.BaseStudentUserPageDto;
import com.xjrsoft.module.student.service.IBaseStudentService;
import com.xjrsoft.module.student.vo.BaseStudentUserPageVo;
import com.xjrsoft.module.system.entity.DictionaryDetail;
import com.xjrsoft.module.teacher.entity.BaseTeacher;
import com.xjrsoft.module.teacher.entity.XjrUser;
import com.xjrsoft.module.teacher.service.ITeacherbaseManagerService;
import com.xjrsoft.module.teacher.vo.XjrUserPageVo;
import com.xjrsoft.module.workflow.constant.WorkflowConstant;
import com.xjrsoft.module.workflow.entity.WorkflowExtra;
import com.xjrsoft.module.workflow.entity.WorkflowSchema;
import com.xjrsoft.module.workflow.service.IWorkflowExtraService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.history.HistoricProcessInstanceQuery;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
* @title: 数据看板代码
* @Date: 2024年8月2日
* @Version 1.0
*/
@RestController
@RequestMapping("/databoard" + "/databoard")
@Api(value = "/databoard"  + "/databoard",tags = "数据看板代码")
@AllArgsConstructor
public class DataboardController {

    private final HistoryService historyService;
    private final ICourseTableService courseTableService;
    private final IVisitorOutInRecordService visitorService;
    private final IBaseStudentService studentService;
    private final ITeacherbaseManagerService teacherService;
    private final IWorkflowExtraService extraService;

    @GetMapping(value = "/process-statistics")
    @ApiOperation(value="流程统计")
    @SaCheckPermission("databoard:detail")
    public RT<ProcessStatisticsVo> processStatistics(@Valid StatisticsDto dto){
        HistoricProcessInstanceQuery instanceQuery = historyService.createHistoricProcessInstanceQuery();
        if(dto.getUserId() != null){
            instanceQuery.variableValueEquals(WorkflowConstant.PROCESS_START_USER_ID_KEY, dto.getUserId());
        }

        List<WorkflowExtra> workflowExtras = extraService.list(
                new MPJLambdaWrapper<WorkflowExtra>()
                        .select(WorkflowExtra.class, x -> VoToColumnUtil.fieldsToColumns(WorkflowExtra.class).contains(x.getProperty()))
                        .leftJoin(WorkflowSchema.class, WorkflowSchema::getId, WorkflowExtra::getSchemaId)
                        .leftJoin(DictionaryDetail.class, DictionaryDetail::getId, WorkflowSchema::getCategory)
        );


        ProcessStatisticsVo result = new ProcessStatisticsVo();
        List<HistoricProcessInstance> list = instanceQuery.list();
        List<WorkflowExtra> allCountList = new ArrayList<>();
        for (HistoricProcessInstance historicProcessInstance : list) {
            workflowExtras.stream()
                    .filter(e -> e.getProcessId().equals(historicProcessInstance.getId()))
                    .max(Comparator.comparing(WorkflowExtra::getStartTime))
                    .ifPresent(e -> {
                        allCountList.add(e);
                    });
        }
        result.setAllCount(Long.parseLong(allCountList.size() + ""));

        List<HistoricProcessInstance> finished = historyService.createHistoricProcessInstanceQuery().finished().list();
        List<WorkflowExtra> completeCountList = new ArrayList<>();
        for (HistoricProcessInstance historicProcessInstance : finished) {
            workflowExtras.stream()
                    .filter(e -> e.getProcessId().equals(historicProcessInstance.getId()))
                    .max(Comparator.comparing(WorkflowExtra::getStartTime))
                    .ifPresent(e -> {
                        completeCountList.add(e);
                    });
        }
        result.setCompleteCount(Long.parseLong(completeCountList.size() + ""));

        List<HistoricProcessInstance> unfinished = historyService.createHistoricProcessInstanceQuery().unfinished().list();
        List<WorkflowExtra> uncompleteCountList = new ArrayList<>();
        for (HistoricProcessInstance historicProcessInstance : unfinished) {
            workflowExtras.stream()
                    .filter(e -> e.getProcessId().equals(historicProcessInstance.getId()))
                    .max(Comparator.comparing(WorkflowExtra::getStartTime))
                    .ifPresent(e -> {
                        uncompleteCountList.add(e);
                    });
        }
        result.setUncompleteCount(Long.parseLong(uncompleteCountList.size() + ""));

        return RT.ok(result);
    }

    @GetMapping(value = "/meeting-statistics")
    @ApiOperation(value="会议统计")
    @SaCheckPermission("databoard:detail")
    public RT<MeetingStatisticsVo> meetingStatistics(@Valid StatisticsDetailDto dto){
        LocalDateTime startTime = null;
        LocalDateTime endTime = null;
        if(dto.getStartDate() != null){
            startTime = dto.getStartDate().atStartOfDay();
        }
        if(dto.getEndDate() != null){
            endTime = dto.getEndDate().atStartOfDay().plusDays(1).plusNanos(-1);
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        String sql = "SELECT id, (SELECT COUNT(*) FROM xjr_user WHERE FIND_IN_SET(id, meeting_apply_participants)) AS person_count FROM wf_meeting_apply where 1 = 1";
        if(startTime != null && endTime != null){
            sql += " and meeting_apply_date between '" + startTime.format(formatter) + "' and '" + endTime.format(formatter) + "'";
        }
        if(dto.getUserId() != null){
            sql += " and FIND_IN_SET(" + dto.getUserId() +", meeting_apply_participants)";
        }
        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
        MeetingStatisticsVo result = new MeetingStatisticsVo();
        result.setAllCount(list.size());
        int personCount = 0;
        for (Map<String, Object> objectMap : list) {
            personCount += (Long)objectMap.get("person_count");
        }
        result.setPersonCount(personCount);
        return RT.ok(result);
    }

    @GetMapping(value = "/course-statistics")
    @ApiOperation(value="课表统计")
    @SaCheckPermission("databoard:detail")
    public RT<CourseStatisticsVo> courseStatistics(@Valid StatisticsDetailDto dto){
        List<CourseTable> list = courseTableService.list(
                new QueryWrapper<CourseTable>().lambda()
                        .eq((dto.getStartDate() == null && dto.getEndDate() == null), CourseTable::getScheduleDate, new Date())
                        .between((dto.getStartDate() != null && dto.getEndDate() != null), CourseTable::getScheduleDate, dto.getStartDate(), dto.getEndDate())
        );
        CourseStatisticsVo result = new CourseStatisticsVo();
        result.setAllCount(list.size());
        int teacherCount = 0, noTeacherCount = 0;
        for (CourseTable courseTable : list) {
            if(courseTable.getTimePeriod() != null && "0".equals(courseTable.getTeacherId())){
                teacherCount ++;
            }else{
                noTeacherCount ++;
            }
        }
        result.setTeacherCount(teacherCount);
        result.setNoTeacherCount(noTeacherCount);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String sql = "SELECT * FROM wf_course_adjust WHERE STATUS = 1 and adjust_type = 'course_adjust'";
        if(dto.getStartDate() != null && dto.getEndDate() != null){
            sql += " AND exchange_date between '" + dto.getStartDate().format(formatter) + "' and '" + dto.getEndDate().format(formatter) + "'";
        }else{
            sql += " AND exchange_date = NOW()";
        }
        long adjustCount = SqlRunnerAdapter.db().selectCount(sql);
        result.setAdjustCount(Integer.parseInt(adjustCount + ""));

        sql = "SELECT * FROM wf_course_adjust WHERE STATUS = 1 and adjust_type = 'course_exchange'";
        if(dto.getStartDate() != null && dto.getEndDate() != null){
            sql += " AND exchange_date between '" + dto.getStartDate().format(formatter) + "' and '" + dto.getEndDate().format(formatter) + "'";
        }else{
            sql += " AND exchange_date = NOW()";
        }
        long exchangeCount = SqlRunnerAdapter.db().selectCount(sql);
        result.setReplaceCount(Integer.parseInt(exchangeCount + ""));

        return RT.ok(result);
    }

    @GetMapping(value = "/visitor-statistics")
    @ApiOperation(value="访客统计")
    @SaCheckPermission("databoard:detail")
    public RT<VisitorStatisticsVo> visitorStatistics(@Valid StatisticsDto dto){
        List<VisitorOutInRecord> list = visitorService.list(
                new QueryWrapper<VisitorOutInRecord>().lambda()
                        .eq(VisitorOutInRecord::getDeleteMark, DeleteMark.DELETED.getCode())
        );
        VisitorStatisticsVo result = new VisitorStatisticsVo();
        result.setAllCount(list.size());
        LocalDate today = LocalDate.now();
        int todayCount = 0;
        for (VisitorOutInRecord record : list) {
            if(today.equals(record.getRecordTime().toLocalDate())){
                todayCount ++;
            }
        }
        result.setTodayCount(todayCount);
        return RT.ok(result);
    }

    @GetMapping(value = "/person-statistics")
    @ApiOperation(value="全校师生数据概览")
    @SaCheckPermission("databoard:detail")
    public RT<PersonStatisticsVo> personStatistics(@Valid StatisticsDto dto){

        List<BaseStudentUserPageVo> studentList = studentService.getStudentList(new BaseStudentUserPageDto());

        PersonStatisticsVo result = new PersonStatisticsVo();
        result.setStudentCount(studentList.size());

        Set<String> studentMaleSet = studentList.stream()
                .filter(x -> (x.getGenderCn() != null && x.getGenderCn().equals(GenderDictionaryEnum.MALE.getCode())))
                .map(BaseStudentUserPageVo::getId).collect(Collectors.toSet());
        result.setStudentMaleCount(studentMaleSet.size());

        Set<String> studentFemaleSet = studentList.stream()
                .filter(x -> (x.getGenderCn() != null && x.getGenderCn().equals(GenderDictionaryEnum.FEMALE.getCode())))
                .map(BaseStudentUserPageVo::getId).collect(Collectors.toSet());
        result.setStudentFemaleCount(studentFemaleSet.size());

        Set<String> studentStayMaleSet = studentList.stream()
                .filter(x -> (
                        x.getGenderCn() != null
                        && x.getGenderCn().equals(GenderDictionaryEnum.MALE.getCode())
                        && x.getStduyStatusCn() != null
                        && x.getStduyStatusCn().equals(StudyStatusEnum.InResidence.getCode())
                ))
                .map(BaseStudentUserPageVo::getId).collect(Collectors.toSet());
        result.setStudentStayMaleCount(studentStayMaleSet.size());

        Set<String> studentNotStayMaleSet = studentList.stream()
                .filter(x -> (
                        x.getGenderCn() != null
                                && x.getGenderCn().equals(GenderDictionaryEnum.MALE.getCode())
                                && x.getStduyStatusCn() != null
                                && x.getStduyStatusCn().equals(StudyStatusEnum.AttendDaySchool.getCode())
                ))
                .map(BaseStudentUserPageVo::getId).collect(Collectors.toSet());
        result.setStudentNotStayMaleCount(studentNotStayMaleSet.size());

        Set<String> studentStayFemaleSet = studentList.stream()
                .filter(x -> (
                        x.getGenderCn() != null
                                && x.getGenderCn().equals(GenderDictionaryEnum.FEMALE.getCode())
                                && x.getStduyStatusCn() != null
                                && x.getStduyStatusCn().equals(StudyStatusEnum.InResidence.getCode())
                ))
                .map(BaseStudentUserPageVo::getId).collect(Collectors.toSet());
        result.setStudentStayFemaleCount(studentStayFemaleSet.size());

        Set<String> studentNotStayFemaleSet = studentList.stream()
                .filter(x -> (
                        x.getGenderCn() != null
                                && x.getGenderCn().equals(GenderDictionaryEnum.FEMALE.getCode())
                                && x.getStduyStatusCn() != null
                                && x.getStduyStatusCn().equals(StudyStatusEnum.AttendDaySchool.getCode())
                ))
                .map(BaseStudentUserPageVo::getId).collect(Collectors.toSet());
        result.setStudentNotStayFemaleCount(studentNotStayFemaleSet.size());

        MPJLambdaWrapper<XjrUser> queryWrapper = MPJWrappers.<XjrUser>lambdaJoin()
                .disableSubLogicDel()
                .orderByDesc(XjrUser::getId)
                .select(XjrUser::getId)
                .select(XjrUser.class,x -> VoToColumnUtil.fieldsToColumns(XjrUserPageVo.class).contains(x.getProperty()))
                .innerJoin(BaseTeacher.class,BaseTeacher::getUserId,XjrUser::getId)
                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode,BaseTeacher::getJobState, ext->ext.selectAs(DictionaryDetail::getName, XjrUserPageVo::getJobState))
                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode,XjrUser::getCredentialType,ext->ext.selectAs(DictionaryDetail::getName, XjrUserPageVo::getCredentialType))
                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode,BaseTeacher::getEmployWay,ext->ext.selectAs(DictionaryDetail::getName, XjrUserPageVo::getEmployWay))

                .selectAsClass(BaseTeacher.class, XjrUserPageVo.class);

        List<XjrUserPageVo> teacherList = teacherService.selectJoinList(XjrUserPageVo.class, queryWrapper);
        result.setTeacherCount(teacherList.size());

        Set<String> teacherMaleSet = teacherList.stream()
                .filter(x -> (x.getGender() != null && x.getGender().equals(GenderDictionaryEnum.MALE.getCode())))
                .map(XjrUserPageVo::getId).collect(Collectors.toSet());
        result.setTeacherMaleCount(teacherMaleSet.size());

        Set<String> teacherFemaleSet = teacherList.stream()
                .filter(x -> (x.getGender() != null && x.getGender().equals(GenderDictionaryEnum.FEMALE.getCode())))
                .map(XjrUserPageVo::getId).collect(Collectors.toSet());
        result.setTeacherFemaleCount(teacherFemaleSet.size());

        Set<String> teacherSet1 = teacherList.stream()
                .filter(x -> (x.getEmployWay() != null && x.getEmployWay().equals("FB1601")))
                .map(XjrUserPageVo::getId).collect(Collectors.toSet());
        result.setTeacherCount1(teacherSet1.size());
        Set<String> teacherSet2 = teacherList.stream()
                .filter(x -> (x.getEmployWay() != null && x.getEmployWay().equals("FB1602")))
                .map(XjrUserPageVo::getId).collect(Collectors.toSet());
        result.setTeacherCount2(teacherSet2.size());
        Set<String> teacherSet3 = teacherList.stream()
                .filter(x -> (x.getEmployWay() != null && x.getEmployWay().equals("FB1606")))
                .map(XjrUserPageVo::getId).collect(Collectors.toSet());
        result.setTeacherCount3(teacherSet3.size());
        Set<String> teacherSet4 = teacherList.stream()
                .filter(x -> (x.getEmployWay() != null && x.getEmployWay().equals("FB1609")))
                .map(XjrUserPageVo::getId).collect(Collectors.toSet());
        result.setTeacherCount4(teacherSet4.size());
        Set<String> teacherSet5 = teacherList.stream()
                .filter(x -> (x.getEmployWay() != null && x.getEmployWay().equals("FB1608")))
                .map(XjrUserPageVo::getId).collect(Collectors.toSet());
        result.setTeacherCount5(teacherSet5.size());
        return RT.ok(result);
    }

    @GetMapping(value = "/health-statistics")
    @ApiOperation(value="学生健康统计")
    @SaCheckPermission("databoard:detail")
    public RT<HealthStatisticsVo> healthStatistics(@Valid StatisticsDto dto){
        String sql = "SELECT gender,COUNT(*) AS a_count FROM student_infection WHERE status = 1 GROUP BY gender";
        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
        HealthStatisticsVo result = new HealthStatisticsVo();
        for (Map<String, Object> objectMap : list) {
            if(objectMap.get("gender") != null && GenderDictionaryEnum.FEMALE.getCode().equals(objectMap.get("gender").toString())){
                result.setInfectionFemaleCount(Integer.parseInt(objectMap.get("a_count").toString()));
            }if(objectMap.get("gender") != null && GenderDictionaryEnum.MALE.getCode().equals(objectMap.get("gender").toString())){
                result.setInfectionMaleCount(Integer.parseInt(objectMap.get("a_count").toString()));
            }
        }

        sql = "SELECT gender,COUNT(*) AS a_count FROM student_psychological WHERE status = 1 GROUP BY gender";
        list = SqlRunnerAdapter.db().selectList(sql);
        for (Map<String, Object> objectMap : list) {
            if(objectMap.get("gender") != null && GenderDictionaryEnum.FEMALE.getCode().equals(objectMap.get("gender").toString())){
                result.setInfectionFemaleCount(Integer.parseInt(objectMap.get("a_count").toString()));
            }if(objectMap.get("gender") != null && GenderDictionaryEnum.MALE.getCode().equals(objectMap.get("gender").toString())){
                result.setPsychologicalMaleCount(Integer.parseInt(objectMap.get("a_count").toString()));
            }
        }
        return RT.ok(result);
    }

    @GetMapping(value = "/reimbursement-statistics")
    @ApiOperation(value="差旅费报销申请")
    @SaCheckPermission("databoard:detail")
    public RT<ReimbursementStatisticsVo> reimbursementStatistics(@Valid StatisticsDetailDto dto){
        LocalDateTime startTime = null;
        LocalDateTime endTime = null;
        if(dto.getStartDate() != null){
            startTime = dto.getStartDate().atStartOfDay();
        }
        if(dto.getEndDate() != null){
            endTime = dto.getEndDate().atStartOfDay().plusDays(1).plusNanos(-1);
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        String sql = "SELECT * FROM billing_reimbursement where 1 = 1";
        if(startTime != null && endTime != null){
            sql += " and aply_time between '" + startTime.format(formatter) + "' and '" + endTime.format(formatter) + "'";
        }
        if(dto.getUserId() != null){
            sql += " and applicant_id = " + dto.getUserId();
        }
        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
        ReimbursementStatisticsVo result = new ReimbursementStatisticsVo();
        result.setAllCount(list.size());
        int completeCount = 0;
        int uncompleteCount = 0;

        for (Map<String, Object> objectMap : list) {
            Object statusObj = objectMap.get("status");
            if(statusObj == null){
                uncompleteCount ++;
            }else{
                completeCount ++;
            }
        }
        result.setCompleteCount(completeCount);
        result.setUncompleteCount(uncompleteCount);

        sql = "select city_in,sum(total_amount) as total_amount from billing_reimbursement where status = 1";
        if(startTime != null && endTime != null){
            sql += " and aply_time between '" + startTime.format(formatter) + "' and '" + endTime.format(formatter) + "'";
        }
        sql += " group by city_in ";
        list = SqlRunnerAdapter.db().selectList(sql);
        List<ItemCountAmountVo> amountList = new ArrayList<>();
        for (Map<String, Object> objectMap : list) {
            Object cityInObj = objectMap.get("city_in");
            String item = "";
            if(cityInObj != null && Integer.parseInt(cityInObj.toString()) == 1){
                item = "市外";
            }else if(cityInObj != null && Integer.parseInt(cityInObj.toString()) == 0){
                item = "室内";
            }
            ItemCountAmountVo amountVo = new ItemCountAmountVo();
            amountVo.setItem(item);
            amountVo.setAmount(Double.parseDouble(objectMap.get("total_amount").toString()));
            amountList.add(amountVo);
        }
        result.setAmountList(amountList);
        return RT.ok(result);
    }

    @GetMapping(value = "/repair-statistics")
    @ApiOperation(value="维修申报")
    @SaCheckPermission("databoard:detail")
    public RT<RepairStatisticsVo> repairStatistics(@Valid StatisticsDetailDto dto){
        LocalDateTime startTime = null;
        LocalDateTime endTime = null;
        if(dto.getStartDate() != null){
            startTime = dto.getStartDate().atStartOfDay();
        }
        if(dto.getEndDate() != null){
            endTime = dto.getEndDate().atStartOfDay().plusDays(1).plusNanos(-1);
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        RepairStatisticsVo result = new RepairStatisticsVo();
        String sql = "SELECT * FROM wf_repair_declaration where 1 = 1";
        if(startTime != null && endTime != null){
            sql += " and application_time between '" + startTime.format(formatter) + "' and '" + endTime.format(formatter) + "'";
        }
        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
        result.setAllCount(list.size());
        int completeCount = 0;
        int uncompleteCount = 0;
        int personCount = 0;

        for (Map<String, Object> objectMap : list) {
            Object statusObj = objectMap.get("status");
            if(statusObj == null){
                uncompleteCount ++;
            }else{
                completeCount ++;
            }
            if(objectMap.get("status") != null && "是".equals(objectMap.get("status").toString())){
                personCount ++;
            }

        }
        result.setCompleteCount(completeCount);
        result.setUncompleteCount(uncompleteCount);
        result.setPersonCount(personCount);

        sql = "SELECT ifnull(SUM(indemnity), 0) as indemnity FROM wf_repair_declaration";
        list = SqlRunnerAdapter.db().selectList(sql);
        result.setTotalAmount(Double.parseDouble(list.get(0).get("indemnity").toString()));

        return RT.ok(result);
    }

    @GetMapping(value = "/attendance-statistics")
    @ApiOperation(value="个人考勤")
    @SaCheckPermission("databoard:detail")
    public RT<AttendanceStatisticsVo> attendanceStatistics(@Valid StatisticsDetailDto dto){
        LocalDateTime startTime = null;
        LocalDateTime endTime = null;
        if(dto.getStartDate() != null){
            startTime = dto.getStartDate().atStartOfDay();
        }
        if(dto.getEndDate() != null){
            endTime = dto.getEndDate().atStartOfDay().plusDays(1).plusNanos(-1);
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        AttendanceStatisticsVo result = new AttendanceStatisticsVo();

        String sql = " SELECT ifnull(sum(leave_days), 0) as leave_days FROM wf_teacherleave WHERE status = 1";

        if(startTime != null && endTime != null){
            String startTimeStr = startTime.format(formatter);
            String endTimeStr = endTime.format(formatter);
            sql +=" AND (" +
                " (leave_start_time BETWEEN '" + startTimeStr + "' and '" + endTimeStr + "')" +
                " OR (leave_end_time BETWEEN '" + startTimeStr + "' and '" + endTimeStr + "')" +
                " OR (leave_start_time > '" + startTimeStr + "' and '" + endTimeStr + "' > leave_end_time)" +
                " OR ('" + startTimeStr + "' > leave_start_time and leave_end_time > '" + endTimeStr + "')" +
                ")";
        }
        if(dto.getUserId() != null){
            sql += " and user_id = " + dto.getUserId();
        }
        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
        result.setLeaveDays(Double.parseDouble(list.get(0).get("leave_days").toString()));

        sql = "SELECT COUNT(*) AS a_count FROM teacher_out_in_record WHERE delete_mark = 0 and attendance_status = '迟到'";
        if(startTime != null && endTime != null){
            sql +=" AND record_time between '" + startTime.format(formatter) + "' and '" + endTime.format(formatter) + "'";
        }
        if(dto.getUserId() != null){
            sql += " and user_id = " + dto.getUserId();
        }
        list = SqlRunnerAdapter.db().selectList(sql);
        result.setLateCount(Integer.parseInt(list.get(0).get("a_count").toString()));

        sql = "select COUNT(*) AS a_count from wf_course_adjust where status = 1";
        if(startTime != null && endTime != null){
            sql +=" AND adjust_date between '" + startTime.format(formatter) + "' and '" + endTime.format(formatter) + "'";
        }
        if(dto.getUserId() != null){
            sql += " and user_id = " + dto.getUserId();
        }
        list = SqlRunnerAdapter.db().selectList(sql);
        result.setAdjustCount(Integer.parseInt(list.get(0).get("a_count").toString()));

        sql = "select COUNT(*) AS a_count from wf_course_adjust where status = 1";
        if(startTime != null && endTime != null){
            sql +=" AND exchange_date between '" + startTime.format(formatter) + "' and '" + endTime.format(formatter) + "'";
        }
        if(dto.getUserId() != null){
            sql += " and user_id = " + dto.getUserId();
        }
        list = SqlRunnerAdapter.db().selectList(sql);
        result.setExchangeCount(Integer.parseInt(list.get(0).get("a_count").toString()));
        return RT.ok(result);
    }

}