package com.xiaopeng.maintenance.service.impl; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xiaopeng.api.model.maintenance.XpCheckLocation; import com.xiaopeng.api.model.maintenance.XpClockIn; import com.xiaopeng.api.model.maintenance.XpShift; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.utils.DateUtils; import com.xiaopeng.common.core.utils.GeodesyUtil; import com.xiaopeng.maintenance.dto.ClockDTO; import com.xiaopeng.maintenance.dto.VerifyRangeDTO; import com.xiaopeng.maintenance.mapper.XpCheckLocationMapper; import com.xiaopeng.maintenance.mapper.XpClockInMapper; import com.xiaopeng.maintenance.mapper.XpShiftMapper; import com.xiaopeng.maintenance.service.IXpClockInService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.Map; import lombok.extern.slf4j.Slf4j; import java.util.Objects; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.List; /** *

* 打卡明细 服务实现类 *

* * @author mitao * @since 2026-02-03 */ @Slf4j @Service public class XpClockInServiceImpl extends ServiceImpl implements IXpClockInService { @Autowired private XpCheckLocationMapper xpCheckLocationMapper; @Autowired private XpShiftMapper xpShiftMapper; @Autowired private XpClockInMapper xpClockInMapper; @Override public Boolean verifyRange(VerifyRangeDTO dto) { XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(dto.getLocationId()); Map distance = GeodesyUtil.getDistance(dto.getUserLon()+","+dto.getUserLat(), xpCheckLocation.getLocationLon()+","+xpCheckLocation.getLocationLat()); if (null != distance) { Double distance1 = distance.get("WGS84"); if (BigDecimal.valueOf(distance1).compareTo(xpCheckLocation.getLocationRange())>0) { return false; }else { return true; } } else { log.error("调用高德计算距离出错"); return false; } } @Override public R clockIn(ClockDTO dto) { XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(dto.getLocationId()); Map distance = GeodesyUtil.getDistance(dto.getUserLon()+","+dto.getUserLat(), xpCheckLocation.getLocationLon()+","+xpCheckLocation.getLocationLat()); if (null != distance) { Double distance1 = distance.get("WGS84"); if (BigDecimal.valueOf(distance1).compareTo(xpCheckLocation.getLocationRange()) > 0) { return R.fail("不在打卡范围内"); } }else { return R.fail("打卡失败"); } // 查询班次 XpShift xpShift = xpShiftMapper.selectById(dto.getShiftId()); if (null == xpShift) { return R.fail("班次不存在"); } // 开始打卡时间 String startTime = xpShift.getStartTime(); LocalDateTime startLocalDateTime = DateUtils.stringToLocalDateTime(LocalDate.now() + " " + startTime + ":00"); XpClockIn xpClockIn = new XpClockIn(); xpClockIn.setAppUserId(dto.getOperationsUserId()); xpClockIn.setClockInTime(LocalDateTime.now()); xpClockIn.setClockInLon(dto.getUserLon()); xpClockIn.setClockInLat(dto.getUserLat()); xpClockIn.setShiftId(dto.getShiftId()); if (xpClockIn.getClockInTime().isAfter(startLocalDateTime)) { xpClockIn.setClockInResult(2); }else { xpClockIn.setClockInResult(1); } this.save(xpClockIn); return R.ok(); } @Override public R clockOut(ClockDTO dto) { XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(dto.getLocationId()); Map distance = GeodesyUtil.getDistance(dto.getUserLon()+","+dto.getUserLat(), xpCheckLocation.getLocationLon()+","+xpCheckLocation.getLocationLat()); if (null != distance) { Double distance1 = distance.get("WGS84"); if (BigDecimal.valueOf(distance1).compareTo(xpCheckLocation.getLocationRange()) > 0) { return R.fail("不在打卡范围内"); } }else { return R.fail("打卡失败"); } // 查询上班打卡信息 XpClockIn xpClockIn = xpClockInMapper.selectOne(Wrappers.lambdaQuery(XpClockIn.class) .eq(XpClockIn::getAppUserId, dto.getOperationsUserId()) .likeRight(XpClockIn::getClockInTime, LocalDate.now()) .last("LIMIT 1")); if(Objects.isNull(xpClockIn)){ return R.fail("请先上班打卡"); } // 查询班次 XpShift xpShift = xpShiftMapper.selectById(xpClockIn.getShiftId()); if (null == xpShift) { return R.fail("班次不存在"); } // 开始打卡时间 String endTime = xpShift.getEndTime(); LocalDateTime endLocalDateTime = DateUtils.stringToLocalDateTime(LocalDate.now() + " " + endTime + ":00"); xpClockIn.setClockOutTime(LocalDateTime.now()); xpClockIn.setClockOutLon(dto.getUserLon()); xpClockIn.setClockOutLat(dto.getUserLat()); if (xpClockIn.getClockOutTime().isBefore(endLocalDateTime)) { xpClockIn.setClockInResult(2); }else { xpClockIn.setClockInResult(1); } this.updateById(xpClockIn); return R.ok(); } @Override public Boolean checkWorkStatus(Long appUserId) { if (appUserId == null) { log.warn("检查上班状态失败: appUserId 为空"); return false; } try { // 1. 计算当天时间范围 LocalDateTime startTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN); // 00:00:00 LocalDateTime endTime = LocalDateTime.of(LocalDate.now(), LocalTime.MAX); // 23:59:59 // 2. 计算分表后缀 (userId % 10) Integer tableSuffix = (int) (appUserId % 10); // 3. 查询当天打卡记录 List records = baseMapper.selectTodayClockInRecords( tableSuffix, appUserId, startTime, endTime ); // 4. 判断上班状态 if (records == null || records.isEmpty()) { // 无打卡记录 = 未上班 log.debug("用户 {} 今日无打卡记录, workFlag=false", appUserId); return false; } else if (records.size() == 1) { // 1条记录 = 已上班未下班 log.debug("用户 {} 今日打卡1次, workFlag=true", appUserId); return true; } else { // 2条及以上记录 = 已下班 log.debug("用户 {} 今日打卡{}次, workFlag=false", appUserId, records.size()); return false; } } catch (Exception e) { log.error("检查用户上班状态异常, appUserId={}", appUserId, e); // 异常情况返回 false return false; } } }