Jelajahi Sumber

小程序首页站点加载修改

skyline 1 tahun lalu
induk
melakukan
f6d14aa122

+ 6 - 6
admin/src/main/resources/application-dev.yml

@@ -71,19 +71,19 @@ spring:
       strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
       datasource:
         db-admin:
-          url: jdbc:mysql://121.40.98.15:3307/charge_admin?serverTimezone=Asia/Shanghai
+          url: jdbc:mysql://183.234.100.174:3306/charge_admin?serverTimezone=Asia/Shanghai
           username: root
           password: KuaiyuMan/*-
           driver-class-name: com.mysql.cj.jdbc.Driver
         db-miniapp:
-          url: jdbc:mysql://121.40.98.15:3307/charge_app?serverTimezone=Asia/Shanghai
+          url: jdbc:mysql://183.234.100.174:3306/charge_app?serverTimezone=Asia/Shanghai
           username: root
           password: KuaiyuMan/*-
           driver-class-name: com.mysql.cj.jdbc.Driver
   data:
     redis:
-      port: 6380
-      host: 121.40.98.15
+      port: 6379
+      host: 183.234.100.174
       password: KtXA^Zx!TZmLEy(@JjB@2(TVG0kdy5)&
       database: 10
       lettuce:
@@ -99,8 +99,8 @@ spring:
       # 缓存过期时间:7天
       time-to-live: 604800
   rabbitmq:
-    host: 121.40.98.15
-    port: 5674
+    host: 183.234.100.174
+    port: 5672
     username: kym
     password: kym!@123
     virtual-host: /dev

+ 6 - 0
common/pom.xml

@@ -130,6 +130,12 @@
             <version>${weixin-java.version}</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.gavaghan</groupId>
+            <artifactId>geodesy</artifactId>
+            <version>1.1.3</version>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 29 - 0
common/src/main/java/com/kym/common/utils/GeodsyDistanceUtils.java

@@ -0,0 +1,29 @@
+package com.kym.common.utils;
+
+import org.gavaghan.geodesy.Ellipsoid;
+import org.gavaghan.geodesy.GeodeticCalculator;
+import org.gavaghan.geodesy.GeodeticCurve;
+import org.gavaghan.geodesy.GlobalCoordinates;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+public class GeodsyDistanceUtils {
+    /**
+     *
+     * @param lonA
+     * @param latA
+     * @param lonB
+     * @param latB
+     * @param newScale
+     * @return
+     */
+    public static double getDistance(Double lonA, Double latA, Double lonB, Double latB, int newScale) {
+        GlobalCoordinates source = new GlobalCoordinates(latA, lonA);
+        GlobalCoordinates target = new GlobalCoordinates(latB, lonB);
+        GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.Sphere, source, target);
+        double distance = geoCurve.getEllipsoidalDistance();
+        BigDecimal distanceBig = new BigDecimal(distance).setScale(newScale, RoundingMode.UP);
+        return distanceBig.doubleValue();
+    }
+}

+ 3 - 0
entity/src/main/java/com/kym/entity/admin/queryParams/StationQueryParam.java

@@ -10,4 +10,7 @@ import lombok.Data;
 public class StationQueryParam extends PageParams {
     private String stationId;
     private String stationName;
+
+    private Double longitude = 	114.044805;
+    private Double latitude = 22.696779;
 }

+ 101 - 0
entity/src/main/java/com/kym/entity/admin/vo/DetailStationVo.java

@@ -0,0 +1,101 @@
+package com.kym.entity.admin.vo;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.kym.entity.admin.Activity;
+import com.kym.entity.admin.ConnectorInfo;
+import com.kym.entity.admin.EquipmentInfo;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 充电站简单信息
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-08-12
+ */
+@Data
+@Accessors(chain = true)
+public class DetailStationVo {
+
+    /**
+     * en+充电站id
+     */
+    private String stationId;
+
+    /**
+     * 站点名称
+     */
+    private String stationName;
+
+    /**
+     * 站点照片
+     */
+    private String pictures;
+
+    /**
+     * 地址
+     */
+    private String address;
+
+    /**
+     * 站点状态:0:未知 1:建设中 5:关闭下线 6:维护中 50:正常使用
+     */
+    private Integer stationStatus;
+
+    /**
+     * 充电车位数量
+     */
+    private Integer parkingNum;
+
+    /**
+     * 空闲充电车位数量
+     */
+    private Integer availableParkingNum;
+
+    /**
+     * 充电桩位置坐标
+     * <p>
+     * FastjsonTypeHandler
+     * 支持 MVC JSON 解析
+     * 不支持 MySQL JSON 解析
+     * <p>
+     * JacksonTypeHandler
+     * 支持 MVC JSON 解析
+     * 支持 MySQL JSON 解析
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private JSONObject location;
+
+    /**
+     * 距离
+     */
+    private Double distance;
+
+    /**
+     * 充电费描述
+     */
+    private String electricityFee;
+
+    /**
+     * 服务费率描述
+     */
+    private String serviceFee;
+
+    /**
+     * 站点活动
+     */
+    private List<Activity> activityList;
+
+    /**
+     * 充电枪信息
+     */
+    private List<ConnectorInfo> connectInfoList;
+
+
+}

