RuleNumSettingServiceImpl.java 18.2 KB
package com.ruoyi.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.cache.NowSchedulingCache;
import com.ruoyi.domain.DriverScheduling;
import com.ruoyi.domain.RuleAttendanceMain;
import com.ruoyi.domain.RuleAttendanceMainHelp;
import com.ruoyi.domain.RuleNumSetting;
import com.ruoyi.driver.mapper.DriverSchedulingMapper;
import com.ruoyi.mapper.RuleNumSettingMapper;
import com.ruoyi.num.service.IRuleNumService;
import com.ruoyi.pojo.dto.AttendanceDto;
import com.ruoyi.pojo.dto.RuleNumDto;
import com.ruoyi.pojo.dto.RuleSchedulingDto;
import com.ruoyi.pojo.vo.SchedulingRequestVo;
import com.ruoyi.pojo.vo.SchedulingResponseVo;
import com.ruoyi.scheduling.service.IRuleSchedulingService;
import com.ruoyi.service.RuleAttendanceMainHelpService;
import com.ruoyi.service.RuleAttendanceMainService;
import com.ruoyi.service.RuleNumSettingService;
import com.ruoyi.utils.ConstDateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

import static com.ruoyi.common.ConstDriverProperties.BC_TYPE_IN;
import static com.ruoyi.common.ConstDriverProperties.BC_TYPE_OUT;
import static com.ruoyi.common.RuleSchedulingProperties.*;

/**
 * @author 20412
 * @description 针对表【rule_num_setting(排班设置表)】的数据库操作Service实现
 * @createDate 2023-08-31 09:31:28
 */
