SchedulingService.java 13.1 KB
package com.ruoyi.service;

import cn.hutool.core.collection.CollectionUtil;
import com.ruoyi.common.cache.NowSchedulingCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.driver.mapper.DriverSchedulingMapper;
import com.ruoyi.in.domain.SignIn;
import com.ruoyi.in.mapper.SignInMapper;
import com.ruoyi.pojo.DriverSignInRecommendation;
import com.ruoyi.pojo.GlobalIndex;
import com.ruoyi.domain.DriverScheduling;
import com.ruoyi.pojo.request.ReportViewRequestVo;
import com.ruoyi.pojo.response.ReportViewResponseVo;
import com.ruoyi.utils.ConstDateUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.temporal.ChronoUnit;
import java.util.*;

import static com.ruoyi.common.ConstDriverProperties.BC_TYPE_IN;
import static com.ruoyi.common.ConstDriverProperties.BC_TYPE_OUT;
import static com.ruoyi.common.ConstSignInConstSignInProperties.*;
import static com.ruoyi.common.ErrorTypeProperties.SIGN_IN_TIMEOUT;
import static com.ruoyi.common.ErrorTypeProperties.SIGN_OUT_TIMEOUT;
import static com.ruoyi.common.ReportProperties.NOW;

/**
 * @author 20412
 */
@Service
public class SchedulingService {

    @Resource
    private NowSchedulingCache nowSchedulingCache;

    @Autowired
    private DriverSchedulingMapper schedulingMapper;

    @Autowired
    private SignInMapper signInMapper;


    /**
     * 获取排班信息
     *
     * @param jobCode
     * @param now
     * @return
     */
    public List<DriverScheduling> queryScheduling(String jobCode, Long now) {

        List<DriverScheduling> dto = null;
        for (int i = 0; i > -2; i--) {
            dto = nowSchedulingCache.getCacheSchedulingMapValueByHKey(ConstDateUtil.formatDate(ConstDateUtil.getTheSpecifiedNumberOfDaysOfTime(i)), jobCode);
            if (!CollectionUtil.isEmpty(dto)) {
                dto.sort(Comparator.comparing(DriverScheduling::getZdsjT));
                if (i == -1) {
                    LocalDateTime zdsjT = ConstDateUtil.getLocalDateTimeByLongTime(dto.get(dto.size() - 1).getZdsjT());
                    LocalDateTime nowTime = ConstDateUtil.getLocalDateTimeByLongTime(now);
                    long range = ChronoUnit.MINUTES.between(zdsjT, nowTime);
                    // 判定存在排班 前天的最后一次打卡时间超过2小时,排班为null
                    if (range > 120L) {
                        dto = null;
                    }
                }
                break;
            }
        }
        return dto;
    }


    /**
     * 计算当前签到签到逻辑
     *
     * @param dto
     * @param now
     * @return
     */
    public DriverSignInRecommendation computedTheCurrentClosestTimestamp(List<DriverScheduling> dto, Long now, Integer result) {
        Map<Integer, DriverSignInRecommendation> timeMap = new HashMap<>();
        for (int i = 0; i < dto.size(); i++) {
            timeMap.put(i, new DriverSignInRecommendation(dto.get(i), i));
        }
        long minDiff = Long.MAX_VALUE;
        Integer index = 0;
        // 迭代比较每个时间戳与当前时间戳的差值
        for (Integer i : timeMap.keySet()) {
            long diff = Math.abs(now - timeMap.get(i).getTimestamps());
            if (diff < minDiff) {
                minDiff = diff;
                index = i;
            }
        }
        if (index + result >= 0 && index + result < timeMap.size()) {
            index = index + result;
        }
        return timeMap.get(index);
    }

    /**
     * 更具最新的签到记录判断是否需要更新考勤。
     *
     * @param dto
     * @param signIn
     * @param globalIndex
     */
    public void computedSignInBySignIn(List<DriverScheduling> dto, SignIn signIn, GlobalIndex globalIndex) {
        // 无排班不记录不在考勤表不更新
        if (CollectionUtil.isEmpty(dto)) {
            return;
        }

        String remark = getRemark(dto, signIn, globalIndex.getIndex());
        // 更新最新的签到记录判断是否需要更新考勤
        // 记录为空直接插入记录
        if (Objects.isNull(dto.get(globalIndex.getIndex()).getSignInId()) || dto.size() == 1) {
            schedulingMapper.updateRoster(dto.get(globalIndex.getIndex()), signIn.getId(), signIn.getExType(), signIn.getCreateTime(), remark, signIn.getType(), signIn.getAlcoholFlag(), signIn.getAlcoholIntake());
            // 更新缓存
            nowSchedulingCache.updateCacheByJobCode(ConstDateUtil.formatDate(dto.get(0).getScheduleDate()), globalIndex.getIndex(), signIn);
        }
        // 之前的无效
        else if (!dto.get(globalIndex.getIndex()).getExType().equals(SIGN_NO_EX_NUM)) {
            schedulingMapper.updateRoster(dto.get(globalIndex.getIndex()), signIn.getId(), signIn.getExType(), signIn.getCreateTime(), remark, signIn.getType(), signIn.getAlcoholFlag(), signIn.getAlcoholIntake());
            nowSchedulingCache.updateCacheByJobCode(ConstDateUtil.formatDate(dto.get(0).getScheduleDate()), globalIndex.getIndex(), signIn);
        }
        // 之前的有效
        else {
            handlerRecord(dto, signIn, globalIndex);
        }

    }