+ 91 - 0
entity/src/main/java/com/kym/entity/admin/vo/SimpleStationVo.java

@@ -0,0 +1,91 @@
+package com.kym.entity.admin.vo;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.kym.entity.BaseEntity;
+import com.kym.entity.admin.Activity;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 充电站简单信息
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-08-12
+ */
+@Data
+@Accessors(chain = true)
+public class SimpleStationVo {
+
+    /**
+     * en+充电站id
+     */
+    private String stationId;
+
+    /**
+     * 站点名称
+     */
+    private String stationName;
+
+    /**
+     * 地址
+     */
+    private String address;
+
+    /**
+     * 站点状态:0:未知 1:建设中 5:关闭下线 6:维护中 50:正常使用
+     */
+    private Integer stationStatus;
+
+    /**
+     * 充电车位数量
+     */
+    private Integer parkingNum;
+
+    /**
+     * 空闲充电车位数量
+     */
+    private Integer availableParkingNum;
+
+    /**
+     * 充电桩位置坐标
+     * <p>
+     * FastjsonTypeHandler
+     * 支持 MVC JSON 解析
+     * 不支持 MySQL JSON 解析
+     * <p>
+     * JacksonTypeHandler
+     * 支持 MVC JSON 解析
+     * 支持 MySQL JSON 解析
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private JSONObject location;
+
+    /**
+     * 距离
+     */
+    private Double distance;
+
+    /**
+     * 充电费描述
+     */
+    private String electricityFee;
+
+    /**
+     * 服务费率描述
+     */
+    private String serviceFee;
+
+    /**
+     * 站点活动
+     */
+    private List<Activity> activityList;
+
+
+}

+ 40 - 13
miniapp/src/main/java/com/kym/miniapp/controller/ChargerController.java → miniapp/src/main/java/com/kym/miniapp/controller/ChargeController.java

@@ -1,5 +1,6 @@
 package com.kym.miniapp.controller;
 
+import cn.dev33.satoken.annotation.SaIgnore;
 import cn.dev33.satoken.stp.StpUtil;
 import com.alibaba.fastjson2.JSONObject;
 import com.kym.common.R;
@@ -7,6 +8,7 @@ import com.kym.common.annotation.ApiLog;
 import com.kym.common.config.WxConfig;
 import com.kym.common.enums.WxApi;
 import com.kym.common.utils.HttpUtil;
+import com.kym.entity.admin.queryParams.StationQueryParam;
 import com.kym.entity.miniapp.ChargeOrder;
 import com.kym.entity.miniapp.queryParams.OrderQueryParams;
 import com.kym.entity.platform.response.PlatformResponse;
@@ -14,7 +16,6 @@ import com.kym.service.admin.StationService;
 import com.kym.service.miniapp.ChargeOrderService;
 import com.kym.service.miniapp.ChargeService;
 import com.kym.service.platform.PlatformNotifyService;
-import lombok.SneakyThrows;
 import org.springframework.format.annotation.DateTimeFormat;
 import org.springframework.web.bind.annotation.*;
 
@@ -30,7 +31,7 @@ import java.util.Map;
  */
 @RestController
 @RequestMapping("/charge")
