Răsfoiți Sursa

Merge branch 'dev_lx' into dev

# Conflicts:
#	admin/src/main/java/com/kym/admin/controller/PlatformController.java
#	entity/src/main/java/com/kym/entity/admin/Platform.java
#	mapper/src/main/java/com/kym/mapper/admin/PlatformMapper.java
#	mapper/src/main/resources/mappers/admin/PlatformMapper.xml
#	service/src/main/java/com/kym/service/admin/PlatformService.java
#	service/src/main/java/com/kym/service/admin/impl/PlatformServiceImpl.java
skyline 1 an în urmă
părinte
comite
ae389a8a3b
83 a modificat fișierele cu 1397 adăugiri și 1097 ștergeri
  1. 2 2
      admin-web/src/views/admin/ordering/index.vue
  2. 4 5
      admin/pom.xml
  3. 18 0
      admin/src/main/java/com/kym/admin/controller/ConnectorPlatformRelationController.java
  4. 0 2
      admin/src/main/java/com/kym/admin/controller/PlatformController.java
  5. 1 1
      admin/src/main/java/com/kym/admin/jobs/EnPlusSaasTokenJob.java
  6. 1 22
      admin/src/main/resources/application-dev.yml
  7. 1 22
      admin/src/main/resources/application-prod.yml
  8. 12 12
      common/pom.xml
  9. 14 0
      common/src/main/java/com/kym/common/annotation/ConnectorID.java
  10. 14 0
      common/src/main/java/com/kym/common/annotation/PlatformConvert.java
  11. 14 0
      common/src/main/java/com/kym/common/annotation/PlatformName.java
  12. 87 0
      common/src/main/java/com/kym/common/aspect/PlatformConvertAspect.java
  13. 84 0
      common/src/main/java/com/kym/common/cache/PlatformCache.java
  14. 0 21
      common/src/main/java/com/kym/common/config/EnPlusConfig.java
  15. 16 16
      common/src/main/java/com/kym/common/constant/ResponseEnum.java
  16. 0 13
      common/src/main/java/com/kym/common/enums/Api.java
  17. 0 45
      common/src/main/java/com/kym/common/enums/EnPlusApi.java
  18. 1 1
      common/src/main/java/com/kym/common/enums/WxApi.java
  19. 4 5
      common/src/main/java/com/kym/common/exception/PlatformPushException.java
  20. 3 3
      common/src/main/java/com/kym/common/handler/GlobalExceptionHandler.java
  21. 2 2
      common/src/main/java/com/kym/common/handler/ResponseResultHandler.java
  22. 0 133
      common/src/main/java/com/kym/common/utils/AESUtil.java
  23. 201 0
      common/src/main/java/com/kym/common/utils/PlatformAesUtil.java
  24. 58 0
      common/src/main/java/com/kym/common/utils/PlatformConvertUtil.java
  25. 0 11
      common/src/main/java/com/kym/common/wxpay/WxJsApi.java
  26. 5 6
      entity/pom.xml
  27. 1 2
      entity/src/main/java/com/kym/entity/admin/EquipmentRelation.java
  28. 1 2
      entity/src/main/java/com/kym/entity/admin/Platform.java
  29. 2 1
      entity/src/main/java/com/kym/entity/admin/queryParams/CustomChargeOrdersQueryParam.java
  30. 0 4
      entity/src/main/java/com/kym/entity/admin/vo/LocalStationVo.java
  31. 3 3
      entity/src/main/java/com/kym/entity/admin/vo/StationVo.java
  32. 6 1
      entity/src/main/java/com/kym/entity/common/RedisKeys.java
  33. 2 0
      entity/src/main/java/com/kym/entity/miniapp/ChargeOrder.java
  34. 2 2
      entity/src/main/java/com/kym/entity/platform/PlatformChargeDetails.java
  35. 2 2
      entity/src/main/java/com/kym/entity/platform/PlatformChargeOrder.java
  36. 3 3
      entity/src/main/java/com/kym/entity/platform/PlatformCheckOrderSeq.java
  37. 6 3
      entity/src/main/java/com/kym/entity/platform/PlatformConnectorInfo.java
  38. 6 2
      entity/src/main/java/com/kym/entity/platform/PlatformConnectorStatsInfo.java
  39. 5 2
      entity/src/main/java/com/kym/entity/platform/PlatformConnectorStatusInfo.java
  40. 7 7
      entity/src/main/java/com/kym/entity/platform/PlatformEquipmentInfo.java
  41. 3 4
      entity/src/main/java/com/kym/entity/platform/PlatformEquipmentStatsInfo.java
  42. 3 3
      entity/src/main/java/com/kym/entity/platform/PlatformNotificationChargeOrderInfo.java
  43. 3 3
      entity/src/main/java/com/kym/entity/platform/PlatformNotificationEquipChargeStatus.java
  44. 2 2
      entity/src/main/java/com/kym/entity/platform/PlatformNotificationStartChargeResult.java
  45. 2 2
      entity/src/main/java/com/kym/entity/platform/PlatformNotificationStopChargeResult.java
  46. 3 3
      entity/src/main/java/com/kym/entity/platform/PlatformPolicyInfo.java
  47. 2 2
      entity/src/main/java/com/kym/entity/platform/PlatformRespQueryToken.java
  48. 3 3
      entity/src/main/java/com/kym/entity/platform/PlatformStationInfo.java
  49. 3 3
      entity/src/main/java/com/kym/entity/platform/PlatformStationStatsInfo.java
  50. 5 5
      entity/src/main/java/com/kym/entity/platform/PlatformStationStatusInfo.java
  51. 13 8
      entity/src/main/java/com/kym/entity/platform/response/PlatformBusinessPolicy.java
  52. 4 5
      entity/src/main/java/com/kym/entity/platform/response/PlatformResponse.java
  53. 6 6
      mapper/pom.xml
  54. 13 7
      mapper/src/main/resources/mappers/miniapp/ChargeOrderMapper.xml
  55. 4 6
      miniapp/pom.xml
  56. 10 8
      miniapp/src/main/java/com/kym/miniapp/config/SaTokenConfigure.java
  57. 39 35
      miniapp/src/main/java/com/kym/miniapp/controller/ChargerController.java
  58. 1 1
      miniapp/src/main/java/com/kym/miniapp/jobs/StartChargeDelayJob.java
  59. 1 22
      miniapp/src/main/resources/application-dev.yml
  60. 1 22
      miniapp/src/main/resources/application-prod.yml
  61. 23 1
      pom.xml
  62. 4 5
      service/pom.xml
  63. 1 1
      service/src/main/java/com/kym/service/admin/PlatformService.java
  64. 7 7
      service/src/main/java/com/kym/service/admin/StationService.java
  65. 0 1
      service/src/main/java/com/kym/service/admin/impl/InvoiceDetailServiceImpl.java
  66. 3 3
      service/src/main/java/com/kym/service/admin/impl/PlatformServiceImpl.java
  67. 80 30
      service/src/main/java/com/kym/service/admin/impl/StationServiceImpl.java
  68. 24 3
      service/src/main/java/com/kym/service/cache/KymCache.java
  69. 0 22
      service/src/main/java/com/kym/service/enplus/EnNotifyService.java
  70. 0 32
      service/src/main/java/com/kym/service/enplus/EnPlusService.java
  71. 0 338
      service/src/main/java/com/kym/service/enplus/impl/EnPlusServiceImpl.java
  72. 2 3
      service/src/main/java/com/kym/service/miniapp/ChargeService.java
  73. 0 3
      service/src/main/java/com/kym/service/miniapp/CollectService.java
  74. 6 5
      service/src/main/java/com/kym/service/miniapp/impl/ChargeOrderServiceImpl.java
  75. 40 39
      service/src/main/java/com/kym/service/miniapp/impl/ChargeServiceImpl.java
  76. 0 19
      service/src/main/java/com/kym/service/miniapp/impl/CollectServiceImpl.java
  77. 9 0
      service/src/main/java/com/kym/service/platform/Api.java
  78. 38 0
      service/src/main/java/com/kym/service/platform/PlatformApi.java
  79. 34 0
      service/src/main/java/com/kym/service/platform/PlatformApiService.java
  80. 23 0
      service/src/main/java/com/kym/service/platform/PlatformNotifyService.java
  81. 294 0
      service/src/main/java/com/kym/service/platform/impl/PlatformApiServiceImpl.java
  82. 91 69
      service/src/main/java/com/kym/service/platform/impl/PlatformNotifyServiceImpl.java
  83. 9 10
      service/src/main/java/com/kym/service/wechat/impl/WxPayServiceImpl.java

+ 2 - 2
admin-web/src/views/admin/ordering/index.vue

@@ -41,7 +41,7 @@
             class="wd150 mr10">
         </el-input>
         <ext-select
-            v-model="state.formQuery.stationId"
+            v-model="state.formQuery.stationIds"
             placeholder="站点"
             clearable
             url="station/listStation"
