package com.ruoyi.system.task; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.ServiceConstants; import com.ruoyi.common.core.domain.entity.AsUser; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.CommonUtil; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.map.GeoUtils; import com.ruoyi.common.utils.map.GpsCoordinateUtils; import com.ruoyi.common.utils.onenet.LogEntry; import com.ruoyi.common.utils.uuid.IdUtils; import com.ruoyi.system.domain.*; import com.ruoyi.system.mapper.*; import com.ruoyi.system.service.*; import com.wechat.pay.java.service.refund.model.Refund; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import javax.annotation.PostConstruct; 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.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; /** * 定时任务调度测试 * * @author ruoyi */ @Slf4j @Component("etTask") public class EtTask { @Resource private EtOrderMapper etOrderMapper; @Autowired private IEtOperatingAreaService etOperatingAreaService; @Resource private SysUserMapper userMapper; @Autowired private IEtDividendDetailService dividendDetailService; @Autowired private ScheduledExecutorService scheduledExecutorService; @Autowired private IEtOrderService etOrderService; @Resource private AsDeviceMapper asDeviceMapper; @Autowired private IWxPayService wxPayService; @Autowired private IEtRefundService etRefundService; @Autowired private RedisCache redisCache; @Resource private AsUserMapper asUserMapper; @Resource private EtLocationLogMapper etLocationLogMapper; @Autowired private IAsDeviceService deviceService; @Autowired private IEtModelService etModelService; @Resource private EtCouponClaimLogMapper etCouponClaimLogMapper; /** * 1.启动时判断是否有未取消预约的订单 * 2.判断已完成的订单未退还押金的 * 3.启动时判断是否分账 */ @Transactional @PostConstruct public void init() { log.info("=========================启动业务处理========================="); log.info("=========================开始========================="); /** 1.启动时判断是否有未取消预约的订单*/ // uncancelledAppointmentHandle(); /** 2.判断已完成的订单未退还押金的(根据et_refund表中的refund_result结果判断是否已经退款) */ /** ①找出所有已完成的订单 status=4 type = 1 r.refund_result IS NULL * ②根据用户查询最后一次押金充值记录 */ List orders = etOrderMapper.selectUserListFinishOrder(); log.info("已完成的订单未退还押金的的订单 = " + JSON.toJSONString(orders)); for(EtOrder order:orders){ // EtFeeRule rule = etFeeRuleService.selectEtFeeRuleByRuleIdIncludeDelete(order.getRuleId()); // if(ObjectUtil.isNull(rule)){ // throw new ServiceException("骑行订单:【"+order.getOrderNo()+"】未找到该套餐【"+order.getRuleId()+"】"); // } EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(order.getAreaId()); AsUser asUser = asUserMapper.selectUserById(order.getUserId()); Integer autoRefundDeposit = order.getAutoRefundDeposit(); // 根据用户查询最后一次押金充值订单 EtOrder etOrder = new EtOrder(); etOrder.setUserId(order.getUserId()); etOrder.setPaid(ServiceConstants.ORDER_PAY_STATUS_PAID); etOrder.setType(ServiceConstants.ORDER_TYPE_DEPOSIT); etOrder.setStatus(ServiceConstants.ORDER_STATUS_ORDER_END); List etOrders = etOrderMapper.selectEtOrderList(etOrder); if (etOrders.size() > 0 || ObjectUtil.isNotNull(etOrders) ) { Optional latestOrderOptional = etOrders.stream() .max(Comparator.comparing(EtOrder::getPayTime)); if (latestOrderOptional.isPresent()) { EtOrder lastOrder = latestOrderOptional.get(); log.info("【系统启动】用户【{}】最后一次押金充值订单 : " + JSON.toJSONString(lastOrder),asUser.getUserId()); if(lastOrder.getTotalFee().compareTo(new BigDecimal(area.getDeposit()))!=0){ log.info("【系统启动】最后一次押金充值记录 金额与押金不一致,订单押金:【{}】,区域押金:【{}】",lastOrder.getTotalFee(),area.getDeposit()); }else{ // 根据最新的订单号,查询是否有退款记录 List etRefunds = etRefundService.selectEtRefundByOrderNo(lastOrder.getOrderNo()); if(etRefunds.size() == 1){ EtRefund etRefund = etRefunds.get(0); // 没有退款记录,发起退款 if(ObjectUtil.isNull(etRefund)){ // 根据订单支付时间 autoRefundDeposit个小时后退押金 String reason = autoRefundDeposit + "个小时后自动退押金"; Date payTime = order.getPayTime(); Date refundDepositTime = DateUtils.getTimeAfterXHours(payTime, autoRefundDeposit); Date nowDate = DateUtils.getNowDate(); if (nowDate.after(refundDepositTime)) { log.info("【系统启动】用户【{}】押金充值订单【{}】已过期,开始自动退押金",asUser.getUserId(),lastOrder.getOrderNo()); refundDeposit(asUser, lastOrder, reason); }else{ int timeDifferenceInMinutes = DateUtils.timeDifferenceInMinutes(payTime, nowDate); int i = autoRefundDeposit * 60; int delay = i - timeDifferenceInMinutes; log.info("【系统启动】用户【{}】押金充值订单【{}】未过期,【{}】分钟后退押金",asUser.getUserId(),lastOrder.getOrderNo(),delay); scheduledExecutorService.schedule(() -> { refundDeposit(asUser, lastOrder, reason); }, delay, TimeUnit.MINUTES); } }else{ // 有退款记录,判断是否成功 if(!Constants.SUCCESS2.equals(etRefund.getRefundResult())){ log.info("【系统启动】押金退款未成功回调,退款单号:【{}】",etRefund.getRefundNo()); // 根据退款单号查询退款信息 Refund refund = wxPayService.queryByOutRefundNo(etRefund.getRefundNo()); if(ObjectUtil.isNotNull(refund) && Constants.SUCCESS2.equals(refund.getStatus().name())){ // 更新退款记录 etRefund.setRefundResult(Constants.SUCCESS2); etRefund.setUpdateTime(new Date()); etRefundService.updateEtRefund(etRefund); log.info("【系统启动】更新押金退款回调成功,退款单号:【{}】",refund.getOutRefundNo()); } } } } } } } } /** 3.启动时判断是否分账(根据订单号查询分账明细表是否有记录来判断是否分账) */ /** ①找出所有已完成的骑行订单 status=4 type = 1 r.refund_result IS NULL * ②根据订单号查询分账明细表是否有记录 * 有记录则已经分账过 * 没值代表还未分账 * 判断是否已过分账时间 * 未过,计算出多少小时后分账 * 已过,直接分账(记录分账明细表) */ // 查询所有待分账的订单 // List needDividendOrders = etOrderMapper.selectNeedDividendOrder(); // for(EtOrder order: needDividendOrders){ // log.info("【系统启动】待分账订单:【{}】",order.getOrderNo()); // EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(order.getAreaId()); // if(dividendDetailService.isDividendComputedByOrderNo(order.getOrderNo())){ // log.info("订单【{}】已经分账",order.getOrderNo()); // break; // } // log.info("【系统启动】骑行订单【{}】未分账,开始分账",order.getOrderNo()); // Date payTime = order.getPayTime(); // Date dividendTime = DateUtils.getTimeAfterXHours(payTime, 24);//分账时间 // Date nowDate = DateUtils.getNowDate(); // if (nowDate.after(dividendTime)) { // log.info("【系统启动】骑行订单【{}】已过分账时间,开始分账",order.getOrderNo()); // // 请求分账处理 // Transaction transaction = wxPayService.queryOrderByOutTradeNo(order.getOrderNo()); //// if (callbackService.dividendHandle(transaction.getTransactionId(), order, area)) break; // }else{ // int timeDifferenceInHours = DateUtils.timeDifferenceInHours(payTime, nowDate); // int delay = 24 - timeDifferenceInHours; // log.info("【系统启动】骑行订单【{}】未过分账时间,【{}】小时后开始分账",order.getOrderNo(),delay); // // 24小时后发起分账 //// scheduledExecutorService.schedule(() -> { //// // 请求分账处理 //// Transaction transaction = wxPayService.queryOrderByOutTradeNo(order.getOrderNo()); //// if (callbackService.dividendHandle(transaction.getTransactionId(), order, area)) return; //// }, delay , TimeUnit.HOURS); // } // } // log.info("=========================结束========================="); } private void refundDeposit(AsUser asUser, EtOrder lastOrder, String reason) { String outRefundNo = IdUtils.getOrderNo("ref"); lastOrder.setReason(reason); EtRefund refund1= etOrderService.createRefund(lastOrder, lastOrder.getTotalFee(), null, null, null, null, outRefundNo,ServiceConstants.REFUND_TYPE_DEPOSIT); if(etRefundService.insertEtRefund(refund1)>0){ log.info("【自动退款】保存退款对象成功"); // 新增资金流水记录 // callbackService.capitalFlowRecords(lastOrder,ServiceConstants.FLOW_TYPE_DISBURSE,ServiceConstants.ORDER_TYPE_DEPOSIT_REFUND); // 更新用户信息,清除缓存 asUser.setBalance(BigDecimal.ZERO); int updateUser = asUserMapper.updateUser(asUser); if(updateUser>0){ // Collection keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.APP_LOGIN_TOKEN_KEY + "*"); // redisCache.deleteObject(keys); log.info("【系统启动】退还押金,更新用户余额成功!"); } wxPayService.refund(lastOrder, reason, lastOrder.getTotalFee(),outRefundNo); log.info("=================【系统启动】退还押金定时任务结束!!!=================="); }else{ throw new ServiceException("【系统启动】保存退款对象失败"); } } private void uncancelledAppointmentHandle() { List orders= etOrderMapper.selectAppointmentUnfinished(); log.info("预约未完成的订单 = " + JSON.toJSONString(orders)); for (EtOrder order:orders) { EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(order.getAreaId()); AsDevice asDevice = asDeviceMapper.selectAsDeviceBySn(order.getSn()); Date appointmentEndTime = DateUtils.getTimeAfterXMinutes(order.getAppointmentStartTime(), area.getTimeoutMinutes());//预约结束时间 int timeDifferenceInSeconds = DateUtils.timeDifferenceInSeconds(appointmentEndTime, order.getAppointmentStartTime());//(超时时间-开始时间)的秒数 int differenceInSeconds = DateUtils.timeDifferenceInSeconds(new Date(), order.getAppointmentStartTime());//(当前时间-开始时间)的秒数 int delay = timeDifferenceInSeconds - differenceInSeconds; log.info("【定时取消预约】延迟:【{}】秒", delay); //定时取消预约 scheduledExecutorService.schedule(() -> { log.error("【车辆超时预约】系统自动取消"); EtOrder order1 = etOrderService.selectEtOrderByOrderNo(order.getOrderNo()); log.info("【定时取消预约】重新获取订单信息:{}",JSON.toJSON(order1)); if(order1.getPaid().equals(ServiceConstants.ORDER_PAY_STATUS_PAID)){//已支付订单,跳过 log.error("【车辆超时预约】订单已支付,跳过"); return; } log.error("【车辆超时预约】订单未支付,系统自动处理"); //未支付 订单更新最后预约时间,并结束订单,做超出预约时间标记 order.setStatus(ServiceConstants.ORDER_STATUS_CANCEL_APPOINTMENT); order.setAppointmentEndTime(new Date()); order.setAppointmentTimeout("1"); //计算预约费 BigDecimal appointmentServiceFee = area.getAppointmentServiceFee(); BigDecimal fee = appointmentServiceFee.multiply(new BigDecimal(area.getTimeoutMinutes()).divide(new BigDecimal(10))); order.setAppointmentFee(fee); order.setTotalFee(fee); order.setPayFee(fee); int update = etOrderService.updateEtOrder(order); if(update==0){ throw new ServiceException("【车辆超时预约】:更新订单状态失败"); } // 改变车辆状态 asDevice.setStatus(ServiceConstants.VEHICLE_STATUS_NORMAL); asDevice.setLockStatus(ServiceConstants.LOCK_STATUS_OPEN); int device = asDeviceMapper.updateAsDevice(asDevice); if(device==0){ log.error("【车辆超时预约】更新车辆状态失败"); throw new ServiceException("【车辆超时预约】更新车辆状态失败"); } }, delay, TimeUnit.SECONDS); } } /** * 每天凌晨0点5分执行,计算分账结果 * cron: 0 5 0 * * ? */ public void computeDividend() { log.info("每天凌晨0点5分执行,计算分账结果"); // 获取昨天的订单,2024-05-26 00:00:00 -- 2024-05-26 23:59:59 // 获取昨天日期格式: yyyy-MM-dd LocalDate yesterday = LocalDate.now().minusDays(1); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String formattedYesterday = yesterday.format(formatter); log.info("获取昨天日期 = " + formattedYesterday); //判断该日期是否已经计算过分账结果 if(dividendDetailService.isDividendComputed(LocalDate.now().format(formatter))){ log.info("该日期已经计算过分账结果"); return; } String startDateStr = formattedYesterday + " "+ Constants.DATE_FORMAT_START_PEREND; String endDateStr = formattedYesterday + " " +Constants.DATE_FORMAT_END_PEREND; EtOrder order = new EtOrder(); order.setStartTime(startDateStr); order.setEndTime(endDateStr); order.setPaid(ServiceConstants.ORDER_PAY_STATUS_PAID); order.setStatus(ServiceConstants.ORDER_STATUS_ORDER_END); order.setType(ServiceConstants.ORDER_TYPE_RIDING); List orderListByDate = etOrderMapper.selectEtOrderList(order); for(EtOrder order1:orderListByDate){ EtDividendDetail etDividendDetail = new EtDividendDetail(); EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(order1.getAreaId()); SysUser sysUser = new SysUser(); sysUser.setUserType("03"); sysUser.setAreaId(area.getAreaId()); List sysUsers = userMapper.selectUserList(sysUser); for(SysUser user : sysUsers){ etDividendDetail.setAreaId(area.getAreaId()); etDividendDetail.setPartnerId(user.getUserId()); etDividendDetail.setOrderNo(order1.getOrderNo()); etDividendDetail.setTotalAmount(order1.getTotalFee()); etDividendDetail.setCreateTime(DateUtils.getNowDate()); etDividendDetail.setDividendProportion(user.getDividendProportion()); String dividendItem = user.getDividendItem(); // todo 分账金额是骑行费,还是调度费,看分账项目 分账项目:1-骑行费(骑行费+预约费);2-调度费(调度费+管理费) BigDecimal dividendAmount = BigDecimal.ZERO; if(dividendItem.contains("1")){ dividendAmount.add(order1.getRidingFee().add(order1.getAppointmentFee()));//1-骑行费(骑行费+预约费) }else if(dividendItem.contains("2")){ dividendAmount.add(order1.getManageFee().add(order1.getManageFee()));//2-调度费(调度费+停车点外调度费) } BigDecimal divide = new BigDecimal(user.getDividendProportion()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP); etDividendDetail.setDividendAmount(dividendAmount.multiply(divide)); etDividendDetail.setDividendItem(dividendItem); log.info("保存分账明细 === " + JSON.toJSONString(etDividendDetail)); int i = dividendDetailService.insertEtDividendDetail(etDividendDetail); if(i==0){ throw new ServiceException("保存分账明细失败"); } } int totalDividendProportion = IntStream.of(sysUsers.stream() .mapToInt(SysUser::getDividendProportion) .toArray()) .sum(); //算运营商自己的分账 etDividendDetail.setAreaId(area.getAreaId()); etDividendDetail.setPartnerId(0L); etDividendDetail.setOrderNo(order1.getOrderNo()); etDividendDetail.setTotalAmount(order1.getTotalFee()); etDividendDetail.setCreateTime(DateUtils.getNowDate()); etDividendDetail.setDividendAmount(order1.getTotalFee().multiply(new BigDecimal(100-totalDividendProportion).divide(new BigDecimal(100),2, BigDecimal.ROUND_HALF_UP))); etDividendDetail.setDividendProportion(100-totalDividendProportion); etDividendDetail.setDividendItem("运营商"); int i = dividendDetailService.insertEtDividendDetail(etDividendDetail); if(i==0){ throw new ServiceException("保存分账明细失败"); } } } /** * 开始骑行未结束的订单,1分钟算一次距离 * cron: 0 5 0 * * ? */ public void computeDistance(){ log.info("-------------------【定时任务】计算订单距离开始-------------------"); EtOrder order = new EtOrder(); order.setType("1"); order.setStatus(ServiceConstants.ORDER_STATUS_RIDING); List orders = etOrderService.selectEtOrderList(order); for(EtOrder etOrder:orders){ String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getNowDate()); String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, etOrder.getUnlockTime()); String tripRouteStr = deviceService.trajectory(etOrder.getSn(), startTime, endTime); if(StrUtil.isNotBlank(tripRouteStr)){ double[][] doubles = GeoUtils.parseJsonTrack(tripRouteStr); double v = GeoUtils.calculateTotalDistance(doubles); EtOrder etOrder1 = new EtOrder(); etOrder1.setOrderId(etOrder.getOrderId()); etOrder1.setDistance((int)Math.round(v)); int updateEtOrder = etOrderService.updateEtOrder(etOrder1); if(updateEtOrder>0){ log.info("【定时任务】计算订单距离成功:【orderNo="+etOrder.getOrderNo()+"】"); } } } } /** * 一个星期删除一次onenet心跳日志 * cron: 0 5 0 * * ? * * DELETE FROM et_location_log * WHERE create_time < NOW() - INTERVAL 7 DAY; */ public void deleteLocationLog(){ log.info("-------------------【定时任务】删除onenet心跳日志-------------------"); etLocationLogMapper.deleteLocationLogByCreateTime(); } /** * 车辆与订单状态同步 * 1. 如果有正在骑行中的订单,车辆的状态是待骑行的,改成临时锁车,不发命令 * 2. 如果车辆状态是骑行中或临时锁车,查询订单没有订单,则修改车辆状态为待骑行 * */ public void stausSynchronization(){ log.info("-------------------【定时任务】车辆与订单状态同步-------------------"); // 当前有骑行中的订单 List orders = etOrderService.getCurrentOrderList(); for (EtOrder order:orders) { AsDevice device = asDeviceMapper.selectAsDeviceBySn(order.getSn()); if(ObjectUtil.isNotNull(device) && device.getStatus().equals(ServiceConstants.VEHICLE_STATUS_NORMAL)){ AsDevice device1 = new AsDevice(); device1.setSn(device.getSn()); device1.setStatus(ServiceConstants.VEHICLE_STATUS_TEMPORARILY_LOCK); device1.setLockStatus(ServiceConstants.LOCK_STATUS_CLOSE); int i = asDeviceMapper.updateAsDeviceBySn(device1); if(i>0){ log.info("【定时任务】车辆状态修改为临时锁车:【sn="+device.getSn()+"】"); } } } // 2. 如果车辆状态是骑行中或临时锁车,查询当前没有订单,则修改车辆状态为待骑行 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.in("status", "3","4"); // 设备状态正常 // 查询所有设备 List allDevices = asDeviceMapper.selectList(wrapper); for(AsDevice device:allDevices){ if(ObjectUtil.isNotNull(etOrderService.getCurrentOrder2(device.getSn()))){ continue; }else{ AsDevice device1 = new AsDevice(); device1.setSn(device.getSn()); device1.setStatus(ServiceConstants.VEHICLE_STATUS_NORMAL); device1.setLockStatus(ServiceConstants.LOCK_STATUS_CLOSE); int i = asDeviceMapper.updateAsDeviceBySn(device1); if(i>0){ log.info("【定时任务】车辆状态修改为待骑行:【sn="+device.getSn()+"】"); } } } } // 写一个定时,如果车辆是骑行中,没有现在骑行中的订单,则关闭车辆 /** * 自动押金抵扣 * 写一个定时任务处理所有的 7天前待支付的订单用押金抵扣,如果已经退押金的直接改成结束订单 * 1. 查询所有待支付的订单,根据还车时间7天前的订单 * 2. 如果订单金额是0,直接结束订单,修改订单状态为已支付 * 3. 查询用户是否还有未退款的押金,如果有,则进行押金抵扣,如果没有,则结束订单 */ public void autoDeduction(){ log.info("-------------------【定时任务】自动押金抵扣-------------------"); /** 1. 查询所有待支付的订单,根据还车时间7天前的订单 */ List orders = etOrderMapper.selectToBePaidEtOrderList(); if(ObjectUtil.isNotNull(orders) && orders.size()>0){ for(EtOrder order:orders){ if(order.getTotalFee().compareTo(BigDecimal.ZERO) == 0){ // 结束订单,修改订单状态为已支付 updateOrderPaid(order); }else{ etOrderService.deduction(order); } } } } /** * 押金抵扣不成功的修复 * 1. 找出所有押金抵扣不成功的订单 * 2. 将状态改成已结束 * */ public void deductionErrorOrder(){ log.info("-------------------【定时任务】押金抵扣不成功的修复---开始----------------"); List orders = etOrderMapper.deductionErrorOrderList(); for (EtOrder order:orders) { EtOrder order1 = new EtOrder(); order1.setOrderId(order.getOrderId()); order1.setStatus(ServiceConstants.ORDER_STATUS_ORDER_END); order1.setMark("押金抵扣修复,订单已结束"); etOrderMapper.updateEtOrder(order1); } log.info("-------------------【定时任务】押金抵扣不成功的修复---结束----------------"); } /** 更新订单为已支付*/ private void updateOrderPaid(EtOrder order) { EtOrder order1 = new EtOrder(); order1.setOrderId(order.getOrderId()); order1.setPaid(ServiceConstants.ORDER_PAY_STATUS_PAID); order1.setPayTime(DateUtils.getNowDate()); order1.setStatus(ServiceConstants.ORDER_STATUS_ORDER_END); order1.setPayType(ServiceConstants.PAY_TYPE_YJ); order1.setMark("超过7天系统自动押金抵扣"); order1.setDepositDeduction(ServiceConstants.IS_DEPOSIT_DEDUCTION); int updateEtOrder = etOrderMapper.updateEtOrder(order1); if(updateEtOrder == 0){ throw new ServiceException("押金抵扣失败,更新骑行订单失败"); } } /** 如果还有未退款的押金,如果有,则进行押金抵扣 */ private void autoDeductionHandle(EtOrder order){ // select * from et_order o // where o.status ='4' and o.paid = '1' and o.type = 1 and o.is_test = '0' // GROUP BY o.user_id } /** * 更新设备的定位和电压 10秒一次 * cron: 0 10 0 * * ? */ public void updateLocation10(){ log.info("-------------------【定时任务10秒一次】更新设备的定位和电压-----开始--------------"); // 记录开始时间 long startTime = System.nanoTime(); Collection keys = redisCache.keys(CacheConstants.CACHE_DEVICE_KEY + "*"); log.info("redis缓存中的数据:" + JSON.toJSONString(keys)); for(String key:keys){ String msg = redisCache.getCacheObject(key); log.info("redis缓存中的数据:" + msg); LogEntry logEntry = JSONObject.parseObject(msg, LogEntry.class); log.info("logEntry转换后的对象: logEntry---【{}】" , JSON.toJSONString(logEntry)); LogEntry.LocationValue value = logEntry.getValue(); AsDevice device = asDeviceMapper.selectAsDeviceByMac(logEntry.getDevName()); if(!isRepeatMsg(msg,logEntry.getDevName())){ log.info("device: sn={},【{}】",device.getSn() , JSON.toJSONString(device)); if(ServiceConstants.LOCK_STATUS_OPEN.equals(device.getLockStatus()) && device.getStatus().equals(ServiceConstants.VEHICLE_STATUS_IN_USING)){ updateLocationHandle(msg, logEntry, value, device); } } } // 计算执行时间(以毫秒为单位) long duration = (System.nanoTime() - startTime) / 1_000_000; log.info("-------------------【定时任务10秒一次】更新设备的定位和电压----结束---------------"+duration+ " 毫秒"); } private boolean isRepeatMsg(String msg,String mac){ // 获取最后一条消息 String lastMsg = etLocationLogMapper.getLastMsg(mac); if(ObjectUtil.isNotNull(lastMsg) && msg.equals(lastMsg)){ return true; }else{ return false; } } /** * 更新设备的定位和电压 5分钟一次 * cron: 0 20 0 * * ? */ public void updateLocation300(){ log.info("-------------------【定时任务5分钟一次】更新设备的定位和电压-----开始--------------"); // 记录开始时间 long startTime = System.nanoTime(); Collection keys = redisCache.keys(CacheConstants.CACHE_DEVICE_KEY + "*"); log.info("redis缓存中的数据:" + JSON.toJSONString(keys)); for(String key:keys){ String msg = redisCache.getCacheObject(key); log.info("redis缓存中的数据:" + msg); LogEntry logEntry = JSONObject.parseObject(msg, LogEntry.class); log.info("logEntry转换后的对象: logEntry---【{}】" , JSON.toJSONString(logEntry)); LogEntry.LocationValue value = logEntry.getValue(); AsDevice device = asDeviceMapper.selectAsDeviceByMac(logEntry.getDevName()); if(ServiceConstants.LOCK_STATUS_CLOSE.equals(device.getLockStatus())){ updateLocationHandle(msg, logEntry, value, device); } } // 计算执行时间(以毫秒为单位) long duration = (System.nanoTime() - startTime) / 1_000_000; log.info("-------------------【定时任务5分钟一次】更新设备的定位和电压----结束---------------"+duration+ " 毫秒"); } private void updateLocationHandle(String msg, LogEntry logEntry, LogEntry.LocationValue value, AsDevice device) { // 坐标转换 WGS84 转 GCJ02 double[] doubles = coordinateConvert(value); BigDecimal lon = new BigDecimal(doubles[1]).setScale(8, RoundingMode.HALF_UP); BigDecimal lat = new BigDecimal(doubles[0]).setScale(8, RoundingMode.HALF_UP); asynchronousSaveLog(msg, logEntry.getAt(), logEntry.getDevName(), lon, lat, device); BigDecimal divide = new BigDecimal(value.getBat()).divide(new BigDecimal(10)); device.setVoltage(divide.toString());//电压 EtModel model = etModelService.selectEtModelByModelId(device.getModelId()); device.setLastTime(DateUtils.getNowDate()); device.setSignalStrength(value.getCsq()); device.setQuality(value.getQ()); if(ObjectUtil.isNotNull(model)){ Integer remainingMileage = 0; if(StrUtil.isNotBlank(device.getVoltage())){ remainingMileage = CommonUtil.getRemainingMileage(device.getVoltage(), model.getFullVoltage(), model.getLowVoltage(), model.getFullEndurance()); } Integer electricQuantity = CommonUtil.getElectricQuantity(device.getVoltage(), model.getFullVoltage(), model.getLowVoltage());//电量百分百 device.setRemainingMileage(remainingMileage); device.setRemainingPower(electricQuantity.toString()); } if(BigDecimal.ZERO.compareTo(lon) != 0 && BigDecimal.ZERO.compareTo(lat) != 0){ device.setLatitude(lat.toString()); device.setLongitude(lon.toString()); device.setLastLocationTime(DateUtils.getNowDate()); device.setGps("1"); // 信号强度 device.setSatellites(value.getS()); }else{ device.setGps("0"); device.setSatellites(0); } int i = deviceService.updateLocation(device); if(i>0){ log.info("===============更新设备信息成功===========>" + logEntry.getDevName()); } } /** * 异步保存定位 */ private void asynchronousSaveLog(String msg, long at,String mac,BigDecimal lon,BigDecimal lat,AsDevice device){ //异步保存定位 scheduledExecutorService.schedule(() -> { EtLocationLog etLocationLog = new EtLocationLog(); etLocationLog.setOnenetMsg(msg); etLocationLog.setCreateTime(DateUtils.getNowDate()); etLocationLog.setLongitude(lon.toString()); etLocationLog.setLatitude(lat.toString()); etLocationLog.setMac(mac); etLocationLog.setAt(new Date(at)); etLocationLog.setStatus(device.getStatus()); etLocationLog.setLockStatus(device.getLockStatus()); etLocationLogMapper.insertEtLocationLog(etLocationLog); }, 0, TimeUnit.SECONDS); } /** 坐标转换 */ @NotNull private double[] coordinateConvert(LogEntry.LocationValue value) { BigDecimal lon = new BigDecimal(value.getLon()); BigDecimal lat = new BigDecimal(value.getLat()); // log.info("WGS84经纬度(未计算):" + lon + "---" + lat); // 除以100 lon = lon.divide(new BigDecimal(100), 10, RoundingMode.HALF_UP); lat = lat.divide(new BigDecimal(100), 10, RoundingMode.HALF_UP); // log.info("WGS84经纬度(除以100后):" + lon + "---" + lat); // 取出lon中后面的小数点 String[] lonStr = getDecimalPart(lon); String[] latStr = getDecimalPart(lat); // log.info("WGS84经纬度(截取小数点):" + lonStr[0] + "---" + lonStr[1] + "---"+ latStr[0]+"---"+ latStr[1]); // 再将结果乘以5/3 String lon2 = "0."+ lonStr[1]; String lat2 = "0."+ latStr[1]; BigDecimal lons = new BigDecimal(lon2).multiply(new BigDecimal(5).divide(new BigDecimal(3), 8, RoundingMode.HALF_UP)); BigDecimal lats = new BigDecimal(lat2).multiply(new BigDecimal(5).divide(new BigDecimal(3), 8, RoundingMode.HALF_UP)); BigDecimal lo = new BigDecimal(lonStr[0]).add(lons); BigDecimal la = new BigDecimal(latStr[0]).add(lats); // log.info("WGS84经纬度(计算后):" + lo + "---" + la); lo = lo.setScale(8, RoundingMode.HALF_UP); la = la.setScale(8, RoundingMode.HALF_UP); // log.info("WGS84经纬度(保留8为小数):" + lo + "---" + la); double[] doubles = GpsCoordinateUtils.calWGS84toGCJ02(la.doubleValue(), lo.doubleValue()); return doubles; } private static String[] getDecimalPart(BigDecimal number) { // 将BigDecimal转换为字符串 String numberStr = number.toPlainString(); // 找到小数点的位置 int indexOfDecimal = numberStr.indexOf("."); // 初始化结果数组 String[] parts = new String[2]; // 如果有小数点 if (indexOfDecimal >= 0) { parts[0] = numberStr.substring(0, indexOfDecimal); // 整数部分 parts[1] = numberStr.substring(indexOfDecimal + 1); // 小数部分 } else { // 如果没有小数点,整数部分为整个字符串,小数部分为空 parts[0] = numberStr; parts[1] = ""; } return parts; } /** * 判断优惠券是否过期 * */ public void couponIsExpires(){ log.info("-------------------【定时任务】判断优惠券是否过期---开始----------------"); EtCouponUserLog etCouponUserLog = new EtCouponUserLog(); etCouponUserLog.setStatus(ServiceConstants.COUPON_STATUS_UNUSED); List couponUserLogs = etCouponClaimLogMapper.selectEtCouponClaimLogList(etCouponUserLog); // 获取当前时间 Date currentTime = new Date(); for(EtCouponUserLog couponLog :couponUserLogs){ // 获取优惠券的过期时间 Date expirationTime = couponLog.getExpirationTime(); // 判断优惠券是否过期 if (expirationTime != null && expirationTime.before(currentTime)) { // 如果过期,更新状态为已过期 couponLog.setStatus(ServiceConstants.COUPON_STATUS_EXPIRED); // 更新到数据库 int result = etCouponClaimLogMapper.updateEtCouponClaimLog(couponLog); if (result > 0) { log.info("优惠券ID: {} 已过期,状态已更新为:已过期", couponLog.getCouponId()); } else { log.warn("优惠券ID: {} 更新状态失败", couponLog.getCouponId()); } } } log.info("-------------------【定时任务】判断优惠券是否过期---结束----------------"); } }