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());
xpClockIn.setClockInAddress(dto.getClockInAddress());
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());
xpClockIn.setClockOutAddress(dto.getClockOutAddress());
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. 查询当天打卡记录
List records = baseMapper.selectTodayClockInRecords(
appUserId, startTime, endTime
);
// 3. 判断上班状态
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;
}
}
}