package com.xiaopeng.maintenance.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xiaopeng.api.feignClient.account.XpOperationUserClient; import com.xiaopeng.api.feignClient.account.XpOperationsUserClient; import com.xiaopeng.api.model.account.XpOperationsUser; import com.xiaopeng.api.model.maintenance.*; import com.xiaopeng.common.core.exception.ServiceException; import com.xiaopeng.common.core.utils.GeodesyUtil; import com.xiaopeng.common.core.utils.StringUtils; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.maintenance.constant.I18nKeyConstant; import com.xiaopeng.maintenance.dto.XpCruiseCheckInRuleDto; import com.xiaopeng.maintenance.dto.XpCruiseCheckInRuleListPageDto; import com.xiaopeng.maintenance.mapper.XpCruiseCheckInRuleMapper; import com.xiaopeng.maintenance.mapper.XpCruiseCheckInRuleOperationsUserMapper; 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 com.xiaopeng.maintenance.vo.CruiseCheckInLocationVo; import com.xiaopeng.maintenance.vo.XpCruiseCheckInRuleInfoVo; import com.xiaopeng.maintenance.vo.XpCruiseCheckInRuleListPage; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; 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.concurrent.TimeUnit; 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; @Autowired private RedisService redisService; @Resource private XpOperationUserClient xpOperationsUserClient; @Override public AppXpCruiseCheckInRuleVo getMyXpCruiseCheckInRule(Long uid) { List list = this.list(new LambdaQueryWrapper().eq(XpCruiseCheckInRule::getDeleted, 0) .eq(XpCruiseCheckInRule::getOperationsUserId, uid).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) .last(" and DATE(check_in_time) = DATE(NOW())")); 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(check_in_time) = DATE(NOW())")); //构建返回结果 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 Long 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(check_in_time) = DATE(NOW())")); 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); return dto.getId(); } /** * 运维端实时上传位置信息,返回提醒消息 * @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(check_in_time) = DATE(NOW()) 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(); vo.setIsInRange(false); Map distance = GeodesyUtil.getDistance(xpCheckLocation.getLocationLon() + "," + xpCheckLocation.getLocationLat(), dto.getLongitude() + "," + dto.getLatitude()); if(xpCheckLocation.getLocationRange().compareTo(new BigDecimal(distance.get("WGS84"))) >= 0){ vo.setIsInRange(true); Boolean read = redisService.getCacheObject("CHECK_IN_SCOPE:" + xpCheckLocation.getId()); if(null == read || !read){ vo.setMessageType(2); vo.setCheckLocationId(cruiseCheckInRuleLocation.getCheckLocationId()); redisService.setCacheObject("CHECK_IN_SCOPE:" + xpCheckLocation.getId(), true, 1L, TimeUnit.HOURS); } 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(1); vo.setCheckLocationId(cruiseCheckInRuleLocation.getCheckLocationId()); vo.setMessage(time > 10 * 50 ? "距离打卡超时还有10分钟,请尽快前往打卡点" : "距离打卡超时还有3分钟,请尽快前往打卡点"); return vo; } return vo; } /** * 获取巡游打卡详情 * @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(check_in_time) = DATE(NOW())")); } /** * 获取巡游打卡规则列表 * @param pageInfo * @param dto * @return */ @Override public List getXpCruiseCheckInRuleListPage(Page pageInfo, XpCruiseCheckInRuleListPageDto dto) { List ids = new ArrayList<>(); if(StringUtils.isNotEmpty(dto.getUserName())){ List data = xpOperationsUserClient.listByName(dto.getUserName()).getData(); ids.addAll(data.stream().map(XpOperationsUser::getId).collect(Collectors.toList())); } if(StringUtils.isNotEmpty(dto.getPhoneNumber())){ List data = xpOperationsUserClient.getByPhoneNumber(dto.getPhoneNumber()).getData(); ids.addAll(data.stream().map(XpOperationsUser::getId).collect(Collectors.toList())); } List xpCruiseCheckInRuleListPage = this.baseMapper.getXpCruiseCheckInRuleListPage(pageInfo, dto.getName(), ids); for (XpCruiseCheckInRuleListPage cruiseCheckInRuleListPage : xpCruiseCheckInRuleListPage) { long count = xpCruiseCheckInRuleLocationService.count(new LambdaQueryWrapper() .eq(XpCruiseCheckInRuleLocation::getCruiseCheckInRuleId, cruiseCheckInRuleListPage.getId())); cruiseCheckInRuleListPage.setPointNum(count); XpOperationsUser xpOperationsUser = xpOperationsUserClient.queryById(cruiseCheckInRuleListPage.getOperationsUserId()).getData(); cruiseCheckInRuleListPage.setUserName(xpOperationsUser.getNickName()); cruiseCheckInRuleListPage.setPhone(xpOperationsUser.getPhoneNumber()); cruiseCheckInRuleListPage.setRoleName(xpOperationsUser.getRoleName()); } return xpCruiseCheckInRuleListPage; } /** * 新增巡游打卡规则 * @param dto */ @Override public void addXpCruiseCheckInRule(XpCruiseCheckInRuleDto dto) { XpCruiseCheckInRule one = this.getOne(new QueryWrapper().like("name", dto.getName()).eq("is_deleted", 0)); if(null != one){ throw new ServiceException("巡游打卡规则名称已存在"); } XpCruiseCheckInRule xpCruiseCheckInRule = new XpCruiseCheckInRule(); BeanUtils.copyProperties(dto, xpCruiseCheckInRule); xpCruiseCheckInRule.setDeleted(false); xpCruiseCheckInRule.setOperationsUserId(dto.getRelationId()); this.save(xpCruiseCheckInRule); dto.getPoints().forEach(s->{ s.setCruiseCheckInRuleId(xpCruiseCheckInRule.getId()); }); xpCruiseCheckInRuleLocationService.saveBatch(dto.getPoints()); } /** * 获取打卡规则详情 * @param id * @return */ @Override public XpCruiseCheckInRuleInfoVo getXpCruiseCheckInRuleInfo(Integer id) { XpCruiseCheckInRuleInfoVo info = new XpCruiseCheckInRuleInfoVo(); XpCruiseCheckInRule byId = this.getById(id); BeanUtils.copyProperties(byId, info); List list = xpCruiseCheckInRuleLocationService.list(new QueryWrapper().eq("cruise_check_in_rule_id", id)); List xpCheckLocations = xpCheckLocationService.listByIds(list.stream().map(XpCruiseCheckInRuleLocation::getCheckLocationId).collect(Collectors.toList())); List collect = list.stream().map(locationList -> { CruiseCheckInLocationVo vo = new CruiseCheckInLocationVo(); vo.setAddress(xpCheckLocations.stream().filter(xpCheckLocation -> xpCheckLocation.getId().equals(locationList.getCheckLocationId())).findFirst().get().getLocationAddress()); vo.setCheckRange(xpCheckLocations.stream().filter(xpCheckLocation -> xpCheckLocation.getId().equals(locationList.getCheckLocationId())).findFirst().get().getLocationRange()); vo.setCheckTime(StringUtils.isNotEmpty(locationList.getStartTime()) ? locationList.getStartTime() + "~" + locationList.getEndTime() : "不限"); return vo; }).collect(Collectors.toList()); info.setLocationList(collect); return info; } }