ReportService.java 16.7 KB
package com.ruoyi.service;

import cn.hutool.core.collection.CollectionUtil;
import com.ruoyi.common.global.Result;
import com.ruoyi.common.global.ResultCode;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.driver.mapper.DriverMapper;
import com.ruoyi.driver.mapper.DriverSchedulingMapper;
import com.ruoyi.eexception.mapper.EquipmentExceptionMapper;
import com.ruoyi.in.mapper.SignInMapper;
import com.ruoyi.domain.DriverScheduling;
import com.ruoyi.pojo.request.ReportViewRequestVo;
import com.ruoyi.pojo.request.ReportErrorRequestVo;
import com.ruoyi.pojo.response.*;
import com.ruoyi.pojo.vo.PersonSignDataResponseVo;
import com.ruoyi.system.domain.SysNotice;
import com.ruoyi.system.service.ISysNoticeService;
import com.ruoyi.utils.ConstDateUtil;
import com.ruoyi.utils.ToolUtils;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.ruoyi.common.ApiProperties.PERSONNEL_API_KEY;
import static com.ruoyi.common.ConstDriverProperties.BC_TYPE_OUT;
import static com.ruoyi.common.ConstSignInConstSignInProperties.*;
import static com.ruoyi.common.ReportProperties.*;

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

    @Autowired
    private SignInMapper signInMapper;

    @Autowired
    private ISysNoticeService noticeService;

    @Autowired
    private EquipmentExceptionMapper exceptionMapper;

    @Autowired
    private DriverMapper driverMapper;

    @Resource
    private SchedulingService schedulingService;

    @Autowired
    private DriverSchedulingMapper schedulingMapper;

    /**
     * 查询报表信息
     */
    public List<ReportViewResponseVo> getReportScrollViewTable(ReportViewRequestVo requestVo, HttpServletResponse response) {
        List<ReportViewResponseVo> reportScrollViewTable = schedulingService.queryReportTableResponseVo(requestVo, response);
        return reportScrollViewTable;
    }

    public List<ReportErrorResponseVo> getErrorReportList(ReportErrorRequestVo request) {
        List<EquipmentExceptionResponseVo> list = exceptionMapper.selectEquipmentExceptionListByVo(request);
        return list.stream().map(item -> {
            ReportErrorResponseVo vo = new ReportErrorResponseVo();
            vo.setRemark(item.getRemark());
            vo.setName(item.getPersonnelName());
            vo.setSiteName(item.getSiteName());
            vo.setImage(item.getImage());
            vo.setJobCode(item.getJobCode());
            vo.setDeviceId(item.getDeviceId());
            vo.setExType(item.getExType());
            vo.setCreateTime(item.getCreateTime());
            vo.setTitle(item.getTitle());
            vo.setNbbm(item.getNbbm());
            vo.setFleetName(item.getFleetName());
            vo.setLineName(item.getLineName());
            vo.setPlanTime(item.getPlanTime());
            return vo;
        }).collect(Collectors.toList());
    }


    public List<ExportReportViewResponseVo> exportReportList(ReportViewRequestVo requestVo, HttpServletResponse response) {
        //  处理天
        if (requestVo.getExportFlag().equals(DAY)) {
            return getDayReportTableResponseVo(requestVo.getDate());
        }
        // 处理月
        else if (requestVo.getExportFlag().equals(MONTH)) {
            return getMonthReportTableResponseVo(requestVo);
        }
        // 处理导出任意时间段  后台追加限制条件 366 天为最长导出时间
        else if (requestVo.getExportFlag().equals(TIME_PERIOD)) {
            return getTimePeriodReportTableResponseVo(requestVo);
        }
        return null;
    }

    private List<ExportReportViewResponseVo> getTimePeriodReportTableResponseVo(ReportViewRequestVo requestVo) {
        String startDate = requestVo.getStartDate();
        String endDate = requestVo.getEndDate();
        LocalDate startLocalDate = LocalDate.parse(startDate);
        LocalDate endLocalDate = LocalDate.parse(endDate);

        long days = ChronoUnit.DAYS.between(startLocalDate, endLocalDate);
        long timePeriod = 366;
        if (days > timePeriod) {
            throw new RuntimeException("时间段不能超过" + timePeriod + "天");
        }
        List<ExportReportViewResponseVo> voList = new ArrayList<>();
        // 分段查询
        spiteQueryResult(startLocalDate, endLocalDate, voList);

        return voList;
    }

    private void spiteQueryResult(LocalDate startLocalDate, LocalDate endLocalDate, List<ExportReportViewResponseVo> voList) {
        // 1 时间按月分段
        String split = "p";
        List<String> localDates = splitByMonth(startLocalDate, endLocalDate, split);
        // 2 按月创建多线程
        ExecutorService pool = Executors.newFixedThreadPool(localDates.size());
        // 3
        for (String date : localDates) {
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    String[] dateSplit = date.split(split);
                    List<DriverScheduling> vos = schedulingMapper.queryByMonth(dateSplit[0], dateSplit[1]);
                    Map<String, List<DriverScheduling>> resultMap = new HashMap<>();
                    handlerResultMap(resultMap, vos);
                    handleResultList(voList, resultMap);
                }
            });
        }
        pool.shutdown();
        try {
            // 等待所有任务执行完毕或超时
            pool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException("导出失败,请尝试刷新页面重新导出或者联系管理员");
        }
    }

    private static List<String> splitByMonth(LocalDate startDate, LocalDate endDate, String split) {
        List<String> dates = new ArrayList<>();
        LocalDate currentMonthStart = startDate;
        LocalDate currentMonthEnd;
        while (currentMonthStart.isBefore(endDate) || currentMonthStart.isEqual(endDate)) {
            currentMonthEnd = currentMonthStart.withDayOfMonth(currentMonthStart.lengthOfMonth());
            if (currentMonthEnd.isAfter(endDate)) {
                currentMonthEnd = endDate;
            }
            dates.add(currentMonthStart + split + currentMonthEnd);
            currentMonthStart = currentMonthEnd.plusDays(1);
        }
        return dates;
    }

    private List<ExportReportViewResponseVo> getDayReportTableResponseVo(String date) {
        List<DriverScheduling> schedulingList = schedulingMapper.queryToDay(date, null, null, null);
        Map<String, List<DriverScheduling>> resultMap = new HashMap<>(800);
        List<ExportReportViewResponseVo> vo = new ArrayList<>(800);
        handlerResultMap(date, resultMap, schedulingList);
        handleResultList(vo, resultMap);
        return vo;
    }

    private void handleResultList(List<ExportReportViewResponseVo> vo, Map<String, List<DriverScheduling>> resultMap) {
        for (String key : resultMap.keySet()) {
            resultMap.get(key).sort(Comparator.comparing(DriverScheduling::getFcsjT));
            vo.add(new ExportReportViewResponseVo(resultMap.get(key)));
        }
    }

    private void handlerResultMap(@NotBlank String date, Map<String, List<DriverScheduling>> resultMap, List<DriverScheduling> schedulingList) {
        for (DriverScheduling scheduling : schedulingList) {
            String key = date + scheduling.getJobCode();
            // TODO 特殊处理
            ToolUtils.updateReport(scheduling);
            if (Objects.isNull(resultMap.get(key))) {
                resultMap.put(key, new ArrayList<>(Arrays.asList(scheduling)));
            } else {
                resultMap.get(key).add(scheduling);
            }
        }
    }

    private void handlerResultMap(Map<String, List<DriverScheduling>> resultMap, List<DriverScheduling> schedulingList) {
        for (DriverScheduling scheduling : schedulingList) {
            String key = scheduling.getScheduleDate() + scheduling.getJobCode();
            ToolUtils.updateReport(scheduling);
            if (Objects.isNull(resultMap.get(key))) {
                resultMap.put(key, new ArrayList<>(Arrays.asList(scheduling)));
            } else {
                resultMap.get(key).add(scheduling);
            }
        }
    }

    private List<ExportReportViewResponseVo> getMonthReportTableResponseVo(ReportViewRequestVo requestVo) {
        List<ExportReportViewResponseVo> responseVos = new ArrayList<>(10000);
        List<String> days = getNowMonthAllDay(requestVo.getDate());
        for (String day : days) {
            List<ExportReportViewResponseVo> dayReportTableResponseVo = getDayReportTableResponseVo(day);
            responseVos.addAll(dayReportTableResponseVo);
        }
        return responseVos;
    }

    private List<String> getNowMonthAllDay(@NotBlank String dateString) {
        // 获取当前年月
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate formatDate = LocalDate.parse(dateString, formatter);
        int month = formatDate.getMonthValue();
        int year = formatDate.getYear();
        YearMonth yearMonth = YearMonth.of(year, month);

        // 获取当前月份的第一天和最后一天日期
        LocalDate firstDay = yearMonth.atDay(1);
        LocalDate lastDay = yearMonth.atEndOfMonth();

        // 获取当前月份的所有日期集合
        List<String> datesInMonth = new ArrayList<>();
        LocalDate date = firstDay;
        while (!date.isAfter(lastDay)) {
            datesInMonth.add(date.toString());
            date = date.plusDays(1);
        }
        return datesInMonth;
    }

    public List<ReportDetailResponseVo> getReportDetail(ReportViewRequestVo vo, HttpServletResponse response) {
        List<ReportDetailResponseVo> responseVos = new ArrayList<>();
        List<DriverScheduling> toDay = schedulingMapper.queryToDay(vo.getDate(), vo.getName(), vo.getJobCode(), vo.getLineName());
        for (DriverScheduling scheduling : toDay) {
            ToolUtils.updateReport(scheduling);
            ReportDetailResponseVo reportDetailResponseVo = new ReportDetailResponseVo();
            handlerReportDetail(reportDetailResponseVo, scheduling);
            responseVos.add(reportDetailResponseVo);
        }
        responseVos.sort(Comparator.comparing(ReportDetailResponseVo::getPlanTime));
        return responseVos;
    }

    private void handlerReportDetail(ReportDetailResponseVo reportDetailResponseVo, DriverScheduling scheduling) {
        BeanUtils.copyProperties(scheduling, reportDetailResponseVo);
        reportDetailResponseVo.setPlanAction(scheduling.getBcType().equals(BC_TYPE_OUT) ? SIGN_IN_STRING : SIGN_IN_OUT_STRING);
        reportDetailResponseVo.setPlanTime(scheduling.getBcType().equals(BC_TYPE_OUT) ? new Date(scheduling.getFcsjT()) : new Date(scheduling.getZdsjT()));
        reportDetailResponseVo.setExString(SIGN_NO_EX_NUM.equals(scheduling.getExType()) ? NO_EX : HAVE_EX);

        // 设置操作 当前有操作的
        if (!Objects.isNull(scheduling.getSignInId())) {
            reportDetailResponseVo.setActualTime(scheduling.getSignTime());
            reportDetailResponseVo.setActualAction(scheduling.getSignType().equals(SIGN_IN) ? SIGN_IN_STRING : SIGN_IN_OUT_STRING);
            reportDetailResponseVo.setRemark(scheduling.getRemark());
            reportDetailResponseVo.setAlcoholString(ALCOHOL_FLAG_YES.equals(scheduling.getAlcoholFlag()) ? ALCOHOL_FLAG_YES_STRING : ALCOHOL_FLAG_NO_STRING);
        }
        // 当前无操作
        else {
            reportDetailResponseVo.setRemark(scheduling.getBcType().equals(BC_TYPE_OUT) ? "未签到" : "未签退");
            reportDetailResponseVo.setAlcoholString(ALCOHOL_FLAG_NO_STRING);
        }

    }

    public List<SignInResponseVo> getBigView(ReportViewRequestVo requestVo, HttpServletResponse response) {
        SignInResponseVo vo = new SignInResponseVo();
        vo.setDate(requestVo.getDate());
        vo.setJobCode(requestVo.getJobCode());
        List<SignInResponseVo> vos = signInMapper.selectSignInList(vo);
        return vos;
    }

    public SysNotice getAlarmNoticeByType(Integer type) {
        String username = SecurityUtils.getUsername();
        return noticeService.getAlarmNotice(username, type);
    }

    public Object sureNotice(SysNotice notice) {
        String username = SecurityUtils.getUsername();
        notice.setRemark(notice.getRemark() + "," + username);
        noticeService.updateNotice(notice);
        return null;
    }

    public Result<PersonSignDataResponseVo> listReportMonth(String month, HttpServletRequest request) {
        boolean validateDate = validateDate(month);
        String header = request.getHeader("X-TOKEN-AUTHORIZATION");
        if (!PERSONNEL_API_KEY.equals(header)) {
            return Result.ERROR(ResultCode.CODE_401, "X-TOKEN-AUTHORIZATION value error");
        }
        if (!validateDate) {
            return Result.ERROR(ResultCode.CODE_400, "Parameter format error");
        }
        ReportViewRequestVo vo = new ReportViewRequestVo();
        vo.setDate(month + "-01");
        List<ExportReportViewResponseVo> responseVoList = getMonthReportTableResponseVo(vo);
        PersonSignDataResponseVo responseVo = new PersonSignDataResponseVo();
        handleResponseByDay(responseVoList, responseVo, vo.getDate());
        return Result.OK(responseVo);
    }

    private void handleResponseByDay(List<ExportReportViewResponseVo> responseVoList, PersonSignDataResponseVo voList, @NotBlank String date) {
        List<PersonSignDataResponseVo.SignData> list = voList.getList();
        Map<String, List<ExportReportViewResponseVo>> map = new HashMap<>(30);
        for (ExportReportViewResponseVo vo : responseVoList) {
            String key = ConstDateUtil.formatDate("yyyy-MM-dd", vo.getScheduleDate());
            List<ExportReportViewResponseVo> vos = map.get(key);
            if (CollectionUtil.isEmpty(vos)) {
                map.put(key, new ArrayList<>(Arrays.asList(vo)));
            } else {
                map.get(key).add(vo);
            }
        }
        // 转换对象
        for (Map.Entry<String, List<ExportReportViewResponseVo>> entry : map.entrySet()) {
            PersonSignDataResponseVo.SignData signData = new PersonSignDataResponseVo.SignData();
            signData.setDate(entry.getKey());
            signData.setResponseVoList(entry.getValue());
            list.add(signData);
        }
    }

    /**
     * yyyy-MM 格式的正则表达式
     */
    public static boolean validateDate(String input) {
        String regex = "^(\\d{4})-(0[1-9]|1[0-2])$";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);

        return matcher.matches();
    }

    public Result<PersonSignDataResponseVo> listReportDay(String date, HttpServletRequest request) {
        boolean validateDayDate = validateDayDate(date);
        String header = request.getHeader("X-TOKEN-AUTHORIZATION");
        if (!PERSONNEL_API_KEY.equals(header)) {
            return Result.ERROR(ResultCode.CODE_401, "X-TOKEN-AUTHORIZATION value error");
        }
        if (!validateDayDate) {
            return Result.ERROR(ResultCode.CODE_400, "Parameter format error");
        }
        ReportViewRequestVo vo = new ReportViewRequestVo();
        vo.setDate(date);
        List<ExportReportViewResponseVo> responseVos = new ArrayList<>(10000);
        List<ExportReportViewResponseVo> dayReportTableResponseVo = getDayReportTableResponseVo(date);
        responseVos.addAll(dayReportTableResponseVo);
        PersonSignDataResponseVo responseVo = new PersonSignDataResponseVo();
        handleResponseByDay(responseVos, responseVo, vo.getDate());
        return Result.OK(responseVo);
    }

    /**
     * yyyy-MM 格式的正则表达式
     */
    public static boolean validateDayDate(String input) {
        String regex = "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|\"+\n" +
                "\"((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|\"+\n" +
                "\"((0[48]|[2468][048]|[3579][26])00))-02-29)$";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);

        return matcher.matches();
    }
}