diff --git a/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java b/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java index e3a14c4..6f2737b 100644 --- a/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java +++ b/electripper-admin/src/main/java/com/ruoyi/web/controller/app/AppVerifyController.java @@ -870,6 +870,7 @@ public class AppVerifyController extends BaseController /** * 根据经纬度判断是否在停车区 */ + @Log(title = "判断是否在停车区", businessType = BusinessType.ISINPARKING) @GetMapping("/isInParkingArea") public AjaxResult isInParkingArea(String longitude,String latitude,String areaId,String sn) { @@ -1337,4 +1338,17 @@ public class AppVerifyController extends BaseController } return toAjax(etOrderService.updateEtOrderByOrderNo(etOrder)); } + + /** + * 更新设备最新信息 + */ + @Log(title = "更新设备", businessType = BusinessType.REFRESH) + @PostMapping("/refreshDevice") + public AjaxResult refreshDevice(String sn) + { + if (StrUtil.isBlank(sn)){ + throw new ServiceException("未传sn"); + } + return toAjax(asDeviceService.refreshDeviceBySn(sn)); + } } diff --git a/electripper-admin/src/main/java/com/ruoyi/web/controller/system/AsDeviceController.java b/electripper-admin/src/main/java/com/ruoyi/web/controller/system/AsDeviceController.java index 4cdaa7b..e31be56 100644 --- a/electripper-admin/src/main/java/com/ruoyi/web/controller/system/AsDeviceController.java +++ b/electripper-admin/src/main/java/com/ruoyi/web/controller/system/AsDeviceController.java @@ -296,5 +296,22 @@ public class AsDeviceController extends BaseController return ajax; } + /** + * 根据订单号查询车辆轨迹 + */ + @PostMapping("/trajectoryByOrderNo") + public AjaxResult trajectoryByOrderNo(String orderNo) + { + AjaxResult ajax = AjaxResult.success(); + if(StrUtil.isBlank(orderNo)){ + logger.info("没有orderNo号参数:【orderNo={}】",orderNo); + return error("请传订单号参数"+"【orderNo="+orderNo+"】"); + } + logger.info("【根据订单号查询车辆轨迹】:orderNo={}",orderNo); + String trajectory = asDeviceService.trajectoryByOrderNo(orderNo); + ajax.put(AjaxResult.DATA_TAG,trajectory); + return ajax; + } + } diff --git a/electripper-common/src/main/java/com/ruoyi/common/enums/BusinessType.java b/electripper-common/src/main/java/com/ruoyi/common/enums/BusinessType.java index 32ffa8b..274e897 100644 --- a/electripper-common/src/main/java/com/ruoyi/common/enums/BusinessType.java +++ b/electripper-common/src/main/java/com/ruoyi/common/enums/BusinessType.java @@ -168,6 +168,11 @@ public enum BusinessType */ REBOOT, + /** + * 根据经纬度判断是否在停车区 + */ + ISINPARKING, + /** * 绑定 */ diff --git a/electripper-common/src/main/java/com/ruoyi/common/utils/CommonUtil.java b/electripper-common/src/main/java/com/ruoyi/common/utils/CommonUtil.java index 567fb90..77668d4 100644 --- a/electripper-common/src/main/java/com/ruoyi/common/utils/CommonUtil.java +++ b/electripper-common/src/main/java/com/ruoyi/common/utils/CommonUtil.java @@ -5,8 +5,10 @@ import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.common.constant.ServiceConstants; import com.ruoyi.common.utils.http.HttpUtils; +import com.ruoyi.common.utils.map.GpsCoordinateUtils; import com.ruoyi.common.utils.spring.SpringUtils; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import java.math.BigDecimal; import java.math.RoundingMode; @@ -177,4 +179,52 @@ public class CommonUtil { log.info("根据百分比计算出的电压:{}V",add); return add.intValue(); } + + /** 坐标转换 */ + @NotNull + public static double[] coordinateConvert(String lon1, String lat1) { + BigDecimal lon = new BigDecimal(lon1); + BigDecimal lat = new BigDecimal(lat1); +// 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); + // 取出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; + } + + + public 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; + } } diff --git a/electripper-common/src/main/java/com/ruoyi/common/utils/onenet/LocationVo.java b/electripper-common/src/main/java/com/ruoyi/common/utils/onenet/LocationVo.java new file mode 100644 index 0000000..468aa3f --- /dev/null +++ b/electripper-common/src/main/java/com/ruoyi/common/utils/onenet/LocationVo.java @@ -0,0 +1,21 @@ +package com.ruoyi.common.utils.onenet; + +import lombok.Data; + +@Data +public class LocationVo { + + private String lon;//经度 + + private String lat;//纬度 + + private Integer status;//电动车状态 0断电,1上电运行 2轮动抱死 3超出区域断电(远程下发了qlose) + + private Integer bat;//电池电压 "bat":571 ==> 57.1V + + private Integer csq;//信号强度 + + private Integer s;//卫星数量 + + private Integer q;//质量 +} diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/IAsDeviceService.java b/electripper-system/src/main/java/com/ruoyi/system/service/IAsDeviceService.java index a666ea7..681fdf2 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/IAsDeviceService.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/IAsDeviceService.java @@ -140,6 +140,14 @@ public interface IAsDeviceService extends IService<AsDevice> */ int refreshDevice(Long[] deviceIds); + /** + * 更新设备 + * + * @param deviceIds 需要更新设备的设备主键集合 + * @return 结果 + */ + int refreshDeviceBySn(String sn); + /** * 删除设备信息 * @@ -377,11 +385,21 @@ public interface IAsDeviceService extends IService<AsDevice> */ boolean updateVersion(String sn); + /** + * 更新最新的位置信息 + */ + boolean updateLatestLocation(String sn); + /** * 根据时间查询车辆轨迹 */ String trajectory(String sn,String startTime,String endTime); + /** + * 根据订单号查询车辆轨迹 + */ + String trajectoryByOrderNo(String orderNo); + // /** // * 是否靠近运营区边界 // */ diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsDeviceServiceImpl.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsDeviceServiceImpl.java index 15e4cf3..d840f43 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsDeviceServiceImpl.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsDeviceServiceImpl.java @@ -8,7 +8,10 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.annotation.DataScope; -import com.ruoyi.common.constant.*; +import com.ruoyi.common.constant.HttpStatus; +import com.ruoyi.common.constant.IotConstants; +import com.ruoyi.common.constant.ServiceConstants; +import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.CommonUtil; @@ -42,7 +45,10 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -591,10 +597,46 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i }else{ log.info("设备【"+device.getSn()+"】更新版本失败"); } + // 最新位置信息 + if(updateLatestLocation(device.getSn())){ + log.info("设备【"+device.getSn()+"】更新位置成功"); + }else{ + log.info("设备【"+device.getSn()+"】更新位置失败"); + } } return 1; } + /** + * 根据sn更新设备 + * @param sn sn + * @return 结果 + */ + @Override + public int refreshDeviceBySn(String sn) + { + AsDevice device = asDeviceMapper.selectAsDeviceBySn(sn); + //设备是否在线 + if(isOnline(device.getSn())){ + log.info("设备【"+device.getSn()+"】在线"); + }else{ + log.info("设备【"+device.getSn()+"】不在线"); + } + if(updateVersion(device.getSn())){ + log.info("设备【"+device.getSn()+"】更新版本成功"); + }else{ + log.info("设备【"+device.getSn()+"】更新版本失败"); + } + // 最新位置信息 + if(updateLatestLocation(device.getSn())){ + log.info("设备【"+device.getSn()+"】更新位置成功"); + }else{ + log.info("设备【"+device.getSn()+"】更新位置失败"); + } + return 1; + } + + /** * 删除设备信息 * @@ -680,6 +722,13 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i EtModel model = etModelService.selectEtModelByModelId(modelId); if(ObjectUtil.isNotNull(model)){ asDevice.setModel(model.getModel()); + Integer remainingMileage = 0; + if(StrUtil.isNotBlank(asDevice.getVoltage())){ + remainingMileage = CommonUtil.getRemainingMileage(asDevice.getVoltage(), model.getFullVoltage(), model.getLowVoltage(), model.getFullEndurance()); + } + Integer electricQuantity = CommonUtil.getElectricQuantity(asDevice.getVoltage(), model.getFullVoltage(), model.getLowVoltage());//电量百分百 + asDevice.setRemainingMileage(remainingMileage); + asDevice.setRemainingPower(electricQuantity.toString()); } } } @@ -2504,6 +2553,8 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i log.info("【查询数据点】===>更新版本失败"); } } + }else{ + } } } @@ -2546,6 +2597,45 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i return trajectoryStr.toString(); } + /** + * 根据时间查询车辆轨迹 + */ + @Override + public String trajectoryByOrderNo(String orderNo) { + EtOrder order = etOrderMapper.selectEtOrderByOrderNo(orderNo); + String endTime; + if(ObjectUtil.isNull(order.getReturnTime())){ + endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getNowDate()); + }else{ + endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, order.getReturnTime()); + } + String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, order.getUnlockTime()); + List<EtLocationLog> etLocationLogs = etLocationLogMapper.selectEtLocationLogListByCreateTime(order.getDeviceMac(), startTime, endTime); + // 将etLocationLogs中的longitude和latitude 转换成 [[120.2534,27.1048],[120.2556,27.1051],[120.2569,27.1057]] 这样的格式 + List<double[]> coordinatesList = new ArrayList<>(); + + for (EtLocationLog log : etLocationLogs) { + double longitude = Double.parseDouble(log.getLongitude()); + double latitude = Double.parseDouble(log.getLatitude()); + coordinatesList.add(new double[]{longitude, latitude}); + } + StringBuilder trajectoryStr = new StringBuilder(); + int size = coordinatesList.size(); + + trajectoryStr.append("["); // 在循环之前添加一个 "[" + + for (int i = 0; i < size; i++) { + double[] coordinate = coordinatesList.get(i); + trajectoryStr.append("[").append(coordinate[0]).append(", ").append(coordinate[1]).append("]"); + + if (i < size - 1) { + trajectoryStr.append(","); + } + } + trajectoryStr.append("]"); // 在循环之后添加一个 "]" + return trajectoryStr.toString(); + } + /** * sn和mac号绑定 @@ -2590,6 +2680,86 @@ public class AsDeviceServiceImpl extends ServiceImpl<AsDeviceMapper, AsDevice> i } + /** + * 更新最新的位置信息 + */ + @Override + @SneakyThrows + public boolean updateLatestLocation(String sn) { + AsDevice device = asDeviceMapper.selectAsDeviceBySn(sn); + if(device!=null){ + String version = device.getVersion(); + if(StrUtil.isBlank(version)){ + String token = Token.getToken(); + DataPointRes datapoints = historyDatapoints(asDeviceMapper.selectAsDeviceBySn(sn).getMac(), token); + if(datapoints.getCode() == 0){ + Data data = datapoints.getData(); + List<Datastream> datastreams = data.getDevices(); + for (Datastream datastream: datastreams) { + List<Datapoint> datapointList = datastream.getDatastreams(); + if(ObjectUtil.isNotNull(datapointList)){ + for (Datapoint datapoint:datapointList) { + if(datapoint.getId().equals(IotConstants.ONENET_LOCATION)){ + String string = JSON.toJSONString(datapoint.getValue()); + if(StrUtil.isNotBlank(string)){ + LocationVo locationVo = JSONObject.parseObject(string, LocationVo.class); + log.info("【手动更新】: locationVo---【{}】" , JSON.toJSONString(locationVo)); + double[] doubles = CommonUtil.coordinateConvert(locationVo.getLon(), locationVo.getLat()); + BigDecimal lat = new BigDecimal(doubles[0]).setScale(8, RoundingMode.HALF_UP); + BigDecimal lon = new BigDecimal(doubles[1]).setScale(8, RoundingMode.HALF_UP); + log.info("转换后的GCJ02经纬度:" + lon + "---" + lat); + /** 计算电量和里程后更新设备*/ + int i = updateDevice(locationVo, device, lon, lat); + if(i > 0){ + log.info("【手动更新】===>更新设备成功"); + return true; + }else{ + log.info("【手动更新】===>更新设备失败"); + return false; + } + } + } + } + } + } + } + } + } + return false; + } + + /** 计算电量和里程后更新设备*/ + public int updateDevice(LocationVo locationVo, AsDevice device, BigDecimal lon, BigDecimal lat) { + device.setLatitude(lat.toString()); + device.setLongitude(lon.toString()); + Integer bat = locationVo.getBat(); + BigDecimal divide = new BigDecimal(bat).divide(new BigDecimal(10)); + log.info("保存电压:" + divide); + device.setVoltage(divide.toString());//电压 + // 根据电压计算续航里程 + EtModel model = etModelService.selectEtModelByModelId(device.getModelId()); + 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()); + } + device.setLastTime(DateUtils.getNowDate()); + device.setLastLocationTime(DateUtils.getNowDate()); + device.setGps("1"); + // 信号强度 + device.setSignalStrength(locationVo.getCsq()); + device.setSatellites(locationVo.getS()); + device.setQuality(locationVo.getQ()); + int i = updateLocation(device); + return i; + } + + + /** * 判断是否靠近边界 */ diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsUserServiceImpl.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsUserServiceImpl.java index cba649e..5853b8b 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsUserServiceImpl.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/AsUserServiceImpl.java @@ -467,12 +467,12 @@ public class AsUserServiceImpl implements IAsUserService public Boolean checkIsDeposit(Long userId) { AsUser asUser = asUserMapper.selectUserById(userId); BigDecimal balance = asUser.getBalance(); - EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(Long.parseLong(asUser.getAreaId())); - BigDecimal deposit = new BigDecimal(area.getDeposit()); - if(deposit.compareTo(BigDecimal.ZERO)==0){//押金为0直接返回true - log.info("运营区【{}】押金为0",area.getAreaName()); - return true; - } +// EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(Long.parseLong(asUser.getAreaId())); +// BigDecimal deposit = new BigDecimal(area.getDeposit()); +// if(deposit.compareTo(BigDecimal.ZERO)==0){//押金为0直接返回true +// log.info("运营区【{}】押金为0",area.getAreaName()); +// return true; +// } if(ObjectUtil.isNull(balance)){ log.info("用户【{}】余额为空",userId); return false; diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtOrderServiceImpl.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtOrderServiceImpl.java index 8b3770a..7b2a89a 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtOrderServiceImpl.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/EtOrderServiceImpl.java @@ -134,6 +134,15 @@ public class EtOrderServiceImpl implements IEtOrderService AsDevice device = asDeviceMapper.selectAsDeviceBySn(order.getSn()); order.setDevice(device); EtFeeRule etFeeRule = etFeeRuleService.selectEtFeeRuleByRuleIdIncludeDelete(order.getRuleId()); + String endTime; + if(ObjectUtil.isNull(order.getReturnTime())){ + endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getNowDate()); + }else{ + endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, order.getReturnTime()); + } + String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, order.getUnlockTime()); + String trajectory = deviceService.trajectory(order.getSn(), startTime, endTime); + order.setTripRouteStr(trajectory); order.setRule(etFeeRule); //行程记录 EtTripLog tripLog = new EtTripLog(); diff --git a/electripper-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java b/electripper-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java index 988b0b2..d6ac035 100644 --- a/electripper-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java +++ b/electripper-system/src/main/java/com/ruoyi/system/service/impl/WxPayService.java @@ -111,7 +111,7 @@ public class WxPayService implements IWxPayService { } String outTradeNo = IdUtils.getOrderNo("wx"); order.setOutTradeNo(outTradeNo); - order.setLocking("1"); +// order.setLocking("1"); int updateEtOrder = etOrderService.updateEtOrder(order); if(updateEtOrder == 0){ throw new ServiceException("更新订单outTradeNo失败"); diff --git a/electripper-system/src/main/resources/mapper/system/EtLocationLogMapper.xml b/electripper-system/src/main/resources/mapper/system/EtLocationLogMapper.xml index 7c27e3f..7193ae7 100644 --- a/electripper-system/src/main/resources/mapper/system/EtLocationLogMapper.xml +++ b/electripper-system/src/main/resources/mapper/system/EtLocationLogMapper.xml @@ -37,12 +37,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" <where> <if test="mac != null and mac != ''"> and mac = #{mac}</if> <if test="startTime != null and startTime != ''"> - AND date_format(create_time,'%Y%m%d%H%i%s') >= date_format(#{startTime},'%Y%m%d%H%i%s') + AND date_format(`AT`,'%Y%m%d%H%i%s') >= date_format(#{startTime},'%Y%m%d%H%i%s') </if> <if test="endTime != null and endTime != ''"> - AND date_format(create_time,'%Y%m%d%H%i%s') <= date_format(#{endTime},'%Y%m%d%H%i%s') + AND date_format(`AT`,'%Y%m%d%H%i%s') <= date_format(#{endTime},'%Y%m%d%H%i%s') </if> </where> + order by `AT` </select> <select id="selectEtLocationLogByLocationId" parameterType="Long" resultMap="EtLocationLogResult">