* !44 comment
* !39 添加下行日志打印
* !36 扩展计价领域模型
* !35 webui 初步成型
* !34 webui 初步成型
This commit is contained in:
三丙
2025-09-09 08:23:59 +00:00
parent 921045af8f
commit 58580ca11e
372 changed files with 37900 additions and 1206 deletions

View File

@@ -10,6 +10,7 @@ package sanbing.jcpp.infrastructure.proto;
import sanbing.jcpp.infrastructure.proto.model.PricingModel;
import sanbing.jcpp.infrastructure.proto.model.PricingModel.FlagPrice;
import sanbing.jcpp.infrastructure.proto.model.PricingModel.Period;
import sanbing.jcpp.infrastructure.proto.model.PricingModel.TimePeriodItem;
import sanbing.jcpp.infrastructure.util.trace.Tracer;
import sanbing.jcpp.infrastructure.util.trace.TracerContextUtil;
import sanbing.jcpp.proto.gen.ProtocolProto.*;
@@ -17,7 +18,7 @@ import sanbing.jcpp.proto.gen.ProtocolProto.*;
import java.util.Map;
/**
* @author baigod
* @author 九筒
*/
public class ProtoConverter {
@@ -30,39 +31,109 @@ public class ProtoConverter {
.build();
}
/**
* 将业务层PricingModel转换为Protobuf格式
* 根据计费规则自动选择对应的价格配置结构
*/
public static PricingModelProto toPricingModel(PricingModel pricingModel) {
// 创建 PricingModelProto 实例
PricingModelProto.Builder builder = PricingModelProto.newBuilder();
// 设置字段
// 设置基本信息
builder.setType(PricingModelType.valueOf(pricingModel.getType().name()));
builder.setRule(PricingModelRule.valueOf(pricingModel.getRule().name()));
builder.setStandardElec(pricingModel.getStandardElec().toPlainString());
builder.setStandardServ(pricingModel.getStandardServ().toPlainString());
// 转换 flagPriceList
for (Map.Entry<PricingModelFlag, FlagPrice> entry : pricingModel.getFlagPriceList().entrySet()) {
PricingModelFlag flag = entry.getKey();
FlagPrice flagPrice = entry.getValue();
// 根据计费规则构建对应的价格配置
switch (pricingModel.getRule()) {
case STANDARD:
// 标准计费:全天统一价格
StandardPricingProto standardPricing = StandardPricingProto.newBuilder()
.setElecPrice(pricingModel.getStandardElec().toPlainString())
.setServPrice(pricingModel.getStandardServ().toPlainString())
.build();
builder.setStandardPricing(standardPricing);
break;
FlagPriceProto flagPriceProto = FlagPriceProto.newBuilder()
.setFlag(PricingModelFlag.valueOf(flag.name())) // 枚举转换
.setElec(flagPrice.getElec().toPlainString())
.setServ(flagPrice.getServ().toPlainString())
.build();
case PEAK_VALLEY_PRICING:
// 峰谷计价:按电网峰谷政策分时段
PeakValleyPricingProto.Builder peakValleyBuilder = PeakValleyPricingProto.newBuilder();
builder.putFlagPrice(flag.ordinal(), flagPriceProto); // 按 ordinal 值作为 key 存入
}
// 转换 flagPriceList
if (pricingModel.getFlagPriceList() != null) {
for (Map.Entry<PricingModelFlag, FlagPrice> entry : pricingModel.getFlagPriceList().entrySet()) {
PricingModelFlag flag = entry.getKey();
FlagPrice flagPrice = entry.getValue();
// 转换 PeriodsList
for (Period period : pricingModel.getPeriodsList()) {
PeriodProto periodProto = PeriodProto.newBuilder()
.setSn(period.getSn())
.setBegin(period.getBegin().toString()) // 假设 begin 是 LocalTime, 转换为字符串
.setEnd(period.getEnd().toString()) // 假设 end 是 LocalTime, 转换为字符串
.setFlag(PricingModelFlag.valueOf(period.getFlag().name()))
.build();
builder.addPeriod(periodProto);
FlagPriceProto flagPriceProto = FlagPriceProto.newBuilder()
.setFlag(PricingModelFlag.valueOf(flag.name()))
.setElec(flagPrice.getElec().toPlainString())
.setServ(flagPrice.getServ().toPlainString())
.build();
peakValleyBuilder.putFlagPrice(flag.ordinal(), flagPriceProto);
}
}
// 转换 PeriodsList
if (pricingModel.getPeriodsList() != null) {
for (Period period : pricingModel.getPeriodsList()) {
PeriodProto periodProto = PeriodProto.newBuilder()
.setSn(period.getSn())
.setBegin(period.getBegin().toString())
.setEnd(period.getEnd().toString())
.setFlag(PricingModelFlag.valueOf(period.getFlag().name()))
.build();
peakValleyBuilder.addPeriod(periodProto);
}
}
builder.setPeakValleyPricing(peakValleyBuilder.build());
break;
case TIME_PERIOD_PRICING:
// 时段计价:运营商自定义时段价格
TimePeriodPricingProto.Builder timePeriodBuilder = TimePeriodPricingProto.newBuilder();
if (pricingModel.getTimePeriodItems() != null) {
// 转换自定义时段计价数据
for (TimePeriodItem item : pricingModel.getTimePeriodItems()) {
TimePeriodItemProto.Builder itemBuilder = TimePeriodItemProto.newBuilder()
.setPeriodNo(item.getPeriodNo())
.setStartTime(item.getStartTime().toString())
.setEndTime(item.getEndTime().toString())
.setElecPrice(item.getElecPrice().toPlainString())
.setServPrice(item.getServPrice().toPlainString());
if (item.getDescription() != null) {
itemBuilder.setDescription(item.getDescription());
}
timePeriodBuilder.addPeriods(itemBuilder.build());
}
} else if (pricingModel.getPeriodsList() != null) {
// 兼容处理:将峰谷时段数据转换为时段计价格式
for (Period period : pricingModel.getPeriodsList()) {
FlagPrice flagPrice = pricingModel.getFlagPriceList() != null ?
pricingModel.getFlagPriceList().get(period.getFlag()) : null;
TimePeriodItemProto.Builder itemBuilder = TimePeriodItemProto.newBuilder()
.setPeriodNo(period.getSn())
.setStartTime(period.getBegin().toString())
.setEndTime(period.getEnd().toString());
if (flagPrice != null) {
itemBuilder.setElecPrice(flagPrice.getElec().toPlainString())
.setServPrice(flagPrice.getServ().toPlainString());
}
timePeriodBuilder.addPeriods(itemBuilder.build());
}
}
builder.setTimePeriodPricing(timePeriodBuilder.build());
break;
default:
throw new IllegalArgumentException("Unsupported pricing rule: " + pricingModel.getRule());
}
return builder.build();

View File

@@ -17,65 +17,86 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* 计费模型 - 支持标准计费、峰谷计价、时段计价三种模式
*/
@Data
public class PricingModel {
private UUID id;
// 计数器,供充电桩协议使用
// 序列号,用于充电桩协议通信
private int sequenceNumber;
private String pileCode;
private PricingModelType type;
private PricingModelType type; // 计费类型:充电/放电
private PricingModelRule rule;
private PricingModelRule rule; // 计费规则:标准/峰谷/时段
/**
* 标准电价(单位元)
* 标准电价(元/度)- 标准计费模式使用
*/
private BigDecimal standardElec;
/**
* 标准服务费(单位元)
* 标准服务费(元/度)- 标准计费模式使用
*/
private BigDecimal standardServ;
/**
* 分时电价
* 峰谷价格配置 - 峰谷计费模式使用
* key: 时段标志(尖峰/峰/平/谷/深谷)
* value: 对应的电费和服务费
*/
private Map<PricingModelFlag, FlagPrice> flagPriceList;
/**
* 分时时段
* 峰谷时段划分 - 峰谷计费模式使用
*/
private List<Period> periodsList;
/**
* 自定义时段配置 - 时段计价模式使用
*/
private List<TimePeriodItem> timePeriodItems;
/**
* 峰谷时段定义 - 用于峰谷计价模式
*/
@Setter
@Getter
public static class Period {
private int sn;
// 起始时间
private LocalTime begin;
// 结束时间
private LocalTime end;
// 尖峰平谷标识
private PricingModelFlag flag;
private int sn; // 时段序号
private LocalTime begin; // 起始时间
private LocalTime end; // 结束时间
private PricingModelFlag flag; // 时段标志(尖峰/峰/平/谷/深谷)
}
/**
* 峰谷价格定义 - 对应各时段标志的价格
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class FlagPrice {
private BigDecimal elec; // 电费价格(元/度)
private BigDecimal serv; // 服务费价格(元/度)
}
// 分时电价,单位元
private BigDecimal elec;
// 分时服务费,单位元
private BigDecimal serv;
/**
* 自定义时段定义 - 用于时段计价模式
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class TimePeriodItem {
private int periodNo; // 时段编号从1开始
private LocalTime startTime; // 开始时间
private LocalTime endTime; // 结束时间
private BigDecimal elecPrice; // 该时段电费(元/度)
private BigDecimal servPrice; // 该时段服务费(元/度)
private String description; // 时段名称(如"早高峰"
}
}

View File

@@ -55,7 +55,9 @@ message UplinkQueueMessage {
int64 sessionIdLSB = 4;
string messageKey = 5;
string protocolName = 6;
int64 ts = 7;
bytes requestData = 10;
SessionCloseEventProto sessionCloseEventProto = 20;
LoginRequest loginRequest = 21;
HeartBeatRequest heartBeatRequest = 22;
VerifyPricingRequest verifyPricingRequest = 23;
@@ -77,7 +79,7 @@ message UplinkQueueMessage {
OfflineCardBalanceUpdateResponse offlineCardBalanceUpdateResponse = 40;
OfflineCardSyncResponse offlineCardSyncResponse = 41;
TimeSyncResponse timeSyncResponse = 42;
BmsDemandChargerOutputProto bmsDemandChargerOutputProto = 43;
}
message DownlinkRequestMessage {
@@ -110,6 +112,19 @@ message DownlinkResponseMessage {
optional string error = 2;
}
message SessionCloseEventProto {
string pileCode = 2; // 充电桩编码
SessionCloseReason reason = 3; // 会话关闭原因
optional string additionalInfo = 20; // 附加信息
}
enum SessionCloseReason {
SESSION_CLOSE_UNKNOWN = 0; // 未知原因
SESSION_CLOSE_DESTRUCTION = 1; // 自然销毁(空闲超时)
SESSION_CLOSE_ON_CHANNEL_INACTIVE = 2; // 通道不活跃
SESSION_CLOSE_MANUALLY = 3; // 手动关闭
}
message LoginRequest {
string pileCode = 2;
string credential = 3;
@@ -159,13 +174,17 @@ message QueryPricingResponse {
PricingModelProto pricingModel = 1;
}
// 计费模型配置 - 支持三种计费方式
message PricingModelProto {
PricingModelType type = 3;
PricingModelRule rule = 4;
string standardElec = 5;
string standardServ = 6;
map<int32, FlagPriceProto> flagPrice = 8;
repeated PeriodProto period = 9;
PricingModelType type = 3; // 计费类型:充电/放电
PricingModelRule rule = 4; // 计费规则:标准/峰谷/时段
// 计费配置根据rule字段确定使用哪种配置
oneof pricing_config {
StandardPricingProto standardPricing = 5; // 标准计费:固定价格
PeakValleyPricingProto peakValleyPricing = 6; // 峰谷计价:按尖峰平谷分时段
TimePeriodPricingProto timePeriodPricing = 7; // 时段计价:自定义时段价格
}
}
message PeriodProto {
@@ -181,14 +200,42 @@ message FlagPriceProto {
string serv = 3;
}
// 标准计费配置 - 全天统一价格
message StandardPricingProto {
string elecPrice = 1; // 电费价格(元/度)
string servPrice = 2; // 服务费价格(元/度)
}
// 峰谷计价配置 - 按电网峰谷政策分时计费
message PeakValleyPricingProto {
map<int32, FlagPriceProto> flagPrice = 1; // 各时段价格映射表
repeated PeriodProto period = 2; // 时段划分配置
}
// 时段计价配置 - 运营商自定义时段计费
message TimePeriodPricingProto {
repeated TimePeriodItemProto periods = 1; // 自定义时段列表
}
// 时段计价单个时段定义
message TimePeriodItemProto {
int32 periodNo = 1; // 时段编号从1开始
string startTime = 2; // 开始时间HH:mm:ss格式
string endTime = 3; // 结束时间HH:mm:ss格式
string elecPrice = 4; // 该时段电费(元/度)
string servPrice = 5; // 该时段服务费(元/度)
optional string description = 6; // 时段名称(如"早高峰"
}
enum PricingModelType {
CHARGE = 0; // 充电费率模型
DISCHARGE = 1; // 放电费率模型
}
enum PricingModelRule {
STANDARD = 0;
SPLIT_TIME = 1;
STANDARD = 0; // 标准计费:全天统一价格
PEAK_VALLEY_PRICING = 1; // 峰谷计费:按电网峰谷政策
TIME_PERIOD_PRICING = 2; // 时段计费:运营商自定义
}
enum PricingModelFlag {
@@ -213,7 +260,6 @@ enum GunRunStatus {
}
message GunRunStatusProto {
int64 ts = 1;
string pileCode = 4;
string gunCode = 5;
GunRunStatus GunRunStatus = 41;
@@ -222,7 +268,6 @@ message GunRunStatusProto {
}
message ChargingProgressProto {
int64 ts = 1;
string pileCode = 4;
string gunCode = 5;
string tradeNo = 6;
@@ -265,7 +310,6 @@ message RestartPileRequest {
}
message RemoteStartChargingResponse {
int64 ts = 1;
string pileCode = 4;
string gunCode = 5;
string tradeNo = 6;
@@ -274,7 +318,6 @@ message RemoteStartChargingResponse {
optional string additionalInfo = 20;
}
message RestartPileResponse {
int64 ts = 1;
string pileCode = 4;
bool success = 7;
}
@@ -285,7 +328,6 @@ message RemoteStopChargingRequest {
}
message RemoteStopChargingResponse {
int64 ts = 1;
string pileCode = 4;
string gunCode = 5;
bool success = 7;
@@ -344,7 +386,6 @@ message TransactionRecordRequest {
}
message BmsChargingErrorProto {
int64 ts = 1;
string pileCode = 4;
string gunCode = 5;
string tradeNo = 6;
@@ -358,7 +399,6 @@ message TransactionRecordResponse {
}
message BmsParamConfigReportProto {
int64 ts = 1; // 时间戳
string pileCode = 2; // 桩编码
string gunCode = 3; // 枪编码
string tradeNo = 4; // 交易号
@@ -376,7 +416,6 @@ message BmsParamConfigReportProto {
}
message BmsChargingInfoProto {
int64 ts = 1; // 时间戳
string pileCode = 4;
string gunCode = 5;
string tradeNo = 6;
@@ -404,7 +443,6 @@ message OtaResponse {
}
message BmsAbortProto {
int64 ts = 1; // 时间戳
string pileCode = 4;
string gunCode = 5;
string tradeNo = 6;
@@ -412,7 +450,6 @@ message BmsAbortProto {
}
message BmsHandshakeProto {
int64 ts = 1; // 时间戳
string pileCode = 2; // 桩编码
string gunCode = 3; // 枪编码
string tradeNo = 4; // 交易流水号
@@ -433,7 +470,6 @@ message BmsHandshakeProto {
}
message GroundLockStatusProto {
int64 ts = 1; // 时间戳
string pileCode = 2; // 桩编号
string gunCode = 3; // 枪号
int32 lockStatus = 4; // 车位锁状态
@@ -485,3 +521,11 @@ message TimeSyncResponse {
string pileCode = 1;
string time = 2;
}
message BmsDemandChargerOutputProto {
string pileCode = 4;
string gunCode = 5;
string tradeNo = 6;
optional string additionalInfo = 20;
}