    private String getRemark(List<DriverScheduling> dto, SignIn signIn, Integer globalIndex) {
        DriverScheduling scheduling = dto.get(globalIndex);
        long date = scheduling.getBcType().equals(BC_TYPE_IN) ? scheduling.getZdsjT() : scheduling.getFcsjT();
        long nowBetween = ChronoUnit.MINUTES.between(ConstDateUtil.getLocalDateTimeByLongTime(date), ConstDateUtil.getLocalDateTimeByLongTime(signIn.getCreateTime().getTime()));
        if (!(Math.abs(nowBetween) <= 60)) {
            if (nowBetween < -60L) {
                return "早签";
            } else {
                return "迟到";
            }
        }
        return signIn.getRemark();
    }

    private void handlerRecord(List<DriverScheduling> dto, SignIn signIn, GlobalIndex globalIndex) {
        if (globalIndex.getIndex() == dto.size() - 1) {
            return;
        }
        long timer = 1000 * 60 * 60;
        // 有效的在一小时内内重复签到不做修改
        if (signIn.getExType().equals(SIGN_NO_EX_NUM) && (DateUtils.getNowDate().getTime() - dto.get(globalIndex.getIndex()).getSignTime().getTime()) <= timer) {
            signIn.setRemark("您已经打卡过了,请勿在一小时内重复打卡");
            return;
        }
        int index = globalIndex.getIndex() + 1;
        // 之前是签到 |  目前有效记录 -》进行修改  变成无效
        if (signIn.getExType().equals(SIGN_NO_EX_NUM)) {
            signIn.setStatus(SIGN_IN_FAIL);
            signIn.setExType(SIGN_TIME_OUT_EX_NUM);
            signInMapper.updateSignIn(signIn);
        }
        DriverScheduling scheduling = dto.get(index);
        long date = scheduling.getBcType().equals(BC_TYPE_IN) ? scheduling.getZdsjT() : scheduling.getFcsjT();
        String prompt = "请在" + ConstDateUtil.formatDate("HH:mm", new Date(date)) + "前后一小时内打卡。";
        signIn.setRemark((scheduling.getBcType().equals(BC_TYPE_IN) ? SIGN_OUT_TIMEOUT : SIGN_IN_TIMEOUT) + prompt);
        signIn.setRemark(signIn.getRemark().replaceFirst(",$", "。"));
        // 之前是签到 |  目前无效 -》往后更新

        String remark = getRemark(dto, signIn, index);
        schedulingMapper.updateRoster(scheduling, signIn.getId(), signIn.getExType(), signIn.getCreateTime(), remark, signIn.getType(), signIn.getAlcoholFlag(), signIn.getAlcoholIntake());
        nowSchedulingCache.updateCacheByJobCode(ConstDateUtil.formatDate(dto.get(0).getScheduleDate()), globalIndex.getIndex() + 1, signIn);
    }

    public List<ReportViewResponseVo> queryReportTableResponseVo(ReportViewRequestVo requestVo, HttpServletResponse response) {
        // 处理天
        if (requestVo.getExportFlag().equals(NOW)) {
            return getDayReportTableResponseVo(requestVo, response);
        }
//        // 处理月
//        else if (requestVo.getExportFlag().equals(MONTH)) {
//            return getMonthReportTableResponseVo(requestVo, response);
//        }

        return null;
    }

    private List<ReportViewResponseVo> getMonthReportTableResponseVo(ReportViewRequestVo requestVo, HttpServletResponse response) {
        // 获取当月到目前为止的所有数据
        List<String> dayList = getAllDaysOfTheMonth();
//        for (String date : dayList) {
//            getDayReportTableResponseVo(date, response);
//        }
        return null;
    }