@Service
public class RuleNumSettingServiceImpl extends ServiceImpl<RuleNumSettingMapper, RuleNumSetting>
        implements RuleNumSettingService {

    private final static Logger log = LoggerFactory.getLogger(RuleNumSettingServiceImpl.class);
    @Autowired
    private RuleAttendanceMainHelpService helpService;
    @Autowired
    private IRuleSchedulingService schedulingService;

    @Autowired
    private RuleNumSettingService ruleNumSettingService;

    @Autowired
    private IRuleNumService ruleNumService;

    @Autowired
    private RuleAttendanceMainService attendanceMainService;

    @Autowired
    private DriverSchedulingMapper schedulingMapper;

    @Resource
    private NowSchedulingCache nowSchedulingCache;

    @Override
    public List<SchedulingResponseVo> getSchedulingList(SchedulingRequestVo vo) {
        return baseMapper.getSchedulingList(vo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createAttendance() {
        // 临时表根据工号生成一个月的模板,固定下来,每天生成一次,如果当前月内的工号已经生成了一次排班,则跳过生成
        // 用户可以修改临时排班表的数据,只能修改未来一个月内的数据   过一天后把数据存储到考勤表,
        // 获取需要生成的人员工号
        try {
            log.info("开始生成排班明细");
            List<AttendanceDto> peopleList = baseMapper.getPeopleList();
            List<Integer> settingList = peopleList.stream().map(AttendanceDto::getSettingId).distinct().collect(Collectors.toList());
            // 获取规则集合
            List<RuleSchedulingDto> ruleList = schedulingService.selectRuleSchedulingListVoBySettingIds(settingList);
            // 获取班次
            List<RuleNumDto> ruleNumDtoList = ruleNumSettingService.selectRuleNumBySettingId(settingList);
            // 处理规则
            List<LocalDate> dateList = ConstDateUtil.getDateSetFromTheCurrentDayToTheEndOfTheMonth();
            List<RuleAttendanceMain> attendanceMains = handleAttendanceMain(peopleList, ruleList, ruleNumDtoList, dateList);
            attendanceMainService.saveBatch(attendanceMains);
            log.info("排班明细生成完毕");
        } catch (Exception e) {
            log.error("排班明细生成失败,失败原因:{}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    private void backCreatePeopleListLog(List<AttendanceDto> peopleList, Map<Integer, RuleNumDto> ruleNumDtoList) {
        List<RuleAttendanceMainHelp> helpList = new ArrayList<>(peopleList.size());
        Date date = new Date();
        for (AttendanceDto dto : peopleList) {
            RuleAttendanceMainHelp help = new RuleAttendanceMainHelp();
            BeanUtils.copyProperties(dto, help);
            help.setDateFlag(date);
            help.setRuleDictName(ruleNumDtoList.get(dto.getSettingId()).getRuleDictName());
            helpList.add(help);
        }
        helpService.saveBatch(helpList);
    }

    private List<RuleAttendanceMain> handleAttendanceMain(List<AttendanceDto> peopleList, List<RuleSchedulingDto> ruleList, List<RuleNumDto> ruleNumDtoList, List<LocalDate> dateList) {
        if (CollectionUtil.isEmpty(peopleList)) {
            return null;
        }
        Map<Integer, List<AttendanceDto>> peopleMap = transformMapByPeople(peopleList);
        Map<Integer, RuleNumDto> ruleNumMap = transformMapByRuleNum(ruleNumDtoList);
        Map<Integer, List<RuleSchedulingDto>> ruleMap = transformMapByRule(ruleList);
        List<RuleAttendanceMain> ruleAttendanceMainList = new ArrayList<>();
        for (Map.Entry<Integer, List<AttendanceDto>> entry : peopleMap.entrySet()) {
            Integer settingId = entry.getKey();
            List<AttendanceDto> attendanceDtoList = entry.getValue();
            RuleNumDto dto = ruleNumMap.get(settingId);
            List<RuleAttendanceMain> mainList = new ArrayList<>(entry.getValue().size() * dateList.size());
            for (AttendanceDto attendanceDto : attendanceDtoList) {
                for (LocalDate date : dateList) {
                    // 处理固定规则翻班
                    if (RULE_TYPE_FIXED.equals(dto.getRuleType())) {
                        handleFixed(date, mainList, ruleMap.get(settingId), attendanceDto, dto.getRuleDictName());
                    }
                    // 处理星期翻班
                    else {
                        handleWeek(date, mainList, ruleMap.get(settingId), attendanceDto, dto.getRuleDictName());
                    }
                }
            }
            ruleAttendanceMainList.addAll(mainList);
        }
        backCreatePeopleListLog(peopleList, ruleNumMap);
        return ruleAttendanceMainList;
    }

    private void handleWeek(LocalDate date, List<RuleAttendanceMain> mainList, List<RuleSchedulingDto> ruleSchedulingDtoList, AttendanceDto attendanceDto, String ruleDictName) {
        RuleAttendanceMain main = new RuleAttendanceMain();
        main.setSchedulingDate(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()));
        main.setPosts(attendanceDto.getPosts());
        main.setRuleDictName(ruleDictName);
        main.setFleetName(attendanceDto.getFleetName());
        RuleSchedulingDto dto = null;
        dto = getRuleByWeek(main, ruleSchedulingDtoList, date, attendanceDto.getStartDate());
        main.setWorkFlag(dto.getId() == 0 ? FREE_FLAG : WORK_FLAG);
        BeanUtils.copyProperties(dto, main);
        main.setName(attendanceDto.getName());
        main.setJobCode(attendanceDto.getJobCode());
        handleSegmentationByDate(date, main, dto);
        mainList.add(main);
    }

    public static void handleSegmentationByDate(LocalDate date, RuleAttendanceMain main, RuleSchedulingDto dto) {
        main.setFirstWorkSignInTime(ConstDateUtil.dateAddition(date.toString(), ConstDateUtil.formatDate("HH:mm:ss", main.getFirstWorkSignInTime())));
        // 不存在分段
        if (NO_SEGMENTATION.equals(dto.getSecondFlag())) {
            if (TOMORROW_YES.equals(dto.getFirstSignInDayTomorrow())) {
                main.setFirstQuittingSignInTime(handleTimeTomorrowByRule(date, main.getFirstQuittingSignInTime()));
            } else {
                main.setFirstQuittingSignInTime(ConstDateUtil.dateAddition(date.toString(), ConstDateUtil.formatDate("HH:mm:ss", main.getFirstQuittingSignInTime())));
            }
        }
        // 存在分段
        else {
            main.setFirstQuittingSignInTime(ConstDateUtil.dateAddition(date.toString(), ConstDateUtil.formatDate("HH:mm:ss", main.getFirstQuittingSignInTime())));
            main.setSecondWorkSignInTime(ConstDateUtil.dateAddition(date.toString(), ConstDateUtil.formatDate("HH:mm:ss", main.getSecondWorkSignInTime())));
            if (TOMORROW_YES.equals(dto.getFirstSignInDayTomorrow())) {
                main.setSecondQuittingSignInTime(handleTimeTomorrowByRule(date, main.getSecondQuittingSignInTime()));
            } else {
                main.setSecondQuittingSignInTime(ConstDateUtil.dateAddition(date.toString(), ConstDateUtil.formatDate("HH:mm:ss", main.getSecondQuittingSignInTime())));
            }
        }
    }

    private static RuleSchedulingDto getRuleByWeek(RuleAttendanceMain main, List<RuleSchedulingDto> ruleSchedulingDtoList, LocalDate nowDate, Date startDate) {
        RuleSchedulingDto dto = null;
        switch (nowDate.getDayOfWeek().toString()) {
            case "MONDAY":
                dto = ruleSchedulingDtoList.get(0);
                break;
            case "TUESDAY":
                dto = ruleSchedulingDtoList.get(1);
                break;
            case "WEDNESDAY":
                dto = ruleSchedulingDtoList.get(2);
                break;
            case "THURSDAY":
                dto = ruleSchedulingDtoList.get(3);
                break;
            case "FRIDAY":
                dto = ruleSchedulingDtoList.get(4);
                break;
            case "SATURDAY":
                dto = ruleSchedulingDtoList.get(5);
                break;
            case "SUNDAY":
                dto = ruleSchedulingDtoList.get(6);
                break;
        }
        LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        int daysDifference = new Long(ChronoUnit.DAYS.between(start, nowDate)).intValue();
        if (daysDifference < 0) {
            return getFreeRuleSchedulingDto(startDate);
        }
        return dto;
    }

    private void handleFixed(LocalDate nowDate, List<RuleAttendanceMain> mainList, List<RuleSchedulingDto> ruleSchedulingDtoList, AttendanceDto attendanceDto, String ruleDictName) {
        RuleAttendanceMain main = new RuleAttendanceMain();
        main.setPosts(attendanceDto.getPosts());
        main.setRuleDictName(ruleDictName);
        main.setSchedulingDate(Date.from(nowDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
        main.setFleetName(attendanceDto.getFleetName());
        Date startDate = attendanceDto.getStartDate();
        // 匹配当天应设置的规则
        RuleSchedulingDto dto = getNowRuleByFixed(nowDate, startDate, ruleSchedulingDtoList);
        main.setWorkFlag(dto.getId() == 0 ? FREE_FLAG : WORK_FLAG);
        BeanUtils.copyProperties(dto, main);
        main.setName(attendanceDto.getName());
        main.setJobCode(attendanceDto.getJobCode());
        // 处理是否分段
        handleSegmentationByDate(nowDate, main, dto);
        mainList.add(main);
    }


    private RuleSchedulingDto getNowRuleByFixed(LocalDate nowDate, Date startDate, List<RuleSchedulingDto> ruleSchedulingDtoList) {
        LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        int daysDifference = new Long(ChronoUnit.DAYS.between(start, nowDate)).intValue();
        if (daysDifference < 0) {
            return getFreeRuleSchedulingDto(startDate);
        }
        int length = ruleSchedulingDtoList.size();
        return ruleSchedulingDtoList.get(daysDifference % length);
    }

    /**
     * 获取休息rule
     *
     * @param startDate
     * @return
     */
    public static RuleSchedulingDto getFreeRuleSchedulingDto(Date startDate) {
        RuleSchedulingDto dto = new RuleSchedulingDto();
        dto.setId(0L);
        dto.setRuleName("休息");
        dto.setWorkingHourPlan(WORK_HOUR_PLAN_NORMAL);
        dto.setWorkingHourType(WORK_HOUR_TYPE_ELASTIC);
        dto.setFirstQuittingSignInTime(startDate);
        dto.setFirstWorkSignInTime(startDate);
        dto.setSecondFlag(NO_SEGMENTATION);
        dto.setFirstSignInQuittingRange(0);
        dto.setFirstSignInWorkingRange(0);
        dto.setSignInTimeOutRange(0);
        return dto;
    }


    private static Date handleTimeTomorrowByRule(LocalDate date, Date time) {
        // 隔天日期需要加1
        return ConstDateUtil.dateAddition(date.plusDays(1).toString(), ConstDateUtil.formatDate("HH:mm:ss", time));
    }


    private Map<Integer, RuleNumDto> transformMapByRuleNum(List<RuleNumDto> ruleNumDtoList) {
        Map<Integer, RuleNumDto> map = new HashMap<>(16);
        for (RuleNumDto ruleNumDto : ruleNumDtoList) {
            map.put(ruleNumDto.getSettingId(), ruleNumDto);
        }
        return map;
    }

    private Map<Integer, List<RuleSchedulingDto>> transformMapByRule(List<RuleSchedulingDto> ruleList) {
        Map<Integer, List<RuleSchedulingDto>> map = new HashMap<>(16);
        for (RuleSchedulingDto dto : ruleList) {
            List<RuleSchedulingDto> dtoList = map.get(dto.getSettingId());
            if (CollectionUtil.isEmpty(dtoList)) {
                map.put(dto.getSettingId(), new ArrayList<>(Arrays.asList(dto)));
            } else {
                dtoList.add(dto);
            }
        }
        for (Map.Entry<Integer, List<RuleSchedulingDto>> entry : map.entrySet()) {
            entry.getValue().sort(Comparator.comparing(RuleSchedulingDto::getSort));
        }
        return map;
    }

    private Map<Integer, List<AttendanceDto>> transformMapByPeople(List<AttendanceDto> peopleList) {
        Map<Integer, List<AttendanceDto>> map = new HashMap<>(16);
        for (AttendanceDto dto : peopleList) {
            List<AttendanceDto> dtoList = map.get(dto.getSettingId());
            if (CollectionUtil.isEmpty(dtoList)) {
                map.put(dto.getSettingId(), new ArrayList<>(Arrays.asList(dto)));
            } else {
                dtoList.add(dto);
            }
        }
        return map;
    }

    @Override
    public List<RuleNumDto> selectRuleNumBySettingId(List<Integer> settingList) {
        if (CollectionUtil.isEmpty(settingList)) {
            return new ArrayList<>();
        }
        return ruleNumService.selectRuleNumBySettingId(settingList);
    }

    @Override
    public void manualAddBcCache() {
        List<DriverScheduling> bcList = handleOtherPostsScheduling();
        schedulingMapper.insertRoster(bcList);
        bcList = schedulingMapper.queryToDay(ConstDateUtil.formatDate("yyyy-MM-dd"), null, null, null);
        String date = ConstDateUtil.formatDate(new Date());
        Map<String, List<DriverScheduling>> resultMap = new HashMap<>(800);
        NowSchedulingCache.handlerResultMap(resultMap, bcList);
        Map<String, List<DriverScheduling>> cacheScheduling = nowSchedulingCache.getCacheScheduling(date);
        for (Map.Entry<String, List<DriverScheduling>> entry : cacheScheduling.entrySet()) {
            String key = entry.getKey();
            if (!Objects.isNull(resultMap.get(key))) {
                resultMap.remove(key);
            }
        }
        cacheScheduling.putAll(resultMap);
    }

    @Override
    public List<AttendanceDto> getPeopleListByMonth(String month) {
        return baseMapper.getPeopleListByMonth(month);
    }

    private List<DriverScheduling> handleOtherPostsScheduling() {
        QueryWrapper<RuleAttendanceMain> qw = new QueryWrapper<>();
        qw.lambda()
                .eq(RuleAttendanceMain::getWorkFlag, WORK_FLAG)
                .eq(RuleAttendanceMain::getSchedulingDate, LocalDate.now());
        List<RuleAttendanceMain> mainList = attendanceMainService.list(qw);
        List<DriverScheduling> bcList = new ArrayList<>(mainList.size() * 2);
        for (RuleAttendanceMain ruleAttendanceMain : mainList) {
            // 第一段
            DriverScheduling scheduling = getDriverScheduling(ruleAttendanceMain);
            scheduling.setFcsjT(ruleAttendanceMain.getFirstWorkSignInTime().getTime());
            scheduling.setBcType(BC_TYPE_OUT);
            scheduling.setZdsjT(ruleAttendanceMain.getFirstWorkSignInTime().getTime());
            scheduling.setScheduleDate(ruleAttendanceMain.getSchedulingDate());
            bcList.add(scheduling);

            DriverScheduling scheduling1 = getDriverScheduling(ruleAttendanceMain);
            scheduling1.setBcType(BC_TYPE_IN);
            scheduling1.setZdsjT(ruleAttendanceMain.getFirstQuittingSignInTime().getTime());
            scheduling1.setFcsjT(ruleAttendanceMain.getFirstQuittingSignInTime().getTime());
            scheduling1.setScheduleDate(ruleAttendanceMain.getSchedulingDate());
            bcList.add(scheduling1);
            // 第二段
            if (!Objects.isNull(ruleAttendanceMain.getSecondWorkSignInTime())) {
                DriverScheduling scheduling2 = getDriverScheduling(ruleAttendanceMain);
                scheduling2.setBcType(BC_TYPE_OUT);
                scheduling2.setFcsjT(ruleAttendanceMain.getSecondWorkSignInTime().getTime());
                scheduling2.setZdsjT(ruleAttendanceMain.getSecondWorkSignInTime().getTime());
                scheduling2.setScheduleDate(ruleAttendanceMain.getSchedulingDate());
                bcList.add(scheduling2);

                DriverScheduling scheduling3 = getDriverScheduling(ruleAttendanceMain);
                scheduling3.setBcType(BC_TYPE_IN);
                scheduling3.setFcsjT(ruleAttendanceMain.getSecondQuittingSignInTime().getTime());
                scheduling3.setZdsjT(ruleAttendanceMain.getSecondQuittingSignInTime().getTime());
                scheduling3.setScheduleDate(ruleAttendanceMain.getSchedulingDate());
                bcList.add(scheduling3);
            }
        }
        return bcList;
    }

    private static DriverScheduling getDriverScheduling(RuleAttendanceMain ruleAttendanceMain) {
        DriverScheduling scheduling = new DriverScheduling();
        scheduling.setPosts(ruleAttendanceMain.getPosts());
        scheduling.setJobCode(ruleAttendanceMain.getJobCode());
        scheduling.setName(ruleAttendanceMain.getName());
        scheduling.setFleetName(ruleAttendanceMain.getFleetName());
        return scheduling;
    }

}