zhangherong
2025-06-25 23855599412c4d61b38d78f0f3abd3430a48b5b1
lxzn-module-mdc/src/main/java/org/jeecg/modules/mdc/service/impl/MdcEquipmentPunchServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,299 @@
package org.jeecg.modules.mdc.service.impl;
import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.mdc.entity.MdcEquipmentPunch;
import org.jeecg.modules.mdc.mapper.MdcEquipmentPunchMapper;
import org.jeecg.modules.mdc.service.IMdcEquipmentPunchService;
import org.jeecg.modules.mdc.service.IMdcEquipmentService;
import org.jeecg.modules.mdc.util.DateUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
 * @Description: mdc_equipment_punch
 * @Author: jeecg-boot
 * @Date:   2025-06-09
 * @Version: V1.0
 */
@Service
public class MdcEquipmentPunchServiceImpl extends ServiceImpl<MdcEquipmentPunchMapper, MdcEquipmentPunch> implements IMdcEquipmentPunchService {
    @Resource
    private MdcEquipmentPunchMapper mdcEquipmentPunchMapper;
    @Resource
    private IMdcEquipmentService mdcEquipmentService;
    /**
     * æŸ¥è¯¢å½“前登录人所负责设备打卡情况
     * @return
     */
    @Override
    public List<MdcEquipmentPunch> queryList() {
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String userId = user.getId();
        List<String> equipmentIds = Lists.newArrayList();
        if (StringUtils.isNotBlank(user.getEquipmentIds())) {
            equipmentIds = Arrays.asList(user.getEquipmentIds().split(StringPool.COMMA));
        }else {
            equipmentIds = mdcEquipmentService.getEquipmentIdsProduction(userId, null);
        }
        if (CollectionUtils.isEmpty(equipmentIds)) {
            return Lists.newArrayList();
        }
        if (StringUtils.isBlank(userId)) {
            return Lists.newArrayList();
        }
        //根据设备、当前日期查询打卡记录
        List<MdcEquipmentPunch> mdcEquipmentPunches = this.baseMapper.list(equipmentIds, DateUtils.format(new Date(), DatePattern.PURE_DATE_PATTERN));
        return mdcEquipmentPunches;
    }
    /**
     * ä¸Šç­æ‰“卡
     * @param mdcEquipmentPunch
     */
    @Override
    public void workUp(MdcEquipmentPunch mdcEquipmentPunch) {
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String userId = user.getId();
        if (StringUtils.isBlank(mdcEquipmentPunch.getEquipmentId())) {
            throw new JeecgBootException("请选择打卡设备!");
        }
        /**
         * æ ¡éªŒæ˜¯å¦åœ¨æœ‰æ•ˆæ‰“卡范围之内
         *      æ—©ç­ä¸Šç­å¡æœ‰æ•ˆèŒƒå›´ä¸ºï¼š00:00:00 ~ 17:30:00
         *      æ™šç­ä¸Šç­å¡æœ‰æ•ˆèŒƒå›´ä¸ºï¼š00:00:00 ~ 23:00:00
         */
        Date startDate = DateUtils.getFormatDate(
                DateUtils.format(mdcEquipmentPunch.getCheckInTime(), DatePattern.NORM_DATE_PATTERN) + " 00:00:00",
                DatePattern.NORM_DATETIME_PATTERN
        );
        Date endDate = DateUtils.getFormatDate(
                DateUtils.format(mdcEquipmentPunch.getCheckInTime(), DatePattern.NORM_DATE_PATTERN) + " 17:30:00",
                DatePattern.NORM_DATETIME_PATTERN
        );
        if (mdcEquipmentPunch.getShiftSchedule() == 2) {
            //晚班无效打卡时间范围
            endDate = DateUtils.getFormatDate(
                    DateUtils.format(mdcEquipmentPunch.getCheckInTime(), DatePattern.NORM_DATE_PATTERN) + " 23:00:00",
                    DatePattern.NORM_DATETIME_PATTERN
            );
        }
        if (startDate.compareTo(mdcEquipmentPunch.getCheckInTime()) == 1 || endDate.compareTo(mdcEquipmentPunch.getCheckInTime()) == -1) {
            throw new JeecgBootException("未在有效上班打卡时间内,不能打卡!");
        }
        //查询所选设备当天是否已打上班卡
        List<String> equipmentIdList = Arrays.asList(mdcEquipmentPunch.getEquipmentId().split(StringPool.COMMA));
        String currentDate = DateUtils.format(mdcEquipmentPunch.getCheckInTime(), DatePattern.PURE_DATE_PATTERN);
        //早班上班正常最晚打卡时间
        String checkInTime = DateUtils.format(mdcEquipmentPunch.getCheckInTime(), DatePattern.NORM_DATE_PATTERN) + " 08:30:00";
        //查询当前设备、当前打卡类型打卡记录
        List<MdcEquipmentPunch> equipmentPunchList = this.list(new LambdaQueryWrapper<MdcEquipmentPunch>()
                .eq(MdcEquipmentPunch::getShiftSchedule, mdcEquipmentPunch.getShiftSchedule())
                .eq(MdcEquipmentPunch::getRecordDate, currentDate)
                .in(MdcEquipmentPunch::getEquipmentId, equipmentIdList));
        List<MdcEquipmentPunch> mdcEquipmentPunchList = equipmentPunchList.stream().filter(equipmentPunch -> Objects.nonNull(equipmentPunch.getCheckInTime())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(mdcEquipmentPunchList)) {
            List<String> equipmentIds = equipmentPunchList.stream()
                    .filter(mdcEquipmentPunchInfo -> Objects.nonNull(mdcEquipmentPunchInfo.getCheckInTime()))
                    .map(MdcEquipmentPunch::getEquipmentId)
                    .distinct()
                    .collect(Collectors.toList());
            throw new JeecgBootException("设备[" + StringUtils.join(equipmentIds, StringPool.COMMA) + "]已打卡,无需重复打卡");
        }
        List<MdcEquipmentPunch> list = Lists.newArrayList();
        //特殊处理晚班上班卡
        if (mdcEquipmentPunch.getShiftSchedule() == 2) {
            //晚班正常上班卡最晚打卡时间
            checkInTime = DateUtils.format(mdcEquipmentPunch.getCheckInTime(), DatePattern.NORM_DATE_PATTERN) + " 17:00:00";
        }
        for (String equipment : equipmentIdList) {
            Optional<MdcEquipmentPunch> first = equipmentPunchList.stream().filter(equipmentPunch -> Objects.isNull(equipmentPunch.getCheckInTime()) && equipment.equals(equipmentPunch.getEquipmentId())).findFirst();
            MdcEquipmentPunch equipmentPunch = new MdcEquipmentPunch();
            if (first.isPresent()) {
                equipmentPunch = first.get();
                //已存在记录说明已打下班卡,故将是否缺卡置为否
                equipmentPunch.setIsAbsent(0);
            }else {
                equipmentPunch.setEquipmentId(equipment);
                equipmentPunch.setPunchUser(userId);
                equipmentPunch.setRecordDate(currentDate);
                equipmentPunch.setShiftSchedule(mdcEquipmentPunch.getShiftSchedule());
                equipmentPunch.setIsEarly(0);
                //正常打卡时先将是否缺卡置为“是”,防止未打下班卡时无法调整状态
                equipmentPunch.setIsAbsent(1);
            }
            equipmentPunch.setCheckInTime(mdcEquipmentPunch.getCheckInTime());
            //打卡时间大于8:30/17:00时为迟到打卡
            equipmentPunch.setIsLate(mdcEquipmentPunch.getCheckInTime().compareTo(DateUtils.getFormatDate(checkInTime, DatePattern.NORM_DATETIME_PATTERN)) == 1 ? 1 : 0);
            list.add(equipmentPunch);
        }
        this.saveOrUpdateBatch(list);
    }
    @Override
    public void workDown(MdcEquipmentPunch mdcEquipmentPunch) {
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String userId = user.getId();
        if (StringUtils.isBlank(mdcEquipmentPunch.getEquipmentId())) {
            throw new JeecgBootException("请选择打卡设备!");
        }
        /**
         * æ ¡éªŒå½“前下班卡是否在有效下班打卡范围之内
         *      æ—©ç­ä¸‹ç­æ— æ•ˆæ‰“卡时间范围为00:00:00 ~ 08:30:00
         *      æ™šç­ä¸‹ç­æ— æ•ˆæ‰“卡时间范围为00:00:00 ~ 17:00:00
         */
        Date startDate = DateUtils.getFormatDate(
                DateUtils.format(mdcEquipmentPunch.getCheckOutTime(), DatePattern.NORM_DATE_PATTERN) + " 00:00:00",
                DatePattern.NORM_DATETIME_PATTERN
        );
        Date endDate = DateUtils.getFormatDate(
                DateUtils.format(mdcEquipmentPunch.getCheckOutTime(), DatePattern.NORM_DATE_PATTERN) + " 08:30:00",
                DatePattern.NORM_DATETIME_PATTERN
        );
        Date checkOutTime = DateUtils.getFormatDate(
                DateUtils.format(mdcEquipmentPunch.getCheckOutTime(), DatePattern.NORM_DATE_PATTERN) + " 17:30:00",
                DatePattern.NORM_DATETIME_PATTERN
        );
        if (mdcEquipmentPunch.getShiftSchedule() == 2) {
            //晚班无效打卡时间范围
            endDate = DateUtils.getFormatDate(
                    DateUtils.format(mdcEquipmentPunch.getCheckOutTime(), DatePattern.NORM_DATE_PATTERN) + " 17:00:00",
                    DatePattern.NORM_DATETIME_PATTERN
            );
            //晚班正常下班最早打卡时间
            checkOutTime = DateUtils.getFormatDate(
                    DateUtils.format(mdcEquipmentPunch.getCheckOutTime(), DatePattern.NORM_DATE_PATTERN) + " 23:00:00",
                    DatePattern.NORM_DATETIME_PATTERN
            );
        }
        if (startDate.compareTo(mdcEquipmentPunch.getCheckOutTime()) == 1
                || endDate.compareTo(mdcEquipmentPunch.getCheckOutTime()) == 1) {
            throw new JeecgBootException("未在有效下班打卡时间内,不能打卡!");
        }
        //查询当前所选设备是否存在上班打卡记录
        List<String> equipmentIdList = Arrays.asList(mdcEquipmentPunch.getEquipmentId().split(StringPool.COMMA));
        String currentDate = DateUtils.format(mdcEquipmentPunch.getCheckOutTime(), DatePattern.PURE_DATE_PATTERN);
        List<MdcEquipmentPunch> equipmentPunchList = this.list(new LambdaQueryWrapper<MdcEquipmentPunch>()
                .eq(MdcEquipmentPunch::getShiftSchedule, mdcEquipmentPunch.getShiftSchedule())
                .eq(MdcEquipmentPunch::getRecordDate, currentDate)
                .in(MdcEquipmentPunch::getEquipmentId, equipmentIdList));
        List<MdcEquipmentPunch> list = Lists.newArrayList();
        for (String equipmentId : equipmentIdList) {
            Optional<MdcEquipmentPunch> mdcEquipmentPunchOptional = equipmentPunchList.stream()
                    .filter(mdcEquipmentPunch1 -> mdcEquipmentPunch1.getEquipmentId().equals(equipmentId))
                    .findFirst();
            MdcEquipmentPunch equipmentPunch = new MdcEquipmentPunch();
            if (mdcEquipmentPunchOptional.isPresent()) {
                equipmentPunch = mdcEquipmentPunchOptional.get();
                equipmentPunch.setIsAbsent(0);
            }else {
                equipmentPunch.setIsAbsent(1);
                equipmentPunch.setIsLate(0);
                equipmentPunch.setEquipmentId(equipmentId);
                equipmentPunch.setShiftSchedule(mdcEquipmentPunch.getShiftSchedule());
                equipmentPunch.setPunchUser(userId);
                equipmentPunch.setRecordDate(currentDate);
            }
            equipmentPunch.setCheckOutTime(mdcEquipmentPunch.getCheckOutTime());
            //下班打卡时间早于17:30/23:00则为早退
            equipmentPunch.setIsEarly(checkOutTime.compareTo(mdcEquipmentPunch.getCheckOutTime()) == 1 ? 1 : 0);
            list.add(equipmentPunch);
        }
        this.saveOrUpdateBatch(list);
    }
    @Override
    public void fillPunchRates(List<MdcEquipmentPunch> punchList) {
        // èŽ·å–æ˜¨å¤©æ—¥æœŸ
        LocalDate yesterday = LocalDate.now().minusDays(1);
        String yesterdayStr = yesterday.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATE_PATTERN)); // æ ¼å¼åŒ–为 "yyyy-MM-dd"
        // èŽ·å–æ€»è®¾å¤‡æ•°
        int totalDevices = mdcEquipmentPunchMapper.getTotalDeviceCount();
        if (totalDevices == 0) return;
        // ç»Ÿè®¡å„类型打卡人数
        int morningIn = mdcEquipmentPunchMapper.countMorningShiftIn(yesterdayStr);
        int eveningIn = mdcEquipmentPunchMapper.countEveningShiftIn(yesterdayStr);
        int morningOut = mdcEquipmentPunchMapper.countMorningShiftOut(yesterdayStr);
        int eveningOut = mdcEquipmentPunchMapper.countEveningShiftOut(yesterdayStr);
        // è®¾ç½®æ‰“卡率到每个 DTO
        for (MdcEquipmentPunch dto : punchList) {
            dto.setMorningShiftInRate(calculateRate(morningIn, totalDevices));
            dto.setEveningShiftInRate(calculateRate(eveningIn, totalDevices));
            dto.setMorningShiftOutRate(calculateRate(morningOut, totalDevices));
            dto.setEveningShiftOutRate(calculateRate(eveningOut, totalDevices));
            // è®¾ç½®æ‰“卡设备数量字段
            dto.setMorningShiftInDeviceNum(morningIn);
            dto.setMorningShiftOutDeviceNum(morningOut);
            dto.setEveningShiftInDeviceNum(eveningIn);
            dto.setEveningShiftOutDeviceNum(eveningOut);
            dto.setDeviceCountNum(totalDevices);
        }
    }
    // è®¡ç®—百分比并保留两位小数
    private BigDecimal calculateRate(int actual, int total) {
        if (total == 0) return BigDecimal.ZERO;
        return new BigDecimal(actual)
                .divide(new BigDecimal(total), 4, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100))
                .setScale(2, RoundingMode.HALF_UP); // ä¿ç•™ä¸¤ä½å°æ•°
    }
    @Override
    public List<MdcEquipmentPunch> getYesterdayRecords(String  targetDate) {
        // æž„造查询条件:record_date = targetDate.toString()
        QueryWrapper<MdcEquipmentPunch> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("record_date", targetDate);
        // æ‰§è¡ŒæŸ¥è¯¢å¹¶è¿”回结果
        return baseMapper.selectList(queryWrapper);
    }
}