车辆位置,极值,位置等重要数据数据

This commit is contained in:
tzy 2026-02-23 08:44:44 +08:00
parent 3290319ba7
commit 6b6be61716
49 changed files with 1180 additions and 621 deletions

3
.vite/deps/package.json Normal file
View File

@ -0,0 +1,3 @@
{
"type": "module"
}

View File

@ -150,7 +150,6 @@ public class MqttConfig {
// 尽最大可能保留原始字节ISO_8859_1一一映射 // 尽最大可能保留原始字节ISO_8859_1一一映射
payloadBytes = ((String) payloadObj).getBytes(StandardCharsets.ISO_8859_1); payloadBytes = ((String) payloadObj).getBytes(StandardCharsets.ISO_8859_1);
} else { } else {
// 兜底从toString获取再按ISO_8859_1转换
payloadBytes = payloadObj.toString().getBytes(StandardCharsets.ISO_8859_1); payloadBytes = payloadObj.toString().getBytes(StandardCharsets.ISO_8859_1);
} }

View File

@ -23,7 +23,7 @@ import springfox.documentation.spring.web.plugins.Docket;
/** /**
* Swagger2的接口配置 * Swagger2的接口配置
* *
* @author ruoyi * @author ruoyi
*/ */
@Configuration @Configuration
@ -108,9 +108,9 @@ public class SwaggerConfig
// 用ApiInfoBuilder进行定制 // 用ApiInfoBuilder进行定制
return new ApiInfoBuilder() return new ApiInfoBuilder()
// 设置标题 // 设置标题
.title("标题:若依管理系统_接口文档") .title("标题:EVO-BMS 电池管理系统_接口文档")
// 描述 // 描述
.description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...") .description("")
// 作者信息 // 作者信息
.contact(new Contact(ruoyiConfig.getName(), null, null)) .contact(new Contact(ruoyiConfig.getName(), null, null))
// 版本 // 版本

View File

@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModelProperty;
/** /**
* Entity基类 * Entity基类
@ -21,28 +22,35 @@ public class BaseEntity implements Serializable
/** 搜索值 */ /** 搜索值 */
@JsonIgnore @JsonIgnore
@TableField(exist = false) @TableField(exist = false)
@ApiModelProperty(value = "搜索值")
private String searchValue; private String searchValue;
/** 创建者 */ /** 创建者 */
@ApiModelProperty(value = "创建者")
private String createBy; private String createBy;
/** 创建时间 */ /** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "创建时间")
private Date createTime; private Date createTime;
/** 更新者 */ /** 更新者 */
@ApiModelProperty(value = "更新者")
private String updateBy; private String updateBy;
/** 更新时间 */ /** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "更新时间")
private Date updateTime; private Date updateTime;
/** 备注 */ /** 备注 */
@TableField(exist = false) @TableField(exist = false)
@ApiModelProperty(value = "备注")
private String remark; private String remark;
/** 请求参数 */ /** 请求参数 */
@JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY)
@ApiModelProperty(value = "请求参数")
@TableField(exist = false) @TableField(exist = false)
private Map<String, Object> params; private Map<String, Object> params;

View File

