package com.xiaopeng.maintenance.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xiaopeng.api.model.maintenance.XpCheckLocation; import com.xiaopeng.api.model.maintenance.XpCruiseCheckInRecord; import com.xiaopeng.api.model.maintenance.XpCruiseCheckInRule; import com.xiaopeng.api.model.maintenance.XpCruiseCheckInRuleLocation; import com.xiaopeng.common.core.exception.ServiceException; import com.xiaopeng.common.core.utils.GeodesyUtil; import com.xiaopeng.maintenance.constant.I18nKeyConstant; import com.xiaopeng.maintenance.mapper.XpCruiseCheckInRuleMapper; import com.xiaopeng.maintenance.model.vo.AppXpCruiseCheckInLocationVo; import com.xiaopeng.maintenance.model.vo.AppXpCruiseCheckInRuleVo; import com.xiaopeng.maintenance.model.vo.CheckInMessageVo; import com.xiaopeng.maintenance.model.vo.RealTimePositionVo; import com.xiaopeng.maintenance.service.IXpCheckLocationService; import com.xiaopeng.maintenance.service.IXpCruiseCheckInRecordService; import com.xiaopeng.maintenance.service.IXpCruiseCheckInRuleLocationService; import com.xiaopeng.maintenance.service.IXpCruiseCheckInRuleService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service public class XpCruiseCheckInRuleServiceImpl extends ServiceImpl implements IXpCruiseCheckInRuleService { @Resource private IXpCruiseCheckInRecordService xpCruiseCheckInRecordService; @Resource private IXpCruiseCheckInRuleLocationService xpCruiseCheckInRuleLocationService; @Resource private IXpCheckLocationService xpCheckLocationService; @Override public AppXpCruiseCheckInRuleVo getMyXpCruiseCheckInRule(Long uid) { List list = this.list(new LambdaQueryWrapper().eq(XpCruiseCheckInRule::getDeleted, 0) .last(" and (now() BETWEEN start_time and end_time or cyclic_mode = 1)")); if(list.isEmpty()){ return null; } XpCruiseCheckInRule xpCruiseCheckInRule = list.get(0); AppXpCruiseCheckInRuleVo vo = new AppXpCruiseCheckInRuleVo(); vo.setId(xpCruiseCheckInRule.getId()); vo.setCruiseCheckInTaskTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " " + xpCruiseCheckInRule.getStartTime().format(DateTimeFormatter.ofPattern("HH:mm")) + "~" + xpCruiseCheckInRule.getEndTime().format(DateTimeFormatter.ofPattern("HH:mm"))); long count1 = xpCruiseCheckInRuleLocationService.count(new LambdaQueryWrapper() .eq(XpCruiseCheckInRuleLocation::getCruiseCheckInRuleId, xpCruiseCheckInRule.getId())); long count = xpCruiseCheckInRecordService.count(new LambdaQueryWrapper() .eq(XpCruiseCheckInRecord::getCruiseCheckInRuleId, xpCruiseCheckInRule.getId()) .eq(XpCruiseCheckInRecord::getDeleted, 0).eq(XpCruiseCheckInRecord::getOperationsUserId, uid)); vo.setCheckInPointCount(count1); vo.setCheckInPointFinishCount(count); vo.setCheckInPointUnFinishCount(count1 - count); return vo; } /** * 获取APP端签到规则位置信息 * @param ruleId * @param uid * @return */ @Override public List getAppXpCruiseCheckInLocation(Integer ruleId, Long uid) { //查询巡游打卡规则和点位关系数据 List list = xpCruiseCheckInRuleLocationService.list(new LambdaQueryWrapper() .eq(XpCruiseCheckInRuleLocation::getCruiseCheckInRuleId, ruleId).orderByAsc(XpCruiseCheckInRuleLocation::getSort)); //查询打卡点位数据 List xpCheckLocations = xpCheckLocationService.listByIds(list.stream().map(XpCruiseCheckInRuleLocation::getCheckLocationId).collect(Collectors.toList())); List appXpCruiseCheckInLocationVos = new ArrayList<>(); //获取运维人员打卡记录 List list1 = xpCruiseCheckInRecordService.list(new LambdaQueryWrapper() .eq(XpCruiseCheckInRecord::getDeleted, 0) .eq(XpCruiseCheckInRecord::getCruiseCheckInRuleId, ruleId) .eq(XpCruiseCheckInRecord::getOperationsUserId, uid) .last(" and DATE_FORMAT(check_in_time, '%Y-%m-%d') = DATE_FORMAT(NOW(), '%Y-%m-%d")); //构建返回结果 for (XpCruiseCheckInRuleLocation xpCruiseCheckInRuleLocation : list) { XpCruiseCheckInRecord xpCruiseCheckInRecord = list1.stream().filter(x -> x.getCheckLocationId().equals(xpCruiseCheckInRuleLocation.getCheckLocationId())).findFirst().orElse(null); XpCheckLocation xpCheckLocation = xpCheckLocations.stream().filter(x -> x.getId().equals(xpCruiseCheckInRuleLocation.getCheckLocationId())).findFirst().orElse(null); AppXpCruiseCheckInLocationVo vo = new AppXpCruiseCheckInLocationVo(); vo.setLocationId(xpCruiseCheckInRuleLocation.getCheckLocationId()); vo.setTime(xpCruiseCheckInRuleLocation.getStartTime() + "-" + xpCruiseCheckInRuleLocation.getEndTime()); vo.setCheckIn(0); if(null != xpCruiseCheckInRecord){ vo.setCheckInTime(xpCruiseCheckInRecord.getCheckInTime().format(DateTimeFormatter.ofPattern("HH:mm:ss"))); vo.setCheckIn(1); vo.setCheckInResult(xpCruiseCheckInRecord.getCheckInResult()); } vo.setLon(xpCheckLocation.getLocationLon()); vo.setLat(xpCheckLocation.getLocationLat()); vo.setAddress(xpCheckLocation.getLocationAddress()); appXpCruiseCheckInLocationVos.add(vo); } return appXpCruiseCheckInLocationVos; } /** * 运维人员巡游打卡操作 * @param dto */ @Override public void saveCruiseCheckInRecord(XpCruiseCheckInRecord dto) { Long checkLocationId = dto.getCheckLocationId(); XpCruiseCheckInRuleLocation one = xpCruiseCheckInRuleLocationService.getOne(new LambdaQueryWrapper() .eq(XpCruiseCheckInRuleLocation::getCheckLocationId, checkLocationId)); if(null == one){ throw new ServiceException("打卡点位不存在", I18nKeyConstant.CHECK_IN_LOCATION_DOES_NOT_EXIST); } XpCruiseCheckInRecord cruiseCheckInRecord = xpCruiseCheckInRecordService.getOne(new LambdaQueryWrapper() .eq(XpCruiseCheckInRecord::getCruiseCheckInRuleId, one.getCruiseCheckInRuleId()) .eq(XpCruiseCheckInRecord::getDeleted, 0) .eq(XpCruiseCheckInRecord::getCheckLocationId, checkLocationId) .eq(XpCruiseCheckInRecord::getOperationsUserId, dto.getOperationsUserId()) .last(" and DATE_FORMAT(check_in_time, '%Y-%m-%d') = DATE_FORMAT(NOW(), '%Y-%m-%d')")); if(null != cruiseCheckInRecord){ throw new ServiceException("不能重复打卡", I18nKeyConstant.CANNOT_REPEAT_CLOCKING_IN); } dto.setCruiseCheckInRuleId(one.getCruiseCheckInRuleId()); dto.setCheckInTime(LocalDateTime.now()); dto.setCheckInResult(1); //判断当前打卡时间是否超过限定时间 Integer endTime = Integer.valueOf(one.getEndTime().replace(":", "")); Integer nowTime = Integer.valueOf(LocalDateTime.now().format(DateTimeFormatter.ofPattern("HHmm"))); if(nowTime > endTime){ dto.setCheckInResult(2); } dto.setDeleted(false); xpCruiseCheckInRecordService.save(dto); } /** * 运维端实时上传位置信息,返回提醒消息 * @param dto * @return */ @Override public CheckInMessageVo uploadRealTimePosition(RealTimePositionVo dto, Long uid) { List list = xpCruiseCheckInRuleLocationService.list(new LambdaQueryWrapper() .eq(XpCruiseCheckInRuleLocation::getCruiseCheckInRuleId, dto.getId()) .orderByAsc(XpCruiseCheckInRuleLocation::getSort)); if(list.isEmpty()){ return null; } //查找即将需要到达的打卡点位 XpCruiseCheckInRecord cruiseCheckInRecord = xpCruiseCheckInRecordService.getOne(new LambdaQueryWrapper() .eq(XpCruiseCheckInRecord::getCruiseCheckInRuleId, dto.getId()) .eq(XpCruiseCheckInRecord::getDeleted, 0) .eq(XpCruiseCheckInRecord::getOperationsUserId, uid) .last(" and DATE_FORMAT(check_in_time, '%Y-%m-%d') = DATE_FORMAT(NOW(), '%Y-%m-%d') order by check_in_time desc limit 1")); XpCruiseCheckInRuleLocation cruiseCheckInRuleLocation = null; //没有打卡的情况,用第一个打卡点位 if(null == cruiseCheckInRecord){ cruiseCheckInRuleLocation = list.get(0); }else{ Long checkLocationId = cruiseCheckInRecord.getCheckLocationId(); for (int i = 0; i < list.size(); i++) { Long checkLocationId1 = list.get(i).getCheckLocationId(); if(checkLocationId.equals(checkLocationId1) && i < list.size() - 1){ cruiseCheckInRuleLocation = list.get(i + 1); break; } } } //没有需要打卡的点位,则返回空数据 if(null == cruiseCheckInRuleLocation){ return null; } //先判断当前定位是否到达打卡点位附近,在范围内则返回打卡消息 XpCheckLocation xpCheckLocation = xpCheckLocationService.getById(cruiseCheckInRuleLocation.getCheckLocationId()); if(null == xpCheckLocation){ return null; } CheckInMessageVo vo = new CheckInMessageVo(); Map distance = GeodesyUtil.getDistance(xpCheckLocation.getLocationLon() + "," + xpCheckLocation.getLocationLat(), dto.getLongitude() + "," + dto.getLatitude()); if(xpCheckLocation.getLocationRange().compareTo(new BigDecimal(distance.get("WGS84"))) >= 0){ vo.setMessageType(1); vo.setCheckLocationId(cruiseCheckInRuleLocation.getCheckLocationId()); return vo; } //判断时间小于10分钟首次触发和小于3分钟再次触发 LocalDateTime now = LocalDateTime.now(); LocalDateTime endTime = now.withHour(Integer.parseInt(cruiseCheckInRuleLocation.getEndTime().split(":")[0])) .withMinute(Integer.parseInt(cruiseCheckInRuleLocation.getEndTime().split(":")[1])) .withSecond(0); long time = endTime.toEpochSecond(ZoneOffset.of("+8")) - now.toEpochSecond(ZoneOffset.of("+8")); if((time <= 10 * 60 && time > 10 * 50) || (time <= 3 * 60 && time > 3 * 50)){ vo.setMessageType(2); vo.setCheckLocationId(cruiseCheckInRuleLocation.getCheckLocationId()); vo.setMessage(time > 10 * 50 ? "距离打卡超时还有10分钟,请尽快前往打卡点" : "距离打卡超时还有3分钟,请尽快前往打卡点"); return vo; } return null; } /** * 获取巡游打卡详情 * @param ruleId * @param locationId * @param uid * @return */ @Override public XpCruiseCheckInRecord getCruiseCheckInRecordInfo(Integer ruleId, Long locationId, Long uid) { return xpCruiseCheckInRecordService.getOne(new LambdaQueryWrapper() .eq(XpCruiseCheckInRecord::getCruiseCheckInRuleId, ruleId) .eq(XpCruiseCheckInRecord::getCheckLocationId, locationId) .eq(XpCruiseCheckInRecord::getDeleted, 0) .eq(XpCruiseCheckInRecord::getOperationsUserId, uid) .last(" and DATE_FORMAT(check_in_time, '%Y-%m-%d') = DATE_FORMAT(NOW(), '%Y-%m-%d')")); } }