ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/ChargingGunFallbackFactory.java
@@ -61,6 +61,11 @@ } @Override public R<List<TChargingGun>> getChargingGunByChargingPileIds(List<Integer> chargingPileIds) { return R.fail("根据充电桩ids获取枪失败:" + throwable.getMessage()); } @Override public R pushChargingGunStatus(Integer id, Integer status) { return R.fail("接口状态变化后推送给第三方失败:" + throwable.getMessage()); } ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/factory/SiteFallbackFactory.java
@@ -6,6 +6,7 @@ import com.ruoyi.chargingPile.api.model.Site; import com.ruoyi.chargingPile.api.model.TChargingPile; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.web.page.PageInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.openfeign.FallbackFactory; @@ -53,6 +54,11 @@ return R.fail("根据合作商id获取合作商详情失败:" + throwable.getMessage()); } @Override public PageInfo<Site> getSiteListPaging(Integer PageNo, Integer PageSize) { return null; } }; } } ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/feignClient/ChargingGunClient.java
@@ -69,6 +69,16 @@ /** * 根据充电桩ids获取枪 * @param chargingPileIds * @return */ @PostMapping("/t-charging-gun/getChargingGunByChargingPileIds") R<List<TChargingGun>> getChargingGunByChargingPileIds(@RequestParam("chargingPileIds") List<Integer> chargingPileIds); /** * 接口状态变化后推送给第三方 * @param id * @param status ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/factory/ChargingOrderAccountingStrategyFallbackFactory.java
@@ -4,6 +4,7 @@ import com.ruoyi.order.api.feignClient.ChargingOrderAccountingStrategyClient; import com.ruoyi.order.api.feignClient.ChargingOrderClient; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TChargingOrderAccountingStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.openfeign.FallbackFactory; @@ -38,6 +39,11 @@ public R<List<Double>> getDailyChargingDegree(Integer days, Set<Integer> siteIds) { return R.fail("获取给定天数每天的充电度数失败:" + throwable.getMessage()); } @Override public R<List<TChargingOrderAccountingStrategy>> getChargingOrderAccountingStrategyByOrderId(Long chargingOrderId) { return R.fail("根据订单id查询充电明细失败:" + throwable.getMessage()); } }; } } ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/factory/ChargingOrderFallbackFactory.java
@@ -4,6 +4,7 @@ import com.ruoyi.common.core.dto.ChargingOrderGroup; import com.ruoyi.common.core.dto.ChargingPercentProvinceDto; import com.ruoyi.order.api.feignClient.ChargingOrderClient; import com.ruoyi.order.api.model.AddTripartitePlatformOrder; import com.ruoyi.order.api.model.ChargingListQuery; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TSettlementConfirm; @@ -63,7 +64,12 @@ public R<List<ChargingOrderGroup>> getBySiteIdAndTime(ChargingPercentProvinceDto chargingPercentProvinceDto) { return null; } @Override public R<List<TChargingOrder>> getOrderBySiteIdAndTime(ChargingPercentProvinceDto chargingPercentProvinceDto) { return R.fail("根据站点id和时间区间查询订单数据失败:" + throwable.getMessage()); } @Override public R<Integer> getChargingCount(TChargingCountQuery req) { return R.fail("根据会员id和有效期查询有效期内享受充电折扣次数:" + throwable.getMessage()); @@ -174,6 +180,22 @@ public R<List<TChargingOrder>> getCarChargingOrder(Long carId, String startTime, String endTime) { return R.fail("根据车辆id获取指定时间范围内的数据失败:" + throwable.getMessage()); } @Override public R addTripartitePlatformOrder(AddTripartitePlatformOrder query) { return R.fail("添加三方平台充电订单数据失败:" + throwable.getMessage()); } @Override public R<TChargingOrder> getChargingOrderByStartChargeSeq(String startChargeSeq) { return R.fail("根据三方平台订单id获取充电数据失败:" + throwable.getMessage()); } @Override public R tripartitePlatformStopCharge(String startChargeSeq) { return R.fail("三方平台请求停止充电失败:" + throwable.getMessage()); } }; } } ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/feignClient/ChargingOrderAccountingStrategyClient.java
@@ -4,6 +4,7 @@ import com.ruoyi.common.core.domain.R; import com.ruoyi.order.api.factory.ChargingOrderAccountingStrategyFallbackFactory; import com.ruoyi.order.api.factory.ChargingOrderFallbackFactory; import com.ruoyi.order.api.model.TChargingOrderAccountingStrategy; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -38,4 +39,13 @@ */ @PostMapping("/t-charging-order-accounting-strategy/getDailyChargingDegree/{days}") R<List<Double>> getDailyChargingDegree(@PathVariable("days") Integer days, @RequestParam("siteIds") Set<Integer> siteIds); /** * 根据订单id查询充电明细 * @param chargingOrderId * @return */ @PostMapping("/t-charging-order-accounting-strategy/getChargingOrderAccountingStrategyByOrderId") R<List<TChargingOrderAccountingStrategy>> getChargingOrderAccountingStrategyByOrderId(@RequestParam("chargingOrderId") Long chargingOrderId); } ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/feignClient/ChargingOrderClient.java
@@ -6,6 +6,7 @@ import com.ruoyi.common.core.dto.ChargingPercentProvinceDto; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.order.api.factory.ChargingOrderFallbackFactory; import com.ruoyi.order.api.model.AddTripartitePlatformOrder; import com.ruoyi.order.api.model.ChargingListQuery; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TSettlementConfirm; @@ -42,6 +43,15 @@ @PostMapping(value = "/t-charging-order/getBySiteIdAndTime") R<List<ChargingOrderGroup>> getBySiteIdAndTime(@RequestBody ChargingPercentProvinceDto chargingPercentProvinceDto); /** * 根据站点id和时间区间查询订单数据 * @param chargingPercentProvinceDto * @return */ @PostMapping(value = "/t-charging-order/getOrderBySiteIdAndTime") R<List<TChargingOrder>> getOrderBySiteIdAndTime(@RequestBody ChargingPercentProvinceDto chargingPercentProvinceDto); @@ -235,5 +245,33 @@ * @return */ @PostMapping("/t-charging-order/getCarChargingOrder") R<List<TChargingOrder>> getCarChargingOrder(@RequestParam("carId") Long carId, @RequestParam("startTime") String startTime, @RequestParam("endTime") String endTime); R<List<TChargingOrder>> getCarChargingOrder(@RequestParam("carId") Long carId, @RequestParam("startTime") String startTime, @RequestParam("endTime") String endTime); /** * 添加三方平台充电订单数据 * @return */ @PostMapping("/t-charging-order/addTripartitePlatformOrder") R addTripartitePlatformOrder(@RequestBody AddTripartitePlatformOrder query); /** * 根据三方平台订单id获取充电数据 * @param startChargeSeq * @return */ @PostMapping("/t-charging-order/getChargingOrderByStartChargeSeq") R<TChargingOrder> getChargingOrderByStartChargeSeq(@RequestParam("startChargeSeq") String startChargeSeq); /** * 三方平台请求停止充电 * @param startChargeSeq * @return */ @PostMapping("/t-charging-order/tripartitePlatformStopCharge") R tripartitePlatformStopCharge(@RequestParam("startChargeSeq") String startChargeSeq); } ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/feignClient/OrderClient.java
@@ -24,10 +24,16 @@ */ @FeignClient(contextId = "OrderClient", value = ServiceNameConstants.ORDER_SERVICE, fallbackFactory = OrderFallbackFactory.class) public interface OrderClient { @PostMapping(value = "/t-charging-order/management/give/vip") public R managementGiveVip(@RequestBody TGrantVip grantVip); R managementGiveVip(@RequestBody TGrantVip grantVip); @GetMapping("/t-exchange-order/getSalesCountByGoodsIds/{goodsIds}") R<List<Integer>> getSalesCountByGoodsId(@PathVariable("goodsIds") String goodsIds); @GetMapping("/t-exchange-order/getCount") R<Integer> getSalesCountByGoodsIdgetCount(@RequestParam("goodId") Integer goodId,@RequestParam("goodeType")Integer goodeType,@RequestParam("buyType")Integer buyType); @@ -37,21 +43,31 @@ * @return */ @GetMapping("/t-exchange-order/getCodeByOrderId/{goodsIds}") public R<List<String>> getCodeByOrderId(@PathVariable("goodsIds")String goodsIds); R<List<String>> getCodeByOrderId(@PathVariable("goodsIds")String goodsIds); //查询已兑换的订单数 @PostMapping("/t-exchange-order/getById") public R<Long> getExchangeById(@RequestParam("goodId") Integer goodId,@RequestParam("userId") Long userId,@RequestParam("goodType") Integer goodType); R<Long> getExchangeById(@RequestParam("goodId") Integer goodId,@RequestParam("userId") Long userId,@RequestParam("goodType") Integer goodType); @PostMapping("/t-exchange-order/create") public R<ExchangeBackDto> exchangeCreate(@RequestBody ExchangeDto exchangeDto); R<ExchangeBackDto> exchangeCreate(@RequestBody ExchangeDto exchangeDto); @PostMapping("/t-vip-order/addVipOrder1") public R<Long> addVipOrder(@RequestBody TVipOrder vipOrder); R<Long> addVipOrder(@RequestBody TVipOrder vipOrder); @PostMapping("/t-shopping-order/create") public R<TShoppingOrder> shopCreate(@RequestBody ExchangeDto exchangeDto); R<TShoppingOrder> shopCreate(@RequestBody ExchangeDto exchangeDto); @PostMapping("/t-shopping-order/callBack") public R callBack(@RequestParam("code")String code,@RequestParam("outTradeNo")String outTradeNo); R callBack(@RequestParam("code")String code,@RequestParam("outTradeNo")String outTradeNo); @PostMapping("/t-vip-order/callBack") public R vipCallBack(@RequestParam("code")String code,@RequestParam("outTradeNo")String outTradeNo); R vipCallBack(@RequestParam("code")String code,@RequestParam("outTradeNo")String outTradeNo); /** @@ -61,6 +77,8 @@ */ @PostMapping(value = "/t-exchange-order/activityStatistics") R<TActivityVO> activityStatistics(@RequestBody TActivityStatisticsQuery dto); @PostMapping(value = "/chargingBill/accountBillList") @ApiOperation(value = "列表查询", tags = {"管理后台-账户结算账单"}) R<AccountListVO> accountBillList(@RequestBody ChargingListQuery dto); ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/AddTripartitePlatformOrder.java
New file @@ -0,0 +1,33 @@ package com.ruoyi.order.api.model; import lombok.Data; import java.math.BigDecimal; /** * @author zhibing.pu * @Date 2025/1/22 18:20 */ @Data public class AddTripartitePlatformOrder { /** * 三方充电订单号 */ private String startChargeSeq; /** * 充电枪id */ private Integer chargingGunId; /** * 运营商id */ private String operatorId; /** * 支付方式(1=微信,2=支付宝) */ private Integer rechargePaymentType; /** * 充电余额 */ private BigDecimal paymentAmount; } ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/StartChargeResult.java
New file @@ -0,0 +1,39 @@ package com.ruoyi.order.api.model; import lombok.Data; import javax.validation.constraints.NotNull; /** * 推送启动充电结果 * @author zhibing.pu * @Date 2025/1/22 18:40 */ @Data public class StartChargeResult { /** * 充电订单号 */ @NotNull private String StartChargeSeq; /** * 充电订单状态 * 1:启动中 * 2:充电中 * 3:停止中 * 4:已结束 * 5:未知 */ @NotNull private Integer StartChargeSeqStat; /** * 充电设别接口编码 */ @NotNull private String ConnectorID; /** * 充电启动时间 */ @NotNull private String StartTime; } ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/TChargingOrder.java
@@ -48,9 +48,18 @@ @ApiModelProperty(value = "订单类型(1=充电订单(小程序),2=充电订单(刷卡))") @TableField("order_type") private Integer orderType; @ApiModelProperty(value = "0平台1其他") @ApiModelProperty(value = "订单来源(1=自己平台,2=三方平台)") @TableField("order_source") private Integer orderSource; @ApiModelProperty(value = "运营商id") @TableField("operator_id") private Integer operatorId; @ApiModelProperty(value = "三方平台名称") @TableField("tripartite_platform_name") private String tripartitePlatformName; @ApiModelProperty(value = "三方平台充电订单号") @TableField("start_charge_seq") private String startChargeSeq; @ApiModelProperty(value = "平台或其他第三分名字") @TableField("source_name") ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/Operator.java
New file @@ -0,0 +1,67 @@ package com.ruoyi.other.api.domain; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; /** * 运营商信息 * @author zhibing.pu * @Date 2025/1/22 15:05 */ @Data @TableName("t_operator") public class Operator { /** * 主键 */ @TableId(value = "id", type = IdType.AUTO) private Integer id; /** * 运营商唯一码 */ @TableField("operatorId") private String operatorId; /** * 运营商名称 */ @TableField("name") private String name; /** * 运营商秘钥 */ @TableField("operatorSecret") private String operatorSecret; /** * 数据加密秘钥 */ @TableField("dataSecret") private String dataSecret; /** * 初始化向量 */ @TableField("dataSecretIv") private String dataSecretIv; /** * 签名秘钥 */ @TableField("sigSecret") private String sigSecret; /** * token */ @TableField(exist = false) private String token; /** * 登录时间 */ @TableField(exist = false) private Long loginTime; /** * 过期时间 */ @TableField(exist = false) private Long expireTime; } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/OperatorFallbackFactory.java
New file @@ -0,0 +1,25 @@ package com.ruoyi.other.api.factory; import com.ruoyi.common.core.domain.R; import com.ruoyi.other.api.domain.Operator; import com.ruoyi.other.api.feignClient.OperatorClient; import org.springframework.cloud.openfeign.FallbackFactory; /** * @author zhibing.pu * @Date 2025/1/22 15:16 */ public class OperatorFallbackFactory implements FallbackFactory<OperatorClient> { @Override public OperatorClient create(Throwable cause) { return new OperatorClient() { @Override public R<Operator> getOperator(String operatorId) { return R.fail("获取运营商数据失败:" + cause.getMessage()); } }; } } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/OperatorClient.java
New file @@ -0,0 +1,29 @@ package com.ruoyi.other.api.feignClient; import com.ruoyi.common.core.constant.ServiceNameConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.other.api.domain.Operator; import com.ruoyi.other.api.factory.OperatorFallbackFactory; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; /** * @author zhibing.pu * @Date 2025/1/22 15:15 */ @FeignClient(contextId = "OperatorClient", value = ServiceNameConstants.OTHER_SERVICE, fallbackFactory = OperatorFallbackFactory.class) public interface OperatorClient { /** * 获取运营商数据 * @param operatorId * @return */ @PostMapping("/operator/getOperator") R<Operator> getOperator(@RequestParam("operatorId") String operatorId); } ruoyi-api/ruoyi-api-other/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -8,4 +8,5 @@ com.ruoyi.other.api.factory.CouponFallbackFactory com.ruoyi.other.api.factory.InvoiceTypeFallbackFactory com.ruoyi.other.api.factory.WebSocketFallbackFactory com.ruoyi.other.api.factory.UserTagFallbackFactory com.ruoyi.other.api.factory.UserTagFallbackFactory com.ruoyi.other.api.factory.OperatorFallbackFactory ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/dto/ChargingPercentProvinceDto.java
@@ -9,8 +9,9 @@ @Data public class ChargingPercentProvinceDto { String provinceCode; LocalDate date1; LocalDate date2; Set<Integer> siteIds; private String provinceCode; private LocalDate date1; private LocalDate date2; private Set<Integer> siteIds; private String tripartitePlatformName; } ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyDetailController.java
@@ -187,7 +187,8 @@ */ @GetMapping("/getListByAccountingStrategyId") public R<List<TAccountingStrategyDetail>> getListByAccountingStrategyId(@RequestParam("id") Integer id){ List<TAccountingStrategyDetail> list = accountingStrategyDetailService.list(new LambdaQueryWrapper<TAccountingStrategyDetail>().eq(TAccountingStrategyDetail::getAccountingStrategyId, id)); List<TAccountingStrategyDetail> list = accountingStrategyDetailService.list(new LambdaQueryWrapper<TAccountingStrategyDetail>() .eq(TAccountingStrategyDetail::getAccountingStrategyId, id).orderByAsc(TAccountingStrategyDetail::getStartTime)); return R.ok(list); } ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingGunController.java
@@ -304,7 +304,21 @@ */ @PostMapping("/getChargingGunByChargingPileId") public R<List<TChargingGun>> getChargingGunByChargingPileId(@RequestParam("chargingPileId") Integer chargingPileId){ List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getChargingPileId, chargingPileId).eq(TChargingGun::getDelFlag, 0)); List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().eq(TChargingGun::getChargingPileId, chargingPileId) .eq(TChargingGun::getDelFlag, 0)); return R.ok(list); } /** * 根据充电桩ids获取枪 * @param chargingPileIds * @return */ @PostMapping("/getChargingGunByChargingPileIds") public R<List<TChargingGun>> getChargingGunByChargingPileIds(@RequestParam("chargingPileIds") List<Integer> chargingPileIds){ List<TChargingGun> list = chargingGunService.list(new LambdaQueryWrapper<TChargingGun>().in(TChargingGun::getChargingPileId, chargingPileIds) .eq(TChargingGun::getDelFlag, 0)); return R.ok(list); } } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/controller/TCECController.java
File was deleted ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/AESUtil.java
New file @@ -0,0 +1,107 @@ package com.ruoyi.integration.drainage; import com.ruoyi.common.core.utils.StringUtils; import org.springframework.util.Base64Utils; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /** * 定义AES加密解密工具类 */ public class AESUtil { private static final String KEY_ALGORITHM = "AES";//加密方式 private static final String DEFAULT_CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";//默认的加密算法 private static final String KEY = "1234567890abcdef";//密码 private static final String IV_PARAMETER = "1234567890abcdef";//偏移量 private static final String CHARSET = "UTF-8";//编码 /** * 加密操作 * @param content 待加密内容 * @return * @throws Exception */ public static String encrypt(String content) { return encrypt(content, KEY, IV_PARAMETER); } /** * 加密操作 * @param content 待加密内容 * @return * @throws Exception */ public static String encrypt(String content, String key, String iv_parameter) { try { if(StringUtils.isEmpty(content)){ return content; } Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); byte[] raw = key.getBytes(CHARSET); SecretKeySpec skeySpec = new SecretKeySpec(raw, KEY_ALGORITHM); IvParameterSpec iv = new IvParameterSpec(iv_parameter.getBytes()); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); byte[] encrypted = cipher.doFinal(content.getBytes(CHARSET)); return Base64Utils.encodeToString(encrypted); }catch (Exception e){ e.printStackTrace(); } return null; } public static String decrypt(String content) { return decrypt(content, KEY, IV_PARAMETER); } /** *解密操作 * @param content 待解密内容 * @return * @throws Exception */ public static String decrypt(String content, String key, String iv_parameter) { try { if(StringUtils.isEmpty(content)){ return content; } byte[] raw = key.getBytes(CHARSET); SecretKeySpec skeySpec = new SecretKeySpec(raw, KEY_ALGORITHM); Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); IvParameterSpec iv = new IvParameterSpec(iv_parameter.getBytes()); cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); byte[] encrypted1 = Base64Utils.decodeFromString(content); byte[] original = cipher.doFinal(encrypted1); String originalString = new String(original, CHARSET); return originalString; } catch (Exception ex) { ex.printStackTrace(); } return null; } public static void main(String[] ages){ String encrypt = AESUtil.encrypt("{\"total\":1,\"stationStatusInfo\":{\"operationID\":\"123456789\",\"stationID\":\"111111111111111\",\"connectorStatusInfos\":{\"connectorID\":1,\"equipmentID\":\"10000000000000000000001\",\"status\":4,\"currentA\":0,\"currentB\":0,\"currentC\":0,\"voltageA\":0,\"voltageB\":0,\"voltageC\":0,\"soc\":10,}}}"); System.err.println(encrypt); // String travel = AESUtil.decrypt("IGc1VSVN8ruGbmmXUQQKZQ=="); // System.err.println(travel); } } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/NotificationStopCharge.java
New file @@ -0,0 +1,33 @@ package com.ruoyi.integration.drainage; import lombok.Data; import javax.validation.constraints.NotNull; /** * 推送停止充电结果应答 * @author zhibing.pu * @Date 2025/1/23 9:17 */ @Data public class NotificationStopCharge { /** * 充电订单号 */ @NotNull private String StartChargeSeq; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull private Integer SuccStat; /** * 失败原因 * 0:无 * 1:接收失败 */ @NotNull private Integer FailReason; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/QueryStopCharge.java
New file @@ -0,0 +1,24 @@ package com.ruoyi.integration.drainage; import lombok.Data; import javax.validation.constraints.NotNull; /** * 请求停止充电 * @author zhibing.pu * @Date 2025/1/22 19:56 */ @Data public class QueryStopCharge { /** * 充电订单号 */ @NotNull private String StartChargeSeq; /** * 充电设备接口编码 */ @NotNull private String ConnectorID; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/SignUtil.java
New file @@ -0,0 +1,208 @@ package com.ruoyi.integration.drainage; import com.alibaba.fastjson.JSONObject; import org.apache.commons.lang3.StringUtils; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; /** * 签名工具 * @author zhibing.pu * @Date 2025/1/23 11:30 */ public class SignUtil { /*************************************快电******************************************/ /** * 签名算法 * * @param aValue 加密的原文,即源数据 * @param aKey 密钥 这是针对一条字符串进行加密的方法 */ public static String hmacSign (String aValue, String aKey) { byte k_ipad[] = new byte[64]; byte k_opad[] = new byte[64]; byte keyb[]; byte value[]; try { keyb = aKey.getBytes("UTF-8"); value = aValue.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { keyb = aKey.getBytes(); value = aValue.getBytes(); } Arrays.fill(k_ipad, keyb.length, 64, (byte) 54); Arrays.fill(k_opad, keyb.length, 64, (byte) 92); for (int i = 0; i < keyb.length; i++) { k_ipad[i] = (byte) (keyb[i] ^ 0x36); k_opad[i] = (byte) (keyb[i] ^ 0x5c); } MessageDigest md = null; try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { return null; } md.update(k_ipad); md.update(value); byte dg[] = md.digest(); md.reset(); md.update(k_opad); md.update(dg, 0, 16); dg = md.digest(); return toHex(dg); } public static String toHex (byte input[]) { if (input == null) { return null; } StringBuffer output = new StringBuffer(input.length * 2); for (int i = 0; i < input.length; i++) { int current = input[i] & 0xff; if (current < 16) { output.append("0"); } output.append(Integer.toString(current, 16)); } return output.toString().toUpperCase(); } /*************************************新电途******************************************/ /** * HmacMd5的计算公式为:HMAC(K,M) = H(K⊕opad∣H(K⊕ipad∣M)) * 其中:K是密钥(byte[] key),长度可为64字节(后面涉及描述都是以字节byte进行),若小于该长度,在密钥后面用0(即0x00)补齐。 * M是消息内容(byte[] m); * H是散列函数(此处采用MD5); * opad和ipad分别是由若干个0x5c和0x36组成的字符串; * ⊕表示异或运算; * ∣表示连接操作。 **/ public static byte[] getHMacMD5Bytes(byte[] key, byte[] m) { try { //定义长度 int length = 64; //定义opad和ipad byte[] opad = new byte[length]; byte[] ipad = new byte[length]; for (int i = 0; i < length; i++) { opad[i] = 0x5C; ipad[i] = 0x36; } byte[] actualKey = key; byte[] keyArr = new byte[length]; //如果密钥长度,大于64字节,就使用MD5算法计算其散列值,作为密钥 if (key.length > length) { actualKey = md5(key); } for (int i = 0; i < actualKey.length; i++) { keyArr[i] = actualKey[i]; } //如果密钥长度不足64字节,就使用0x00补齐到64字节 if (actualKey.length < length) { for (int i = key.length; i < length; i++) { keyArr[i] = 0x00; } } //使用密钥和ipad进行异或运算【K⊕ipad】 byte[] kIpadXorResult = new byte[length]; for (int i = 0; i < length; i++) { kIpadXorResult[i] = (byte) (keyArr[i] ^ ipad[i]); } //将待加密数据M追加到kIpadXorResult后面【K⊕ipad∣M】 byte[] firstAppendResult = new byte[kIpadXorResult.length + m.length]; for (int i = 0; i < kIpadXorResult.length; i++) { firstAppendResult[i] = kIpadXorResult[i]; } for (int i = 0; i < m.length; i++) { firstAppendResult[i + keyArr.length] = m[i]; } //做MD5运算【H(K⊕ipad∣M)】 byte[] firstHashResult = md5(firstAppendResult); //使用密钥和opad进行异或运算【K⊕opad】 byte[] kOpadXorResult = new byte[length]; for (int i = 0; i < length; i++) { kOpadXorResult[i] = (byte) (keyArr[i] ^ opad[i]); } //将firstHashResult追加到kOpadXorResult后面【K⊕opad∣H(K⊕ipad∣M)】 byte[] secondAppendResult = new byte[kOpadXorResult.length + firstHashResult.length]; for (int i = 0; i < kOpadXorResult.length; i++) { secondAppendResult[i] = kOpadXorResult[i]; } for (int i = 0; i < firstHashResult.length; i++) { secondAppendResult[kOpadXorResult.length + i] = firstHashResult[i]; } //做MD5运算【H(K⊕opad∣H(K⊕ipad∣M))】 return md5(secondAppendResult); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * MD5(产生出一个128位(16字节)的散列值) **/ private static byte[] md5(byte[] str) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str); return md.digest(); } /** * HEX转化为字符串 **/ public static String bytesToHexString(byte[] m) { StringBuilder stringBuilder = new StringBuilder(); if (m == null || m.length <= 0) { return null; } for (int i = 0; i < m.length; i++) { int v = m[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } //最后得到的签名,统一转化为大写 return stringBuilder.toString().toUpperCase(); } public static void main(String[] args) { // String encrypt = AESUtil.encrypt("{\"total\":1,\"stationStatusInfo\":{\"operationID\":\"123456789\",\"stationID\":\"111111111111111\",\"connectorStatusInfos\":{\"connectorID\":1,\"equipmentID\":\"10000000000000000000001\",\"status\":4,\"currentA\":0,\"currentB\":0,\"currentC\":0,\"voltageA\":0,\"voltageB\":0,\"voltageC\":0,\"soc\":10,}}}"); // String s = hmacSign(encrypt, "123456789abcdef"); // System.err.println(s); //签名秘钥SigSecret String key = "1234567890abcdef"; //运营商标识OperatorId String operatorId = "123456789"; //参数信息Data String data = "il7B0BSEjFdzpyKzfOFpvg/Se1CP802RItKYFPfSLRxJ3jf0bVl9hvYOEktPAYW2nd7S8MBcyHYyacHKbISq5iTmDzG+ivnR+SZJv3USNTYVMz9rCQVSxd0cLlqsJauko79NnwQJbzDTyLooYoIwz75qBOH2/xOMirpeEqRJrF/EQjWekJmGk9RtboXePu2rka+Xm51syBPhiXJAq0GfbfaFu9tNqs/e2Vjja/ltE1M0lqvxfXQ6da6HrThsm5id4ClZFIi0acRfrsPLRixS/IQYtksxghvJwbqOsbIsITail9Ayy4tKcogeEZiOO+4Ed264NSKmk7l3wKwJLAFjCFogBx8GE3OBz4pqcAn/ydA="; //时间戳TimeStamp(格式:年月日时分秒) String timeStamp = "20160729142400"; //自增序列Seq String seq = "0001"; //进行字符串拼接、计算 String m = new StringBuilder(operatorId).append(data).append(timeStamp).append(seq).toString(); byte[] hmacMd5 = getHMacMD5Bytes(key.getBytes(), m.getBytes()); // 打印计算得到的签名Sig System.out.println(bytesToHexString(hmacMd5)); } } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/TCECController.java
New file @@ -0,0 +1,1155 @@ package com.ruoyi.integration.drainage; import com.alibaba.fastjson.JSON; import com.ruoyi.chargingPile.api.feignClient.AccountingStrategyDetailClient; import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient; import com.ruoyi.chargingPile.api.feignClient.ChargingPileClient; import com.ruoyi.chargingPile.api.feignClient.SiteClient; import com.ruoyi.chargingPile.api.model.Site; import com.ruoyi.chargingPile.api.model.TAccountingStrategyDetail; import com.ruoyi.chargingPile.api.model.TChargingGun; import com.ruoyi.chargingPile.api.model.TChargingPile; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.dto.ChargingPercentProvinceDto; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.web.page.PageInfo; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.integration.drainage.model.*; import com.ruoyi.integration.drainage.model.enu.*; import com.ruoyi.order.api.feignClient.ChargingOrderAccountingStrategyClient; import com.ruoyi.order.api.feignClient.ChargingOrderClient; import com.ruoyi.order.api.model.AddTripartitePlatformOrder; import com.ruoyi.order.api.model.StartChargeResult; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TChargingOrderAccountingStrategy; import com.ruoyi.other.api.domain.Operator; import com.ruoyi.other.api.feignClient.OperatorClient; import com.ruoyi.system.api.model.LoginUser; import org.springframework.beans.BeanUtils; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; /** * @author zhibing.pu * @Date 2025/1/21 17:52 */ @RestController @RequestMapping("/evcs/v1.0") public class TCECController { @Resource private SiteClient siteClient; @Resource private ChargingPileClient chargingPileClient; @Resource private ChargingGunClient chargingGunClient; @Resource private ChargingOrderClient chargingOrderClient; @Resource private OperatorClient operatorClient; @Resource private AccountingStrategyDetailClient accountingStrategyDetailClient; @Resource private ChargingOrderAccountingStrategyClient chargingOrderAccountingStrategyClient; @Resource private TokenUtil tokenUtil; private static Map<Long, Integer> map = new HashMap<>(); /** * 请求校验 * @param baseRequest * @param request * @return */ public BaseResult requestCheck(Boolean tokenCheck, BaseRequest baseRequest, HttpServletRequest request){ BaseResult baseResult = new BaseResult(); baseResult.setRet(0); baseResult.setMsg("成功"); baseResult.setOperatorID(baseRequest.getOperatorID()); Long mapKey = Long.valueOf(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); Integer integer = map.get(mapKey); if(null == integer){ integer = 1; }else{ integer++; } map.put(mapKey, integer); baseResult.setTimeStamp(mapKey); baseResult.setSeq(String.format("%04d", integer)); //清空小于当前时间的map中的无效数据 for (Long k : map.keySet()) { if(k <= (mapKey - 10)){ map.remove(k); } } //校验token和签名 String operatorID = baseRequest.getOperatorID(); String sig = baseRequest.getSig(); Long timeStamp = baseRequest.getTimeStamp(); String data = baseRequest.getData(); String seq = baseRequest.getSeq(); if(StringUtils.isEmpty(operatorID) || StringUtils.isEmpty(sig) || StringUtils.isEmpty(data) || StringUtils.isEmpty(seq) || null == timeStamp){ baseResult.setRet(4003); baseResult.setMsg("参数异常"); return baseResult; } R<Operator> r = operatorClient.getOperator(operatorID); if(200 != r.getCode()){ baseResult.setRet(500); baseResult.setMsg("系统异常"); return baseResult; } //校验token if(tokenCheck){ LoginUser loginUser = tokenUtil.getLoginUser(request); if(null == loginUser){ baseResult.setRet(4002); baseResult.setMsg("身份校验失败,无效的token"); return baseResult; } } Operator operator = r.getData(); baseRequest.setOperator(operator); //校验签名 String sign = buildSign(baseRequest); if(!sign.equals(sig)){ baseResult.setRet(4001); baseResult.setMsg("签名校验失败"); return baseResult; } baseResult.setOperator(operator); return baseResult; } /** * 构建签名字符串 * @param model * @return */ public String buildSign(BaseModel model){ Operator operator = model.getOperator(); //签名秘钥SigSecret String key = operator.getSigSecret(); String sign = ""; switch (operator.getName()){ case "XinDianTu": //进行字符串拼接、计算 String m = new StringBuilder(model.getOperatorID()).append(model.getData()).append(model.getTimeStamp()).append(model.getSeq()).toString(); byte[] hmacMd5 = SignUtil.getHMacMD5Bytes(key.getBytes(), m.getBytes()); // 打印计算得到的签名Sig sign = SignUtil.bytesToHexString(hmacMd5); break; case "KuaiDian": sign = SignUtil.hmacSign(model.getData(), key); break; } return sign; } /** * 获取token * @return */ @PostMapping("/query_token") public BaseResult queryToken(@RequestBody BaseRequest baseRequest, HttpServletRequest request){ BaseResult baseResult = requestCheck(false, baseRequest, request); if(0 != baseResult.getRet()){ baseResult.setData(""); baseResult.setSig(buildSign(baseResult)); return baseResult; } QueryTokenResult queryTokenResult = new QueryTokenResult(); Operator operator = baseResult.getOperator(); if(null == operator){ queryTokenResult.setSuccStat(1); queryTokenResult.setFailReason(1); return baseResult; } //解密参数 String decrypt = AESUtil.decrypt(baseRequest.getData(), operator.getDataSecret(), operator.getDataSecretIv()); QueryToken queryToken = JSON.parseObject(decrypt, QueryToken.class); if(!queryToken.getOperatorSecret().equals(operator.getOperatorSecret())){ queryTokenResult.setSuccStat(1); queryTokenResult.setFailReason(2); //参数加密 String jsonString = JSON.toJSONString(queryTokenResult); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } //生成token Map<String, Object> token = tokenUtil.createToken(operator); String access_token = token.get("access_token").toString(); Long expires_in = Long.valueOf(token.get("expires_in").toString()); queryTokenResult.setSuccStat(0); queryTokenResult.setFailReason(0); queryTokenResult.setAccessToken(access_token); queryTokenResult.setTokenAvailableTime(expires_in * 60); //参数加密 String jsonString = JSON.toJSONString(queryTokenResult); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } /** * 查询充电站信息 * @return */ @PostMapping("/query_stations_info") public BaseResult queryStationsInfo(@RequestBody BaseRequest baseRequest, HttpServletRequest request){ //校验token和签名 BaseResult baseResult = requestCheck(true, baseRequest, request); if(0 != baseResult.getRet()){ baseResult.setData(""); baseResult.setSig(buildSign(baseResult)); return baseResult; } Operator operator = baseResult.getOperator(); //解密参数 String decrypt = AESUtil.decrypt(baseRequest.getData(), operator.getDataSecret(), operator.getDataSecretIv()); QueryStationsInfo queryStationsInfo = JSON.parseObject(decrypt, QueryStationsInfo.class); Integer pageNo = queryStationsInfo.getPageNo(); Integer pageSize = queryStationsInfo.getPageSize(); if(null == pageNo){ pageNo = 1; } if(null == pageSize){ pageSize = 10; } PageInfo<Site> siteListPaging = siteClient.getSiteListPaging(pageNo, pageSize); QueryStationsInfoResult queryStationsInfoResult = new QueryStationsInfoResult(); queryStationsInfoResult.setPageNo(pageNo); queryStationsInfoResult.setPageCount((0 == (siteListPaging.getTotal() % pageSize) ? 0 : 1) + Double.valueOf(siteListPaging.getTotal() / pageSize).intValue()); queryStationsInfoResult.setItemSize(Long.valueOf(siteListPaging.getTotal()).intValue()); queryStationsInfoResult.setStationInfos(buildSite(siteListPaging.getRecords())); //参数加密 String jsonString = JSON.toJSONString(queryStationsInfoResult); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } /** * 构建站点数据 * @param sites * @return */ public List<StationInfo> buildSite(List<Site> sites){ List<Integer> siteIds = sites.stream().map(Site::getId).collect(Collectors.toList()); List<TChargingPile> tChargingPiles = chargingPileClient.getChargingPileBySiteIds(siteIds).getData(); List<Integer> collect1 = tChargingPiles.stream().map(TChargingPile::getId).collect(Collectors.toList()); List<TChargingGun> chargingGunList = chargingGunClient.getChargingGunByChargingPileIds(collect1).getData(); List<StationInfo> StationInfos = new ArrayList<>(); for (Site datum : sites) { StationInfo stationInfo = new StationInfo(); stationInfo.setStationID(datum.getId().toString()); stationInfo.setOperatorID(""); stationInfo.setEquipmentOwnerID("91510903906171535D"); stationInfo.setStationName(datum.getName()); stationInfo.setCountryCode(datum.getCountryCode()); stationInfo.setAreaCode(datum.getDistrictsCode()); stationInfo.setAddress(datum.getAddress()); stationInfo.setStationTel(datum.getPhone()); stationInfo.setServiceTel(datum.getServicePhone()); switch (datum.getSiteType()){ case 0: stationInfo.setStationType(StationTypeEnum.OTHER.getType()); break; case 1: stationInfo.setStationType(StationTypeEnum.PUBLIC.getType()); break; case 2: stationInfo.setStationType(StationTypeEnum.PERSONAGE.getType()); break; case 3: stationInfo.setStationType(StationTypeEnum.BUS_SPECIFIC.getType()); break; case 4: stationInfo.setStationType(StationTypeEnum.SANITATION_SPECIFIC.getType()); break; case 5: stationInfo.setStationType(StationTypeEnum.LOGISTICS_SPECIFIC.getType()); break; case 6: stationInfo.setStationType(StationTypeEnum.TEXT_SPECIFIC.getType()); break; } if(datum.getStatus() == 1){ stationInfo.setStationStatus(StationStatusEnum.NORMAL_USE.getStatus()); } if(datum.getStatus() == 2){ stationInfo.setStationStatus(StationStatusEnum.MAINTAIN.getStatus()); } if(datum.getStatus() == 3){ stationInfo.setStationStatus(StationStatusEnum.OFF_LINE.getStatus()); } stationInfo.setParkNums(datum.getParkingSpace()); stationInfo.setStationLat(new BigDecimal(datum.getLat()).setScale(6, RoundingMode.DOWN)); stationInfo.setStationLng(new BigDecimal(datum.getLon()).setScale(6, RoundingMode.DOWN)); stationInfo.setConstruction(datum.getConstructionSite() == 0 ? ConstructionEnum.OTHER.getType() : datum.getConstructionSite()); stationInfo.setPictures(Arrays.asList(datum.getImgUrl().split(","))); stationInfo.setSiteGuide(datum.getGuide()); stationInfo.setMatchCars(datum.getVehicleDescription()); stationInfo.setBusineHours(datum.getStartServiceTime() + "-" + datum.getEndServiceTime()); stationInfo.setElectricityFee(datum.getRateDescription()); //构建充电设备信息数据 stationInfo.setEquipmentInfos(buildEquipmentInfo(datum.getId(), tChargingPiles, chargingGunList)); StationInfos.add(stationInfo); } return StationInfos; } /** * 构建桩数据 * @param tChargingPiles * @return */ public List<EquipmentInfo> buildEquipmentInfo(Integer siteId, List<TChargingPile> tChargingPiles, List<TChargingGun> chargingGunList){ List<EquipmentInfo> equipmentInfos = new ArrayList<>(); List<TChargingPile> collect = tChargingPiles.stream().filter(s -> s.getSiteId().equals(siteId)).collect(Collectors.toList()); for (TChargingPile tChargingPile : collect) { EquipmentInfo equipmentInfo = new EquipmentInfo(); equipmentInfo.setEquipmentID(tChargingPile.getId().toString()); equipmentInfo.setManufacturerID(tChargingPile.getManufacturerCode()); equipmentInfo.setManufacturerName(tChargingPile.getManufacturer()); equipmentInfo.setEquipmentModel(tChargingPile.getEquipmentType()); if(null != tChargingPile.getProductionDate()){ equipmentInfo.setProductionDate(tChargingPile.getProductionDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); } switch (tChargingPile.getType()){ case 0: equipmentInfo.setEquipmentType(EquipmentTypeEnum.OTHER.getType()); break; case 1: equipmentInfo.setEquipmentType(EquipmentTypeEnum.DIRECT_CURRENT.getType()); break; case 2: equipmentInfo.setEquipmentType(EquipmentTypeEnum.ALTERNATING_CURRENT.getType()); break; case 3: equipmentInfo.setEquipmentType(EquipmentTypeEnum.ALTERNATING_DIRECT.getType()); break; case 4: equipmentInfo.setEquipmentType(EquipmentTypeEnum.WIRELESS_DEVICE.getType()); break; } //构建设备接口信息 equipmentInfo.setConnectorInfos(buildConnectorInfos(tChargingPile.getId(), chargingGunList)); equipmentInfos.add(equipmentInfo); } return equipmentInfos; } /** * 构建接口数据 * @param chargingGunList * @return */ public List<ConnectorInfo> buildConnectorInfos(Integer chargingPileId, List<TChargingGun> chargingGunList){ List<ConnectorInfo> connectorInfos = new ArrayList<>(); List<TChargingGun> collect = chargingGunList.stream().filter(s -> s.getChargingPileId().equals(chargingPileId)).collect(Collectors.toList()); for (TChargingGun chargingGun : collect) { ConnectorInfo connectorInfo = new ConnectorInfo(); connectorInfo.setConnectorID(chargingGun.getId().toString()); connectorInfo.setConnectorName(chargingGun.getName()); switch (chargingGun.getType()){ case 0: connectorInfo.setConnectorType(ConnectorTypeEnum.OTHER.getType()); break; case 1: connectorInfo.setConnectorType(ConnectorTypeEnum.HOUSEHOLD_SOCKET.getType()); break; case 2: connectorInfo.setConnectorType(ConnectorTypeEnum.AC_SOCKET.getType()); break; case 3: connectorInfo.setConnectorType(ConnectorTypeEnum.AC_INTERFACE_PLUG.getType()); break; case 4: connectorInfo.setConnectorType(ConnectorTypeEnum.DC_INTERFACE_GUN_HEAD.getType()); break; case 5: connectorInfo.setConnectorType(ConnectorTypeEnum.WIRELESS_CHARGING_STAND.getType()); break; } connectorInfo.setVoltageUpperLimits(chargingGun.getUpperRatedVoltage().intValue()); connectorInfo.setVoltageLowerLimits(chargingGun.getLowerLimitOfRatedVoltage().intValue()); connectorInfo.setCurrent(chargingGun.getRatedCurrent().intValue()); connectorInfo.setPower(chargingGun.getRatedPower()); connectorInfo.setParkNo(chargingGun.getParkingNumber()); connectorInfo.setNationalStandard(Integer.valueOf(chargingGun.getNationalStandard())); connectorInfos.add(connectorInfo); } return connectorInfos; } /** * 接口状态变化后推送给第三方 * @return */ @PostMapping("/pushChargingGunStatus") public R pushChargingGunStatus(@RequestParam("id") Integer id, @RequestParam("status") Integer status){ ConnectorStatusInfo connectorStatusInfo = new ConnectorStatusInfo(); connectorStatusInfo.setConnectorID(id.toString()); switch (status){ case 1: connectorStatusInfo.setStatus(0); break; case 2: connectorStatusInfo.setStatus(1); break; case 3: connectorStatusInfo.setStatus(2); break; case 4: connectorStatusInfo.setStatus(3); break; case 5: connectorStatusInfo.setStatus(3); break; case 6: connectorStatusInfo.setStatus(4); break; case 7: connectorStatusInfo.setStatus(255); break; } NotificationStationStatusResult result = TCECUtil.notificationStationStatus(connectorStatusInfo); return R.ok(); } /** * 设备接口状态查询 * @return */ @PostMapping("/query_station_status") public BaseResult queryStationStatus(@RequestBody BaseRequest baseRequest, HttpServletRequest request){ BaseResult baseResult = requestCheck(true, baseRequest, request); if(0 != baseResult.getRet()){ baseResult.setData(""); baseResult.setSig(buildSign(baseResult)); return baseResult; } Operator operator = baseResult.getOperator(); //解密参数 String decrypt = AESUtil.decrypt(baseRequest.getData(), operator.getDataSecret(), operator.getDataSecretIv()); QueryStationStatus queryStationsInfo = JSON.parseObject(decrypt, QueryStationStatus.class); List<Integer> collect = queryStationsInfo.getStationIDs().stream().map(Integer::valueOf).collect(Collectors.toList()); List<Site> data = siteClient.getSiteByIds(collect).getData(); List<Integer> siteIds = data.stream().map(Site::getId).collect(Collectors.toList()); List<TChargingPile> tChargingPiles = chargingPileClient.getChargingPileBySiteIds(siteIds).getData(); List<Integer> collect1 = tChargingPiles.stream().map(TChargingPile::getId).collect(Collectors.toList()); List<TChargingGun> chargingGunList = chargingGunClient.getChargingGunByChargingPileIds(collect1).getData(); QueryStationStatusResult result = new QueryStationStatusResult(); result.setTotal(data.size()); List<StationStatusInfo> StationStatusInfos = new ArrayList<>(); for (Site datum : data) { StationStatusInfo stationStatusInfo = new StationStatusInfo(); stationStatusInfo.setStationID(datum.getId().toString()); //构建接口状态 List<ConnectorStatusInfo> ConnectorStatusInfos = new ArrayList<>(); List<TChargingGun> collect2 = chargingGunList.stream().filter(s -> s.getSiteId().equals(datum.getId())).collect(Collectors.toList()); for (TChargingGun chargingGun : collect2) { ConnectorStatusInfo info = new ConnectorStatusInfo(); info.setConnectorID(chargingGun.getId().toString()); switch (chargingGun.getStatus()){ case 1: info.setStatus(0); break; case 2: info.setStatus(1); break; case 3: info.setStatus(2); break; case 4: info.setStatus(3); break; case 5: info.setStatus(3); break; case 6: info.setStatus(4); break; case 7: info.setStatus(255); break; } ConnectorStatusInfos.add(info); } stationStatusInfo.setConnectorStatusInfos(ConnectorStatusInfos); StationStatusInfos.add(stationStatusInfo); } result.setStationStatusInfos(StationStatusInfos); //参数加密 String jsonString = JSON.toJSONString(result); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } /** * 查询统计信息 * @return */ @PostMapping("/query_station_stats") public BaseResult queryStationStats(@RequestBody BaseRequest baseRequest, HttpServletRequest request){ //校验token和签名 BaseResult baseResult = requestCheck(true, baseRequest, request); if(0 != baseResult.getRet()){ baseResult.setData(""); baseResult.setSig(buildSign(baseResult)); return baseResult; } Operator operator = baseResult.getOperator(); //解密参数 String decrypt = AESUtil.decrypt(baseRequest.getData(), operator.getDataSecret(), operator.getDataSecretIv()); QueryStationStats queryStationStats = JSON.parseObject(decrypt, QueryStationStats.class); QueryStationStatsResult result = new QueryStationStatsResult(); ChargingPercentProvinceDto dto = new ChargingPercentProvinceDto(); dto.setDate1(LocalDate.parse(queryStationStats.getStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"))); dto.setDate2(LocalDate.parse(queryStationStats.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"))); dto.setSiteIds(new HashSet<>(Integer.valueOf(queryStationStats.getStationID()))); dto.setTripartitePlatformName(operator.getName()); List<TChargingOrder> chargingOrders = chargingOrderClient.getOrderBySiteIdAndTime(dto).getData(); BigDecimal reduce = chargingOrders.stream().map(TChargingOrder::getChargingCapacity).reduce(BigDecimal.ZERO, BigDecimal::add); StationStatsInfo stationStats = new StationStatsInfo(); stationStats.setStationID(chargingOrders.get(0).getSiteId().toString()); stationStats.setStartTime(queryStationStats.getStartTime()); stationStats.setEndTime(queryStationStats.getEndTime()); stationStats.setStationElectricity(reduce); //构建设备统计数据 List<EquipmentStatsInfo> EquipmentStatsInfos = new ArrayList<>(); Map<Integer, List<TChargingOrder>> collect = chargingOrders.stream().collect(Collectors.groupingBy(TChargingOrder::getChargingPileId)); for (Integer integer : collect.keySet()) { List<TChargingOrder> tChargingOrders = collect.get(integer); BigDecimal reduce1 = tChargingOrders.stream().map(TChargingOrder::getChargingCapacity).reduce(BigDecimal.ZERO, BigDecimal::add); EquipmentStatsInfo equipmentStatsInfo = new EquipmentStatsInfo(); equipmentStatsInfo.setEquipmentID(integer.toString()); equipmentStatsInfo.setEquipmentElectricity(reduce1); //构建设备接口统计数据 Map<Integer, List<TChargingOrder>> collect2 = tChargingOrders.stream().collect(Collectors.groupingBy(TChargingOrder::getChargingGunId)); List<ConnectorStatsInfo> ConnectorStatsInfos = new ArrayList<>(); for (Integer integer1 : collect2.keySet()) { List<TChargingOrder> tChargingOrders1 = collect2.get(integer1); BigDecimal reduce2 = tChargingOrders1.stream().map(TChargingOrder::getChargingCapacity).reduce(BigDecimal.ZERO, BigDecimal::add); ConnectorStatsInfo connectorStatsInfo = new ConnectorStatsInfo(); connectorStatsInfo.setConnectorID(integer1.toString()); connectorStatsInfo.setConnectorElectricity(reduce2); ConnectorStatsInfos.add(connectorStatsInfo); } equipmentStatsInfo.setConnectorStatsInfos(ConnectorStatsInfos); EquipmentStatsInfos.add(equipmentStatsInfo); } stationStats.setEquipmentStatsInfos(EquipmentStatsInfos); result.setStationStats(stationStats); //参数加密 String jsonString = JSON.toJSONString(result); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } /** * 请求设备认证 * @return */ @PostMapping("/query_equip_auth") public BaseResult queryEquipAuth(@RequestBody BaseRequest baseRequest, HttpServletRequest request){ //校验token和签名 BaseResult baseResult = requestCheck(true, baseRequest, request); if(0 != baseResult.getRet()){ baseResult.setData(""); baseResult.setSig(buildSign(baseResult)); return baseResult; } Operator operator = baseResult.getOperator(); //解密参数 String decrypt = AESUtil.decrypt(baseRequest.getData(), operator.getDataSecret(), operator.getDataSecretIv()); QueryEquipAuth queryEquipAuth = JSON.parseObject(decrypt, QueryEquipAuth.class); String connectorID = queryEquipAuth.getConnectorID(); TChargingGun tChargingGun = chargingGunClient.getChargingGunById(Integer.valueOf(connectorID)).getData(); if(null == tChargingGun){ baseResult.setRet(4004); baseResult.setMsg("connectorID 参数无效"); return baseResult; } QueryEquipAuthResult queryEquipAuthResult = new QueryEquipAuthResult(); queryEquipAuthResult.setEquipAuthSeq(queryEquipAuth.getEquipAuthSeq()); queryEquipAuthResult.setConnectorID(connectorID); //1=离线,2=空闲,3=占用(未充电),4=占用(充电中),5=占用(已充满),6=占用(预约锁定),7=故障 switch (tChargingGun.getStatus()){ case 1: queryEquipAuthResult.setSuccStat(1); queryEquipAuthResult.setFailReason(2); break; case 2: queryEquipAuthResult.setSuccStat(0); queryEquipAuthResult.setFailReason(0); break; case 3: queryEquipAuthResult.setSuccStat(0); queryEquipAuthResult.setFailReason(1); break; case 4: queryEquipAuthResult.setSuccStat(1); queryEquipAuthResult.setFailReason(4); break; case 5: queryEquipAuthResult.setSuccStat(1); queryEquipAuthResult.setFailReason(5); break; case 6: queryEquipAuthResult.setSuccStat(1); queryEquipAuthResult.setFailReason(6); break; case 7: queryEquipAuthResult.setSuccStat(1); queryEquipAuthResult.setFailReason(2); break; } //参数加密 String jsonString = JSON.toJSONString(queryEquipAuthResult); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } /** * 查询业务策略信息 * @return */ @PostMapping("/query_equip_business_policy") public BaseResult queryEquipBusinessPolicy(@RequestBody BaseRequest baseRequest, HttpServletRequest request){ //校验token和签名 BaseResult baseResult = requestCheck(true, baseRequest, request); if(0 != baseResult.getRet()){ baseResult.setData(""); baseResult.setSig(buildSign(baseResult)); return baseResult; } Operator operator = baseResult.getOperator(); //解密参数 String decrypt = AESUtil.decrypt(baseRequest.getData(), operator.getDataSecret(), operator.getDataSecretIv()); QueryEquipBusinessPolicy queryEquipBusinessPolicy = JSON.parseObject(decrypt, QueryEquipBusinessPolicy.class); //构建返回结果 QueryEquipBusinessPolicyResult queryEquipBusinessPolicyResult = new QueryEquipBusinessPolicyResult(); queryEquipBusinessPolicyResult.setEquipBizSeq(queryEquipBusinessPolicy.getEquipBizSeq()); queryEquipBusinessPolicyResult.setConnectorID(queryEquipBusinessPolicy.getConnectorID()); queryEquipBusinessPolicyResult.setSuccStat(0); queryEquipBusinessPolicyResult.setFailReason(0); String connectorID = queryEquipBusinessPolicy.getConnectorID(); TChargingGun tChargingGun = chargingGunClient.getChargingGunById(Integer.valueOf(connectorID)).getData(); if(null == tChargingGun){ baseResult.setRet(4004); baseResult.setMsg("connectorID 参数无效"); //参数加密 String jsonString = JSON.toJSONString(queryEquipBusinessPolicyResult); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } Integer accountingStrategyId = tChargingGun.getAccountingStrategyId(); if(null == accountingStrategyId){ List<Site> data = siteClient.getSiteByIds(Arrays.asList(tChargingGun.getSiteId())).getData(); accountingStrategyId = data.get(0).getAccountingStrategyId(); } List<TAccountingStrategyDetail> accountingStrategyDetails = accountingStrategyDetailClient.getListByAccountingStrategyId(accountingStrategyId).getData(); if(accountingStrategyDetails.size() == 0){ queryEquipBusinessPolicyResult.setSuccStat(1); queryEquipBusinessPolicyResult.setFailReason(1); queryEquipBusinessPolicyResult.setSumPeriod(0); //参数加密 String jsonString = JSON.toJSONString(queryEquipBusinessPolicyResult); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } List<PolicyInfo> PolicyInfos = new ArrayList<>(); for (TAccountingStrategyDetail accountingStrategyDetail : accountingStrategyDetails) { PolicyInfo policyInfo = new PolicyInfo(); policyInfo.setStartTime(accountingStrategyDetail.getStartTime().replaceAll(":", "") + "00"); policyInfo.setElecPrice(accountingStrategyDetail.getElectrovalence()); policyInfo.setSevicePrice(accountingStrategyDetail.getServiceCharge()); PolicyInfos.add(policyInfo); } queryEquipBusinessPolicyResult.setSumPeriod(PolicyInfos.size()); queryEquipBusinessPolicyResult.setPolicyInfos(PolicyInfos); //参数加密 String jsonString = JSON.toJSONString(queryEquipBusinessPolicyResult); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } /** * 请求定充电 * @return */ @PostMapping("/query_start_charge") public BaseResult queryStartCharge(@RequestBody BaseRequest baseRequest, HttpServletRequest request){ //校验token和签名 BaseResult baseResult = requestCheck(true, baseRequest, request); if(0 != baseResult.getRet()){ baseResult.setData(""); baseResult.setSig(buildSign(baseResult)); return baseResult; } Operator operator = baseResult.getOperator(); //解密参数 String decrypt = AESUtil.decrypt(baseRequest.getData(), operator.getDataSecret(), operator.getDataSecretIv()); QueryStartCharge queryStartCharge = JSON.parseObject(decrypt, QueryStartCharge.class); //构建返回结果 QueryStartChargeResult result = new QueryStartChargeResult(); result.setStartChargeSeq(queryStartCharge.getStartChargeSeq()); result.setConnectorID(queryStartCharge.getConnectorID()); String connectorID = queryStartCharge.getConnectorID(); TChargingGun tChargingGun = chargingGunClient.getChargingGunById(Integer.valueOf(connectorID)).getData(); //设备不存在 if(null == tChargingGun){ baseResult.setRet(4004); baseResult.setMsg("connectorID 参数无效"); result.setSuccStat(1); result.setFailReason(1); result.setStartChargeSeqStat(5); //参数加密 String jsonString = JSON.toJSONString(result); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } //设备离线 if(tChargingGun.getStatus() == 1){ result.setSuccStat(1); result.setFailReason(2); result.setStartChargeSeqStat(5); //参数加密 String jsonString = JSON.toJSONString(result); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } //调用充电接口 AddTripartitePlatformOrder addTripartitePlatformOrder = new AddTripartitePlatformOrder(); addTripartitePlatformOrder.setStartChargeSeq(queryStartCharge.getStartChargeSeq()); addTripartitePlatformOrder.setChargingGunId(tChargingGun.getId()); // addTripartitePlatformOrder.setOperatorId(query.get); addTripartitePlatformOrder.setPaymentAmount(queryStartCharge.getPaymentAmount()); addTripartitePlatformOrder.setRechargePaymentType(queryStartCharge.getPaymentType()); R order = chargingOrderClient.addTripartitePlatformOrder(addTripartitePlatformOrder); //启动失败 if(200 != order.getCode()){ result.setSuccStat(1); result.setFailReason(1); result.setStartChargeSeqStat(2); //参数加密 String jsonString = JSON.toJSONString(result); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } result.setStartChargeSeqStat(1); result.setSuccStat(0); result.setFailReason(0); //参数加密 String jsonString = JSON.toJSONString(result); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } /** * 启动充电结果推送 * @param result * @return */ @PostMapping("/notificationStartChargeResult") public R notificationStartChargeResult(@RequestBody StartChargeResult result){ NotificationStartCharge notificationStartCharge = new NotificationStartCharge(); BeanUtils.copyProperties(result, notificationStartCharge); com.ruoyi.integration.drainage.model.NotificationStartChargeResult notificationStartChargeResult = TCECUtil.notificationStartChargeResult(notificationStartCharge); //启动重试推送机制 if(null == notificationStartChargeResult || 1 == notificationStartChargeResult.getSuccStat()){ } return R.ok(); } /** * 查询充电状态 * @return */ @PostMapping("/query_equip_charge_status") public BaseResult queryEquipChargeStatus(@RequestBody BaseRequest baseRequest, HttpServletRequest request){ //校验token和签名 BaseResult baseResult = requestCheck(true, baseRequest, request); if(0 != baseResult.getRet()){ baseResult.setData(""); baseResult.setSig(buildSign(baseResult)); return baseResult; } Operator operator = baseResult.getOperator(); //解密参数 String decrypt = AESUtil.decrypt(baseRequest.getData(), operator.getDataSecret(), operator.getDataSecretIv()); QueryEquipChargeStatus queryEquipChargeStatus = JSON.parseObject(decrypt, QueryEquipChargeStatus.class); //校验token和签名 QueryEquipChargeStatusResult queryEquipChargeStatusResult = buildQueryEquipChargeStatusResult(queryEquipChargeStatus.getStartChargeSeq()); //参数加密 String jsonString = JSON.toJSONString(queryEquipChargeStatusResult); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } /** * 构建充电状态结果 * @param startChargeSeq * @return */ public QueryEquipChargeStatusResult buildQueryEquipChargeStatusResult(String startChargeSeq){ //构建返回结果 QueryEquipChargeStatusResult queryEquipChargeStatusResult = new QueryEquipChargeStatusResult(); queryEquipChargeStatusResult.setStartChargeSeq(startChargeSeq); TChargingOrder chargingOrder = chargingOrderClient.getChargingOrderByStartChargeSeq(startChargeSeq).getData(); if(null == chargingOrder){ return null; } //0=未知,1=等待中/已插枪,2=启动中,3=充电中,4=停止中,5=已结束 switch (chargingOrder.getStatus()){ case 0: queryEquipChargeStatusResult.setStartChargeSeqStat(5); break; case 1: queryEquipChargeStatusResult.setStartChargeSeqStat(0); break; case 2: queryEquipChargeStatusResult.setStartChargeSeqStat(1); break; case 3: queryEquipChargeStatusResult.setStartChargeSeqStat(2); break; case 4: queryEquipChargeStatusResult.setStartChargeSeqStat(3); break; case 5: queryEquipChargeStatusResult.setStartChargeSeqStat(4); break; } queryEquipChargeStatusResult.setConnectorID(chargingOrder.getChargingGunId().toString()); TChargingGun chargingGun = chargingGunClient.getChargingGunById(chargingOrder.getChargingGunId()).getData(); //1=离线,2=空闲,3=占用(未充电),4=占用(充电中),5=占用(已充满),6=占用(预约锁定),7=故障 switch (chargingGun.getStatus()){ case 1: queryEquipChargeStatusResult.setConnectorStatus(0); break; case 2: queryEquipChargeStatusResult.setConnectorStatus(1); break; case 3: queryEquipChargeStatusResult.setConnectorStatus(2); break; case 4: queryEquipChargeStatusResult.setConnectorStatus(3); break; case 5: queryEquipChargeStatusResult.setConnectorStatus(1); break; case 6: queryEquipChargeStatusResult.setConnectorStatus(4); break; case 7: queryEquipChargeStatusResult.setConnectorStatus(255); break; } queryEquipChargeStatusResult.setCurrentA(chargingOrder.getCurrent()); queryEquipChargeStatusResult.setVoltageA(chargingOrder.getVoltage()); queryEquipChargeStatusResult.setSoc(chargingOrder.getTotalElectricity()); queryEquipChargeStatusResult.setStartTime((null == chargingOrder.getStartTime() ? chargingOrder.getCreateTime() : chargingOrder.getStartTime()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); queryEquipChargeStatusResult.setEndTime((null == chargingOrder.getStartTime() ? LocalDateTime.now() : chargingOrder.getEndTime()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); queryEquipChargeStatusResult.setTotalPower(chargingOrder.getElectricity()); queryEquipChargeStatusResult.setElecMoney(chargingOrder.getTotalElectricity()); queryEquipChargeStatusResult.setSeviceMoney(chargingOrder.getServiceCharge()); queryEquipChargeStatusResult.setTotalMoney(chargingOrder.getTotalElectricity().add(chargingOrder.getServiceCharge())); //构建充电明细 List<ChargeDetail> chargeDetails = new ArrayList<>(); List<TChargingOrderAccountingStrategy> data = chargingOrderAccountingStrategyClient.getChargingOrderAccountingStrategyByOrderId(chargingOrder.getId()).getData(); LocalDateTime startTime = chargingOrder.getStartTime(); LocalDateTime endTime = chargingOrder.getEndTime(); String s_format = startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); String e_format = endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); for (TChargingOrderAccountingStrategy datum : data) { ChargeDetail chargeDetail = new ChargeDetail(); if(s_format.equals(e_format)){ chargeDetail.setDetailStartTime(s_format + " " + datum.getStartTime() + ":00"); chargeDetail.setDetailEndTime(s_format + " " + datum.getEndTime() + ":59"); }else{ String substring = datum.getEndTime().substring(0, datum.getEndTime().indexOf(":")); if(Integer.valueOf(substring) > 12){ chargeDetail.setDetailStartTime(s_format + " " + datum.getStartTime() + ":00"); chargeDetail.setDetailEndTime(s_format + " " + datum.getEndTime() + ":59"); }else{ chargeDetail.setDetailStartTime(e_format + " " + datum.getStartTime() + ":00"); chargeDetail.setDetailEndTime(e_format + " " + datum.getEndTime() + ":59"); } } chargeDetail.setElecPrice(datum.getElectrovalence()); chargeDetail.setSevicePrice(datum.getServiceCharge()); chargeDetail.setDetailPower(datum.getChargingCapacity()); chargeDetail.setDetailElecMoney(datum.getPeriodElectricPrice()); chargeDetail.setDetailSeviceMoney(datum.getPeriodServicePrice()); chargeDetails.add(chargeDetail); } queryEquipChargeStatusResult.setChargeDetails(chargeDetails); return queryEquipChargeStatusResult; } /** * 推送充电状态 * @param startChargeSeq * @return */ @PostMapping("/notificationEquipChargeStatus") public R notificationEquipChargeStatus(@RequestParam("startChargeSeq") String startChargeSeq){ QueryEquipChargeStatusResult queryEquipChargeStatusResult = buildQueryEquipChargeStatusResult(startChargeSeq); NotificationEquipChargeStatusResult notificationEquipChargeStatusResult = TCECUtil.notificationEquipChargeStatus(queryEquipChargeStatusResult); //启动重试推送机制 if(null == notificationEquipChargeStatusResult || 1 == notificationEquipChargeStatusResult.getSuccStat()){ } return R.ok(); } /** * 请求停止充电 * @return */ @PostMapping("/query_stop_charge") public BaseResult queryStopCharge(@RequestBody BaseRequest baseRequest, HttpServletRequest request){ //校验token和签名 BaseResult baseResult = requestCheck(true, baseRequest, request); if(0 != baseResult.getRet()){ baseResult.setData(""); baseResult.setSig(buildSign(baseResult)); return baseResult; } Operator operator = baseResult.getOperator(); //解密参数 String decrypt = AESUtil.decrypt(baseRequest.getData(), operator.getDataSecret(), operator.getDataSecretIv()); QueryStopCharge queryStopCharge = JSON.parseObject(decrypt, QueryStopCharge.class); QueryStopChargeResult queryStopChargeResult = new QueryStopChargeResult(); queryStopChargeResult.setStartChargeSeq(queryStopCharge.getStartChargeSeq()); queryStopChargeResult.setStartChargeSeqStat(3); queryStopChargeResult.setSuccStat(0); queryStopChargeResult.setFailReason(0); //执行停机操作 R r = chargingOrderClient.tripartitePlatformStopCharge(queryStopCharge.getStartChargeSeq()); if(200 != r.getCode()){ queryStopChargeResult.setStartChargeSeqStat(5); queryStopChargeResult.setSuccStat(1); queryStopChargeResult.setFailReason(3); //参数加密 String jsonString = JSON.toJSONString(queryStopChargeResult); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } //参数加密 String jsonString = JSON.toJSONString(queryStopChargeResult); String encrypt = AESUtil.encrypt(jsonString, operator.getDataSecret(), operator.getDataSecretIv()); baseResult.setData(encrypt); baseResult.setSig(buildSign(baseResult)); return baseResult; } /** * 推送停止充电结果 * @param startChargeSeq 充电订单号 * @param connectorID 充电设备接口编码 * @return */ @PostMapping("/notificationStopChargeResult") public R notificationStopChargeResult(@RequestParam("startChargeSeq") String startChargeSeq, @RequestParam("connectorID") String connectorID){ NotificationStopChargeResult info = new NotificationStopChargeResult(); info.setStartChargeSeq(startChargeSeq); info.setStartChargeSeqStat(4); info.setConnectorID(connectorID); info.setSuccStat(0); info.setFailReason(0); NotificationStopCharge notificationStopCharge = TCECUtil.notificationStopChargeResult(info); //启动重试推送机制 if(null == notificationStopCharge || 1 == notificationStopCharge.getSuccStat()){ } return R.ok(); } /** * 推送订单信息 * @param startChargeSeq * @return */ @PostMapping("/notificationChargeOrderInfo") public R notificationChargeOrderInfo(@RequestParam("startChargeSeq") String startChargeSeq){ NotificationChargeOrderInfo info = buildNotificationChargeOrderInfo(startChargeSeq); NotificationChargeOrderInfoResult notificationChargeOrderInfoResult = TCECUtil.notificationChargeOrderInfo(info); //启动重试推送机制 if(null == notificationChargeOrderInfoResult || 1 == notificationChargeOrderInfoResult.getConfirmResult()){ } return R.ok(); } /** * 构建推送订单信息 * @param startChargeSeq * @return */ public NotificationChargeOrderInfo buildNotificationChargeOrderInfo(String startChargeSeq){ //构建返回结果 NotificationChargeOrderInfo notificationChargeOrderInfo = new NotificationChargeOrderInfo(); notificationChargeOrderInfo.setStartChargeSeq(startChargeSeq); TChargingOrder chargingOrder = chargingOrderClient.getChargingOrderByStartChargeSeq(startChargeSeq).getData(); if(null == chargingOrder){ return null; } notificationChargeOrderInfo.setConnectorID(chargingOrder.getChargingGunId().toString()); notificationChargeOrderInfo.setStartTime((null == chargingOrder.getStartTime() ? chargingOrder.getCreateTime() : chargingOrder.getStartTime()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); notificationChargeOrderInfo.setEndTime((null == chargingOrder.getStartTime() ? LocalDateTime.now() : chargingOrder.getEndTime()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); notificationChargeOrderInfo.setTotalPower(chargingOrder.getElectricity()); notificationChargeOrderInfo.setTotalElecMoney(chargingOrder.getTotalElectricity()); notificationChargeOrderInfo.setTotalSeviceMoney(chargingOrder.getServiceCharge()); notificationChargeOrderInfo.setTotalMoney(chargingOrder.getTotalElectricity().add(chargingOrder.getServiceCharge())); //结束方式(0=异常终止,1=主动终止,2=满电终止,3=费用不足终止) switch (chargingOrder.getEndMode()){ case 0: notificationChargeOrderInfo.setStopReason(3); break; case 1: notificationChargeOrderInfo.setStopReason(0); break; case 2: notificationChargeOrderInfo.setStopReason(2); break; case 3: notificationChargeOrderInfo.setStopReason(5); break; } //构建充电明细 List<ChargeDetail> chargeDetails = new ArrayList<>(); List<TChargingOrderAccountingStrategy> data = chargingOrderAccountingStrategyClient.getChargingOrderAccountingStrategyByOrderId(chargingOrder.getId()).getData(); LocalDateTime startTime = chargingOrder.getStartTime(); LocalDateTime endTime = chargingOrder.getEndTime(); String s_format = startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); String e_format = endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); for (TChargingOrderAccountingStrategy datum : data) { ChargeDetail chargeDetail = new ChargeDetail(); if(s_format.equals(e_format)){ chargeDetail.setDetailStartTime(s_format + " " + datum.getStartTime() + ":00"); chargeDetail.setDetailEndTime(s_format + " " + datum.getEndTime() + ":59"); }else{ String substring = datum.getEndTime().substring(0, datum.getEndTime().indexOf(":")); if(Integer.valueOf(substring) > 12){ chargeDetail.setDetailStartTime(s_format + " " + datum.getStartTime() + ":00"); chargeDetail.setDetailEndTime(s_format + " " + datum.getEndTime() + ":59"); }else{ chargeDetail.setDetailStartTime(e_format + " " + datum.getStartTime() + ":00"); chargeDetail.setDetailEndTime(e_format + " " + datum.getEndTime() + ":59"); } } chargeDetail.setElecPrice(datum.getElectrovalence()); chargeDetail.setSevicePrice(datum.getServiceCharge()); chargeDetail.setDetailPower(datum.getChargingCapacity()); chargeDetail.setDetailElecMoney(datum.getPeriodElectricPrice()); chargeDetail.setDetailSeviceMoney(datum.getPeriodServicePrice()); chargeDetails.add(chargeDetail); } notificationChargeOrderInfo.setChargeDetails(chargeDetails); return notificationChargeOrderInfo; } } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/TCECUtil.java
@@ -2,8 +2,15 @@ import cn.hutool.http.*; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.ruoyi.integration.drainage.model.*; import lombok.extern.slf4j.Slf4j; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; /** * 中电联TCEC标准 @@ -12,6 +19,63 @@ */ @Slf4j public class TCECUtil { /** * 运营商标识 */ private static final String OperatorID = ""; /** * 运营商秘钥 */ private static final String OperatorSecret = ""; /** * tokne */ private static String token = ""; /** * token过期时间,秒 */ private static Long TokenAvailableTime = 0L; private static Map<Long, Integer> map = new HashMap<>(); /** * 获取token */ public static void queryToken(){ HttpRequest post = HttpUtil.createPost(""); post.contentType("application/json;charset=utf-8"); JSONObject body = new JSONObject(); body.put("OperatorID", OperatorID); body.put("OperatorSecret", OperatorSecret); post.body(body.toJSONString()); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ log.error("获取token失败:" + execute.body()); return; } JSONObject jsonObject = JSON.parseObject(execute.body()); Integer succStat = jsonObject.getInteger("SuccStat"); if(0 != succStat){ log.error("获取token失败:" + jsonObject.getString("FailReason")); return; } token = jsonObject.getString("AccessToken"); TokenAvailableTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) + jsonObject.getLong("TokenAvailableTime"); } /** * 获取token * @return */ public static String getToken(){ long second = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC); if(second >= TokenAvailableTime){ queryToken(); } return token; } @@ -21,8 +85,7 @@ */ public static NotificationStationStatusResult notificationStationStatus(ConnectorStatusInfo info) { HttpRequest post = HttpUtil.createPost(""); post.contentType(ContentType.JSON.toString()); post.body(JSON.toJSONString(info)); buildBody(post, info); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ log.error("设备状态变化推送失败:" + execute.body()); @@ -32,32 +95,32 @@ } /** * 查询统计信息 * @param query * 推送启动充电结果 * @param info * @return */ public QueryStationStatsResult queryStationStats(QueryStationStats query){ } /** * 查询业务策略信息 * @param query * @return */ public BaseResult<QueryEquipBusinessPolicyResult> queryEquipBusinessPolicy(QueryEquipBusinessPolicy query){ public static NotificationStartChargeResult notificationStartChargeResult(NotificationStartCharge info){ HttpRequest post = HttpUtil.createPost(""); buildBody(post, info); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ log.error("启动充电结果推送失败:" + execute.body()); return null; } JSONObject jsonObject = JSON.parseObject(execute.body()); Integer ret = jsonObject.getInteger("Ret"); if(0 != ret){ log.error("启动充电结果推送失败:" + execute.body()); return null; } return jsonObject.getObject("Data", NotificationStartChargeResult.class); } /** * 查询充电状态 * @param query * @return */ public BaseResult<QueryEquipChargeStatusResult> queryEquipChargeStatus(QueryEquipChargeStatus query){ } /** @@ -65,18 +128,101 @@ * @param info * @return */ public BaseResult<NotificationEquipChargeStatusResult> notificationEquipChargeStatus(QueryEquipChargeStatusResult info){ public static NotificationEquipChargeStatusResult notificationEquipChargeStatus(QueryEquipChargeStatusResult info){ HttpRequest post = HttpUtil.createPost(""); buildBody(post, info); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ log.error("推送充电状态失败:" + execute.body()); return null; } JSONObject jsonObject = JSON.parseObject(execute.body()); Integer ret = jsonObject.getInteger("Ret"); if(0 != ret){ log.error("推送充电状态失败:" + execute.body()); return null; } return jsonObject.getObject("Data", NotificationEquipChargeStatusResult.class); } /** * 推送充电订单信息 * @param indo * 推送停止充电结果 * @param info * @return */ public BaseResult<NotificationChargeOrderInfoResult> notificationChargeOrderInfo(NotificationChargeOrderInfo indo){ public static NotificationStopCharge notificationStopChargeResult(NotificationStopChargeResult info){ HttpRequest post = HttpUtil.createPost(""); buildBody(post, info); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ log.error("推送停止充电结果失败:" + execute.body()); return null; } JSONObject jsonObject = JSON.parseObject(execute.body()); Integer ret = jsonObject.getInteger("Ret"); if(0 != ret){ log.error("推送停止充电结果失败:" + execute.body()); return null; } return jsonObject.getObject("Data", NotificationStopCharge.class); } /** * 推送充电订单信息 * @param info * @return */ public static NotificationChargeOrderInfoResult notificationChargeOrderInfo(NotificationChargeOrderInfo info){ HttpRequest post = HttpUtil.createPost(""); buildBody(post, info); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ log.error("推送充电订单信息失败:" + execute.body()); return null; } JSONObject jsonObject = JSON.parseObject(execute.body()); Integer ret = jsonObject.getInteger("Ret"); if(0 != ret){ log.error("推送充电订单信息失败:" + execute.body()); return null; } return jsonObject.getObject("Data", NotificationChargeOrderInfoResult.class); } /** * 构建请求参数和消息头 * @param post * @param o */ public static void buildBody(HttpRequest post, Object o){ Long key = Long.valueOf(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); Integer integer = map.get(key); if(null == integer){ integer = 1; }else{ integer++; } map.put(key, integer); post.contentType("application/json;charset=utf-8"); post.header("Authorization", "Bearer " + getToken()); JSONObject body = new JSONObject(); body.put("OperatorID", OperatorID); body.put("Data", AESUtil.encrypt(JSON.toJSONString(o))); body.put("TimeStamp", key); body.put("Seq", String.format("%04d", integer)); body.put("Sig", ""); post.body(body.toJSONString()); //清空小于当前时间的map中的无效数据 for (Long k : map.keySet()) { if(k <= (key - 10)){ map.remove(k); } } } } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/TokenUtil.java
New file @@ -0,0 +1,165 @@ package com.ruoyi.integration.drainage; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.exception.auth.NotLoginException; import com.ruoyi.common.core.utils.JwtUtils; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.ip.IpUtils; import com.ruoyi.common.core.utils.uuid.IdUtils; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.other.api.domain.Operator; import com.ruoyi.system.api.model.LoginUser; import com.ruoyi.system.api.model.LoginUserApplet; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; /** * token验证处理 * * @author ruoyi */ @Component public class TokenUtil { @Autowired private RedisService redisService; protected static final long MILLIS_SECOND = 1000; protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; private final static long expireTime = CacheConstants.EXPIRATION; private final static long expireAppletTime = CacheConstants.EXPIRATION_APPLET; private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY; private final static Long MILLIS_MINUTE_TEN = CacheConstants.REFRESH_TIME * MILLIS_MINUTE; /** * 创建令牌 */ public Map<String, Object> createToken(Operator operator) { String token = IdUtils.fastUUID(); operator.setToken(token); refreshToken(operator); // Jwt存储信息 Map<String, Object> claimsMap = new HashMap<String, Object>(); claimsMap.put(SecurityConstants.USER_KEY, token); claimsMap.put(SecurityConstants.DETAILS_USER_ID, operator.getOperatorId()); claimsMap.put(SecurityConstants.USER_TYPE, "system"); claimsMap.put(SecurityConstants.DETAILS_USERNAME, operator.getName()); // 接口返回信息 Map<String, Object> rspMap = new HashMap<String, Object>(); rspMap.put("access_token", JwtUtils.createToken(claimsMap)); rspMap.put("expires_in", expireTime); return rspMap; } /** * 获取用户身份信息 * * @return 用户信息 */ public LoginUser getLoginUser() { LoginUser loginUser = getLoginUser(ServletUtils.getRequest()); if (loginUser == null) { throw new NotLoginException("令牌已过期,请重新登录!"); } return loginUser; } /** * 获取用户身份信息 * * @return 用户信息 */ public LoginUser getLoginUser(HttpServletRequest request) { // 获取请求携带的令牌 String token = SecurityUtils.getToken(request); return getLoginUser(token); } /** * 获取用户身份信息 * * @return 用户信息 */ public LoginUser getLoginUser(String token) { LoginUser user = null; try { if (StringUtils.isNotEmpty(token)) { String userkey = JwtUtils.getUserKey(token); user = redisService.getCacheObject(getTokenKey(userkey)); return user; } } catch (Exception e) { } return user; } /** * 设置用户身份信息 */ public void setLoginUser(Operator operator) { if (StringUtils.isNotNull(operator) && StringUtils.isNotEmpty(operator.getToken())) { refreshToken(operator); } } /** * 删除用户缓存信息 */ public void delLoginUser(String token) { if (StringUtils.isNotEmpty(token)) { String userkey = JwtUtils.getUserKey(token); redisService.deleteObject(getTokenKey(userkey)); } } /** * 验证令牌有效期,相差不足120分钟,自动刷新缓存 * * @param operator */ public void verifyToken(Operator operator) { long expireTime = operator.getExpireTime(); long currentTime = System.currentTimeMillis(); if (expireTime - currentTime <= MILLIS_MINUTE_TEN) { refreshToken(operator); } } /** * 刷新令牌有效期 * * @param operator 登录信息 */ public void refreshToken(Operator operator) { operator.setLoginTime(System.currentTimeMillis()); operator.setExpireTime(operator.getLoginTime() + expireTime * MILLIS_MINUTE); // 根据uuid将loginUser缓存 String userKey = getTokenKey(operator.getToken()); redisService.setCacheObject(userKey, operator, expireTime, TimeUnit.MINUTES); } public void refreshToken1(LoginUserApplet dto) { dto.setLoginTime(System.currentTimeMillis()); dto.setExpireTime(dto.getLoginTime() + expireAppletTime * MILLIS_MINUTE); // 根据uuid将loginUser缓存 String userKey = getTokenKey(dto.getToken()); redisService.setCacheObject(userKey, dto, expireAppletTime, TimeUnit.MINUTES); } private String getTokenKey(String token) { return ACCESS_TOKEN + token; } } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/BaseModel.java
New file @@ -0,0 +1,40 @@ package com.ruoyi.integration.drainage.model; import com.ruoyi.other.api.domain.Operator; import lombok.Data; import javax.validation.constraints.NotNull; /** * @author zhibing.pu * @Date 2025/1/23 18:33 */ @Data public class BaseModel { /** * 运营商标识 */ @NotNull private String OperatorID; /** * 参数内容 */ @NotNull private String Data; /** * 时间戳 * yyyyMMddHHmmss */ @NotNull private Long TimeStamp; /** * 自增序列 * 4位自增序列取自时间戳,同一秒内按序列自增长,新秒重计。如 0001 */ @NotNull private String Seq; /** * 运营商对象 */ private Operator operator; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/BaseRequest.java
@@ -10,29 +10,7 @@ * @Date 2025/1/21 17:08 */ @Data public class BaseRequest<T> { /** * 运营商标识 */ @NotNull private String OperatorID; /** * 参数内容 */ @NotNull private T Data; /** * 时间戳 * yyyyMMddHHmmss */ @NotNull private Long TimeStamp; /** * 自增序列 * 4位自增序列取自时间戳,同一秒内按序列自增长,新秒重计。如 0001 */ @NotNull private String Seq; public class BaseRequest extends BaseModel { /** * 数字签名 */ ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/BaseResult.java
@@ -1,5 +1,6 @@ package com.ruoyi.integration.drainage.model; import com.ruoyi.other.api.domain.Operator; import lombok.Data; import javax.validation.constraints.NotNull; @@ -10,7 +11,7 @@ * @Date 2025/1/21 15:54 */ @Data public class BaseResult<T> { public class BaseResult extends BaseModel { /** * 参数编码 * -1:系统繁忙,此时请求方稍后重试 @@ -29,13 +30,13 @@ @NotNull private String Msg; /** * 参数实体 */ @NotNull private T Data; /** * 签名 */ @NotNull private String Sig; /** * 运营商对象 */ private Operator operator; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/NotificationStartCharge.java
New file @@ -0,0 +1,39 @@ package com.ruoyi.integration.drainage.model; import lombok.Data; import javax.validation.constraints.NotNull; /** * 推送启动充电结果 * @author zhibing.pu * @Date 2025/1/22 18:40 */ @Data public class NotificationStartCharge { /** * 充电订单号 */ @NotNull private String StartChargeSeq; /** * 充电订单状态 * 1:启动中 * 2:充电中 * 3:停止中 * 4:已结束 * 5:未知 */ @NotNull private Integer StartChargeSeqStat; /** * 充电设别接口编码 */ @NotNull private String ConnectorID; /** * 充电启动时间 */ @NotNull private String StartTime; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/NotificationStartChargeResult.java
New file @@ -0,0 +1,33 @@ package com.ruoyi.integration.drainage.model; import lombok.Data; import javax.validation.constraints.NotNull; /** * 推送启动充电结果返回值 * @author zhibing.pu * @Date 2025/1/22 18:47 */ @Data public class NotificationStartChargeResult { /** * 充电订单号 */ @NotNull private String StartChargeSeq; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull private Integer SuccStat; /** * 失败原因 * 0:无 * 1:接收失败 */ @NotNull private Integer FailReason; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/NotificationStopChargeResult.java
New file @@ -0,0 +1,51 @@ package com.ruoyi.integration.drainage.model; import lombok.Data; import javax.validation.constraints.NotNull; /** * 推送停止充电结果 * @author zhibing.pu * @Date 2025/1/23 9:13 */ @Data public class NotificationStopChargeResult { /** * 充电订单号 */ @NotNull private String StartChargeSeq; /** * 充电订单状态 * 1:启动中 * 2:充电中 * 3:停止中 * 4:已结束 * 5:未知 */ @NotNull private Integer StartChargeSeqStat; /** * 充电设备接口编码 */ @NotNull private String ConnectorID; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull private Integer SuccStat; /** * 失败原因 * 0:无 * 1:此设备不存在 * 2:此设备离线 * 3:此设备已停止充电 * 4`9:自定义 */ @NotNull private Integer FailReason; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/QueryEquipAuth.java
New file @@ -0,0 +1,24 @@ package com.ruoyi.integration.drainage.model; import lombok.Data; import javax.validation.constraints.NotNull; /** * 请求设备认证 * @author zhibing.pu * @Date 2025/1/22 16:15 */ @Data public class QueryEquipAuth { /** * 设备认证流水 */ @NotNull private String EquipAuthSeq; /** * 充电设备接口编码 */ @NotNull private String ConnectorID; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/QueryEquipAuthResult.java
New file @@ -0,0 +1,40 @@ package com.ruoyi.integration.drainage.model; import lombok.Data; import javax.validation.constraints.NotNull; /** * 请求设备认证返回结果 * @author zhibing.pu * @Date 2025/1/22 16:16 */ @Data public class QueryEquipAuthResult { /** * 设备认证流水号 */ @NotNull private String EquipAuthSeq; /** * 充电设备接口编码 */ @NotNull private String ConnectorID; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull private Integer SuccStat; /** * 失败原因 * 0:无 * 1:此设备尚未插枪 * 2:设备检测失败 * 3·99:自定义 */ @NotNull private Integer FailReason; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/QueryStartCharge.java
New file @@ -0,0 +1,40 @@ package com.ruoyi.integration.drainage.model; import lombok.Data; import javax.validation.constraints.NotNull; import java.math.BigDecimal; /** * 请求启动充电 * @author zhibing.pu * @Date 2025/1/22 16:59 */ @Data public class QueryStartCharge { /** * 充电订单号 */ @NotNull private String StartChargeSeq; /** * 充电设备接口编码 */ @NotNull private String ConnectorID; /** * 二维码其他信息 */ @NotNull private String QRCode; /** * 支付方式(1=微信,2=支付宝) */ @NotNull private Integer paymentType; /** * 充电余额 */ @NotNull private BigDecimal paymentAmount; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/QueryStartChargeResult.java
New file @@ -0,0 +1,50 @@ package com.ruoyi.integration.drainage.model; import lombok.Data; import javax.validation.constraints.NotNull; /** * 请求启动充电返回结果 * @author zhibing.pu * @Date 2025/1/22 17:02 */ @Data public class QueryStartChargeResult { /** * 充电订单号 */ @NotNull private String StartChargeSeq; /** * 充电订单状态 * 1:启动中 * 2:充电中 * 3:停止中 * 4:已结束 * 5:未知 */ @NotNull private Integer StartChargeSeqStat; /** * 充电设别接口编码 */ @NotNull private String ConnectorID; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull private Integer SuccStat; /** * 失败原因 * 0:无 * 1:此设备不存在 * 2:此设备离线 * 3`9:自定义 */ @NotNull private Integer FailReason; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/QueryStationStats.java
@@ -12,6 +12,11 @@ @Data public class QueryStationStats { /** * 运营商ID */ @NotNull private String OperatorID; /** * 充电站ID */ @NotNull ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/QueryStopChargeResult.java
New file @@ -0,0 +1,47 @@ package com.ruoyi.integration.drainage.model; import lombok.Data; import javax.validation.constraints.NotNull; /** * 请求停止充电返回结果 * @author zhibing.pu * @Date 2025/1/22 19:58 */ @Data public class QueryStopChargeResult { /** * 充电订单号 */ @NotNull private String StartChargeSeq; /** * 充电订单状态 * 1:启动中 * 2:充电中 * 3:停止中 * 4:已结束 * 5:未知 */ @NotNull private Integer StartChargeSeqStat; /** * 操作结果 * 0:成功 * 1:失败 */ @NotNull private Integer SuccStat; /** * 失败原因 * 0:无 * 1:此设备不存在 * 2:此设备离线 * 3:此设备已停止充电 * 4`9:自定义 */ @NotNull private Integer FailReason; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/QueryToken.java
New file @@ -0,0 +1,24 @@ package com.ruoyi.integration.drainage.model; import lombok.Data; import javax.validation.constraints.NotNull; /** * 获取token * @author zhibing.pu * @Date 2025/1/23 17:13 */ @Data public class QueryToken { /** * 运营商标识 */ @NotNull private String OperatorID; /** * 运营商秘钥 */ @NotNull private String OperatorSecret; } ruoyi-service/ruoyi-integration/src/main/java/com/ruoyi/integration/drainage/model/QueryTokenResult.java
New file @@ -0,0 +1,45 @@ package com.ruoyi.integration.drainage.model; import lombok.Data; import javax.validation.constraints.NotNull; /** * 获取token返回结果 * @author zhibing.pu * @Date 2025/1/23 17:15 */ @Data public class QueryTokenResult { /** * 运营商标识 */ @NotNull private String OperatorID; /** * 成功状态 * 0:成功 * 1:失败 */ @NotNull private Integer SuccStat; /** * 获取的凭证 */ @NotNull private String AccessToken; /** * 凭证有效期,秒 */ @NotNull private Long TokenAvailableTime; /** * 失败原因 * 0:无 * 1:无此运营商 * 2:秘钥错误 * 3`9自定义 */ @NotNull private Integer FailReason; } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderAccountingStrategyController.java
@@ -1,7 +1,9 @@ package com.ruoyi.order.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.core.domain.R; import com.ruoyi.order.api.model.TChargingOrderAccountingStrategy; import com.ruoyi.order.service.TChargingOrderAccountingStrategyService; import io.swagger.annotations.Api; import org.springframework.web.bind.annotation.*; @@ -52,5 +54,18 @@ List<Double> list = chargingOrderAccountingStrategyService.getDailyChargingDegree(days, siteIds); return R.ok(list); } /** * 根据订单id查询充电明细 * @param chargingOrderId * @return */ @PostMapping("/getChargingOrderAccountingStrategyByOrderId") public R<List<TChargingOrderAccountingStrategy>> getChargingOrderAccountingStrategyByOrderId(@RequestParam("chargingOrderId") Long chargingOrderId){ List<TChargingOrderAccountingStrategy> list = chargingOrderAccountingStrategyService.list(new LambdaQueryWrapper<TChargingOrderAccountingStrategy>().eq(TChargingOrderAccountingStrategy::getChargingOrderId, chargingOrderId)); return R.ok(list); } } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java
@@ -20,6 +20,7 @@ import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.dto.ChargingOrderGroup; import com.ruoyi.common.core.dto.ChargingPercentProvinceDto; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.web.domain.BasePojo; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.common.security.annotation.Logical; @@ -605,6 +606,27 @@ List<ChargingOrderGroup> groups = chargingOrderService.chargingOrderGroup(chargingPercentProvinceDto); return R.ok(groups); } /** * 根据站点id和时间区间查询订单数据 * @param chargingPercentProvinceDto * @return */ @PostMapping(value = "/getOrderBySiteIdAndTime") public R<List<TChargingOrder>> getOrderBySiteIdAndTime(@RequestBody ChargingPercentProvinceDto chargingPercentProvinceDto){ LocalDate date1 = chargingPercentProvinceDto.getDate1(); LocalDate date2 = chargingPercentProvinceDto.getDate2(); String tripartitePlatformName = chargingPercentProvinceDto.getTripartitePlatformName(); List<TChargingOrder> list = chargingOrderService.list(new LambdaQueryWrapper<TChargingOrder>().in(TChargingOrder::getSiteId, chargingPercentProvinceDto.getSiteIds()) .between(null != date1 && null != date2, TChargingOrder::getPayTime, date1.atTime(0, 0, 0), date2.atTime(23, 59, 59)) .eq(TChargingOrder::getDelFlag, 0).eq(TChargingOrder::getStatus, 5) .eq(StringUtils.isNotEmpty(tripartitePlatformName), TChargingOrder::getOrderSource, 2) .eq(StringUtils.isNotEmpty(tripartitePlatformName), TChargingOrder::getTripartitePlatformName, tripartitePlatformName)); return R.ok(list); } /** * 根据充电枪id获取正在进行中的订单 @@ -1988,51 +2010,7 @@ List<Integer> gunIds = list.stream().map(TChargingOrder::getChargingGunId).collect(Collectors.toList()); return R.ok(gunIds); } private static List<TChargingOrder> getSampleData() { // 这里可以替换为实际查询逻辑 List<TChargingOrder> list = new ArrayList<>(); // 示例数据 for (int i = 0; i < 24; i++) { TChargingOrder order = new TChargingOrder(); order.setStartTime(LocalDateTime.now().minusHours(23 - i)); order.setOrderAmount(BigDecimal.valueOf(i + 1)); list.add(order); } return list; } private static List<Map<String, BigDecimal>> processData(List<TChargingOrder> list) { Map<LocalDateTime, BigDecimal> hourlySum = new HashMap<>(); // 按每个小时分组并求和 for (TChargingOrder order : list) { LocalDateTime hour = order.getStartTime().truncatedTo(ChronoUnit.HOURS); BigDecimal amount = order.getOrderAmount(); hourlySum.merge(hour, amount, BigDecimal::add); } // 创建结果列表 List<Map<String, BigDecimal>> resultList = new ArrayList<>(); for (int i = 1; i <= 23; i++) { LocalDateTime keyHour = LocalDateTime.now().withHour(i); BigDecimal sum = BigDecimal.ZERO; // 计算键之后的一小时的数据之和 for (int j = i + 1; j <= 23; j++) { LocalDateTime nextHour = LocalDateTime.now().withHour(j); sum = sum.add(hourlySum.getOrDefault(nextHour, BigDecimal.ZERO)); } Map<String, BigDecimal> entry = new HashMap<>(); entry.put(String.valueOf(i), sum); resultList.add(entry); } return resultList; } /** @@ -2116,4 +2094,42 @@ return R.ok(list); } /** * 添加三方平台充电订单数据 * @return */ @PostMapping("/addTripartitePlatformOrder") public R addTripartitePlatformOrder(@RequestBody AddTripartitePlatformOrder query){ return chargingOrderService.addTripartitePlatformOrder(query.getChargingGunId(), query.getOperatorId(), query.getRechargePaymentType(), query.getPaymentAmount(), query.getStartChargeSeq()); } /** * 根据三方平台订单id获取充电数据 * @param startChargeSeq * @return */ @PostMapping("/getChargingOrderByStartChargeSeq") public R<TChargingOrder> getChargingOrderByStartChargeSeq(@RequestParam("startChargeSeq") String startChargeSeq){ TChargingOrder chargingOrder = chargingOrderService.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getStartChargeSeq, startChargeSeq)); return R.ok(chargingOrder); } /** * 三方平台请求停止充电 * @param startChargeSeq * @return */ @PostMapping("/tripartitePlatformStopCharge") public R tripartitePlatformStopCharge(@RequestParam("startChargeSeq") String startChargeSeq){ return chargingOrderService.tripartitePlatformStopCharge(startChargeSeq); } } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TChargingOrderService.java
@@ -19,7 +19,9 @@ import com.ruoyi.order.vo.ChargingOrderListInfoVO; import com.ruoyi.order.vo.EndOfChargePageInfo; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import java.math.BigDecimal; import java.time.LocalDate; import java.util.List; import java.util.Map; @@ -286,4 +288,19 @@ List<TChargingOrder> getChargingOrder(TChargingOrderVo order); Long countCar(List<String> brands); /** * 添加三方平台充电订单数据 * @param chargingGunId */ R addTripartitePlatformOrder(Integer chargingGunId, String operatorId, Integer rechargePaymentType, BigDecimal paymentAmount, String startChargeSeq); /** * 三方平台停止充电操作 * @param startChargeSeq * @return */ R tripartitePlatformStopCharge(@RequestParam("startChargeSeq") String startChargeSeq); } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -202,6 +202,9 @@ //计数器 private Map<String, Integer> boot_failed_map = new HashMap<>(); @Resource private OperatorClient operatorClient; @@ -465,7 +468,7 @@ chargingOrder.setRechargeAmount(addChargingOrder.getPaymentAmount()); chargingOrder.setAppCouponId(addChargingOrder.getAppUserCouponId()); chargingOrder.setVipDiscountAmount(BigDecimal.ZERO); chargingOrder.setOrderSource(0); chargingOrder.setOrderSource(1); chargingOrder.setTitle("【充电桩充电】" + chargingPile.getNumber() + "号桩/" + tChargingGun.getCode() + "号枪"); Site site = siteClient.getSiteByIds(Arrays.asList(tChargingGun.getSiteId())).getData().get(0); @@ -845,7 +848,7 @@ public void refund(String code){ log.info(code + ":-------------------充电启动失败,执行退款-------------------"); TChargingOrder chargingOrder = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getCode, code)); if(chargingOrder.getStatus() == 2){ if(chargingOrder.getOrderSource() == 1 && chargingOrder.getStatus() == 2){ Integer rechargePaymentType = chargingOrder.getRechargePaymentType(); BigDecimal rechargeAmount = chargingOrder.getRechargeAmount(); //构建退款明细 @@ -3974,4 +3977,144 @@ public Long countCar(List<String> brands) { return this.baseMapper.countCar(brands); } /** * 添加三方平台充电订单数据 * @param chargingGunId */ @Override public R addTripartitePlatformOrder(Integer chargingGunId, String operatorId, Integer rechargePaymentType, BigDecimal paymentAmount, String startChargeSeq) { //检查当前枪是否是正在使用中 TChargingOrder one = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getChargingGunId, chargingGunId) .in(TChargingOrder::getStatus, Arrays.asList(1, 2, 3)).eq(TChargingOrder::getDelFlag, 0)); if(null != one){ return R.fail("充电枪正在充电中,启动失败"); } //构建新的待支付订单 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); TChargingOrder chargingOrder = new TChargingOrder(); String code = "CD" + Double.valueOf(Math.random() * 1000).intValue() + sdf.format(new Date()); chargingOrder.setCode(code); chargingOrder.setOrderType(1); chargingOrder.setOrderClassification(1); TChargingGun tChargingGun = chargingGunClient.getChargingGunById(chargingGunId).getData(); TChargingPile chargingPile = chargingPileClient.getChargingPileById(tChargingGun.getChargingPileId()).getData(); chargingOrder.setSiteId(tChargingGun.getSiteId()); chargingOrder.setChargingPileId(tChargingGun.getChargingPileId()); chargingOrder.setChargingGunId(chargingGunId); chargingOrder.setRechargePaymentType(rechargePaymentType); chargingOrder.setRechargePaymentStatus(2); chargingOrder.setRechargeAmount(paymentAmount); chargingOrder.setVipDiscountAmount(BigDecimal.ZERO); chargingOrder.setOrderSource(2); Operator operator = operatorClient.getOperator(operatorId).getData(); chargingOrder.setOperatorId(operator.getId()); chargingOrder.setAppUserId(operator.getId().longValue()); chargingOrder.setTripartitePlatformName(operator.getName()); chargingOrder.setStartChargeSeq(startChargeSeq); chargingOrder.setTitle("【充电桩充电】" + chargingPile.getNumber() + "号桩/" + tChargingGun.getCode() + "号枪"); chargingOrder.setStatus(2); chargingOrder.setPayTime(LocalDateTime.now()); chargingOrder.setChargeAmount(chargingOrder.getRechargeAmount()); chargingOrder.setVipDiscountAmount(BigDecimal.ZERO); this.save(chargingOrder); Integer accountingStrategyId = tChargingGun.getAccountingStrategyId(); if(null == accountingStrategyId){ Site site = siteClient.getSiteByIds(Arrays.asList(tChargingGun.getSiteId())).getData().get(0); //查询站点上面的计费策略 accountingStrategyId = site.getAccountingStrategyId(); } TAccountingStrategy accountingStrategy = accountingStrategyClient.getAccountingStrategyById(accountingStrategyId).getData(); //添加订单的计费策略 List<TAccountingStrategyDetail> strategyDetailList = accountingStrategyDetailClient.getListByAccountingStrategyId(accountingStrategyId).getData(); AccountingStrategyOrder accountingStrategyOrder = new AccountingStrategyOrder(); BeanUtils.copyProperties(accountingStrategy, accountingStrategyOrder); accountingStrategyOrder.setChargingOrderId(chargingOrder.getId()); accountingStrategyOrderService.save(accountingStrategyOrder); List<AccountingStrategyDetailOrder> list1 = new ArrayList<>(); for (TAccountingStrategyDetail tAccountingStrategyDetail : strategyDetailList) { AccountingStrategyDetailOrder accountingStrategyDetailOrder = new AccountingStrategyDetailOrder(); BeanUtils.copyProperties(tAccountingStrategyDetail, accountingStrategyDetailOrder); accountingStrategyDetailOrder.setChargingOrderId(chargingOrder.getId()); list1.add(accountingStrategyDetailOrder); } accountingStrategyDetailOrderService.saveBatch(list1); //添加安全检测数据到缓存中,每步安全检测完成后需要更新缓存数据 PreChargeCheck preChargeCheck = new PreChargeCheck(); preChargeCheck.setElectronicLockLock(false); preChargeCheck.setInsulationTesting(false); preChargeCheck.setSecureConnectionDetection(false); preChargeCheck.setStartupSuccess(1); String key = "AQJC_" + chargingOrder.getChargingGunId(); redisService.setCacheObject(key, preChargeCheck, 24L, TimeUnit.HOURS); BigDecimal rechargeAmount = chargingOrder.getRechargeAmount(); //调用远程启动充电消息 PlatformStartCharging platformStartCharging = new PlatformStartCharging(); platformStartCharging.setTransaction_serial_number(chargingOrder.getCode()); platformStartCharging.setCharging_pile_code(chargingPile.getCode()); platformStartCharging.setCharging_gun_code(tChargingGun.getCode()); //使用订单id作为逻辑卡号 platformStartCharging.setCard_number(chargingOrder.getId().toString()); platformStartCharging.setAccount_balance(rechargeAmount); log.info(chargingOrder.getCode() + ":-------------------远程调起开始充电请求-------------------" + platformStartCharging.toString()); sendMessageClient.platformStartCharging(platformStartCharging); //异步线程检测远程启动的应答结果。如果失败,则需要全额退款 Long id = chargingOrder.getId(); //执行5分钟的定时任务检测 ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); scheduler.scheduleAtFixedRate(()->{ if(timingDetection(id)){ scheduler.shutdown(); } }, 5, 1, TimeUnit.SECONDS); return R.ok(); } /** * 三方平台停止充电操作 * @param startChargeSeq * @return */ @Override public R tripartitePlatformStopCharge(String startChargeSeq) { TChargingOrder order = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getStartChargeSeq, startChargeSeq)); Integer status = order.getStatus(); if(status != 3){ return R.fail("还未开始充电"); } if(status == 4 || status == 5){ return R.fail("不能重复操作"); } TChargingOrder chargingOrder = new TChargingOrder(); chargingOrder.setId(order.getId()); chargingOrder.setAppUserId(order.getOperatorId().longValue()); chargingOrder.setEndTime(LocalDateTime.now()); chargingOrder.setStatus(4); chargingOrder.setEndMode(1); this.updateById(chargingOrder); String code1 = order.getCode(); TChargingGun chargingGun = chargingGunClient.getChargingGunById(order.getChargingGunId()).getData(); //异步线程处理停机 ExecutorService cachedThreadPool = Executors.newFixedThreadPool(1); cachedThreadPool.execute(()->{ //调用硬件停止充电,停止成功后开始计算费用退款 TChargingPile chargingPile = chargingPileClient.getChargingPileById(order.getChargingPileId()).getData(); PlatformStopCharging platformStopCharging = new PlatformStopCharging(); platformStopCharging.setCharging_pile_code(chargingPile.getCode()); platformStopCharging.setCharging_gun_code(chargingGun.getCode()); sendMessageClient.platformStopCharging(platformStopCharging); log.info(code1 + ":-------------------远程停止充电请求-------------------"); log.info(platformStopCharging.toString()); }); return R.ok(); } } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/OperatorController.java
New file @@ -0,0 +1,36 @@ package com.ruoyi.other.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.core.domain.R; import com.ruoyi.other.api.domain.Operator; import com.ruoyi.other.service.OperatorService; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @author zhibing.pu * @Date 2025/1/22 15:12 */ @RestController @RequestMapping("/operator") public class OperatorController { @Resource private OperatorService operatorService; /** * 获取运营商数据 * @param operatorId * @return */ @PostMapping("/getOperator") public R<Operator> getOperator(@RequestParam("operatorId") String operatorId){ Operator operator = operatorService.getOne(new LambdaQueryWrapper<Operator>().eq(Operator::getOperatorId, operatorId)); return R.ok(operator); } } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/mapper/OperatorMapper.java
New file @@ -0,0 +1,11 @@ package com.ruoyi.other.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.other.api.domain.Operator; /** * @author zhibing.pu * @Date 2025/1/22 15:08 */ public interface OperatorMapper extends BaseMapper<Operator> { } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/OperatorService.java
New file @@ -0,0 +1,11 @@ package com.ruoyi.other.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.other.api.domain.Operator; /** * @author zhibing.pu * @Date 2025/1/22 15:09 */ public interface OperatorService extends IService<Operator> { } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/OperatorServiceImpl.java
New file @@ -0,0 +1,15 @@ package com.ruoyi.other.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.other.api.domain.Operator; import com.ruoyi.other.mapper.OperatorMapper; import com.ruoyi.other.service.OperatorService; import org.springframework.stereotype.Service; /** * @author zhibing.pu * @Date 2025/1/22 15:09 */ @Service public class OperatorServiceImpl extends ServiceImpl<OperatorMapper, Operator> implements OperatorService { }