@ -20,15 +20,18 @@ import com.evobms.framework.web.controller.BaseController;
import com.evobms.framework.web.domain.AjaxResult; import com.evobms.framework.web.domain.AjaxResult;
import com.evobms.common.utils.poi.ExcelUtil; import com.evobms.common.utils.poi.ExcelUtil;
import com.evobms.framework.web.page.TableDataInfo; import com.evobms.framework.web.page.TableDataInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/** /**
* 电池极值数据Controller * 电池极值数据Controller
* *
* @author 田志阳 * @author 田志阳
* @date 2025-10-14 * @date 2025-11-15
*/ */
@RestController @RestController
@RequestMapping("/BatteryData/BatteryData") @RequestMapping("/Battery/ExtremeValues")
@Api(tags = "电池极值数据")
public class ExtremeValuesController extends BaseController public class ExtremeValuesController extends BaseController
{ {
@Autowired @Autowired
@ -37,8 +40,9 @@ public class ExtremeValuesController extends BaseController
/** /**
* 查询电池极值数据列表 * 查询电池极值数据列表
*/ */
@PreAuthorize("@ss.hasPermi('BatteryData:BatteryData:list')") @PreAuthorize("@ss.hasPermi('Battery:ExtremeValues:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询电池极值数据列表")
public TableDataInfo list(ExtremeValues extremeValues) public TableDataInfo list(ExtremeValues extremeValues)
{ {
startPage(); startPage();
@ -49,9 +53,10 @@ public class ExtremeValuesController extends BaseController
/** /**
* 导出电池极值数据列表 * 导出电池极值数据列表
*/ */
@PreAuthorize("@ss.hasPermi('BatteryData:BatteryData:export')") @PreAuthorize("@ss.hasPermi('Battery:ExtremeValues:export')")
@Log(title = "电池极值数据", businessType = BusinessType.EXPORT) @Log(title = "电池极值数据", businessType = BusinessType.EXPORT)
@PostMapping("/export") @PostMapping("/export")
@ApiOperation("导出电池极值数据列表")
public void export(HttpServletResponse response, ExtremeValues extremeValues) public void export(HttpServletResponse response, ExtremeValues extremeValues)
{ {
List<ExtremeValues> list = extremeValuesService.selectExtremeValuesList(extremeValues); List<ExtremeValues> list = extremeValuesService.selectExtremeValuesList(extremeValues);
@ -62,8 +67,9 @@ public class ExtremeValuesController extends BaseController
/** /**
* 获取电池极值数据详细信息 * 获取电池极值数据详细信息
*/ */
@PreAuthorize("@ss.hasPermi('BatteryData:BatteryData:query')") @PreAuthorize("@ss.hasPermi('Battery:ExtremeValues:query')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取电池极值数据详细信息")
public AjaxResult getInfo(@PathVariable("id") Long id) public AjaxResult getInfo(@PathVariable("id") Long id)
{ {
return success(extremeValuesService.selectExtremeValuesById(id)); return success(extremeValuesService.selectExtremeValuesById(id));
@ -72,9 +78,10 @@ public class ExtremeValuesController extends BaseController
/** /**
* 新增电池极值数据 * 新增电池极值数据
*/ */
@PreAuthorize("@ss.hasPermi('BatteryData:BatteryData:add')") @PreAuthorize("@ss.hasPermi('Battery:ExtremeValues:add')")
@Log(title = "电池极值数据", businessType = BusinessType.INSERT) @Log(title = "电池极值数据", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
@ApiOperation("新增电池极值数据")
public AjaxResult add(@RequestBody ExtremeValues extremeValues) public AjaxResult add(@RequestBody ExtremeValues extremeValues)
{ {
return toAjax(extremeValuesService.insertExtremeValues(extremeValues)); return toAjax(extremeValuesService.insertExtremeValues(extremeValues));
@ -83,9 +90,10 @@ public class ExtremeValuesController extends BaseController
/** /**
* 修改电池极值数据 * 修改电池极值数据
*/ */
@PreAuthorize("@ss.hasPermi('BatteryData:BatteryData:edit')") @PreAuthorize("@ss.hasPermi('Battery:ExtremeValues:edit')")
@Log(title = "电池极值数据", businessType = BusinessType.UPDATE) @Log(title = "电池极值数据", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
@ApiOperation("修改电池极值数据")
public AjaxResult edit(@RequestBody ExtremeValues extremeValues) public AjaxResult edit(@RequestBody ExtremeValues extremeValues)
{ {
return toAjax(extremeValuesService.updateExtremeValues(extremeValues)); return toAjax(extremeValuesService.updateExtremeValues(extremeValues));
@ -94,9 +102,10 @@ public class ExtremeValuesController extends BaseController
/** /**
* 删除电池极值数据 * 删除电池极值数据
*/ */
@PreAuthorize("@ss.hasPermi('BatteryData:BatteryData:remove')") @PreAuthorize("@ss.hasPermi('Battery:ExtremeValues:remove')")
@Log(title = "电池极值数据", businessType = BusinessType.DELETE) @Log(title = "电池极值数据", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}") @DeleteMapping("/{ids}")
@ApiOperation("删除电池极值数据")
public AjaxResult remove(@PathVariable Long[] ids) public AjaxResult remove(@PathVariable Long[] ids)
{ {
return toAjax(extremeValuesService.deleteExtremeValuesByIds(ids)); return toAjax(extremeValuesService.deleteExtremeValuesByIds(ids));

View File

@ -20,6 +20,8 @@ import com.evobms.framework.web.controller.BaseController;
import com.evobms.framework.web.domain.AjaxResult; import com.evobms.framework.web.domain.AjaxResult;
import com.evobms.common.utils.poi.ExcelUtil; import com.evobms.common.utils.poi.ExcelUtil;
import com.evobms.framework.web.page.TableDataInfo; import com.evobms.framework.web.page.TableDataInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/** /**
* 可充电储能子系统温度信息Controller * 可充电储能子系统温度信息Controller
@ -28,7 +30,8 @@ import com.evobms.framework.web.page.TableDataInfo;
* @date 2025-11-15 * @date 2025-11-15
*/ */
@RestController @RestController
@RequestMapping("/temperature/temperature") @RequestMapping("/Battery/SubsystemTemperature")
@Api(tags = "可充电储能子系统温度信息")
public class SubsystemTemperatureController extends BaseController public class SubsystemTemperatureController extends BaseController
{ {
@Autowired @Autowired
@ -37,8 +40,9 @@ public class SubsystemTemperatureController extends BaseController
/** /**
* 查询可充电储能子系统温度信息列表 * 查询可充电储能子系统温度信息列表
*/ */
@PreAuthorize("@ss.hasPermi('temperature:temperature:list')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemTemperature:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询子系统温度信息列表")
public TableDataInfo list(SubsystemTemperature subsystemTemperature) public TableDataInfo list(SubsystemTemperature subsystemTemperature)
{ {
startPage(); startPage();
@ -49,9 +53,10 @@ public class SubsystemTemperatureController extends BaseController
/** /**
* 导出可充电储能子系统温度信息列表 * 导出可充电储能子系统温度信息列表
*/ */
@PreAuthorize("@ss.hasPermi('temperature:temperature:export')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemTemperature:export')")
@Log(title = "可充电储能子系统温度信息", businessType = BusinessType.EXPORT) @Log(title = "可充电储能子系统温度信息", businessType = BusinessType.EXPORT)
@PostMapping("/export") @PostMapping("/export")
@ApiOperation("导出子系统温度信息列表")
public void export(HttpServletResponse response, SubsystemTemperature subsystemTemperature) public void export(HttpServletResponse response, SubsystemTemperature subsystemTemperature)
{ {
List<SubsystemTemperature> list = subsystemTemperatureService.selectSubsystemTemperatureList(subsystemTemperature); List<SubsystemTemperature> list = subsystemTemperatureService.selectSubsystemTemperatureList(subsystemTemperature);
@ -62,8 +67,9 @@ public class SubsystemTemperatureController extends BaseController
/** /**
* 获取可充电储能子系统温度信息详细信息 * 获取可充电储能子系统温度信息详细信息
*/ */
@PreAuthorize("@ss.hasPermi('temperature:temperature:query')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemTemperature:query')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取子系统温度信息详细信息")
public AjaxResult getInfo(@PathVariable("id") Long id) public AjaxResult getInfo(@PathVariable("id") Long id)
{ {
return success(subsystemTemperatureService.selectSubsystemTemperatureById(id)); return success(subsystemTemperatureService.selectSubsystemTemperatureById(id));
@ -72,9 +78,10 @@ public class SubsystemTemperatureController extends BaseController
/** /**
* 新增可充电储能子系统温度信息 * 新增可充电储能子系统温度信息
*/ */
@PreAuthorize("@ss.hasPermi('temperature:temperature:add')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemTemperature:add')")
@Log(title = "可充电储能子系统温度信息", businessType = BusinessType.INSERT) @Log(title = "可充电储能子系统温度信息", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
@ApiOperation("新增子系统温度信息")
public AjaxResult add(@RequestBody SubsystemTemperature subsystemTemperature) public AjaxResult add(@RequestBody SubsystemTemperature subsystemTemperature)
{ {
return toAjax(subsystemTemperatureService.insertSubsystemTemperature(subsystemTemperature)); return toAjax(subsystemTemperatureService.insertSubsystemTemperature(subsystemTemperature));
@ -83,9 +90,10 @@ public class SubsystemTemperatureController extends BaseController
/** /**
* 修改可充电储能子系统温度信息 * 修改可充电储能子系统温度信息
*/ */
@PreAuthorize("@ss.hasPermi('temperature:temperature:edit')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemTemperature:edit')")
@Log(title = "可充电储能子系统温度信息", businessType = BusinessType.UPDATE) @Log(title = "可充电储能子系统温度信息", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
@ApiOperation("修改子系统温度信息")
public AjaxResult edit(@RequestBody SubsystemTemperature subsystemTemperature) public AjaxResult edit(@RequestBody SubsystemTemperature subsystemTemperature)
{ {
return toAjax(subsystemTemperatureService.updateSubsystemTemperature(subsystemTemperature)); return toAjax(subsystemTemperatureService.updateSubsystemTemperature(subsystemTemperature));
@ -94,9 +102,10 @@ public class SubsystemTemperatureController extends BaseController
/** /**
* 删除可充电储能子系统温度信息 * 删除可充电储能子系统温度信息
*/ */
@PreAuthorize("@ss.hasPermi('temperature:temperature:remove')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemTemperature:remove')")
@Log(title = "可充电储能子系统温度信息", businessType = BusinessType.DELETE) @Log(title = "可充电储能子系统温度信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}") @DeleteMapping("/{ids}")
@ApiOperation("删除子系统温度信息")
public AjaxResult remove(@PathVariable Long[] ids) public AjaxResult remove(@PathVariable Long[] ids)
{ {
return toAjax(subsystemTemperatureService.deleteSubsystemTemperatureByIds(ids)); return toAjax(subsystemTemperatureService.deleteSubsystemTemperatureByIds(ids));

View File

@ -20,6 +20,8 @@ import com.evobms.framework.web.controller.BaseController;
import com.evobms.framework.web.domain.AjaxResult; import com.evobms.framework.web.domain.AjaxResult;
import com.evobms.common.utils.poi.ExcelUtil; import com.evobms.common.utils.poi.ExcelUtil;
import com.evobms.framework.web.page.TableDataInfo; import com.evobms.framework.web.page.TableDataInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/** /**
* 可充电储能子系统电压信息Controller * 可充电储能子系统电压信息Controller
@ -28,7 +30,8 @@ import com.evobms.framework.web.page.TableDataInfo;
* @date 2025-11-15 * @date 2025-11-15
*/ */
@RestController @RestController
@RequestMapping("/voltage/voltage") @RequestMapping("/Battery/SubsystemVoltage")
@Api(tags = "可充电储能子系统电压信息")
public class SubsystemVoltageController extends BaseController public class SubsystemVoltageController extends BaseController
{ {
@Autowired @Autowired
@ -37,8 +40,9 @@ public class SubsystemVoltageController extends BaseController
/** /**
* 查询可充电储能子系统电压信息列表 * 查询可充电储能子系统电压信息列表
*/ */
@PreAuthorize("@ss.hasPermi('voltage:voltage:list')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemVoltage:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询子系统电压信息列表")
public TableDataInfo list(SubsystemVoltage subsystemVoltage) public TableDataInfo list(SubsystemVoltage subsystemVoltage)
{ {
startPage(); startPage();
@ -49,9 +53,10 @@ public class SubsystemVoltageController extends BaseController
/** /**
* 导出可充电储能子系统电压信息列表 * 导出可充电储能子系统电压信息列表
*/ */
@PreAuthorize("@ss.hasPermi('voltage:voltage:export')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemVoltage:export')")
@Log(title = "可充电储能子系统电压信息", businessType = BusinessType.EXPORT) @Log(title = "可充电储能子系统电压信息", businessType = BusinessType.EXPORT)
@PostMapping("/export") @PostMapping("/export")
@ApiOperation("导出子系统电压信息列表")
public void export(HttpServletResponse response, SubsystemVoltage subsystemVoltage) public void export(HttpServletResponse response, SubsystemVoltage subsystemVoltage)
{ {
List<SubsystemVoltage> list = subsystemVoltageService.selectSubsystemVoltageList(subsystemVoltage); List<SubsystemVoltage> list = subsystemVoltageService.selectSubsystemVoltageList(subsystemVoltage);
@ -62,8 +67,9 @@ public class SubsystemVoltageController extends BaseController
/** /**
* 获取可充电储能子系统电压信息详细信息 * 获取可充电储能子系统电压信息详细信息
*/ */
@PreAuthorize("@ss.hasPermi('voltage:voltage:query')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemVoltage:query')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取子系统电压信息详细信息")
public AjaxResult getInfo(@PathVariable("id") Long id) public AjaxResult getInfo(@PathVariable("id") Long id)
{ {
return success(subsystemVoltageService.selectSubsystemVoltageById(id)); return success(subsystemVoltageService.selectSubsystemVoltageById(id));
@ -72,9 +78,10 @@ public class SubsystemVoltageController extends BaseController
/** /**
* 新增可充电储能子系统电压信息 * 新增可充电储能子系统电压信息
*/ */
@PreAuthorize("@ss.hasPermi('voltage:voltage:add')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemVoltage:add')")
@Log(title = "可充电储能子系统电压信息", businessType = BusinessType.INSERT) @Log(title = "可充电储能子系统电压信息", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
@ApiOperation("新增子系统电压信息")
public AjaxResult add(@RequestBody SubsystemVoltage subsystemVoltage) public AjaxResult add(@RequestBody SubsystemVoltage subsystemVoltage)
{ {
return toAjax(subsystemVoltageService.insertSubsystemVoltage(subsystemVoltage)); return toAjax(subsystemVoltageService.insertSubsystemVoltage(subsystemVoltage));
@ -83,9 +90,10 @@ public class SubsystemVoltageController extends BaseController
/** /**
* 修改可充电储能子系统电压信息 * 修改可充电储能子系统电压信息
*/ */
@PreAuthorize("@ss.hasPermi('voltage:voltage:edit')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemVoltage:edit')")
@Log(title = "可充电储能子系统电压信息", businessType = BusinessType.UPDATE) @Log(title = "可充电储能子系统电压信息", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
@ApiOperation("修改子系统电压信息")
public AjaxResult edit(@RequestBody SubsystemVoltage subsystemVoltage) public AjaxResult edit(@RequestBody SubsystemVoltage subsystemVoltage)
{ {
return toAjax(subsystemVoltageService.updateSubsystemVoltage(subsystemVoltage)); return toAjax(subsystemVoltageService.updateSubsystemVoltage(subsystemVoltage));
@ -94,9 +102,10 @@ public class SubsystemVoltageController extends BaseController
/** /**
* 删除可充电储能子系统电压信息 * 删除可充电储能子系统电压信息
*/ */
@PreAuthorize("@ss.hasPermi('voltage:voltage:remove')") @PreAuthorize("@ss.hasPermi('Battery:SubsystemVoltage:remove')")
@Log(title = "可充电储能子系统电压信息", businessType = BusinessType.DELETE) @Log(title = "可充电储能子系统电压信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}") @DeleteMapping("/{ids}")
@ApiOperation("删除子系统电压信息")
public AjaxResult remove(@PathVariable Long[] ids) public AjaxResult remove(@PathVariable Long[] ids)
{ {
return toAjax(subsystemVoltageService.deleteSubsystemVoltageByIds(ids)); return toAjax(subsystemVoltageService.deleteSubsystemVoltageByIds(ids));

View File

@ -2,7 +2,11 @@ package com.evobms.project.battery.domain;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import com.evobms.framework.aspectj.lang.annotation.Excel; import com.evobms.framework.aspectj.lang.annotation.Excel;
@ -14,67 +18,85 @@ import com.evobms.framework.web.domain.BaseEntity;
* @author 田志阳 * @author 田志阳
* @date 2025-10-14 * @date 2025-10-14
*/ */
@ApiModel(description = "电池极值数据对象")
@Data
@EqualsAndHashCode(callSuper = false)
public class ExtremeValues extends BaseEntity public class ExtremeValues extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 主键ID */ /** 主键ID */
@ApiModelProperty(value = "主键ID")
private Long id; private Long id;
/** 设备ID */ /** 设备ID */
@ApiModelProperty(value = "设备ID")
@Excel(name = "设备ID") @Excel(name = "设备ID")
private String deviceId; private String deviceId;
/** 数据时间戳 */ /** 数据时间戳 */
@ApiModelProperty(value = "数据时间戳")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date timestamp; private Date timestamp;
/** 最高电压电池子系统号 */ /** 最高电压电池子系统号 */
@ApiModelProperty(value = "最高电压电池子系统号")
@Excel(name = "最高电压电池子系统号") @Excel(name = "最高电压电池子系统号")
private Integer maxVoltageSubsystemNo; private Integer maxVoltageSubsystemNo;
/** 最高电压电池单体代号 */ /** 最高电压电池单体代号 */
@ApiModelProperty(value = "最高电压电池单体代号")
@Excel(name = "最高电压电池单体代号") @Excel(name = "最高电压电池单体代号")
private Integer maxVoltageBatteryNo; private Integer maxVoltageBatteryNo;
/** 电池单体电压最高值(V) */ /** 电池单体电压最高值(V) */
@ApiModelProperty(value = "电池单体电压最高值(V)")
@Excel(name = "电池单体电压最高值(V)") @Excel(name = "电池单体电压最高值(V)")
private BigDecimal maxVoltageValue; private BigDecimal maxVoltageValue;
/** 最低电压电池子系统号 */ /** 最低电压电池子系统号 */
@ApiModelProperty(value = "最低电压电池子系统号")
@Excel(name = "最低电压电池子系统号") @Excel(name = "最低电压电池子系统号")
private Integer minVoltageSubsystemNo; private Integer minVoltageSubsystemNo;
/** 最低电压电池单体代号 */ /** 最低电压电池单体代号 */
@ApiModelProperty(value = "最低电压电池单体代号")
@Excel(name = "最低电压电池单体代号") @Excel(name = "最低电压电池单体代号")
private Integer minVoltageBatteryNo; private Integer minVoltageBatteryNo;
/** 电池单体电压最低值(V) */ /** 电池单体电压最低值(V) */
@ApiModelProperty(value = "电池单体电压最低值(V)")
@Excel(name = "电池单体电压最低值(V)") @Excel(name = "电池单体电压最低值(V)")
private BigDecimal minVoltageValue; private BigDecimal minVoltageValue;
/** 最高温度子系统号 */ /** 最高温度子系统号 */
@ApiModelProperty(value = "最高温度子系统号")
@Excel(name = "最高温度子系统号") @Excel(name = "最高温度子系统号")
private Integer maxTempSubsystemNo; private Integer maxTempSubsystemNo;
/** 最高温度探针序号 */ /** 最高温度探针序号 */
@ApiModelProperty(value = "最高温度探针序号")
@Excel(name = "最高温度探针序号") @Excel(name = "最高温度探针序号")
private Integer maxTempProbeNo; private Integer maxTempProbeNo;
/** 最高温度值(℃) */ /** 最高温度值(℃) */
@ApiModelProperty(value = "最高温度值(℃)")
@Excel(name = "最高温度值(℃)") @Excel(name = "最高温度值(℃)")
private BigDecimal maxTempValue; private BigDecimal maxTempValue;
/** 最低温度子系统号 */ /** 最低温度子系统号 */
@ApiModelProperty(value = "最低温度子系统号")
@Excel(name = "最低温度子系统号") @Excel(name = "最低温度子系统号")
private Integer minTempSubsystemNo; private Integer minTempSubsystemNo;
/** 最低温度探针序号 */ /** 最低温度探针序号 */
@ApiModelProperty(value = "最低温度探针序号")
@Excel(name = "最低温度探针序号") @Excel(name = "最低温度探针序号")
private Integer minTempProbeNo; private Integer minTempProbeNo;
/** 最低温度值(℃) */ /** 最低温度值(℃) */
@ApiModelProperty(value = "最低温度值(℃)")
@Excel(name = "最低温度值(℃)") @Excel(name = "最低温度值(℃)")
private BigDecimal minTempValue; private BigDecimal minTempValue;

View File

@ -1,10 +1,13 @@
package com.evobms.project.battery.domain; package com.evobms.project.battery.domain;
import java.util.Date; import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data; import lombok.Data;
import com.evobms.framework.aspectj.lang.annotation.Excel; import com.evobms.framework.aspectj.lang.annotation.Excel;
import com.evobms.framework.web.domain.BaseEntity; import com.evobms.framework.web.domain.BaseEntity;
import lombok.EqualsAndHashCode;
/** /**
* 可充电储能子系统温度信息对象 subsystem_temperature * 可充电储能子系统温度信息对象 subsystem_temperature
@ -13,44 +16,55 @@ import com.evobms.framework.web.domain.BaseEntity;
* @date 2025-11-15 * @date 2025-11-15
*/ */
@Data @Data
@ApiModel(description = "可充电储能子系统温度信息对象")
@EqualsAndHashCode(callSuper = false)
public class SubsystemTemperature extends BaseEntity public class SubsystemTemperature extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 主键ID */ /** 主键ID */
@ApiModelProperty(value = "主键ID")
private Long id; private Long id;
/** 设备ID */ /** 设备ID */
@ApiModelProperty(value = "设备ID")
@Excel(name = "设备ID") @Excel(name = "设备ID")
private String deviceId; private String deviceId;
/** 数据时间戳 */ /** 数据时间戳 */
@ApiModelProperty(value = "数据时间戳")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date timestamp; private Date timestamp;
/** 可充电储能子系统个数 */ /** 可充电储能子系统个数 */
@ApiModelProperty(value = "可充电储能子系统个数")
@Excel(name = "可充电储能子系统个数") @Excel(name = "可充电储能子系统个数")
private Integer subsystemCount; private Integer subsystemCount;
/** 可充电储能子系统号 */ /** 可充电储能子系统号 */
@ApiModelProperty(value = "可充电储能子系统号")
@Excel(name = "可充电储能子系统号") @Excel(name = "可充电储能子系统号")
private Integer subsystemNo; private Integer subsystemNo;
/** 可充电储能温度探针个数 */ /** 可充电储能温度探针个数 */
@ApiModelProperty(value = "可充电储能温度探针个数")
@Excel(name = "可充电储能温度探针个数") @Excel(name = "可充电储能温度探针个数")
private Integer tempProbeCount; private Integer tempProbeCount;
/** 各温度探针检测的温度值数组(℃) */ /** 各温度探针检测的温度值数组(℃) */
@ApiModelProperty(value = "各温度探针检测的温度值数组(℃)")
@Excel(name = "各温度探针检测的温度值数组(℃)") @Excel(name = "各温度探针检测的温度值数组(℃)")
private String temperatureValues; private String temperatureValues;
/** 创建时间 */ /** 创建时间 */
@ApiModelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date createTime; private Date createTime;
/** 更新时间 */ /** 更新时间 */
@ApiModelProperty(value = "更新时间")
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date updateTime; private Date updateTime;

View File

@ -2,6 +2,8 @@ package com.evobms.project.battery.domain;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data; import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
@ -16,60 +18,74 @@ import com.evobms.framework.web.domain.BaseEntity;
* @date 2025-11-15 * @date 2025-11-15
*/ */
@Data @Data
@ApiModel(description = "可充电储能子系统电压信息对象")
public class SubsystemVoltage extends BaseEntity public class SubsystemVoltage extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 主键ID */ /** 主键ID */
@ApiModelProperty(value = "主键ID")
private Long id; private Long id;
/** 设备ID */ /** 设备ID */
@ApiModelProperty(value = "设备ID")
@Excel(name = "设备ID") @Excel(name = "设备ID")
private String deviceId; private String deviceId;
/** 数据时间戳 */ /** 数据时间戳 */
@ApiModelProperty(value = "数据时间戳")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date timestamp; private Date timestamp;
/** 可充电储能子系统个数 */ /** 可充电储能子系统个数 */
@ApiModelProperty(value = "可充电储能子系统个数")
@Excel(name = "可充电储能子系统个数") @Excel(name = "可充电储能子系统个数")
private Integer subsystemCount; private Integer subsystemCount;
/** 可充电储能子系统号 */ /** 可充电储能子系统号 */
@ApiModelProperty(value = "可充电储能子系统号")
@Excel(name = "可充电储能子系统号") @Excel(name = "可充电储能子系统号")
private Integer subsystemNo; private Integer subsystemNo;
/** 可充电储能装置电压(V) */ /** 可充电储能装置电压(V) */
@ApiModelProperty(value = "可充电储能装置电压(V)")
@Excel(name = "可充电储能装置电压(V)") @Excel(name = "可充电储能装置电压(V)")
private BigDecimal subsystemVoltage; private BigDecimal subsystemVoltage;
/** 可充电储能装置电流(A) */ /** 可充电储能装置电流(A) */
@ApiModelProperty(value = "可充电储能装置电流(A)")
@Excel(name = "可充电储能装置电流(A)") @Excel(name = "可充电储能装置电流(A)")
private BigDecimal subsystemCurrent; private BigDecimal subsystemCurrent;
/** 单体电池总数 */ /** 单体电池总数 */
@ApiModelProperty(value = "单体电池总数")
@Excel(name = "单体电池总数") @Excel(name = "单体电池总数")
private Integer totalBatteryCount; private Integer totalBatteryCount;
/** 本帧起始电池序号 */ /** 本帧起始电池序号 */
@ApiModelProperty(value = "本帧起始电池序号")
@Excel(name = "本帧起始电池序号") @Excel(name = "本帧起始电池序号")
private Integer frameStartBatteryNo; private Integer frameStartBatteryNo;
/** 本帧单体电池总数 */ /** 本帧单体电池总数 */
@ApiModelProperty(value = "本帧单体电池总数")
@Excel(name = "本帧单体电池总数") @Excel(name = "本帧单体电池总数")
private Integer frameBatteryCount; private Integer frameBatteryCount;
/** 单体电池电压数组(V) */ /** 单体电池电压数组(V) */
@ApiModelProperty(value = "单体电池电压数组(V)")
@Excel(name = "单体电池电压数组(V)") @Excel(name = "单体电池电压数组(V)")
private String batteryVoltages; private String batteryVoltages;
/** 创建时间 */ /** 创建时间 */
@ApiModelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date createTime; private Date createTime;
/** 更新时间 */ /** 更新时间 */
@ApiModelProperty(value = "更新时间")
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date updateTime; private Date updateTime;

View File

@ -7,8 +7,10 @@ import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
public class GBT32960FullDecoder { public class GBT32960FullDecoder {
private static final Logger log = LoggerFactory.getLogger(GBT32960FullDecoder.class); private static final Logger log = LoggerFactory.getLogger(GBT32960FullDecoder.class);
// 从SN码生成AES密钥 // 从SN码生成AES密钥
private static byte[] generateKeyFromSn(String sn) { private static byte[] generateKeyFromSn(String sn) {
String s = sn == null ? "" : sn; String s = sn == null ? "" : sn;
@ -68,150 +70,236 @@ public class GBT32960FullDecoder {
} }
// 详细的协议解析方法 // 详细的协议解析方法
public static String parseGBT32960Data(byte[] receivedData, String deviceSn) { public static String parseGBT32960Data(byte[] receivedData, String deviceSn) {
String bytesData = null; String bytesData = null;
try { try {
log.info("=== GBT32960协议数据解析 ==="); log.info("=== GBT32960协议数据解析 ===");
log.info("实际数据长度: " + receivedData.length + " 字节"); log.info("实际数据长度: " + receivedData.length + " 字节");
// 1. 检查起始位 // 1. 检查起始位
if (receivedData.length < 2 || receivedData[0] != 0x23 || receivedData[1] != 0x23) { if (receivedData.length < 2 || receivedData[0] != 0x23 || receivedData[1] != 0x23) {
log.error("无效的起始位或数据过短"); log.error("无效的起始位或数据过短");
return null; return null;
} }
log.info("起始位: 0x2323 ✓"); log.info("起始位: 0x2323 ✓");
// 2. 打印完整数据用于调试 // 2. 打印完整数据用于调试
log.info("完整数据: " + bytesToHex(receivedData)); log.info("完整数据: " + bytesToHex(receivedData));
// 3. 分析协议结构 // 3. 分析协议结构
int offset = 2; // 跳过起始位 int offset = 2; // 跳过起始位
// 命令标识 // 命令标识
byte commandId = receivedData[offset++]; byte commandId = receivedData[offset++];
log.info("命令标识: 0x" + String.format("%02X", commandId)); log.info("命令标识: 0x" + String.format("%02X", commandId));
// 应答标志 // 应答标志
byte responseFlag = receivedData[offset++]; byte responseFlag = receivedData[offset++];
log.info("应答标志: 0x" + String.format("%02X", responseFlag)); log.info("应答标志: 0x" + String.format("%02X", responseFlag));
// VIN码 (17字节) // VIN码 (17字节)
byte[] vin = Arrays.copyOfRange(receivedData, offset, offset + 17); byte[] vin = Arrays.copyOfRange(receivedData, offset, offset + 17);
offset += 17; offset += 17;
log.info("VIN码: " + bytesToHex(vin) + " (" + new String(vin).trim() + ")"); log.info("VIN码: " + bytesToHex(vin) + " (" + new String(vin).trim() + ")");
// 加密方式 // 加密方式
byte encryptionMethod = receivedData[offset++]; byte encryptionMethod = receivedData[offset++];
log.info("加密方式: 0x" + String.format("%02X", encryptionMethod)); log.info("加密方式: 0x" + String.format("%02X", encryptionMethod));
if (encryptionMethod != 0x03) { if (encryptionMethod != 0x03) {
log.error("不支持的解密方式期望AES128(0x03)"); log.error("不支持的解密方式期望AES128(0x03)");
return null; return null;
} }
// 数据单元长度 (WORD, 大端序) // 数据单元长度 (WORD, 大端序)
int dataUnitLength = ((receivedData[offset] & 0xFF) << 8) | (receivedData[offset + 1] & 0xFF); int dataUnitLength = ((receivedData[offset] & 0xFF) << 8) | (receivedData[offset + 1] & 0xFF);
offset += 2; offset += 2;
log.info("声明的数据单元长度: " + dataUnitLength + " 字节"); log.info("声明的数据单元长度: " + dataUnitLength + " 字节");
// 计算当前头部长度 // 计算当前头部长度
int headerLength = offset; int headerLength = offset;
log.info("协议头部长度: " + headerLength + " 字节"); log.info("协议头部长度: " + headerLength + " 字节");
// 剩余数据长度 // 剩余数据长度
int remainingDataLength = receivedData.length - headerLength; int remainingDataLength = receivedData.length - headerLength;
log.info("剩余数据长度: " + remainingDataLength + " 字节"); log.info("剩余数据长度: " + remainingDataLength + " 字节");
// 4. 重新计算期望长度 // 4. 重新计算期望长度
// 方案1: 如果BCC是1字节 // 方案1: 如果BCC是1字节
int expectedLength1 = headerLength + dataUnitLength + 1; int expectedLength1 = headerLength + dataUnitLength + 1;
// 方案2: 如果BCC是2字节根据您最初描述 // 方案2: 如果BCC是2字节根据您最初描述
int expectedLength2 = headerLength + dataUnitLength + 2; int expectedLength2 = headerLength + dataUnitLength + 2;
log.info("期望长度 (BCC=1字节): " + expectedLength1); log.info("期望长度 (BCC=1字节): " + expectedLength1);
log.info("期望长度 (BCC=2字节): " + expectedLength2); log.info("期望长度 (BCC=2字节): " + expectedLength2);
log.info("实际长度: " + receivedData.length); log.info("实际长度: " + receivedData.length);
// 5. 确定正确的数据范围 // 5. 确定正确的数据范围
int encryptedDataStart = offset; int encryptedDataStart = offset;
int encryptedDataEnd; int encryptedDataEnd;
int bccStart; int bccStart;
if (receivedData.length == expectedLength1) { if (receivedData.length == expectedLength1) {
// BCC为1字节 // BCC为1字节
encryptedDataEnd = encryptedDataStart + dataUnitLength; encryptedDataEnd = encryptedDataStart + dataUnitLength;
bccStart = encryptedDataEnd; bccStart = encryptedDataEnd;
log.info("采用方案: BCC为1字节"); log.info("采用方案: BCC为1字节");
} else if (receivedData.length == expectedLength2) { } else if (receivedData.length == expectedLength2) {
// BCC为2字节 // BCC为2字节
encryptedDataEnd = encryptedDataStart + dataUnitLength; encryptedDataEnd = encryptedDataStart + dataUnitLength;
bccStart = encryptedDataEnd; bccStart = encryptedDataEnd;
log.info("采用方案: BCC为2字节"); log.info("采用方案: BCC为2字节");
} else { } else {
// 自动适应使用剩余的所有数据作为加密数据 // 自动适应使用剩余的所有数据作为加密数据
encryptedDataEnd = receivedData.length - 1; // 假设BCC为1字节 encryptedDataEnd = receivedData.length - 1; // 假设BCC为1字节
int actualDataUnitLength = encryptedDataEnd - encryptedDataStart; int actualDataUnitLength = encryptedDataEnd - encryptedDataStart;
log.info("长度不匹配,使用实际数据单元长度: " + actualDataUnitLength + " 字节"); log.info("长度不匹配,使用实际数据单元长度: " + actualDataUnitLength + " 字节");
dataUnitLength = actualDataUnitLength; dataUnitLength = actualDataUnitLength;
bccStart = encryptedDataEnd; bccStart = encryptedDataEnd;
} }
// 6. 提取加密数据 // 6. 提取加密数据
byte[] encryptedData = Arrays.copyOfRange(receivedData, encryptedDataStart, encryptedDataStart + dataUnitLength); byte[] encryptedData = Arrays.copyOfRange(receivedData, encryptedDataStart, encryptedDataStart + dataUnitLength);
log.info("加密数据长度: " + encryptedData.length + " 字节"); log.info("加密数据长度: " + encryptedData.length + " 字节");
log.info("加密数据 (前64字节): " + bytesToHex(Arrays.copyOf(encryptedData, Math.min(64, encryptedData.length))) + "..."); log.info("加密数据 (前64字节): " + bytesToHex(Arrays.copyOf(encryptedData, Math.min(64, encryptedData.length))) + "...");
if (encryptedData.length % 16 != 0) {
log.error("AES密文长度非法不是16倍数length=" + encryptedData.length);
return null;
}
// 7. 提取BCC校验码
int bccLength = receivedData.length - (encryptedDataStart + dataUnitLength);
byte[] receivedBCC = Arrays.copyOfRange(receivedData, encryptedDataStart + dataUnitLength, receivedData.length);
//log.info("BCC长度: " + bccLength + " 字节");
//log.info("接收到的BCC: " + bytesToHex(receivedBCC));
// 7. 提取BCC校验码 // 8. 计算BCC校验范围从命令单元开始到加密数据结束
int bccLength = receivedData.length - (encryptedDataStart + dataUnitLength); int bccCalcStart = 2; // 从命令标识开始 (跳过0x2323)
byte[] receivedBCC = Arrays.copyOfRange(receivedData, encryptedDataStart + dataUnitLength, receivedData.length); int bccCalcEnd = encryptedDataStart + dataUnitLength;
//log.info("BCC长度: " + bccLength + " 字节"); byte calculatedBCC = calculateBCC(receivedData, bccCalcStart, bccCalcEnd);
//log.info("接收到的BCC: " + bytesToHex(receivedBCC));
// 8. 计算BCC校验范围从命令单元开始到加密数据结束 log.info("BCC计算范围: 字节[" + bccCalcStart + "~" + bccCalcEnd + ")");
int bccCalcStart = 2; // 从命令标识开始 (跳过0x2323) log.info("计算出的BCC: 0x" + String.format("%02X", calculatedBCC));
int bccCalcEnd = encryptedDataStart + dataUnitLength;
byte calculatedBCC = calculateBCC(receivedData, bccCalcStart, bccCalcEnd);
log.info("BCC计算范围: 字节[" + bccCalcStart + "~" + bccCalcEnd + ")"); // 验证BCC (只比较第一个字节)
log.info("计算出的BCC: 0x" + String.format("%02X", calculatedBCC)); if (receivedBCC.length > 0 && calculatedBCC == receivedBCC[0]) {
log.info("BCC校验通过 ✓");
// 验证BCC (只比较第一个字节) } else {
if (receivedBCC.length > 0 && calculatedBCC == receivedBCC[0]) { log.error("BCC校验失败!");
log.info("BCC校验通过 ✓"); }
} else {
log.error("BCC校验失败!");
}
//使用的AES密钥 //使用的AES密钥
byte[] aesKey = generateKeyFromSn(deviceSn); byte[] aesKey = generateKeyFromSn(deviceSn);
System.out.println("密钥------------------------>"+aesKey); System.out.println(Arrays.toString(aesKey));
byte[] decryptedData = decryptData(encryptedData, aesKey); System.out.println(aesKey.length);
bytesData = bytesToHex(decryptedData); log.info("AES密钥: " + bytesToHex(aesKey));
log.info("解密成功!"); byte[] decryptedData = decryptData(encryptedData, aesKey);
log.info("解密后数据长度: " + decryptedData.length + " 字节"); bytesData = bytesToHex(decryptedData);
log.info("解密后数据 (完整): " + bytesData); log.info("解密成功!");
log.info("解密后数据长度: " + decryptedData.length + " 字节");
log.info("解密后数据 (完整): " + bytesData);
// 10. 解析解密后的数据单元 // 10. 解析解密后的数据单元
// parseDecryptedDataUnit(decryptedData); // parseDecryptedDataUnit(decryptedData);
} catch (Exception e) { } catch (Exception e) {
log.error("解析过程中发生错误: " + e.getMessage()); log.error("解析过程中发生错误: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
}
return bytesData;
}
/* public static String parseGBT32960Data(byte[] frame, String deviceSn) throws Exception {
if (frame == null || frame.length < 25) {
throw new IllegalArgumentException("报文长度非法");
} }
return bytesData; int offset = 0;
// 1. 起始符校验 0x23 0x23
if (frame[offset++] != 0x23 || frame[offset++] != 0x23) {
throw new IllegalArgumentException("非法起始位非0x2323");
}
// 2. 命令标识
byte commandId = frame[offset++];
// 3. 应答标志
byte responseFlag = frame[offset++];
// 4. VIN (17字节)
byte[] vinBytes = Arrays.copyOfRange(frame, offset, offset + 17);
String vin = new String(vinBytes).trim();
offset += 17;
// 5. 加密方式
byte encryptType = frame[offset++];
// 6. 数据单元长度 (大端)
if (offset + 2 > frame.length) {
throw new IllegalArgumentException("数据单元长度字段越界");
}
int dataUnitLength = ((frame[offset] & 0xFF) << 8) | (frame[offset + 1] & 0xFF);
offset += 2;
int headerLength = offset;
// 7. 校验整体长度
// 标准格式
// 头部 + 数据单元 + 1字节BCC
int expectedLength = headerLength + dataUnitLength + 1;
if (frame.length != expectedLength) {
throw new IllegalArgumentException("报文长度不匹配,声明长度=" + dataUnitLength + ",实际长度=" + frame.length + ",期望总长度=" + expectedLength);
}
// 8. 提取数据单元
byte[] dataUnit = Arrays.copyOfRange(frame, headerLength, headerLength + dataUnitLength
);
// 9. BCC 校验
// BCC范围从命令标识开始
byte receivedBcc = frame[frame.length - 1];
byte calculatedBcc = calculateBCC(frame, 2, headerLength + dataUnitLength
);
if (receivedBcc != calculatedBcc) {
throw new IllegalStateException(
String.format("BCC校验失败收到=0x%02X 计算=0x%02X",
receivedBcc, calculatedBcc)
);
}
// 10. 加密处理
if (encryptType == 0x01) {
// 不加密
return bytesToHex(dataUnit);
}
if (encryptType != 0x03) {
throw new UnsupportedOperationException(
"不支持的加密方式: " + encryptType);
}
// AES 必须 16倍数
if (dataUnitLength % 16 != 0) {
throw new IllegalStateException(
"AES密文长度非法不是16倍数length=" + dataUnitLength);
}
// 11. AES解密
byte[] aesKey = generateKeyFromSn(deviceSn);
byte[] decrypted = decryptData(dataUnit, aesKey);
return bytesToHex(decrypted);
} }
*/
private static void parseDecryptedDataUnit(byte[] decryptedData) { private static void parseDecryptedDataUnit(byte[] decryptedData) {
log.info("\n=== 数据单元解析 ==="); log.info("\n=== 数据单元解析 ===");
if (decryptedData == null || decryptedData.length == 0) { if (decryptedData == null || decryptedData.length == 0) {
log.info("解密数据为空"); log.info("解密数据为空");
return; return;
} }
log.info("数据单元总长度: " + decryptedData.length + " 字节"); log.info("数据单元总长度: " + decryptedData.length + " 字节");
log.info("数据单元内容: " + bytesToHex(decryptedData)); log.info("数据单元内容: " + bytesToHex(decryptedData));
// 尝试解析采集时间(前6字节BCD) // 尝试解析采集时间(前6字节BCD)
if (decryptedData.length >= 6) { if (decryptedData.length >= 6) {
@ -280,16 +368,26 @@ public class GBT32960FullDecoder {
private static String typeName(int typeId) { private static String typeName(int typeId) {
switch (typeId & 0xFF) { switch (typeId & 0xFF) {
case 0x01: return "整车数据"; case 0x01:
case 0x02: return "驱动电机数据"; return "整车数据";
case 0x03: return "燃料电池数据"; case 0x02:
case 0x04: return "发动机数据"; return "驱动电机数据";
case 0x05: return "车辆位置数据"; case 0x03:
case 0x06: return "极值数据"; return "燃料电池数据";
case 0x07: return "报警数据"; case 0x04:
case 0x08: return "储能装置电压数据"; return "发动机数据";
case 0x09: return "储能装置温度数据"; case 0x05:
default: return String.format("未知类型(0x%02X)", typeId); return "车辆位置数据";
case 0x06:
return "极值数据";
case 0x07:
return "报警数据";
case 0x08:
return "储能装置电压数据";
case 0x09:
return "储能装置温度数据";
default:
return String.format("未知类型(0x%02X)", typeId);
} }
} }

View File

@ -5,6 +5,8 @@ import com.evobms.common.constant.Constants;
import com.evobms.common.constant.BboxApiConstants; import com.evobms.common.constant.BboxApiConstants;
import com.evobms.common.utils.StringUtils; import com.evobms.common.utils.StringUtils;
import com.evobms.project.bms.service.MqttService; import com.evobms.project.bms.service.MqttService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -25,6 +27,7 @@ import org.slf4j.LoggerFactory;
*/ */
@RestController @RestController
@RequestMapping("/bms/mqtt") @RequestMapping("/bms/mqtt")
@Api(tags = "MQTT消息发布")
public class MqttPublishController { public class MqttPublishController {
private static final Logger log = LoggerFactory.getLogger(MqttPublishController.class); private static final Logger log = LoggerFactory.getLogger(MqttPublishController.class);
@ -39,6 +42,7 @@ public class MqttPublishController {
*/ */
@PostMapping("/publish") @PostMapping("/publish")
// @Log(title = "MQTT消息发布", businessType = BusinessType.INSERT) // @Log(title = "MQTT消息发布", businessType = BusinessType.INSERT)
@ApiOperation("发布文本消息")
public AjaxResult publishMessage(@RequestParam String topic, @RequestParam String message) { public AjaxResult publishMessage(@RequestParam String topic, @RequestParam String message) {
try { try {
if (mqttService == null) { if (mqttService == null) {
@ -58,6 +62,7 @@ public class MqttPublishController {
* 发布原始十六进制字节消息到指定主题 * 发布原始十六进制字节消息到指定主题
*/ */
@PostMapping("/publishHex") @PostMapping("/publishHex")
@ApiOperation("发布HEX消息")
public AjaxResult publishHex(@RequestParam String topic, @RequestParam String hex) { public AjaxResult publishHex(@RequestParam String topic, @RequestParam String hex) {
try { try {
if (mqttService == null) { if (mqttService == null) {
@ -78,6 +83,7 @@ public class MqttPublishController {
* 获取当前请求的鉴权令牌从请求头读取并去除前缀 * 获取当前请求的鉴权令牌从请求头读取并去除前缀
*/ */
@GetMapping("/authToken") @GetMapping("/authToken")
@ApiOperation("获取鉴权令牌")
public AjaxResult getAuthToken(HttpServletRequest request) { public AjaxResult getAuthToken(HttpServletRequest request) {
try { try {
String raw = request.getHeader(tokenHeader); String raw = request.getHeader(tokenHeader);
@ -129,6 +135,7 @@ public class MqttPublishController {
*/ */
@PostMapping("/publishDeviceData") @PostMapping("/publishDeviceData")
// @Log(title = "设备数据发布", businessType = BusinessType.INSERT) // @Log(title = "设备数据发布", businessType = BusinessType.INSERT)
@ApiOperation("发布设备测试数据")
public AjaxResult publishDeviceData(@RequestParam String deviceCode) { public AjaxResult publishDeviceData(@RequestParam String deviceCode) {
try { try {
if (mqttService == null) { if (mqttService == null) {
@ -160,6 +167,7 @@ public class MqttPublishController {
* 快速测试 - 发布消息到test设备 * 快速测试 - 发布消息到test设备
*/ */
@GetMapping("/quickTest") @GetMapping("/quickTest")
@ApiOperation("快速测试发布")
public AjaxResult quickTest() { public AjaxResult quickTest() {
try { try {
if (mqttService == null) { if (mqttService == null) {
@ -192,6 +200,7 @@ public class MqttPublishController {
*/ */
@PostMapping("/batchPublish") @PostMapping("/batchPublish")
// @Log(title = "批量MQTT消息发布", businessType = BusinessType.INSERT) // @Log(title = "批量MQTT消息发布", businessType = BusinessType.INSERT)
@ApiOperation("批量发布测试消息")
public AjaxResult batchPublish(@RequestParam String deviceCode, @RequestParam(defaultValue = "5") int count) { public AjaxResult batchPublish(@RequestParam String deviceCode, @RequestParam(defaultValue = "5") int count) {
try { try {
if (mqttService == null) { if (mqttService == null) {

View File

@ -1,6 +1,8 @@
package com.evobms.project.bms.controller; package com.evobms.project.bms.controller;
import com.evobms.project.bms.service.MqttService; import com.evobms.project.bms.service.MqttService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -17,6 +19,7 @@ import java.util.Map;
*/ */
@RestController @RestController
@RequestMapping("/mqtt/test") @RequestMapping("/mqtt/test")
@Api(tags = "MQTT测试")
public class MqttTestController { public class MqttTestController {
private static final Logger log = LoggerFactory.getLogger(MqttTestController.class); private static final Logger log = LoggerFactory.getLogger(MqttTestController.class);
@ -31,6 +34,7 @@ public class MqttTestController {
* @return 测试结果 * @return 测试结果
*/ */
@PostMapping("/handleDeviceData") @PostMapping("/handleDeviceData")
@ApiOperation("测试处理设备数据")
public Map<String, Object> testHandleDeviceData( public Map<String, Object> testHandleDeviceData(
@RequestParam String topic, @RequestParam String topic,
@RequestParam byte[] payload) { @RequestParam byte[] payload) {
@ -70,6 +74,7 @@ public class MqttTestController {
* @return 测试用的JSON数据 * @return 测试用的JSON数据
*/ */
@GetMapping("/generateTestData") @GetMapping("/generateTestData")
@ApiOperation("生成测试数据")
public Map<String, Object> generateTestData() { public Map<String, Object> generateTestData() {
Map<String, Object> testData = new HashMap<>(); Map<String, Object> testData = new HashMap<>();
testData.put("voltage", 12.5); testData.put("voltage", 12.5);

View File

@ -0,0 +1,75 @@
package com.evobms.project.bms.domain;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import com.evobms.framework.aspectj.lang.annotation.Excel;
import com.evobms.framework.web.domain.BaseEntity;
@Data
@ApiModel(description = "BMS充电过程详细数据")
public class BmsChargeDetail extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键ID")
private Long id;
@ApiModelProperty("设备ID")
@Excel(name = "设备ID")
private String deviceId;
@ApiModelProperty("数据时间戳")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date timestamp;
@ApiModelProperty("慢充电流(A)")
@Excel(name = "慢充电流(A)")
private java.math.BigDecimal acChargeCurrent;
@ApiModelProperty("慢充电压(V)")
@Excel(name = "慢充电压(V)")
private java.math.BigDecimal acChargeVoltage;
@ApiModelProperty("快充电流(A)")
@Excel(name = "快充电流(A)")
private java.math.BigDecimal dcChargeCurrent;
@ApiModelProperty("快充电压(V)")
@Excel(name = "快充电压(V)")
private java.math.BigDecimal dcChargeVoltage;
@ApiModelProperty("充电时长(min)")
@Excel(name = "充电时长(min)")
private Integer chargeTime;
@ApiModelProperty("慢充停止码")
@Excel(name = "慢充停止码")
private Integer acStopCode;
@ApiModelProperty("快充停止码")
@Excel(name = "快充停止码")
private Integer dcStopCode;
@ApiModelProperty("慢充CP值")
@Excel(name = "慢充CP值")
private Integer acCpValue;
@ApiModelProperty("慢充枪阻值")
@Excel(name = "慢充枪阻值")
private Integer acGunResistance;
@ApiModelProperty("充电阶段")
@Excel(name = "充电阶段")
private Integer chargingStage;
@ApiModelProperty("慢充阶段")
@Excel(name = "慢充阶段")
private Integer acStage;
@ApiModelProperty("快充阶段")
@Excel(name = "快充阶段")
private Integer dcStage;
}

View File

@ -0,0 +1,67 @@
package com.evobms.project.bms.domain;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import com.evobms.framework.aspectj.lang.annotation.Excel;
import com.evobms.framework.web.domain.BaseEntity;
@Data
@ApiModel(description = "BMS功率能力(SOP)数据")
public class BmsSopData extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键ID")
private Long id;
@ApiModelProperty("设备ID")
@Excel(name = "设备ID")
private String deviceId;
@ApiModelProperty("数据时间戳")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date timestamp;
@ApiModelProperty("10秒放电SOP(A)")
@Excel(name = "10秒放电SOP(A)")
private Integer dischargeSop10s;
@ApiModelProperty("30秒放电SOP(A)")
@Excel(name = "30秒放电SOP(A)")
private Integer dischargeSop30s;
@ApiModelProperty("60秒放电SOP(A)")
@Excel(name = "60秒放电SOP(A)")
private Integer dischargeSop60s;
@ApiModelProperty("持续放电SOP(A)")
@Excel(name = "持续放电SOP(A)")
private Integer dischargeSopContinuous;
@ApiModelProperty("10秒回馈SOP(A)")
@Excel(name = "10秒回馈SOP(A)")
private Integer regenSop10s;
@ApiModelProperty("30秒回馈SOP(A)")
@Excel(name = "30秒回馈SOP(A)")
private Integer regenSop30s;
@ApiModelProperty("60秒回馈SOP(A)")
@Excel(name = "60秒回馈SOP(A)")
private Integer regenSop60s;
@ApiModelProperty("持续回馈SOP(A)")
@Excel(name = "持续回馈SOP(A)")
private Integer regenSopContinuous;
@ApiModelProperty("充电SOP(A)")
@Excel(name = "充电SOP(A)")
private Integer chargeSop;
@ApiModelProperty("慢充SOP(A)")
@Excel(name = "慢充SOP(A)")
private Integer acChargeSop;
}

View File

@ -0,0 +1,59 @@
package com.evobms.project.bms.domain;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import com.evobms.framework.aspectj.lang.annotation.Excel;
import com.evobms.framework.web.domain.BaseEntity;
@Data
@ApiModel(description = "BMS系统状态数据")
public class BmsSystemStatus extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键ID")
private Long id;
@ApiModelProperty("设备ID")
@Excel(name = "设备ID")
private String deviceId;
@ApiModelProperty("数据时间戳")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date timestamp;
@ApiModelProperty("继电器状态")
@Excel(name = "继电器状态")
private Integer relayStatus;
@ApiModelProperty("ON/A+/CC状态")
@Excel(name = "ON/A+/CC状态")
private Integer onaaccStatus;
@ApiModelProperty("系统复位次数")
@Excel(name = "系统复位次数")
private Integer resetCount;
@ApiModelProperty("电池循环次数")
@Excel(name = "电池循环次数")
private Integer cycleCount;
@ApiModelProperty("2.5V采样电压(V)")
@Excel(name = "2.5V采样电压(V)")
private java.math.BigDecimal sample25v;
@ApiModelProperty("5V采样电压(V)")
@Excel(name = "5V采样电压(V)")
private java.math.BigDecimal sample5v;
@ApiModelProperty("单体数量")
@Excel(name = "单体数量")
private Integer cellCount;
@ApiModelProperty("温度探头数量")
@Excel(name = "温度探头数量")
private Integer tempSensorCount;
}

View File

@ -0,0 +1,9 @@
package com.evobms.project.bms.mapper;
import com.evobms.project.bms.domain.BmsChargeDetail;
import java.util.List;
public interface BmsChargeDetailMapper {
int insertBmsChargeDetail(BmsChargeDetail data);
List<BmsChargeDetail> selectBmsChargeDetailList(BmsChargeDetail filter);
}

View File

@ -0,0 +1,9 @@
package com.evobms.project.bms.mapper;
import com.evobms.project.bms.domain.BmsSopData;
import java.util.List;
public interface BmsSopDataMapper {
int insertBmsSopData(BmsSopData data);
List<BmsSopData> selectBmsSopDataList(BmsSopData filter);
}

View File

@ -0,0 +1,9 @@
package com.evobms.project.bms.mapper;
import com.evobms.project.bms.domain.BmsSystemStatus;
import java.util.List;
public interface BmsSystemStatusMapper {
int insertBmsSystemStatus(BmsSystemStatus data);
List<BmsSystemStatus> selectBmsSystemStatusList(BmsSystemStatus filter);
}

View File

@ -0,0 +1,7 @@
package com.evobms.project.bms.service;
import com.evobms.project.bms.domain.BmsChargeDetail;
public interface IBmsChargeDetailService {
int insertBmsChargeDetail(BmsChargeDetail data);
}

View File

@ -0,0 +1,7 @@
package com.evobms.project.bms.service;
import com.evobms.project.bms.domain.BmsSopData;
public interface IBmsSopDataService {
int insertBmsSopData(BmsSopData data);
}

View File

@ -0,0 +1,7 @@
package com.evobms.project.bms.service;
import com.evobms.project.bms.domain.BmsSystemStatus;
public interface IBmsSystemStatusService {
int insertBmsSystemStatus(BmsSystemStatus data);
}

View File

@ -261,30 +261,32 @@ public class MqttService {
*/ */
private void parseByProtocolIndex(byte[] message, String deviceSn) { private void parseByProtocolIndex(byte[] message, String deviceSn) {
try { try {
// 1. 时间信息 - 索引24-29 (6字节) // 1.时间戳- 索引24-29 (6字节)
Date frameTime = parseTimeAtIndex(message, 0, deviceSn); Date frameTime = parseTimeAtIndex(message, 0, deviceSn);
if (frameTime == null) { if (frameTime == null) {
frameTime = new Date(); frameTime = new Date();
} }
// 2. 整车数据 - 索引30-49 (20字节) // 2. 整车数据 - 绝对索引30-49(20字节) | 相对偏移: 6-25
parseVehicleDataAtIndex(message, 6, deviceSn, frameTime); parseVehicleDataAtIndex(message, 6, deviceSn, frameTime);
// 3. 位置信息 - 索引51-60 (10字节) // 3. 位置信息 - 绝对索引51-60(10字节) | 相对偏移: 27-36
parseLocationDataAtIndex(message, 27, deviceSn, frameTime); parseLocationDataAtIndex(message, 27, deviceSn, frameTime);
// 4. 极值数据 - 索引61-75 (14字节) // 4. 极值数据 - 绝对索引61-75(15字节) | 相对偏移: 37-51
parseExtremeDataAtIndex(message, 37, deviceSn, frameTime); parseExtremeDataAtIndex(message, 37, deviceSn, frameTime);
// 5. 单体电压数据 - 索引76-447 (372字节) // 5. 单体电压数据 - 绝对索引76-447(372字节) | 相对偏移: 52-423
parseCellVoltageAtIndex(message, 52, deviceSn, frameTime); parseCellVoltageAtIndex(message, 52, deviceSn, frameTime);
// 6. 单体温度数据 - 索引448-542 (95字节) // 6. 单体温度数据 - 绝对索引448-542(95字节) | 相对偏移: 424-518
parseCellTemperatureAtIndex(message, 424, deviceSn, frameTime); parseCellTemperatureAtIndex(message, 424, deviceSn, frameTime);
// 7. 累计充放电量 - 索引543-553 (11字节) // 7. 累计充放电量 - 绝对索引543-553(11字节) | 相对偏移: 519-529
parseChargeDischargeAtIndex(message, 519, deviceSn, frameTime); parseChargeDischargeAtIndex(message, 519, deviceSn, frameTime);
parseExtendedDataAtIndex(message, 506, deviceSn, frameTime);
log.info("设备 {} 所有数据段解析完成", deviceSn); log.info("设备 {} 所有数据段解析完成", deviceSn);
} catch (Exception e) { } catch (Exception e) {
@ -293,7 +295,7 @@ public class MqttService {
} }
/** /**
* 解析时间信息 - 索引24-29 (6字节) * 解析时间信息 - 绝对索引24-29(6字节) | 相对偏移: 0-5
* 格式: (偏移2000) + + + + + * 格式: (偏移2000) + + + + +
*/ */
private Date parseTimeAtIndex(byte[] message, int startIndex, String deviceSn) { private Date parseTimeAtIndex(byte[] message, int startIndex, String deviceSn) {
@ -330,7 +332,7 @@ public class MqttService {
} }
/** /**
* 解析整车数据 - 索引30-49 (20字节) * 解析整车数据 - 绝对索引30-49(20字节) | 相对偏移: 6-25
*/ */
private void parseVehicleDataAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) { private void parseVehicleDataAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
try { try {
@ -381,7 +383,7 @@ public class MqttService {
/** /**
* 解析位置信息 - 索引51-60 (10字节) * 解析位置信息 - 绝对索引51-60(10字节) | 相对偏移: 27-36
*/ */
private void parseLocationDataAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) { private void parseLocationDataAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
try { try {
@ -431,7 +433,7 @@ public class MqttService {
} }
/** /**
* 解析极值数据 - 索引61-75 (14字节) * 解析极值数据 - 绝对索引61-75(15字节) | 相对偏移: 37-51
*/ */
private void parseExtremeDataAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) { private void parseExtremeDataAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
try { try {
@ -492,7 +494,7 @@ public class MqttService {
/** /**
* 解析单体电压数据 - 索引76-447 (372字节) * 解析单体电压数据 - 绝对索引76-447(372字节) | 相对偏移: 52-423
*/ */
private void parseCellVoltageAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) { private void parseCellVoltageAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
try { try {
@ -575,7 +577,7 @@ public class MqttService {
/** /**
* 解析单体温度数据 - 索引448-542 (95字节) * 解析单体温度数据 - 绝对索引448-542(95字节) | 相对偏移: 424-518
*/ */
private void parseCellTemperatureAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) { private void parseCellTemperatureAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
try { try {
@ -638,7 +640,7 @@ public class MqttService {
} }
/** /**
* 解析累计充放电量 - 索引543-553 (11字节) * 解析累计充放电量 - 绝对索引543-553(11字节) | 相对偏移: 519-529
*/ */
private void parseChargeDischargeAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) { private void parseChargeDischargeAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
try { try {
@ -646,7 +648,6 @@ public class MqttService {
log.warn("设备 {}: 充放电数据索引越界", deviceSn); log.warn("设备 {}: 充放电数据索引越界", deviceSn);
return; return;
} }
// 索引543: 数据标识 (应该是0x80) // 索引543: 数据标识 (应该是0x80)
byte dataFlag = message[startIndex]; byte dataFlag = message[startIndex];
if (dataFlag != (byte) 0x80) { if (dataFlag != (byte) 0x80) {
@ -658,16 +659,10 @@ public class MqttService {
// 跳过索引544-545的保留字节 // 跳过索引544-545的保留字节
// 索引546-549: 累计放电电量 (0.1kWh) // 索引546-549: 累计放电电量 (0.1kWh)
long dischargeEnergy = ((message[startIndex + 3] & 0xFFL) << 24) | long dischargeEnergy = ((message[startIndex + 3] & 0xFFL) << 24) | ((message[startIndex + 4] & 0xFFL) << 16) | ((message[startIndex + 5] & 0xFFL) << 8) | (message[startIndex + 6] & 0xFFL);
((message[startIndex + 4] & 0xFFL) << 16) |
((message[startIndex + 5] & 0xFFL) << 8) |
(message[startIndex + 6] & 0xFFL);
// 索引550-553: 累计充电电量 (0.1kWh) // 索引550-553: 累计充电电量 (0.1kWh)
long chargeEnergy = ((message[startIndex + 7] & 0xFFL) << 24) | long chargeEnergy = ((message[startIndex + 7] & 0xFFL) << 24) |((message[startIndex + 8] & 0xFFL) << 16) | ((message[startIndex + 9] & 0xFFL) << 8) | (message[startIndex + 10] & 0xFFL);
((message[startIndex + 8] & 0xFFL) << 16) |
((message[startIndex + 9] & 0xFFL) << 8) |
(message[startIndex + 10] & 0xFFL);
double dischargeKwh = dischargeEnergy * 0.1; double dischargeKwh = dischargeEnergy * 0.1;
double chargeKwh = chargeEnergy * 0.1; double chargeKwh = chargeEnergy * 0.1;
@ -944,6 +939,132 @@ public class MqttService {
sendDeviceCommand(deviceCode, "STATUS_QUERY"); sendDeviceCommand(deviceCode, "STATUS_QUERY");
} }
/**
* 扩展区块解析BatteryData[530..716]
* 索引换算: 绝对索引abs message索引 = startIndex + (abs - 530)
* 单位与偏移:
* - 电压/电流 ×0.1除特殊 2.5V/5V 采样为 ×0.001
* - 温度值需减去 40协议偏移
* - 车速 ×0.1 km/h
* - 里程为 u32 原始值单位由上位业务确定
*/
private void parseExtendedDataAtIndex(byte[] message, int startIndex, String deviceSn, Date frameTime) {
try {
int base = startIndex;
int need = (716 - 530 + 1);
if (message.length < base + need) {
log.warn("设备 {}: 扩展数据索引越界", deviceSn);
return;
}
// 系统计数/绝缘/车速/总压
long resetCount = ((message[base + 0] & 0xFFL) << 24) | ((message[base + 1] & 0xFFL) << 16) | ((message[base + 2] & 0xFFL) << 8) | (message[base + 3] & 0xFFL); // 复位次数(u32)
int insulationVal = ((message[base + 4] & 0xFF) << 8) | (message[base + 5] & 0xFF); // 绝缘值(单位KΩ)
int carSpdRaw = ((message[base + 6] & 0xFF) << 8) | (message[base + 7] & 0xFF); // 车速原始(×0.1km/h)
double carSpd = carSpdRaw * 0.1;
int gpvRaw = ((message[base + 8] & 0xFF) << 8) | (message[base + 9] & 0xFF); // GPV(×0.1V)
double gpv = gpvRaw * 0.1;
// RTP1..7(×0.1V)
double rtp1 = (((message[base + 10] & 0xFF) << 8) | (message[base + 11] & 0xFF)) * 0.1;
double rtp2 = (((message[base + 12] & 0xFF) << 8) | (message[base + 13] & 0xFF)) * 0.1;
double rtp3 = (((message[base + 14] & 0xFF) << 8) | (message[base + 15] & 0xFF)) * 0.1;
double rtp4 = (((message[base + 16] & 0xFF) << 8) | (message[base + 17] & 0xFF)) * 0.1;
double rtp5 = (((message[base + 18] & 0xFF) << 8) | (message[base + 19] & 0xFF)) * 0.1;
double rtp6 = (((message[base + 20] & 0xFF) << 8) | (message[base + 21] & 0xFF)) * 0.1;
double rtp7 = (((message[base + 22] & 0xFF) << 8) | (message[base + 23] & 0xFF)) * 0.1;
// RTN探针序号
int rtn1 = message[base + 24] & 0xFF; // RTN1
int rtn2 = message[base + 25] & 0xFF; // RTN2
int rtn3 = message[base + 26] & 0xFF; // RTN3
int rtn4 = message[base + 27] & 0xFF; // RTN4
double realSocMax = (((message[base + 28] & 0xFF) << 8) | (message[base + 29] & 0xFF)) * 0.1; // RealSOC最大(×0.1%)
double realSocMin = (((message[base + 30] & 0xFF) << 8) | (message[base + 31] & 0xFF)) * 0.1; // RealSOC最小(×0.1%)
// 充电座温度(需减40)
int chgBs1Tmp = (message[base + 32] & 0xFF) - 40;
int chgBs2Tmp = (message[base + 33] & 0xFF) - 40;
int chgBs3Tmp = (message[base + 34] & 0xFF) - 40;
int chgBs4Tmp = (message[base + 35] & 0xFF) - 40;
int chgBs5Tmp = (message[base + 36] & 0xFF) - 40;
int chgBs6Tmp = (message[base + 37] & 0xFF) - 40;
int chgBs7Tmp = (message[base + 38] & 0xFF) - 40;
int chgBs8Tmp = (message[base + 39] & 0xFF) - 40;
// 慢充/快充电流电压(×0.1)
double tChgCur = (((message[base + 40] & 0xFF) << 8) | (message[base + 41] & 0xFF)) * 0.1; // 慢充电流(A)
double tChgVol = (((message[base + 42] & 0xFF) << 8) | (message[base + 43] & 0xFF)) * 0.1; // 慢充电压(V)
double fChgCur = (((message[base + 44] & 0xFF) << 8) | (message[base + 45] & 0xFF)) * 0.1; // 快充电流(A)
double fChgVol = (((message[base + 46] & 0xFF) << 8) | (message[base + 47] & 0xFF)) * 0.1; // 快充电压(V)
// 放电/回馈SOP能力(A)
int disSop10 = ((message[base + 48] & 0xFF) << 8) | (message[base + 49] & 0xFF);
int disSop30 = ((message[base + 50] & 0xFF) << 8) | (message[base + 51] & 0xFF);
int disSop60 = ((message[base + 52] & 0xFF) << 8) | (message[base + 53] & 0xFF);
int disSopCont = ((message[base + 54] & 0xFF) << 8) | (message[base + 55] & 0xFF);
int regSop10 = ((message[base + 56] & 0xFF) << 8) | (message[base + 57] & 0xFF);
int regSop30 = ((message[base + 58] & 0xFF) << 8) | (message[base + 59] & 0xFF);
int regSop60 = ((message[base + 60] & 0xFF) << 8) | (message[base + 61] & 0xFF);
int regSopCont = ((message[base + 62] & 0xFF) << 8) | (message[base + 63] & 0xFF);
int disSopTol = ((message[base + 64] & 0xFF) << 8) | (message[base + 65] & 0xFF);
int regSopTol = ((message[base + 66] & 0xFF) << 8) | (message[base + 67] & 0xFF);
// 版本与编码
int hwVer = ((message[base + 68] & 0xFF) << 8) | (message[base + 69] & 0xFF); // 硬件版本
int swVer = ((message[base + 70] & 0xFF) << 8) | (message[base + 71] & 0xFF); // 软件版本
String bmsCode = readAsciiRange(message, 602, 28, base); // BMS编码(28字节ASCII)
String vin = readAsciiRange(message, 629, 21, base); // VIN码(21字节ASCII)
// 系统状态
int sysVolRaw = ((message[base + (649 - 530)] & 0xFF) << 8) | (message[base + (650 - 530)] & 0xFF); // 系统电压(×0.1V)
int sysCurRaw = ((message[base + (651 - 530)] & 0xFF) << 8) | (message[base + (652 - 530)] & 0xFF); // 系统电流(×0.1A)
double sysVol = sysVolRaw * 0.1;
double sysCur = sysCurRaw * 0.1;
int cellCount = ((message[base + (653 - 530)] & 0xFF) << 8) | (message[base + (654 - 530)] & 0xFF);
int tempSensorCount = ((message[base + (655 - 530)] & 0xFF) << 8) | (message[base + (656 - 530)] & 0xFF);
int relayStatus = ((message[base + (657 - 530)] & 0xFF) << 8) | (message[base + (658 - 530)] & 0xFF);
int onaaccStatus = ((message[base + (659 - 530)] & 0xFF) << 8) | (message[base + (660 - 530)] & 0xFF);
int acStopCode = message[base + (661 - 530)] & 0xFF;
int dcStopCode = message[base + (662 - 530)] & 0xFF;
int cycleCount = ((message[base + (663 - 530)] & 0xFF) << 8) | (message[base + (664 - 530)] & 0xFF);
long devId = ((message[base + (665 - 530)] & 0xFFL) << 24) | ((message[base + (666 - 530)] & 0xFFL) << 16) | ((message[base + (667 - 530)] & 0xFFL) << 8) | (message[base + (668 - 530)] & 0xFFL);
String clientCode = readAsciiRange(message, 669, 28, base); // 客户编码(28字节ASCII)
double samp25v = (((message[base + (696 - 530)] & 0xFF) << 8) | (message[base + (697 - 530)] & 0xFF)) * 0.001; // 2.5V采样(×0.001V)
double samp5v = (((message[base + (698 - 530)] & 0xFF) << 8) | (message[base + (699 - 530)] & 0xFF)) * 0.001; // 5V采样(×0.001V)
int chargeSop = ((message[base + (700 - 530)] & 0xFF) << 8) | (message[base + (701 - 530)] & 0xFF); // 充电SOP(A)
int acChargeSop = ((message[base + (702 - 530)] & 0xFF) << 8) | (message[base + (703 - 530)] & 0xFF); // 慢充SOP(A)
// 运行阶段/充电阶段/时间与里程
int runSts = message[base + (704 - 530)] & 0xFF; // 行车阶段
int runPwrSts = message[base + (705 - 530)] & 0xFF; // 行车上电阶段
int tChgCp = message[base + (706 - 530)] & 0xFF; // 慢充CP值
int tChgR = message[base + (707 - 530)] & 0xFF; // 慢充枪阻值
int tChgSts = message[base + (708 - 530)] & 0xFF; // 慢充阶段
int fChgSts2 = message[base + (709 - 530)] & 0xFF; // 快充阶段
int chgSts = message[base + (710 - 530)] & 0xFF; // 充电阶段
int chgTime = ((message[base + (711 - 530)] & 0xFF) << 8) | (message[base + (712 - 530)] & 0xFF); // 充电时长(min)
long mileage = ((message[base + (713 - 530)] & 0xFFL) << 24) | ((message[base + (714 - 530)] & 0xFFL) << 16) | ((message[base + (715 - 530)] & 0xFFL) << 8) | (message[base + (716 - 530)] & 0xFFL); // 里程(u32)
log.info("设备 {} 扩展数据: resetCount={}, insulationValKOhm={}, carSpeedKmH={}, GPV0_1V={}, RTPs(V)=[{},{},{},{},{},{},{}], RTNs=[{},{},{},{}], realSOCMax0_1={}, realSOCMin0_1={}, chargeSeatTempsC=[{},{},{},{},{},{},{},{}]", deviceSn, resetCount, insulationVal, carSpd, gpv, rtp1, rtp2, rtp3, rtp4, rtp5, rtp6, rtp7, rtn1, rtn2, rtn3, rtn4, realSocMax, realSocMin, chgBs1Tmp, chgBs2Tmp, chgBs3Tmp, chgBs4Tmp, chgBs5Tmp, chgBs6Tmp, chgBs7Tmp, chgBs8Tmp);
log.info("设备 {} 充电详情: tChgCurA={}, tChgVolV={}, fChgCurA={}, fChgVolV={}, disSOP(A)=[{},{},{},{}], regSOP(A)=[{},{},{},{}], disSopTolA={}, regSopTolA={}", deviceSn, tChgCur, tChgVol, fChgCur, fChgVol, disSop10, disSop30, disSop60, disSopCont, regSop10, regSop30, regSop60, regSopCont, disSopTol, regSopTol);
log.info("设备 {} 版本与编码: hwVer={}, swVer={}, BMSCode='{}', VIN='{}', clientCode='{}', devId={}", deviceSn, hwVer, swVer, bmsCode, vin, clientCode, devId);
log.info("设备 {} 系统状态: sysVolV={}, sysCurA={}, cellCount={}, tempSensorCount={}, relayStatus={}, onaaccStatus={}, acStopCode={}, dcStopCode={}, cycleCount={}, samp25V={}, samp5V={}, chargeSopA={}, acChargeSopA={}", deviceSn, sysVol, sysCur, cellCount, tempSensorCount, relayStatus, onaaccStatus, acStopCode, dcStopCode, cycleCount, samp25v, samp5v, chargeSop, acChargeSop);
log.info("设备 {} 运行阶段: runSts={}, runPwrSts={}, tChgCp={}, tChgR={}, tChgSts={}, fChgSts={}, chgSts={}, chgTimeMin={}, mileage={}", deviceSn, runSts, runPwrSts, tChgCp, tChgR, tChgSts, fChgSts2, chgSts, chgTime, mileage);
} catch (Exception e) {
log.error("设备 {} 解析扩展数据时发生错误: {}", deviceSn, e.getMessage());
}
}
/**
* 读取 ASCII 字符串
* @param startAbs BatteryData 绝对索引(例如 602 对应 BMS编码起始)
* @param len 字节长度
* @param base 530 的映射起点message 中的 startIndex
*/
private String readAsciiRange(byte[] message, int startAbs, int len, int base) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i++) {
int idx = base + (startAbs - 530) + i;
if (idx >= 0 && idx < message.length) {
int b = message[idx] & 0xFF;
if (b != 0) {
sb.append((char) b);
}
}
}
return sb.toString().trim();
}
/** /**
* 根据设备唯一编号(deviceCode)查询系统设备表的SN码 * 根据设备唯一编号(deviceCode)查询系统设备表的SN码

View File

@ -0,0 +1,18 @@
package com.evobms.project.bms.service.impl;
import com.evobms.project.bms.domain.BmsChargeDetail;
import com.evobms.project.bms.mapper.BmsChargeDetailMapper;
import com.evobms.project.bms.service.IBmsChargeDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BmsChargeDetailServiceImpl implements IBmsChargeDetailService {
@Autowired
private BmsChargeDetailMapper mapper;
@Override
public int insertBmsChargeDetail(BmsChargeDetail data) {
return mapper.insertBmsChargeDetail(data);
}
}

View File

@ -0,0 +1,18 @@
package com.evobms.project.bms.service.impl;
import com.evobms.project.bms.domain.BmsSopData;
import com.evobms.project.bms.mapper.BmsSopDataMapper;
import com.evobms.project.bms.service.IBmsSopDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BmsSopDataServiceImpl implements IBmsSopDataService {
@Autowired
private BmsSopDataMapper mapper;
@Override
public int insertBmsSopData(BmsSopData data) {
return mapper.insertBmsSopData(data);
}
}

View File

@ -0,0 +1,18 @@
package com.evobms.project.bms.service.impl;
import com.evobms.project.bms.domain.BmsSystemStatus;
import com.evobms.project.bms.mapper.BmsSystemStatusMapper;
import com.evobms.project.bms.service.IBmsSystemStatusService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BmsSystemStatusServiceImpl implements IBmsSystemStatusService {
@Autowired
private BmsSystemStatusMapper mapper;
@Override
public int insertBmsSystemStatus(BmsSystemStatus data) {
return mapper.insertBmsSystemStatus(data);
}
}

View File

@ -13,6 +13,7 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.slf4j.MDC; import org.slf4j.MDC;
@ -52,7 +53,9 @@ import java.util.Map;
*/ */
@RestController @RestController
@Tag(name = "设备鉴权", description = "设备鉴权令牌接口") @Tag(name = "设备鉴权", description = "设备鉴权令牌接口")
@Api(tags = "IoT设备鉴权")
@RequestMapping("/iot") @RequestMapping("/iot")
@Slf4j
public class IotAuthController { public class IotAuthController {
private static final Logger log = LoggerFactory.getLogger(IotAuthController.class); private static final Logger log = LoggerFactory.getLogger(IotAuthController.class);
@ -96,11 +99,13 @@ public class IotAuthController {
*/ */
@PostMapping("/auth/token") @PostMapping("/auth/token")
@Operation(summary = "设备请求令牌", description = "通过SN码设备号版本信息生成TOKEN") @Operation(summary = "设备请求令牌", description = "通过SN码设备号版本信息生成TOKEN")
@ApiOperation("设备请求令牌")
public Map<String, Object> requestToken(@RequestBody Map<String, String> body) { public Map<String, Object> requestToken(@RequestBody Map<String, String> body) {
String sn = safeTrim(body.get("sn")); String sn = safeTrim(body.get("sn"));
String model = safeTrim(body.get("device")); String model = safeTrim(body.get("device"));
String version = safeTrim(body.get("version")); String version = safeTrim(body.get("version"));
log.info("设备请求:{}",body.toString());
log.info("sn:{}, device:{}, version:{}", sn, model, version);
MDC.put("sn", sn); MDC.put("sn", sn);
MDC.put("model", model); MDC.put("model", model);
MDC.put("version", version); MDC.put("version", version);
@ -388,6 +393,7 @@ public class IotAuthController {
*/ */
@GetMapping("/ota/{num}") @GetMapping("/ota/{num}")
@Operation(summary = "OTA固件分片下载", description = " OTA 固件分片下载接口") @Operation(summary = "OTA固件分片下载", description = " OTA 固件分片下载接口")
@ApiOperation("OTA固件分片下载")
public Object downloadOtaChunk(@PathVariable("num") String num, public Object downloadOtaChunk(@PathVariable("num") String num,
@RequestParam(value = "version", required = false) String version, @RequestParam(value = "version", required = false) String version,
HttpServletRequest request) { HttpServletRequest request) {

View File

@ -3,6 +3,8 @@ package com.evobms.project.iot.controller;
import com.evobms.common.constant.BboxApiConstants; import com.evobms.common.constant.BboxApiConstants;
import com.evobms.common.utils.StringUtils; import com.evobms.common.utils.StringUtils;
import com.evobms.project.iot.service.DeviceTokenService; import com.evobms.project.iot.service.DeviceTokenService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.slf4j.MDC; import org.slf4j.MDC;
@ -25,6 +27,7 @@ import java.util.Map;
*/ */
@RestController @RestController
@RequestMapping("/iot/ota") @RequestMapping("/iot/ota")
@Api(tags = "IoT OTA状态上报")
public class IotOtaController { public class IotOtaController {
private static final Logger log = LoggerFactory.getLogger(IotOtaController.class); private static final Logger log = LoggerFactory.getLogger(IotOtaController.class);
@ -32,6 +35,7 @@ public class IotOtaController {
private DeviceTokenService deviceTokenService; private DeviceTokenService deviceTokenService;
@PostMapping("/status") @PostMapping("/status")
@ApiOperation("上报OTA升级状态")
public Map<String, Object> reportOtaStatus(@RequestBody Map<String, String> body, public Map<String, Object> reportOtaStatus(@RequestBody Map<String, String> body,
HttpServletRequest request) { HttpServletRequest request) {
Map<String, Object> resp = new HashMap<>(); Map<String, Object> resp = new HashMap<>();

View File

@ -20,6 +20,8 @@ import com.evobms.framework.web.controller.BaseController;
import com.evobms.framework.web.domain.AjaxResult; import com.evobms.framework.web.domain.AjaxResult;
import com.evobms.common.utils.poi.ExcelUtil; import com.evobms.common.utils.poi.ExcelUtil;
import com.evobms.framework.web.page.TableDataInfo; import com.evobms.framework.web.page.TableDataInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/** /**
* OTA任务Controller * OTA任务Controller
@ -29,6 +31,7 @@ import com.evobms.framework.web.page.TableDataInfo;
*/ */
@RestController @RestController
@RequestMapping("/ota/tasks") @RequestMapping("/ota/tasks")
@Api(tags = "OTA任务管理")
public class OtaTasksController extends BaseController public class OtaTasksController extends BaseController
{ {
@Autowired @Autowired
@ -39,6 +42,7 @@ public class OtaTasksController extends BaseController
*/ */
//@PreAuthorize("@ss.hasPermi('OTA:tasks:list')") //@PreAuthorize("@ss.hasPermi('OTA:tasks:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询OTA任务列表")
public TableDataInfo list(OtaTasks otaTasks) public TableDataInfo list(OtaTasks otaTasks)
{ {
startPage(); startPage();
@ -52,6 +56,7 @@ public class OtaTasksController extends BaseController
//@PreAuthorize("@ss.hasPermi('OTA:tasks:export')") //@PreAuthorize("@ss.hasPermi('OTA:tasks:export')")
@Log(title = "OTA任务", businessType = BusinessType.EXPORT) @Log(title = "OTA任务", businessType = BusinessType.EXPORT)
@PostMapping("/export") @PostMapping("/export")
@ApiOperation("导出OTA任务列表")
public void export(HttpServletResponse response, OtaTasks otaTasks) public void export(HttpServletResponse response, OtaTasks otaTasks)
{ {
List<OtaTasks> list = otaTasksService.selectOtaTasksList(otaTasks); List<OtaTasks> list = otaTasksService.selectOtaTasksList(otaTasks);
@ -64,6 +69,7 @@ public class OtaTasksController extends BaseController
*/ */
//@PreAuthorize("@ss.hasPermi('OTA:tasks:query')") //@PreAuthorize("@ss.hasPermi('OTA:tasks:query')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取OTA任务详细信息")
public AjaxResult getInfo(@PathVariable("id") String id) public AjaxResult getInfo(@PathVariable("id") String id)
{ {
return success(otaTasksService.selectOtaTasksById(id)); return success(otaTasksService.selectOtaTasksById(id));
@ -75,6 +81,7 @@ public class OtaTasksController extends BaseController
//@PreAuthorize("@ss.hasPermi('OTA:tasks:add')") //@PreAuthorize("@ss.hasPermi('OTA:tasks:add')")
@Log(title = "OTA任务", businessType = BusinessType.INSERT) @Log(title = "OTA任务", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
@ApiOperation("新增OTA任务")
public AjaxResult add(@RequestBody OtaTasks otaTasks) public AjaxResult add(@RequestBody OtaTasks otaTasks)
{ {
return toAjax(otaTasksService.insertOtaTasks(otaTasks)); return toAjax(otaTasksService.insertOtaTasks(otaTasks));
@ -86,6 +93,7 @@ public class OtaTasksController extends BaseController
//@PreAuthorize("@ss.hasPermi('OTA:tasks:edit')") //@PreAuthorize("@ss.hasPermi('OTA:tasks:edit')")
@Log(title = "OTA任务", businessType = BusinessType.UPDATE) @Log(title = "OTA任务", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
@ApiOperation("修改OTA任务")
public AjaxResult edit(@RequestBody OtaTasks otaTasks) public AjaxResult edit(@RequestBody OtaTasks otaTasks)
{ {
return toAjax(otaTasksService.updateOtaTasks(otaTasks)); return toAjax(otaTasksService.updateOtaTasks(otaTasks));
@ -96,6 +104,7 @@ public class OtaTasksController extends BaseController
*/ */
@Log(title = "OTA任务", businessType = BusinessType.DELETE) @Log(title = "OTA任务", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}") @DeleteMapping("/{ids}")
@ApiOperation("删除OTA任务")
public AjaxResult remove(@PathVariable String[] ids) public AjaxResult remove(@PathVariable String[] ids)
{ {
return toAjax(otaTasksService.deleteOtaTasksByIds(ids)); return toAjax(otaTasksService.deleteOtaTasksByIds(ids));

View File

@ -1,7 +1,11 @@
package com.evobms.project.ota.domain; package com.evobms.project.ota.domain;
import java.util.Date; import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import com.evobms.framework.aspectj.lang.annotation.Excel; import com.evobms.framework.aspectj.lang.annotation.Excel;
@ -9,157 +13,62 @@ import com.evobms.framework.web.domain.BaseEntity;
/** /**
* OTA任务对象 ota_tasks * OTA任务对象 ota_tasks
* *
* @author ruoyi * @author ruoyi
* @date 2025-10-14 * @date 2025-10-14
*/ */
@EqualsAndHashCode(callSuper = true)
@ApiModel(description = "OTA任务对象")
@Data
public class OtaTasks extends BaseEntity public class OtaTasks extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 任务IDUUID */ /** 任务IDUUID */
@ApiModelProperty(value = "任务IDUUID")
private String id; private String id;
/** 设备ID */ /** 设备ID */
@ApiModelProperty(value = "设备ID")
@Excel(name = "设备ID") @Excel(name = "设备ID")
private String deviceId; private String deviceId;
/** 任务名称 */ /** 任务名称 */
@ApiModelProperty(value = "任务名称")
@Excel(name = "任务名称") @Excel(name = "任务名称")
private String taskName; private String taskName;
/** 目标固件版本 */ /** 目标固件版本 */
@ApiModelProperty(value = "目标固件版本")
@Excel(name = "目标固件版本") @Excel(name = "目标固件版本")
private String firmwareVersion; private String firmwareVersion;
/** 任务状态 */ /** 任务状态 */
@ApiModelProperty(value = "任务状态")
@Excel(name = "任务状态") @Excel(name = "任务状态")
private String status; private String status;
/** 升级进度(0-100) */ /** 升级进度(0-100) */
@ApiModelProperty(value = "升级进度(0-100)")
@Excel(name = "升级进度(0-100)") @Excel(name = "升级进度(0-100)")
private Long progress; private Long progress;
/** 开始时间 */ /** 开始时间 */
@ApiModelProperty(value = "开始时间")
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date startTime; private Date startTime;
/** 结束时间 */ /** 结束时间 */
@ApiModelProperty(value = "结束时间")
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date endTime; private Date endTime;
/** 错误信息 */ /** 错误信息 */
@ApiModelProperty(value = "错误信息")
@Excel(name = "错误信息") @Excel(name = "错误信息")
private String errorMessage; private String errorMessage;
public void setId(String id)
{
this.id = id;
}
public String getId()
{
return id;
}
public void setDeviceId(String deviceId)
{
this.deviceId = deviceId;
}
public String getDeviceId()
{
return deviceId;
}
public void setTaskName(String taskName)
{
this.taskName = taskName;
}
public String getTaskName()
{
return taskName;
}
public void setFirmwareVersion(String firmwareVersion)
{
this.firmwareVersion = firmwareVersion;
}
public String getFirmwareVersion()
{
return firmwareVersion;
}
public void setStatus(String status)
{
this.status = status;
}
public String getStatus()
{
return status;
}
public void setProgress(Long progress)
{
this.progress = progress;
}
public Long getProgress()
{
return progress;
}
public void setStartTime(Date startTime)
{
this.startTime = startTime;
}
public Date getStartTime()
{
return startTime;
}
public void setEndTime(Date endTime)
{
this.endTime = endTime;
}
public Date getEndTime()
{
return endTime;
}
public void setErrorMessage(String errorMessage)
{
this.errorMessage = errorMessage;
}
public String getErrorMessage()
{
return errorMessage;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("deviceId", getDeviceId())
.append("taskName", getTaskName())
.append("firmwareVersion", getFirmwareVersion())
.append("status", getStatus())
.append("progress", getProgress())
.append("startTime", getStartTime())
.append("endTime", getEndTime())
.append("errorMessage", getErrorMessage())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.append("updateBy", getUpdateBy())
.append("createBy", getCreateBy())
.toString();
}
} }

View File

@ -20,6 +20,8 @@ import com.evobms.framework.web.controller.BaseController;
import com.evobms.framework.web.domain.AjaxResult; import com.evobms.framework.web.domain.AjaxResult;
import com.evobms.common.utils.poi.ExcelUtil; import com.evobms.common.utils.poi.ExcelUtil;
import com.evobms.framework.web.page.TableDataInfo; import com.evobms.framework.web.page.TableDataInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/** /**
* 累计充放电量Controller * 累计充放电量Controller
@ -29,6 +31,7 @@ import com.evobms.framework.web.page.TableDataInfo;
*/ */
@RestController @RestController
@RequestMapping("/summary/summary") @RequestMapping("/summary/summary")
@Api(tags = "充放电统计")
public class ChargeDischargeSummaryController extends BaseController public class ChargeDischargeSummaryController extends BaseController
{ {
@Autowired @Autowired
@ -39,6 +42,7 @@ public class ChargeDischargeSummaryController extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('summary:summary:list')") @PreAuthorize("@ss.hasPermi('summary:summary:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询累计充放电量列表")
public TableDataInfo list(ChargeDischargeSummary chargeDischargeSummary) public TableDataInfo list(ChargeDischargeSummary chargeDischargeSummary)
{ {
startPage(); startPage();
@ -52,6 +56,7 @@ public class ChargeDischargeSummaryController extends BaseController
@PreAuthorize("@ss.hasPermi('summary:summary:export')") @PreAuthorize("@ss.hasPermi('summary:summary:export')")
@Log(title = "累计充放电量", businessType = BusinessType.EXPORT) @Log(title = "累计充放电量", businessType = BusinessType.EXPORT)
@PostMapping("/export") @PostMapping("/export")
@ApiOperation("导出累计充放电量列表")
public void export(HttpServletResponse response, ChargeDischargeSummary chargeDischargeSummary) public void export(HttpServletResponse response, ChargeDischargeSummary chargeDischargeSummary)
{ {
List<ChargeDischargeSummary> list = chargeDischargeSummaryService.selectChargeDischargeSummaryList(chargeDischargeSummary); List<ChargeDischargeSummary> list = chargeDischargeSummaryService.selectChargeDischargeSummaryList(chargeDischargeSummary);
@ -64,6 +69,7 @@ public class ChargeDischargeSummaryController extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('summary:summary:query')") @PreAuthorize("@ss.hasPermi('summary:summary:query')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取累计充放电量详细信息")
public AjaxResult getInfo(@PathVariable("id") Long id) public AjaxResult getInfo(@PathVariable("id") Long id)
{ {
return success(chargeDischargeSummaryService.selectChargeDischargeSummaryById(id)); return success(chargeDischargeSummaryService.selectChargeDischargeSummaryById(id));
@ -75,6 +81,7 @@ public class ChargeDischargeSummaryController extends BaseController
@PreAuthorize("@ss.hasPermi('summary:summary:add')") @PreAuthorize("@ss.hasPermi('summary:summary:add')")
@Log(title = "累计充放电量", businessType = BusinessType.INSERT) @Log(title = "累计充放电量", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
@ApiOperation("新增累计充放电量")
public AjaxResult add(@RequestBody ChargeDischargeSummary chargeDischargeSummary) public AjaxResult add(@RequestBody ChargeDischargeSummary chargeDischargeSummary)
{ {
return toAjax(chargeDischargeSummaryService.insertChargeDischargeSummary(chargeDischargeSummary)); return toAjax(chargeDischargeSummaryService.insertChargeDischargeSummary(chargeDischargeSummary));
@ -86,6 +93,7 @@ public class ChargeDischargeSummaryController extends BaseController
@PreAuthorize("@ss.hasPermi('summary:summary:edit')") @PreAuthorize("@ss.hasPermi('summary:summary:edit')")
@Log(title = "累计充放电量", businessType = BusinessType.UPDATE) @Log(title = "累计充放电量", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
@ApiOperation("修改累计充放电量")
public AjaxResult edit(@RequestBody ChargeDischargeSummary chargeDischargeSummary) public AjaxResult edit(@RequestBody ChargeDischargeSummary chargeDischargeSummary)
{ {
return toAjax(chargeDischargeSummaryService.updateChargeDischargeSummary(chargeDischargeSummary)); return toAjax(chargeDischargeSummaryService.updateChargeDischargeSummary(chargeDischargeSummary));
@ -96,7 +104,8 @@ public class ChargeDischargeSummaryController extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('summary:summary:remove')") @PreAuthorize("@ss.hasPermi('summary:summary:remove')")
@Log(title = "累计充放电量", businessType = BusinessType.DELETE) @Log(title = "累计充放电量", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}") @DeleteMapping("/{ids}")
@ApiOperation("删除累计充放电量")
public AjaxResult remove(@PathVariable Long[] ids) public AjaxResult remove(@PathVariable Long[] ids)
{ {
return toAjax(chargeDischargeSummaryService.deleteChargeDischargeSummaryByIds(ids)); return toAjax(chargeDischargeSummaryService.deleteChargeDischargeSummaryByIds(ids));

View File

@ -3,6 +3,10 @@ package com.evobms.project.summary.domain;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import com.evobms.framework.aspectj.lang.annotation.Excel; import com.evobms.framework.aspectj.lang.annotation.Excel;
@ -14,6 +18,9 @@ import com.evobms.framework.web.domain.BaseEntity;
* @author 田志阳 * @author 田志阳
* @date 2026-01-09 * @date 2026-01-09
*/ */
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ChargeDischargeSummary", description = "累计充放电量对象")
public class ChargeDischargeSummary extends BaseEntity public class ChargeDischargeSummary extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -23,83 +30,23 @@ public class ChargeDischargeSummary extends BaseEntity
/** 设备ID */ /** 设备ID */
@Excel(name = "设备ID") @Excel(name = "设备ID")
@ApiModelProperty(value = "设备ID")
private String deviceId; private String deviceId;
/** 时间戳 */ /** 时间戳 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss ") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss ")
@ApiModelProperty(value = "时间戳")
@Excel(name = "时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @Excel(name = "时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date timestamp; private Date timestamp;
/** 累计放电(kWh) */ /** 累计放电(kWh) */
@ApiModelProperty(value = "累计放电(kWh)")
@Excel(name = "累计放电(kWh)") @Excel(name = "累计放电(kWh)")
private BigDecimal dischargeKwh; private BigDecimal dischargeKwh;
/** 累计充电kWh) */ /** 累计充电kWh) */
@Excel(name = "累计充电kWh)") @ApiModelProperty(value = "累计充电kWh")
@Excel(name = "累计充电(kWh)")
private BigDecimal chargeKwh; private BigDecimal chargeKwh;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setDeviceId(String deviceId)
{
this.deviceId = deviceId;
}
public String getDeviceId()
{
return deviceId;
}
public void setTimestamp(Date timestamp)
{
this.timestamp = timestamp;
}
public Date getTimestamp()
{
return timestamp;
}
public void setDischargeKwh(BigDecimal dischargeKwh)
{
this.dischargeKwh = dischargeKwh;
}
public BigDecimal getDischargeKwh()
{
return dischargeKwh;
}
public void setChargeKwh(BigDecimal chargeKwh)
{
this.chargeKwh = chargeKwh;
}
public BigDecimal getChargeKwh()
{
return chargeKwh;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("deviceId", getDeviceId())
.append("timestamp", getTimestamp())
.append("dischargeKwh", getDischargeKwh())
.append("chargeKwh", getChargeKwh())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.append("createBy", getCreateBy())
.append("updateBy", getUpdateBy())
.toString();
}
} }

View File

@ -20,15 +20,18 @@ import com.evobms.framework.web.controller.BaseController;
import com.evobms.framework.web.domain.AjaxResult; import com.evobms.framework.web.domain.AjaxResult;
import com.evobms.common.utils.poi.ExcelUtil; import com.evobms.common.utils.poi.ExcelUtil;
import com.evobms.framework.web.page.TableDataInfo; import com.evobms.framework.web.page.TableDataInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/** /**
* BBOX管理Controller * BBOX管理Controller
* *
* @author 田志阳 * @author 田志阳
* @date 2025-10-10 * @date 2025-11-15
*/ */
@RestController @RestController
@RequestMapping("/devices/devices") @RequestMapping("/devices/devices")
@Api(tags = "BBOX设备管理")
public class BmsDevicesController extends BaseController public class BmsDevicesController extends BaseController
{ {
@Autowired @Autowired
@ -37,7 +40,9 @@ public class BmsDevicesController extends BaseController
/** /**
* 查询BBOX管理列表 * 查询BBOX管理列表
*/ */
@PreAuthorize("@ss.hasPermi('system:devices:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询BBOX设备列表")
public TableDataInfo list(BmsDevices bmsDevices) public TableDataInfo list(BmsDevices bmsDevices)
{ {
startPage(); startPage();
@ -48,8 +53,10 @@ public class BmsDevicesController extends BaseController
/** /**
* 导出BBOX管理列表 * 导出BBOX管理列表
*/ */
@PreAuthorize("@ss.hasPermi('system:devices:export')")
@Log(title = "BBOX管理", businessType = BusinessType.EXPORT) @Log(title = "BBOX管理", businessType = BusinessType.EXPORT)
@PostMapping("/export") @PostMapping("/export")
@ApiOperation("导出BBOX设备列表")
public void export(HttpServletResponse response, BmsDevices bmsDevices) public void export(HttpServletResponse response, BmsDevices bmsDevices)
{ {
List<BmsDevices> list = bmsDevicesService.selectBmsDevicesList(bmsDevices); List<BmsDevices> list = bmsDevicesService.selectBmsDevicesList(bmsDevices);
@ -60,7 +67,9 @@ public class BmsDevicesController extends BaseController
/** /**
* 获取BBOX管理详细信息 * 获取BBOX管理详细信息
*/ */
@PreAuthorize("@ss.hasPermi('system:devices:query')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取BBOX设备详细信息")
public AjaxResult getInfo(@PathVariable("id") String id) public AjaxResult getInfo(@PathVariable("id") String id)
{ {
return success(bmsDevicesService.selectBmsDevicesById(id)); return success(bmsDevicesService.selectBmsDevicesById(id));
@ -69,8 +78,10 @@ public class BmsDevicesController extends BaseController
/** /**
* 新增BBOX管理 * 新增BBOX管理
*/ */
@PreAuthorize("@ss.hasPermi('system:devices:add')")
@Log(title = "BBOX管理", businessType = BusinessType.INSERT) @Log(title = "BBOX管理", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
@ApiOperation("新增BBOX设备")
public AjaxResult add(@RequestBody BmsDevices bmsDevices) public AjaxResult add(@RequestBody BmsDevices bmsDevices)
{ {
return toAjax(bmsDevicesService.insertBmsDevices(bmsDevices)); return toAjax(bmsDevicesService.insertBmsDevices(bmsDevices));
@ -79,8 +90,10 @@ public class BmsDevicesController extends BaseController
/** /**
* 修改BBOX管理 * 修改BBOX管理
*/ */
@PreAuthorize("@ss.hasPermi('system:devices:edit')")
@Log(title = "BBOX管理", businessType = BusinessType.UPDATE) @Log(title = "BBOX管理", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
@ApiOperation("修改BBOX设备")
public AjaxResult edit(@RequestBody BmsDevices bmsDevices) public AjaxResult edit(@RequestBody BmsDevices bmsDevices)
{ {
return toAjax(bmsDevicesService.updateBmsDevices(bmsDevices)); return toAjax(bmsDevicesService.updateBmsDevices(bmsDevices));
@ -89,8 +102,10 @@ public class BmsDevicesController extends BaseController
/** /**
* 删除BBOX管理 * 删除BBOX管理
*/ */
@PreAuthorize("@ss.hasPermi('system:devices:remove')")
@Log(title = "BBOX管理", businessType = BusinessType.DELETE) @Log(title = "BBOX管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}") @DeleteMapping("/{ids}")
@ApiOperation("删除BBOX设备")
public AjaxResult remove(@PathVariable String[] ids) public AjaxResult remove(@PathVariable String[] ids)
{ {
return toAjax(bmsDevicesService.deleteBmsDevicesByIds(ids)); return toAjax(bmsDevicesService.deleteBmsDevicesByIds(ids));

View File

@ -2,6 +2,8 @@ package com.evobms.project.system.domain;
import java.util.Date; import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
@ -17,41 +19,51 @@ import com.evobms.framework.web.domain.BaseEntity;
*/ */
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Data @Data
@ApiModel(value = "BmsDevices", description = "BBOX设备管理对象")
public class BmsDevices extends BaseEntity public class BmsDevices extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 主键ID */ /** 主键ID */
@ApiModelProperty("主键ID")
private String id; private String id;
/** 设备唯一编号 */ /** 设备唯一编号 */
@ApiModelProperty("设备唯一编号")
@Excel(name = "设备唯一编号") @Excel(name = "设备唯一编号")
private String deviceId; private String deviceId;
/** 设备名称 */ /** 设备名称 */
@ApiModelProperty("设备名称")
@Excel(name = "设备名称") @Excel(name = "设备名称")
private String deviceName; private String deviceName;
/** 设备名称 */ /** 设备名称 */
@ApiModelProperty("设备SN码")
@Excel(name = "设备SN码") @Excel(name = "设备SN码")
private String deviceSn; private String deviceSn;
/** 设备类型 */ /** 设备类型 */
@ApiModelProperty("设备类型")
@Excel(name = "设备类型") @Excel(name = "设备类型")
private String deviceType; private String deviceType;
/** 设备状态 */ /** 设备状态 */
@ApiModelProperty("设备状态")
@Excel(name = "设备状态") @Excel(name = "设备状态")
private String status; private String status;
/** 设备IP地址 */ /** 设备IP地址 */
@ApiModelProperty("设备IP地址")
@Excel(name = "设备IP地址") @Excel(name = "设备IP地址")
private String ipAddress; private String ipAddress;
/** 服务器固件版本号 */ /** 服务器固件版本号 */
@ApiModelProperty("固件版本号")
@Excel(name = "固件版本号") @Excel(name = "固件版本号")
private String firmwareVersion; private String firmwareVersion;
/** 最后在线时间 */ /** 最后在线时间 */
@ApiModelProperty("最后在线时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "最后在线时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @Excel(name = "最后在线时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date lastOnline; private Date lastOnline;

View File

@ -29,6 +29,7 @@ import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
/** /**
* 图标组件Controller * 图标组件Controller
* *
@ -57,7 +58,9 @@ public class BatteryChartController {
// 图表数据按最近 hours 小时返回整车电压/电流/SOC 的时间序列 // 图表数据按最近 hours 小时返回整车电压/电流/SOC 的时间序列
@GetMapping("/battery-data/{deviceId}/chart") @GetMapping("/battery-data/{deviceId}/chart")
@ApiOperation(value = "整车电压电流SOC时间序列", notes = "按最近hours小时返回时间序列") @ApiOperation(value = "整车电压电流SOC时间序列", notes = "按最近hours小时返回时间序列")
public List<ChartDataPoint> getChartData(@PathVariable("deviceId") String deviceId, @RequestParam(value = "hours", required = false, defaultValue = "24") int hours) { public List<ChartDataPoint> getChartData(
@ApiParam(value = "设备ID", required = true) @PathVariable("deviceId") String deviceId,
@ApiParam(value = "最近多少小时的数据", defaultValue = "24") @RequestParam(value = "hours", required = false, defaultValue = "24") int hours) {
long millis = System.currentTimeMillis() - (long) hours * 3600_000L; long millis = System.currentTimeMillis() - (long) hours * 3600_000L;
Date startTime = new Date(millis); Date startTime = new Date(millis);
List<VehicleData> rows = vehicleDataService.selectByDeviceAndStartTime(deviceId, startTime); List<VehicleData> rows = vehicleDataService.selectByDeviceAndStartTime(deviceId, startTime);
@ -72,21 +75,25 @@ public class BatteryChartController {
// 整车最新返回 deviceId 最新的一条整车数据 // 整车最新返回 deviceId 最新的一条整车数据
@GetMapping("/vehicle-data/{deviceId}/latest") @GetMapping("/vehicle-data/{deviceId}/latest")
@ApiOperation(value = "整车最新数据", notes = "返回指定设备最新整车数据") @ApiOperation(value = "整车最新数据", notes = "返回指定设备最新整车数据")
public VehicleData latestVehicleData(@PathVariable("deviceId") String deviceId) { public VehicleData latestVehicleData(@ApiParam(value = "设备ID", required = true) @PathVariable("deviceId") String deviceId) {
return vehicleDataService.selectLatestByDeviceId(deviceId); return vehicleDataService.selectLatestByDeviceId(deviceId);
} }
// 位置最新返回 deviceId 最新的一条位置数据 // 位置最新返回 deviceId 最新的一条位置数据
@GetMapping("/vehicle-location/{deviceId}/latest") @GetMapping("/vehicle-location/{deviceId}/latest")
@ApiOperation(value = "车辆最新位置", notes = "返回指定设备最新位置数据") @ApiOperation(value = "车辆最新位置", notes = "返回指定设备最新位置数据")
public VehicleLocation latestVehicleLocation(@PathVariable("deviceId") String deviceId) { public VehicleLocation latestVehicleLocation(@ApiParam(value = "设备ID", required = true) @PathVariable("deviceId") String deviceId) {
return vehicleLocationService.selectLatestByDeviceId(deviceId); return vehicleLocationService.selectLatestByDeviceId(deviceId);
} }
// 位置轨迹按时间范围返回位置列表start/end 为毫秒时间戳可选 limit 限制条数 // 位置轨迹按时间范围返回位置列表start/end 为毫秒时间戳可选 limit 限制条数
@GetMapping("/vehicle-location/{deviceId}") @GetMapping("/vehicle-location/{deviceId}")
@ApiOperation(value = "车辆位置轨迹", notes = "按时间范围返回位置列表") @ApiOperation(value = "车辆位置轨迹", notes = "按时间范围返回位置列表")
public List<VehicleLocation> locationRange(@PathVariable("deviceId") String deviceId, @RequestParam("start") long startMillis, @RequestParam("end") long endMillis, @RequestParam(value = "limit", required = false) Integer limit) { public List<VehicleLocation> locationRange(
@ApiParam(value = "设备ID", required = true) @PathVariable("deviceId") String deviceId,
@ApiParam(value = "开始时间戳(毫秒)", required = true) @RequestParam("start") long startMillis,
@ApiParam(value = "结束时间戳(毫秒)", required = true) @RequestParam("end") long endMillis,
@ApiParam(value = "限制返回条数") @RequestParam(value = "limit", required = false) Integer limit) {
Date start = new Date(startMillis); Date start = new Date(startMillis);
Date end = new Date(endMillis); Date end = new Date(endMillis);
return vehicleLocationService.selectByDeviceAndRange(deviceId, start, end, limit); return vehicleLocationService.selectByDeviceAndRange(deviceId, start, end, limit);
@ -95,21 +102,26 @@ public class BatteryChartController {
// 子系统最新帧电压返回指定子系统号最新的一帧电压数据 // 子系统最新帧电压返回指定子系统号最新的一帧电压数据
@GetMapping("/subsystem-voltage/{deviceId}/{subsystemNo}/latest") @GetMapping("/subsystem-voltage/{deviceId}/{subsystemNo}/latest")
@ApiOperation(value = "子系统最新电压帧", notes = "返回指定子系统最新电压数据") @ApiOperation(value = "子系统最新电压帧", notes = "返回指定子系统最新电压数据")
public SubsystemVoltage latestVoltage(@PathVariable("deviceId") String deviceId, @PathVariable("subsystemNo") Integer subsystemNo) { public SubsystemVoltage latestVoltage(
@ApiParam(value = "设备ID", required = true) @PathVariable("deviceId") String deviceId,
@ApiParam(value = "子系统号", required = true) @PathVariable("subsystemNo") Integer subsystemNo) {
return subsystemVoltageService.selectLatestByDeviceAndSubsystem(deviceId, subsystemNo); return subsystemVoltageService.selectLatestByDeviceAndSubsystem(deviceId, subsystemNo);
} }
// 子系统最新帧温度返回指定子系统号最新的一帧温度数据 // 子系统最新帧温度返回指定子系统号最新的一帧温度数据
@GetMapping("/subsystem-temperature/{deviceId}/{subsystemNo}/latest") @GetMapping("/subsystem-temperature/{deviceId}/{subsystemNo}/latest")
@ApiOperation(value = "子系统最新温度帧", notes = "返回指定子系统最新温度数据") @ApiOperation(value = "子系统最新温度帧", notes = "返回指定子系统最新温度数据")
public SubsystemTemperature latestTemperature(@PathVariable("deviceId") String deviceId, @PathVariable("subsystemNo") Integer subsystemNo) { public SubsystemTemperature latestTemperature(
@ApiParam(value = "设备ID", required = true) @PathVariable("deviceId") String deviceId,
@ApiParam(value = "子系统号", required = true) @PathVariable("subsystemNo") Integer subsystemNo) {
return subsystemTemperatureService.selectLatestByDeviceAndSubsystem(deviceId, subsystemNo); return subsystemTemperatureService.selectLatestByDeviceAndSubsystem(deviceId, subsystemNo);
} }
@GetMapping("/extreme-values/{deviceId}/latest") @GetMapping("/extreme-values/{deviceId}/latest")
@ApiOperation(value = "极值最新数据", notes = "返回指定设备极值数据支持before筛选") @ApiOperation(value = "极值最新数据", notes = "返回指定设备极值数据支持before筛选")
public ExtremeValues latestExtremeValues(@PathVariable("deviceId") String deviceId, public ExtremeValues latestExtremeValues(
@RequestParam(value = "before", required = false) String before) { @ApiParam(value = "设备ID", required = true) @PathVariable("deviceId") String deviceId,
@ApiParam(value = "筛选指定时间之前的数据(yyyy-MM-dd HH:mm:ss 或 毫秒时间戳)") @RequestParam(value = "before", required = false) String before) {
if (before == null || before.isEmpty()) { if (before == null || before.isEmpty()) {
return extremeValuesService.selectLatestByDeviceId(deviceId); return extremeValuesService.selectLatestByDeviceId(deviceId);
} }
@ -126,7 +138,7 @@ public class BatteryChartController {
return extremeValuesService.selectLatestByDeviceIdBefore(deviceId, beforeTime); return extremeValuesService.selectLatestByDeviceIdBefore(deviceId, beforeTime);
} }
@GetMapping("/api/dashboard/home") @GetMapping("/api/dashboard/home")
@ApiOperation(value = "首页所有分布数据", notes = "返回指定设备极值数据支持before筛选") @ApiOperation(value = "首页所有分布数据", notes = "获取首页大屏的分布统计数据")
public R<HomeDashboardDTO> home(){ public R<HomeDashboardDTO> home(){
HomeDashboardDTO dto = vehicleDataService.getHomeDashboard(); HomeDashboardDTO dto = vehicleDataService.getHomeDashboard();
return R.ok(dto); return R.ok(dto);

View File

@ -20,6 +20,8 @@ import com.evobms.framework.web.controller.BaseController;
import com.evobms.framework.web.domain.AjaxResult; import com.evobms.framework.web.domain.AjaxResult;
import com.evobms.common.utils.poi.ExcelUtil; import com.evobms.common.utils.poi.ExcelUtil;
import com.evobms.framework.web.page.TableDataInfo; import com.evobms.framework.web.page.TableDataInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/** /**
* 整车数据Controller * 整车数据Controller
@ -29,6 +31,7 @@ import com.evobms.framework.web.page.TableDataInfo;
*/ */
@RestController @RestController
@RequestMapping("/VehicleData/VehicleData") @RequestMapping("/VehicleData/VehicleData")
@Api(tags = "整车数据管理")
public class VehicleDataController extends BaseController public class VehicleDataController extends BaseController
{ {
@Autowired @Autowired
@ -39,6 +42,7 @@ public class VehicleDataController extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:list')") @PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询整车数据列表")
public TableDataInfo list(VehicleData vehicleData) public TableDataInfo list(VehicleData vehicleData)
{ {
startPage(); startPage();
@ -52,6 +56,7 @@ public class VehicleDataController extends BaseController
@PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:export')") @PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:export')")
@Log(title = "整车数据", businessType = BusinessType.EXPORT) @Log(title = "整车数据", businessType = BusinessType.EXPORT)
@PostMapping("/export") @PostMapping("/export")
@ApiOperation("导出整车数据列表")
public void export(HttpServletResponse response, VehicleData vehicleData) public void export(HttpServletResponse response, VehicleData vehicleData)
{ {
List<VehicleData> list = vehicleDataService.selectVehicleDataList(vehicleData); List<VehicleData> list = vehicleDataService.selectVehicleDataList(vehicleData);
@ -64,6 +69,7 @@ public class VehicleDataController extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:query')") @PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:query')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取整车数据详细信息")
public AjaxResult getInfo(@PathVariable("id") Long id) public AjaxResult getInfo(@PathVariable("id") Long id)
{ {
return success(vehicleDataService.selectVehicleDataById(id)); return success(vehicleDataService.selectVehicleDataById(id));
@ -75,6 +81,7 @@ public class VehicleDataController extends BaseController
@PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:add')") @PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:add')")
@Log(title = "整车数据", businessType = BusinessType.INSERT) @Log(title = "整车数据", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
@ApiOperation("新增整车数据")
public AjaxResult add(@RequestBody VehicleData vehicleData) public AjaxResult add(@RequestBody VehicleData vehicleData)
{ {
return toAjax(vehicleDataService.insertVehicleData(vehicleData)); return toAjax(vehicleDataService.insertVehicleData(vehicleData));
@ -86,6 +93,7 @@ public class VehicleDataController extends BaseController
@PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:edit')") @PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:edit')")
@Log(title = "整车数据", businessType = BusinessType.UPDATE) @Log(title = "整车数据", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
@ApiOperation("修改整车数据")
public AjaxResult edit(@RequestBody VehicleData vehicleData) public AjaxResult edit(@RequestBody VehicleData vehicleData)
{ {
return toAjax(vehicleDataService.updateVehicleData(vehicleData)); return toAjax(vehicleDataService.updateVehicleData(vehicleData));
@ -96,7 +104,8 @@ public class VehicleDataController extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:remove')") @PreAuthorize("@ss.hasPermi('VehicleData:VehicleData:remove')")
@Log(title = "整车数据", businessType = BusinessType.DELETE) @Log(title = "整车数据", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}") @DeleteMapping("/{ids}")
@ApiOperation("删除整车数据")
public AjaxResult remove(@PathVariable Long[] ids) public AjaxResult remove(@PathVariable Long[] ids)
{ {
return toAjax(vehicleDataService.deleteVehicleDataByIds(ids)); return toAjax(vehicleDataService.deleteVehicleDataByIds(ids));

View File

@ -20,6 +20,8 @@ import com.evobms.framework.web.controller.BaseController;
import com.evobms.framework.web.domain.AjaxResult; import com.evobms.framework.web.domain.AjaxResult;
import com.evobms.common.utils.poi.ExcelUtil; import com.evobms.common.utils.poi.ExcelUtil;
import com.evobms.framework.web.page.TableDataInfo; import com.evobms.framework.web.page.TableDataInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/** /**
* 车辆位置数据Controller * 车辆位置数据Controller
@ -29,6 +31,7 @@ import com.evobms.framework.web.page.TableDataInfo;
*/ */
@RestController @RestController
@RequestMapping("/location/location") @RequestMapping("/location/location")
@Api(tags = "车辆位置管理")
public class VehicleLocationController extends BaseController public class VehicleLocationController extends BaseController
{ {
@Autowired @Autowired
@ -39,6 +42,7 @@ public class VehicleLocationController extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('location:location:list')") @PreAuthorize("@ss.hasPermi('location:location:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询车辆位置列表")
public TableDataInfo list(VehicleLocation vehicleLocation) public TableDataInfo list(VehicleLocation vehicleLocation)
{ {
startPage(); startPage();
@ -52,6 +56,7 @@ public class VehicleLocationController extends BaseController
@PreAuthorize("@ss.hasPermi('location:location:export')") @PreAuthorize("@ss.hasPermi('location:location:export')")
@Log(title = "车辆位置数据", businessType = BusinessType.EXPORT) @Log(title = "车辆位置数据", businessType = BusinessType.EXPORT)
@PostMapping("/export") @PostMapping("/export")
@ApiOperation("导出车辆位置列表")
public void export(HttpServletResponse response, VehicleLocation vehicleLocation) public void export(HttpServletResponse response, VehicleLocation vehicleLocation)
{ {
List<VehicleLocation> list = vehicleLocationService.selectVehicleLocationList(vehicleLocation); List<VehicleLocation> list = vehicleLocationService.selectVehicleLocationList(vehicleLocation);
@ -64,6 +69,7 @@ public class VehicleLocationController extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('location:location:query')") @PreAuthorize("@ss.hasPermi('location:location:query')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取车辆位置详细信息")
public AjaxResult getInfo(@PathVariable("id") Long id) public AjaxResult getInfo(@PathVariable("id") Long id)
{ {
return success(vehicleLocationService.selectVehicleLocationById(id)); return success(vehicleLocationService.selectVehicleLocationById(id));
@ -75,6 +81,7 @@ public class VehicleLocationController extends BaseController
@PreAuthorize("@ss.hasPermi('location:location:add')") @PreAuthorize("@ss.hasPermi('location:location:add')")
@Log(title = "车辆位置数据", businessType = BusinessType.INSERT) @Log(title = "车辆位置数据", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
@ApiOperation("新增车辆位置")
public AjaxResult add(@RequestBody VehicleLocation vehicleLocation) public AjaxResult add(@RequestBody VehicleLocation vehicleLocation)
{ {
return toAjax(vehicleLocationService.insertVehicleLocation(vehicleLocation)); return toAjax(vehicleLocationService.insertVehicleLocation(vehicleLocation));
@ -86,6 +93,7 @@ public class VehicleLocationController extends BaseController
@PreAuthorize("@ss.hasPermi('location:location:edit')") @PreAuthorize("@ss.hasPermi('location:location:edit')")
@Log(title = "车辆位置数据", businessType = BusinessType.UPDATE) @Log(title = "车辆位置数据", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
@ApiOperation("修改车辆位置")
public AjaxResult edit(@RequestBody VehicleLocation vehicleLocation) public AjaxResult edit(@RequestBody VehicleLocation vehicleLocation)
{ {
return toAjax(vehicleLocationService.updateVehicleLocation(vehicleLocation)); return toAjax(vehicleLocationService.updateVehicleLocation(vehicleLocation));
@ -96,7 +104,8 @@ public class VehicleLocationController extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('location:location:remove')") @PreAuthorize("@ss.hasPermi('location:location:remove')")
@Log(title = "车辆位置数据", businessType = BusinessType.DELETE) @Log(title = "车辆位置数据", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}") @DeleteMapping("/{ids}")
@ApiOperation("删除车辆位置")
public AjaxResult remove(@PathVariable Long[] ids) public AjaxResult remove(@PathVariable Long[] ids)
{ {
return toAjax(vehicleLocationService.deleteVehicleLocationByIds(ids)); return toAjax(vehicleLocationService.deleteVehicleLocationByIds(ids));

View File

@ -1,18 +1,28 @@
package com.evobms.project.vehicledata.domain; package com.evobms.project.vehicledata.domain;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import java.util.Map; import java.util.Map;
@Data @Data
@ApiModel(description = "首页仪表盘数据传输对象")
public class HomeDashboardDTO { public class HomeDashboardDTO {
@ApiModelProperty(value = "设备总数")
private Long deviceCount; // 设备总数 private Long deviceCount; // 设备总数
@ApiModelProperty(value = "在线设备数")
private Integer onlineCount; // 在线设备数 private Integer onlineCount; // 在线设备数
@ApiModelProperty(value = "平均 SOC")
private Double avgSoc; // 平均 SOC private Double avgSoc; // 平均 SOC
@ApiModelProperty(value = "当前最高温度")
private Double maxTemp; // 当前最高温度 private Double maxTemp; // 当前最高温度
@ApiModelProperty(value = "最大单体压差")
private Double maxVoltageDiff; // 最大单体压差 private Double maxVoltageDiff; // 最大单体压差
@ApiModelProperty(value = "未恢复告警数")
private Integer alarmCount; // 未恢复告警数 private Integer alarmCount; // 未恢复告警数
@ApiModelProperty(value = "SOC 分布")
private Map<String, Integer> socDistribution; // SOC 分布 private Map<String, Integer> socDistribution; // SOC 分布
@ApiModelProperty(value = "温度分布")
private Map<String, Integer> tempDistribution; // 温度分布 private Map<String, Integer> tempDistribution; // 温度分布
} }

View File

@ -2,7 +2,11 @@ package com.evobms.project.vehicledata.domain;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import com.evobms.framework.aspectj.lang.annotation.Excel; import com.evobms.framework.aspectj.lang.annotation.Excel;
@ -14,240 +18,87 @@ import com.evobms.framework.web.domain.BaseEntity;
* @author 田志阳 * @author 田志阳
* @date 2025-11-15 * @date 2025-11-15
*/ */
@ApiModel(description = "整车数据对象")
@Data
@EqualsAndHashCode(callSuper = true)
public class VehicleData extends BaseEntity public class VehicleData extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 主键ID */ /** 主键ID */
@ApiModelProperty(value = "主键ID")
private Long id; private Long id;
/** 设备ID */ /** 设备ID */
@ApiModelProperty(value = "设备ID")
@Excel(name = "设备ID") @Excel(name = "设备ID")
private String deviceId; private String deviceId;
/** 数据时间戳 */ /** 数据时间戳 */
@ApiModelProperty(value = "数据时间戳")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date timestamp; private Date timestamp;
/** 车辆状态 (1:启动 2:熄火 3:其他 254:异常 255:无效) */ /** 车辆状态 (1:启动 2:熄火 3:其他 254:异常 255:无效) */
@ApiModelProperty(value = "车辆状态 (1:启动 2:熄火 3:其他 254:异常 255:无效)")
@Excel(name = "车辆状态 (1:启动 2:熄火 3:其他 254:异常 255:无效)") @Excel(name = "车辆状态 (1:启动 2:熄火 3:其他 254:异常 255:无效)")
private Integer vehicleStatus; private Integer vehicleStatus;
/** 充电状态 (1:停车充电 2:行驶充电 3:未充电 4:充电完成 254:异常 255:无效) */ /** 充电状态 (1:停车充电 2:行驶充电 3:未充电 4:充电完成 254:异常 255:无效) */
@ApiModelProperty(value = "充电状态 (1:停车充电 2:行驶充电 3:未充电 4:充电完成 254:异常 255:无效)")
@Excel(name = "充电状态 (1:停车充电 2:行驶充电 3:未充电 4:充电完成 254:异常 255:无效)") @Excel(name = "充电状态 (1:停车充电 2:行驶充电 3:未充电 4:充电完成 254:异常 255:无效)")
private Integer chargingStatus; private Integer chargingStatus;
/** 运行模式 (1:纯电 2:混动 3:燃油 254:异常 255:无效) */ /** 运行模式 (1:纯电 2:混动 3:燃油 254:异常 255:无效) */
@ApiModelProperty(value = "运行模式 (1:纯电 2:混动 3:燃油 254:异常 255:无效)")
@Excel(name = "运行模式 (1:纯电 2:混动 3:燃油 254:异常 255:无效)") @Excel(name = "运行模式 (1:纯电 2:混动 3:燃油 254:异常 255:无效)")
private Integer operationMode; private Integer operationMode;
/** 车速(km/h) */ /** 车速(km/h) */
@ApiModelProperty(value = "车速(km/h)")
@Excel(name = "车速(km/h)") @Excel(name = "车速(km/h)")
private BigDecimal vehicleSpeed; private BigDecimal vehicleSpeed;
/** 累计里程(km) */ /** 累计里程(km) */
@ApiModelProperty(value = "累计里程(km)")
@Excel(name = "累计里程(km)") @Excel(name = "累计里程(km)")
private BigDecimal totalMileage; private BigDecimal totalMileage;
/** 总电压(V) */ /** 总电压(V) */
@ApiModelProperty(value = "总电压(V)")
@Excel(name = "总电压(V)") @Excel(name = "总电压(V)")
private BigDecimal totalVoltage; private BigDecimal totalVoltage;
/** 总电流(A) */ /** 总电流(A) */
@ApiModelProperty(value = "总电流(A)")
@Excel(name = "总电流(A)") @Excel(name = "总电流(A)")
private BigDecimal totalCurrent; private BigDecimal totalCurrent;
/** SOC电量百分比(%) */ /** SOC电量百分比(%) */
@ApiModelProperty(value = "SOC电量百分比(%)")
@Excel(name = "SOC电量百分比(%)") @Excel(name = "SOC电量百分比(%)")
private Integer soc; private Integer soc;
/** DC-DC状态 (1:工作 2:断开) */ /** DC-DC状态 (1:工作 2:断开) */
@ApiModelProperty(value = "DC-DC状态 (1:工作 2:断开)")
@Excel(name = "DC-DC状态 (1:工作 2:断开)") @Excel(name = "DC-DC状态 (1:工作 2:断开)")
private Integer dcdcStatus; private Integer dcdcStatus;
/** 档位 (0:空档 1-6:1-6档 13:倒档 14:自动D档 15:停车P档) */ /** 档位 (0:空档 1-6:1-6档 13:倒档 14:自动D档 15:停车P档) */
@ApiModelProperty(value = "档位 (0:空档 1-6:1-6档 13:倒档 14:自动D档 15:停车P档)")
@Excel(name = "档位 (0:空档 1-6:1-6档 13:倒档 14:自动D档 15:停车P档)") @Excel(name = "档位 (0:空档 1-6:1-6档 13:倒档 14:自动D档 15:停车P档)")
private Integer gearPosition; private Integer gearPosition;
/** 绝缘电阻(kΩ) */ /** 绝缘电阻(kΩ) */
@ApiModelProperty(value = "绝缘电阻(kΩ)")
@Excel(name = "绝缘电阻(kΩ)") @Excel(name = "绝缘电阻(kΩ)")
private Integer insulationResistance; private Integer insulationResistance;
/** 预留字段 */ /** 预留字段 */
@ApiModelProperty(value = "预留字段")
@Excel(name = "预留字段") @Excel(name = "预留字段")
private String reservedData; private String reservedData;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setDeviceId(String deviceId)
{
this.deviceId = deviceId;
}
public String getDeviceId()
{
return deviceId;
}
public void setTimestamp(Date timestamp)
{
this.timestamp = timestamp;
}
public Date getTimestamp()
{
return timestamp;
}
public void setVehicleStatus(Integer vehicleStatus)
{
this.vehicleStatus = vehicleStatus;
}
public Integer getVehicleStatus()
{
return vehicleStatus;
}
public void setChargingStatus(Integer chargingStatus)
{
this.chargingStatus = chargingStatus;
}
public Integer getChargingStatus()
{
return chargingStatus;
}
public void setOperationMode(Integer operationMode)
{
this.operationMode = operationMode;
}
public Integer getOperationMode()
{
return operationMode;
}
public void setVehicleSpeed(BigDecimal vehicleSpeed)
{
this.vehicleSpeed = vehicleSpeed;
}
public BigDecimal getVehicleSpeed()
{
return vehicleSpeed;
}
public void setTotalMileage(BigDecimal totalMileage)
{
this.totalMileage = totalMileage;
}
public BigDecimal getTotalMileage()
{
return totalMileage;
}
public void setTotalVoltage(BigDecimal totalVoltage)
{
this.totalVoltage = totalVoltage;
}
public BigDecimal getTotalVoltage()
{
return totalVoltage;
}
public void setTotalCurrent(BigDecimal totalCurrent)
{
this.totalCurrent = totalCurrent;
}
public BigDecimal getTotalCurrent()
{
return totalCurrent;
}
public void setSoc(Integer soc)
{
this.soc = soc;
}
public Integer getSoc()
{
return soc;
}
public void setDcdcStatus(Integer dcdcStatus)
{
this.dcdcStatus = dcdcStatus;
}
public Integer getDcdcStatus()
{
return dcdcStatus;
}
public void setGearPosition(Integer gearPosition)
{
this.gearPosition = gearPosition;
}
public Integer getGearPosition()
{
return gearPosition;
}
public void setInsulationResistance(Integer insulationResistance)
{
this.insulationResistance = insulationResistance;
}
public Integer getInsulationResistance()
{
return insulationResistance;
}
public void setReservedData(String reservedData)
{
this.reservedData = reservedData;
}
public String getReservedData()
{
return reservedData;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("deviceId", getDeviceId())
.append("timestamp", getTimestamp())
.append("vehicleStatus", getVehicleStatus())
.append("chargingStatus", getChargingStatus())
.append("operationMode", getOperationMode())
.append("vehicleSpeed", getVehicleSpeed())
.append("totalMileage", getTotalMileage())
.append("totalVoltage", getTotalVoltage())
.append("totalCurrent", getTotalCurrent())
.append("soc", getSoc())
.append("dcdcStatus", getDcdcStatus())
.append("gearPosition", getGearPosition())
.append("insulationResistance", getInsulationResistance())
.append("reservedData", getReservedData())
.toString();
}
} }

View File

@ -3,7 +3,11 @@ package com.evobms.project.vehicledata.domain;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import com.evobms.framework.aspectj.lang.annotation.Excel; import com.evobms.framework.aspectj.lang.annotation.Excel;
@ -15,23 +19,29 @@ import com.evobms.framework.web.domain.BaseEntity;
* @author ruoyi * @author ruoyi
* @date 2025-11-15 * @date 2025-11-15
*/ */
@ApiModel(description = "车辆位置数据对象")
@Data
@EqualsAndHashCode(callSuper = false)
public class VehicleLocation extends BaseEntity { public class VehicleLocation extends BaseEntity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 主键ID * 主键ID
*/ */
@ApiModelProperty(value = "主键ID")
private Long id; private Long id;
/** /**
* 设备ID * 设备ID
*/ */
@ApiModelProperty(value = "设备ID")
@Excel(name = "设备ID") @Excel(name = "设备ID")
private String deviceId; private String deviceId;
/** /**
* 数据时间戳 * 数据时间戳
*/ */
@ApiModelProperty(value = "数据时间戳")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @Excel(name = "数据时间戳", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date timestamp; private Date timestamp;
@ -39,79 +49,21 @@ public class VehicleLocation extends BaseEntity {
/** /**
* 定位状态 (0:无效 1:有效) * 定位状态 (0:无效 1:有效)
*/ */
@ApiModelProperty(value = "定位状态 (0:无效 1:有效)")
@Excel(name = "定位状态 (0:无效 1:有效)") @Excel(name = "定位状态 (0:无效 1:有效)")
private Integer positioningStatus; private Integer positioningStatus;
/** /**
* 经度 * 经度
*/ */
@ApiModelProperty(value = "经度")
@Excel(name = "经度") @Excel(name = "经度")
private BigDecimal longitude; private BigDecimal longitude;
/** /**
* 纬度 * 纬度
*/ */
@ApiModelProperty(value = "纬度")
@Excel(name = "纬度") @Excel(name = "纬度")
private BigDecimal latitude; private BigDecimal latitude;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getDeviceId() {
return deviceId;
}
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}
public Date getTimestamp() {
return timestamp;
}
public void setPositioningStatus(Integer positioningStatus) {
this.positioningStatus = positioningStatus;
}
public Integer getPositioningStatus() {
return positioningStatus;
}
public void setLongitude(BigDecimal longitude) {
this.longitude = longitude;
}
public BigDecimal getLongitude() {
return longitude;
}
public void setLatitude(BigDecimal latitude) {
this.latitude = latitude;
}
public BigDecimal getLatitude() {
return latitude;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("deviceId", getDeviceId())
.append("timestamp", getTimestamp())
.append("positioningStatus", getPositioningStatus())
.append("longitude", getLongitude())
.append("latitude", getLatitude())
.toString();
}
} }

View File

@ -6,7 +6,7 @@ spring:
druid: druid:
# 主库数据源 # 主库数据源
master: master:
url: jdbc:mysql://localhost:3306/evo_bms1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 url: jdbc:mysql://192.168.5.121:3306/evo_bms1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root username: root
password: root password: root
# 从库数据源 # 从库数据源

View File

@ -16,7 +16,7 @@ ruoyi:
# 开发环境配置 # 开发环境配置
server: server:
# 服务器HTTP端口支持环境变量覆盖SERVER_PORT默认8080 # 服务器HTTP端口支持环境变量覆盖SERVER_PORT默认8080
port: ${SERVER_PORT:8080} port: ${SERVER_PORT:8011}
servlet: servlet:
# 应用的访问路径 # 应用的访问路径
context-path: / context-path: /

View File

@ -1,24 +1,10 @@
Application Version: ${ruoyi.version} Application Version: ${ruoyi-vue-plus.version}
Spring Boot Version: ${spring-boot.version} Spring Boot Version: ${spring-boot.version}
//////////////////////////////////////////////////////////////////// _______ _______ _________ _______ _______
// _ooOoo_ // ( ____ \|\ /|( ___ )\__ __/( ____ \( ____ \|\ /|
// o8888888o // | ( \/| ) ( || ( ) | ) ( | ( \/| ( \/| ) ( |
// 88" . "88 // | (__ | | | || | | | | | | (__ | | | (___) |
// (| ^_^ |) // | __) ( ( ) )| | | | | | | __) | | | ___ |
// O\ = /O // | ( \ \_/ / | | | | | | | ( | | | ( ) |
// ____/`---'\____ // | (____/\ \ / | (___) | | | | (____/\| (____/\| ) ( |
// .' \\| |// `. // (_______/ \_/ (_______) )_( (_______/(_______/|/ \|
// / \\||| : |||// \ //
// / _||||| -:- |||||- \ //
// | | \\\ - /// | | //
// | \_| ''\---/'' | | //
// \ .-\__ `-` ___/-. / //
// ___`. .' /--.--\ `. . ___ //
// ."" '< `.___\_<|>_/___.' >'"". //
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
// \ \ `-. \_ __\ /__ _/ .-` / / //
// ========`-.____`-.___\_____/___.-`____.-'======== //
// `=---=' //
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
// 佛祖保佑 永不宕机 永无BUG //
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.evobms.project.bms.mapper.BmsChargeDetailMapper">
<resultMap type="com.evobms.project.bms.domain.BmsChargeDetail" id="BmsChargeDetailResult">
<result property="id" column="id"/>
<result property="deviceId" column="device_id"/>
<result property="timestamp" column="timestamp"/>
<result property="acChargeCurrent" column="ac_charge_current"/>
<result property="acChargeVoltage" column="ac_charge_voltage"/>
<result property="dcChargeCurrent" column="dc_charge_current"/>
<result property="dcChargeVoltage" column="dc_charge_voltage"/>
<result property="chargeTime" column="charge_time"/>
<result property="acStopCode" column="ac_stop_code"/>
<result property="dcStopCode" column="dc_stop_code"/>
<result property="acCpValue" column="ac_cp_value"/>
<result property="acGunResistance" column="ac_gun_resistance"/>
<result property="chargingStage" column="charging_stage"/>
<result property="acStage" column="ac_stage"/>
<result property="dcStage" column="dc_stage"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
</resultMap>
<insert id="insertBmsChargeDetail" parameterType="com.evobms.project.bms.domain.BmsChargeDetail" useGeneratedKeys="true" keyProperty="id">
insert into bms_charge_detail
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="deviceId != null and deviceId != ''">device_id,</if>
<if test="timestamp != null">timestamp,</if>
<if test="acChargeCurrent != null">ac_charge_current,</if>
<if test="acChargeVoltage != null">ac_charge_voltage,</if>
<if test="dcChargeCurrent != null">dc_charge_current,</if>
<if test="dcChargeVoltage != null">dc_charge_voltage,</if>
<if test="chargeTime != null">charge_time,</if>
<if test="acStopCode != null">ac_stop_code,</if>
<if test="dcStopCode != null">dc_stop_code,</if>
<if test="acCpValue != null">ac_cp_value,</if>
<if test="acGunResistance != null">ac_gun_resistance,</if>
<if test="chargingStage != null">charging_stage,</if>
<if test="acStage != null">ac_stage,</if>
<if test="dcStage != null">dc_stage,</if>
<if test="createTime != null">create_time,</if>
<if test="updateTime != null">update_time,</if>
<if test="createBy != null">create_by,</if>
<if test="updateBy != null">update_by,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="deviceId != null and deviceId != ''">#{deviceId},</if>
<if test="timestamp != null">#{timestamp},</if>
<if test="acChargeCurrent != null">#{acChargeCurrent},</if>
<if test="acChargeVoltage != null">#{acChargeVoltage},</if>
<if test="dcChargeCurrent != null">#{dcChargeCurrent},</if>
<if test="dcChargeVoltage != null">#{dcChargeVoltage},</if>
<if test="chargeTime != null">#{chargeTime},</if>
<if test="acStopCode != null">#{acStopCode},</if>
<if test="dcStopCode != null">#{dcStopCode},</if>
<if test="acCpValue != null">#{acCpValue},</if>
<if test="acGunResistance != null">#{acGunResistance},</if>
<if test="chargingStage != null">#{chargingStage},</if>
<if test="acStage != null">#{acStage},</if>
<if test="dcStage != null">#{dcStage},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="createBy != null">#{createBy},</if>
<if test="updateBy != null">#{updateBy},</if>
</trim>
</insert>
</mapper>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.evobms.project.bms.mapper.BmsSopDataMapper">
<resultMap type="com.evobms.project.bms.domain.BmsSopData" id="BmsSopDataResult">
<result property="id" column="id"/>
<result property="deviceId" column="device_id"/>
<result property="timestamp" column="timestamp"/>
<result property="dischargeSop10s" column="discharge_sop_10s"/>
<result property="dischargeSop30s" column="discharge_sop_30s"/>
<result property="dischargeSop60s" column="discharge_sop_60s"/>
<result property="dischargeSopContinuous" column="discharge_sop_continuous"/>
<result property="regenSop10s" column="regen_sop_10s"/>
<result property="regenSop30s" column="regen_sop_30s"/>
<result property="regenSop60s" column="regen_sop_60s"/>
<result property="regenSopContinuous" column="regen_sop_continuous"/>
<result property="chargeSop" column="charge_sop"/>
<result property="acChargeSop" column="ac_charge_sop"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
</resultMap>
<insert id="insertBmsSopData" parameterType="com.evobms.project.bms.domain.BmsSopData" useGeneratedKeys="true" keyProperty="id">
insert into bms_sop_data
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="deviceId != null and deviceId != ''">device_id,</if>
<if test="timestamp != null">timestamp,</if>
<if test="dischargeSop10s != null">discharge_sop_10s,</if>
<if test="dischargeSop30s != null">discharge_sop_30s,</if>
<if test="dischargeSop60s != null">discharge_sop_60s,</if>
<if test="dischargeSopContinuous != null">discharge_sop_continuous,</if>
<if test="regenSop10s != null">regen_sop_10s,</if>
<if test="regenSop30s != null">regen_sop_30s,</if>
<if test="regenSop60s != null">regen_sop_60s,</if>
<if test="regenSopContinuous != null">regen_sop_continuous,</if>
<if test="chargeSop != null">charge_sop,</if>
<if test="acChargeSop != null">ac_charge_sop,</if>
<if test="createTime != null">create_time,</if>
<if test="updateTime != null">update_time,</if>
<if test="createBy != null">create_by,</if>
<if test="updateBy != null">update_by,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="deviceId != null and deviceId != ''">#{deviceId},</if>
<if test="timestamp != null">#{timestamp},</if>
<if test="dischargeSop10s != null">#{dischargeSop10s},</if>
<if test="dischargeSop30s != null">#{dischargeSop30s},</if>
<if test="dischargeSop60s != null">#{dischargeSop60s},</if>
<if test="dischargeSopContinuous != null">#{dischargeSopContinuous},</if>
<if test="regenSop10s != null">#{regenSop10s},</if>
<if test="regenSop30s != null">#{regenSop30s},</if>
<if test="regenSop60s != null">#{regenSop60s},</if>
<if test="regenSopContinuous != null">#{regenSopContinuous},</if>
<if test="chargeSop != null">#{chargeSop},</if>
<if test="acChargeSop != null">#{acChargeSop},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="createBy != null">#{createBy},</if>
<if test="updateBy != null">#{updateBy},</if>
</trim>
</insert>
</mapper>

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.evobms.project.bms.mapper.BmsSystemStatusMapper">
<resultMap type="com.evobms.project.bms.domain.BmsSystemStatus" id="BmsSystemStatusResult">
<result property="id" column="id"/>
<result property="deviceId" column="device_id"/>
<result property="timestamp" column="timestamp"/>
<result property="relayStatus" column="relay_status"/>
<result property="onaaccStatus" column="onaacc_status"/>
<result property="resetCount" column="reset_count"/>
<result property="cycleCount" column="cycle_count"/>
<result property="sample25v" column="sample_25v"/>
<result property="sample5v" column="sample_5v"/>
<result property="cellCount" column="cell_count"/>
<result property="tempSensorCount" column="temp_sensor_count"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
</resultMap>
<insert id="insertBmsSystemStatus" parameterType="com.evobms.project.bms.domain.BmsSystemStatus" useGeneratedKeys="true" keyProperty="id">
insert into bms_system_status
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="deviceId != null and deviceId != ''">device_id,</if>
<if test="timestamp != null">timestamp,</if>
<if test="relayStatus != null">relay_status,</if>
<if test="onaaccStatus != null">onaacc_status,</if>
<if test="resetCount != null">reset_count,</if>
<if test="cycleCount != null">cycle_count,</if>
<if test="sample25v != null">sample_25v,</if>
<if test="sample5v != null">sample_5v,</if>
<if test="cellCount != null">cell_count,</if>
<if test="tempSensorCount != null">temp_sensor_count,</if>
<if test="createTime != null">create_time,</if>
<if test="updateTime != null">update_time,</if>
<if test="createBy != null">create_by,</if>
<if test="updateBy != null">update_by,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="deviceId != null and deviceId != ''">#{deviceId},</if>
<if test="timestamp != null">#{timestamp},</if>
<if test="relayStatus != null">#{relayStatus},</if>
<if test="onaaccStatus != null">#{onaaccStatus},</if>
<if test="resetCount != null">#{resetCount},</if>
<if test="cycleCount != null">#{cycleCount},</if>
<if test="sample25v != null">#{sample25v},</if>
<if test="sample5v != null">#{sample5v},</if>
<if test="cellCount != null">#{cellCount},</if>
<if test="tempSensorCount != null">#{tempSensorCount},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="createBy != null">#{createBy},</if>
<if test="updateBy != null">#{updateBy},</if>
</trim>
</insert>
</mapper>

File diff suppressed because one or more lines are too long

Binary file not shown.