1. 远端设备在线离线调整

This commit is contained in:
andy 2026-03-17 10:31:59 +08:00
parent d26e02f364
commit c8ed787bf6
18 changed files with 400 additions and 10 deletions

View File

@ -57,6 +57,14 @@ public class Result<T> implements Serializable {
return this;
}
public Result<T> success(T o, String msg) {
this.status = 1;
this.code = CodeMsg.SUCCESS.getCode();
this.msg = msg;
this.data = o;
return this;
}
public Result<T> error(String errMsg) {
this.status = 1;
this.code = CodeMsg.ERROR.getCode();

View File

@ -27,7 +27,7 @@ public class BatteryStationDcc extends BaseEntity implements Serializable {
@NotBlank(message = "换电站编码不能为空")
private String stationCode;
@Schema(description = "换电站编码")
@Schema(description = "换电站名称")
private String stationName;
@Schema(description = "电池仓序号", requiredMode = RequiredMode.REQUIRED)

View File

@ -0,0 +1,74 @@
package com.evotech.hd.cloud.controller.mqtt;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.evotech.hd.cloud.entity.MqttClientLineInfo;
import com.evotech.hd.cloud.entity.request.PageListMessageMqttRequest;
import com.evotech.hd.cloud.entity.request.PageMqttClientRequest;
import com.evotech.hd.cloud.service.BatteryStationService;
import com.evotech.hd.cloud.service.MqttClientLineInfoService;
import com.evotech.hd.common.core.Dto.Result;
import com.evotech.hd.common.core.entity.cloud.BatteryStation;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.Map;
/**
* MqttClientController
*
* @author andy.shi
* @ClassName:MqttClientController
* @date: 2026年03月16日 13:25
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Tag(name = "mqtt换电客户端信息")
@Slf4j
@RestController
@RequestMapping("/mqtt/client")
public class MqttClientController {
@Autowired
private BatteryStationService batteryStationService;
@Autowired
private MqttClientLineInfoService mqttClientLineInfoService;
@Operation(summary = "查询")
@GetMapping("/list")
@ApiOperationSupport(order = 1)
public Result<Page<MqttClientLineInfo>> list(@ParameterObject PageMqttClientRequest plmmr) {
return mqttClientLineInfoService.pageList(plmmr);
}
@PostMapping("/callback/info")
public void dingDingClock(@RequestBody Map<String, Object> params){
log.info("mqtt-client 站端情况: {}", JSON.toJSONString(params));
Object object = params.get("clientid");
if(ObjectUtils.isEmpty(object)){
log.info("未找到数据信息, 相关数据为"+ JSON.toJSONString(params));
return;
}
BatteryStation batteryStation = batteryStationService.getBatteryStationByCode(object.toString());
if(batteryStation == null){
log.info("未找到相关站信息, 相关数据为"+ JSON.toJSONString(params));
return;
}
MqttClientLineInfo mqttClientLineInfo = new MqttClientLineInfo();
mqttClientLineInfo.setStationCode(batteryStation.getCode());
mqttClientLineInfo.setStationName(batteryStation.getName());
mqttClientLineInfo.setStationCode(batteryStation.getCode());
mqttClientLineInfo.setState(params.get("event").equals("client.connected") ? "在线" : "离线");
mqttClientLineInfo.setHttpContent(JSON.toJSONString(params));
mqttClientLineInfo.setLineTime(new Date(Long.valueOf(params.get("timestamp").toString())));
mqttClientLineInfo.setCtime(new Date());
mqttClientLineInfoService.save(mqttClientLineInfo);
}
}

View File

@ -0,0 +1,15 @@
package com.evotech.hd.cloud.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.evotech.hd.cloud.entity.MqttClientLineInfo;
/**
* MqttClientLineInfoMapper
*
* @author andy.shi
* @ClassName:MqttClientLineInfoMapper
* @date: 2026年03月16日 16:13
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
public interface MqttClientLineInfoMapper extends BaseMapper<MqttClientLineInfo> {
}

View File

@ -0,0 +1,51 @@
package com.evotech.hd.cloud.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
/**
* MqttClientLineInfo
*
* @author andy.shi
* @ClassName:MqttClientLineInfo
* @date: 2026年03月16日 16:02
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Getter
@Setter
@TableName("yt_t_mqtt_client_line")
@Schema(name = "mqtt客户端在线信息记录")
public class MqttClientLineInfo implements Serializable {
@TableId(value = "pk_id", type = IdType.AUTO)
private Integer pkId;
@Schema(description = "换电站")
private String stationCode;
@Schema(description = "换电站名称")
private String stationName;
@Schema(description = "状态")
private String state;
@Schema(description = "http消息")
private String httpContent;
@Schema(description = "变化时间")
private Date lineTime;
@Schema(description = "创建时间", hidden = true)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date ctime;
}

View File

@ -0,0 +1,16 @@
package com.evotech.hd.cloud.entity.request;
import com.evotech.hd.common.core.entity.BasePageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@Schema(name = "查询MQTT消息请求参数", hidden = true)
@EqualsAndHashCode(callSuper = false)
public class PageMqttClientRequest extends BasePageRequest {
@Schema(description = "换电站")
private String stationCode;
}

View File

@ -16,6 +16,8 @@ public enum StateFunctionTypesEnum {
FUN_BAT_DATA("batData", "", "电池实时信息"),
FUN_STATION_STATE("stationState", "", "站级状态信息"),
FUN_CHARGING_STRATEGY("chargingStrategy", "", "充电策略信息"),
FUN_BATTERY_COMPARTMENT_STATE("batteryCompartment", "", "电池仓推送信息"),
FUN_BATTERY_STATE("battery", "", "电池推送信息"),
;

View File

@ -14,9 +14,12 @@ import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.evotech.hd.cloud.dao.BatteryStationDao;
import com.evotech.hd.cloud.dao.BatteryStationSecretKeyDao;
import com.evotech.hd.cloud.entity.BatteryStationSecretKey;
import com.evotech.hd.cloud.entity.MessageMqtt;
@ -28,6 +31,8 @@ import com.evotech.hd.cloud.mqtt.message.MyMqttMessage;
import com.evotech.hd.cloud.mqtt.message.dto.newer.req.MqttResponse;
import com.evotech.hd.cloud.service.MessageMqttService;
import com.evotech.hd.common.core.constant.HDConstant;
import com.evotech.hd.common.core.entity.cloud.BatteryStation;
import com.evotech.hd.common.core.utils.DataUtils;
import com.evotech.hd.common.redis.utils.RedisUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@ -49,6 +54,8 @@ public class MessageUtilService {
@Resource
private BatteryStationSecretKeyDao batteryStationSecretKeyDao;
@Resource
private BatteryStationDao batteryStationDao;
@Resource
private MqttPublishMessage publishMessage;
@ -252,6 +259,13 @@ public class MessageUtilService {
// jo.set("aesIv", iv);
jo.set("encryptKey", base64KeyStr);
jo.set("encryptVector", iv);
//此处新增加换电站电池数量, 用于初始化电池仓
try {
BatteryStation batteryStation = batteryStationDao.selectOne(new LambdaQueryWrapper<BatteryStation>().eq(BatteryStation::getCode, stationCode));
jo.set("dccNum", DataUtils.findDefaultValue(batteryStation.getDccQuantity(), 0));
} catch (JSONException e) {
log.error("回传电池仓数量出现错误"+e.getMessage());
}
return jo;
}

View File

@ -0,0 +1,49 @@
package com.evotech.hd.cloud.mqtt.message.processor.strategy.impl.state;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.evotech.hd.cloud.mqtt.enums.StateFunctionTypesEnum;
import com.evotech.hd.cloud.mqtt.message.MessageTopic;
import com.evotech.hd.cloud.mqtt.message.MqttMessageHeader;
import com.evotech.hd.cloud.service.BatteryStationDccService;
import com.evotech.hd.cloud.service.BatteryStationService;
import com.evotech.hd.common.core.entity.cloud.BatteryStationDcc;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 换电站状态类
*
* @ClassName:MqttStateStationStateExchangeProcessor
* @date: 2025年05月05日 13:23
* @author: andy.shi
* @contact: 17330188597
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Slf4j
@Service
public class MqttStateBatteryCompartmentExchangeProcessor implements MqttStrategyStateExchangeProcessor {
@Resource
BatteryStationService batteryStationService;
@Resource
BatteryStationDccService batteryStationDccService;
@Override
public boolean accept(String functionName) {
return StateFunctionTypesEnum.FUN_BATTERY_COMPARTMENT_STATE.getFunction().equals(functionName);
}
@Override
public void exchange(MessageTopic topic, MqttMessageHeader header, JSONObject dataBody) {
//记录站级状态信息
log.info("MqttStateBatteryCompartmentExchangeProcessor-->>>>> 请求参数{}", JSONUtil.toJsonStr(dataBody));
//初始化电池仓信息
try {
BatteryStationDcc batteryStationDcc = JSONUtil.toBean(dataBody.toString(), BatteryStationDcc.class);
batteryStationDcc.setStationName(batteryStationService.getBatteryStationByCode(topic.getStationCode()).getName());
batteryStationDccService.add(batteryStationDcc);
} catch (Exception e) {
log.error("初始化电池仓出现异常"+e.getMessage());
}
}
}

View File

@ -0,0 +1,49 @@
package com.evotech.hd.cloud.mqtt.message.processor.strategy.impl.state;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.evotech.hd.cloud.mqtt.enums.StateFunctionTypesEnum;
import com.evotech.hd.cloud.mqtt.message.MessageTopic;
import com.evotech.hd.cloud.mqtt.message.MqttMessageHeader;
import com.evotech.hd.cloud.service.BatteryStationDcService;
import com.evotech.hd.cloud.service.BatteryStationService;
import com.evotech.hd.common.core.entity.cloud.BatteryStationDc;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 换电站状态类
*
* @ClassName:MqttStateStationStateExchangeProcessor
* @date: 2025年05月05日 13:23
* @author: andy.shi
* @contact: 17330188597
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Slf4j
@Service
public class MqttStateBatteryExchangeProcessor implements MqttStrategyStateExchangeProcessor {
@Resource
BatteryStationService batteryStationService;
@Resource
BatteryStationDcService batteryStationDcService;
@Override
public boolean accept(String functionName) {
return StateFunctionTypesEnum.FUN_BATTERY_STATE.getFunction().equals(functionName);
}
@Override
public void exchange(MessageTopic topic, MqttMessageHeader header, JSONObject dataBody) {
//记录电池状态信息
log.info("MqttStateBatteryExchangeProcessor-->>>>> 请求参数{}", JSONUtil.toJsonStr(dataBody));
//初始化电池仓信息
try {
BatteryStationDc batteryStationDc = JSONUtil.toBean(dataBody.toString(), BatteryStationDc.class);
batteryStationDc.setPointName(batteryStationService.getBatteryStationByCode(topic.getStationCode()).getName());
batteryStationDcService.add(batteryStationDc);
} catch (Exception e) {
log.error("初始化电池仓出现异常"+e.getMessage());
}
}
}

View File

@ -1,6 +1,7 @@
package com.evotech.hd.cloud.service;
import com.evotech.hd.common.core.Dto.Result;
import com.evotech.hd.common.core.entity.cloud.BatteryStation;
import com.evotech.hd.common.core.entity.cloud.BatteryStationHdFeeStandard;
import java.util.List;
@ -15,4 +16,5 @@ public interface BatteryStationHdFeeStandardService {
public Result<List<BatteryStationHdFeeStandard>> list(String stationCode);
public Result<Integer> buildByStation(BatteryStation batteryStation);
}

View File

@ -31,7 +31,7 @@ public interface BatteryStationService {
public void downloadQRCode2(String path, String width, HttpServletResponse response);
public BatteryStation getBatteryStationByCode(String code);

View File

@ -0,0 +1,22 @@
package com.evotech.hd.cloud.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.evotech.hd.cloud.entity.MqttClientLineInfo;
import com.evotech.hd.cloud.entity.request.PageMqttClientRequest;
import com.evotech.hd.common.core.Dto.Result;
import org.springdoc.core.annotations.ParameterObject;
/**
* MqttClientLineInfoService
*
* @author andy.shi
* @ClassName:MqttClientLineInfoService
* @date: 2026年03月16日 16:11
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
public interface MqttClientLineInfoService extends IService<MqttClientLineInfo> {
Result<Page<MqttClientLineInfo>> pageList(@ParameterObject PageMqttClientRequest plmmr);
}

View File

@ -1,5 +1,6 @@
package com.evotech.hd.cloud.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -14,6 +15,7 @@ import com.evotech.hd.common.core.enums.CodeMsg;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.Date;
@ -31,6 +33,9 @@ public class BatteryStationDcServiceImpl extends ServiceImpl<BatteryStationDcDao
@Override
@Transactional
public Result<Integer> add(BatteryStationDc bsdc) {
if(!checkExists(bsdc.getBatCode())){
return new Result<Integer>().success(1,"电池编号已存在!");
}
Date d = new Date();
bsdc.setCtime(d);
int n = batteryStationDcDao.insert(bsdc);
@ -48,6 +53,10 @@ public class BatteryStationDcServiceImpl extends ServiceImpl<BatteryStationDcDao
return new Result<Integer>().error("添加电池出错!");
}
public Boolean checkExists(String batCode){
return ObjectUtils.isEmpty(new LambdaQueryWrapper<BatteryStationDc>().eq(BatteryStationDc::getBatCode, batCode));
}
@Override
public Result<Integer> delete(Integer id) {
BatteryStationDc bsdc = new BatteryStationDc();

View File

@ -1,26 +1,34 @@
package com.evotech.hd.cloud.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.evotech.hd.cloud.dao.BatteryStationHdFeeStandardDao;
import com.evotech.hd.cloud.dao.BatteryStationHdFeeStandardDetailDao;
import com.evotech.hd.cloud.service.BatteryStationHdFeeStandardService;
import com.evotech.hd.cloud.service.rpc.ResourceService;
import com.evotech.hd.common.core.Dto.Result;
import com.evotech.hd.common.core.Dto.ResultUtil;
import com.evotech.hd.common.core.entity.cloud.BatteryStation;
import com.evotech.hd.common.core.entity.cloud.BatteryStationHdFeeStandard;
import com.evotech.hd.common.core.entity.cloud.BatteryStationHdFeeStandardDetail;
import com.evotech.hd.common.core.entity.resource.dict.Dict;
import com.evotech.hd.common.core.enums.CodeMsg;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
@Slf4j
@Service
public class BatteryStationHdFeeStandardServiceImpl implements BatteryStationHdFeeStandardService {
@Resource
private BatteryStationHdFeeStandardDao batteryStationHdFeeStandardDao;
@Resource
private ResourceService resourceService;
@Resource
private BatteryStationHdFeeStandardDetailDao batteryStationHdFeeStandardDetailDao;
@Override
@ -78,7 +86,27 @@ public class BatteryStationHdFeeStandardServiceImpl implements BatteryStationHdF
return new Result<List<BatteryStationHdFeeStandard>>().success(list);
}
@Override
public Result<Integer> buildByStation(BatteryStation batteryStation) {
List<Dict> dictList = ResultUtil.getValue(resourceService.listDict("fee _schedule"));
if(dictList == null){
log.error("初始化收费标准, 找到有效配置");// endregion
return new Result<Integer>().error("初始化收费标准, 找到有效配置!");
}
try {
for (Dict dict : dictList){
BatteryStationHdFeeStandard bsfs = JSONObject.parseObject(dict.getDictValue(), BatteryStationHdFeeStandard.class);
//查询字典, 初始化
bsfs.setCtime(new Date());
batteryStationHdFeeStandardDao.insert(bsfs);
}
return new Result<Integer>().success(1);
} catch (Exception e) {
e.printStackTrace();
return new Result<Integer>().error("初始化, 添加换电站费用标准出错!"+e.getMessage() );
}
}
}

View File

@ -19,6 +19,7 @@ import com.evotech.hd.cloud.exception.DHException;
import com.evotech.hd.cloud.mqtt.config.MqttSubscribeService;
import com.evotech.hd.cloud.mqtt.message.processor.observer.event.BatteryStationStopServerEvent;
import com.evotech.hd.cloud.mqtt.message.processor.observer.publisher.CommonEventPublisher;
import com.evotech.hd.cloud.service.BatteryStationHdFeeStandardService;
import com.evotech.hd.cloud.service.BatteryStationService;
import com.evotech.hd.cloud.service.newthread.GZHTemplateMessageService;
import com.evotech.hd.cloud.service.rpc.ResourceService;
@ -70,6 +71,9 @@ public class BatteryStationServiceImpl implements BatteryStationService {
private GZHTemplateMessageService templateMessageService;
@Resource
private MqttSubscribeService mqttSubscribeService;
@Resource
private BatteryStationHdFeeStandardService batteryStationHdFeeStandardService;
@Resource
CommonEventPublisher eventPublisher;
@Override
@ -87,6 +91,12 @@ public class BatteryStationServiceImpl implements BatteryStationService {
addStore(bs);
//新增站点, 添加订阅信息
mqttSubscribeService.subscribe(bs.getCode());
//同步生成夏季, 冬季收费标准
try {
batteryStationHdFeeStandardService.buildByStation(bs);
} catch (Exception e) {
log.error("初始化收费标准失败");
}
return new Result<Integer>().success(n);
}
return new Result<Integer>().error("添加换电站出错!");
@ -334,6 +344,11 @@ public class BatteryStationServiceImpl implements BatteryStationService {
}
}
@Override
public BatteryStation getBatteryStationByCode(String code) {
return batteryStationDao.selectOne(new LambdaQueryWrapper<BatteryStation>().eq(BatteryStation::getCode, code).eq(BatteryStation::getDelFlag, HDConstant.DELETE_NO));
}
public Result<List<BatteryStation>> loginList(String proxyCode) {
return new Result<List<BatteryStation>>().success(batteryStationDao.selectList(new LambdaQueryWrapper<BatteryStation>().eq(BatteryStation::getProxyId, proxyCode).select(BatteryStation::getPkId, BatteryStation::getCode)));
}

View File

@ -0,0 +1,30 @@
package com.evotech.hd.cloud.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evotech.hd.cloud.dao.MqttClientLineInfoMapper;
import com.evotech.hd.cloud.entity.MqttClientLineInfo;
import com.evotech.hd.cloud.entity.request.PageMqttClientRequest;
import com.evotech.hd.cloud.service.MqttClientLineInfoService;
import com.evotech.hd.common.core.Dto.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
/**
* MqttClientLineInfoServiceImpl
*
* @author andy.shi
* @ClassName:MqttClientLineInfoServiceImpl
* @date: 2026年03月16日 16:12
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Service
public class MqttClientLineInfoServiceImpl extends ServiceImpl<MqttClientLineInfoMapper, MqttClientLineInfo> implements MqttClientLineInfoService {
@Override
public Result<Page<MqttClientLineInfo>> pageList(PageMqttClientRequest plmmr) {
return new Result<Page<MqttClientLineInfo>>().success(page(new Page<MqttClientLineInfo>(plmmr.getPageNo(), plmmr.getPageSize()),
new LambdaQueryWrapper<MqttClientLineInfo>().eq(StringUtils.isNotEmpty(plmmr.getStationCode()), MqttClientLineInfo::getStationCode, plmmr.getStationCode()).orderByDesc(MqttClientLineInfo::getLineTime)));
}
}

View File

@ -37,9 +37,15 @@ public class WechatUserController {
@ApiOperationSupport(order = 5)
public com.evotech.hd.common.core.Dto.Result<WalletAccount> walletOne(@RequestParam(name = "wuid") String wuid, HttpServletRequest request) {
WalletAccount walletAccount = ResultUtil.getValue(wechatUserService.walletOne(wuid, request));
if(ObjectUtils.isEmpty(walletAccount)){
wechatUserService.openWallet(wuid, request);
walletAccount = ResultUtil.getValue(wechatUserService.walletOne(wuid, request));
if(ObjectUtils.isEmpty(walletAccount)){
return com.evotech.hd.common.core.Dto.Result.getInstance().build(WalletAccount.class).error("未找到账户信息");
}
}
walletAccount.setTotalAmount(walletAccount.getRechargeAmount()+walletAccount.getGiftAmount());
return com.evotech.hd.common.core.Dto.Result.getInstance().build(WalletAccount.class).success(walletAccount);
}