@@ -411,4 +411,4 @@ const handleTableSortChange = (column, prop, order) => {
 // defineExpose({
 //     loadData,
 // });
-</script>
+</script>

+ 4 - 5
admin/pom.xml

@@ -17,7 +17,7 @@
         <dependency>
             <groupId>com.kym</groupId>
             <artifactId>service</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
+            <version>${project.version}</version>
         </dependency>
 
         <dependency>
@@ -34,19 +34,18 @@
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-validation</artifactId>
-            <version>3.1.1</version>
         </dependency>
 
         <dependency>
             <groupId>org.apache.poi</groupId>
             <artifactId>poi-ooxml</artifactId>
-            <version>5.2.3</version>
+            <version>${poi-ooxml.version}</version>
         </dependency>
 
         <dependency>
             <groupId>com.sun.mail</groupId>
             <artifactId>javax.mail</artifactId>
-            <version>1.6.2</version>
+            <version>${javax.mail.version}</version>
         </dependency>
 
     </dependencies>
@@ -77,4 +76,4 @@
     </build>
 
 
-</project>
+</project>

+ 18 - 0
admin/src/main/java/com/kym/admin/controller/ConnectorPlatformRelationController.java

@@ -0,0 +1,18 @@
+package com.kym.admin.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 充电桩接口(枪)互联互通平台关联表 前端控制器
+ * </p>
+ *
+ * @author skyline
+ * @since 2024-12-20
+ */
+@RestController
+@RequestMapping("/connector-platform-relation")
+public class ConnectorPlatformRelationController {
+
+}

+ 0 - 2
admin/src/main/java/com/kym/admin/controller/PlatformController.java

@@ -5,8 +5,6 @@ import com.kym.common.R;
 import com.kym.common.controller.IController;
 import com.kym.entity.admin.Platform;
 import com.kym.entity.admin.queryParams.CommonQueryParam;
-import com.kym.entity.admin.vo.AdminUserRoleVo;
-import com.kym.entity.admin.vo.AdminUserVo;
 import com.kym.service.admin.PlatformService;
 import jakarta.annotation.Resource;
 import org.springframework.web.bind.annotation.GetMapping;

+ 1 - 1
admin/src/main/java/com/kym/admin/jobs/EnPlusSaasTokenJob.java

@@ -14,7 +14,7 @@ import org.springframework.stereotype.Component;
  * @description EN+ SASS平台token刷新任务
  * @date 2023-09-30 16:15
  */
-@Component
+//@Component
 @Slf4j
 public class EnPlusSaasTokenJob {
 

+ 1 - 22
admin/src/main/resources/application-dev.yml

@@ -1,24 +1,3 @@
-# EN+充电配置
-en-plus:
-  # 运营商ID
-  operatorId: MA5HJNDG1
-  # 运营商密钥
-  operatorSecret: 5009db3dc1e94ea8
-  # 消息密钥
-  dataSecret: 8c15f5bf050948ba
-  # 消息密钥初始化向量
-  dataSecretIv: 915bea94fa13461d
-  # 签名密钥
-  sigSecret: 46050b0bb5b7415c
-  # 最小充电余额(分)
-  chargeMinAmount: 200
-  # 接口地址
-  apiDomain: https://dev.en-plus.cn/Charge/evcs/v1//MA5HJNDG1/
-  # sass配置
-  sass: https://dev.en-plus.cn/Charge/op/login?username=快与慢&password=Admin123
-  # sass结算订单
-  sassClose: https://dev.en-plus.cn/Charge/op/analyze/order/close?orderCode=
-
 # 微信支付
 wechat:
   payment:
@@ -124,7 +103,7 @@ spring:
     port: 5674
     username: kym
     password: kym!@123
-    virtual-host: /
+    virtual-host: /dev
     publisher-returns: true
     publisher-confirms: true
     listener:

+ 1 - 22
admin/src/main/resources/application-prod.yml

@@ -1,24 +1,3 @@
-# EN+充电配置
-en-plus:
-  # 运营商ID
-  operatorId: MA5HJNDG1
-  # 运营商密钥
-  operatorSecret: c7fd9b753a9f434e
-  # 消息密钥
-  dataSecret: 5cb7e12da198420a
-  # 消息密钥初始化向量
-  dataSecretIv: 8a6ac88326bc4d3f
-  # 签名密钥
-  sigSecret: 2365b20f69e44817
-  # 最小充电余额(分)
-  chargeMinAmount: 200
-  # 接口地址
-  apiDomain: https://api.en-plus.cn:8080/Charge/evcs/v1//MA5HJNDG1/
-  # sass配置
-  sass: https://api.en-plus.cn:8080/Charge/op/login?username=快与慢工程&password=Kuaiyuman2o22
-  # sass结算订单
-  sassClose: https://api.en-plus.cn:8080/Charge/op/analyze/order/close?orderCode=
-
 # 微信支付
 wechat:
   payment:
@@ -140,4 +119,4 @@ spring:
         batch-size: 100 #每次批量消费大小
 
 kym:
-  notify-email: zaizai@kuaiyuman.cn,skyline@kuaiyuman.cn
+  notify-email: zaizai@kuaiyuman.cn,skyline@kuaiyuman.cn

+ 12 - 12
common/pom.xml

@@ -21,7 +21,7 @@
         <dependency>
             <groupId>com.kym</groupId>
             <artifactId>entity</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
+            <version>${project.version}</version>
         </dependency>
 
         <dependency>
@@ -45,47 +45,47 @@
         <dependency>
             <groupId>jakarta.servlet</groupId>
             <artifactId>jakarta.servlet-api</artifactId>
-            <version>6.0.0</version>
+            <version>${jakarta.servlet-api.version}</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>com.google.code.gson</groupId>
             <artifactId>gson</artifactId>
-            <version>2.10.1</version>
+            <version>${gson.version}</version>
         </dependency>
 
         <dependency>
             <groupId>com.auth0</groupId>
             <artifactId>java-jwt</artifactId>
-            <version>4.4.0</version>
+            <version>${jwt.version}</version>
         </dependency>
         <dependency>
             <groupId>io.jsonwebtoken</groupId>
             <artifactId>jjwt-api</artifactId>
-            <version>0.11.5</version>
+            <version>${jjwt-api.version}</version>
         </dependency>
         <dependency>
             <groupId>cn.dev33</groupId>
             <artifactId>sa-token-spring-boot3-starter</artifactId>
-            <version>1.38.0</version>
+            <version>${sa-token.version}</version>
         </dependency>
         <!-- sa-token 集成redis-->
         <dependency>
             <groupId>cn.dev33</groupId>
             <artifactId>sa-token-redis-jackson</artifactId>
-            <version>1.38.0</version>
+            <version>${sa-token.version}</version>
         </dependency>
 
         <dependency>
             <groupId>com.squareup.okhttp3</groupId>
             <artifactId>okhttp</artifactId>
-            <version>4.11.0</version>
+            <version>${okhttp.version}</version>
         </dependency>
 
         <dependency>
             <groupId>cn.hutool</groupId>
             <artifactId>hutool-all</artifactId>
-            <version>5.8.21</version>
+            <version>${hutool.version}</version>
         </dependency>
 
         <dependency>
@@ -121,15 +121,15 @@
         <dependency>
             <groupId>com.github.binarywang</groupId>
             <artifactId>weixin-java-miniapp</artifactId>
-            <version>4.6.0</version>
+            <version>${weixin-java.version}</version>
         </dependency>
 
         <dependency>
             <groupId>com.github.binarywang</groupId>
             <artifactId>weixin-java-mp</artifactId>
-            <version>4.6.0</version>
+            <version>${weixin-java.version}</version>
         </dependency>
 
     </dependencies>
 
-</project>
+</project>

+ 14 - 0
common/src/main/java/com/kym/common/annotation/ConnectorID.java

@@ -0,0 +1,14 @@
+package com.kym.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 标记ConnectorID
+ *
+ * @author skyline
+ */
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ConnectorID {
+}

+ 14 - 0
common/src/main/java/com/kym/common/annotation/PlatformConvert.java

@@ -0,0 +1,14 @@
+package com.kym.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 平台数据转换注解
+ *
+ * @author skyline
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface PlatformConvert {
+}

+ 14 - 0
common/src/main/java/com/kym/common/annotation/PlatformName.java

@@ -0,0 +1,14 @@
+package com.kym.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 标记platformName
+ *
+ * @author skyline
+ */
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface PlatformName {
+}

+ 87 - 0
common/src/main/java/com/kym/common/aspect/PlatformConvertAspect.java

@@ -0,0 +1,87 @@
+package com.kym.common.aspect;
+
+import com.kym.common.annotation.ConnectorID;
+import com.kym.common.annotation.PlatformName;
+import com.kym.common.exception.BusinessException;
+import com.kym.common.utils.PlatformConvertUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+
+
+/**
+ * APP日志,切面处理类
+ *
+ * @author skyline
+ */
+@Aspect
+@Component
+@Slf4j
+public class PlatformConvertAspect {
+
+
+    /**
+     * 切点
+     */
+    @Pointcut("@annotation(com.kym.common.annotation.PlatformConvert)")
+    public void platformConvertPointCut() {
+    }
+
+    @Around("platformConvertPointCut()")
+    Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
+        return convert(joinPoint);
+    }
+
+
+    private Object convert(ProceedingJoinPoint joinPoint) throws Throwable {
+        if (joinPoint == null) {
+            throw new IllegalArgumentException("joinPoint cannot be null");
+        }
+
+        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+        Method method = signature.getMethod();
+        if (method == null) {
+            throw new IllegalArgumentException("method cannot be null");
+        }
+
+        Parameter[] parameters = method.getParameters();
+        Object[] args = joinPoint.getArgs();
+        Platform platformName = Platform.EN_PLUS;
+
+        for (int i = 0; i < parameters.length; i++) {
+            Parameter parameter = parameters[i];
+            if (parameter.isAnnotationPresent(PlatformName.class)) {
+                if (args[i] != null) {
+                    platformName = Platform.valueOf(args[i].toString());
+                }
+            } else if (parameter.isAnnotationPresent(ConnectorID.class)) {
+                if (args[i] != null) {
+                    switch (platformName) {
+                        case EN_PLUS:
+                            args[i] = PlatformConvertUtil.parse2LocalConnectorId(args[i].toString());
+                            break;
+                        case LONGSHINE:
+                            args[i] = PlatformConvertUtil.convert2LongshineConnectorId(args[i].toString());
+                            break;
+                        default:
+                            throw new BusinessException("不支持的平台:" + platformName);
+                    }
+                }
+            }
+        }
+
+        return joinPoint.proceed(args);
+    }
+
+    // 枚举类定义
+    enum Platform {
+        EN_PLUS, LONGSHINE
+    }
+}

+ 84 - 0
common/src/main/java/com/kym/common/cache/PlatformCache.java

@@ -0,0 +1,84 @@
+package com.kym.common.cache;
+
+import com.kym.common.utils.PlatformConvertUtil;
+import com.kym.entity.admin.Platform;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 平台配置缓存
+ *
+ * @author skyline
+ */
+public enum PlatformCache {
+    INSTANCE;
+
+    /**
+     * 充电口ID-平台映射
+     */
+    private static ConcurrentHashMap<String, String> CONNECTOR_ID_PLATFORM_NAME_MAPPING = new ConcurrentHashMap<>();
+
+    /**
+     * 站点ID-平台映射
+     */
+    private static ConcurrentHashMap<String, String> STATION_ID_PLATFORM_NAME_MAPPING = new ConcurrentHashMap<>();
+
+    /**
+     * 平台名称-平台配置映射
+     */
+    private static ConcurrentHashMap<String, Platform> PLATFORM_CONFIG_MAPPING = new ConcurrentHashMap<>();
+
+    /**
+     * 站点ID获取平台名称
+     *
+     * @param stationId
+     * @return
+     */
+    public String getPlatformNameByStationId(String stationId) {
+        return STATION_ID_PLATFORM_NAME_MAPPING.get(stationId);
+    }
+
+    public void putConnectorId2PlatformName(Map<String, String> data) {
+        CONNECTOR_ID_PLATFORM_NAME_MAPPING.putAll(data);
+    }
+
+    /**
+     * 保存站点id-平台映射
+     *
+     * @param data
+     */
+    public void putStationId2PlatformName(Map<String, String> data) {
+        STATION_ID_PLATFORM_NAME_MAPPING.putAll(data);
+    }
+
+    public void putPlatformName2Config(Map<String, Platform> data) {
+        PLATFORM_CONFIG_MAPPING.putAll(data);
+    }
+
+    public String getPlatformNameByConnectorId(String connectorId) {
+        connectorId = PlatformConvertUtil.parse2LocalConnectorId(connectorId);
+        return CONNECTOR_ID_PLATFORM_NAME_MAPPING.get(connectorId);
+    }
+
+    public Platform getPlatformByName(String... platformName) {
+        var name = "EN_PLUS";
+        if (platformName.length > 0 && platformName[0] != null) {
+            name = platformName[0];
+        }
+        return PLATFORM_CONFIG_MAPPING.get(name);
+    }
+
+    /**
+     * 根据充电口ID获取平台配置
+     *
+     * @param connectorId
+     * @return
+     */
+    public Platform getPlatformByConnectorId(String connectorId) {
+        connectorId = PlatformConvertUtil.parse2LocalConnectorId(connectorId);
+        var platformName = getPlatformNameByConnectorId(connectorId);
+        return PLATFORM_CONFIG_MAPPING.get(platformName);
+    }
+
+}

+ 0 - 21
common/src/main/java/com/kym/common/config/EnPlusConfig.java

@@ -1,21 +0,0 @@
-package com.kym.common.config;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
-
-
-@Data
-@Configuration("EnPlusConfig")
-@ConfigurationProperties(prefix = "en-plus")
-public class EnPlusConfig {
-    private String operatorId;
-    private String operatorSecret;
-    private String dataSecret;
-    private String dataSecretIv;
-    private String sigSecret;
-    private int chargeMinAmount;
-    private String apiDomain;
-    private String sass;
-    private String sassClose;
-}

+ 16 - 16
common/src/main/java/com/kym/common/constant/ResponseEnum.java

@@ -25,7 +25,7 @@ public enum ResponseEnum implements BusinessExceptionAssert {
     WX_MP_LOGIN_ERROR(301, "微信登录异常"),
 
     // 微信支付
-    WX_PAY_AMOUNT_ERROR(300001,"微信支付金额异常"),
+    WX_PAY_AMOUNT_ERROR(300001, "微信支付金额异常"),
 
 
     // 登录 权限
@@ -37,24 +37,24 @@ public enum ResponseEnum implements BusinessExceptionAssert {
     ORDER_IN_PROGRESS(20001, "用户有进行中的订单"),
     NO_ORDER_IN_PROGRESS(20002, "用户无进行中的订单"),
     INSUFFICIENT_USER_BALANCE(20003, "用户余额不足"),
-    EN_PLUS_EQUIP_AUTH_FAIL(20004, "设备认证失败"),
-    EN_PLUS_EQUIP_NOT_CONNECTED(20005, "设备未连接"),
-    EN_PLUS_ORDER_IS_PARKING(20006, "此订单为停车中"),
-    EN_PLUS_ORDER_CLOSED(20007, "此订单已关闭"),
-    EN_PLUS_EQUIP_CHECK_FAIL(20008, "设备检测失败"),
-    EN_PLUS_EQUIP_START_FAIL(20009, "设备启动充电失败"),
-    EN_PLUS_EQUIP_NOT_EXIST(20010, "设备不存在"),
-    EN_PLUS_EQUIP_OFFLINE(20011, "设备离线"),
-    EN_PLUS_EQUIP_STOP_FAIL(20012, "设备停止充电失败"),
-    EN_PLUS_EQUIP_EXIST_ORDER_UNFINISHED(20013, "设备存在未完成的订单"),
+    PLATFORM_EQUIP_AUTH_FAIL(20004, "设备认证失败"),
+    PLATFORM_EQUIP_NOT_CONNECTED(20005, "设备未连接"),
+    PLATFORM_ORDER_IS_PARKING(20006, "此订单为停车中"),
+    PLATFORM_ORDER_CLOSED(20007, "此订单已关闭"),
+    PLATFORM_EQUIP_CHECK_FAIL(20008, "设备检测失败"),
+    PLATFORM_EQUIP_START_FAIL(20009, "设备启动充电失败"),
+    PLATFORM_EQUIP_NOT_EXIST(20010, "设备不存在"),
+    PLATFORM_EQUIP_OFFLINE(20011, "设备离线"),
+    PLATFORM_EQUIP_STOP_FAIL(20012, "设备停止充电失败"),
+    PLATFORM_EQUIP_EXIST_ORDER_UNFINISHED(20013, "设备存在未完成的订单"),
     ORDER_IN_BOOKING(20014, "用户有预约中的订单"),
 
 
-    // EN+
-    EN_PLUS_API_EXCEPTION(90000, "接口数据异常"),
-    EN_PLUS_QUERY_TOKEN_ERROR(90001, "TOKEN获取异常"),
-    EN_PLUS_PUSH_SIGN_FAIL(90002, "EN+推送数据验签失败"),
-    EN_PLUS_TOKEN_EXCEPTION(90003,"EN+TOKEN过期");
+    // 互联互通平台
+    PLATFORM_API_EXCEPTION(90000, "接口数据异常"),
+    PLATFORM_QUERY_TOKEN_ERROR(90001, "TOKEN获取异常"),
+    PLATFORM_PUSH_SIGN_FAIL(90002, "推送数据验签失败"),
+    PLATFORM_QUERY_TOKEN_EXCEPTION(90003, "EN+TOKEN过期");
 
     private final Integer code;
     private final String message;

+ 0 - 13
common/src/main/java/com/kym/common/enums/Api.java

@@ -1,13 +0,0 @@
-package com.kym.common.enums;
-
-import org.springframework.web.bind.annotation.RequestMethod;
-
-/**
- * @author skyline
- * @description
- * @date 2023-07-08 10:34
- */
-public interface Api {
-    String getApi();
-    RequestMethod getRequestMethod();
-}

+ 0 - 45
common/src/main/java/com/kym/common/enums/EnPlusApi.java

@@ -1,45 +0,0 @@
-package com.kym.common.enums;
-
-import cn.hutool.extra.spring.SpringUtil;
-import com.kym.common.config.EnPlusConfig;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import org.springframework.web.bind.annotation.RequestMethod;
-
-
-/**
- * @author skyline
- * @description EN+接口
- * @date 2023-07-29 12:33
- */
-@AllArgsConstructor
-@Getter
-public enum EnPlusApi implements Api {
-
-    // 认证-获取token
-    EN_PLUS_QUERY_TOKEN(Constants.DOMAIN + "query_token", RequestMethod.POST), //获取AccessToken
-
-    // 站点
-    EN_PLUS_QUERY_STATION_INFO(Constants.DOMAIN + "query_stations_info", RequestMethod.POST), // 站点信息
-    EN_PLUS_QUERY_STATION_STATUS(Constants.DOMAIN + "query_station_status", RequestMethod.POST), // 站点状态
-    EN_PLUS_QUERY_STATION_STATS(Constants.DOMAIN + "query_station_stats", RequestMethod.POST), // 站点统计
-    //充电
-    EN_PLUS_QUERY_EQUIP_AUTH(Constants.DOMAIN + "query_equip_auth", RequestMethod.POST), // 请求设备认证
-    EN_PLUS_QUERY_EQUIP_BUSINESS_POLICY(Constants.DOMAIN + "query_equip_business_policy", RequestMethod.POST), // 查询业务策略信息
-    EN_PLUS_QUERY_START_CHARGE(Constants.DOMAIN + "query_start_charge", RequestMethod.POST), // 查询启动充电
-    EN_PLUS_QUERY_STOP_CHARGE(Constants.DOMAIN + "query_stop_charge", RequestMethod.POST), // 请求停止充电
-    EN_PLUS_QUERY_EQUIP_CHARGE_STATUS(Constants.DOMAIN + "query_equip_charge_status", RequestMethod.POST), // 查询设备充电状态
-
-    //微信
-    WX_MP_GET_PHONE("", RequestMethod.POST), // 获取手机号
-    WX_GET_ACCESS_TOKEN("", RequestMethod.POST); // 获取AccessToken
-
-    private final String api;
-    private final RequestMethod requestMethod;
-
-
-    private static class Constants {
-        static EnPlusConfig config = SpringUtil.getBean("EnPlusConfig");
-        private static final String DOMAIN = config.getApiDomain();
-    }
-}

+ 1 - 1
common/src/main/java/com/kym/common/enums/WxApi.java

@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
  */
 @AllArgsConstructor
 @Getter
-public enum WxApi implements Api {
+public enum WxApi {
 
     // 微信小程序登录
     WX_MP_LOGIN("https://api.weixin.qq.com/sns/jscode2session?grant_type=authorization_code", RequestMethod.GET),

+ 4 - 5
common/src/main/java/com/kym/common/exception/EnPushException.java → common/src/main/java/com/kym/common/exception/PlatformPushException.java

@@ -5,18 +5,17 @@ import lombok.Getter;
 
 /**
  * @author skyline
- * @description EN+推送数据数据异常
- * @date 2023-08-04 13:36
+ * 互联互通平台推送数据数据异常
  */
 @Getter
-public class EnPushException extends RuntimeException {
+public class PlatformPushException extends RuntimeException {
     Integer code;
     String message;
     Object data;
 
-    public EnPushException(IResponseCode responseEnum, Object data) {
+    public PlatformPushException(IResponseCode responseEnum, Object data) {
         this.code = responseEnum.getCode();
         this.message = responseEnum.getMessage();
         this.data = data;
     }
-}
+}

+ 3 - 3
common/src/main/java/com/kym/common/handler/GlobalExceptionHandler.java

@@ -6,7 +6,7 @@ import cn.dev33.satoken.exception.NotRoleException;
 import com.kym.common.R;
 import com.kym.common.exception.BaseException;
 import com.kym.common.exception.BusinessException;
-import com.kym.common.exception.EnPushException;
+import com.kym.common.exception.PlatformPushException;
 import jakarta.validation.ConstraintViolation;
 import jakarta.validation.ConstraintViolationException;
 import jakarta.validation.ValidationException;
@@ -103,9 +103,9 @@ public class GlobalExceptionHandler {
      * @param e
      * @return
      */
-    @ExceptionHandler(value = EnPushException.class)
+    @ExceptionHandler(value = PlatformPushException.class)
     @ResponseBody
-    public Object handleEnPushException(EnPushException e) {
+    public Object handleEnPushException(PlatformPushException e) {
         return e.getData();
     }
 

+ 2 - 2
common/src/main/java/com/kym/common/handler/ResponseResultHandler.java

@@ -1,7 +1,7 @@
 package com.kym.common.handler;
 
 import com.kym.common.R;
-import com.kym.entity.enplus.response.EnResponse;
+import com.kym.entity.platform.response.PlatformResponse;
 import org.springframework.core.MethodParameter;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
@@ -36,7 +36,7 @@ public class ResponseResultHandler implements ResponseBodyAdvice {
                                   Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
 
         // 响应给en+,微信的信息不做处理
-        if (body instanceof R<?> || body instanceof EnResponse || body instanceof ResponseEntity) {
+        if (body instanceof R<?> || body instanceof PlatformResponse || body instanceof ResponseEntity) {
             return body;
         } else if (body == null) {
             return R.success();

+ 0 - 133
common/src/main/java/com/kym/common/utils/AESUtil.java

@@ -1,133 +0,0 @@
-package com.kym.common.utils;
-
-
-import com.kym.common.config.EnPlusConfig;
-import org.apache.tomcat.util.codec.binary.Base64;
-import org.springframework.stereotype.Component;
-
-import javax.crypto.Cipher;
-import javax.crypto.KeyGenerator;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-import java.security.SecureRandom;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * @author skyline
- * @description AES加解密工具
- * @date 2023-07-30 01:41
- */
-@Component
-public class AESUtil {
-
-    //编码方式
-    public static final String CODE_TYPE = "UTF-8";
-    //AES:加密方式   CBC:工作模式   PKCS5Padding:填充模式
-    private static final String CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";
-    private static final String AES = "AES";
-
-
-    static EnPlusConfig config;
-
-    public AESUtil(EnPlusConfig config) {
-        AESUtil.config = config;
-    }
-
-    /**
-     * AES 加密操作
-     *
-     * @param content 待加密内容
-     * @return 返回Base64转码后的加密数据
-     */
-    public static String encrypt(String content) {
-
-        if (content == null || "".equals(content)) {
-            return content;
-        }
-
-        try {
-            /*
-             * 新建一个密码编译器的实例,由三部分构成,用"/"分隔,分别代表如下
-             * 1. 加密的类型(如AES,DES,RC2等)
-             * 2. 模式(AES中包含ECB,CBC,CFB,CTR,CTS等)
-             * 3. 补码方式(包含nopadding/PKCS5Padding等等)
-             * 依据这三个参数可以创建很多种加密方式
-             */
-            Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
-
-            //偏移量
-            IvParameterSpec zeroIv = new IvParameterSpec(config.getDataSecretIv().getBytes(CODE_TYPE));
-
-            byte[] byteContent = content.getBytes(CODE_TYPE);
-
-            //使用加密秘钥
-            SecretKeySpec skeySpec = new SecretKeySpec(config.getDataSecret().getBytes(CODE_TYPE), AES);
-            //SecretKeySpec skeySpec = getSecretKey(key);
-
-            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, zeroIv);// 初始化为加密模式的密码器
-
-            byte[] result = cipher.doFinal(byteContent);// 加密
-
-            return Base64.encodeBase64String(result);//通过Base64转码返回
-        } catch (Exception ex) {
-            Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
-        }
-
-        return null;
-
-    }
-
-    /**
-     * AES 解密操作
-     *
-     * @param content
-     * @return
-     */
-    public static String decrypt(String content) {
-        if (content == null || "".equals(content)) {
-            return content;
-        }
-
-        try {
-            //实例化
-            Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
-            IvParameterSpec zeroIv = new IvParameterSpec(config.getDataSecretIv().getBytes(CODE_TYPE));
-
-            SecretKeySpec skeySpec = new SecretKeySpec(config.getDataSecret().getBytes(CODE_TYPE), AES);
-            //SecretKeySpec skeySpec = getSecretKey(key);
-            cipher.init(Cipher.DECRYPT_MODE, skeySpec, zeroIv);
-
-            byte[] result = cipher.doFinal(Base64.decodeBase64(content));
-
-            return new String(result, CODE_TYPE);
-        } catch (Exception ex) {
-            Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
-        }
-
-        return null;
-    }
-
-    /**
-     * 生成加密秘钥
-     *
-     * @return
-     */
-    private static SecretKeySpec getSecretKey(final String key) {
-        //返回生成指定算法密钥生成器的 KeyGenerator 对象
-        KeyGenerator kg;
-        try {
-            kg = KeyGenerator.getInstance(AES);
-            //AES 要求密钥长度为 128
-            kg.init(128, new SecureRandom(key.getBytes()));
-            //生成一个密钥
-            SecretKey secretKey = kg.generateKey();
-            // 转换为AES专用密钥
-            return new SecretKeySpec(secretKey.getEncoded(), AES);
-        } catch (Exception ex) {
-            Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
-        }
-        return null;
-    }
-}

+ 201 - 0
common/src/main/java/com/kym/common/utils/PlatformAesUtil.java

@@ -0,0 +1,201 @@
+package com.kym.common.utils;
+
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.LocalDateTimeUtil;
+import cn.hutool.crypto.digest.HMac;
+import cn.hutool.crypto.digest.HmacAlgorithm;
+import com.alibaba.fastjson2.JSONObject;
+import com.kym.common.cache.PlatformCache;
+import com.kym.common.constant.ResponseEnum;
+import com.kym.common.exception.PlatformPushException;
+import com.kym.entity.platform.response.PlatformResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.tomcat.util.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * 各互联互通平台AES加解密工具
+ *
+ * @author skyline
+ */
+@Slf4j
+public class PlatformAesUtil {
+
+    /**
+     * AES:加密方式   CBC:工作模式   PKCS5Padding:填充模式
+     */
+    private static final String CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";
+    private static final String AES = "AES";
+
+
+    /**
+     * AES 加密操作
+     *
+     * @param dataSecret
+     * @param dataSecretIv
+     * @param content      待加密内容
+     * @return 返回Base64转码后的加密数据
+     */
+    public static String encrypt(String dataSecret, String dataSecretIv, String content) {
+
+        if (content == null || content.isEmpty()) {
+            return content;
+        }
+
+        try {
+            /*
+             * 新建一个密码编译器的实例,由三部分构成,用"/"分隔,分别代表如下
+             * 1. 加密的类型(如AES,DES,RC2等)
+             * 2. 模式(AES中包含ECB,CBC,CFB,CTR,CTS等)
+             * 3. 补码方式(包含nopadding/PKCS5Padding等等)
+             * 依据这三个参数可以创建很多种加密方式
+             */
+            Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
+
+            //偏移量
+            IvParameterSpec zeroIv = new IvParameterSpec(dataSecretIv.getBytes(StandardCharsets.UTF_8));
+
+            byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
+
+            //使用加密秘钥
+            SecretKeySpec skeySpec = new SecretKeySpec(dataSecret.getBytes(StandardCharsets.UTF_8), AES);
+            //初始化为加密模式的密码器
+            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, zeroIv);
+            // 加密
+            byte[] result = cipher.doFinal(byteContent);
+            // 通过Base64转码返回
+            return Base64.encodeBase64String(result);
+        } catch (Exception ex) {
+            Logger.getLogger(PlatformAesUtil.class.getName()).log(Level.SEVERE, null, ex);
+        }
+
+        return null;
+
+    }
+
+    /**
+     * AES 解密操作
+     *
+     * @param dataSecret
+     * @param dataSecretIv
+     * @param content
+     * @return
+     */
+    public static String decrypt(String dataSecret, String dataSecretIv, String content) {
+        if (content == null || content.isEmpty()) {
+            return content;
+        }
+
+        try {
+            //实例化
+            Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
+            IvParameterSpec zeroIv = new IvParameterSpec(dataSecretIv.getBytes(StandardCharsets.UTF_8));
+
+            SecretKeySpec skeySpec = new SecretKeySpec(dataSecret.getBytes(StandardCharsets.UTF_8), AES);
+            //SecretKeySpec skeySpec = getSecretKey(key);
+            cipher.init(Cipher.DECRYPT_MODE, skeySpec, zeroIv);
+
+            byte[] result = cipher.doFinal(Base64.decodeBase64(content));
+
+            return new String(result, StandardCharsets.UTF_8);
+        } catch (Exception ex) {
+            Logger.getLogger(PlatformAesUtil.class.getName()).log(Level.SEVERE, null, ex);
+        }
+
+        return null;
+    }
+
+    /**
+     * 生成加密秘钥
+     *
+     * @return
+     */
+//    private static SecretKeySpec getSecretKey(final String key) {
+//        //返回生成指定算法密钥生成器的 KeyGenerator 对象
+//        KeyGenerator kg;
+//        try {
+//            kg = KeyGenerator.getInstance(AES);
+//            //AES 要求密钥长度为 128
+//            kg.init(128, new SecureRandom(key.getBytes()));
+//            //生成一个密钥
+//            SecretKey secretKey = kg.generateKey();
+//            // 转换为AES专用密钥
+//            return new SecretKeySpec(secretKey.getEncoded(), AES);
+//        } catch (Exception ex) {
+//            Logger.getLogger(PlatformAesUtil.class.getName()).log(Level.SEVERE, null, ex);
+//        }
+//        return null;
+//    }
+
+    /**
+     * 验签、解密推送消息
+     *
+     * @param platformName
+     * @param json
+     * @return
+     */
+    public static String signValidation(String platformName, JSONObject json) {
+        var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        // 验签 解密数据
+        var OperatorID = json.getString("OperatorID");
+        var Data = json.getString("Data");
+        var TimeStamp = json.getString("TimeStamp");
+        var Seq = json.getString("Seq");
+        var Sig = json.getString("Sig");
+        var signString = OperatorID + Data + TimeStamp + Seq;
+        HMac mac = new HMac(HmacAlgorithm.HmacMD5, platform.getUserSigSecret().getBytes());
+        // 签名(转为大写)
+        var sign = mac.digestHex(signString).toUpperCase();
+        if (sign.equals(Sig)) {
+            // 解密数据
+            return PlatformAesUtil.decrypt(platform.getUserDataSecret(), platform.getUserDataSecretIv(), Data);
+        } else {
+            // 验签失败
+            PlatformResponse platformResponse = new PlatformResponse();
+            platformResponse.setRet(4001);
+            platformResponse.setMsg(ResponseEnum.PLATFORM_PUSH_SIGN_FAIL.getMessage());
+            log.error("{}推送数据验签失败,数据:{}", platformName, json);
+            throw new PlatformPushException(ResponseEnum.PLATFORM_PUSH_SIGN_FAIL, platformResponse);
+        }
+
+    }
+
+    /**
+     * 构建平台参数(向谁请求数据则用谁的秘钥。OperatorID请求者的)
+     *
+     * @param platformName
+     * @param params
+     * @return
+     */
+    public static String buildPlatformParams(String platformName, String params) {
+        var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        // 使用DataSecret对data加密
+        var dataStr = PlatformAesUtil.encrypt(platform.getDataSecret(), platform.getDataSecretIv(), params);
+        // 时间戳
+        var timeStamp = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
+        // 自增序列
+        var seq = timeStamp.substring(timeStamp.length() - 4);
+        // 使用SigSecret以HMAC-MD5算法对消息体签名(签名顺序:OperatorId、Data、TimeStamp、Seq)
+        var signString = platform.getUserOperatorId() + dataStr + timeStamp + seq;
+        HMac mac = new HMac(HmacAlgorithm.HmacMD5, platform.getSigSecret().getBytes());
+        // 签名(转为大写)
+        var sign = mac.digestHex(signString).toUpperCase();
+        return """
+                {
+                    "OperatorID":"%s",
+                    "Data":"%s",
+                    "TimeStamp":"%s",
+                    "Seq":"%s",
+                    "Sig":"%s"
+                }
+                """.formatted(platform.getOperatorId(), dataStr, timeStamp, seq, sign);
+    }
+}

+ 58 - 0
common/src/main/java/com/kym/common/utils/PlatformConvertUtil.java

@@ -0,0 +1,58 @@
+package com.kym.common.utils;
+
+import com.alibaba.fastjson2.JSONObject;
+
+/**
+ * 互联互通平台转换工具
+ *
+ * @author skyline
+ */
+public class PlatformConvertUtil {
+
+    public static String queryStartChargeParamsConvert(String platformName, String paramsJson, Integer balance) {
+        // 如果是朗新平台,参数增加ChargingAmt(单位元),其他为amount(单位分)
+        var json = JSONObject.parseObject(paramsJson);
+        if ("EN_PLUS".equals(platformName)) {
+            // EN+平台不做超消费控制,自行实现低于0.5元自动停止充电
+            json.put("amount", balance - 50);
+            return json.toJSONString();
+        }
+        if ("LONGSHINE".equals(platformName)) {
+            // 朗新平台默认低于1元则下发停止充电指令,这里加0.5统一成低于0.5元则停止充电防止超金额消费
+            json.put("ChargingAmt", balance + 0.5);
+            return json.toJSONString();
+        }
+        return paramsJson;
+    }
+
+
+    /**
+     * 将ConnectorID转化成本地格式
+     *
+     * @param connectorId
+     * @return
+     */
+    public static String parse2LocalConnectorId(String connectorId) {
+        if (connectorId.contains("_")) {
+            return connectorId.replaceAll("_", "");
+        }
+        return connectorId;
+    }
+
+    /**
+     * 转换成朗新格式的ConnectorID
+     *
+     * @param connectorId
+     * @return
+     */
+    public static String convert2LongshineConnectorId(String connectorId) {
+        // connectorId包含"_"并且"_"在倒数第二位
+        if (connectorId.contains("_") && connectorId.indexOf("_") == connectorId.length() - 2) {
+            // 在connectorId最后一位前添加字符"_"
+            return connectorId;
+        } else {
+            return connectorId.substring(0, connectorId.length() - 1) + "_" + connectorId.substring(connectorId.length() - 1);
+        }
+    }
+
+}

+ 0 - 11
common/src/main/java/com/kym/common/wxpay/WxJsApi.java

@@ -1,11 +0,0 @@
-package com.kym.common.wxpay;
-
-/**
- * @author skyline
- * @description JSAPI下单
- * @date 2023-08-10 14:01
- */
-public class WxJsApi {
-
-
-}

+ 5 - 6
entity/pom.xml

@@ -27,13 +27,13 @@
         <dependency>
             <groupId>com.baomidou</groupId>
             <artifactId>mybatis-plus-boot-starter</artifactId>
-            <version>3.5.3.2</version>
+            <version>${mybatis-plus-boot-starter.version}</version>
         </dependency>
         <!-- 联表查询插件 -->
         <dependency>
             <groupId>com.github.yulichang</groupId>
             <artifactId>mybatis-plus-join-boot-starter</artifactId>
-            <version>1.5.2</version>
+            <version>${mybatis-plus-join-boot-starter.version}</version>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -50,13 +50,13 @@
         <dependency>
             <groupId>com.alibaba.fastjson2</groupId>
             <artifactId>fastjson2</artifactId>
-            <version>2.0.35</version>
+            <version>${fastjson2.version}</version>
         </dependency>
 
         <dependency>
             <groupId>com.github.pagehelper</groupId>
             <artifactId>pagehelper-spring-boot-starter</artifactId>
-            <version>1.4.7</version>
+            <version>${pagehelper-spring-boot-starter.version}</version>
         </dependency>
         <dependency>
             <groupId>com.google.code.gson</groupId>
@@ -66,9 +66,8 @@
         <dependency>
             <groupId>com.fasterxml.jackson.datatype</groupId>
             <artifactId>jackson-datatype-jsr310</artifactId>
-            <version>2.13.4</version>
+            <version>${jackson-datatype-jsr310.version}</version>
         </dependency>
-
     </dependencies>
 
 </project>

+ 1 - 2
entity/src/main/java/com/kym/entity/admin/EquipmentRelation.java

@@ -38,14 +38,13 @@ public class EquipmentRelation extends BaseEntity implements Serializable {
     private String shortId;
 
     /**
-     * EN+充电的sn号
+     * 充电桩设备的sn号
      */
     private String equipmentId;
     /**
      * 充电枪口编号
      */
     private String connectorId;
-
     /**
      * 平台名称
      */

+ 1 - 2
entity/src/main/java/com/kym/entity/admin/Platform.java

@@ -2,7 +2,6 @@ package com.kym.entity.admin;
 
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.kym.entity.BaseEntity;
-import java.io.Serializable;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -12,7 +11,7 @@ import lombok.Setter;
  * </p>
  *
  * @author skyline
- * @since 2025-01-08
+ * @since 2024-12-19
  */
 @Getter
 @Setter

+ 2 - 1
entity/src/main/java/com/kym/entity/admin/queryParams/CustomChargeOrdersQueryParam.java

@@ -6,6 +6,7 @@ import lombok.Data;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
+import java.util.List;
 
 
 /**
@@ -34,7 +35,7 @@ public class CustomChargeOrdersQueryParam extends PageParams {
     /**
      * 站点id
      */
-    private String stationId;
+    private List<String> stationIds;
     /**
      * 充电桩序列号
      */

+ 0 - 4
entity/src/main/java/com/kym/entity/admin/vo/LocalStationVo.java

@@ -1,15 +1,11 @@
 package com.kym.entity.admin.vo;
 
-import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
-import com.alibaba.fastjson2.annotation.JSONCreator;
-import com.alibaba.fastjson2.annotation.JSONField;
 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 com.kym.entity.admin.EquipmentInfo;
-import com.kym.entity.enplus.EnEquipmentInfo;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;

+ 3 - 3
entity/src/main/java/com/kym/entity/admin/vo/StationVo.java

@@ -8,7 +8,7 @@ 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 com.kym.entity.enplus.EnEquipmentInfo;
+import com.kym.entity.platform.PlatformEquipmentInfo;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -190,7 +190,7 @@ public class StationVo extends BaseEntity implements Serializable {
      * 充电设备信息列表
      */
     @TableField(exist = false)
-    private List<EnEquipmentInfo> equipmentInfos;
+    private List<PlatformEquipmentInfo> equipmentInfos;
     /**
      * 站点活动
      */
@@ -200,6 +200,6 @@ public class StationVo extends BaseEntity implements Serializable {
     @JSONCreator
     public StationVo(@JSONField(name = "StationLng") Double lng, @JSONField(name = "StationLat") Double lat, @JSONField(name = "EquipmentInfos") JSONArray array) {
         this.location = JSONObject.of("stationLng", lng, "stationLat", lat);
-        this.equipmentInfos = array.toJavaList(EnEquipmentInfo.class);
+        this.equipmentInfos = array.toJavaList(PlatformEquipmentInfo.class);
     }
 }

+ 6 - 1
entity/src/main/java/com/kym/entity/common/RedisKeys.java

@@ -6,7 +6,12 @@ package com.kym.entity.common;
  * @date 2023-07-31 18:26
  */
 public interface RedisKeys {
-    String EN_PLUS_TOKEN = "EN_PLUS_TOKEN";
+    String PLATFORM_QUERY_TOKEN = "PLATFORM_QUERY_TOKEN:";
+
+    /**
+     * 我们自己平台生成的Token,给外部调用获取
+     */
+    String PLATFORM_TOKEN = "PLATFORM_TOKEN:";
     String EN_PLUS_SASS_TOKEN = "EN_PLUS_SASS_TOKEN";
     String OFFLINE = "OFFLINE:";
     String OFFLINE_EXPIRED = "OFFLINE_EXPIRED:";

+ 2 - 0
entity/src/main/java/com/kym/entity/miniapp/ChargeOrder.java

@@ -55,7 +55,9 @@ public class ChargeOrder extends BaseEntity implements Serializable {
     public static int STOP_REASON_BMS停止 = 2;
     public static int STOP_REASON_充电机器设备故障 = 3;
     public static int STOP_REASON_连接器断开 = 4;
+
     public static int STOP_REASON_预约启动充电失败 = 5;
+    public static int STOP_REASON_启动充电异常 = 6;
 
     private Long userId;
 

+ 2 - 2
entity/src/main/java/com/kym/entity/enplus/EnChargeDetails.java → entity/src/main/java/com/kym/entity/platform/PlatformChargeDetails.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import lombok.Data;
 
@@ -10,7 +10,7 @@ import java.math.BigDecimal;
  * @date 2023-08-03 16:32
  */
 @Data
-public class EnChargeDetails {
+public class PlatformChargeDetails {
     private String DetailStartTime;
     private String DetailEndTime;
     /**

+ 2 - 2
entity/src/main/java/com/kym/entity/enplus/EnChargeOrder.java → entity/src/main/java/com/kym/entity/platform/PlatformChargeOrder.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import lombok.Data;
 
@@ -10,7 +10,7 @@ import java.math.BigDecimal;
  * @date 2023-08-04 10:29
  */
 @Data
-public class EnChargeOrder {
+public class PlatformChargeOrder {
     /**
      * 充电订单号
      */

+ 3 - 3
entity/src/main/java/com/kym/entity/enplus/EnCheckOrderSeq.java → entity/src/main/java/com/kym/entity/platform/PlatformCheckOrderSeq.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import lombok.Data;
 
@@ -11,7 +11,7 @@ import java.util.List;
  * @date 2023-08-04 10:25
  */
 @Data
-public class EnCheckOrderSeq {
+public class PlatformCheckOrderSeq {
 
     private String CheckOrderSeq;
     private String StartTime;
@@ -28,6 +28,6 @@ public class EnCheckOrderSeq {
      * 总金额
      */
     private BigDecimal TotalOrderMoney;
-    private List<EnChargeOrder> ChargeOrders;
+    private List<PlatformChargeOrder> ChargeOrders;
 
 }

+ 6 - 3
entity/src/main/java/com/kym/entity/enplus/EnConnectorInfo.java → entity/src/main/java/com/kym/entity/platform/PlatformConnectorInfo.java

@@ -1,7 +1,6 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import com.alibaba.fastjson2.annotation.JSONField;
-import com.baomidou.mybatisplus.annotation.TableField;
 import lombok.Data;
 
 /**
@@ -10,12 +9,16 @@ import lombok.Data;
  * @date 2023-07-31 15:30
  */
 @Data
-public class EnConnectorInfo {
+public class PlatformConnectorInfo {
     /**
      * 充电设备接口编码
      */
     @JSONField(name = "ConnectorID")
     private String connectorId;
+    public void setConnectorId(String connectorId) {
+        this.connectorId = connectorId.replace("_", "");
+    }
+
 
     /**
      * 充电设备接口名称

+ 6 - 2
entity/src/main/java/com/kym/entity/enplus/EnConnectorStatsInfo.java → entity/src/main/java/com/kym/entity/platform/PlatformConnectorStatsInfo.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import com.alibaba.fastjson2.annotation.JSONField;
 import lombok.Data;
@@ -11,7 +11,7 @@ import java.math.BigDecimal;
  * @date 2023-07-31 16:15
  */
 @Data
-public class EnConnectorStatsInfo {
+public class PlatformConnectorStatsInfo {
 
     /**
      * 充电设备接口编码
@@ -24,5 +24,9 @@ public class EnConnectorStatsInfo {
      */
     @JSONField(name = "ConnectorElectricity")
     private BigDecimal connectorElectricity;
+    public void setConnectorId(String connectorId) {
+        this.connectorId = connectorId.replace("_", "");
+    }
+
 
 }

+ 5 - 2
entity/src/main/java/com/kym/entity/enplus/EnConnectorStatusInfo.java → entity/src/main/java/com/kym/entity/platform/PlatformConnectorStatusInfo.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import com.alibaba.fastjson2.annotation.JSONField;
 import lombok.Data;
@@ -9,12 +9,15 @@ import lombok.Data;
  * @date 2023-07-31 15:40
  */
 @Data
-public class EnConnectorStatusInfo {
+public class PlatformConnectorStatusInfo {
     /**
      * 充电设备接口编码
      */
     @JSONField(name = "ConnectorID")
     private String connectorId;
+    public void setConnectorId(String connectorId) {
+        this.connectorId = connectorId.replace("_", "");
+    }
     /**
      * 充电设备接口状态
      * 0:离网

+ 7 - 7
entity/src/main/java/com/kym/entity/enplus/EnEquipmentInfo.java → entity/src/main/java/com/kym/entity/platform/PlatformEquipmentInfo.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
@@ -16,7 +16,7 @@ import java.util.List;
  */
 @Data
 @Accessors(chain = true)
-public class EnEquipmentInfo {
+public class PlatformEquipmentInfo {
 
     /**
      * 设备编码
@@ -72,7 +72,7 @@ public class EnEquipmentInfo {
     /**
      * 充电设备接口信息列表
      */
-    private List<EnConnectorInfo> connectorInfos;
+    private List<PlatformConnectorInfo> connectorInfos;
 
     /**
      * 充电桩坐标
@@ -86,10 +86,10 @@ public class EnEquipmentInfo {
     private Double power;
 
     @JSONCreator
-    public EnEquipmentInfo(@JSONField(name = "ConnectorInfos") JSONArray array,
-                           @JSONField(name = "EquipmentLng") float equipmentLng,
-                           @JSONField(name = "EquipmentLat") float equipmentLat) {
-        this.connectorInfos = array.toJavaList(EnConnectorInfo.class);
+    public PlatformEquipmentInfo(@JSONField(name = "ConnectorInfos") JSONArray array,
+                                 @JSONField(name = "EquipmentLng") float equipmentLng,
+                                 @JSONField(name = "EquipmentLat") float equipmentLat) {
+        this.connectorInfos = array.toJavaList(PlatformConnectorInfo.class);
         this.location = JSONObject.of("equipmentLng", equipmentLng, "equipmentLat", equipmentLat);
     }
 

+ 3 - 4
entity/src/main/java/com/kym/entity/enplus/EnEquipmentStatsInfo.java → entity/src/main/java/com/kym/entity/platform/PlatformEquipmentStatsInfo.java

@@ -1,9 +1,8 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import com.alibaba.fastjson2.annotation.JSONField;
 import lombok.Data;
 
-import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -12,7 +11,7 @@ import java.util.List;
  * @date 2023-07-31 16:10
  */
 @Data
-public class EnEquipmentStatsInfo {
+public class PlatformEquipmentStatsInfo {
     /**
      * 设备编码
      * 设备唯一编码,对同一运营商,保证唯一
@@ -25,6 +24,6 @@ public class EnEquipmentStatsInfo {
     @JSONField(name = "equipmentElectricity")
     private Double EquipmentElectricity;
     @JSONField(name = "ConnectorStatsInfos")
-    private List<EnConnectorStatsInfo> connectorStatsInfos;
+    private List<PlatformConnectorStatsInfo> connectorStatsInfos;
 
 }

+ 3 - 3
entity/src/main/java/com/kym/entity/enplus/EnNotificationChargeOrderInfo.java → entity/src/main/java/com/kym/entity/platform/PlatformNotificationChargeOrderInfo.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import lombok.Data;
 
@@ -11,7 +11,7 @@ import java.util.List;
  * @date 2023-08-04 10:12
  */
 @Data
-public class EnNotificationChargeOrderInfo {
+public class PlatformNotificationChargeOrderInfo {
     private String StartChargeSeq;
     private String ConnectorID;
     private String StartTime;
@@ -47,7 +47,7 @@ public class EnNotificationChargeOrderInfo {
      * 时段数N 范围0~32
      */
     private int SumPeriod;
-    private List<EnChargeDetails> ChargeDetails;
+    private List<PlatformChargeDetails> ChargeDetails;
 
 
 }

+ 3 - 3
entity/src/main/java/com/kym/entity/enplus/EnNotificationEquipChargeStatus.java → entity/src/main/java/com/kym/entity/platform/PlatformNotificationEquipChargeStatus.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import lombok.Data;
 
@@ -11,7 +11,7 @@ import java.util.List;
  * @date 2023-08-03 16:22
  */
 @Data
-public class EnNotificationEquipChargeStatus {
+public class PlatformNotificationEquipChargeStatus {
 
     private String StartChargeSeq;
 
@@ -68,7 +68,7 @@ public class EnNotificationEquipChargeStatus {
      */
     private int SumPeriod;
 
-    private List<EnChargeDetails> ChargeDetails;
+    private List<PlatformChargeDetails> ChargeDetails;
 
 
 }

+ 2 - 2
entity/src/main/java/com/kym/entity/enplus/EnNotificationStartChargeResult.java → entity/src/main/java/com/kym/entity/platform/PlatformNotificationStartChargeResult.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import lombok.Data;
 
@@ -8,7 +8,7 @@ import lombok.Data;
  * @date 2023-08-04 10:05
  */
 @Data
-public class EnNotificationStartChargeResult {
+public class PlatformNotificationStartChargeResult {
 
     /**
      * 充电订单号

+ 2 - 2
entity/src/main/java/com/kym/entity/enplus/EnNotificationStopChargeResult.java → entity/src/main/java/com/kym/entity/platform/PlatformNotificationStopChargeResult.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import lombok.Data;
 
@@ -8,7 +8,7 @@ import lombok.Data;
  * @date 2023-08-04 10:05
  */
 @Data
-public class EnNotificationStopChargeResult {
+public class PlatformNotificationStopChargeResult {
 
     /**
      * 充电订单号

+ 3 - 3
entity/src/main/java/com/kym/entity/enplus/EnPolicyInfo.java → entity/src/main/java/com/kym/entity/platform/PlatformPolicyInfo.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import com.alibaba.fastjson2.annotation.JSONCreator;
 import com.alibaba.fastjson2.annotation.JSONField;
@@ -14,7 +14,7 @@ import java.time.format.DateTimeFormatter;
  * @date 2023-08-15 16:11
  */
 @Data
-public class EnPolicyInfo {
+public class PlatformPolicyInfo {
     public final static String[] PRICE_PERIOD = {"谷", "平", "峰", "尖"};
     /**
      * 价格时段(尖峰平谷)
@@ -37,7 +37,7 @@ public class EnPolicyInfo {
     private Double servicePrice;
 
     @JSONCreator
-    EnPolicyInfo(@JSONField(name = "StartTime") String startTime) {
+    PlatformPolicyInfo(@JSONField(name = "StartTime") String startTime) {
         this.startTime = LocalTime.parse(startTime, DateTimeFormatter.ofPattern("HHmmss"));
     }
 }

+ 2 - 2
entity/src/main/java/com/kym/entity/enplus/EnRespQueryToken.java → entity/src/main/java/com/kym/entity/platform/PlatformRespQueryToken.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import lombok.Data;
 
@@ -8,7 +8,7 @@ import lombok.Data;
  * @date 2023-07-31 11:32
  */
 @Data
-public class EnRespQueryToken {
+public class PlatformRespQueryToken {
     /**
      * 运营商ID
      */

+ 3 - 3
entity/src/main/java/com/kym/entity/enplus/EnStationInfo.java → entity/src/main/java/com/kym/entity/platform/PlatformStationInfo.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import lombok.Data;
 
@@ -11,7 +11,7 @@ import java.util.List;
  * @date 2023-07-31 14:55
  */
 @Data
-public class EnStationInfo {
+public class PlatformStationInfo {
 
 
     /**
@@ -147,5 +147,5 @@ public class EnStationInfo {
     /**
      * 充电设备信息列表
      */
-    private List<EnEquipmentInfo> EquipmentInfos;
+    private List<PlatformEquipmentInfo> EquipmentInfos;
 }

+ 3 - 3
entity/src/main/java/com/kym/entity/enplus/EnStationStatsInfo.java → entity/src/main/java/com/kym/entity/platform/PlatformStationStatsInfo.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import com.alibaba.fastjson2.annotation.JSONField;
 import lombok.Data;
@@ -12,7 +12,7 @@ import java.util.List;
  * @date 2023-07-31 16:02
  */
 @Data
-public class EnStationStatsInfo {
+public class PlatformStationStatsInfo {
     /**
      * 充电站ID
      */
@@ -38,6 +38,6 @@ public class EnStationStatsInfo {
      * 充电设备统计信息列表
      */
     @JSONField(name = "EquipmentStatsInfos")
-    private List<EnEquipmentStatsInfo> equipmentStatsInfos;
+    private List<PlatformEquipmentStatsInfo> equipmentStatsInfos;
 
 }

+ 5 - 5
entity/src/main/java/com/kym/entity/enplus/EnStationStatusInfo.java → entity/src/main/java/com/kym/entity/platform/PlatformStationStatusInfo.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus;
+package com.kym.entity.platform;
 
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.annotation.JSONCreator;
@@ -13,7 +13,7 @@ import java.util.List;
  * @date 2023-07-31 16:00
  */
 @Data
-public class EnStationStatusInfo {
+public class PlatformStationStatusInfo {
     /**
      * 充电站ID(20字符,运营商自定义的唯一编码,不足长度在前方补0)
      */
@@ -23,11 +23,11 @@ public class EnStationStatusInfo {
     /**
      * 充电设备接口状态列表
      */
-    private List<EnConnectorStatusInfo> connectorStatusInfos;
+    private List<PlatformConnectorStatusInfo> connectorStatusInfos;
 
     @JSONCreator
-    public EnStationStatusInfo(@JSONField(name = "connectorStatusInfos") JSONArray infos) {
-        this.connectorStatusInfos = infos.toJavaList(EnConnectorStatusInfo.class);
+    public PlatformStationStatusInfo(@JSONField(name = "connectorStatusInfos") JSONArray infos) {
+        this.connectorStatusInfos = infos.toJavaList(PlatformConnectorStatusInfo.class);
     }
 
 }

+ 13 - 8
entity/src/main/java/com/kym/entity/enplus/response/EnBusinessPolicy.java → entity/src/main/java/com/kym/entity/platform/response/PlatformBusinessPolicy.java

@@ -1,9 +1,9 @@
-package com.kym.entity.enplus.response;
+package com.kym.entity.platform.response;
 
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.annotation.JSONCreator;
 import com.alibaba.fastjson2.annotation.JSONField;
-import com.kym.entity.enplus.EnPolicyInfo;
+import com.kym.entity.platform.PlatformPolicyInfo;
 import lombok.Data;
 
 import java.util.List;
@@ -15,12 +15,17 @@ import java.util.stream.Collectors;
  * @date 2023-08-15 15:58
  */
 @Data
-public class EnBusinessPolicy {
+public class PlatformBusinessPolicy {
     /**
      * 业务策略查询流水号
      */
     @JSONField(name = "EquipBizSeq")
     private String equipBizSeq;
+
+    public void setConnectorId(String connectorId) {
+        this.connectorId = connectorId.replace("_", "");
+    }
+
     /**
      * 充电设备接口编码
      */
@@ -48,15 +53,15 @@ public class EnBusinessPolicy {
     /**
      * 单项业务策略信息
      */
-    private List<EnPolicyInfo> policyInfos;
+    private List<PlatformPolicyInfo> policyInfos;
 
     @JSONCreator
-    EnBusinessPolicy(@JSONField(name = "PolicyInfos") JSONArray array) {
-        this.policyInfos = array.toJavaList(EnPolicyInfo.class);
+    PlatformBusinessPolicy(@JSONField(name = "PolicyInfos") JSONArray array) {
+        this.policyInfos = array.toJavaList(PlatformPolicyInfo.class);
         // 将尖峰平谷信息填入EnPolicyInfo中
-        var elecPriceSet = policyInfos.stream().map(EnPolicyInfo::getElecPrice).collect(Collectors.toSet()).stream().sorted().toList();
+        var elecPriceSet = policyInfos.stream().map(PlatformPolicyInfo::getElecPrice).collect(Collectors.toSet()).stream().sorted().toList();
         if (elecPriceSet.size() > 1) {
-            policyInfos = policyInfos.stream().peek(price -> price.setPricePeriod(EnPolicyInfo.PRICE_PERIOD[elecPriceSet.indexOf(price.getElecPrice())])).toList();
+            policyInfos = policyInfos.stream().peek(price -> price.setPricePeriod(PlatformPolicyInfo.PRICE_PERIOD[elecPriceSet.indexOf(price.getElecPrice())])).toList();
         } else {
             // 统一电价
             policyInfos = policyInfos.stream().peek(price -> price.setPricePeriod("统")).toList();

+ 4 - 5
entity/src/main/java/com/kym/entity/enplus/response/EnResponse.java → entity/src/main/java/com/kym/entity/platform/response/PlatformResponse.java

@@ -1,4 +1,4 @@
-package com.kym.entity.enplus.response;
+package com.kym.entity.platform.response;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
@@ -6,12 +6,11 @@ import lombok.NoArgsConstructor;
 
 /**
  * @author skyline
- * @description en+接口返回数据
- * @date 2023-07-31 11:59
+ * 互联互通接口返回数据
  */
 @Data
 @NoArgsConstructor
-public class EnResponse {
+public class PlatformResponse {
     @JsonProperty("Ret")
     private int Ret;
     @JsonProperty("Msg")
@@ -22,7 +21,7 @@ public class EnResponse {
     private String Sig;
 
 
-    public EnResponse(String data) {
+    public PlatformResponse(String data) {
         this.Ret = 0;
         this.Msg = "";
         this.Data = data;

+ 6 - 6
mapper/pom.xml

@@ -21,33 +21,33 @@
         <dependency>
             <groupId>com.kym</groupId>
             <artifactId>entity</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
+            <version>${project.version}</version>
         </dependency>
 
         <dependency>
             <groupId>com.baomidou</groupId>
             <artifactId>mybatis-plus-generator</artifactId>
-            <version>3.5.3.2</version>
+            <version>${mybatis-plus-generator.version}</version>
         </dependency>
 
         <!-- 代码生成使用 -->
         <dependency>
             <groupId>org.freemarker</groupId>
             <artifactId>freemarker</artifactId>
-            <version>2.3.32</version>
+            <version>${freemarker.version}</version>
         </dependency>
 
         <!-- 多数据源配置 -->
         <dependency>
             <groupId>com.baomidou</groupId>
             <artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
-            <version>4.1.3</version>
+            <version>${dynamic-datasource-spring-boot3-starter.version}</version>
         </dependency>
 
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>druid-spring-boot-starter</artifactId>
-            <version>1.2.20</version>
+            <version>${druid-spring-boot-starter.version}</version>
         </dependency>
 
         <dependency>
@@ -58,4 +58,4 @@
 
     </dependencies>
 
-</project>
+</project>

+ 13 - 7
mapper/src/main/resources/mappers/miniapp/ChargeOrderMapper.xml

@@ -102,9 +102,6 @@
             <if test="params.startChargeSeq != null and params.startChargeSeq != ''">
                 and t1.start_charge_seq = #{params.startChargeSeq}
             </if>
-            <if test="params.stationId != null and params.stationId != ''">
-                and t1.station_id = #{params.stationId}
-            </if>
             <if test="params.orderStatus != null">
                 and t1.order_status = #{params.orderStatus}
             </if>
@@ -114,6 +111,12 @@
             <if test="params.endDate != null">
                 and t1.start_time &lt;= #{params.endDate}
             </if>
+            <if test="params.stationIds != null and params.stationIds.size() > 0">
+                and t1.station_id IN
+                <foreach collection="params.stationIds" item="stationId" index="index" open="(" close=")" separator=",">
+                    #{stationId}
+                </foreach>
+            </if>
         </where>
     </select>
 
@@ -153,9 +156,6 @@
             <if test="params.connectorId != null and params.connectorId != ''">
                 and t1.connector_id = #{params.connectorId}
             </if>
-            <if test="params.stationId != null and params.stationId != ''">
-                and t1.station_id = #{params.stationId}
-            </if>
             <if test="params.startChargeSeq != null and params.startChargeSeq != ''">
                 and t1.start_charge_seq = #{params.startChargeSeq}
             </if>
@@ -177,13 +177,19 @@
             <if test="params.stopReason != null">
                 and t1.stop_reason = #{params.stopReason}
             </if>
+            <if test="params.stationIds != null and params.stationIds.size() > 0">
+                and t1.station_id IN
+                <foreach collection="params.stationIds" item="stationId" index="index" open="(" close=")" separator=",">
+                    #{stationId}
+                </foreach>
+            </if>
         </where>
         order by t1.id desc
     </select>
 
     <select id="stationStat" resultMap="StationStatMap" parameterType="com.kym.entity.admin.queryParams.StatQueryParam">
         SELECT
-        <if test="params.stationId != null and params.stationId != ''">
+        <if test="params.stationIds != null and params.stationId != ''">
             t1.station_id,
         </if>
         <if test="params.type == null or params.type == 'day'">

+ 4 - 6
miniapp/pom.xml

@@ -21,14 +21,14 @@
         <dependency>
             <groupId>com.kym</groupId>
             <artifactId>common</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
+            <version>${project.version}</version>
             <scope>compile</scope>
         </dependency>
 
         <dependency>
             <groupId>com.kym</groupId>
             <artifactId>service</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
+            <version>${project.version}</version>
             <scope>compile</scope>
         </dependency>
 
@@ -46,17 +46,15 @@
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-validation</artifactId>
-            <version>3.1.1</version>
         </dependency>
 
         <dependency>
             <groupId>com.sun.mail</groupId>
             <artifactId>javax.mail</artifactId>
-            <version>1.6.2</version>
+            <version>${javax.mail.version}</version>
         </dependency>
 
 
-
     </dependencies>
 
     <build>
@@ -88,4 +86,4 @@
     </build>
 
 
-</project>
+</project>

+ 10 - 8
miniapp/src/main/java/com/kym/miniapp/config/SaTokenConfigure.java

@@ -2,6 +2,7 @@ package com.kym.miniapp.config;
 
 import cn.dev33.satoken.interceptor.SaInterceptor;
 import cn.dev33.satoken.stp.StpUtil;
+import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
@@ -10,7 +11,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  * @description 权限校验
  * @date 2023-07-11 21:49
  */
-//@Configuration
+@Configuration
 public class SaTokenConfigure implements WebMvcConfigurer {
     // 注册拦截器
     @Override
@@ -24,13 +25,14 @@ public class SaTokenConfigure implements WebMvcConfigurer {
                         "/user/wxLogin",
                         "/user/refresh",
                         "/charge/pullEnStations/*",
-                        "/charge/notification_stationStatus",
-                        "/charge/notification_start_charge_result",
-                        "/charge/notification_start_charge_status",
-                        "/charge/notification_equip_charge_status",
-                        "/charge/notification_stop_charge_result",
-                        "/charge/notification_charge_order_info"
+                        "/charge/*/query_token",
+                        "/charge/*/notification_stationStatus",
+                        "/charge/*/notification_start_charge_result",
+                        "/charge/*/notification_start_charge_status",
+                        "/charge/*/notification_equip_charge_status",
+                        "/charge/*/notification_stop_charge_result",
+                        "/charge/*/notification_charge_order_info"
                 );
     }
 
-}
+}

+ 39 - 35
miniapp/src/main/java/com/kym/miniapp/controller/ChargerController.java

@@ -7,14 +7,13 @@ 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.enplus.response.EnResponse;
 import com.kym.entity.miniapp.ChargeOrder;
 import com.kym.entity.miniapp.queryParams.OrderQueryParams;
+import com.kym.entity.platform.response.PlatformResponse;
 import com.kym.service.admin.StationService;
-import com.kym.service.enplus.EnNotifyService;
-import com.kym.service.enplus.EnPlusService;
 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.*;
@@ -35,20 +34,19 @@ public class ChargerController {
 
     private final StationService stationService;
 
-    private final EnPlusService enPlusService;
-
     private final ChargeService chargeService;
 
     private final ChargeOrderService chargeOrderService;
 
-    private final EnNotifyService enNotifyService;
+    private final PlatformNotifyService enNotifyService;
 
     private final WxConfig wxConfig;
 
 
-    public ChargerController(StationService stationService, EnPlusService enPlusService, ChargeService chargeService, ChargeOrderService chargeOrderService, EnNotifyService enNotifyService, WxConfig wxConfig) {
+    public ChargerController(StationService stationService, ChargeService chargeService,
+                             ChargeOrderService chargeOrderService,
+                             PlatformNotifyService enNotifyService, WxConfig wxConfig) {
         this.stationService = stationService;
-        this.enPlusService = enPlusService;
         this.chargeService = chargeService;
         this.chargeOrderService = chargeOrderService;
         this.enNotifyService = enNotifyService;
@@ -83,11 +81,6 @@ public class ChargerController {
         return R.success(response);
     }
 
-    @GetMapping("/token")
-    R<String> queryToken() {
-        return R.success(enPlusService.queryToken());
-    }
-
     @ApiLog("启动充电")
     @GetMapping("/startCharge/{connectorId}")
     R<?> startCharge(@PathVariable("connectorId") String connectorId,
@@ -204,68 +197,79 @@ public class ChargerController {
     //====================================================以下是EN+推送接口==============================================================
 
     /**
-     * EN+场站设备状态变化推送
+     * 【互联互通平台】提供Token
+     */
+    @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));
+    }
+
+    /**
+     * 【互联互通平台】推送场站设备状态变化
      *
      * @param json
      * @return 0:接收 1:丢弃/忽略,不需要重试
      */
-    @PostMapping("/notification_stationStatus")
-    EnResponse notificationStationStatus(@RequestBody JSONObject json) {
-        return new EnResponse(enNotifyService.handleNotificationStationStatus(json));
+    @ApiLog("推送场站设备状态变化")
+    @PostMapping("/{platformName}/notification_stationStatus")
+    PlatformResponse notificationStationStatus(@PathVariable(value = "platformName", required = false) String platformName, @RequestBody JSONObject json) {
+        return new PlatformResponse(enNotifyService.handleNotificationStationStatus(platformName, json));
     }
 
     /**
-     * EN+推送启动充电结果
+     * 【互联互通平台】推送启动充电结果
      *
      * @param json
      * @return StartChargeSeq SuccStat 0:成功 1:失败  FailReason 0:无 1:接收失败
      */
-    @ApiLog("EN+推送启动充电结果")
-    @PostMapping("/notification_start_charge_result")
-    EnResponse notificationStartChargeResult(@RequestBody JSONObject json) {
-        return new EnResponse(enNotifyService.handleNotificationStartChargeResult(json));
+    @ApiLog("推送启动充电结果")
+    @PostMapping("/{platformName}/notification_start_charge_result")
+    PlatformResponse notificationStartChargeResult(@PathVariable(value = "platformName", required = false) String platformName, @RequestBody JSONObject json) {
+        return new PlatformResponse(enNotifyService.handleNotificationStartChargeResult(platformName, json));
     }
 
     /**
-     * EN+推送充电状态
+     * 【互联互通平台】推送充电状态
      *
      * @param json
      * @return
      */
-    @PostMapping("/notification_equip_charge_status")
-    EnResponse notificationEquipChargeStatus(@RequestBody JSONObject json) {
-        return new EnResponse(enNotifyService.handleNotificationEquipChargeStatus(json));
+    @ApiLog("推送充电状态")
+    @PostMapping("/{platformName}/notification_equip_charge_status")
+    PlatformResponse notificationEquipChargeStatus(@PathVariable(value = "platformName", required = false) String platformName, @RequestBody JSONObject json) {
+        return new PlatformResponse(enNotifyService.handleNotificationEquipChargeStatus(platformName, json));
     }
 
     /**
-     * EN+推送停止充电结果
+     * 【互联互通平台】推送停止充电结果
      *
      * @param json
      * @return
      */
     @ApiLog("推送停止充电结果")
-    @PostMapping("/notification_stop_charge_result")
-    EnResponse notificationStopChargeResult(@RequestBody JSONObject json) {
-        return new EnResponse(enNotifyService.handleNotificationStopChargeResult(json));
+    @PostMapping("/{platformName}/notification_stop_charge_result")
+    PlatformResponse notificationStopChargeResult(@PathVariable(value = "platformName", required = false) String platformName, @RequestBody JSONObject json) {
+        return new PlatformResponse(enNotifyService.handleNotificationStopChargeResult(platformName, json));
     }
 
     /**
-     * EN+推送充电订单信息
+     * 【互联互通平台】推送充电订单信息
      *
      * @param json
      * @return
      */
     @ApiLog("推送充电订单信息")
-    @PostMapping("/notification_charge_order_info")
-    EnResponse notificationChargeOrderInfo(@RequestBody JSONObject json) {
-        return new EnResponse(enNotifyService.handleNotificationChargeOrderInfo(json));
+    @PostMapping("/{platformName}/notification_charge_order_info")
+    PlatformResponse notificationChargeOrderInfo(@PathVariable(value = "platformName", required = false) String platformName, @RequestBody JSONObject json) {
+        return new PlatformResponse(enNotifyService.handleNotificationChargeOrderInfo(platformName, json));
     }
 
 
     //====================================================以下是手动同步数据接口==============================================================
 
     /**
-     * 拉取EN+充电站信息数据并更新本地服务器数据
+     * 拉取充电站信息数据并更新本地服务器数据
      *
      * @return
      */

+ 1 - 1
miniapp/src/main/java/com/kym/miniapp/jobs/StartChargeDelayJob.java

@@ -101,7 +101,7 @@ public class StartChargeDelayJob implements DelayService<DelayChargeOrder> {
                         log.error("预约充电队列take异常", e);
                     } else {
                         log.info("预约启动充电失败,订单号:{}", threadLocal.get());
-                        if (e instanceof BusinessException && (ResponseEnum.EN_PLUS_TOKEN_EXCEPTION.getCode().equals(((BusinessException) e).getCode()))) {
+                        if (e instanceof BusinessException && (ResponseEnum.PLATFORM_QUERY_TOKEN_EXCEPTION.getCode().equals(((BusinessException) e).getCode()))) {
                             if (retryList.contains(threadLocal.get())) {
                                 log.info("EN+ token异常,预约订单:{}已重试忽略", threadLocal.get());
                                 log.error(e.getMessage());

+ 1 - 22
miniapp/src/main/resources/application-dev.yml

@@ -1,24 +1,3 @@
-# EN+充电配置
-en-plus:
-  # 运营商ID
-  operatorId: MA5HJNDG1
-  # 运营商密钥
-  operatorSecret: 5009db3dc1e94ea8
-  # 消息密钥
-  dataSecret: 8c15f5bf050948ba
-  # 消息密钥初始化向量
-  dataSecretIv: 915bea94fa13461d
-  # 签名密钥
-  sigSecret: 46050b0bb5b7415c
-  # 最小充电余额(分)
-  chargeMinAmount: 200
-  # 接口地址
-  apiDomain: https://dev.en-plus.cn/Charge/evcs/v1/MA5HJNDG1/
-  # sass配置
-  sass: https://dev.en-plus.cn/Charge/op/login?username=快与慢&password=Admin123
-  # sass结算订单
-  sassClose: https://dev.en-plus.cn/Charge/op/analyze/order/close?orderCode=
-
 # 微信支付
 wechat:
   payment:
@@ -131,4 +110,4 @@ spring:
           multiplier: 2
 
 kym:
-  notify-email: skyline@kuaiyuman.cn
+  notify-email: skyline@kuaiyuman.cn

+ 1 - 22
miniapp/src/main/resources/application-prod.yml

@@ -1,24 +1,3 @@
-# EN+充电配置
-en-plus:
-  # 运营商ID
-  operatorId: MA5HJNDG1
-  # 运营商密钥
-  operatorSecret: c7fd9b753a9f434e
-  # 消息密钥
-  dataSecret: 5cb7e12da198420a
-  # 消息密钥初始化向量
-  dataSecretIv: 8a6ac88326bc4d3f
-  # 签名密钥
-  sigSecret: 2365b20f69e44817
-  # 最小充电余额(分)
-  chargeMinAmount: 200
-  # 接口地址
-  apiDomain: https://api.en-plus.cn:8080/Charge/evcs/v1//MA5HJNDG1/
-  # sass配置
-  sass: https://api.en-plus.cn:8080/Charge/op/login?username=快与慢工程&password=Kuaiyuman2o22
-  # sass结算订单
-  sassClose: https://api.en-plus.cn:8080/Charge/op/analyze/order/close?orderCode=
-
 # 微信支付
 wechat:
   payment:
@@ -131,4 +110,4 @@ spring:
           multiplier: 2
 
 kym:
-  notify-email: zaizai@kuaiyuman.cn,skyline@kuaiyuman.cn
+  notify-email: zaizai@kuaiyuman.cn,skyline@kuaiyuman.cn

+ 23 - 1
pom.xml

@@ -24,6 +24,29 @@
     </modules>
     <properties>
         <java.version>17</java.version>
+
+        <spring-boot.version>${parent.version}</spring-boot.version>
+        <project.version>0.0.1-SNAPSHOT</project.version>
+        <mybatis-plus-boot-starter.version>3.5.3.2</mybatis-plus-boot-starter.version>
+        <mybatis-plus-generator.version>3.5.3.2</mybatis-plus-generator.version>
+        <mybatis-plus-join-boot-starter.version>1.5.2</mybatis-plus-join-boot-starter.version>
+        <wechatpay.version>0.2.11</wechatpay.version>
+        <jackson-datatype-jsr310.version>2.13.4</jackson-datatype-jsr310.version>
+        <fastjson2.version>2.0.35</fastjson2.version>
+        <pagehelper-spring-boot-starter.version>1.4.7</pagehelper-spring-boot-starter.version>
+        <freemarker.version>2.3.32</freemarker.version>
+        <dynamic-datasource-spring-boot3-starter.version>4.1.3</dynamic-datasource-spring-boot3-starter.version>
+        <druid-spring-boot-starter.version>1.2.20</druid-spring-boot-starter.version>
+        <poi-ooxml.version>5.2.3</poi-ooxml.version>
+        <javax.mail.version>1.6.2</javax.mail.version>
+        <weixin-java.version>4.7.0</weixin-java.version>
+        <hutool.version>5.8.21</hutool.version>
+        <okhttp.version>4.11.0</okhttp.version>
+        <sa-token.version>1.38.0</sa-token.version>
+        <jakarta.servlet-api.version>6.0.0</jakarta.servlet-api.version>
+        <gson.version>2.10.1</gson.version>
+        <jwt.version>4.4.0</jwt.version>
+        <jjwt-api.version>0.11.5</jjwt-api.version>
     </properties>
 
     <dependencies>
@@ -61,5 +84,4 @@
     </build>
 
 
-
 </project>

+ 4 - 5
service/pom.xml

@@ -22,27 +22,26 @@
         <dependency>
             <groupId>com.kym</groupId>
             <artifactId>common</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
+            <version>${project.version}</version>
         </dependency>
 
         <dependency>
             <groupId>com.kym</groupId>
             <artifactId>mapper</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
+            <version>${project.version}</version>
         </dependency>
 
         <dependency>
             <groupId>com.github.wechatpay-apiv3</groupId>
             <artifactId>wechatpay-java</artifactId>
-            <version>0.2.11</version>
+            <version>${wechatpay.version}</version>
         </dependency>
 
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-amqp</artifactId>
-            <version>3.2.5</version>
         </dependency>
 
     </dependencies>
 
-</project>
+</project>

+ 1 - 1
service/src/main/java/com/kym/service/admin/PlatformService.java

@@ -11,7 +11,6 @@ import com.kym.service.mybatisplus.MyBaseService;
  * </p>
  *
  * @author skyline
- * @since 2025-01-08
  */
 public interface PlatformService extends MyBaseService<Platform> {
 
@@ -24,4 +23,5 @@ public interface PlatformService extends MyBaseService<Platform> {
     Platform detail(long id);
 
     void removePlatform(long id);
+
 }

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

@@ -10,8 +10,8 @@ import com.kym.entity.admin.Station;
 import com.kym.entity.admin.queryParams.StationQueryParam;
 import com.kym.entity.admin.vo.LocalStationVo;
 import com.kym.entity.admin.vo.StationVo;
-import com.kym.entity.enplus.EnStationStatsInfo;
-import com.kym.entity.enplus.EnStationStatusInfo;
+import com.kym.entity.platform.PlatformStationStatsInfo;
+import com.kym.entity.platform.PlatformStationStatusInfo;
 
 import java.util.List;
 import java.util.Map;
@@ -26,20 +26,20 @@ import java.util.Map;
  */
 public interface StationService extends MPJBaseService<Station> {
 
-    List<StationVo> queryEnStationInfo(int pageNum, int pageSize) throws JsonProcessingException;
+    List<StationVo> queryPlatformStationInfo(String platformName, int pageNum, int pageSize) throws JsonProcessingException;
 
     @DynamicCache
-    Map<String,List<EquipmentInfo>> getCachedEquipmentMap();
+    Map<String, List<EquipmentInfo>> getCachedEquipmentMap();
 
     @DynamicCache
-    Map<String,List<ConnectorInfo>> getCachedConnectorMap();
+    Map<String, List<ConnectorInfo>> getCachedConnectorMap();
 
     //    @DynamicCache // 方法的返回结果加一层方法缓存,5分钟内不变
     List<LocalStationVo> queryLocalStationInfo(int pageNum, int pageSize);
 
-    List<EnStationStatusInfo> stationStatus(String[] ids);
+    List<PlatformStationStatusInfo> stationStatus(String[] ids);
 
-    EnStationStatsInfo stationStats(String stationId, String startTime, String endTime);
+    PlatformStationStatsInfo stationStats(String stationId, String startTime, String endTime);
 
     void pullEnStationInfos(String stationId);
 

+ 0 - 1
service/src/main/java/com/kym/service/admin/impl/InvoiceDetailServiceImpl.java

@@ -139,7 +139,6 @@ public class InvoiceDetailServiceImpl extends MPJBaseServiceImpl<InvoiceDetailMa
                     .setBuyerInformation(fapiaoApplications.getFapiao_information().get(0).getBuyer_information())
                     .setExtraInformation(fapiaoApplications.getFapiao_information().get(0).getExtra_information())
                     .setItems(fapiaoApplications.getFapiao_information().get(0).getItems());
-            // 手动切换数据源
             removeByMap(Map.of("apply_id", applyId));
             save(invoiceDetail);
         }

+ 3 - 3
service/src/main/java/com/kym/service/admin/impl/PlatformServiceImpl.java

@@ -1,6 +1,6 @@
 package com.kym.service.admin.impl;
 
-import cn.hutool.core.comparator.CompareUtil;
+import com.baomidou.dynamic.datasource.annotation.DS;
 import com.github.pagehelper.PageHelper;
 import com.kym.common.utils.CommUtil;
 import com.kym.entity.admin.Platform;
@@ -17,9 +17,9 @@ import org.springframework.stereotype.Service;
  * </p>
  *
  * @author skyline
- * @since 2025-01-08
  */
 @Service
+@DS("db-admin")
 public class PlatformServiceImpl extends MyBaseServiceImpl<PlatformMapper, Platform> implements PlatformService {
 
     @Override
@@ -42,7 +42,7 @@ public class PlatformServiceImpl extends MyBaseServiceImpl<PlatformMapper, Platf
     public void updatePlatform(Platform platform) {
         CommUtil.assertsNonNull(platform.getPlatformName(), "平台名称不能为空");
         CommUtil.assertsNonNull(platform.getCompanyName(), "公司名称能为空");
-        Long count = lambdaQuery().eq(Platform::getPlatformName, platform.getPlatformName()).ne(Platform::getId,platform.getId()).count();
+        Long count = lambdaQuery().eq(Platform::getPlatformName, platform.getPlatformName()).ne(Platform::getId, platform.getId()).count();
         CommUtil.asserts(count == 0, "平台已存在");
         updateById(platform);
     }

+ 80 - 30
service/src/main/java/com/kym/service/admin/impl/StationServiceImpl.java

@@ -6,24 +6,24 @@ 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.QueryWrapper;
-import com.github.yulichang.toolkit.JoinWrappers;
-import com.github.yulichang.wrapper.MPJLambdaWrapper;
 import com.kym.common.annotation.DynamicCache;
-import com.kym.common.enums.EnPlusApi;
+import com.kym.common.cache.PlatformCache;
 import com.kym.common.exception.BusinessException;
-import com.kym.common.utils.AESUtil;
 import com.kym.common.utils.CommUtil;
+import com.kym.common.utils.PlatformAesUtil;
 import com.kym.entity.admin.*;
 import com.kym.entity.admin.queryParams.StationQueryParam;
 import com.kym.entity.admin.vo.LocalStationVo;
 import com.kym.entity.admin.vo.StationVo;
-import com.kym.entity.enplus.EnStationStatsInfo;
-import com.kym.entity.enplus.EnStationStatusInfo;
+import com.kym.entity.platform.PlatformStationStatsInfo;
+import com.kym.entity.platform.PlatformStationStatusInfo;
+import com.kym.entity.platform.response.PlatformResponse;
 import com.kym.mapper.admin.StationMapper;
-import com.kym.service.mybatisplus.MyBaseServiceImpl;
 import com.kym.service.admin.*;
 import com.kym.service.cache.KymCache;
-import com.kym.service.enplus.EnPlusService;
+import com.kym.service.mybatisplus.MyBaseServiceImpl;
+import com.kym.service.platform.PlatformApi;
+import com.kym.service.platform.PlatformApiService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.aop.framework.AopContext;
 import org.springframework.beans.BeanUtils;
@@ -35,6 +35,8 @@ import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import static com.kym.common.utils.PlatformAesUtil.buildPlatformParams;
+
 /**
  * <p>
  * 充电站信息 服务实现类
@@ -48,17 +50,17 @@ import java.util.stream.Stream;
 @Slf4j
 public class StationServiceImpl extends MyBaseServiceImpl<StationMapper, Station> implements StationService {
 
-    private final EnPlusService enPlusService;
+    private final PlatformApiService platformApiService;
     private final EquipmentInfoService equipmentInfoService;
     private final ConnectorInfoService connectorInfoService;
     private final EquipmentRelationService equipmentRelationService;
     private final ActivityStationService activityStationService;
     private final ActivityService activityService;
 
-    public StationServiceImpl(EnPlusService enPlusService, EquipmentInfoService equipmentInfoService,
+    public StationServiceImpl(PlatformApiService platformApiService, EquipmentInfoService equipmentInfoService,
                               ConnectorInfoService connectorInfoService, EquipmentRelationService equipmentRelationService,
                               ActivityStationService activityStationService, @Lazy ActivityService activityService) {
-        this.enPlusService = enPlusService;
+        this.platformApiService = platformApiService;
         this.equipmentInfoService = equipmentInfoService;
         this.connectorInfoService = connectorInfoService;
         this.equipmentRelationService = equipmentRelationService;
@@ -85,8 +87,16 @@ public class StationServiceImpl extends MyBaseServiceImpl<StationMapper, Station
         return list(queryWrapper);
     }
 
+    /**
+     * 查询互联互通平台站点信息
+     *
+     * @param platformName
+     * @param pageNum
+     * @param pageSize
+     * @return
+     */
     @Override
-    public List<StationVo> queryEnStationInfo(int pageNum, int pageSize) {
+    public List<StationVo> queryPlatformStationInfo(String platformName, int pageNum, int pageSize) {
         var param = """
                 {
                     "PageNo":%d,
@@ -94,8 +104,8 @@ public class StationServiceImpl extends MyBaseServiceImpl<StationMapper, Station
                     "LastQueryTime":""
                 }
                 """.formatted(pageNum, pageSize);
-        var response = enPlusService.enPlusPost(EnPlusApi.EN_PLUS_QUERY_STATION_INFO.getApi(), enPlusService.buildParams(param));
-        var enStations = JSONObject.parseObject(AESUtil.decrypt(response.getData()));
+        var response = platformApiService.platformPost(platformName, PlatformApi.PLATFORM_QUERY_STATION_INFO.getApi(platformName), buildPlatformParams(platformName, param));
+        var enStations = parsePlatformResponseData(response, platformName);
         var stationList = enStations.getJSONArray("StationInfos").toJavaList(StationVo.class);
         // 我方station表数据
         var stations = list();
@@ -113,6 +123,19 @@ public class StationServiceImpl extends MyBaseServiceImpl<StationMapper, Station
         return stationList;
     }
 
+    /**
+     * 解析平台返回数据为JSONObject
+     *
+     * @param response
+     * @param platformName
+     * @return
+     */
+    JSONObject parsePlatformResponseData(PlatformResponse response, String platformName) {
+        var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        return JSONObject.parseObject(PlatformAesUtil.decrypt(platform.getDataSecret(), platform.getDataSecretIv(), response.getData()));
+    }
+
+
     @DynamicCache(timeout = 15 * 60 * 1000L)
     @Override
     public Map<String, List<EquipmentInfo>> getCachedEquipmentMap() {
@@ -179,15 +202,37 @@ public class StationServiceImpl extends MyBaseServiceImpl<StationMapper, Station
 
 
     @Override
-    public List<EnStationStatusInfo> stationStatus(String[] ids) {
-        var param = """
-                {
-                    "StationIDs":["%s"]
-                }
-                """.formatted(String.join("\",\"", ids));
-        var response = enPlusService.enPlusPost(EnPlusApi.EN_PLUS_QUERY_STATION_STATUS.getApi(), enPlusService.buildParams(param));
-        var enStationStatus = JSONObject.parseObject(AESUtil.decrypt(response.getData()));
-        return enStationStatus.getJSONArray("StationStatusInfos").toJavaList(EnStationStatusInfo.class);
+    public List<PlatformStationStatusInfo> stationStatus(String[] stationIds) {
+        // 站点ID对应平台名称
+        var stationId2Platform = new HashMap<String, String>();
+        // 先对站点id进行分组,单独去请求各自互联互通平台数据
+        var platforms = new HashSet<String>();
+
+        for (String stationId : stationIds) {
+            platforms.add(PlatformCache.INSTANCE.getPlatformNameByStationId(stationId));
+            stationId2Platform.put(stationId, PlatformCache.INSTANCE.getPlatformNameByStationId(stationId));
+        }
+
+        // 平台名称对应站点列表
+        var platform2StationIds = new HashMap<String, List<String>>();
+        platforms.forEach(platformName -> {
+            var stationIdsByPlatform = stationId2Platform.entrySet().stream().filter(entry -> entry.getValue().equals(platformName)).map(Map.Entry::getKey).toList();
+            platform2StationIds.put(platformName, stationIdsByPlatform);
+        });
+
+        var res = new ArrayList<PlatformStationStatusInfo>();
+        platforms.forEach(platformName -> {
+            var param = """
+                    {
+                        "StationIDs":["%s"]
+                    }
+                    """.formatted(String.join("\",\"", String.join(",", platform2StationIds.get(platformName))));
+            var response = platformApiService.platformPost(platformName, PlatformApi.PLATFORM_QUERY_STATION_STATUS.getApi(platformName), buildPlatformParams(platformName, param));
+            var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+            var enStationStatus = JSONObject.parseObject(PlatformAesUtil.decrypt(platform.getDataSecret(), platform.getDataSecretIv(), response.getData()));
+            res.addAll(enStationStatus.getJSONArray("StationStatusInfos").toJavaList(PlatformStationStatusInfo.class));
+        });
+        return res;
     }
 
 
@@ -200,7 +245,7 @@ public class StationServiceImpl extends MyBaseServiceImpl<StationMapper, Station
      * @return
      */
     @Override
-    public EnStationStatsInfo stationStats(String stationId, String startTime, String endTime) {
+    public PlatformStationStatsInfo stationStats(String stationId, String startTime, String endTime) {
         var param = """
                 {
                     "StationID":"%s",
@@ -208,21 +253,23 @@ public class StationServiceImpl extends MyBaseServiceImpl<StationMapper, Station
                     "EndTime":"%s"
                 }
                 """.formatted(stationId, startTime, endTime);
-        var response = enPlusService.enPlusPost(EnPlusApi.EN_PLUS_QUERY_STATION_STATS.getApi(), enPlusService.buildParams(param));
-        // TODO: 2023-08-12 包装成自己的数据格式
-        var enStationStats = JSONObject.parseObject(AESUtil.decrypt(response.getData()));
-        return enStationStats.getJSONObject("StationStats").toJavaObject(EnStationStatsInfo.class);
+        var platformName = PlatformCache.INSTANCE.getPlatformNameByStationId(stationId);
+        var response = platformApiService.platformPost(platformName, PlatformApi.PLATFORM_QUERY_STATION_STATS.getApi(platformName), buildPlatformParams(platformName, param));
+        var enStationStats = parsePlatformResponseData(response, platformName);
+        return enStationStats.getJSONObject("StationStats").toJavaObject(PlatformStationStatsInfo.class);
     }
 
 
     /**
-     * 拉取EN+充电站信息数据并更新本地服务器数据
+     * 拉取互联互通平台充电站信息数据并更新本地服务器数据
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void pullEnStationInfos(String stationId) {
         // 指定的站点信息
-        var stationVo = queryEnStationInfo(1, 1000).stream().filter(vo -> stationId.equals(vo.getStationId())).findFirst().orElse(null);
+        var platformName = PlatformCache.INSTANCE.getPlatformNameByStationId(stationId);
+        var stationVo = queryPlatformStationInfo(platformName, 1, 1000)
+                .stream().filter(vo -> stationId.equals(vo.getStationId())).findFirst().orElse(null);
 
         var station = new Station();
         var equipmentList = new ArrayList<EquipmentInfo>();
@@ -272,6 +319,9 @@ public class StationServiceImpl extends MyBaseServiceImpl<StationMapper, Station
         KymCache.INSTANCE.putStationId2Name(Map.of(stationVo.getStationId(), stationVo.getStationName()));
         KymCache.INSTANCE.putConnectorId2Status(connectorList.stream().collect(Collectors.toMap(ConnectorInfo::getConnectorId, ConnectorInfo::getStatus)));
 
+        PlatformCache.INSTANCE.putStationId2PlatformName(Map.of(stationVo.getStationId(), platformName));
+        PlatformCache.INSTANCE.putConnectorId2PlatformName(connectorList.stream().collect(Collectors.toMap(ConnectorInfo::getConnectorId, connectorInfo -> platformName)));
+
     }
 
 

+ 24 - 3
service/src/main/java/com/kym/service/cache/KymCache.java

@@ -1,13 +1,18 @@
 package com.kym.service.cache;
 
 import cn.hutool.extra.spring.SpringUtil;
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import com.kym.common.cache.PlatformCache;
 import com.kym.entity.admin.ConnectorInfo;
 import com.kym.entity.admin.EquipmentRelation;
+import com.kym.entity.admin.Platform;
 import com.kym.entity.admin.Station;
 import com.kym.entity.common.RedisKeys;
 import com.kym.service.admin.ConnectorInfoService;
 import com.kym.service.admin.EquipmentRelationService;
+import com.kym.service.admin.PlatformService;
 import com.kym.service.admin.StationService;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.context.event.ApplicationStartedEvent;
 import org.springframework.context.ApplicationListener;
 import org.springframework.data.redis.core.SetOperations;
@@ -174,19 +179,27 @@ public enum KymCache {
         private static final StringRedisTemplate redisTemplate = SpringUtil.getBean(StringRedisTemplate.class);
 
         private final EquipmentRelationService equipmentRelationService;
+        private final PlatformService platformService;
         private final StationService stationService;
-
         private final ConnectorInfoService connectorInfoService;
 
 
-        private KymCacheInjector(EquipmentRelationService equipmentRelationService, StationService stationService, ConnectorInfoService connectorInfoService) {
+
+        @Value("${spring.profiles.active}")
+        public String env;
+
+
+        private KymCacheInjector(EquipmentRelationService equipmentRelationService, StationService stationService, ConnectorInfoService connectorInfoService, PlatformService platformService) {
             this.equipmentRelationService = equipmentRelationService;
             this.stationService = stationService;
             this.connectorInfoService = connectorInfoService;
+            this.platformService = platformService;
         }
 
         @Override
         public void onApplicationEvent(ApplicationStartedEvent event) {
+            // 手动切换数据源
+            DynamicDataSourceContextHolder.push("db-admin");
             // 将数据库数据缓存到redis
             var equipmentRelations = equipmentRelationService.list();
 
@@ -204,6 +217,14 @@ public enum KymCache {
 
             var connectorId2Status = connectorInfoService.list().stream().collect(Collectors.toMap(ConnectorInfo::getConnectorId, ConnectorInfo::getStatus));
             KymCache.INSTANCE.putConnectorId2Status(connectorId2Status);
+
+
+            // 缓存平台数据
+            PlatformCache.INSTANCE.putPlatformName2Config(platformService.lambdaQuery().eq(Platform::getEnv, env).list().stream().collect(Collectors.toMap(Platform::getPlatformName, platform -> platform)));
+            PlatformCache.INSTANCE.putConnectorId2PlatformName(equipmentRelations.stream().collect(Collectors.toMap(EquipmentRelation::getConnectorId, EquipmentRelation::getPlatformName)));
+            PlatformCache.INSTANCE.putStationId2PlatformName(equipmentRelations.stream().collect(Collectors.toMap(EquipmentRelation::getStationId, EquipmentRelation::getPlatformName)));
+
+            DynamicDataSourceContextHolder.poll();
         }
     }
-}
+}

+ 0 - 22
service/src/main/java/com/kym/service/enplus/EnNotifyService.java

@@ -1,22 +0,0 @@
-package com.kym.service.enplus;
-
-import com.alibaba.fastjson2.JSONObject;
-
-/**
- * @author skyline
- * @description
- * @date 2023-08-04 14:24
- */
-public interface EnNotifyService {
-
-
-    String handleNotificationStartChargeResult(JSONObject json);
-
-    String handleNotificationEquipChargeStatus(JSONObject json);
-
-    String handleNotificationStopChargeResult(JSONObject json);
-
-    String handleNotificationChargeOrderInfo(JSONObject json);
-
-    String handleNotificationStationStatus(JSONObject json);
-}

+ 0 - 32
service/src/main/java/com/kym/service/enplus/EnPlusService.java

@@ -1,32 +0,0 @@
-package com.kym.service.enplus;
-
-import com.alibaba.fastjson2.JSONObject;
-import com.kym.entity.enplus.response.EnResponse;
-
-/**
- * @author skyline
- * @description
- * @date 2023-07-31 14:13
- */
-public interface EnPlusService {
-    EnResponse enPlusPost(String url, String params);
-
-    String queryToken();
-
-    String buildParams(String params);
-
-
-    String signValidation(JSONObject json);
-
-    JSONObject queryEquipAuth(String connectorId, String equipAuthSeq);
-
-    JSONObject queryEquipBusinessPolicy(String equipBizSeq, String connectorId);
-
-    JSONObject queryStartCharge(String startChargeSeq, String connectorId, String qrCode, Integer amount);
-
-    JSONObject queryEquipChargeStatus(String startChargeSeq);
-
-    JSONObject updateBalanceByQueryEquipChargeStatus(String startChargeSeq, int amount);
-
-    JSONObject queryStopCharge(String startChargeSeq, String connectorId);
-}

+ 0 - 338
service/src/main/java/com/kym/service/enplus/impl/EnPlusServiceImpl.java

@@ -1,338 +0,0 @@
-package com.kym.service.enplus.impl;
-
-import cn.hutool.core.date.DatePattern;
-import cn.hutool.core.date.LocalDateTimeUtil;
-import cn.hutool.crypto.digest.HMac;
-import cn.hutool.crypto.digest.HmacAlgorithm;
-import com.alibaba.fastjson2.JSONObject;
-import com.kym.common.annotation.DynamicCache;
-import com.kym.common.constant.ResponseEnum;
-import com.kym.common.enums.EnPlusApi;
-import com.kym.common.exception.BusinessException;
-import com.kym.common.exception.EnPushException;
-import com.kym.common.utils.AESUtil;
-import com.kym.common.utils.CommUtil;
-import com.kym.entity.common.RedisKeys;
-import com.kym.entity.enplus.EnRespQueryToken;
-import com.kym.entity.enplus.response.EnResponse;
-import com.kym.service.enplus.EnPlusService;
-import okhttp3.*;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.stereotype.Service;
-
-import java.io.IOException;
-import java.time.LocalDateTime;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author skyline
- * @description EN+平台接口服务
- * @date 2023-07-29 14:43
- */
-@Service
-public class EnPlusServiceImpl implements EnPlusService {
-
-    public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
-    private static final Logger LOGGER = LoggerFactory.getLogger(EnPlusServiceImpl.class);
-    static OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder().build();
-    private final RedisTemplate<String, String> redisTemplate;
-
-    @Value("${en-plus.operatorId}")
-    private String OperatorId;
-    @Value("${en-plus.operatorSecret}")
-    private String OperatorSecret;
-    @Value("${en-plus.sigSecret}")
-    private String SigSecret;
-
-    public EnPlusServiceImpl(RedisTemplate<String, String> redisTemplate) {
-        this.redisTemplate = redisTemplate;
-    }
-
-    public static <T> T parse(String json, Class<T> clz) {
-        return JSONObject.parseObject(json, clz);
-    }
-
-    private static String synchronizedCall(Request request) {
-        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
-            return response.body().string();
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * EN+ POST请求专属方法
-     *
-     * @param url
-     * @param params
-     * @return
-     */
-    @Override
-    public EnResponse enPlusPost(String url, String params) {
-        // token获取
-        var token = queryToken();
-        Headers headers = Headers.of("Authorization", "Bearer ".concat(token));
-        RequestBody requestBody = RequestBody.create(params, JSON);
-        Request request = new Request.Builder()
-                .headers(headers)
-                .post(requestBody)
-                .url(url)
-                .build();
-        var response = parse(synchronizedCall(request), EnResponse.class);
-
-        if (0 == response.getRet()) {
-            return response;
-        } else {
-            LOGGER.error(":url:{}\n params:{}\ntoken:{}\n返回信息:{}", url, params, token, response);
-            if(4002 == response.getRet() ){
-                // 如果返回Ret=4002,token错误的情况下,删除redis中的token,如果是预约订单则将此订单设置为延迟启动
-                redisTemplate.delete(RedisKeys.EN_PLUS_TOKEN);
-                throw new BusinessException(ResponseEnum.EN_PLUS_TOKEN_EXCEPTION);
-            }
-            throw new BusinessException(ResponseEnum.EN_PLUS_API_EXCEPTION);
-        }
-    }
-
-    /**
-     * 获取en+ AccessToken
-     * HMAC-MD5
-     * 签名密钥对整个消息体加密,MD5摘要,参数签名要求大写
-     * 签名消息体拼接顺序:OperatorID、Data、TimeStamp、Seq
-     */
-    @Override
-    public String queryToken() {
-        LOGGER.debug("查询token");
-        var token = redisTemplate.opsForValue().get(RedisKeys.EN_PLUS_TOKEN);
-        if (CommUtil.isNotEmptyAndNull(token)) {
-            LOGGER.debug("从缓存中查询到token:{},ttl:{}", token, redisTemplate.getExpire(RedisKeys.EN_PLUS_TOKEN));
-            return token;
-        }
-        var data = """
-                {
-                    "OperatorID":"%s",
-                    "OperatorSecret":"%s"
-                }
-                """.formatted(OperatorId, OperatorSecret);
-
-        var requestParams = buildParams(data);
-
-        var enResponse = enGetToken(EnPlusApi.EN_PLUS_QUERY_TOKEN.getApi(), requestParams);
-
-        if (enResponse != null && 0 == enResponse.getRet()) {
-            // 解密Data获取token
-            var enRespQueryToken = JSONObject.parseObject(AESUtil.decrypt(enResponse.getData()), EnRespQueryToken.class);
-            LOGGER.debug("EN+接口AccessToken:{}", enRespQueryToken.toString());
-            // 缓存token,有效期7天(我们这里每次请求en+获取token的有效期并不是从7天开始,有效期是在en+的剩余有效时间)
-            redisTemplate.opsForValue().set(RedisKeys.EN_PLUS_TOKEN, enRespQueryToken.getAccessToken(), enRespQueryToken.getTokenAvailableTime(), TimeUnit.SECONDS);
-            return enRespQueryToken.getAccessToken();
-        } else {
-            // 记录错误码,返回错误信息
-            LOGGER.error("EN+接口错误:接口名{}:返回信息:{}", "query_token", enResponse);
-            throw new BusinessException(ResponseEnum.EN_PLUS_QUERY_TOKEN_ERROR);
-        }
-    }
-
-    public EnResponse enGetToken(String url, String params) {
-        // token获取
-        RequestBody requestBody = RequestBody.create(params, JSON);
-        Request request = new Request.Builder()
-                .post(requestBody)
-                .url(url)
-                .build();
-        var response = parse(synchronizedCall(request), EnResponse.class);
-
-        if (response != null && 0 == response.getRet()) {
-            return response;
-        } else {
-            LOGGER.error("EN+接口数据异常:url:{}\n params:{}\n返回信息:{}", url, params, response);
-            throw new BusinessException(ResponseEnum.EN_PLUS_API_EXCEPTION);
-        }
-    }
-
-
-    /**
-     * 加密数据、签名、组装请求消息体
-     *
-     * @param params
-     * @return
-     */
-    @Override
-    public String buildParams(String params) {
-        // 使用DataSecret对data加密
-        var dataStr = AESUtil.encrypt(params);
-        // 时间戳
-        var timeStamp = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
-        // 自增序列
-        var seq = timeStamp.substring(timeStamp.length() - 4);
-        // 使用SigSecret以HMAC-MD5算法对消息体签名(签名顺序:OperatorId、Data、TimeStamp、Seq)
-        var signString = OperatorId + dataStr + timeStamp + seq;
-        HMac mac = new HMac(HmacAlgorithm.HmacMD5, SigSecret.getBytes());
-        // 签名(转为大写)
-        var sign = mac.digestHex(signString).toUpperCase();
-        return """
-                {
-                    "OperatorID":"%s",
-                    "Data":"%s",
-                    "TimeStamp":"%s",
-                    "Seq":"%s",
-                    "Sig":"%s"
-                }
-                """.formatted(OperatorId, dataStr, timeStamp, seq, sign);
-    }
-
-    /**
-     * 验签、解密推送消息
-     *
-     * @param json
-     * @return
-     */
-    @Override
-    public String signValidation(JSONObject json) {
-        // 验签 解密数据
-        var OperatorID = json.getString("OperatorID");
-        var Data = json.getString("Data");
-        var TimeStamp = json.getString("TimeStamp");
-        var Seq = json.getString("Seq");
-        var Sig = json.getString("Sig");
-        var signString = OperatorID + Data + TimeStamp + Seq;
-        HMac mac = new HMac(HmacAlgorithm.HmacMD5, SigSecret.getBytes());
-        // 签名(转为大写)
-        var sign = mac.digestHex(signString).toUpperCase();
-        if (sign.equals(Sig)) {
-            // 解密数据
-            return AESUtil.decrypt(Data);
-        } else {
-            // 验签失败
-            EnResponse enResponse = new EnResponse();
-            enResponse.setRet(4001);
-            enResponse.setMsg(ResponseEnum.EN_PLUS_PUSH_SIGN_FAIL.getMessage());
-            LOGGER.error("EN+推送数据验签失败,数据:{}", json);
-            throw new EnPushException(ResponseEnum.EN_PLUS_PUSH_SIGN_FAIL, enResponse);
-        }
-
-    }
-
-
-    /**
-     * 请求设备认证
-     *
-     * @param connectorId  充电设备接口编码
-     * @param equipAuthSeq 格式:运营商ID+唯一编码 27字符
-     * @return
-     */
-    @Override
-    public JSONObject queryEquipAuth(String connectorId, String equipAuthSeq) {
-        var param = """
-                {
-                    "EquipAuthSeq":"%s",
-                    "ConnectorID":"%s"
-                }
-                """.formatted(equipAuthSeq, connectorId);
-        var response = enPlusPost(EnPlusApi.EN_PLUS_QUERY_EQUIP_AUTH.getApi(), buildParams(param));
-
-        return JSONObject.parseObject(AESUtil.decrypt(response.getData()));
-    }
-
-
-    /**
-     * 查询业务策略信息
-     *
-     * @param equipBizSeq 业务策略查询流水号 格式:运营商ID+唯一编码 27字符
-     * @param connectorId 充电设备接口编码
-     * @return
-     */
-    @Override
-    @DynamicCache(spel = "#connectorId")
-    public JSONObject queryEquipBusinessPolicy(String equipBizSeq, String connectorId) {
-        var param = """
-                {
-                    "EquipBizSeq":"%s",
-                    "ConnectorID":"%s"
-                }
-                """.formatted(equipBizSeq, connectorId);
-        var response = enPlusPost(EnPlusApi.EN_PLUS_QUERY_EQUIP_BUSINESS_POLICY.getApi(), buildParams(param));
-        return JSONObject.parseObject(AESUtil.decrypt(response.getData()));
-    }
-
-    /**
-     * 请求EN+启动充电
-     *
-     * @param startChargeSeq
-     * @param connectorId
-     * @param qrCode
-     * @param amount
-     * @return
-     */
-    @Override
-    public JSONObject queryStartCharge(String startChargeSeq, String connectorId, String qrCode, Integer amount) {
-        var param = """
-                {
-                    "StartChargeSeq":"%s",
-                    "ConnectorID":"%s",
-                    "QRCode":"%s",
-                    "amount":"%d"
-                }
-                """.formatted(startChargeSeq, connectorId, qrCode, amount);
-        var response = enPlusPost(EnPlusApi.EN_PLUS_QUERY_START_CHARGE.getApi(), buildParams(param));
-        return JSONObject.parseObject(AESUtil.decrypt(response.getData()));
-    }
-
-    /**
-     * 查询充电状态
-     *
-     * @param startChargeSeq
-     * @return
-     */
-    @Override
-    public JSONObject queryEquipChargeStatus(String startChargeSeq) {
-        var param = """
-                {
-                    "StartChargeSeq":"%s"
-                }
-                """.formatted(startChargeSeq);
-        var response = enPlusPost(EnPlusApi.EN_PLUS_QUERY_EQUIP_CHARGE_STATUS.getApi(), buildParams(param));
-        return JSONObject.parseObject(AESUtil.decrypt(response.getData()));
-    }
-
-    /**
-     * 与en+开发约定使用该接口更新正在充电中的订单的金额信息,解决充电过程中用户充值续充场景
-     *
-     * @param startChargeSeq
-     * @param amount
-     * @return
-     */
-    @Override
-    public JSONObject updateBalanceByQueryEquipChargeStatus(String startChargeSeq, int amount) {
-        var param = """
-                {
-                    "StartChargeSeq":"%s",
-                    "amount":%d
-                }
-                """.formatted(startChargeSeq, amount);
-        var response = enPlusPost(EnPlusApi.EN_PLUS_QUERY_EQUIP_CHARGE_STATUS.getApi(), buildParams(param));
-        return JSONObject.parseObject(AESUtil.decrypt(response.getData()));
-    }
-
-    /**
-     * 请求停止充电
-     *
-     * @param startChargeSeq
-     * @param connectorId
-     * @return
-     */
-    @Override
-    public JSONObject queryStopCharge(String startChargeSeq, String connectorId) {
-        var param = """
-                {
-                    "StartChargeSeq":"%s",
-                    "ConnectorID":"%s"
-                }
-                """.formatted(startChargeSeq, connectorId);
-        var response = enPlusPost(EnPlusApi.EN_PLUS_QUERY_STOP_CHARGE.getApi(), buildParams(param));
-        return JSONObject.parseObject(AESUtil.decrypt(response.getData()));
-    }
-
-}

+ 2 - 3
service/src/main/java/com/kym/service/miniapp/ChargeService.java

@@ -1,7 +1,6 @@
 package com.kym.service.miniapp;
 
-import com.baomidou.dynamic.datasource.annotation.DS;
-import com.kym.entity.enplus.response.EnBusinessPolicy;
+import com.kym.entity.platform.response.PlatformBusinessPolicy;
 import com.kym.entity.miniapp.ChargeOrder;
 
 import java.time.LocalDateTime;
@@ -25,7 +24,7 @@ public interface ChargeService {
 
     void queryStopCharge(long userId, String connectorId);
 
-    EnBusinessPolicy queryEquipBusinessPolicy(String connectorId);
+    PlatformBusinessPolicy queryEquipBusinessPolicy(String connectorId);
 
     Map<String, String> immediatelyCharge(String connectorId);
 

+ 0 - 3
service/src/main/java/com/kym/service/miniapp/CollectService.java

@@ -1,7 +1,6 @@
 package com.kym.service.miniapp;
 
 import com.github.yulichang.base.MPJBaseService;
-import com.kym.entity.enplus.EnStationStatusInfo;
 import com.kym.entity.miniapp.Collect;
 
 import java.util.List;
@@ -18,7 +17,5 @@ public interface CollectService extends MPJBaseService<Collect> {
 
     void updateCollect(String stationId, Integer status);
 
-    List<EnStationStatusInfo> getCollectList();
-
     List<Collect> listCollect();
 }

+ 6 - 5
service/src/main/java/com/kym/service/miniapp/impl/ChargeOrderServiceImpl.java

@@ -70,7 +70,8 @@ public class ChargeOrderServiceImpl extends MyBaseServiceImpl<ChargeOrderMapper,
     private final StationStatMonthService stationStatMonthService;
 
     private final StringRedisTemplate redisTemplate;
-    @Value("${en-plus.sassClose}")
+
+//    @Value("${en-plus.sassClose}")
     public String saasClose;
 
 
@@ -105,8 +106,8 @@ public class ChargeOrderServiceImpl extends MyBaseServiceImpl<ChargeOrderMapper,
             params.setConnectorId(connectorId);
         }
         // 判断数据权限
-        if (params.getStationId() == null) {
-            params.setStationId(CommUtil.isEmptyOrNull(KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong())) ? null : KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong()).get(0));
+        if (params.getStationIds() == null) {
+            params.setStationIds(CommUtil.isEmptyOrNull(KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong())) ? null : KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong()));
         }
         PageHelper.startPage(params.getPageNum(), params.getPageSize());
         // 查询订单列表(订单编号,手机号,充电站,充电桩SN/短码,订单状态,建单时间,结算时间,充电电量,实付金额,付款状态)
@@ -129,8 +130,8 @@ public class ChargeOrderServiceImpl extends MyBaseServiceImpl<ChargeOrderMapper,
         }
         // 判断数据权限
         var adminStationIds = KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong());
-        if (params.getStationId() != null && adminStationIds.contains(params.getStationId())) {
-            params.setStationId(adminStationIds.get(0));
+        if (params.getStationIds() == null) {
+            params.setStationIds(CommUtil.isEmptyOrNull(KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong())) ? null : KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong()));
         }
         // 查询订单列表(订单编号,手机号,充电站,充电桩SN/短码,订单状态,建单时间,结算时间,充电电量,实付金额,付款状态)
         var result = baseMapper.listChargeOrders(params);

+ 40 - 39
service/src/main/java/com/kym/service/miniapp/impl/ChargeServiceImpl.java

@@ -5,7 +5,7 @@ import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
 import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
-import com.kym.common.config.EnPlusConfig;
+import com.kym.common.cache.PlatformCache;
 import com.kym.common.constant.ResponseEnum;
 import com.kym.common.exception.BusinessException;
 import com.kym.common.utils.CommUtil;
@@ -14,16 +14,16 @@ import com.kym.entity.admin.Activity;
 import com.kym.entity.admin.ConnectorInfo;
 import com.kym.entity.admin.EquipmentInfo;
 import com.kym.entity.common.RedisKeys;
-import com.kym.entity.enplus.response.EnBusinessPolicy;
 import com.kym.entity.miniapp.*;
 import com.kym.entity.miniapp.delay.DelayChargeOrder;
+import com.kym.entity.platform.response.PlatformBusinessPolicy;
 import com.kym.service.admin.ConnectorInfoService;
 import com.kym.service.admin.EquipmentInfoService;
 import com.kym.service.admin.EquipmentRelationService;
 import com.kym.service.cache.KymCache;
-import com.kym.service.enplus.EnPlusService;
 import com.kym.service.jobs.DelayService;
 import com.kym.service.miniapp.*;
+import com.kym.service.platform.PlatformApiService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
@@ -33,7 +33,6 @@ import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
-import java.math.BigDecimal;
 import java.time.Duration;
 import java.time.LocalDateTime;
 import java.util.Map;
@@ -59,15 +58,15 @@ public class ChargeServiceImpl implements ChargeService {
     private final UserCouponService userCouponService;
     private final OrderCouponService orderCouponService;
     private final AccountService accountService;
-    private final EnPlusService enPlusService;
-    private final EnPlusConfig enPlusConfig;
+    private final PlatformApiService platformApiService;
     private final DelayService<DelayChargeOrder> startDelayService;
     private final DelayService<DelayChargeOrder> stopDelayService;
 
     public ChargeServiceImpl(EquipmentRelationService equipmentRelationService, EquipmentInfoService equipmentInfoService,
                              ConnectorInfoService connectorInfoService, ChargeOrderService chargeOrderService,
-                             OrderRechargeRightsService orderRechargeRightsService, UserRechargeRightsService userRechargeRightsService, UserCouponService userCouponService, OrderCouponService orderCouponService,
-                             AccountService accountService, EnPlusService enPlusService, EnPlusConfig enPlusConfig,
+                             OrderRechargeRightsService orderRechargeRightsService, UserRechargeRightsService userRechargeRightsService,
+                             UserCouponService userCouponService, OrderCouponService orderCouponService,
+                             AccountService accountService, PlatformApiService platformApiService,
                              @Qualifier("StartChargeDelayJob") @Lazy DelayService<DelayChargeOrder> startDelayService,
                              @Qualifier("StopChargeDelayJob") @Lazy DelayService<DelayChargeOrder> stopDelayService, StringRedisTemplate redisTemplate) {
         this.equipmentRelationService = equipmentRelationService;
@@ -79,8 +78,7 @@ public class ChargeServiceImpl implements ChargeService {
         this.userCouponService = userCouponService;
         this.orderCouponService = orderCouponService;
         this.accountService = accountService;
-        this.enPlusService = enPlusService;
-        this.enPlusConfig = enPlusConfig;
+        this.platformApiService = platformApiService;
         this.startDelayService = startDelayService;
         this.stopDelayService = stopDelayService;
         this.redisTemplate = redisTemplate;
@@ -193,7 +191,8 @@ public class ChargeServiceImpl implements ChargeService {
      */
     @Override
     @DSTransactional(rollbackFor = Exception.class)
-    public Map<String, String> queryStartCharge(Long userId, String connectorId, Long userRechargeRightsId, Long userCouponId, Boolean isBooking, LocalDateTime startTime, LocalDateTime endTime) {
+    public Map<String, String> queryStartCharge(Long userId, String connectorId, Long userRechargeRightsId, Long userCouponId,
+                                                Boolean isBooking, LocalDateTime startTime, LocalDateTime endTime) {
         var connectorId2StationId = getConnectorIdAndStationId(connectorId);
         connectorId = connectorId2StationId.get("connectorId");
         var stationId = connectorId2StationId.get("stationId");
@@ -209,7 +208,7 @@ public class ChargeServiceImpl implements ChargeService {
 
         if (order == null) {
             // 充电订单号/设备认证号
-            String startChargeSeq = OrderUtils.getOrderNo(enPlusConfig.getOperatorId());
+            String startChargeSeq = OrderUtils.getOrderNo(PlatformCache.INSTANCE.getPlatformByName(PlatformCache.INSTANCE.getPlatformNameByConnectorId(connectorId)).getOperatorId());
 
             // 组装订单数据
             order = new ChargeOrder();
@@ -297,10 +296,7 @@ public class ChargeServiceImpl implements ChargeService {
             }
         }
 
-        // 传递给EN+的余额要小于实际余额,防止订单超扣的情况,这里少传0.5元
-        // TODO: 2023-11-30 快充这里考虑过充的金额要提高
-        var amount = account.getBalance() - 50;
-        return startCharge(order, connectorId, amount);
+        return startCharge(order, connectorId, account.getBalance());
 
     }
 
@@ -368,13 +364,13 @@ public class ChargeServiceImpl implements ChargeService {
      *
      * @param order
      * @param connectorId
-     * @param amount
+     * @param balance
      * @return
      */
-    private Map<String, String> startCharge(ChargeOrder order, String connectorId, int amount) {
+    private Map<String, String> startCharge(ChargeOrder order, String connectorId, int balance) {
 
         // 请求设备认证
-        var equipAuth = enPlusService.queryEquipAuth(connectorId, order.getStartChargeSeq());
+        var equipAuth = platformApiService.queryEquipAuth(PlatformCache.INSTANCE.getPlatformNameByConnectorId(connectorId), connectorId, order.getStartChargeSeq());
 
         if (equipAuth.containsKey("SuccStat") && equipAuth.getIntValue("SuccStat") == 0) {
             // 启动充电
@@ -383,15 +379,15 @@ public class ChargeServiceImpl implements ChargeService {
             try {
                 // 二维码文本
                 var qrCode = "";
-                startCharge = enPlusService.queryStartCharge(order.getStartChargeSeq(), connectorId, qrCode, amount);
+                startCharge = platformApiService.queryStartCharge(PlatformCache.INSTANCE.getPlatformNameByConnectorId(connectorId), order.getStartChargeSeq(), connectorId, qrCode, balance);
             } catch (Exception e) {
                 // 这里可能超时,忽略
-                LOGGER.error("EN+启动充电超时,订单:{}", order.getStartChargeSeq());
+                LOGGER.error("启动充电异常,订单:{}", order.getStartChargeSeq());
                 // 启动充电超时,更新订单状态为取消
                 chargeOrderService.lambdaUpdate()
                         .set(ChargeOrder::getOrderStatus, ChargeOrder.CHARGE_STATUS_已取消)
                         .set(ChargeOrder::getChargeStatus, ChargeOrder.CHARGE_STATUS_已取消)
-                        .set(ChargeOrder::getStopReason, "EN+启动充电超时")
+                        .set(ChargeOrder::getStopReason, ChargeOrder.STOP_REASON_启动充电异常)
                         .eq(ChargeOrder::getStartChargeSeq, order.getStartChargeSeq()).update();
                 return Map.of("startChargeSeq", order.getStartChargeSeq());
             }
@@ -405,33 +401,33 @@ public class ChargeServiceImpl implements ChargeService {
                 LOGGER.error("设备启动充电失败:{}", startCharge);
                 switch (equipAuth.getIntValue("FailReason")) {
                     case 1 -> // 设备不存在
-                            throw new BusinessException(ResponseEnum.EN_PLUS_EQUIP_NOT_EXIST);
+                            throw new BusinessException(ResponseEnum.PLATFORM_EQUIP_NOT_EXIST);
                     case 2 -> // 设备离线
                         // todo 设备离线,加入重试机制
-                            throw new BusinessException(ResponseEnum.EN_PLUS_EQUIP_OFFLINE);
+                            throw new BusinessException(ResponseEnum.PLATFORM_EQUIP_OFFLINE);
                     case 3 -> // 存在未完成的订单
-                            throw new BusinessException(ResponseEnum.EN_PLUS_EQUIP_EXIST_ORDER_UNFINISHED);
+                            throw new BusinessException(ResponseEnum.PLATFORM_EQUIP_EXIST_ORDER_UNFINISHED);
                     case 4 -> // 此订单为停车中
-                            throw new BusinessException(ResponseEnum.EN_PLUS_ORDER_IS_PARKING);
+                            throw new BusinessException(ResponseEnum.PLATFORM_ORDER_IS_PARKING);
                     case 5 -> // 此订单已关闭
-                            throw new BusinessException(ResponseEnum.EN_PLUS_ORDER_CLOSED);
+                            throw new BusinessException(ResponseEnum.PLATFORM_ORDER_CLOSED);
                     case 6 -> // 设备未插枪
-                            throw new BusinessException(ResponseEnum.EN_PLUS_EQUIP_NOT_CONNECTED);
+                            throw new BusinessException(ResponseEnum.PLATFORM_EQUIP_NOT_CONNECTED);
                     case 7 -> // 预充金额存在且小于1元
                             throw new BusinessException(ResponseEnum.INSUFFICIENT_USER_BALANCE);
                 }
-                throw new BusinessException(ResponseEnum.EN_PLUS_EQUIP_START_FAIL);
+                throw new BusinessException(ResponseEnum.PLATFORM_EQUIP_START_FAIL);
             }
         } else {
             // 设备认证失败
             LOGGER.error("设备认证失败:{}", equipAuth);
             switch (equipAuth.getIntValue("FailReason")) {
                 case 1 -> // 设备未插枪
-                        throw new BusinessException(ResponseEnum.EN_PLUS_EQUIP_NOT_CONNECTED);
+                        throw new BusinessException(ResponseEnum.PLATFORM_EQUIP_NOT_CONNECTED);
                 case 2 -> // 设备检测失败
-                        throw new BusinessException(ResponseEnum.EN_PLUS_EQUIP_CHECK_FAIL);
+                        throw new BusinessException(ResponseEnum.PLATFORM_EQUIP_CHECK_FAIL);
             }
-            throw new BusinessException(ResponseEnum.EN_PLUS_EQUIP_AUTH_FAIL);
+            throw new BusinessException(ResponseEnum.PLATFORM_EQUIP_AUTH_FAIL);
         }
     }
 
@@ -541,17 +537,21 @@ public class ChargeServiceImpl implements ChargeService {
         connectorId = getConnectorId(connectorId);
         LOGGER.info("用户:{},设备:{}请求停止充电", userId, connectorId);
         // 查询充电订单
-        var chargeOrder = chargeOrderService.lambdaQuery().eq(ChargeOrder::getUserId, userId).eq(ChargeOrder::getConnectorId, connectorId).eq(ChargeOrder::getChargeStatus, ChargeOrder.CHARGE_STATUS_充电中).one();
+        var chargeOrder = chargeOrderService.lambdaQuery()
+                .eq(ChargeOrder::getUserId, userId)
+                .eq(ChargeOrder::getConnectorId, connectorId)
+                .eq(ChargeOrder::getChargeStatus, ChargeOrder.CHARGE_STATUS_充电中)
+                .one();
         if (chargeOrder == null) {
             // 记录失败原因
             LOGGER.error("用户:{}请求停止充电异常,设备:{}无进行中的订单", userId, connectorId);
             throw new BusinessException(ResponseEnum.NO_ORDER_IN_PROGRESS);
         }
-        var data = enPlusService.queryStopCharge(chargeOrder.getStartChargeSeq(), connectorId);
+        var data = platformApiService.queryStopCharge(PlatformCache.INSTANCE.getPlatformNameByConnectorId(connectorId), chargeOrder.getStartChargeSeq(), connectorId);
         if (data.containsKey("SuccStat") && data.getIntValue("SuccStat") != 0) {
             // 记录失败原因
             LOGGER.error("订单:{}停止充电失败,返回结果:{}", chargeOrder.getStartChargeSeq(), data);
-            throw new BusinessException(ResponseEnum.EN_PLUS_EQUIP_STOP_FAIL);
+            throw new BusinessException(ResponseEnum.PLATFORM_EQUIP_STOP_FAIL);
         }
         // 这里不更新订单状态,等待EN+推送停止充电结果信息再处理
 
@@ -564,10 +564,11 @@ public class ChargeServiceImpl implements ChargeService {
      * @return
      */
     @Override
-    public EnBusinessPolicy queryEquipBusinessPolicy(String connectorId) {
-        var equipBizSeq = OrderUtils.getOrderNo(enPlusConfig.getOperatorId());
-        var data = enPlusService.queryEquipBusinessPolicy(equipBizSeq, connectorId);
-        return data.toJavaObject(EnBusinessPolicy.class);
+    public PlatformBusinessPolicy queryEquipBusinessPolicy(String connectorId) {
+        var platformName = PlatformCache.INSTANCE.getPlatformNameByConnectorId(connectorId);
+        var equipBizSeq = OrderUtils.getOrderNo(PlatformCache.INSTANCE.getPlatformByName(platformName).getOperatorId());
+        var data = platformApiService.queryEquipBusinessPolicy(platformName, equipBizSeq, connectorId);
+        return data.toJavaObject(PlatformBusinessPolicy.class);
     }
 
 }

+ 0 - 19
service/src/main/java/com/kym/service/miniapp/impl/CollectServiceImpl.java

@@ -3,7 +3,6 @@ package com.kym.service.miniapp.impl;
 import cn.dev33.satoken.stp.StpUtil;
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.github.yulichang.base.MPJBaseServiceImpl;
-import com.kym.entity.enplus.EnStationStatusInfo;
 import com.kym.entity.miniapp.Collect;
 import com.kym.mapper.miniapp.CollectMapper;
 import com.kym.service.admin.StationService;
@@ -62,24 +61,6 @@ public class CollectServiceImpl extends MPJBaseServiceImpl<CollectMapper, Collec
 
     }
 
-    /**
-     * 收藏列表
-     * 获取EN+对应站点数据
-     *
-     * @return
-     */
-    @Override
-    public List<EnStationStatusInfo> getCollectList() {
-        var userid = StpUtil.getLoginIdAsLong();
-        var collectList = lambdaQuery().eq(Collect::getUserId, userid).list().stream().map(c -> String.valueOf(c.getStationId())).toArray(String[]::new);
-        if (collectList.length == 0) {
-            return stationService.stationStatus(collectList);
-        } else {
-            return null;
-        }
-
-    }
-
     /**
      * 获取收藏列表,前端匹配站点详情数据
      *

+ 9 - 0
service/src/main/java/com/kym/service/platform/Api.java

@@ -0,0 +1,9 @@
+package com.kym.service.platform;
+
+/**
+ * @author skyline
+ * @description
+ * @date 2023-07-08 10:34
+ */
+public interface Api {
+}

+ 38 - 0
service/src/main/java/com/kym/service/platform/PlatformApi.java

@@ -0,0 +1,38 @@
+package com.kym.service.platform;
+
+import com.kym.common.cache.PlatformCache;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+
+/**
+ * @author skyline
+ * 公共接口
+ */
+@AllArgsConstructor
+public enum PlatformApi implements Api {
+
+    // 认证-获取token
+    PLATFORM_QUERY_TOKEN("query_token", RequestMethod.POST), //获取AccessToken
+
+    // 站点
+    PLATFORM_QUERY_STATION_INFO("query_stations_info", RequestMethod.POST), // 站点信息
+    PLATFORM_QUERY_STATION_STATUS("query_station_status", RequestMethod.POST), // 站点状态
+    PLATFORM_QUERY_STATION_STATS("query_station_stats", RequestMethod.POST), // 站点统计
+    //充电
+    PLATFORM_QUERY_EQUIP_AUTH("query_equip_auth", RequestMethod.POST), // 请求设备认证
+    PLATFORM_QUERY_EQUIP_BUSINESS_POLICY("query_equip_business_policy", RequestMethod.POST), // 查询业务策略信息
+    PLATFORM_QUERY_START_CHARGE("query_start_charge", RequestMethod.POST), // 查询启动充电
+    PLATFORM_QUERY_STOP_CHARGE("query_stop_charge", RequestMethod.POST), // 请求停止充电
+    PLATFORM_QUERY_EQUIP_CHARGE_STATUS("query_equip_charge_status", RequestMethod.POST); // 查询设备充电状态
+
+
+    private final String api;
+    private final RequestMethod requestMethod;
+
+    public String getApi(String platformName) {
+        var config = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        return config.getApiDomain() + api;
+    }
+
+}

+ 34 - 0
service/src/main/java/com/kym/service/platform/PlatformApiService.java

@@ -0,0 +1,34 @@
+package com.kym.service.platform;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.kym.common.annotation.DynamicCache;
+import com.kym.entity.platform.response.PlatformResponse;
+
+/**
+ * @author skyline
+ * @description
+ * @date 2023-07-31 14:13
+ */
+public interface PlatformApiService {
+
+    PlatformResponse platformPost(String platformName, String url, String params);
+
+    String queryPlatformToken(String platformName);
+
+    JSONObject queryEquipAuth(String platformName, String connectorId, String equipAuthSeq);
+
+    @DynamicCache(spel = "#connectorId")
+    JSONObject queryEquipBusinessPolicy(String platformName, String equipBizSeq, String connectorId);
+
+
+    JSONObject queryStartCharge(String platformName, String startChargeSeq, String connectorId, String qrCode, Integer amount);
+
+
+    JSONObject queryEquipChargeStatus(String platformName, String startChargeSeq);
+
+
+    JSONObject updateBalanceByQueryEquipChargeStatus(String platformName, String startChargeSeq, int amount);
+
+
+    JSONObject queryStopCharge(String platformName, String startChargeSeq, String connectorId);
+}

+ 23 - 0
service/src/main/java/com/kym/service/platform/PlatformNotifyService.java

@@ -0,0 +1,23 @@
+package com.kym.service.platform;
+
+import com.alibaba.fastjson2.JSONObject;
+
+/**
+ * @author skyline
+ * @description
+ * @date 2023-08-04 14:24
+ */
+public interface PlatformNotifyService {
+
+
+    String handleNotificationStartChargeResult(String platformName, JSONObject json);
+
+    String handleNotificationEquipChargeStatus(String platformName, JSONObject json);
+
+    String handleNotificationStopChargeResult(String platformName, JSONObject json);
+
+    String handleNotificationChargeOrderInfo(String platformName, JSONObject json);
+
+    String handleNotificationStationStatus(String platformName, JSONObject json);
+    String queryToken(String platformName, JSONObject json);
+}

+ 294 - 0
service/src/main/java/com/kym/service/platform/impl/PlatformApiServiceImpl.java

@@ -0,0 +1,294 @@
+package com.kym.service.platform.impl;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.kym.common.annotation.ConnectorID;
+import com.kym.common.annotation.DynamicCache;
+import com.kym.common.annotation.PlatformConvert;
+import com.kym.common.annotation.PlatformName;
+import com.kym.common.cache.PlatformCache;
+import com.kym.common.constant.ResponseEnum;
+import com.kym.common.exception.BusinessException;
+import com.kym.common.utils.CommUtil;
+import com.kym.common.utils.PlatformAesUtil;
+import com.kym.common.utils.PlatformConvertUtil;
+import com.kym.entity.common.RedisKeys;
+import com.kym.entity.platform.PlatformRespQueryToken;
+import com.kym.entity.platform.response.PlatformResponse;
+import com.kym.service.platform.PlatformApi;
+import com.kym.service.platform.PlatformApiService;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import static com.kym.common.utils.PlatformAesUtil.buildPlatformParams;
+
+/**
+ * @author skyline
+ * 互联互通平台接口服务
+ */
+@Service
+@Slf4j
+public class PlatformApiServiceImpl implements PlatformApiService {
+
+    public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
+    static OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder().build();
+    private final RedisTemplate<String, String> redisTemplate;
+
+    public PlatformApiServiceImpl(RedisTemplate<String, String> redisTemplate) {
+        this.redisTemplate = redisTemplate;
+    }
+
+    public static <T> T parse(String json, Class<T> clz) {
+        return JSONObject.parseObject(json, clz);
+    }
+
+    private static String synchronizedCall(Request request) {
+        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
+            return response.body().string();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    /**
+     * 互联互通POST请求专属方法
+     *
+     * @param platformName
+     * @param url
+     * @param params
+     * @return
+     */
+    @Override
+    public PlatformResponse platformPost(String platformName, String url, String params) {
+        // token获取
+        var token = queryPlatformToken(platformName);
+        Headers headers = Headers.of("Authorization", "Bearer ".concat(token));
+        RequestBody requestBody = RequestBody.create(params, JSON);
+        Request request = new Request.Builder()
+                .headers(headers)
+                .post(requestBody)
+                .url(url)
+                .build();
+        var response = parse(synchronizedCall(request), PlatformResponse.class);
+
+        if (0 == response.getRet()) {
+            return response;
+        } else {
+            log.error(":url:{}, params:{},token:{},返回信息:{}", url, params, token, response);
+            if (4002 == response.getRet()) {
+                // 如果返回Ret=4002,token错误的情况下,删除redis中的token,如果是预约订单则将此订单设置为延迟启动
+                redisTemplate.delete(RedisKeys.PLATFORM_QUERY_TOKEN + platformName);
+                throw new BusinessException(ResponseEnum.PLATFORM_QUERY_TOKEN_EXCEPTION);
+            }
+            throw new BusinessException(ResponseEnum.PLATFORM_API_EXCEPTION);
+        }
+    }
+
+    /**
+     * 解析平台返回数据为JSONObject
+     *
+     * @param response
+     * @param platformName
+     * @return
+     */
+    JSONObject parsePlatformResponseData(PlatformResponse response, String platformName) {
+        var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        return JSONObject.parseObject(PlatformAesUtil.decrypt(platform.getDataSecret(), platform.getDataSecretIv(), response.getData()));
+    }
+
+
+    /**
+     * 查询平台互联互通token
+     *
+     * @param platformName
+     * @return
+     */
+    @Override
+    public String queryPlatformToken(String platformName) {
+        log.info("查询互联互通平台{}token", platformName);
+        var token = redisTemplate.opsForValue().get(RedisKeys.PLATFORM_QUERY_TOKEN + platformName);
+        if (CommUtil.isNotEmptyAndNull(token)) {
+            // 不同平台不同key
+            log.debug("从缓存中查询到token:{},ttl:{}", token, redisTemplate.getExpire(RedisKeys.PLATFORM_QUERY_TOKEN + platformName));
+            return token;
+        }
+        var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        var data = """
+                {
+                    "OperatorID":"%s",
+                    "OperatorSecret":"%s"
+                }
+                """.formatted(platform.getUserOperatorId(), platform.getOperatorSecret());
+
+        var requestParams = buildPlatformParams(platformName, data);
+
+        var response = platformGetToken(PlatformApi.PLATFORM_QUERY_TOKEN.getApi(platformName), requestParams);
+
+        if (response != null && 0 == response.getRet()) {
+            // 解密Data获取token
+            var jsonObject = parsePlatformResponseData(response, platformName);
+            var platformRespQueryToken = parse(jsonObject.toJSONString(), PlatformRespQueryToken.class);
+            log.debug("{}接口AccessToken:{}", platformName, platformRespQueryToken.toString());
+            // 缓存token不同平台不同key,有效期7天(我们这里每次请求en+获取token的有效期并不是从7天开始,有效期是在en+的剩余有效时间)
+            redisTemplate.opsForValue().set(RedisKeys.PLATFORM_QUERY_TOKEN + platformName,
+                    platformRespQueryToken.getAccessToken(), platformRespQueryToken.getTokenAvailableTime(), TimeUnit.SECONDS);
+            return platformRespQueryToken.getAccessToken();
+        } else {
+            // 记录错误码,返回错误信息
+            log.error("{}接口错误:接口名{}:返回信息:{}", platformName, "query_token", response);
+            throw new BusinessException(ResponseEnum.PLATFORM_QUERY_TOKEN_ERROR);
+        }
+    }
+
+    public PlatformResponse platformGetToken(String url, String params) {
+        // token获取
+        RequestBody requestBody = RequestBody.create(params, JSON);
+        Request request = new Request.Builder()
+                .post(requestBody)
+                .url(url)
+                .build();
+        var response = parse(synchronizedCall(request), PlatformResponse.class);
+
+        if (response != null && 0 == response.getRet()) {
+            return response;
+        } else {
+            log.error("互联互通接口数据异常:url:{}, params:{},返回信息:{}", url, params, response);
+            throw new BusinessException(ResponseEnum.PLATFORM_API_EXCEPTION);
+        }
+    }
+
+    /**
+     * 请求设备认证
+     *
+     * @param platformName 互联互通平台名称
+     * @param connectorId  充电设备接口编码
+     * @param equipAuthSeq 格式:运营商ID+唯一编码 27字符
+     * @return
+     */
+    @PlatformConvert
+    @Override
+    public JSONObject queryEquipAuth(@PlatformName String platformName, @ConnectorID String connectorId, String equipAuthSeq) {
+        var param = """
+                {
+                    "EquipAuthSeq":"%s",
+                    "ConnectorID":"%s"
+                }
+                """.formatted(equipAuthSeq, connectorId);
+        var response = platformPost(platformName, PlatformApi.PLATFORM_QUERY_EQUIP_AUTH.getApi(platformName), buildPlatformParams(platformName, param));
+
+        return parsePlatformResponseData(response, platformName);
+    }
+
+
+    /**
+     * 查询业务策略信息
+     *
+     * @param platformName 互联互通平台名称
+     * @param equipBizSeq  业务策略查询流水号 格式:运营商ID+唯一编码 27字符
+     * @param connectorId  充电设备接口编码
+     * @return
+     */
+    @Override
+    @DynamicCache(spel = "#connectorId")
+    @PlatformConvert
+    public JSONObject queryEquipBusinessPolicy(@PlatformName String platformName, String equipBizSeq, @ConnectorID String connectorId) {
+        var param = """
+                {
+                    "EquipBizSeq":"%s",
+                    "ConnectorID":"%s"
+                }
+                """.formatted(equipBizSeq, connectorId);
+        var response = platformPost(platformName, PlatformApi.PLATFORM_QUERY_EQUIP_BUSINESS_POLICY.getApi(platformName), buildPlatformParams(platformName, param));
+        return parsePlatformResponseData(response, platformName);
+    }
+
+    /**
+     * 请求EN+启动充电
+     *
+     * @param platformName
+     * @param startChargeSeq
+     * @param connectorId
+     * @param qrCode
+     * @param amount
+     * @return
+     */
+    @Override
+    @PlatformConvert
+    public JSONObject queryStartCharge(@PlatformName String platformName, String startChargeSeq, @ConnectorID String connectorId, String qrCode, Integer amount) {
+        var param = """
+                {
+                    "StartChargeSeq":"%s",
+                    "ConnectorID":"%s",
+                    "QRCode":"%s",
+                }
+                """.formatted(startChargeSeq, connectorId, qrCode);
+        var completeParams = PlatformConvertUtil.queryStartChargeParamsConvert(platformName, param, amount);
+        var response = platformPost(platformName, PlatformApi.PLATFORM_QUERY_START_CHARGE.getApi(platformName), buildPlatformParams(platformName, completeParams));
+        return parsePlatformResponseData(response, platformName);
+    }
+
+    /**
+     * 查询充电状态
+     *
+     * @param platformName
+     * @param startChargeSeq
+     * @return
+     */
+    @Override
+    public JSONObject queryEquipChargeStatus(String platformName, String startChargeSeq) {
+        var param = """
+                {
+                    "StartChargeSeq":"%s"
+                }
+                """.formatted(startChargeSeq);
+        var response = platformPost(platformName, PlatformApi.PLATFORM_QUERY_EQUIP_CHARGE_STATUS.getApi(platformName), buildPlatformParams(platformName, param));
+        return parsePlatformResponseData(response, platformName);
+    }
+
+    /**
+     * 与en+开发约定使用该接口更新正在充电中的订单的金额信息,解决充电过程中用户充值续充场景 (注意:朗新不支持该功能)
+     *
+     * @param platformName
+     * @param startChargeSeq
+     * @param amount         【EN+互联互通扩展参数】
+     * @return
+     */
+    @Override
+    public JSONObject updateBalanceByQueryEquipChargeStatus(String platformName, String startChargeSeq, int amount) {
+        var param = """
+                {
+                    "StartChargeSeq":"%s",
+                    "amount":%d
+                }
+                """.formatted(startChargeSeq, amount);
+        var response = platformPost(platformName, PlatformApi.PLATFORM_QUERY_EQUIP_CHARGE_STATUS.getApi(platformName), buildPlatformParams(platformName, param));
+        return parsePlatformResponseData(response, platformName);
+    }
+
+    /**
+     * 请求停止充电
+     *
+     * @param platformName
+     * @param startChargeSeq
+     * @param connectorId
+     * @return
+     */
+    @Override
+    @PlatformConvert
+    public JSONObject queryStopCharge(@PlatformName String platformName, String startChargeSeq, @ConnectorID String connectorId) {
+        var param = """
+                {
+                    "StartChargeSeq":"%s",
+                    "ConnectorID":"%s"
+                }
+                """.formatted(startChargeSeq, connectorId);
+        var response = platformPost(platformName, PlatformApi.PLATFORM_QUERY_STOP_CHARGE.getApi(platformName), buildPlatformParams(platformName, param));
+        return parsePlatformResponseData(response, platformName);
+    }
+
+}

+ 91 - 69
service/src/main/java/com/kym/service/enplus/impl/EnNotifyServiceImpl.java → service/src/main/java/com/kym/service/platform/impl/PlatformNotifyServiceImpl.java

@@ -1,26 +1,30 @@
-package com.kym.service.enplus.impl;
+package com.kym.service.platform.impl;
 
+import cn.hutool.core.util.IdUtil;
 import cn.hutool.extra.mail.MailUtil;
 import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.kym.common.cache.PlatformCache;
+import com.kym.common.utils.CommUtil;
+import com.kym.common.utils.PlatformAesUtil;
+import com.kym.common.utils.PlatformConvertUtil;
 import com.kym.entity.admin.ConnectorInfo;
 import com.kym.entity.admin.EquipmentInfo;
 import com.kym.entity.admin.MonitorLog;
 import com.kym.entity.common.RedisKeys;
-import com.kym.entity.enplus.EnConnectorStatusInfo;
 import com.kym.entity.miniapp.Account;
 import com.kym.entity.miniapp.ChargeOrder;
 import com.kym.entity.miniapp.WalletDetail;
+import com.kym.entity.platform.PlatformConnectorStatusInfo;
 import com.kym.service.admin.ConnectorInfoService;
 import com.kym.service.admin.EquipmentInfoService;
 import com.kym.service.admin.MonitorLogService;
 import com.kym.service.cache.KymCache;
-import com.kym.service.enplus.EnNotifyService;
-import com.kym.service.enplus.EnPlusService;
 import com.kym.service.factory.DiscountStrategyFactory;
 import com.kym.service.miniapp.*;
+import com.kym.service.platform.PlatformNotifyService;
 import jakarta.annotation.PostConstruct;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -33,19 +37,18 @@ import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
  * @author skyline
- * @description
- * @date 2023-08-04 14:26
+ * 接收处理互联互通平台推送信息
  */
 
 @Service
-public class EnNotifyServiceImpl implements EnNotifyService {
-    private static final Logger LOGGER = LoggerFactory.getLogger(EnNotifyServiceImpl.class);
+public class PlatformNotifyServiceImpl implements PlatformNotifyService {
+    private static final Logger LOGGER = LoggerFactory.getLogger(PlatformNotifyServiceImpl.class);
     public final StringRedisTemplate redisTemplate;
-    private final EnPlusService enPlusService;
     private final ChargeOrderService chargeOrderService;
     private final ChargeService chargeService;
     private final AccountService accountService;
@@ -53,17 +56,16 @@ public class EnNotifyServiceImpl implements EnNotifyService {
     private final MonitorLogService monitorLogService;
     private final EquipmentInfoService equipmentInfoService;
     private final ConnectorInfoService connectorInfoService;
-
     private final UserStationService userStationService;
 
     @Value("${kym.notify-email}")
     private String notifyEmail;
 
-    public EnNotifyServiceImpl(EnPlusService enPlusService, ChargeOrderService chargeOrderService,
-                               ChargeService chargeService, AccountService accountService, WalletDetailService walletDetailService,
-                               MonitorLogService monitorLogService, EquipmentInfoService equipmentInfoService,
-                               ConnectorInfoService connectorInfoService, StringRedisTemplate redisTemplate, UserStationService userStationService) {
-        this.enPlusService = enPlusService;
+    public PlatformNotifyServiceImpl(ChargeOrderService chargeOrderService, ChargeService chargeService,
+                                     AccountService accountService, WalletDetailService walletDetailService,
+                                     MonitorLogService monitorLogService, EquipmentInfoService equipmentInfoService,
+                                     ConnectorInfoService connectorInfoService, StringRedisTemplate redisTemplate,
+                                     UserStationService userStationService) {
         this.chargeOrderService = chargeOrderService;
         this.chargeService = chargeService;
         this.accountService = accountService;
@@ -80,31 +82,53 @@ public class EnNotifyServiceImpl implements EnNotifyService {
         KymCache.INSTANCE.putConnectorId2Status(connectorInfoService.list().stream().collect(Collectors.toMap(ConnectorInfo::getConnectorId, ConnectorInfo::getStatus)));
     }
 
+    @Override
+    public String queryToken(String platformName, JSONObject json) {
+        var data = PlatformAesUtil.signValidation(platformName, json);
+        LOGGER.info("【{}互联互通平台推送】收到请求快与慢Token:{},解密数据:{}", platformName, json, data);
+        var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        // 查询缓存,存在则返回值和过期时间,不存在则重新生成并缓存
+        var token = redisTemplate.opsForValue().get(RedisKeys.PLATFORM_TOKEN + platformName);
+        // 过期时间
+        var ttl = redisTemplate.getExpire(RedisKeys.PLATFORM_TOKEN + platformName);
+        if (CommUtil.isEmptyOrNull(token)) {
+            token = IdUtil.simpleUUID();
+            ttl = 7 * 24 * 3600L;
+            redisTemplate.opsForValue().set(RedisKeys.PLATFORM_TOKEN + platformName, token, ttl, TimeUnit.SECONDS);
+        }
+
+        var params = """
+                {
+                    "OperatorID":"%s",
+                    "SuccStat":%d,
+                    "AccessToken":"%s",
+                    "TokenAvailableTime":%d,
+                    "FailReason":%d
+                }
+                """.formatted(platform.getOperatorId(), 0, token, ttl, 0);
+        return PlatformAesUtil.encrypt(platform.getUserDataSecret(), platform.getUserDataSecretIv(), params);
+    }
+
     /**
      * EN+ 充电站设备状态变化推送
      *
+     * @param platformName
      * @param json
      * @return
      */
     @Override
     @DS("db-admin")
-    public String handleNotificationStationStatus(JSONObject json) {
-        var data = enPlusService.signValidation(json);
-        LOGGER.info("【EN+推送】收到充电桩设备状态变化推送:{},解密数据:{}", json, data);
+    public String handleNotificationStationStatus(String platformName, JSONObject json) {
+        var data = PlatformAesUtil.signValidation(platformName, json);
+        LOGGER.info("【{}互联互通平台推送】收到充电桩设备状态变化推送:{},解密数据:{}", platformName, json, data);
         // 更新数据库,存入redis,发送邮件通知
-        var connectorStatusInfo = JSONObject.parseObject(data).getJSONObject("ConnectorStatusInfo").toJavaObject(EnConnectorStatusInfo.class);
-        var connectorId = connectorStatusInfo.getConnectorId();
+        var connectorStatusInfo = JSONObject.parseObject(data).getJSONObject("ConnectorStatusInfo").toJavaObject(PlatformConnectorStatusInfo.class);
+        var connectorId = PlatformConvertUtil.parse2LocalConnectorId(connectorStatusInfo.getConnectorId());
         var equipmentId = connectorId.substring(0, 16);
 
-        equipmentInfoService.lambdaUpdate()
-                .eq(EquipmentInfo::getEquipmentId, equipmentId)
-                .set(EquipmentInfo::getServiceStatus, connectorStatusInfo.getStatus())
-                .update();
+        equipmentInfoService.lambdaUpdate().eq(EquipmentInfo::getEquipmentId, equipmentId).set(EquipmentInfo::getServiceStatus, connectorStatusInfo.getStatus()).update();
 
-        connectorInfoService.lambdaUpdate()
-                .eq(ConnectorInfo::getConnectorId, connectorId)
-                .set(ConnectorInfo::getStatus, connectorStatusInfo.getStatus())
-                .update();
+        connectorInfoService.lambdaUpdate().eq(ConnectorInfo::getConnectorId, connectorId).set(ConnectorInfo::getStatus, connectorStatusInfo.getStatus()).update();
 
 
         var connectorStatus = connectorStatusInfo.getStatus();
@@ -112,12 +136,7 @@ public class EnNotifyServiceImpl implements EnNotifyService {
         if (connectorStatus == 0) {
             LOGGER.info("充电桩设备离线:{}", connectorStatusInfo.getConnectorId());
             // 如果设备离线,则存入redis
-            var monitorLog = new MonitorLog()
-                    .setStationId(KymCache.INSTANCE.getStationIdByEquipmentIdOrConnectorId(connectorStatusInfo.getConnectorId()))
-                    .setSn(connectorStatusInfo.getConnectorId())
-                    .setOfflineTime(LocalDateTime.now())
-                    .setType(2)
-                    .setOfflineStatus(connectorStatusInfo.getStatus());
+            var monitorLog = new MonitorLog().setStationId(KymCache.INSTANCE.getStationIdByEquipmentIdOrConnectorId(connectorStatusInfo.getConnectorId())).setSn(connectorStatusInfo.getConnectorId()).setOfflineTime(LocalDateTime.now()).setType(2).setOfflineStatus(connectorStatusInfo.getStatus());
             monitorLogService.save(monitorLog);
 
             // 离线设备放入队列,60分钟之后如果还未恢复则放入长时间离线设备集合中并发送提醒,上线后发送提醒
@@ -128,16 +147,12 @@ public class EnNotifyServiceImpl implements EnNotifyService {
             var exist = redisTemplate.opsForSet().remove(RedisKeys.OFFLINE_EXPIRED, connectorStatusInfo.getConnectorId());
             if ((isDelete != null && isDelete > 0) || (exist != null && exist > 0)) {
                 // 更新设备监控表
-                monitorLogService.lambdaUpdate()
-                        .eq(MonitorLog::getSn, connectorStatusInfo.getConnectorId())
-                        .eq(MonitorLog::getIsRecover, MonitorLog.IS_RECOVER_未恢复) // 未恢复的记录
-                        .set(MonitorLog::getRecoverTime, LocalDateTime.now())
-                        .set(MonitorLog::getIsRecover, MonitorLog.IS_RECOVER_已恢复) // 设置为已恢复
+                monitorLogService.lambdaUpdate().eq(MonitorLog::getSn, connectorStatusInfo.getConnectorId()).eq(MonitorLog::getIsRecover, MonitorLog.IS_RECOVER_未恢复) // 未恢复的记录
+                        .set(MonitorLog::getRecoverTime, LocalDateTime.now()).set(MonitorLog::getIsRecover, MonitorLog.IS_RECOVER_已恢复) // 设置为已恢复
                         .update();
             }
             if (exist != null && exist > 0) {
-                MailUtil.send(notifyEmail, "【设备上线通知】", "站点:%s,设备%s恢复上线"
-                        .formatted(KymCache.INSTANCE.getStationNameByConnectorId(connectorStatusInfo.getConnectorId()), KymCache.INSTANCE.getShortIdByEquipmentIdOrConnectorId(connectorStatusInfo.getConnectorId())), false);
+                MailUtil.send(notifyEmail, "【设备上线通知】", "站点:%s,设备%s恢复上线".formatted(KymCache.INSTANCE.getStationNameByConnectorId(connectorStatusInfo.getConnectorId()), KymCache.INSTANCE.getShortIdByEquipmentIdOrConnectorId(connectorStatusInfo.getConnectorId())), false);
             }
         }
 
@@ -148,29 +163,33 @@ public class EnNotifyServiceImpl implements EnNotifyService {
         }
         KymCache.INSTANCE.putConnectorId2Status(Map.of(connectorId, connectorStatus));
 
-        return """
+        var params = """
                 {
                     "Status":%d
                 }
                 """.formatted(0);
+        var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        return PlatformAesUtil.encrypt(platform.getUserDataSecret(), platform.getUserDataSecretIv(), params);
     }
 
+
     /**
      * EN+ 推送启动充电结果
      *
+     * @param platformName
      * @param json
      * @return
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
     @DS("db-miniapp")
-    public String handleNotificationStartChargeResult(JSONObject json) {
-        var data = enPlusService.signValidation(json);
-        LOGGER.info("【EN+推送】收到启动充电结果推送:{},解密数据:{}", json, data);
+    public String handleNotificationStartChargeResult(String platformName, JSONObject json) {
+        var data = PlatformAesUtil.signValidation(platformName, json);
+        LOGGER.info("【{}互联互通平台推送】收到启动充电结果推送:{},解密数据:{}", platformName, json, data);
         var obj = JSONObject.parseObject(data);
         var startChargeSeq = obj.getString("StartChargeSeq");
         var startChargeSeqStat = obj.getIntValue("StartChargeSeqStat");
-        var connectorId = obj.getString("ConnectorID");
+        var connectorId = PlatformConvertUtil.parse2LocalConnectorId(obj.getString("ConnectorID"));
         var startTime = LocalDateTime.parse(obj.getString("StartTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
 
         // 更新订单状态
@@ -181,28 +200,31 @@ public class EnNotifyServiceImpl implements EnNotifyService {
         updateWrapper.set("charge_status", startChargeSeqStat);
         updateWrapper.set("start_time", startTime);
         chargeOrderService.update(updateWrapper);
-        return """
+        var params = """
                 {
                     "StartChargeSeq":"%s",
                     "SuccStat":%d,
                     "FailReason":%d
                 }
                 """.formatted(startChargeSeq, 0, 0);
+        var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        return PlatformAesUtil.encrypt(platform.getUserDataSecret(), platform.getUserDataSecretIv(), params);
     }
 
     /**
      * 推送充电状态,1分钟推送一次
      *
+     * @param platformName
      * @param json
      * @return
      * @see com.kym.miniapp.jobs.EquipmentChargeStatusJob#executeMpUserRelationJob()
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public String handleNotificationEquipChargeStatus(JSONObject json) {
-        var dataStr = enPlusService.signValidation(json);
+    public String handleNotificationEquipChargeStatus(String platformName, JSONObject json) {
+        var dataStr = PlatformAesUtil.signValidation(platformName, json);
         var data = JSONObject.parseObject(dataStr);
-        LOGGER.info("【EN+推送】 :{},解密数据:{}", json, data);
+        LOGGER.info("【{}互联互通平台推送】 :{},解密数据:{}", platformName, json, data);
         var startChargeSeq = data.getString("StartChargeSeq");
         var chargeOrder = chargeOrderService.getChargingOrderByStartChargeSeq(startChargeSeq);
         // 更新订单信息
@@ -219,53 +241,59 @@ public class EnNotifyServiceImpl implements EnNotifyService {
         redisTemplate.opsForHash().put(RedisKeys.CHARGE_ORDER_EQUIP_CHARGE_STATUS, startChargeSeq, JSONObject.toJSONString(chargeOrder));
         // 将数据库写入操作放到定时任务中
         // chargeOrderService.updateById(chargeOrder);
-        return """
+        var params = """
                 {
                     "StartChargeSeq":"%s",
                     "SuccStat":%d
                 }
                 """.formatted(startChargeSeq, 0);
+        var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        return PlatformAesUtil.encrypt(platform.getUserDataSecret(), platform.getUserDataSecretIv(), params);
     }
 
     /**
      * 推送停止充电结果
      *
+     * @param platformName
      * @param json
      * @return
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public String handleNotificationStopChargeResult(JSONObject json) {
-        var dataStr = enPlusService.signValidation(json);
+    public String handleNotificationStopChargeResult(String platformName, JSONObject json) {
+        var dataStr = PlatformAesUtil.signValidation(platformName, json);
         var data = JSONObject.parseObject(dataStr);
-        LOGGER.info("【EN+推送】收到停止充电结果推送:{},解密数据:{}", json, data);
+        LOGGER.info("【{}互联互通平台推送】收到停止充电结果推送:{},解密数据:{}", platformName, json, data);
         var startChargeSeq = data.getString("StartChargeSeq");
         var chargeOrder = chargeOrderService.getChargingOrderByStartChargeSeq(startChargeSeq);
         if (data.containsKey("SuccStat") && data.getIntValue("SuccStat") == 0) {
             chargeOrder.setChargeStatus(data.getIntValue("StartChargeSeqStat"));
             chargeOrderService.updateById(chargeOrder);
         }
-        return """
+        var params = """
                 {
                     "StartChargeSeq":"%s",
                     "SuccStat":%d,
                     "FailReason":%d
                 }
                 """.formatted(startChargeSeq, 0, 0);
+        var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        return PlatformAesUtil.encrypt(platform.getUserDataSecret(), platform.getUserDataSecretIv(), params);
     }
 
     /**
      * 推送充电订单信息(订单结算)
      *
+     * @param platformName
      * @param json
      * @return
      */
     @Override
     @DSTransactional(rollbackFor = Exception.class)
-    public String handleNotificationChargeOrderInfo(JSONObject json) {
-        var dataStr = enPlusService.signValidation(json);
+    public String handleNotificationChargeOrderInfo(String platformName, JSONObject json) {
+        var dataStr = PlatformAesUtil.signValidation(platformName, json);
         var data = JSONObject.parseObject(dataStr);
-        LOGGER.info("【EN+推送】收到充电订单信息推送:{},解密数据:{}", json, data);
+        LOGGER.info("【{}互联互通平台推送】收到充电订单信息推送:{},解密数据:{}", platformName, json, data);
         var startChargeSeq = data.getString("StartChargeSeq");
         var chargeOrder = chargeOrderService.getChargingOrderByStartChargeSeq(startChargeSeq);
 
@@ -275,16 +303,8 @@ public class EnNotifyServiceImpl implements EnNotifyService {
         // EN+平台推送重试策略是当天失败第二天再推送一次,仅此一次。EN+订单页面可以多次手动推送,所以这里要先判断订单状态,避免重复处理。
         if (chargeOrder.getChargeStatus() != ChargeOrder.CHARGE_STATUS_已结束 || chargeOrder.getOrderStatus() != ChargeOrder.ORDER_STATUS_成功) {
             // 更新订单信息
-            chargeOrder
-                    .setStartTime(LocalDateTime.parse(data.getString("StartTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
-                    .setEndTime(LocalDateTime.parse(data.getString("EndTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
-                    .setTotalPower(data.getDoubleValue("TotalPower"))
-                    .setElecMoney((int) Math.round(data.getDouble("TotalElecMoney") * 100))
-                    .setServiceMoney((int) Math.round(data.getDoubleValue("TotalSeviceMoney") * 100)) // 这里文档service单词错误,按文档填写
-                    .setTotalMoney((int) Math.round(data.getDoubleValue("TotalMoney") * 100))
-                    .setStopReason(data.getIntValue("StopReason"))
-                    .setSumPeriod(data.getIntValue("SumPeriod"))
-                    .setChargeDetail(data.getString("ChargeDetails"))
+            chargeOrder.setStartTime(LocalDateTime.parse(data.getString("StartTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).setEndTime(LocalDateTime.parse(data.getString("EndTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).setTotalPower(data.getDoubleValue("TotalPower")).setElecMoney((int) Math.round(data.getDouble("TotalElecMoney") * 100)).setServiceMoney((int) Math.round(data.getDoubleValue("TotalSeviceMoney") * 100)) // 这里文档service单词错误,按文档填写
+                    .setTotalMoney((int) Math.round(data.getDoubleValue("TotalMoney") * 100)).setStopReason(data.getIntValue("StopReason")).setSumPeriod(data.getIntValue("SumPeriod")).setChargeDetail(data.getString("ChargeDetails"))
                     // 实付金额初始化为订单总金额
                     .setPayAmount(chargeOrder.getTotalMoney());
 
@@ -306,13 +326,15 @@ public class EnNotifyServiceImpl implements EnNotifyService {
             userStationService.updateUserStation(chargeOrder);
         }
 
-        return """
+        var params = """
                 {
                     "StartChargeSeq":"%s",
                     "ConnectorID":"%s",
                     "ConfirmResult":%d
                 }
                 """.formatted(startChargeSeq, chargeOrder.getConnectorId(), 0);
+        var platform = PlatformCache.INSTANCE.getPlatformByName(platformName);
+        return PlatformAesUtil.encrypt(platform.getUserDataSecret(), platform.getUserDataSecretIv(), params);
     }
 
 

+ 9 - 10
service/src/main/java/com/kym/service/wechat/impl/WxPayServiceImpl.java

@@ -11,7 +11,6 @@ import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
 import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
-import com.google.common.util.concurrent.AtomicDouble;
 import com.kym.common.config.WxFapiaoConfig;
 import com.kym.common.config.WxPayConfig;
 import com.kym.common.constant.ResponseEnum;
@@ -19,14 +18,14 @@ import com.kym.common.exception.BusinessException;
 import com.kym.common.utils.CommUtil;
 import com.kym.common.utils.LambadaTools;
 import com.kym.common.utils.OrderUtils;
-import com.kym.entity.admin.InvoiceDetail;
 import com.kym.entity.miniapp.Account;
 import com.kym.entity.miniapp.*;
 import com.kym.entity.wechat.*;
 import com.kym.service.admin.ActivityService;
 import com.kym.service.admin.InvoiceDetailService;
-import com.kym.service.enplus.EnPlusService;
+import com.kym.common.cache.PlatformCache;
 import com.kym.service.miniapp.*;
+import com.kym.service.platform.PlatformApiService;
 import com.kym.service.wechat.WxPayService;
 import com.wechat.pay.java.core.Config;
 import com.wechat.pay.java.core.RSAAutoCertificateConfig;
@@ -106,7 +105,7 @@ public class WxPayServiceImpl implements WxPayService {
 
     private final InvoiceTitleService invoiceTitleService;
 
-    private final EnPlusService enPlusService;
+    private final PlatformApiService platformApiService;
 
     private final ActivityService activityService;
 
@@ -124,7 +123,7 @@ public class WxPayServiceImpl implements WxPayService {
     public WxPayServiceImpl(WxPayConfig conf, WxFapiaoConfig fapiaoConfig, WalletDetailService walletDetailService,
                             PayLogService payLogService, AccountService accountService, ChargeOrderService chargeOrderService,
                             RefundLogService refundLogService, InvoiceService invoiceService, InvoiceTitleService invoiceTitleService,
-                            EnPlusService enPlusService, ActivityService activityService, UserRechargeRightsService userRechargeRightsService, InvoiceDetailService invoiceDetailService) {
+                            PlatformApiService platformApiService, ActivityService activityService, UserRechargeRightsService userRechargeRightsService, InvoiceDetailService invoiceDetailService) {
         this.conf = conf;
         this.fapiaoConfig = fapiaoConfig;
         this.walletDetailService = walletDetailService;
@@ -134,7 +133,7 @@ public class WxPayServiceImpl implements WxPayService {
         this.refundLogService = refundLogService;
         this.invoiceService = invoiceService;
         this.invoiceTitleService = invoiceTitleService;
-        this.enPlusService = enPlusService;
+        this.platformApiService = platformApiService;
         this.activityService = activityService;
         this.userRechargeRightsService = userRechargeRightsService;
         this.invoiceDetailService = invoiceDetailService;
@@ -357,13 +356,13 @@ public class WxPayServiceImpl implements WxPayService {
                 payLogService.save(payLog);
                 LOGGER.info("微信支付回调{}:业务处理结束", notifyRes[2]);
 
-                // 如果存在进行中的订单,则向en+更新用户余额
+                // 如果存在进行中的订单,则向en+更新用户余额(朗新不支持此操作)
                 var chargingOrder = chargeOrderService.getChargingOrderByUserId(walletDetail.getUserId());
-                if (chargingOrder != null) {
+                if (chargingOrder != null && "EN_PLUS".equals(PlatformCache.INSTANCE.getPlatformNameByConnectorId(chargingOrder.getConnectorId()))) {
                     var account = accountService.getAccountByUserId(walletDetail.getUserId());
                     // TODO: 2023-11-30 快充这里考虑过充的金额要提高
-                    var res = enPlusService.updateBalanceByQueryEquipChargeStatus(chargingOrder.getStartChargeSeq(), account.getBalance() - 50);
-                    LOGGER.info("用户:{}充电过程中充值,已更新en+充电金额,en+返回数据:{}", account.getUserId(), res);
+                    var res = platformApiService.updateBalanceByQueryEquipChargeStatus(PlatformCache.INSTANCE.getPlatformNameByConnectorId(chargingOrder.getConnectorId()), chargingOrder.getStartChargeSeq(), account.getBalance() - 50);
+                    LOGGER.info("用户:{}充电过程中充值,已更新EN_PLUS充电金额,en+返回数据:{}", account.getUserId(), res);
                 }
                 return ResponseEntity.status(HttpStatus.OK).build();