    private List<String> getAllDaysOfTheMonth() {
        // 获取当前日期
        LocalDate currentDate = LocalDate.now();

        // 获取当前月份
        YearMonth currentMonth = YearMonth.from(currentDate);
        int nowDay = Integer.parseInt(ConstDateUtil.formatDate("dd"));
        // 构建日期集合
        List<String> datesInMonth = new ArrayList<>();
        for (int day = 1; day <= nowDay; day++) {
            String date = currentMonth.atDay(day).toString();
            datesInMonth.add(date);
        }
        return datesInMonth;
    }


    private List<ReportViewResponseVo> getDayReportTableResponseVo(ReportViewRequestVo vo, HttpServletResponse response) {
        // 签到数据
        List<DriverScheduling> toDay = schedulingMapper.queryToDay(vo.getDate(), vo.getName(), vo.getJobCode(), vo.getLineName());
        toDay.sort(Comparator.comparing(DriverScheduling::getFcsjT));
        // 转换日期 + jobCode为key
        Map<String, List<DriverScheduling>> orangeMap = new HashMap<>(1200);
        transformMapByDriverScheduling(vo, toDay, orangeMap);
        Map<String, ReportViewResponseVo> resultMap = new HashMap<>(1200);
        for (String key : orangeMap.keySet()) {
            List<DriverScheduling> list = orangeMap.get(key);
            // 如果有选超时过滤的话过滤
            if (filterReportVoList(vo.getStage(), list)) {
                continue;
            }
            ReportViewResponseVo vo1 = new ReportViewResponseVo();
            handlerScheduling(list, vo1);
            resultMap.put(key, vo1);
        }
        return new ArrayList<>(resultMap.values());
    }

    private static void transformMapByDriverScheduling(ReportViewRequestVo vo, List<DriverScheduling> toDay, Map<String, List<DriverScheduling>> orangeMap) {
        for (DriverScheduling scheduling : toDay) {
            String key = vo.getDate() + scheduling.getJobCode();
            if (Objects.isNull(orangeMap.get(key))) {
                orangeMap.put(key, new ArrayList<>(Arrays.asList(scheduling)));
            } else {
                orangeMap.get(key).add(scheduling);
            }
        }
    }

    private boolean filterReportVoList(Integer stage, List<DriverScheduling> list) {
        if (!stage.equals(0)) {
            return handleReportScrollViewTable(stage, list);
        }
        return false;
    }

    private boolean handleReportScrollViewTable(Integer stage, List<DriverScheduling> list) {
        if (list.size() < stage) {
            return true;
        }

        if (Objects.isNull(list.get(stage - 1).getSignTime())) {
            return false;
        }

        DriverScheduling scheduling = list.get(stage - 1);
        // 获取两个 Date 对象之间的时间差(以毫秒为单位)
        long timeDifferenceInMillis = scheduling.getSignTime().getTime() - (scheduling.getBcType().equals(BC_TYPE_OUT) ? scheduling.getFcsjT() : scheduling.getZdsjT());
        // 相差十五分钟
        if (timeDifferenceInMillis > 0 && timeDifferenceInMillis < (60 * 1000 * 15)) {
            return true;
        } else if (timeDifferenceInMillis <= 0) {
            return true;
        }
        return false;
    }

    private static void handlerScheduling(List<DriverScheduling> list, ReportViewResponseVo vo) {
        int planSignInCount = 0;
        int actualSignInCount = 0;
        int planSignOutCount = 0;
        int actualSignOutCount = 0;
        BeanUtils.copyProperties(list.get(0), vo);
        String exString = NO_EX;
        for (DriverScheduling scheduling : list) {
            // 获取计划签到|签退次数
            if (scheduling.getBcType().equals(BC_TYPE_OUT)) {
                planSignInCount = planSignInCount + 1;
                if (!Objects.isNull(scheduling.getSignInId())) {
                    actualSignInCount = actualSignInCount + 1;
                }

            } else {
                planSignOutCount = planSignOutCount + 1;
                if (!Objects.isNull(scheduling.getSignInId())) {
                    actualSignOutCount = actualSignOutCount + 1;
                }
            }

            // 判断是否异常
            if (!SIGN_NO_EX_NUM.equals(scheduling.getExType())) {
                exString = HAVE_EX;
            }
        }
        vo.setExString(exString);
        vo.setPlanSignInCount(planSignInCount);
        vo.setPlanSignOutCount(planSignOutCount);
        vo.setActualSignInCount(actualSignInCount);
        vo.setActualSignOutCount(actualSignOutCount);
    }

    public List<DriverScheduling> queryToDay(String date) {
        return schedulingMapper.queryToDay(date, null, null, null);
    }
}