-public class ChargerController {
+public class ChargeController {
 
     private final StationService stationService;
 
@@ -43,9 +44,9 @@ public class ChargerController {
     private final WxConfig wxConfig;
 
 
-    public ChargerController(StationService stationService, ChargeService chargeService,
-                             ChargeOrderService chargeOrderService,
-                             PlatformNotifyService enNotifyService, WxConfig wxConfig) {
+    public ChargeController(StationService stationService, ChargeService chargeService,
+                            ChargeOrderService chargeOrderService,
+                            PlatformNotifyService enNotifyService, WxConfig wxConfig) {
         this.stationService = stationService;
         this.chargeService = chargeService;
         this.chargeOrderService = chargeOrderService;
@@ -53,19 +54,45 @@ public class ChargerController {
         this.wxConfig = wxConfig;
     }
 
+//    /**
+//     * 充电站列表
+//     *
+//     * @param pageNum
+//     * @param pageSize
+//     * @return
+//     */
+//    @SneakyThrows
+//    @GetMapping("/listStation")
+//    @SaIgnore
+//    R<?> listChargeStation(
+//            @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
+//            @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
+//        return R.success(stationService.queryLocalStationInfo(pageNum, pageSize));
+//    }
+
+
     /**
      * 充电站列表
      *
-     * @param pageNum
-     * @param pageSize
+     * @param params
      * @return
      */
-    @SneakyThrows
     @GetMapping("/listStation")
-    R<?> listChargeStation(
-            @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
-            @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
-        return R.success(stationService.queryLocalStationInfo(pageNum, pageSize));
+    @SaIgnore
+    R<?> listChargeStation(@ModelAttribute StationQueryParam params) {
+        return R.success(stationService.listStationForApp(params));
+    }
+
+    /**
+     * 站点信息(包含充电枪信息)
+     *
+     * @param stationId
+     * @return
+     */
+    @GetMapping("/stationInfo/{stationId}")
+    @SaIgnore
+    R<?> stationInfo(@PathVariable String stationId) {
+        return R.success(stationService.stationInfo(stationId));
     }
 
     /**
@@ -202,7 +229,7 @@ public class ChargerController {
     @ApiLog("互联互通平台推送请求Token")
     @PostMapping("/{platformName}/query_token")
     PlatformResponse queryToken(@PathVariable(value = "platformName", required = false) String platformName, @RequestBody JSONObject json) {
-        return new PlatformResponse(enNotifyService.queryToken(platformName,json));
+        return new PlatformResponse(enNotifyService.queryToken(platformName, json));
     }
 
     /**

+ 6 - 6
miniapp/src/main/resources/application-dev.yml

@@ -64,19 +64,19 @@ spring:
       strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
       datasource:
         db-admin:
-          url: jdbc:mysql://121.40.98.15:3307/charge_admin?tinyInt1isBit=false&serverTimezone=Asia/Shanghai
+          url: jdbc:mysql://183.234.100.174:3306/charge_admin?tinyInt1isBit=false&serverTimezone=Asia/Shanghai
           username: root
           password: KuaiyuMan/*-
           driver-class-name: com.mysql.cj.jdbc.Driver
         db-miniapp:
-          url: jdbc:mysql://121.40.98.15:3307/charge_app
+          url: jdbc:mysql://183.234.100.174:3306/charge_app
           username: root
           password: KuaiyuMan/*-
           driver-class-name: com.mysql.cj.jdbc.Driver
   data:
     redis:
-      port: 6380
-      host: 121.40.98.15
+      port: 6379
+      host: 183.234.100.174
       password: KtXA^Zx!TZmLEy(@JjB@2(TVG0kdy5)&
       database: 10
       lettuce:
@@ -92,8 +92,8 @@ spring:
       # 缓存过期时间:7天
       time-to-live: 604800
   rabbitmq:
-    host: 121.40.98.15
-    port: 5674
+    host: 183.234.100.174
+    port: 5672
     username: kym
     password: kym!@123
     virtual-host: /dev

+ 13 - 6
service/src/main/java/com/kym/service/admin/StationService.java

@@ -8,8 +8,11 @@ import com.kym.entity.admin.ConnectorInfo;
 import com.kym.entity.admin.EquipmentInfo;
 import com.kym.entity.admin.Station;
 import com.kym.entity.admin.queryParams.StationQueryParam;
+import com.kym.entity.admin.vo.DetailStationVo;
 import com.kym.entity.admin.vo.LocalStationVo;
+import com.kym.entity.admin.vo.SimpleStationVo;
 import com.kym.entity.admin.vo.StationVo;
+import com.kym.entity.common.PageBean;
 import com.kym.entity.platform.PlatformStationStatsInfo;
 import com.kym.entity.platform.PlatformStationStatusInfo;
 
@@ -26,15 +29,19 @@ import java.util.Map;
  */
 public interface StationService extends MPJBaseService<Station> {
 
+    List<Station> listStation(StationQueryParam params);
+
     List<StationVo> queryPlatformStationInfo(String platformName, int pageNum, int pageSize) throws JsonProcessingException;
 
-    @DynamicCache
-    Map<String, List<EquipmentInfo>> getCachedEquipmentMap();
+    Map<String, List<EquipmentInfo>> getCachedEquipmentMap(String... stationId);
+
+    @DynamicCache(timeout = 15 * 60 * 1000L)
+    Map<String, List<ConnectorInfo>> getCachedStationConnectorMap(String... stationId);
 
-    @DynamicCache
-    Map<String, List<ConnectorInfo>> getCachedConnectorMap();
+    Map<String, List<ConnectorInfo>> getCachedStationConnectorMap();
+
+    DetailStationVo stationInfo(String stationId);
 
-    //    @DynamicCache // 方法的返回结果加一层方法缓存,5分钟内不变
     List<LocalStationVo> queryLocalStationInfo(int pageNum, int pageSize);
 
     List<PlatformStationStatusInfo> stationStatus(String[] ids);
@@ -47,5 +54,5 @@ public interface StationService extends MPJBaseService<Station> {
 
     void importStation(JSONObject data);
 
-    List<Station> listStation(StationQueryParam params);
+    PageBean<SimpleStationVo> listStationForApp(StationQueryParam params);
 }

+ 112 - 4
service/src/main/java/com/kym/service/admin/impl/StationServiceImpl.java

@@ -5,17 +5,23 @@ import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.github.pagehelper.PageHelper;
 import com.kym.common.annotation.DynamicCache;
 import com.kym.common.cache.PlatformCache;
 import com.kym.common.exception.BusinessException;
 import com.kym.common.utils.CommUtil;
+import com.kym.common.utils.GeodsyDistanceUtils;
 import com.kym.common.utils.PlatformAesUtil;
 import com.kym.common.utils.PlatformConvertUtil;
 import com.kym.entity.admin.*;
 import com.kym.entity.admin.queryParams.StationQueryParam;
+import com.kym.entity.admin.vo.DetailStationVo;
 import com.kym.entity.admin.vo.LocalStationVo;
+import com.kym.entity.admin.vo.SimpleStationVo;
 import com.kym.entity.admin.vo.StationVo;
+import com.kym.entity.common.PageBean;
 import com.kym.entity.platform.PlatformStationStatsInfo;
 import com.kym.entity.platform.PlatformStationStatusInfo;
 import com.kym.entity.platform.response.PlatformResponse;
@@ -137,26 +143,128 @@ public class StationServiceImpl extends MyBaseServiceImpl<StationMapper, Station
     }
 
 
+    /**
+     * 获取缓存的 站点ID:桩信息 映射
+     *
+     * @return
+     */
     @DynamicCache(timeout = 15 * 60 * 1000L)
     @Override
-    public Map<String, List<EquipmentInfo>> getCachedEquipmentMap() {
-        return equipmentInfoService.list().stream().collect(Collectors.groupingBy(EquipmentInfo::getStationId));
+    public Map<String, List<EquipmentInfo>> getCachedEquipmentMap(String... stationId) {
+        var list = equipmentInfoService.lambdaQuery().eq(CommUtil.isNotEmptyAndNull(stationId), EquipmentInfo::getStationId, stationId[0]).list();
+        return list.stream().collect(Collectors.groupingBy(EquipmentInfo::getStationId));
     }
 
+    /**
+     * 获取缓存的 桩ID:枪信息 映射
+     *
+     * @return
+     */
     @DynamicCache(timeout = 15 * 60 * 1000L)
     @Override
-    public Map<String, List<ConnectorInfo>> getCachedConnectorMap() {
+    public Map<String, List<ConnectorInfo>> getCachedStationConnectorMap(String... stationId) {
+        var list = connectorInfoService.lambdaQuery().eq(CommUtil.isNotEmptyAndNull(stationId), ConnectorInfo::getStationId, stationId[0]).list();
+        return list.stream().collect(Collectors.groupingBy(ConnectorInfo::getStationId));
+    }
+
+    /**
+     * 获取缓存的 桩ID:枪信息 映射
+     *
+     * @return
+     */
+    @DynamicCache(timeout = 15 * 60 * 1000L)
+    @Override
+    public Map<String, List<ConnectorInfo>> getCachedStationConnectorMap() {
         return connectorInfoService.list().stream().collect(Collectors.groupingBy(ConnectorInfo::getEquipmentId));
     }
 
 
+    /**
+     * APP首页地图接口,传入经纬度,按照距离由远到近返回站点列表
+     *
+     * @param params
+     * @return
+     */
+    @Override
+    @DynamicCache
+    public PageBean<SimpleStationVo> listStationForApp(StationQueryParam params) {
+        PageHelper.startPage(params.getPageNum(), params.getPageSize());
+        // 站点列表
+        LambdaQueryWrapper<Station> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.select(Station::getStationId, Station::getStationName, Station::getAddress, Station::getLocation,
+                Station::getStationStatus, Station::getParkingNum, Station::getElectricityFee, Station::getServiceFee, Station::getParkFee);
+        var stationVoList = new ArrayList<SimpleStationVo>();
+        var stationList = list(queryWrapper);
+        for (var station : stationList) {
+            var simpleStationVo = new SimpleStationVo();
+            BeanUtils.copyProperties(station, simpleStationVo);
+            // 计算距离,单位m
+            simpleStationVo.setDistance(GeodsyDistanceUtils.getDistance(
+                    station.getLocation().getDoubleValue("stationLng"),
+                    station.getLocation().getDoubleValue("stationLat"),
+                    params.getLongitude(),
+                    params.getLatitude(),
+                    2));
+            stationVoList.add(simpleStationVo);
+        }
+        // 按照距离由近到远排序
+        stationVoList.sort(Comparator.comparing(SimpleStationVo::getDistance));
+
+        // 计算站点空闲数量
+        var stationIds = stationVoList.stream().map(SimpleStationVo::getStationId).toList();
+        var stationConnectorCountMap = connectorInfoService.lambdaQuery()
+                .in(ConnectorInfo::getStationId, stationIds)
+                .eq(ConnectorInfo::getStatus, EquipmentInfo.SERVICE_STATUS_空闲)
+                .list()
+                .stream().collect(Collectors.groupingBy(ConnectorInfo::getStationId, Collectors.counting()));
+
+        // 填充站点空闲数量
+        stationVoList.forEach(stationVo -> stationVo.setAvailableParkingNum(stationConnectorCountMap.getOrDefault(stationVo.getStationId(), 0L).intValue()));
+
+        // 查询正在进行中的活动和各站点正在进行中的活动 (限充值优惠和优惠券领取活动) todo 性能待优化
+        var rechargeRightsActivityList = activityService.lambdaQuery().eq(Activity::getStatus, Activity.STATUS_进行中).eq(Activity::getDiscountType, Activity.DISCOUNT_TYPE_服务费折扣权益).list();
+        var couponActivityList = activityService.getAvailableCouponActivities();
+        var activityList = Stream.concat(rechargeRightsActivityList.stream(), couponActivityList.stream()).toList();
+
+        if (CommUtil.isNotEmptyAndNull(activityList)) {
+            var station2ActivityListMap = activityStationService.lambdaQuery().eq(ActivityStation::getStatus, Activity.STATUS_进行中).list()
+                    .stream().collect(Collectors.groupingBy(ActivityStation::getStationId));
+            var station2ActivityList = new HashMap<String, List<Activity>>();
+            station2ActivityListMap.forEach((k, v) -> station2ActivityList.put(k,
+                    v.stream().map(item -> activityList.stream().filter(activity -> activity.getId().equals(item.getActivityId())).findFirst().orElse(null)).toList()));
+            stationVoList.forEach(vo -> vo.setActivityList(station2ActivityList.get(vo.getStationId())));
+        }
+
+        return new PageBean<>(stationVoList);
+    }
+
+    /**
+     * 站点详情
+     *
+     * @param stationId
+     */
+    @Override
+    public DetailStationVo stationInfo(String stationId) {
+        var station = lambdaQuery().eq(Station::getStationId, stationId).oneOpt();
+        return station.map(s -> {
+            var vo = new DetailStationVo();
+            BeanUtils.copyProperties(s, vo);
+            // 填充桩信息
+            vo.setConnectInfoList(getCachedStationConnectorMap(s.getStationId()).get(s.getStationId()));
+            return vo;
+        }).orElse(null);
+    }
+
+
+    @Deprecated
     @Override
     @DynamicCache
     public List<LocalStationVo> queryLocalStationInfo(int pageNum, int pageSize) {
         StationService proxy = (StationService) AopContext.currentProxy();
         var stationList = list();
+        // 获取桩号等映射信息缓存
         var equipmentInfoMap = proxy.getCachedEquipmentMap();
-        var connectorInfoMap = proxy.getCachedConnectorMap();
+        var connectorInfoMap = proxy.getCachedStationConnectorMap();
 
         var stationVoList = new ArrayList<LocalStationVo>();
         for (var station : stationList) {