临时修改
This commit is contained in:
@ -0,0 +1,51 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import com.xzzn.common.annotation.Log;
|
||||||
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
|
import com.xzzn.common.core.page.TableDataInfo;
|
||||||
|
import com.xzzn.common.enums.BusinessType;
|
||||||
|
import com.xzzn.ems.domain.EmsPointCalcConfig;
|
||||||
|
import com.xzzn.ems.service.IEmsPointCalcConfigService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ems/pointCalcConfig")
|
||||||
|
public class EmsPointCalcConfigController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEmsPointCalcConfigService pointCalcConfigService;
|
||||||
|
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(EmsPointCalcConfig pointCalcConfig) {
|
||||||
|
startPage();
|
||||||
|
List<EmsPointCalcConfig> list = pointCalcConfigService.selectPointCalcConfigList(pointCalcConfig);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||||
|
return success(pointCalcConfigService.selectPointCalcConfigById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "计算点配置", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody EmsPointCalcConfig pointCalcConfig) {
|
||||||
|
return toAjax(pointCalcConfigService.insertPointCalcConfig(pointCalcConfig, getUsername()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "计算点配置", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody EmsPointCalcConfig pointCalcConfig) {
|
||||||
|
return toAjax(pointCalcConfigService.updatePointCalcConfig(pointCalcConfig, getUsername()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "计算点配置", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||||
|
return toAjax(pointCalcConfigService.deletePointCalcConfigByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package com.xzzn.web.controller.ems;
|
||||||
|
|
||||||
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyRuntimeConfig;
|
||||||
|
import com.xzzn.ems.service.IEmsStrategyRuntimeConfigService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策略运行参数配置Controller
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/system/strategyRuntimeConfig")
|
||||||
|
public class EmsStrategyRuntimeConfigController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEmsStrategyRuntimeConfigService runtimeConfigService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按站点ID获取策略运行参数
|
||||||
|
*/
|
||||||
|
@GetMapping("/getBySiteId")
|
||||||
|
public AjaxResult getBySiteId(String siteId) {
|
||||||
|
if (StringUtils.isEmpty(siteId)) {
|
||||||
|
return error("缺少必填字段siteId");
|
||||||
|
}
|
||||||
|
return success(runtimeConfigService.getBySiteId(siteId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存策略运行参数(按siteId新增/更新)
|
||||||
|
*/
|
||||||
|
@PostMapping("/save")
|
||||||
|
public AjaxResult save(@RequestBody EmsStrategyRuntimeConfig config) {
|
||||||
|
if (config == null || StringUtils.isEmpty(config.getSiteId())) {
|
||||||
|
return error("缺少必填字段siteId");
|
||||||
|
}
|
||||||
|
config.setCreateBy(getUsername());
|
||||||
|
config.setUpdateBy(getUsername());
|
||||||
|
return toAjax(runtimeConfigService.saveBySiteId(config));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,6 +16,7 @@ import com.xzzn.ems.domain.EmsAmmeterData;
|
|||||||
import com.xzzn.ems.domain.EmsBatteryStack;
|
import com.xzzn.ems.domain.EmsBatteryStack;
|
||||||
import com.xzzn.ems.domain.EmsDevicesSetting;
|
import com.xzzn.ems.domain.EmsDevicesSetting;
|
||||||
import com.xzzn.ems.domain.EmsPcsSetting;
|
import com.xzzn.ems.domain.EmsPcsSetting;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyRuntimeConfig;
|
||||||
import com.xzzn.ems.domain.EmsStrategyLog;
|
import com.xzzn.ems.domain.EmsStrategyLog;
|
||||||
import com.xzzn.ems.domain.EmsStrategyTemp;
|
import com.xzzn.ems.domain.EmsStrategyTemp;
|
||||||
import com.xzzn.ems.domain.EmsStrategyTimeConfig;
|
import com.xzzn.ems.domain.EmsStrategyTimeConfig;
|
||||||
@ -25,17 +26,20 @@ import com.xzzn.ems.mapper.EmsBatteryStackMapper;
|
|||||||
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
|
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
|
||||||
import com.xzzn.ems.mapper.EmsPcsSettingMapper;
|
import com.xzzn.ems.mapper.EmsPcsSettingMapper;
|
||||||
import com.xzzn.ems.mapper.EmsStrategyLogMapper;
|
import com.xzzn.ems.mapper.EmsStrategyLogMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyRuntimeConfigMapper;
|
||||||
import com.xzzn.ems.mapper.EmsStrategyRunningMapper;
|
import com.xzzn.ems.mapper.EmsStrategyRunningMapper;
|
||||||
import com.xzzn.ems.mapper.EmsStrategyTempMapper;
|
import com.xzzn.ems.mapper.EmsStrategyTempMapper;
|
||||||
import com.xzzn.ems.mapper.EmsStrategyTimeConfigMapper;
|
import com.xzzn.ems.mapper.EmsStrategyTimeConfigMapper;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -57,16 +61,20 @@ public class StrategyPoller {
|
|||||||
private static final ConcurrentHashMap<Long, Boolean> strategyLocks = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<Long, Boolean> strategyLocks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
// SOC 上下限值,默认为0%-100%
|
// SOC 上下限值,默认为0%-100%
|
||||||
private static final BigDecimal SOC_DOWN = new BigDecimal(0);
|
private static final BigDecimal DEFAULT_SOC_DOWN = BigDecimal.ZERO;
|
||||||
private static final BigDecimal SOC_UP = new BigDecimal(100);
|
private static final BigDecimal DEFAULT_SOC_UP = new BigDecimal(100);
|
||||||
// 逆变器功率下限值,默认为30kW
|
// 逆变器功率下限值,默认为30kW
|
||||||
private static final BigDecimal ANTI_REVERSE_THRESHOLD = new BigDecimal(30);
|
private static final BigDecimal DEFAULT_ANTI_REVERSE_THRESHOLD = new BigDecimal(30);
|
||||||
// 逆变器下限值范围,默认为20%
|
// 逆变器下限值范围,默认为20%
|
||||||
private static final BigDecimal ANTI_REVERSE_RANGE_PERCENT = new BigDecimal(20);
|
private static final BigDecimal DEFAULT_ANTI_REVERSE_RANGE_PERCENT = new BigDecimal(20);
|
||||||
// 逆变器功率上限值,默认为100kW
|
// 逆变器功率上限值,默认为100kW
|
||||||
private static final BigDecimal ANTI_REVERSE_UP = new BigDecimal(100);
|
private static final BigDecimal DEFAULT_ANTI_REVERSE_UP = new BigDecimal(100);
|
||||||
// PCS功率降幅,默认为10%
|
// PCS功率降幅,默认为10%
|
||||||
private static final BigDecimal ANTI_REVERSE_POWER_DOWN_PERCENT = new BigDecimal(10);
|
private static final BigDecimal DEFAULT_ANTI_REVERSE_POWER_DOWN_PERCENT = new BigDecimal(10);
|
||||||
|
// 电网有功功率低于20kW时,强制待机
|
||||||
|
private static final BigDecimal DEFAULT_ANTI_REVERSE_HARD_STOP_THRESHOLD = new BigDecimal(20);
|
||||||
|
// 除法精度,避免BigDecimal除不尽异常
|
||||||
|
private static final int POWER_SCALE = 4;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmsStrategyRunningMapper emsStrategyRunningMapper;
|
private EmsStrategyRunningMapper emsStrategyRunningMapper;
|
||||||
@ -85,6 +93,8 @@ public class StrategyPoller {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EmsStrategyLogMapper emsStrategyLogMapper;
|
private EmsStrategyLogMapper emsStrategyLogMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private EmsStrategyRuntimeConfigMapper runtimeConfigMapper;
|
||||||
|
@Autowired
|
||||||
private ModbusProcessor modbusProcessor;
|
private ModbusProcessor modbusProcessor;
|
||||||
|
|
||||||
@Resource(name = "modbusExecutor")
|
@Resource(name = "modbusExecutor")
|
||||||
@ -132,6 +142,7 @@ public class StrategyPoller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void dealStrategyCurveData(Long strategyId, String siteId) {
|
private void dealStrategyCurveData(Long strategyId, String siteId) {
|
||||||
|
EmsStrategyRuntimeConfig runtimeConfig = getRuntimeConfig(siteId);
|
||||||
// 1.获取当前策略的所有模板
|
// 1.获取当前策略的所有模板
|
||||||
List<Map<String, String>> temps = emsStrategyTempMapper.getTempNameList(strategyId, siteId);
|
List<Map<String, String>> temps = emsStrategyTempMapper.getTempNameList(strategyId, siteId);
|
||||||
if (CollectionUtils.isEmpty(temps)) {
|
if (CollectionUtils.isEmpty(temps)) {
|
||||||
@ -174,24 +185,38 @@ public class StrategyPoller {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 判断SOC上下限
|
// 判断SOC上下限
|
||||||
if (isSocInRange(emsStrategyTemp)) {
|
if (isSocInRange(emsStrategyTemp, runtimeConfig)) {
|
||||||
BigDecimal avgChargeDischargePower = emsStrategyTemp.getChargeDischargePower().divide(new BigDecimal(pcsDeviceList.size()));
|
Map<Long, EmsPcsSetting> pcsSettingCache = new HashMap<>();
|
||||||
|
BigDecimal avgChargeDischargePower = emsStrategyTemp.getChargeDischargePower()
|
||||||
|
.divide(new BigDecimal(pcsDeviceList.size()), POWER_SCALE, RoundingMode.HALF_UP);
|
||||||
|
BigDecimal totalActivePower = null;
|
||||||
|
if (ChargeStatus.DISCHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
|
||||||
|
// 同一站点同一轮执行只读取一次电网电表,降低重复查库和数据抖动
|
||||||
|
EmsAmmeterData emsAmmeterData = emsAmmeterDataMapper.getLastData(emsStrategyTemp.getSiteId(), SiteDevice.LOAD.name());
|
||||||
|
if (emsAmmeterData != null) {
|
||||||
|
totalActivePower = emsAmmeterData.getTotalActivePower();
|
||||||
|
}
|
||||||
|
}
|
||||||
for (EmsDevicesSetting pcsDevice : pcsDeviceList) {
|
for (EmsDevicesSetting pcsDevice : pcsDeviceList) {
|
||||||
EmsPcsSetting pcsSetting = emsPcsSettingMapper.selectEmsPcsSettingByDeviceId(pcsDevice.getId());
|
EmsPcsSetting pcsSetting = pcsSettingCache.computeIfAbsent(
|
||||||
|
pcsDevice.getId(),
|
||||||
|
id -> emsPcsSettingMapper.selectEmsPcsSettingByDeviceId(id)
|
||||||
|
);
|
||||||
if (pcsSetting == null || pcsSetting.getClusterNum() < 1) {
|
if (pcsSetting == null || pcsSetting.getClusterNum() < 1) {
|
||||||
logger.info("当前站点: {}, PCS设备: {} 未获取电池簇数量", siteId, pcsDevice.getDeviceId());
|
logger.info("当前站点: {}, PCS设备: {} 未获取电池簇数量", siteId, pcsDevice.getDeviceId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 功率默认放大10倍,平均功率值,根据电池簇数量进行平均分配
|
// 功率默认放大10倍,平均功率值,根据电池簇数量进行平均分配
|
||||||
avgChargeDischargePower = avgChargeDischargePower.multiply(new BigDecimal(10)).divide(new BigDecimal(pcsSetting.getClusterNum()));
|
BigDecimal strategyPower = avgChargeDischargePower.multiply(new BigDecimal(10))
|
||||||
|
.divide(new BigDecimal(pcsSetting.getClusterNum()), POWER_SCALE, RoundingMode.HALF_UP);
|
||||||
// 根据充电状态,处理数据
|
// 根据充电状态,处理数据
|
||||||
if (ChargeStatus.CHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
|
if (ChargeStatus.CHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
|
||||||
// 发送Modbus命令控制设备-充电
|
// 发送Modbus命令控制设备-充电
|
||||||
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.CHARGING, avgChargeDischargePower, emsStrategyTemp, false, null);
|
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.CHARGING, strategyPower, emsStrategyTemp, false, null);
|
||||||
} else if (ChargeStatus.DISCHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
|
} else if (ChargeStatus.DISCHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
|
||||||
boolean needAntiReverseFlow = false;
|
boolean needAntiReverseFlow = false;
|
||||||
Integer powerDownType = null;
|
Integer powerDownType = null;
|
||||||
BigDecimal chargeDischargePower = avgChargeDischargePower;
|
BigDecimal chargeDischargePower = strategyPower;
|
||||||
// 查询策略运行日志
|
// 查询策略运行日志
|
||||||
EmsStrategyLog lastStrategyLog = getLastStrategyLog(pcsDevice.getDeviceId(), emsStrategyTemp);
|
EmsStrategyLog lastStrategyLog = getLastStrategyLog(pcsDevice.getDeviceId(), emsStrategyTemp);
|
||||||
if (lastStrategyLog != null) {
|
if (lastStrategyLog != null) {
|
||||||
@ -204,32 +229,54 @@ public class StrategyPoller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 查询电网电表的正向有功功率,36kW-50kW范围内,稳定运行,低于36kW,降功率,高于50kW,增加功率
|
// 查询电网电表的正向有功功率,36kW-50kW范围内,稳定运行,低于36kW,降功率,高于50kW,增加功率
|
||||||
EmsAmmeterData emsAmmeterData = emsAmmeterDataMapper.getLastData(emsStrategyTemp.getSiteId(), SiteDevice.LOAD.name());
|
if (totalActivePower == null) {
|
||||||
if (emsAmmeterData == null || emsAmmeterData.getTotalActivePower() == null) {
|
logger.warn("当前站点: {}, 未获取到最新电表数据,执行保守策略并切换待机", emsStrategyTemp.getSiteId());
|
||||||
logger.info("当前站点: {}, 未获取到最新电表数据", emsStrategyTemp.getSiteId());
|
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, true, 0);
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
// 电网功率过低,直接待机,不再放电
|
||||||
|
if (totalActivePower.compareTo(runtimeConfig.getAntiReverseHardStopThreshold()) < 0) {
|
||||||
|
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, true, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 放电开始先按差值限幅:差值=电网功率-防逆流阈值
|
||||||
|
BigDecimal diffPower = totalActivePower.subtract(runtimeConfig.getAntiReverseThreshold());
|
||||||
|
BigDecimal targetPower = diffPower.compareTo(BigDecimal.ZERO) > 0 ? diffPower : BigDecimal.ZERO;
|
||||||
|
if (targetPower.compareTo(strategyPower) > 0) {
|
||||||
|
targetPower = strategyPower;
|
||||||
|
}
|
||||||
|
if (chargeDischargePower.compareTo(targetPower) > 0) {
|
||||||
|
chargeDischargePower = targetPower;
|
||||||
|
}
|
||||||
// 判断是否需要防逆流
|
// 判断是否需要防逆流
|
||||||
needAntiReverseFlow = isNeedAntiReverseFlow(emsAmmeterData.getTotalActivePower());
|
needAntiReverseFlow = isNeedAntiReverseFlow(totalActivePower, runtimeConfig);
|
||||||
BigDecimal power = avgChargeDischargePower.multiply(ANTI_REVERSE_POWER_DOWN_PERCENT).divide(new BigDecimal(100));
|
BigDecimal power = strategyPower.multiply(runtimeConfig.getAntiReversePowerDownPercent())
|
||||||
|
.divide(new BigDecimal(100), POWER_SCALE, RoundingMode.HALF_UP);
|
||||||
if (needAntiReverseFlow) {
|
if (needAntiReverseFlow) {
|
||||||
// 降功率
|
// 降功率
|
||||||
chargeDischargePower = chargeDischargePower.subtract(power);
|
chargeDischargePower = chargeDischargePower.subtract(power);
|
||||||
powerDownType = 0;
|
powerDownType = 0;
|
||||||
} else {
|
} else {
|
||||||
// 判断是否需要增加功率,
|
// 判断是否需要增加功率,
|
||||||
if (powerDownType != null && emsAmmeterData.getTotalActivePower().compareTo(ANTI_REVERSE_UP) > 0) {
|
if (powerDownType != null && totalActivePower.compareTo(runtimeConfig.getAntiReverseUp()) > 0) {
|
||||||
if (chargeDischargePower.compareTo(avgChargeDischargePower) == 0) {
|
if (chargeDischargePower.compareTo(targetPower) >= 0) {
|
||||||
// 功率增加到平均值则停止
|
// 功率增加到限幅值则停止
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 增加功率
|
// 增加功率
|
||||||
chargeDischargePower = chargeDischargePower.add(power);
|
chargeDischargePower = chargeDischargePower.add(power);
|
||||||
|
if (chargeDischargePower.compareTo(targetPower) > 0) {
|
||||||
|
chargeDischargePower = targetPower;
|
||||||
|
}
|
||||||
powerDownType = 1;
|
powerDownType = 1;
|
||||||
needAntiReverseFlow = true;
|
needAntiReverseFlow = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chargeDischargePower.compareTo(BigDecimal.ZERO) < 0) {
|
||||||
|
chargeDischargePower = BigDecimal.ZERO;
|
||||||
|
}
|
||||||
if (BigDecimal.ZERO.compareTo(chargeDischargePower) == 0) {
|
if (BigDecimal.ZERO.compareTo(chargeDischargePower) == 0) {
|
||||||
// 如果已经降功率到0,则设备直接待机
|
// 如果已经降功率到0,则设备直接待机
|
||||||
// 发送Modbus命令控制设备-待机
|
// 发送Modbus命令控制设备-待机
|
||||||
@ -297,11 +344,11 @@ public class StrategyPoller {
|
|||||||
return emsStrategyLogMapper.getLastStrategyLog(query);
|
return emsStrategyLogMapper.getLastStrategyLog(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNeedAntiReverseFlow(BigDecimal totalActivePower) {
|
private boolean isNeedAntiReverseFlow(BigDecimal totalActivePower, EmsStrategyRuntimeConfig runtimeConfig) {
|
||||||
// 获取当前设定的防逆流阈值(30kW)
|
// 获取当前设定的防逆流阈值(30kW)
|
||||||
BigDecimal threshold = ANTI_REVERSE_THRESHOLD;
|
BigDecimal threshold = runtimeConfig.getAntiReverseThreshold();
|
||||||
// 计算20%范围的上限(36kW)
|
// 计算20%范围的上限(36kW)
|
||||||
BigDecimal upperLimit = threshold.multiply(ANTI_REVERSE_RANGE_PERCENT).divide(new BigDecimal(100)).add(threshold);
|
BigDecimal upperLimit = threshold.multiply(runtimeConfig.getAntiReverseRangePercent()).divide(new BigDecimal(100)).add(threshold);
|
||||||
|
|
||||||
// 判断电网电表正向有功功率是否小于36kW(接近30kW的20%范围)
|
// 判断电网电表正向有功功率是否小于36kW(接近30kW的20%范围)
|
||||||
return totalActivePower.compareTo(upperLimit) < 0;
|
return totalActivePower.compareTo(upperLimit) < 0;
|
||||||
@ -409,8 +456,9 @@ public class StrategyPoller {
|
|||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
// 充、放电,则先开机设备
|
// 充、放电,则先开机设备
|
||||||
switchDevice(pcsDevice, pcsSetting, WorkStatus.NORMAL);
|
if (!switchDevice(pcsDevice, pcsSetting, WorkStatus.NORMAL)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,14 +488,17 @@ public class StrategyPoller {
|
|||||||
private boolean switchDevice(EmsDevicesSetting pcsDevice, EmsPcsSetting pcsSetting, WorkStatus workStatus) {
|
private boolean switchDevice(EmsDevicesSetting pcsDevice, EmsPcsSetting pcsSetting, WorkStatus workStatus) {
|
||||||
String siteId = pcsDevice.getSiteId();
|
String siteId = pcsDevice.getSiteId();
|
||||||
String deviceId = pcsDevice.getDeviceId();
|
String deviceId = pcsDevice.getDeviceId();
|
||||||
|
String originalWorkStatus = pcsDevice.getWorkStatus();
|
||||||
pcsDevice.setWorkStatus(workStatus.getCode());
|
pcsDevice.setWorkStatus(workStatus.getCode());
|
||||||
DeviceConfig deviceConfig = getDeviceConfig(siteId, deviceId, pcsDevice, pcsSetting , null, 1);
|
DeviceConfig deviceConfig = getDeviceConfig(siteId, deviceId, pcsDevice, pcsSetting , null, 1);
|
||||||
if (deviceConfig == null) {
|
if (deviceConfig == null) {
|
||||||
|
pcsDevice.setWorkStatus(originalWorkStatus);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean result = modbusProcessor.writeDataToDeviceWithRetry(deviceConfig);
|
boolean result = modbusProcessor.writeDataToDeviceWithRetry(deviceConfig);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceConfig, workStatus.getInfo());
|
pcsDevice.setWorkStatus(originalWorkStatus);
|
||||||
|
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceId, workStatus.getInfo());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -461,13 +512,17 @@ public class StrategyPoller {
|
|||||||
LocalTime endLocalTime = endTime.toInstant()
|
LocalTime endLocalTime = endTime.toInstant()
|
||||||
.atZone(zoneId)
|
.atZone(zoneId)
|
||||||
.toLocalTime();
|
.toLocalTime();
|
||||||
return now.equals(startLocalTime) || (now.isAfter(startLocalTime) && now.isBefore(endLocalTime));
|
// 支持跨天时段,如23:00-01:00;边界采用闭区间
|
||||||
|
if (!startLocalTime.isAfter(endLocalTime)) {
|
||||||
|
return !now.isBefore(startLocalTime) && !now.isAfter(endLocalTime);
|
||||||
|
}
|
||||||
|
return !now.isBefore(startLocalTime) || !now.isAfter(endLocalTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断SOC上限和下限
|
// 判断SOC上限和下限
|
||||||
private boolean isSocInRange(EmsStrategyTemp emsStrategyTemp) {
|
private boolean isSocInRange(EmsStrategyTemp emsStrategyTemp, EmsStrategyRuntimeConfig runtimeConfig) {
|
||||||
BigDecimal socDown = SOC_DOWN;
|
BigDecimal socDown = runtimeConfig.getSocDown();
|
||||||
BigDecimal socUp = SOC_UP;
|
BigDecimal socUp = runtimeConfig.getSocUp();
|
||||||
if (SocLimit.ON.getCode().equals(emsStrategyTemp.getSdcLimit())) {
|
if (SocLimit.ON.getCode().equals(emsStrategyTemp.getSdcLimit())) {
|
||||||
socDown = emsStrategyTemp.getSdcDown();
|
socDown = emsStrategyTemp.getSdcDown();
|
||||||
socUp = emsStrategyTemp.getSdcUp();
|
socUp = emsStrategyTemp.getSdcUp();
|
||||||
@ -491,4 +546,34 @@ public class StrategyPoller {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EmsStrategyRuntimeConfig getRuntimeConfig(String siteId) {
|
||||||
|
EmsStrategyRuntimeConfig config = runtimeConfigMapper.selectBySiteId(siteId);
|
||||||
|
if (config == null) {
|
||||||
|
config = new EmsStrategyRuntimeConfig();
|
||||||
|
config.setSiteId(siteId);
|
||||||
|
}
|
||||||
|
if (config.getSocDown() == null) {
|
||||||
|
config.setSocDown(DEFAULT_SOC_DOWN);
|
||||||
|
}
|
||||||
|
if (config.getSocUp() == null) {
|
||||||
|
config.setSocUp(DEFAULT_SOC_UP);
|
||||||
|
}
|
||||||
|
if (config.getAntiReverseThreshold() == null) {
|
||||||
|
config.setAntiReverseThreshold(DEFAULT_ANTI_REVERSE_THRESHOLD);
|
||||||
|
}
|
||||||
|
if (config.getAntiReverseRangePercent() == null) {
|
||||||
|
config.setAntiReverseRangePercent(DEFAULT_ANTI_REVERSE_RANGE_PERCENT);
|
||||||
|
}
|
||||||
|
if (config.getAntiReverseUp() == null) {
|
||||||
|
config.setAntiReverseUp(DEFAULT_ANTI_REVERSE_UP);
|
||||||
|
}
|
||||||
|
if (config.getAntiReversePowerDownPercent() == null) {
|
||||||
|
config.setAntiReversePowerDownPercent(DEFAULT_ANTI_REVERSE_POWER_DOWN_PERCENT);
|
||||||
|
}
|
||||||
|
if (config.getAntiReverseHardStopThreshold() == null) {
|
||||||
|
config.setAntiReverseHardStopThreshold(DEFAULT_ANTI_REVERSE_HARD_STOP_THRESHOLD);
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,6 +49,10 @@ public class EmsPcsSetting extends BaseEntity
|
|||||||
@Excel(name = "关机目标功率")
|
@Excel(name = "关机目标功率")
|
||||||
private BigDecimal stopPower;
|
private BigDecimal stopPower;
|
||||||
|
|
||||||
|
/** 目标功率倍率 */
|
||||||
|
@Excel(name = "目标功率倍率")
|
||||||
|
private BigDecimal powerMultiplier;
|
||||||
|
|
||||||
/** 电池簇数 */
|
/** 电池簇数 */
|
||||||
@Excel(name = "电池簇数")
|
@Excel(name = "电池簇数")
|
||||||
private Integer clusterNum;
|
private Integer clusterNum;
|
||||||
@ -135,6 +139,16 @@ public class EmsPcsSetting extends BaseEntity
|
|||||||
return stopPower;
|
return stopPower;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigDecimal getPowerMultiplier()
|
||||||
|
{
|
||||||
|
return powerMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPowerMultiplier(BigDecimal powerMultiplier)
|
||||||
|
{
|
||||||
|
this.powerMultiplier = powerMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
public void setClusterNum(Integer clusterNum)
|
public void setClusterNum(Integer clusterNum)
|
||||||
{
|
{
|
||||||
this.clusterNum = clusterNum;
|
this.clusterNum = clusterNum;
|
||||||
@ -165,6 +179,7 @@ public class EmsPcsSetting extends BaseEntity
|
|||||||
.append("stopCommand", getStopCommand())
|
.append("stopCommand", getStopCommand())
|
||||||
.append("startPower", getStartPower())
|
.append("startPower", getStartPower())
|
||||||
.append("stopPower", getStopPower())
|
.append("stopPower", getStopPower())
|
||||||
|
.append("powerMultiplier", getPowerMultiplier())
|
||||||
.append("clusterNum", getClusterNum())
|
.append("clusterNum", getClusterNum())
|
||||||
.append("clusterPointAddress", getClusterPointAddress())
|
.append("clusterPointAddress", getClusterPointAddress())
|
||||||
.append("createBy", getCreateBy())
|
.append("createBy", getCreateBy())
|
||||||
|
|||||||
@ -0,0 +1,128 @@
|
|||||||
|
package com.xzzn.ems.domain;
|
||||||
|
|
||||||
|
import com.xzzn.common.annotation.Excel;
|
||||||
|
import com.xzzn.common.core.domain.BaseEntity;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
|
public class EmsPointCalcConfig extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Excel(name = "点位ID")
|
||||||
|
private String pointId;
|
||||||
|
|
||||||
|
@Excel(name = "站点ID")
|
||||||
|
private String siteId;
|
||||||
|
|
||||||
|
@Excel(name = "设备类型")
|
||||||
|
private String deviceCategory;
|
||||||
|
|
||||||
|
@Excel(name = "点位名称")
|
||||||
|
private String pointName;
|
||||||
|
|
||||||
|
@Excel(name = "数据键")
|
||||||
|
private String dataKey;
|
||||||
|
|
||||||
|
@Excel(name = "点位描述")
|
||||||
|
private String pointDesc;
|
||||||
|
|
||||||
|
@Excel(name = "单位")
|
||||||
|
private String dataUnit;
|
||||||
|
|
||||||
|
@Excel(name = "计算表达式")
|
||||||
|
private String calcExpression;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPointId() {
|
||||||
|
return pointId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointId(String pointId) {
|
||||||
|
this.pointId = pointId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSiteId() {
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteId(String siteId) {
|
||||||
|
this.siteId = siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPointName() {
|
||||||
|
return pointName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointName(String pointName) {
|
||||||
|
this.pointName = pointName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceCategory() {
|
||||||
|
return deviceCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceCategory(String deviceCategory) {
|
||||||
|
this.deviceCategory = deviceCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataKey() {
|
||||||
|
return dataKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataKey(String dataKey) {
|
||||||
|
this.dataKey = dataKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPointDesc() {
|
||||||
|
return pointDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointDesc(String pointDesc) {
|
||||||
|
this.pointDesc = pointDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataUnit() {
|
||||||
|
return dataUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataUnit(String dataUnit) {
|
||||||
|
this.dataUnit = dataUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCalcExpression() {
|
||||||
|
return calcExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCalcExpression(String calcExpression) {
|
||||||
|
this.calcExpression = calcExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
||||||
|
.append("id", getId())
|
||||||
|
.append("pointId", getPointId())
|
||||||
|
.append("siteId", getSiteId())
|
||||||
|
.append("deviceCategory", getDeviceCategory())
|
||||||
|
.append("pointName", getPointName())
|
||||||
|
.append("dataKey", getDataKey())
|
||||||
|
.append("pointDesc", getPointDesc())
|
||||||
|
.append("dataUnit", getDataUnit())
|
||||||
|
.append("calcExpression", getCalcExpression())
|
||||||
|
.append("createBy", getCreateBy())
|
||||||
|
.append("createTime", getCreateTime())
|
||||||
|
.append("updateBy", getUpdateBy())
|
||||||
|
.append("updateTime", getUpdateTime())
|
||||||
|
.append("remark", getRemark())
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,6 +15,9 @@ public class EmsPointConfig extends BaseEntity {
|
|||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
@Excel(name = "点位ID")
|
||||||
|
private String pointId;
|
||||||
|
|
||||||
@Excel(name = "站点ID")
|
@Excel(name = "站点ID")
|
||||||
private String siteId;
|
private String siteId;
|
||||||
|
|
||||||
@ -68,6 +71,14 @@ public class EmsPointConfig extends BaseEntity {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPointId() {
|
||||||
|
return pointId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointId(String pointId) {
|
||||||
|
this.pointId = pointId;
|
||||||
|
}
|
||||||
|
|
||||||
public String getSiteId() {
|
public String getSiteId() {
|
||||||
return siteId;
|
return siteId;
|
||||||
}
|
}
|
||||||
@ -192,6 +203,7 @@ public class EmsPointConfig extends BaseEntity {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
||||||
.append("id", getId())
|
.append("id", getId())
|
||||||
|
.append("pointId", getPointId())
|
||||||
.append("siteId", getSiteId())
|
.append("siteId", getSiteId())
|
||||||
.append("deviceCategory", getDeviceCategory())
|
.append("deviceCategory", getDeviceCategory())
|
||||||
.append("deviceId", getDeviceId())
|
.append("deviceId", getDeviceId())
|
||||||
|
|||||||
@ -12,6 +12,8 @@ public class EmsSiteMonitorPointMatch extends BaseEntity {
|
|||||||
private String siteId;
|
private String siteId;
|
||||||
private String fieldCode;
|
private String fieldCode;
|
||||||
private String dataPoint;
|
private String dataPoint;
|
||||||
|
private String fixedDataPoint;
|
||||||
|
private Integer useFixedDisplay;
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
@ -44,4 +46,20 @@ public class EmsSiteMonitorPointMatch extends BaseEntity {
|
|||||||
public void setDataPoint(String dataPoint) {
|
public void setDataPoint(String dataPoint) {
|
||||||
this.dataPoint = dataPoint;
|
this.dataPoint = dataPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFixedDataPoint() {
|
||||||
|
return fixedDataPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFixedDataPoint(String fixedDataPoint) {
|
||||||
|
this.fixedDataPoint = fixedDataPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUseFixedDisplay() {
|
||||||
|
return useFixedDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseFixedDisplay(Integer useFixedDisplay) {
|
||||||
|
this.useFixedDisplay = useFixedDisplay;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,144 @@
|
|||||||
|
package com.xzzn.ems.domain;
|
||||||
|
|
||||||
|
import com.xzzn.common.annotation.Excel;
|
||||||
|
import com.xzzn.common.core.domain.BaseEntity;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策略运行参数配置对象 ems_strategy_runtime_config
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2026-02-13
|
||||||
|
*/
|
||||||
|
public class EmsStrategyRuntimeConfig extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 主键 */
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 站点ID */
|
||||||
|
@Excel(name = "站点ID")
|
||||||
|
private String siteId;
|
||||||
|
|
||||||
|
/** SOC下限(%) */
|
||||||
|
@Excel(name = "SOC下限(%)")
|
||||||
|
private BigDecimal socDown;
|
||||||
|
|
||||||
|
/** SOC上限(%) */
|
||||||
|
@Excel(name = "SOC上限(%)")
|
||||||
|
private BigDecimal socUp;
|
||||||
|
|
||||||
|
/** 防逆流阈值(kW) */
|
||||||
|
@Excel(name = "防逆流阈值(kW)")
|
||||||
|
private BigDecimal antiReverseThreshold;
|
||||||
|
|
||||||
|
/** 防逆流阈值上浮比例(%) */
|
||||||
|
@Excel(name = "防逆流阈值上浮比例(%)")
|
||||||
|
private BigDecimal antiReverseRangePercent;
|
||||||
|
|
||||||
|
/** 防逆流恢复上限(kW) */
|
||||||
|
@Excel(name = "防逆流恢复上限(kW)")
|
||||||
|
private BigDecimal antiReverseUp;
|
||||||
|
|
||||||
|
/** 防逆流降功率比例(%) */
|
||||||
|
@Excel(name = "防逆流降功率比例(%)")
|
||||||
|
private BigDecimal antiReversePowerDownPercent;
|
||||||
|
/** 防逆流硬停阈值(kW) */
|
||||||
|
@Excel(name = "防逆流硬停阈值(kW)")
|
||||||
|
private BigDecimal antiReverseHardStopThreshold;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSiteId() {
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteId(String siteId) {
|
||||||
|
this.siteId = siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getSocDown() {
|
||||||
|
return socDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSocDown(BigDecimal socDown) {
|
||||||
|
this.socDown = socDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getSocUp() {
|
||||||
|
return socUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSocUp(BigDecimal socUp) {
|
||||||
|
this.socUp = socUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAntiReverseThreshold() {
|
||||||
|
return antiReverseThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAntiReverseThreshold(BigDecimal antiReverseThreshold) {
|
||||||
|
this.antiReverseThreshold = antiReverseThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAntiReverseRangePercent() {
|
||||||
|
return antiReverseRangePercent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAntiReverseRangePercent(BigDecimal antiReverseRangePercent) {
|
||||||
|
this.antiReverseRangePercent = antiReverseRangePercent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAntiReverseUp() {
|
||||||
|
return antiReverseUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAntiReverseUp(BigDecimal antiReverseUp) {
|
||||||
|
this.antiReverseUp = antiReverseUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAntiReversePowerDownPercent() {
|
||||||
|
return antiReversePowerDownPercent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAntiReversePowerDownPercent(BigDecimal antiReversePowerDownPercent) {
|
||||||
|
this.antiReversePowerDownPercent = antiReversePowerDownPercent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAntiReverseHardStopThreshold() {
|
||||||
|
return antiReverseHardStopThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAntiReverseHardStopThreshold(BigDecimal antiReverseHardStopThreshold) {
|
||||||
|
this.antiReverseHardStopThreshold = antiReverseHardStopThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
|
||||||
|
.append("id", getId())
|
||||||
|
.append("siteId", getSiteId())
|
||||||
|
.append("socDown", getSocDown())
|
||||||
|
.append("socUp", getSocUp())
|
||||||
|
.append("antiReverseThreshold", getAntiReverseThreshold())
|
||||||
|
.append("antiReverseRangePercent", getAntiReverseRangePercent())
|
||||||
|
.append("antiReverseUp", getAntiReverseUp())
|
||||||
|
.append("antiReversePowerDownPercent", getAntiReversePowerDownPercent())
|
||||||
|
.append("antiReverseHardStopThreshold", getAntiReverseHardStopThreshold())
|
||||||
|
.append("createBy", getCreateBy())
|
||||||
|
.append("createTime", getCreateTime())
|
||||||
|
.append("updateBy", getUpdateBy())
|
||||||
|
.append("updateTime", getUpdateTime())
|
||||||
|
.append("remark", getRemark())
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -35,6 +35,14 @@ public class EmsStrategyTempTimeConfig extends BaseEntity
|
|||||||
@Excel(name = "充放功率 (kW)")
|
@Excel(name = "充放功率 (kW)")
|
||||||
private BigDecimal chargeDischargePower;
|
private BigDecimal chargeDischargePower;
|
||||||
|
|
||||||
|
/** SDC下限 (%) */
|
||||||
|
@Excel(name = "SDC下限 (%)")
|
||||||
|
private BigDecimal sdcDown;
|
||||||
|
|
||||||
|
/** SDC上限 (%) */
|
||||||
|
@Excel(name = "SDC上限 (%)")
|
||||||
|
private BigDecimal sdcUp;
|
||||||
|
|
||||||
/** 充电状态,如“1-充电”、“2-待机” */
|
/** 充电状态,如“1-充电”、“2-待机” */
|
||||||
@Excel(name = "充电状态,如“1-充电”、“2-待机”")
|
@Excel(name = "充电状态,如“1-充电”、“2-待机”")
|
||||||
private String chargeStatus;
|
private String chargeStatus;
|
||||||
@ -83,6 +91,26 @@ public class EmsStrategyTempTimeConfig extends BaseEntity
|
|||||||
return chargeDischargePower;
|
return chargeDischargePower;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSdcDown(BigDecimal sdcDown)
|
||||||
|
{
|
||||||
|
this.sdcDown = sdcDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getSdcDown()
|
||||||
|
{
|
||||||
|
return sdcDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSdcUp(BigDecimal sdcUp)
|
||||||
|
{
|
||||||
|
this.sdcUp = sdcUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getSdcUp()
|
||||||
|
{
|
||||||
|
return sdcUp;
|
||||||
|
}
|
||||||
|
|
||||||
public void setChargeStatus(String chargeStatus)
|
public void setChargeStatus(String chargeStatus)
|
||||||
{
|
{
|
||||||
this.chargeStatus = chargeStatus;
|
this.chargeStatus = chargeStatus;
|
||||||
@ -110,6 +138,8 @@ public class EmsStrategyTempTimeConfig extends BaseEntity
|
|||||||
.append("startTime", getStartTime())
|
.append("startTime", getStartTime())
|
||||||
.append("endTime", getEndTime())
|
.append("endTime", getEndTime())
|
||||||
.append("chargeDischargePower", getChargeDischargePower())
|
.append("chargeDischargePower", getChargeDischargePower())
|
||||||
|
.append("sdcDown", getSdcDown())
|
||||||
|
.append("sdcUp", getSdcUp())
|
||||||
.append("chargeStatus", getChargeStatus())
|
.append("chargeStatus", getChargeStatus())
|
||||||
.append("createBy", getCreateBy())
|
.append("createBy", getCreateBy())
|
||||||
.append("createTime", getCreateTime())
|
.append("createTime", getCreateTime())
|
||||||
|
|||||||
@ -3,7 +3,9 @@ package com.xzzn.ems.domain.vo;
|
|||||||
public class PointConfigCurveRequest {
|
public class PointConfigCurveRequest {
|
||||||
private String siteId;
|
private String siteId;
|
||||||
private String deviceId;
|
private String deviceId;
|
||||||
|
private String pointId;
|
||||||
private String dataKey;
|
private String dataKey;
|
||||||
|
private String pointType;
|
||||||
private String rangeType;
|
private String rangeType;
|
||||||
private String startTime;
|
private String startTime;
|
||||||
private String endTime;
|
private String endTime;
|
||||||
@ -24,6 +26,14 @@ public class PointConfigCurveRequest {
|
|||||||
this.deviceId = deviceId;
|
this.deviceId = deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPointId() {
|
||||||
|
return pointId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointId(String pointId) {
|
||||||
|
this.pointId = pointId;
|
||||||
|
}
|
||||||
|
|
||||||
public String getDataKey() {
|
public String getDataKey() {
|
||||||
return dataKey;
|
return dataKey;
|
||||||
}
|
}
|
||||||
@ -32,6 +42,14 @@ public class PointConfigCurveRequest {
|
|||||||
this.dataKey = dataKey;
|
this.dataKey = dataKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPointType() {
|
||||||
|
return pointType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointType(String pointType) {
|
||||||
|
this.pointType = pointType;
|
||||||
|
}
|
||||||
|
|
||||||
public String getRangeType() {
|
public String getRangeType() {
|
||||||
return rangeType;
|
return rangeType;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,8 @@ public class SiteMonitorProjectPointMappingSaveRequest {
|
|||||||
|
|
||||||
private List<SiteMonitorProjectPointMappingVo> mappings;
|
private List<SiteMonitorProjectPointMappingVo> mappings;
|
||||||
|
|
||||||
|
private List<String> deletedFieldCodes;
|
||||||
|
|
||||||
public String getSiteId() {
|
public String getSiteId() {
|
||||||
return siteId;
|
return siteId;
|
||||||
}
|
}
|
||||||
@ -23,4 +25,12 @@ public class SiteMonitorProjectPointMappingSaveRequest {
|
|||||||
public void setMappings(List<SiteMonitorProjectPointMappingVo> mappings) {
|
public void setMappings(List<SiteMonitorProjectPointMappingVo> mappings) {
|
||||||
this.mappings = mappings;
|
this.mappings = mappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getDeletedFieldCodes() {
|
||||||
|
return deletedFieldCodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeletedFieldCodes(List<String> deletedFieldCodes) {
|
||||||
|
this.deletedFieldCodes = deletedFieldCodes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,10 @@ public class SiteMonitorProjectPointMappingVo {
|
|||||||
|
|
||||||
private String dataPoint;
|
private String dataPoint;
|
||||||
|
|
||||||
|
private String fixedDataPoint;
|
||||||
|
|
||||||
|
private Integer useFixedDisplay;
|
||||||
|
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
return moduleCode;
|
return moduleCode;
|
||||||
}
|
}
|
||||||
@ -81,4 +85,20 @@ public class SiteMonitorProjectPointMappingVo {
|
|||||||
public void setDataPoint(String dataPoint) {
|
public void setDataPoint(String dataPoint) {
|
||||||
this.dataPoint = dataPoint;
|
this.dataPoint = dataPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFixedDataPoint() {
|
||||||
|
return fixedDataPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFixedDataPoint(String fixedDataPoint) {
|
||||||
|
this.fixedDataPoint = fixedDataPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUseFixedDisplay() {
|
||||||
|
return useFixedDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseFixedDisplay(Integer useFixedDisplay) {
|
||||||
|
this.useFixedDisplay = useFixedDisplay;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
package com.xzzn.ems.mapper;
|
||||||
|
|
||||||
|
import com.xzzn.ems.domain.EmsPointCalcConfig;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface EmsPointCalcConfigMapper {
|
||||||
|
EmsPointCalcConfig selectEmsPointCalcConfigById(Long id);
|
||||||
|
|
||||||
|
List<EmsPointCalcConfig> selectEmsPointCalcConfigList(EmsPointCalcConfig emsPointCalcConfig);
|
||||||
|
|
||||||
|
int insertEmsPointCalcConfig(EmsPointCalcConfig emsPointCalcConfig);
|
||||||
|
|
||||||
|
int updateEmsPointCalcConfig(EmsPointCalcConfig emsPointCalcConfig);
|
||||||
|
|
||||||
|
int deleteEmsPointCalcConfigById(Long id);
|
||||||
|
|
||||||
|
int deleteEmsPointCalcConfigByIds(Long[] ids);
|
||||||
|
|
||||||
|
int countBySiteId(@Param("siteId") String siteId);
|
||||||
|
|
||||||
|
int deleteBySiteId(@Param("siteId") String siteId);
|
||||||
|
}
|
||||||
@ -13,6 +13,8 @@ public interface EmsPointConfigMapper {
|
|||||||
|
|
||||||
int insertEmsPointConfig(EmsPointConfig emsPointConfig);
|
int insertEmsPointConfig(EmsPointConfig emsPointConfig);
|
||||||
|
|
||||||
|
int insertBatchEmsPointConfig(@Param("list") List<EmsPointConfig> list);
|
||||||
|
|
||||||
int updateEmsPointConfig(EmsPointConfig emsPointConfig);
|
int updateEmsPointConfig(EmsPointConfig emsPointConfig);
|
||||||
|
|
||||||
int deleteEmsPointConfigById(Long id);
|
int deleteEmsPointConfigById(Long id);
|
||||||
@ -41,4 +43,7 @@ public interface EmsPointConfigMapper {
|
|||||||
@Param("deviceCategory") String deviceCategory,
|
@Param("deviceCategory") String deviceCategory,
|
||||||
@Param("pointNames") List<String> pointNames,
|
@Param("pointNames") List<String> pointNames,
|
||||||
@Param("deviceIds") List<String> deviceIds);
|
@Param("deviceIds") List<String> deviceIds);
|
||||||
|
|
||||||
|
List<EmsPointConfig> selectBySiteIdAndPointIds(@Param("siteId") String siteId,
|
||||||
|
@Param("pointIds") List<String> pointIds);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,36 @@
|
|||||||
|
package com.xzzn.ems.mapper;
|
||||||
|
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyRuntimeConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策略运行参数配置Mapper接口
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2026-02-13
|
||||||
|
*/
|
||||||
|
public interface EmsStrategyRuntimeConfigMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据站点ID查询参数配置
|
||||||
|
*
|
||||||
|
* @param siteId 站点ID
|
||||||
|
* @return 参数配置
|
||||||
|
*/
|
||||||
|
EmsStrategyRuntimeConfig selectBySiteId(String siteId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增参数配置
|
||||||
|
*
|
||||||
|
* @param config 参数配置
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insert(EmsStrategyRuntimeConfig config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按站点ID更新参数配置
|
||||||
|
*
|
||||||
|
* @param config 参数配置
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateBySiteId(EmsStrategyRuntimeConfig config);
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.xzzn.ems.service;
|
||||||
|
|
||||||
|
import com.xzzn.ems.domain.EmsPointCalcConfig;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface IEmsPointCalcConfigService {
|
||||||
|
List<EmsPointCalcConfig> selectPointCalcConfigList(EmsPointCalcConfig pointCalcConfig);
|
||||||
|
|
||||||
|
EmsPointCalcConfig selectPointCalcConfigById(Long id);
|
||||||
|
|
||||||
|
int insertPointCalcConfig(EmsPointCalcConfig pointCalcConfig, String operName);
|
||||||
|
|
||||||
|
int updatePointCalcConfig(EmsPointCalcConfig pointCalcConfig, String operName);
|
||||||
|
|
||||||
|
int deletePointCalcConfigByIds(Long[] ids);
|
||||||
|
|
||||||
|
int deleteBySiteId(String siteId);
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.xzzn.ems.service;
|
||||||
|
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyRuntimeConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策略运行参数配置Service接口
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2026-02-13
|
||||||
|
*/
|
||||||
|
public interface IEmsStrategyRuntimeConfigService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按站点ID获取参数配置(不存在时返回默认值)
|
||||||
|
*
|
||||||
|
* @param siteId 站点ID
|
||||||
|
* @return 参数配置
|
||||||
|
*/
|
||||||
|
EmsStrategyRuntimeConfig getBySiteId(String siteId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存参数配置(按siteId新增或更新)
|
||||||
|
*
|
||||||
|
* @param config 参数配置
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int saveBySiteId(EmsStrategyRuntimeConfig config);
|
||||||
|
}
|
||||||
@ -61,15 +61,19 @@ import com.xzzn.ems.utils.DevicePointMatchDataProcessor;
|
|||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Deque;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -77,6 +81,7 @@ import java.util.Objects;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
@ -104,12 +109,14 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
// 匹配DTDC+数字格式的正则(提取序号)
|
// 匹配DTDC+数字格式的正则(提取序号)
|
||||||
private static final Pattern DTDC_PATTERN = Pattern.compile("DTDC(\\d+)([A-Za-z]*)");
|
private static final Pattern DTDC_PATTERN = Pattern.compile("DTDC(\\d+)([A-Za-z]*)");
|
||||||
private static final Pattern DB_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9_]+$");
|
private static final Pattern DB_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9_]+$");
|
||||||
|
private static final Pattern VARIABLE_SAFE_PATTERN = Pattern.compile("[^A-Za-z0-9_]");
|
||||||
private static final int POINT_QUEUE_CAPACITY = 100000;
|
private static final int POINT_QUEUE_CAPACITY = 100000;
|
||||||
private static final int POINT_FLUSH_BATCH_SIZE = 2000;
|
private static final int POINT_FLUSH_BATCH_SIZE = 2000;
|
||||||
private static final int POINT_FLUSH_MAX_DRAIN_PER_RUN = 20000;
|
private static final int POINT_FLUSH_MAX_DRAIN_PER_RUN = 20000;
|
||||||
private static final int POINT_ENQUEUE_RETRY_TIMES = 3;
|
private static final int POINT_ENQUEUE_RETRY_TIMES = 3;
|
||||||
private static final long POINT_ENQUEUE_RETRY_WAIT_MS = 10;
|
private static final long POINT_ENQUEUE_RETRY_WAIT_MS = 10;
|
||||||
private static final long POINT_FLUSH_INTERVAL_MS = 100;
|
private static final long POINT_FLUSH_INTERVAL_MS = 100;
|
||||||
|
private static final String SITE_LEVEL_CALC_DEVICE_ID = "SITE_CALC";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmsBatteryClusterMapper emsBatteryClusterMapper;
|
private EmsBatteryClusterMapper emsBatteryClusterMapper;
|
||||||
@ -169,6 +176,7 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
@Autowired
|
@Autowired
|
||||||
private InfluxPointDataWriter influxPointDataWriter;
|
private InfluxPointDataWriter influxPointDataWriter;
|
||||||
private final BlockingQueue<PointDataRecord> pointDataQueue = new LinkedBlockingQueue<>(POINT_QUEUE_CAPACITY);
|
private final BlockingQueue<PointDataRecord> pointDataQueue = new LinkedBlockingQueue<>(POINT_QUEUE_CAPACITY);
|
||||||
|
private final Map<String, List<ExpressionToken>> calcExpressionCache = new ConcurrentHashMap<>();
|
||||||
private final ScheduledExecutorService pointDataWriter = Executors.newSingleThreadScheduledExecutor(r -> {
|
private final ScheduledExecutorService pointDataWriter = Executors.newSingleThreadScheduledExecutor(r -> {
|
||||||
Thread thread = new Thread(r);
|
Thread thread = new Thread(r);
|
||||||
thread.setName("point-data-writer");
|
thread.setName("point-data-writer");
|
||||||
@ -201,6 +209,9 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
long startMs = System.currentTimeMillis();
|
long startMs = System.currentTimeMillis();
|
||||||
log.info("开始处理设备数据, siteId: {}, messageSize: {}", siteId, arraylist.size());
|
log.info("开始处理设备数据, siteId: {}, messageSize: {}", siteId, arraylist.size());
|
||||||
Set<String> deviceIds = new LinkedHashSet<>();
|
Set<String> deviceIds = new LinkedHashSet<>();
|
||||||
|
Map<String, String> deviceCategoryMap = buildDeviceCategoryMap(siteId, arraylist);
|
||||||
|
Map<String, BigDecimal> batchContextBySite = buildBatchContextBySite(siteId, arraylist, deviceCategoryMap);
|
||||||
|
Date latestDataUpdateTime = null;
|
||||||
|
|
||||||
for (int i = 0; i < arraylist.size(); i++) {
|
for (int i = 0; i < arraylist.size(); i++) {
|
||||||
JSONObject obj = JSONObject.parseObject(arraylist.get(i).toString());
|
JSONObject obj = JSONObject.parseObject(arraylist.get(i).toString());
|
||||||
@ -209,6 +220,9 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
String jsonData = obj.getString("Data");
|
String jsonData = obj.getString("Data");
|
||||||
Long timestamp = obj.getLong("timestamp");
|
Long timestamp = obj.getLong("timestamp");
|
||||||
Date dataUpdateTime = DateUtils.convertUpdateTime(timestamp);
|
Date dataUpdateTime = DateUtils.convertUpdateTime(timestamp);
|
||||||
|
if (dataUpdateTime != null && (latestDataUpdateTime == null || dataUpdateTime.after(latestDataUpdateTime))) {
|
||||||
|
latestDataUpdateTime = dataUpdateTime;
|
||||||
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(deviceId)) {
|
if (StringUtils.isNotBlank(deviceId)) {
|
||||||
deviceIds.add(deviceId);
|
deviceIds.add(deviceId);
|
||||||
@ -222,65 +236,210 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceId, obj);
|
redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceId, obj);
|
||||||
redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA + siteId + "_" + deviceId, obj, 1, TimeUnit.MINUTES);
|
redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA + siteId + "_" + deviceId, obj, 1, TimeUnit.MINUTES);
|
||||||
|
|
||||||
processPointConfigData(siteId, deviceId, jsonData, dataUpdateTime);
|
String deviceCategory = resolveDeviceCategory(siteId, deviceId, deviceCategoryMap);
|
||||||
iEmsDeviceSettingService.syncSiteMonitorDataByMqtt(siteId, deviceId, jsonData, dataUpdateTime);
|
Map<String, BigDecimal> pointIdValueMap = processPointConfigData(siteId, deviceId, deviceCategory, jsonData, dataUpdateTime);
|
||||||
|
iEmsDeviceSettingService.syncSiteMonitorDataByMqtt(siteId, deviceId, JSON.toJSONString(pointIdValueMap), dataUpdateTime);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("点位映射数据处理失败,siteId: {}, deviceId: {}, err: {}",
|
log.warn("点位映射数据处理失败,siteId: {}, deviceId: {}, err: {}",
|
||||||
siteId, deviceId, e.getMessage(), e);
|
siteId, deviceId, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Map<String, BigDecimal> calcPointIdValueMap = executeCalcPointConfigs(
|
||||||
|
siteId, SITE_LEVEL_CALC_DEVICE_ID, getSiteCalcPointConfigs(siteId), batchContextBySite, latestDataUpdateTime
|
||||||
|
);
|
||||||
|
if (!calcPointIdValueMap.isEmpty()) {
|
||||||
|
iEmsDeviceSettingService.syncSiteMonitorDataByMqtt(
|
||||||
|
siteId, SITE_LEVEL_CALC_DEVICE_ID, JSON.toJSONString(calcPointIdValueMap), latestDataUpdateTime
|
||||||
|
);
|
||||||
|
}
|
||||||
log.info("结束处理设备数据, siteId: {}, deviceCount: {}, deviceIds: {}, costMs: {}",
|
log.info("结束处理设备数据, siteId: {}, deviceCount: {}, deviceIds: {}, costMs: {}",
|
||||||
siteId, deviceIds.size(), String.join(",", deviceIds), System.currentTimeMillis() - startMs);
|
siteId, deviceIds.size(), String.join(",", deviceIds), System.currentTimeMillis() - startMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processPointConfigData(String siteId, String deviceId, String jsonData, Date dataUpdateTime) {
|
private Map<String, BigDecimal> processPointConfigData(String siteId, String deviceId, String deviceCategory, String jsonData, Date dataUpdateTime) {
|
||||||
|
Map<String, BigDecimal> pointIdValueMap = new HashMap<>();
|
||||||
if (StringUtils.isAnyBlank(siteId, deviceId, jsonData)) {
|
if (StringUtils.isAnyBlank(siteId, deviceId, jsonData)) {
|
||||||
return;
|
return pointIdValueMap;
|
||||||
}
|
}
|
||||||
if (!DB_NAME_PATTERN.matcher(siteId).matches()) {
|
if (!DB_NAME_PATTERN.matcher(siteId).matches()) {
|
||||||
log.warn("站点ID不合法,跳过点位映射落库,siteId: {}", siteId);
|
log.warn("站点ID不合法,跳过点位映射落库,siteId: {}", siteId);
|
||||||
return;
|
return pointIdValueMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> dataMap = JSON.parseObject(jsonData, new TypeReference<Map<String, Object>>() {
|
Map<String, Object> dataMap = JSON.parseObject(jsonData, new TypeReference<Map<String, Object>>() {
|
||||||
});
|
});
|
||||||
if (org.apache.commons.collections4.MapUtils.isEmpty(dataMap)) {
|
if (org.apache.commons.collections4.MapUtils.isEmpty(dataMap)) {
|
||||||
return;
|
return pointIdValueMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<EmsPointConfig> pointConfigs = getPointConfigsWithCache(siteId, deviceId);
|
List<EmsPointConfig> pointConfigs = getPointConfigsWithCache(siteId, deviceId, deviceCategory);
|
||||||
if (CollectionUtils.isEmpty(pointConfigs)) {
|
if (CollectionUtils.isEmpty(pointConfigs)) {
|
||||||
return;
|
return pointIdValueMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, EmsPointConfig> configByDataKey = pointConfigs.stream()
|
List<EmsPointConfig> dataPointConfigs = new ArrayList<>();
|
||||||
.filter(cfg -> StringUtils.isNotBlank(cfg.getDataKey()))
|
Set<String> uniquePointKeys = new HashSet<>();
|
||||||
.collect(Collectors.toMap(
|
for (EmsPointConfig pointConfig : pointConfigs) {
|
||||||
cfg -> cfg.getDataKey().toUpperCase(),
|
String pointContextKey = resolvePointContextKey(pointConfig);
|
||||||
cfg -> cfg,
|
if (pointConfig == null || StringUtils.isBlank(pointContextKey)) {
|
||||||
(oldValue, newValue) -> oldValue
|
continue;
|
||||||
));
|
}
|
||||||
|
if (!uniquePointKeys.add(pointContextKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isCalcPoint(pointConfig)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dataPointConfigs.add(pointConfig);
|
||||||
|
}
|
||||||
|
Map<String, BigDecimal> rawDataValues = new HashMap<>();
|
||||||
for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
|
for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
|
||||||
String dataKey = entry.getKey();
|
if (StringUtils.isBlank(entry.getKey())) {
|
||||||
if (StringUtils.isBlank(dataKey)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
EmsPointConfig pointConfig = configByDataKey.get(dataKey.toUpperCase());
|
|
||||||
if (pointConfig == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BigDecimal pointValue = StringUtils.getBigDecimal(entry.getValue());
|
BigDecimal pointValue = StringUtils.getBigDecimal(entry.getValue());
|
||||||
if (pointValue == null) {
|
if (pointValue == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
rawDataValues.put(entry.getKey().trim().toUpperCase(), pointValue);
|
||||||
// 支持按配置进行二次转换:f(x)=A*x^2 + K*x + B
|
|
||||||
pointValue = convertPointValue(pointValue, pointConfig);
|
|
||||||
|
|
||||||
enqueuePointData(siteId, deviceId, pointConfig.getDataKey(), pointValue, dataUpdateTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (EmsPointConfig dataPointConfig : dataPointConfigs) {
|
||||||
|
BigDecimal sourceValue = getSourceValueFromRawData(dataPointConfig, rawDataValues);
|
||||||
|
if (sourceValue == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BigDecimal convertedValue = convertPointValue(sourceValue, dataPointConfig);
|
||||||
|
String pointId = resolveInfluxPointKey(dataPointConfig);
|
||||||
|
if (StringUtils.isBlank(pointId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
enqueuePointData(siteId, deviceId, pointId, convertedValue, dataUpdateTime);
|
||||||
|
pointIdValueMap.put(pointId, convertedValue);
|
||||||
|
}
|
||||||
|
return pointIdValueMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> buildDeviceCategoryMap(String siteId, JSONArray arraylist) {
|
||||||
|
Map<String, String> deviceCategoryMap = new HashMap<>();
|
||||||
|
if (arraylist == null || arraylist.isEmpty()) {
|
||||||
|
return deviceCategoryMap;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < arraylist.size(); i++) {
|
||||||
|
JSONObject item = JSONObject.parseObject(arraylist.get(i).toString());
|
||||||
|
if (item == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String deviceId = item.getString("Device");
|
||||||
|
if (StringUtils.isBlank(deviceId) || deviceCategoryMap.containsKey(deviceId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String category = getDeviceCategory(siteId, deviceId);
|
||||||
|
if (StringUtils.isNotBlank(category)) {
|
||||||
|
deviceCategoryMap.put(deviceId, category);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceCategoryMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveDeviceCategory(String siteId, String deviceId, Map<String, String> deviceCategoryMap) {
|
||||||
|
if (StringUtils.isBlank(deviceId)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String mappedCategory = deviceCategoryMap == null ? null : deviceCategoryMap.get(deviceId);
|
||||||
|
if (StringUtils.isNotBlank(mappedCategory)) {
|
||||||
|
return mappedCategory;
|
||||||
|
}
|
||||||
|
String runtimeCategory = getDeviceCategory(siteId, deviceId);
|
||||||
|
if (StringUtils.isNotBlank(runtimeCategory) && deviceCategoryMap != null) {
|
||||||
|
deviceCategoryMap.put(deviceId, runtimeCategory);
|
||||||
|
}
|
||||||
|
return StringUtils.defaultString(runtimeCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, BigDecimal> buildBatchContextBySite(String siteId, JSONArray arraylist, Map<String, String> deviceCategoryMap) {
|
||||||
|
Map<String, BigDecimal> contextBySite = new HashMap<>();
|
||||||
|
if (arraylist == null || arraylist.isEmpty()) {
|
||||||
|
return contextBySite;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < arraylist.size(); i++) {
|
||||||
|
JSONObject item = JSONObject.parseObject(arraylist.get(i).toString());
|
||||||
|
if (item == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String deviceId = item.getString("Device");
|
||||||
|
String devicePrefix = normalizeVariablePart(deviceId);
|
||||||
|
String deviceCategory = resolveDeviceCategory(siteId, deviceId, deviceCategoryMap);
|
||||||
|
String jsonData = item.getString("Data");
|
||||||
|
if (checkJsonDataEmpty(jsonData)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Map<String, Object> dataMap = JSON.parseObject(jsonData, new TypeReference<Map<String, Object>>() {
|
||||||
|
});
|
||||||
|
if (org.apache.commons.collections4.MapUtils.isEmpty(dataMap)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Map<String, EmsPointConfig> pointConfigByDataKey = new HashMap<>();
|
||||||
|
List<EmsPointConfig> pointConfigs = getPointConfigsWithCache(siteId, deviceId, deviceCategory);
|
||||||
|
if (!CollectionUtils.isEmpty(pointConfigs)) {
|
||||||
|
for (EmsPointConfig pointConfig : pointConfigs) {
|
||||||
|
if (isCalcPoint(pointConfig)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String dataKey = StringUtils.defaultString(pointConfig.getDataKey()).trim().toUpperCase();
|
||||||
|
if (StringUtils.isBlank(dataKey) || pointConfigByDataKey.containsKey(dataKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pointConfigByDataKey.put(dataKey, pointConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
|
||||||
|
if (StringUtils.isBlank(entry.getKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BigDecimal pointValue = StringUtils.getBigDecimal(entry.getValue());
|
||||||
|
if (pointValue == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String normalizedKey = normalizeVariablePart(entry.getKey());
|
||||||
|
if (StringUtils.isBlank(normalizedKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 兼容旧表达式:继续支持直接使用变量名(如 WD4)
|
||||||
|
contextBySite.put(normalizedKey, pointValue);
|
||||||
|
// 新规则:支持设备前缀变量(如 DONGHUAN_WD4)
|
||||||
|
if (StringUtils.isNotBlank(devicePrefix)) {
|
||||||
|
contextBySite.put(devicePrefix + "_" + normalizedKey, pointValue);
|
||||||
|
}
|
||||||
|
// 同时支持按点位ID引用(如 POINT4092)
|
||||||
|
EmsPointConfig pointConfig = pointConfigByDataKey.get(entry.getKey().trim().toUpperCase());
|
||||||
|
if (pointConfig != null) {
|
||||||
|
String pointIdKey = resolvePointContextKey(pointConfig);
|
||||||
|
if (StringUtils.isNotBlank(pointIdKey)) {
|
||||||
|
BigDecimal convertedValue = convertPointValue(pointValue, pointConfig);
|
||||||
|
contextBySite.put(pointIdKey, convertedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return contextBySite;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeVariablePart(String source) {
|
||||||
|
if (StringUtils.isBlank(source)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String normalized = VARIABLE_SAFE_PATTERN.matcher(source.trim().toUpperCase()).replaceAll("_");
|
||||||
|
if (StringUtils.isBlank(normalized)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
normalized = normalized.replaceAll("_+", "_");
|
||||||
|
normalized = StringUtils.strip(normalized, "_");
|
||||||
|
return StringUtils.isBlank(normalized) ? null : normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCalcPoint(EmsPointConfig pointConfig) {
|
||||||
|
return pointConfig != null && "calc".equalsIgnoreCase(pointConfig.getPointType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enqueuePointData(String siteId, String deviceId, String pointKey, BigDecimal pointValue, Date dataTime) {
|
private void enqueuePointData(String siteId, String deviceId, String pointKey, BigDecimal pointValue, Date dataTime) {
|
||||||
@ -325,6 +484,315 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
.add(b);
|
.add(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String resolveInfluxPointKey(EmsPointConfig pointConfig) {
|
||||||
|
if (pointConfig == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(pointConfig.getPointId())) {
|
||||||
|
return pointConfig.getPointId().trim();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, BigDecimal> executeCalcPointConfigs(String siteId, String deviceId, List<EmsPointConfig> calcPointConfigs,
|
||||||
|
Map<String, BigDecimal> contextValues, Date dataUpdateTime) {
|
||||||
|
Map<String, BigDecimal> calcPointIdValueMap = new HashMap<>();
|
||||||
|
if (CollectionUtils.isEmpty(calcPointConfigs)) {
|
||||||
|
return calcPointIdValueMap;
|
||||||
|
}
|
||||||
|
Map<String, EmsPointConfig> remaining = new HashMap<>();
|
||||||
|
for (EmsPointConfig calcPointConfig : calcPointConfigs) {
|
||||||
|
String calcContextKey = resolveCalcContextKey(calcPointConfig);
|
||||||
|
if (calcPointConfig == null || StringUtils.isBlank(calcContextKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
remaining.putIfAbsent(calcContextKey, calcPointConfig);
|
||||||
|
}
|
||||||
|
if (remaining.isEmpty()) {
|
||||||
|
return calcPointIdValueMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!remaining.isEmpty()) {
|
||||||
|
boolean progressed = false;
|
||||||
|
List<String> finishedKeys = new ArrayList<>();
|
||||||
|
List<String> unresolvedKeys = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Map.Entry<String, EmsPointConfig> entry : remaining.entrySet()) {
|
||||||
|
String calcDataKey = entry.getKey();
|
||||||
|
EmsPointConfig calcPointConfig = entry.getValue();
|
||||||
|
try {
|
||||||
|
BigDecimal calcValue = evaluateCalcExpression(calcPointConfig.getCalcExpression(), contextValues);
|
||||||
|
contextValues.put(calcDataKey, calcValue);
|
||||||
|
putPointValueToContext(calcPointConfig, calcValue, contextValues);
|
||||||
|
// 计算点按站点维度统一落库,不再按配置中的 device_id 分流
|
||||||
|
String pointId = resolveInfluxPointKey(calcPointConfig);
|
||||||
|
if (StringUtils.isNotBlank(pointId)) {
|
||||||
|
enqueuePointData(siteId, deviceId, pointId, calcValue, dataUpdateTime);
|
||||||
|
calcPointIdValueMap.put(pointId, calcValue);
|
||||||
|
}
|
||||||
|
finishedKeys.add(calcDataKey);
|
||||||
|
progressed = true;
|
||||||
|
} catch (MissingVariableException missingVariableException) {
|
||||||
|
unresolvedKeys.add(calcDataKey + " <- " + missingVariableException.getVariable());
|
||||||
|
} catch (IllegalArgumentException expressionException) {
|
||||||
|
log.warn("计算点表达式执行失败,siteId: {}, deviceId: {}, dataKey: {}, expression: {}, err: {}",
|
||||||
|
siteId, deviceId, calcPointConfig.getDataKey(), calcPointConfig.getCalcExpression(),
|
||||||
|
expressionException.getMessage());
|
||||||
|
finishedKeys.add(calcDataKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finishedKeys.forEach(remaining::remove);
|
||||||
|
|
||||||
|
if (!progressed) {
|
||||||
|
if (!unresolvedKeys.isEmpty()) {
|
||||||
|
log.warn("计算点依赖未就绪,跳过本轮计算,siteId: {}, deviceId: {}, unresolved: {}",
|
||||||
|
siteId, deviceId, String.join(", ", unresolvedKeys));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return calcPointIdValueMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal getSourceValueFromRawData(EmsPointConfig pointConfig, Map<String, BigDecimal> rawDataValues) {
|
||||||
|
if (pointConfig == null || rawDataValues == null || rawDataValues.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String dataKey = StringUtils.defaultString(pointConfig.getDataKey()).trim().toUpperCase();
|
||||||
|
return StringUtils.isBlank(dataKey) ? null : rawDataValues.get(dataKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putPointValueToContext(EmsPointConfig pointConfig, BigDecimal pointValue, Map<String, BigDecimal> contextValues) {
|
||||||
|
if (pointConfig == null || pointValue == null || contextValues == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String pointKey = resolvePointContextKey(pointConfig);
|
||||||
|
if (StringUtils.isNotBlank(pointKey)) {
|
||||||
|
contextValues.put(pointKey, pointValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveCalcContextKey(EmsPointConfig pointConfig) {
|
||||||
|
return resolvePointContextKey(pointConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolvePointContextKey(EmsPointConfig pointConfig) {
|
||||||
|
if (pointConfig == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String pointId = StringUtils.defaultString(pointConfig.getPointId()).trim().toUpperCase();
|
||||||
|
return StringUtils.isNotBlank(pointId) ? pointId : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal evaluateCalcExpression(String expression, Map<String, BigDecimal> contextValues) {
|
||||||
|
if (StringUtils.isBlank(expression)) {
|
||||||
|
throw new IllegalArgumentException("计算表达式为空");
|
||||||
|
}
|
||||||
|
List<ExpressionToken> rpnTokens = calcExpressionCache.computeIfAbsent(expression, this::compileExpressionToRpn);
|
||||||
|
return evaluateRpnTokens(rpnTokens, contextValues == null ? Collections.emptyMap() : contextValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ExpressionToken> compileExpressionToRpn(String expression) {
|
||||||
|
if (StringUtils.isBlank(expression)) {
|
||||||
|
throw new IllegalArgumentException("计算表达式为空");
|
||||||
|
}
|
||||||
|
List<ExpressionToken> output = new ArrayList<>();
|
||||||
|
Deque<ExpressionToken> operators = new ArrayDeque<>();
|
||||||
|
int index = 0;
|
||||||
|
ExpressionToken previous = null;
|
||||||
|
|
||||||
|
while (index < expression.length()) {
|
||||||
|
char ch = expression.charAt(index);
|
||||||
|
if (Character.isWhitespace(ch)) {
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Character.isDigit(ch) || ch == '.') {
|
||||||
|
int start = index;
|
||||||
|
boolean hasDot = ch == '.';
|
||||||
|
index++;
|
||||||
|
while (index < expression.length()) {
|
||||||
|
char next = expression.charAt(index);
|
||||||
|
if (Character.isDigit(next)) {
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (next == '.' && !hasDot) {
|
||||||
|
hasDot = true;
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String numberText = expression.substring(start, index);
|
||||||
|
try {
|
||||||
|
output.add(ExpressionToken.number(new BigDecimal(numberText)));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("数值格式错误: " + numberText);
|
||||||
|
}
|
||||||
|
previous = output.get(output.size() - 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Character.isLetter(ch) || ch == '_') {
|
||||||
|
int start = index;
|
||||||
|
index++;
|
||||||
|
while (index < expression.length()) {
|
||||||
|
char next = expression.charAt(index);
|
||||||
|
if (Character.isLetterOrDigit(next) || next == '_') {
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String variable = expression.substring(start, index).trim().toUpperCase();
|
||||||
|
output.add(ExpressionToken.variable(variable));
|
||||||
|
previous = output.get(output.size() - 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch == '(') {
|
||||||
|
operators.push(ExpressionToken.leftParen());
|
||||||
|
previous = ExpressionToken.leftParen();
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch == ')') {
|
||||||
|
boolean matched = false;
|
||||||
|
while (!operators.isEmpty()) {
|
||||||
|
ExpressionToken token = operators.pop();
|
||||||
|
if (token.getType() == ExpressionTokenType.LEFT_PAREN) {
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
output.add(token);
|
||||||
|
}
|
||||||
|
if (!matched) {
|
||||||
|
throw new IllegalArgumentException("括号不匹配");
|
||||||
|
}
|
||||||
|
previous = ExpressionToken.rightParen();
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isOperator(ch)) {
|
||||||
|
boolean unaryMinus = ch == '-' && (previous == null
|
||||||
|
|| previous.getType() == ExpressionTokenType.OPERATOR
|
||||||
|
|| previous.getType() == ExpressionTokenType.LEFT_PAREN);
|
||||||
|
String operatorText = unaryMinus ? "~" : String.valueOf(ch);
|
||||||
|
ExpressionToken currentOperator = ExpressionToken.operator(operatorText);
|
||||||
|
while (!operators.isEmpty() && operators.peek().getType() == ExpressionTokenType.OPERATOR) {
|
||||||
|
ExpressionToken top = operators.peek();
|
||||||
|
if (shouldPopOperator(currentOperator, top)) {
|
||||||
|
output.add(operators.pop());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
operators.push(currentOperator);
|
||||||
|
previous = currentOperator;
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("表达式包含非法字符: " + ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!operators.isEmpty()) {
|
||||||
|
ExpressionToken token = operators.pop();
|
||||||
|
if (token.getType() == ExpressionTokenType.LEFT_PAREN) {
|
||||||
|
throw new IllegalArgumentException("括号不匹配");
|
||||||
|
}
|
||||||
|
output.add(token);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal evaluateRpnTokens(List<ExpressionToken> rpnTokens, Map<String, BigDecimal> contextValues) {
|
||||||
|
Deque<BigDecimal> values = new ArrayDeque<>();
|
||||||
|
for (ExpressionToken token : rpnTokens) {
|
||||||
|
if (token.getType() == ExpressionTokenType.NUMBER) {
|
||||||
|
values.push(token.getNumber());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (token.getType() == ExpressionTokenType.VARIABLE) {
|
||||||
|
BigDecimal variableValue = contextValues.get(token.getText());
|
||||||
|
if (variableValue == null) {
|
||||||
|
throw new MissingVariableException(token.getText());
|
||||||
|
}
|
||||||
|
values.push(variableValue);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (token.getType() != ExpressionTokenType.OPERATOR) {
|
||||||
|
throw new IllegalArgumentException("表达式令牌类型不合法: " + token.getType());
|
||||||
|
}
|
||||||
|
if ("~".equals(token.getText())) {
|
||||||
|
if (values.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("表达式不合法,缺少操作数");
|
||||||
|
}
|
||||||
|
values.push(values.pop().negate());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (values.size() < 2) {
|
||||||
|
throw new IllegalArgumentException("表达式不合法,缺少操作数");
|
||||||
|
}
|
||||||
|
BigDecimal right = values.pop();
|
||||||
|
BigDecimal left = values.pop();
|
||||||
|
values.push(applyOperator(left, right, token.getText()));
|
||||||
|
}
|
||||||
|
if (values.size() != 1) {
|
||||||
|
throw new IllegalArgumentException("表达式不合法,无法归约到单值");
|
||||||
|
}
|
||||||
|
return values.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal applyOperator(BigDecimal left, BigDecimal right, String operator) {
|
||||||
|
switch (operator) {
|
||||||
|
case "+":
|
||||||
|
return left.add(right);
|
||||||
|
case "-":
|
||||||
|
return left.subtract(right);
|
||||||
|
case "*":
|
||||||
|
return left.multiply(right);
|
||||||
|
case "/":
|
||||||
|
if (BigDecimal.ZERO.compareTo(right) == 0) {
|
||||||
|
throw new IllegalArgumentException("除数不能为0");
|
||||||
|
}
|
||||||
|
return left.divide(right, 10, RoundingMode.HALF_UP);
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("不支持的操作符: " + operator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldPopOperator(ExpressionToken currentOperator, ExpressionToken stackOperator) {
|
||||||
|
if (currentOperator == null || stackOperator == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int currentPriority = getOperatorPriority(currentOperator.getText());
|
||||||
|
int stackPriority = getOperatorPriority(stackOperator.getText());
|
||||||
|
if (isRightAssociative(currentOperator.getText())) {
|
||||||
|
return stackPriority > currentPriority;
|
||||||
|
}
|
||||||
|
return stackPriority >= currentPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getOperatorPriority(String operator) {
|
||||||
|
if ("~".equals(operator)) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if ("*".equals(operator) || "/".equals(operator)) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if ("+".equals(operator) || "-".equals(operator)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isRightAssociative(String operator) {
|
||||||
|
return "~".equals(operator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOperator(char ch) {
|
||||||
|
return ch == '+' || ch == '-' || ch == '*' || ch == '/';
|
||||||
|
}
|
||||||
|
|
||||||
private void flushPointDataSafely() {
|
private void flushPointDataSafely() {
|
||||||
if (!pointDataFlushing.compareAndSet(false, true)) {
|
if (!pointDataFlushing.compareAndSet(false, true)) {
|
||||||
return;
|
return;
|
||||||
@ -366,21 +834,48 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
influxPointDataWriter.writeBatch(payloads);
|
influxPointDataWriter.writeBatch(payloads);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<EmsPointConfig> getPointConfigsWithCache(String siteId, String deviceId) {
|
private List<EmsPointConfig> getPointConfigsWithCache(String siteId, String deviceId, String deviceCategory) {
|
||||||
String cacheKey = RedisKeyConstants.POINT_CONFIG_DEVICE + siteId + "_" + deviceId;
|
String normalizedCategory = StringUtils.defaultString(deviceCategory).trim().toUpperCase();
|
||||||
|
String cacheKey = RedisKeyConstants.POINT_CONFIG_DEVICE + siteId + "_" + deviceId + "_" + normalizedCategory;
|
||||||
List<EmsPointConfig> cached = redisCache.getCacheObject(cacheKey);
|
List<EmsPointConfig> cached = redisCache.getCacheObject(cacheKey);
|
||||||
if (cached != null) {
|
if (cached != null) {
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1) 设备级点位(原有逻辑)
|
||||||
EmsPointConfig query = new EmsPointConfig();
|
EmsPointConfig query = new EmsPointConfig();
|
||||||
query.setSiteId(siteId);
|
query.setSiteId(siteId);
|
||||||
query.setDeviceId(deviceId);
|
query.setDeviceId(deviceId);
|
||||||
List<EmsPointConfig> latest = emsPointConfigMapper.selectEmsPointConfigList(query);
|
List<EmsPointConfig> cacheValue = emsPointConfigMapper.selectEmsPointConfigList(query);
|
||||||
List<EmsPointConfig> cacheValue = latest == null ? new ArrayList<>() : latest;
|
|
||||||
redisCache.setCacheObject(cacheKey, cacheValue);
|
redisCache.setCacheObject(cacheKey, cacheValue);
|
||||||
return cacheValue;
|
return cacheValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<EmsPointConfig> getSiteCalcPointConfigs(String siteId) {
|
||||||
|
if (StringUtils.isBlank(siteId)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
EmsPointConfig query = new EmsPointConfig();
|
||||||
|
query.setSiteId(siteId);
|
||||||
|
query.setPointType("calc");
|
||||||
|
List<EmsPointConfig> calcPoints = emsPointConfigMapper.selectEmsPointConfigList(query);
|
||||||
|
if (CollectionUtils.isEmpty(calcPoints)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
Map<String, EmsPointConfig> uniqueByPointId = new LinkedHashMap<>();
|
||||||
|
for (EmsPointConfig calcPoint : calcPoints) {
|
||||||
|
if (!isCalcPoint(calcPoint)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String calcKey = resolvePointContextKey(calcPoint);
|
||||||
|
if (StringUtils.isBlank(calcKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uniqueByPointId.putIfAbsent(calcKey, calcPoint);
|
||||||
|
}
|
||||||
|
return new ArrayList<>(uniqueByPointId.values());
|
||||||
|
}
|
||||||
|
|
||||||
private static class PointDataRecord {
|
private static class PointDataRecord {
|
||||||
private final String siteId;
|
private final String siteId;
|
||||||
private final String deviceId;
|
private final String deviceId;
|
||||||
@ -417,6 +912,71 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class MissingVariableException extends IllegalArgumentException {
|
||||||
|
private final String variable;
|
||||||
|
|
||||||
|
private MissingVariableException(String variable) {
|
||||||
|
super("缺少变量: " + variable);
|
||||||
|
this.variable = variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getVariable() {
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ExpressionTokenType {
|
||||||
|
NUMBER,
|
||||||
|
VARIABLE,
|
||||||
|
OPERATOR,
|
||||||
|
LEFT_PAREN,
|
||||||
|
RIGHT_PAREN
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ExpressionToken {
|
||||||
|
private final ExpressionTokenType type;
|
||||||
|
private final String text;
|
||||||
|
private final BigDecimal number;
|
||||||
|
|
||||||
|
private ExpressionToken(ExpressionTokenType type, String text, BigDecimal number) {
|
||||||
|
this.type = type;
|
||||||
|
this.text = text;
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ExpressionToken number(BigDecimal value) {
|
||||||
|
return new ExpressionToken(ExpressionTokenType.NUMBER, null, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ExpressionToken variable(String variable) {
|
||||||
|
return new ExpressionToken(ExpressionTokenType.VARIABLE, variable, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ExpressionToken operator(String operator) {
|
||||||
|
return new ExpressionToken(ExpressionTokenType.OPERATOR, operator, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ExpressionToken leftParen() {
|
||||||
|
return new ExpressionToken(ExpressionTokenType.LEFT_PAREN, "(", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ExpressionToken rightParen() {
|
||||||
|
return new ExpressionToken(ExpressionTokenType.RIGHT_PAREN, ")", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExpressionTokenType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal getNumber() {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private JSONArray parseJsonData(String message) {
|
private JSONArray parseJsonData(String message) {
|
||||||
try {
|
try {
|
||||||
JSONObject object = JSONObject.parseObject(message);
|
JSONObject object = JSONObject.parseObject(message);
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import com.xzzn.common.exception.ServiceException;
|
|||||||
import com.xzzn.common.utils.DateUtils;
|
import com.xzzn.common.utils.DateUtils;
|
||||||
import com.xzzn.common.utils.StringUtils;
|
import com.xzzn.common.utils.StringUtils;
|
||||||
import com.xzzn.ems.domain.EmsDevicesSetting;
|
import com.xzzn.ems.domain.EmsDevicesSetting;
|
||||||
|
import com.xzzn.ems.domain.EmsPointConfig;
|
||||||
import com.xzzn.ems.domain.EmsPointMatch;
|
import com.xzzn.ems.domain.EmsPointMatch;
|
||||||
import com.xzzn.ems.domain.EmsPcsSetting;
|
import com.xzzn.ems.domain.EmsPcsSetting;
|
||||||
import com.xzzn.ems.domain.EmsSiteMonitorItem;
|
import com.xzzn.ems.domain.EmsSiteMonitorItem;
|
||||||
@ -33,6 +34,7 @@ import com.xzzn.ems.domain.vo.SiteMonitorProjectPointMappingVo;
|
|||||||
import com.xzzn.ems.mapper.EmsBatteryDataMinutesMapper;
|
import com.xzzn.ems.mapper.EmsBatteryDataMinutesMapper;
|
||||||
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
|
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
|
||||||
import com.xzzn.ems.mapper.EmsPcsSettingMapper;
|
import com.xzzn.ems.mapper.EmsPcsSettingMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsPointConfigMapper;
|
||||||
import com.xzzn.ems.mapper.EmsPointMatchMapper;
|
import com.xzzn.ems.mapper.EmsPointMatchMapper;
|
||||||
import com.xzzn.ems.mapper.EmsSiteMonitorDataMapper;
|
import com.xzzn.ems.mapper.EmsSiteMonitorDataMapper;
|
||||||
import com.xzzn.ems.mapper.EmsSiteMonitorItemMapper;
|
import com.xzzn.ems.mapper.EmsSiteMonitorItemMapper;
|
||||||
@ -45,12 +47,14 @@ import java.util.Arrays;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -71,9 +75,12 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
private static final String MODULE_HOME = "HOME";
|
private static final String MODULE_HOME = "HOME";
|
||||||
private static final String MODULE_SBJK = "SBJK";
|
private static final String MODULE_SBJK = "SBJK";
|
||||||
private static final String MODULE_TJBB = "TJBB";
|
private static final String MODULE_TJBB = "TJBB";
|
||||||
|
private static final Integer USE_FIXED_DISPLAY_YES = 1;
|
||||||
private static final String HISTORY_TABLE_HOME = "ems_site_monitor_data_home_his";
|
private static final String HISTORY_TABLE_HOME = "ems_site_monitor_data_home_his";
|
||||||
private static final String HISTORY_TABLE_SBJK = "ems_site_monitor_data_sbjk_his";
|
private static final String HISTORY_TABLE_SBJK = "ems_site_monitor_data_sbjk_his";
|
||||||
private static final String HISTORY_TABLE_TJBB = "ems_site_monitor_data_tjbb_his";
|
private static final String HISTORY_TABLE_TJBB = "ems_site_monitor_data_tjbb_his";
|
||||||
|
private static final String DELETED_FIELD_MARK = "__DELETED__";
|
||||||
|
private static final long MONITOR_ITEM_CACHE_TTL_MS = 60_000L;
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmsDevicesSettingMapper emsDevicesMapper;
|
private EmsDevicesSettingMapper emsDevicesMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -81,6 +88,8 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EmsPcsSettingMapper emsPcsSettingMapper;
|
private EmsPcsSettingMapper emsPcsSettingMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private EmsPointConfigMapper emsPointConfigMapper;
|
||||||
|
@Autowired
|
||||||
private RedisCache redisCache;
|
private RedisCache redisCache;
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmsBatteryDataMinutesMapper emsBatteryDataMinutesMapper;
|
private EmsBatteryDataMinutesMapper emsBatteryDataMinutesMapper;
|
||||||
@ -95,6 +104,9 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EmsSiteMonitorDataMapper emsSiteMonitorDataMapper;
|
private EmsSiteMonitorDataMapper emsSiteMonitorDataMapper;
|
||||||
|
|
||||||
|
private volatile List<EmsSiteMonitorItem> monitorItemCache = Collections.emptyList();
|
||||||
|
private volatile long monitorItemCacheExpireAt = 0L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取设备详细信息
|
* 获取设备详细信息
|
||||||
* @param id
|
* @param id
|
||||||
@ -406,16 +418,30 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
if (StringUtils.isBlank(siteId)) {
|
if (StringUtils.isBlank(siteId)) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
List<EmsSiteMonitorItem> itemList = emsSiteMonitorItemMapper.selectEnabledList();
|
List<EmsSiteMonitorItem> itemList = getEnabledMonitorItems();
|
||||||
if (itemList == null || itemList.isEmpty()) {
|
if (itemList == null || itemList.isEmpty()) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
List<EmsSiteMonitorPointMatch> mappingList = emsSiteMonitorPointMatchMapper.selectBySiteId(siteId);
|
List<EmsSiteMonitorPointMatch> mappingList = emsSiteMonitorPointMatchMapper.selectBySiteId(siteId);
|
||||||
|
Set<String> deletedFieldCodeSet = mappingList.stream()
|
||||||
|
.filter(item -> StringUtils.isNotBlank(item.getFieldCode()))
|
||||||
|
.filter(item -> DELETED_FIELD_MARK.equals(item.getDataPoint()))
|
||||||
|
.map(EmsSiteMonitorPointMatch::getFieldCode)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Map<String, EmsSiteMonitorPointMatch> mappingByFieldCode = mappingList.stream()
|
||||||
|
.filter(item -> StringUtils.isNotBlank(item.getFieldCode()))
|
||||||
|
.filter(item -> !DELETED_FIELD_MARK.equals(item.getDataPoint()))
|
||||||
|
.collect(Collectors.toMap(EmsSiteMonitorPointMatch::getFieldCode, item -> item, (a, b) -> b));
|
||||||
Map<String, String> pointMap = mappingList.stream()
|
Map<String, String> pointMap = mappingList.stream()
|
||||||
.filter(item -> StringUtils.isNotBlank(item.getFieldCode()))
|
.filter(item -> StringUtils.isNotBlank(item.getFieldCode()))
|
||||||
|
.filter(item -> !DELETED_FIELD_MARK.equals(item.getDataPoint()))
|
||||||
.collect(Collectors.toMap(EmsSiteMonitorPointMatch::getFieldCode, EmsSiteMonitorPointMatch::getDataPoint, (a, b) -> b));
|
.collect(Collectors.toMap(EmsSiteMonitorPointMatch::getFieldCode, EmsSiteMonitorPointMatch::getDataPoint, (a, b) -> b));
|
||||||
|
|
||||||
itemList.forEach(item -> {
|
itemList.forEach(item -> {
|
||||||
|
if (deletedFieldCodeSet.contains(item.getFieldCode())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EmsSiteMonitorPointMatch pointMatch = mappingByFieldCode.get(item.getFieldCode());
|
||||||
SiteMonitorProjectPointMappingVo vo = new SiteMonitorProjectPointMappingVo();
|
SiteMonitorProjectPointMappingVo vo = new SiteMonitorProjectPointMappingVo();
|
||||||
vo.setModuleCode(item.getModuleCode());
|
vo.setModuleCode(item.getModuleCode());
|
||||||
vo.setModuleName(item.getModuleName());
|
vo.setModuleName(item.getModuleName());
|
||||||
@ -425,6 +451,8 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
vo.setFieldCode(item.getFieldCode());
|
vo.setFieldCode(item.getFieldCode());
|
||||||
vo.setFieldName(item.getFieldName());
|
vo.setFieldName(item.getFieldName());
|
||||||
vo.setDataPoint(pointMap.getOrDefault(item.getFieldCode(), ""));
|
vo.setDataPoint(pointMap.getOrDefault(item.getFieldCode(), ""));
|
||||||
|
vo.setFixedDataPoint(pointMatch == null ? "" : pointMatch.getFixedDataPoint());
|
||||||
|
vo.setUseFixedDisplay(pointMatch == null ? 0 : (pointMatch.getUseFixedDisplay() == null ? 0 : pointMatch.getUseFixedDisplay()));
|
||||||
result.add(vo);
|
result.add(vo);
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
@ -436,37 +464,70 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
throw new ServiceException("站点ID不能为空");
|
throw new ServiceException("站点ID不能为空");
|
||||||
}
|
}
|
||||||
String siteId = request.getSiteId();
|
String siteId = request.getSiteId();
|
||||||
List<EmsSiteMonitorItem> itemList = emsSiteMonitorItemMapper.selectEnabledList();
|
List<EmsSiteMonitorItem> itemList = getEnabledMonitorItems();
|
||||||
if (itemList == null || itemList.isEmpty()) {
|
if (itemList == null || itemList.isEmpty()) {
|
||||||
throw new ServiceException("单站监控配置项为空,请先初始化 ems_site_monitor_item");
|
throw new ServiceException("单站监控配置项为空,请先初始化 ems_site_monitor_item");
|
||||||
}
|
}
|
||||||
Set<String> fieldCodeSet = itemList.stream().map(EmsSiteMonitorItem::getFieldCode).collect(Collectors.toSet());
|
Set<String> fieldCodeSet = itemList.stream().map(EmsSiteMonitorItem::getFieldCode).collect(Collectors.toSet());
|
||||||
emsSiteMonitorPointMatchMapper.deleteBySiteId(siteId);
|
Set<String> deletedFieldCodeSet = new HashSet<>();
|
||||||
|
if (request.getDeletedFieldCodes() != null) {
|
||||||
if (request.getMappings() == null || request.getMappings().isEmpty()) {
|
request.getDeletedFieldCodes().stream()
|
||||||
return 0;
|
.filter(StringUtils::isNotBlank)
|
||||||
|
.map(String::trim)
|
||||||
|
.filter(fieldCodeSet::contains)
|
||||||
|
.forEach(deletedFieldCodeSet::add);
|
||||||
}
|
}
|
||||||
|
int deletedRows = emsSiteMonitorPointMatchMapper.deleteBySiteId(siteId);
|
||||||
|
|
||||||
List<EmsSiteMonitorPointMatch> saveList = new ArrayList<>();
|
List<EmsSiteMonitorPointMatch> saveList = new ArrayList<>();
|
||||||
for (SiteMonitorProjectPointMappingVo mapping : request.getMappings()) {
|
if (request.getMappings() != null) {
|
||||||
if (mapping == null || StringUtils.isBlank(mapping.getFieldCode()) || StringUtils.isBlank(mapping.getDataPoint())) {
|
for (SiteMonitorProjectPointMappingVo mapping : request.getMappings()) {
|
||||||
continue;
|
if (mapping == null || StringUtils.isBlank(mapping.getFieldCode())) {
|
||||||
}
|
continue;
|
||||||
String fieldCode = mapping.getFieldCode().trim();
|
}
|
||||||
if (!fieldCodeSet.contains(fieldCode)) {
|
String fieldCode = mapping.getFieldCode().trim();
|
||||||
continue;
|
if (!fieldCodeSet.contains(fieldCode) || deletedFieldCodeSet.contains(fieldCode)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String dataPoint = StringUtils.isBlank(mapping.getDataPoint()) ? "" : mapping.getDataPoint().trim();
|
||||||
|
String fixedDataPoint = StringUtils.isBlank(mapping.getFixedDataPoint()) ? null : mapping.getFixedDataPoint().trim();
|
||||||
|
Integer useFixedDisplay = mapping.getUseFixedDisplay() == null ? 0 : mapping.getUseFixedDisplay();
|
||||||
|
boolean hasMapping = StringUtils.isNotBlank(dataPoint) || StringUtils.isNotBlank(fixedDataPoint) || USE_FIXED_DISPLAY_YES.equals(useFixedDisplay);
|
||||||
|
if (!hasMapping) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EmsSiteMonitorPointMatch pointMatch = new EmsSiteMonitorPointMatch();
|
||||||
|
pointMatch.setSiteId(siteId);
|
||||||
|
pointMatch.setFieldCode(fieldCode);
|
||||||
|
pointMatch.setDataPoint(dataPoint);
|
||||||
|
pointMatch.setFixedDataPoint(fixedDataPoint);
|
||||||
|
pointMatch.setUseFixedDisplay(useFixedDisplay);
|
||||||
|
pointMatch.setCreateBy(operName);
|
||||||
|
pointMatch.setUpdateBy(operName);
|
||||||
|
saveList.add(pointMatch);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String deletedFieldCode : deletedFieldCodeSet) {
|
||||||
EmsSiteMonitorPointMatch pointMatch = new EmsSiteMonitorPointMatch();
|
EmsSiteMonitorPointMatch pointMatch = new EmsSiteMonitorPointMatch();
|
||||||
pointMatch.setSiteId(siteId);
|
pointMatch.setSiteId(siteId);
|
||||||
pointMatch.setFieldCode(fieldCode);
|
pointMatch.setFieldCode(deletedFieldCode);
|
||||||
pointMatch.setDataPoint(mapping.getDataPoint().trim());
|
pointMatch.setDataPoint(DELETED_FIELD_MARK);
|
||||||
|
pointMatch.setFixedDataPoint(null);
|
||||||
|
pointMatch.setUseFixedDisplay(0);
|
||||||
pointMatch.setCreateBy(operName);
|
pointMatch.setCreateBy(operName);
|
||||||
pointMatch.setUpdateBy(operName);
|
pointMatch.setUpdateBy(operName);
|
||||||
saveList.add(pointMatch);
|
saveList.add(pointMatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 点位映射变更后清理“单站监控最新值”缓存,避免页面回退读取到旧快照
|
||||||
|
clearSiteMonitorLatestCache(siteId);
|
||||||
|
|
||||||
if (saveList.isEmpty()) {
|
if (saveList.isEmpty()) {
|
||||||
return 0;
|
return deletedRows;
|
||||||
}
|
}
|
||||||
return emsSiteMonitorPointMatchMapper.insertBatch(saveList);
|
int insertedRows = emsSiteMonitorPointMatchMapper.insertBatch(saveList);
|
||||||
|
return deletedRows + insertedRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -475,6 +536,12 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
if (mappingList.isEmpty()) {
|
if (mappingList.isEmpty()) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
Set<String> pointIds = mappingList.stream()
|
||||||
|
.map(SiteMonitorProjectPointMappingVo::getDataPoint)
|
||||||
|
.filter(StringUtils::isNotBlank)
|
||||||
|
.map(item -> item.trim().toUpperCase())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Map<String, EmsPointConfig> pointConfigByPointId = buildPointConfigByPointId(siteId, pointIds);
|
||||||
Map<String, Object> homeLatestMap = safeRedisMap(redisCache.getCacheMap(buildSiteMonitorLatestRedisKey(siteId, MODULE_HOME)));
|
Map<String, Object> homeLatestMap = safeRedisMap(redisCache.getCacheMap(buildSiteMonitorLatestRedisKey(siteId, MODULE_HOME)));
|
||||||
Map<String, Object> sbjkLatestMap = safeRedisMap(redisCache.getCacheMap(buildSiteMonitorLatestRedisKey(siteId, MODULE_SBJK)));
|
Map<String, Object> sbjkLatestMap = safeRedisMap(redisCache.getCacheMap(buildSiteMonitorLatestRedisKey(siteId, MODULE_SBJK)));
|
||||||
Map<String, Object> tjbbLatestMap = safeRedisMap(redisCache.getCacheMap(buildSiteMonitorLatestRedisKey(siteId, MODULE_TJBB)));
|
Map<String, Object> tjbbLatestMap = safeRedisMap(redisCache.getCacheMap(buildSiteMonitorLatestRedisKey(siteId, MODULE_TJBB)));
|
||||||
@ -483,6 +550,20 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
for (SiteMonitorProjectPointMappingVo mapping : mappingList) {
|
for (SiteMonitorProjectPointMappingVo mapping : mappingList) {
|
||||||
SiteMonitorProjectDisplayVo vo = new SiteMonitorProjectDisplayVo();
|
SiteMonitorProjectDisplayVo vo = new SiteMonitorProjectDisplayVo();
|
||||||
BeanUtils.copyProperties(mapping, vo);
|
BeanUtils.copyProperties(mapping, vo);
|
||||||
|
if (USE_FIXED_DISPLAY_YES.equals(mapping.getUseFixedDisplay()) && StringUtils.isNotBlank(mapping.getFixedDataPoint())) {
|
||||||
|
vo.setFieldValue(mapping.getFixedDataPoint());
|
||||||
|
vo.setValueTime(null);
|
||||||
|
result.add(vo);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 与“点位配置列表最新值”一致:按 pointId -> 点位配置(dataKey/deviceId) -> MQTT 最新报文读取
|
||||||
|
PointLatestSnapshot latestSnapshot = getLatestSnapshotByPointId(siteId, mapping.getDataPoint(), pointConfigByPointId);
|
||||||
|
if (latestSnapshot != null && latestSnapshot.getFieldValue() != null) {
|
||||||
|
vo.setFieldValue(latestSnapshot.getFieldValue());
|
||||||
|
vo.setValueTime(latestSnapshot.getValueTime());
|
||||||
|
result.add(vo);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Object cacheObj = null;
|
Object cacheObj = null;
|
||||||
if (MODULE_HOME.equals(mapping.getModuleCode())) {
|
if (MODULE_HOME.equals(mapping.getModuleCode())) {
|
||||||
cacheObj = homeLatestMap.get(mapping.getFieldCode());
|
cacheObj = homeLatestMap.get(mapping.getFieldCode());
|
||||||
@ -501,6 +582,139 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, EmsPointConfig> buildPointConfigByPointId(String siteId, Set<String> pointIds) {
|
||||||
|
Map<String, EmsPointConfig> result = new HashMap<>();
|
||||||
|
if (StringUtils.isBlank(siteId) || pointIds == null || pointIds.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
List<EmsPointConfig> configList = emsPointConfigMapper.selectBySiteIdAndPointIds(
|
||||||
|
siteId.trim(),
|
||||||
|
new ArrayList<>(pointIds)
|
||||||
|
);
|
||||||
|
if (configList == null || configList.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (EmsPointConfig config : configList) {
|
||||||
|
if (config == null || StringUtils.isBlank(config.getPointId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String pointId = config.getPointId().trim().toUpperCase();
|
||||||
|
result.putIfAbsent(pointId, config);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PointLatestSnapshot getLatestSnapshotByPointId(String siteId, String pointId, Map<String, EmsPointConfig> pointConfigByPointId) {
|
||||||
|
if (StringUtils.isAnyBlank(siteId, pointId) || pointConfigByPointId == null || pointConfigByPointId.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
EmsPointConfig pointConfig = pointConfigByPointId.get(pointId.trim().toUpperCase());
|
||||||
|
if (pointConfig == null || StringUtils.isAnyBlank(pointConfig.getDeviceId(), pointConfig.getDataKey())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String redisKey = RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + pointConfig.getDeviceId().trim();
|
||||||
|
Object raw = redisCache.getCacheObject(redisKey);
|
||||||
|
if (raw == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JSONObject root = toJsonObject(raw);
|
||||||
|
if (root == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JSONObject dataObject = extractDataObject(root);
|
||||||
|
if (dataObject == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Object rawValue = getValueIgnoreCase(dataObject, pointConfig.getDataKey());
|
||||||
|
BigDecimal sourceValue = StringUtils.getBigDecimal(rawValue);
|
||||||
|
if (sourceValue == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BigDecimal pointValue = convertPointValue(sourceValue, pointConfig);
|
||||||
|
Long timestamp = root.getLong("timestamp");
|
||||||
|
Date valueTime = timestamp == null ? null : DateUtils.convertUpdateTime(timestamp);
|
||||||
|
return new PointLatestSnapshot(pointValue.stripTrailingZeros().toPlainString(), valueTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject toJsonObject(Object raw) {
|
||||||
|
if (raw == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (raw instanceof JSONObject) {
|
||||||
|
return (JSONObject) raw;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return JSON.parseObject(JSON.toJSONString(raw));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject extractDataObject(JSONObject root) {
|
||||||
|
if (root == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JSONObject dataObject = root.getJSONObject("Data");
|
||||||
|
if (dataObject != null) {
|
||||||
|
return dataObject;
|
||||||
|
}
|
||||||
|
String dataJson = root.getString("Data");
|
||||||
|
if (StringUtils.isBlank(dataJson)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return JSON.parseObject(dataJson);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getValueIgnoreCase(JSONObject dataObject, String dataKey) {
|
||||||
|
if (dataObject == null || StringUtils.isBlank(dataKey)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Object directValue = dataObject.get(dataKey);
|
||||||
|
if (directValue != null) {
|
||||||
|
return directValue;
|
||||||
|
}
|
||||||
|
for (String key : dataObject.keySet()) {
|
||||||
|
if (key != null && key.equalsIgnoreCase(dataKey)) {
|
||||||
|
return dataObject.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal convertPointValue(BigDecimal sourceValue, EmsPointConfig pointConfig) {
|
||||||
|
if (sourceValue == null || pointConfig == null) {
|
||||||
|
return sourceValue;
|
||||||
|
}
|
||||||
|
BigDecimal a = pointConfig.getDataA() == null ? BigDecimal.ZERO : pointConfig.getDataA();
|
||||||
|
BigDecimal k = pointConfig.getDataK() == null ? BigDecimal.ONE : pointConfig.getDataK();
|
||||||
|
BigDecimal b = pointConfig.getDataB() == null ? BigDecimal.ZERO : pointConfig.getDataB();
|
||||||
|
return a.multiply(sourceValue).multiply(sourceValue)
|
||||||
|
.add(k.multiply(sourceValue))
|
||||||
|
.add(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PointLatestSnapshot {
|
||||||
|
private final String fieldValue;
|
||||||
|
private final Date valueTime;
|
||||||
|
|
||||||
|
private PointLatestSnapshot(String fieldValue, Date valueTime) {
|
||||||
|
this.fieldValue = fieldValue;
|
||||||
|
this.valueTime = valueTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFieldValue() {
|
||||||
|
return fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getValueTime() {
|
||||||
|
return valueTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int saveSiteMonitorProjectData(SiteMonitorDataSaveRequest request, String operName) {
|
public int saveSiteMonitorProjectData(SiteMonitorDataSaveRequest request, String operName) {
|
||||||
if (request == null || StringUtils.isBlank(request.getSiteId())) {
|
if (request == null || StringUtils.isBlank(request.getSiteId())) {
|
||||||
@ -509,7 +723,7 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
if (request.getItems() == null || request.getItems().isEmpty()) {
|
if (request.getItems() == null || request.getItems().isEmpty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
List<EmsSiteMonitorItem> itemList = emsSiteMonitorItemMapper.selectEnabledList();
|
List<EmsSiteMonitorItem> itemList = getEnabledMonitorItems();
|
||||||
if (itemList == null || itemList.isEmpty()) {
|
if (itemList == null || itemList.isEmpty()) {
|
||||||
throw new ServiceException("单站监控配置项为空,请先初始化 ems_site_monitor_item");
|
throw new ServiceException("单站监控配置项为空,请先初始化 ems_site_monitor_item");
|
||||||
}
|
}
|
||||||
@ -590,7 +804,7 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
if (mappingList == null || mappingList.isEmpty()) {
|
if (mappingList == null || mappingList.isEmpty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
List<EmsSiteMonitorItem> itemList = emsSiteMonitorItemMapper.selectEnabledList();
|
List<EmsSiteMonitorItem> itemList = getEnabledMonitorItems();
|
||||||
if (itemList == null || itemList.isEmpty()) {
|
if (itemList == null || itemList.isEmpty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -608,15 +822,24 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
Map<Date, JSONObject> tjbbHistoryByMinute = new HashMap<>();
|
Map<Date, JSONObject> tjbbHistoryByMinute = new HashMap<>();
|
||||||
|
|
||||||
for (EmsSiteMonitorPointMatch mapping : mappingList) {
|
for (EmsSiteMonitorPointMatch mapping : mappingList) {
|
||||||
if (mapping == null || StringUtils.isAnyBlank(mapping.getFieldCode(), mapping.getDataPoint())) {
|
if (mapping == null || StringUtils.isBlank(mapping.getFieldCode())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (DELETED_FIELD_MARK.equals(mapping.getDataPoint())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
EmsSiteMonitorItem itemDef = itemMap.get(mapping.getFieldCode());
|
EmsSiteMonitorItem itemDef = itemMap.get(mapping.getFieldCode());
|
||||||
if (itemDef == null || StringUtils.isBlank(itemDef.getModuleCode())) {
|
if (itemDef == null || StringUtils.isBlank(itemDef.getModuleCode())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (USE_FIXED_DISPLAY_YES.equals(mapping.getUseFixedDisplay())) {
|
||||||
String point = mapping.getDataPoint().trim();
|
continue;
|
||||||
|
}
|
||||||
|
String point = mapping.getDataPoint();
|
||||||
|
if (StringUtils.isBlank(point)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
point = point.trim();
|
||||||
Object value = upperDataMap.get(point.toUpperCase());
|
Object value = upperDataMap.get(point.toUpperCase());
|
||||||
if (value == null && StringUtils.isNotBlank(deviceId)) {
|
if (value == null && StringUtils.isNotBlank(deviceId)) {
|
||||||
value = upperDataMap.get((deviceId + point).toUpperCase());
|
value = upperDataMap.get((deviceId + point).toUpperCase());
|
||||||
@ -715,6 +938,27 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
return source == null ? new HashMap<>() : source;
|
return source == null ? new HashMap<>() : source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<EmsSiteMonitorItem> getEnabledMonitorItems() {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
List<EmsSiteMonitorItem> cached = monitorItemCache;
|
||||||
|
if (now < monitorItemCacheExpireAt && cached != null) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
synchronized (this) {
|
||||||
|
now = System.currentTimeMillis();
|
||||||
|
if (now < monitorItemCacheExpireAt && monitorItemCache != null) {
|
||||||
|
return monitorItemCache;
|
||||||
|
}
|
||||||
|
List<EmsSiteMonitorItem> latest = emsSiteMonitorItemMapper.selectEnabledList();
|
||||||
|
if (latest == null) {
|
||||||
|
latest = Collections.emptyList();
|
||||||
|
}
|
||||||
|
monitorItemCache = latest;
|
||||||
|
monitorItemCacheExpireAt = now + MONITOR_ITEM_CACHE_TTL_MS;
|
||||||
|
return latest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, String> extractHotColumns(JSONObject merged) {
|
private Map<String, String> extractHotColumns(JSONObject merged) {
|
||||||
Map<String, String> result = new HashMap<>();
|
Map<String, String> result = new HashMap<>();
|
||||||
result.put("hotSoc", extractFieldValue(merged,
|
result.put("hotSoc", extractFieldValue(merged,
|
||||||
@ -833,6 +1077,15 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
return RedisKeyConstants.SITE_MONITOR_LATEST + siteId + "_" + moduleCode;
|
return RedisKeyConstants.SITE_MONITOR_LATEST + siteId + "_" + moduleCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearSiteMonitorLatestCache(String siteId) {
|
||||||
|
if (StringUtils.isBlank(siteId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
redisCache.deleteObject(buildSiteMonitorLatestRedisKey(siteId, MODULE_HOME));
|
||||||
|
redisCache.deleteObject(buildSiteMonitorLatestRedisKey(siteId, MODULE_SBJK));
|
||||||
|
redisCache.deleteObject(buildSiteMonitorLatestRedisKey(siteId, MODULE_TJBB));
|
||||||
|
}
|
||||||
|
|
||||||
// 辅助方法:根据值查找对应的对象(用于比较器中获取完整对象)
|
// 辅助方法:根据值查找对应的对象(用于比较器中获取完整对象)
|
||||||
private PointQueryResponse findByValue(List<PointQueryResponse> list, Object value) {
|
private PointQueryResponse findByValue(List<PointQueryResponse> list, Object value) {
|
||||||
return list.stream()
|
return list.stream()
|
||||||
@ -1050,6 +1303,10 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
public List<WriteTagConfig> getWriteTags(String workStatus, EmsPcsSetting pcsSetting) {
|
public List<WriteTagConfig> getWriteTags(String workStatus, EmsPcsSetting pcsSetting) {
|
||||||
List<WriteTagConfig> writeTags = new ArrayList<>();
|
List<WriteTagConfig> writeTags = new ArrayList<>();
|
||||||
BigDecimal power;
|
BigDecimal power;
|
||||||
|
BigDecimal powerMultiplier = pcsSetting.getPowerMultiplier();
|
||||||
|
if (powerMultiplier == null || BigDecimal.ZERO.compareTo(powerMultiplier) == 0) {
|
||||||
|
powerMultiplier = BigDecimal.ONE;
|
||||||
|
}
|
||||||
|
|
||||||
if (WorkStatus.NORMAL.getCode().equals(workStatus)) {
|
if (WorkStatus.NORMAL.getCode().equals(workStatus)) {
|
||||||
// 开机先发送开机指令再发送有功功率给定值
|
// 开机先发送开机指令再发送有功功率给定值
|
||||||
@ -1073,7 +1330,7 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
if (power == null) {
|
if (power == null) {
|
||||||
power = BigDecimal.ZERO;
|
power = BigDecimal.ZERO;
|
||||||
}
|
}
|
||||||
clusterWriteTag.setValue(power);
|
clusterWriteTag.setValue(power.multiply(powerMultiplier));
|
||||||
writeTags.add(clusterWriteTag);
|
writeTags.add(clusterWriteTag);
|
||||||
}
|
}
|
||||||
if (WorkStatus.STOP.getCode().equals(workStatus)) {
|
if (WorkStatus.STOP.getCode().equals(workStatus)) {
|
||||||
|
|||||||
@ -0,0 +1,144 @@
|
|||||||
|
package com.xzzn.ems.service.impl;
|
||||||
|
|
||||||
|
import com.xzzn.common.exception.ServiceException;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsPointConfig;
|
||||||
|
import com.xzzn.ems.domain.EmsPointCalcConfig;
|
||||||
|
import com.xzzn.ems.service.IEmsPointConfigService;
|
||||||
|
import com.xzzn.ems.service.IEmsPointCalcConfigService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class EmsPointCalcConfigServiceImpl implements IEmsPointCalcConfigService {
|
||||||
|
private static final Pattern CALC_EXPRESSION_PATTERN = Pattern.compile("^[0-9A-Za-z_+\\-*/().\\s]+$");
|
||||||
|
private static final String CALC_POINT_TYPE = "calc";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEmsPointConfigService pointConfigService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<EmsPointCalcConfig> selectPointCalcConfigList(EmsPointCalcConfig pointCalcConfig) {
|
||||||
|
EmsPointConfig query = toPointConfigQuery(pointCalcConfig);
|
||||||
|
List<EmsPointConfig> configList = pointConfigService.selectPointConfigList(query);
|
||||||
|
if (configList == null || configList.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return configList.stream().map(this::toCalcConfig).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EmsPointCalcConfig selectPointCalcConfigById(Long id) {
|
||||||
|
EmsPointConfig config = pointConfigService.selectPointConfigById(id);
|
||||||
|
if (config == null || !CALC_POINT_TYPE.equalsIgnoreCase(config.getPointType())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return toCalcConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertPointCalcConfig(EmsPointCalcConfig pointCalcConfig, String operName) {
|
||||||
|
if (pointCalcConfig == null || StringUtils.isBlank(pointCalcConfig.getSiteId())) {
|
||||||
|
throw new ServiceException("站点ID不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(pointCalcConfig.getPointId())) {
|
||||||
|
throw new ServiceException("点位ID不能为空");
|
||||||
|
}
|
||||||
|
validateCalcExpression(pointCalcConfig.getCalcExpression());
|
||||||
|
return pointConfigService.insertPointConfig(toPointConfig(pointCalcConfig), operName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updatePointCalcConfig(EmsPointCalcConfig pointCalcConfig, String operName) {
|
||||||
|
if (pointCalcConfig == null || StringUtils.isBlank(pointCalcConfig.getSiteId())) {
|
||||||
|
throw new ServiceException("站点ID不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(pointCalcConfig.getPointId())) {
|
||||||
|
throw new ServiceException("点位ID不能为空");
|
||||||
|
}
|
||||||
|
validateCalcExpression(pointCalcConfig.getCalcExpression());
|
||||||
|
return pointConfigService.updatePointConfig(toPointConfig(pointCalcConfig), operName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deletePointCalcConfigByIds(Long[] ids) {
|
||||||
|
return pointConfigService.deletePointConfigByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteBySiteId(String siteId) {
|
||||||
|
if (StringUtils.isBlank(siteId)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EmsPointConfig query = new EmsPointConfig();
|
||||||
|
query.setSiteId(siteId);
|
||||||
|
query.setPointType(CALC_POINT_TYPE);
|
||||||
|
List<EmsPointConfig> configList = pointConfigService.selectPointConfigList(query);
|
||||||
|
if (configList == null || configList.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Long[] ids = configList.stream().map(EmsPointConfig::getId).toArray(Long[]::new);
|
||||||
|
return pointConfigService.deletePointConfigByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateCalcExpression(String expression) {
|
||||||
|
if (StringUtils.isBlank(expression)) {
|
||||||
|
throw new ServiceException("计算表达式不能为空");
|
||||||
|
}
|
||||||
|
if (!CALC_EXPRESSION_PATTERN.matcher(expression).matches()) {
|
||||||
|
throw new ServiceException("计算表达式仅支持数字、字母、下划线、空格和四则运算符");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmsPointConfig toPointConfig(EmsPointCalcConfig calcConfig) {
|
||||||
|
EmsPointConfig pointConfig = new EmsPointConfig();
|
||||||
|
pointConfig.setId(calcConfig.getId());
|
||||||
|
pointConfig.setPointId(calcConfig.getPointId());
|
||||||
|
pointConfig.setSiteId(calcConfig.getSiteId());
|
||||||
|
pointConfig.setPointType(CALC_POINT_TYPE);
|
||||||
|
pointConfig.setDeviceCategory(calcConfig.getDeviceCategory());
|
||||||
|
pointConfig.setDeviceId("");
|
||||||
|
pointConfig.setRegisterAddress("");
|
||||||
|
pointConfig.setPointName(calcConfig.getPointName());
|
||||||
|
pointConfig.setDataKey(calcConfig.getDataKey());
|
||||||
|
pointConfig.setPointDesc(calcConfig.getPointDesc());
|
||||||
|
pointConfig.setDataUnit(calcConfig.getDataUnit());
|
||||||
|
pointConfig.setCalcExpression(calcConfig.getCalcExpression());
|
||||||
|
pointConfig.setRemark(calcConfig.getRemark());
|
||||||
|
return pointConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmsPointConfig toPointConfigQuery(EmsPointCalcConfig calcConfig) {
|
||||||
|
EmsPointConfig query = new EmsPointConfig();
|
||||||
|
query.setSiteId(calcConfig == null ? null : calcConfig.getSiteId());
|
||||||
|
query.setDeviceCategory(calcConfig == null ? null : calcConfig.getDeviceCategory());
|
||||||
|
query.setDataKey(calcConfig == null ? null : calcConfig.getDataKey());
|
||||||
|
query.setPointDesc(calcConfig == null ? null : calcConfig.getPointDesc());
|
||||||
|
query.setPointType(CALC_POINT_TYPE);
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmsPointCalcConfig toCalcConfig(EmsPointConfig pointConfig) {
|
||||||
|
EmsPointCalcConfig calcConfig = new EmsPointCalcConfig();
|
||||||
|
calcConfig.setId(pointConfig.getId());
|
||||||
|
calcConfig.setPointId(pointConfig.getPointId());
|
||||||
|
calcConfig.setSiteId(pointConfig.getSiteId());
|
||||||
|
calcConfig.setDeviceCategory(pointConfig.getDeviceCategory());
|
||||||
|
calcConfig.setPointName(pointConfig.getPointName());
|
||||||
|
calcConfig.setDataKey(pointConfig.getDataKey());
|
||||||
|
calcConfig.setPointDesc(pointConfig.getPointDesc());
|
||||||
|
calcConfig.setDataUnit(pointConfig.getDataUnit());
|
||||||
|
calcConfig.setCalcExpression(pointConfig.getCalcExpression());
|
||||||
|
calcConfig.setRemark(pointConfig.getRemark());
|
||||||
|
calcConfig.setCreateBy(pointConfig.getCreateBy());
|
||||||
|
calcConfig.setCreateTime(pointConfig.getCreateTime());
|
||||||
|
calcConfig.setUpdateBy(pointConfig.getUpdateBy());
|
||||||
|
calcConfig.setUpdateTime(pointConfig.getUpdateTime());
|
||||||
|
return calcConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,7 +17,12 @@ import com.xzzn.ems.domain.vo.PointConfigLatestValueVo;
|
|||||||
import com.xzzn.ems.mapper.EmsPointConfigMapper;
|
import com.xzzn.ems.mapper.EmsPointConfigMapper;
|
||||||
import com.xzzn.ems.service.IEmsPointConfigService;
|
import com.xzzn.ems.service.IEmsPointConfigService;
|
||||||
import com.xzzn.ems.service.InfluxPointDataWriter;
|
import com.xzzn.ems.service.InfluxPointDataWriter;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -43,7 +48,10 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(EmsPointConfigServiceImpl.class);
|
||||||
private static final String TEMPLATE_SITE_ID = "DEFAULT";
|
private static final String TEMPLATE_SITE_ID = "DEFAULT";
|
||||||
|
private static final String SITE_LEVEL_CALC_DEVICE_ID = "SITE_CALC";
|
||||||
|
private static final int CSV_IMPORT_BATCH_SIZE = 200;
|
||||||
private static final Pattern DB_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9_]+$");
|
private static final Pattern DB_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9_]+$");
|
||||||
private static final Pattern INTEGER_PATTERN = Pattern.compile("^-?\\d+$");
|
private static final Pattern INTEGER_PATTERN = Pattern.compile("^-?\\d+$");
|
||||||
private static final Pattern DECIMAL_PATTERN = Pattern.compile("^-?\\d+(\\.\\d+)?$");
|
private static final Pattern DECIMAL_PATTERN = Pattern.compile("^-?\\d+(\\.\\d+)?$");
|
||||||
@ -75,7 +83,12 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
|||||||
normalizeAndValidatePointConfig(pointConfig);
|
normalizeAndValidatePointConfig(pointConfig);
|
||||||
pointConfig.setCreateBy(operName);
|
pointConfig.setCreateBy(operName);
|
||||||
pointConfig.setUpdateBy(operName);
|
pointConfig.setUpdateBy(operName);
|
||||||
int rows = emsPointConfigMapper.insertEmsPointConfig(pointConfig);
|
int rows;
|
||||||
|
try {
|
||||||
|
rows = emsPointConfigMapper.insertEmsPointConfig(pointConfig);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw translatePointConfigPersistenceException(ex, pointConfig == null ? null : pointConfig.getPointId());
|
||||||
|
}
|
||||||
if (rows > 0) {
|
if (rows > 0) {
|
||||||
invalidatePointConfigCache(pointConfig.getSiteId(), pointConfig.getDeviceId());
|
invalidatePointConfigCache(pointConfig.getSiteId(), pointConfig.getDeviceId());
|
||||||
}
|
}
|
||||||
@ -87,7 +100,12 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
|||||||
EmsPointConfig oldConfig = pointConfig.getId() == null ? null : emsPointConfigMapper.selectEmsPointConfigById(pointConfig.getId());
|
EmsPointConfig oldConfig = pointConfig.getId() == null ? null : emsPointConfigMapper.selectEmsPointConfigById(pointConfig.getId());
|
||||||
normalizeAndValidatePointConfig(pointConfig);
|
normalizeAndValidatePointConfig(pointConfig);
|
||||||
pointConfig.setUpdateBy(operName);
|
pointConfig.setUpdateBy(operName);
|
||||||
int rows = emsPointConfigMapper.updateEmsPointConfig(pointConfig);
|
int rows;
|
||||||
|
try {
|
||||||
|
rows = emsPointConfigMapper.updateEmsPointConfig(pointConfig);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw translatePointConfigPersistenceException(ex, pointConfig == null ? null : pointConfig.getPointId());
|
||||||
|
}
|
||||||
if (rows > 0) {
|
if (rows > 0) {
|
||||||
if (oldConfig != null) {
|
if (oldConfig != null) {
|
||||||
invalidatePointConfigCache(oldConfig.getSiteId(), oldConfig.getDeviceId());
|
invalidatePointConfigCache(oldConfig.getSiteId(), oldConfig.getDeviceId());
|
||||||
@ -175,12 +193,25 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
|||||||
emsPointConfigMapper.deleteBySiteId(siteId);
|
emsPointConfigMapper.deleteBySiteId(siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
int importCount = 0;
|
|
||||||
for (EmsPointConfig pointConfig : pointConfigList) {
|
for (EmsPointConfig pointConfig : pointConfigList) {
|
||||||
pointConfig.setCreateBy(operName);
|
pointConfig.setCreateBy(operName);
|
||||||
pointConfig.setUpdateBy(operName);
|
pointConfig.setUpdateBy(operName);
|
||||||
importCount += emsPointConfigMapper.insertEmsPointConfig(pointConfig);
|
|
||||||
}
|
}
|
||||||
|
int importCount = 0;
|
||||||
|
long importStart = System.currentTimeMillis();
|
||||||
|
for (int fromIndex = 0; fromIndex < pointConfigList.size(); fromIndex += CSV_IMPORT_BATCH_SIZE) {
|
||||||
|
int toIndex = Math.min(fromIndex + CSV_IMPORT_BATCH_SIZE, pointConfigList.size());
|
||||||
|
List<EmsPointConfig> batchList = pointConfigList.subList(fromIndex, toIndex);
|
||||||
|
long batchStart = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
importCount += emsPointConfigMapper.insertBatchEmsPointConfig(batchList);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw translatePointConfigPersistenceException(ex, null);
|
||||||
|
}
|
||||||
|
log.info("点位CSV导入批量入库完成,siteId={}, batch={}~{}, batchSize={}, costMs={}",
|
||||||
|
siteId, fromIndex + 1, toIndex, batchList.size(), System.currentTimeMillis() - batchStart);
|
||||||
|
}
|
||||||
|
log.info("点位CSV导入完成,siteId={}, total={}, costMs={}", siteId, importCount, System.currentTimeMillis() - importStart);
|
||||||
|
|
||||||
invalidatePointConfigCacheBySite(siteId);
|
invalidatePointConfigCacheBySite(siteId);
|
||||||
return String.format("导入成功:站点 %s,点位 %d 条", siteId, importCount);
|
return String.format("导入成功:站点 %s,点位 %d 条", siteId, importCount);
|
||||||
@ -214,17 +245,23 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PointConfigCurveValueVo> getCurveData(PointConfigCurveRequest request) {
|
public List<PointConfigCurveValueVo> getCurveData(PointConfigCurveRequest request) {
|
||||||
if (request == null || StringUtils.isAnyBlank(request.getSiteId(), request.getDeviceId(), request.getDataKey())) {
|
if (request == null || StringUtils.isBlank(request.getSiteId())) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
String siteId = StringUtils.trim(request.getSiteId());
|
String siteId = StringUtils.trim(request.getSiteId());
|
||||||
String deviceId = StringUtils.trim(request.getDeviceId());
|
String deviceId = StringUtils.trim(request.getDeviceId());
|
||||||
String dataKey = StringUtils.trim(request.getDataKey());
|
String pointId = StringUtils.trim(request.getPointId());
|
||||||
if (StringUtils.isAnyBlank(siteId, deviceId, dataKey)) {
|
if (StringUtils.isAnyBlank(siteId, pointId)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
EmsPointConfig pointConfig = resolvePointConfigForCurve(siteId, pointId);
|
||||||
|
String pointType = resolvePointTypeForCurve(request, pointConfig);
|
||||||
|
String queryDeviceId = resolveCurveDeviceId(pointType, deviceId, pointConfig);
|
||||||
|
if (StringUtils.isBlank(queryDeviceId)) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
Date[] range = resolveTimeRange(request);
|
Date[] range = resolveTimeRange(request);
|
||||||
return queryCurveDataFromInflux(siteId, deviceId, dataKey, range[0], range[1]);
|
return queryCurveDataFromInflux(siteId, queryDeviceId, pointId, pointConfig, range[0], range[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PointConfigLatestValueVo queryLatestValueFromRedis(PointConfigLatestValueItemVo item,
|
private PointConfigLatestValueVo queryLatestValueFromRedis(PointConfigLatestValueItemVo item,
|
||||||
@ -259,8 +296,13 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
|||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PointConfigCurveValueVo> queryCurveDataFromInflux(String siteId, String deviceId, String dataKey, Date startTime, Date endTime) {
|
private List<PointConfigCurveValueVo> queryCurveDataFromInflux(String siteId, String deviceId, String pointId,
|
||||||
List<InfluxPointDataWriter.PointValue> values = influxPointDataWriter.queryCurveData(siteId, deviceId, dataKey, startTime, endTime);
|
EmsPointConfig pointConfig, Date startTime, Date endTime) {
|
||||||
|
String influxPointKey = resolveInfluxPointKey(pointConfig, pointId);
|
||||||
|
if (StringUtils.isBlank(influxPointKey)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
List<InfluxPointDataWriter.PointValue> values = influxPointDataWriter.queryCurveData(siteId, deviceId, influxPointKey, startTime, endTime);
|
||||||
if (values == null || values.isEmpty()) {
|
if (values == null || values.isEmpty()) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
@ -306,11 +348,53 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RuntimeException translatePointConfigPersistenceException(Exception ex, String pointId) {
|
||||||
|
if (isPointIdDuplicateException(ex)) {
|
||||||
|
String normalizedPointId = StringUtils.trim(pointId);
|
||||||
|
if (StringUtils.isBlank(normalizedPointId)) {
|
||||||
|
return new ServiceException("点位ID已存在(point_id 全局唯一),请修改后重试");
|
||||||
|
}
|
||||||
|
return new ServiceException("点位ID已存在:" + normalizedPointId + "(point_id 全局唯一),请修改后重试");
|
||||||
|
}
|
||||||
|
if (ex instanceof RuntimeException) {
|
||||||
|
return (RuntimeException) ex;
|
||||||
|
}
|
||||||
|
return new ServiceException("点位配置保存失败,请稍后重试");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPointIdDuplicateException(Throwable throwable) {
|
||||||
|
Throwable current = throwable;
|
||||||
|
while (current != null) {
|
||||||
|
if (current instanceof DuplicateKeyException || current instanceof DataIntegrityViolationException) {
|
||||||
|
String message = current.getMessage();
|
||||||
|
if (StringUtils.isNotBlank(message) && message.toLowerCase(Locale.ROOT).contains("uk_point_id")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String message = current.getMessage();
|
||||||
|
if (StringUtils.isNotBlank(message)) {
|
||||||
|
String lowerMessage = message.toLowerCase(Locale.ROOT);
|
||||||
|
if (lowerMessage.contains("duplicate entry") && lowerMessage.contains("uk_point_id")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current = current.getCause();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void invalidatePointConfigCache(String siteId, String deviceId) {
|
private void invalidatePointConfigCache(String siteId, String deviceId) {
|
||||||
if (StringUtils.isAnyBlank(siteId, deviceId)) {
|
if (StringUtils.isBlank(siteId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
redisCache.deleteObject(RedisKeyConstants.POINT_CONFIG_DEVICE + siteId + "_" + deviceId);
|
if (StringUtils.isBlank(deviceId)) {
|
||||||
|
invalidatePointConfigCacheBySite(siteId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Collection<String> keys = redisCache.keys(RedisKeyConstants.POINT_CONFIG_DEVICE + siteId + "_" + deviceId + "_*");
|
||||||
|
if (keys != null && !keys.isEmpty()) {
|
||||||
|
redisCache.deleteObject(keys);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invalidatePointConfigCacheBySite(String siteId) {
|
private void invalidatePointConfigCacheBySite(String siteId) {
|
||||||
@ -410,6 +494,53 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
|||||||
return configByKey.get(dataKey.toUpperCase(Locale.ROOT));
|
return configByKey.get(dataKey.toUpperCase(Locale.ROOT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String resolveInfluxPointKey(EmsPointConfig pointConfig, String pointId) {
|
||||||
|
if (pointConfig != null && StringUtils.isNotBlank(pointConfig.getPointId())) {
|
||||||
|
return pointConfig.getPointId().trim();
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(pointId)) {
|
||||||
|
return pointId.trim();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmsPointConfig resolvePointConfigForCurve(String siteId, String pointId) {
|
||||||
|
if (StringUtils.isAnyBlank(siteId, pointId)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
EmsPointConfig query = new EmsPointConfig();
|
||||||
|
query.setSiteId(siteId);
|
||||||
|
query.setPointId(pointId);
|
||||||
|
List<EmsPointConfig> pointConfigs = emsPointConfigMapper.selectEmsPointConfigList(query);
|
||||||
|
if (CollectionUtils.isEmpty(pointConfigs)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return pointConfigs.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolvePointTypeForCurve(PointConfigCurveRequest request, EmsPointConfig pointConfig) {
|
||||||
|
if (pointConfig != null && StringUtils.isNotBlank(pointConfig.getPointType())) {
|
||||||
|
return StringUtils.trim(pointConfig.getPointType()).toLowerCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
if (request == null || StringUtils.isBlank(request.getPointType())) {
|
||||||
|
return "data";
|
||||||
|
}
|
||||||
|
return StringUtils.trim(request.getPointType()).toLowerCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveCurveDeviceId(String pointType, String requestDeviceId, EmsPointConfig pointConfig) {
|
||||||
|
if ("calc".equalsIgnoreCase(StringUtils.defaultString(pointType))) {
|
||||||
|
return SITE_LEVEL_CALC_DEVICE_ID;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(requestDeviceId)) {
|
||||||
|
return StringUtils.trim(requestDeviceId);
|
||||||
|
}
|
||||||
|
if (pointConfig != null && StringUtils.isNotBlank(pointConfig.getDeviceId())) {
|
||||||
|
return StringUtils.trim(pointConfig.getDeviceId());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private BigDecimal convertPointValue(BigDecimal sourceValue, EmsPointConfig pointConfig) {
|
private BigDecimal convertPointValue(BigDecimal sourceValue, EmsPointConfig pointConfig) {
|
||||||
if (sourceValue == null || pointConfig == null) {
|
if (sourceValue == null || pointConfig == null) {
|
||||||
return sourceValue;
|
return sourceValue;
|
||||||
@ -431,8 +562,7 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
|||||||
}
|
}
|
||||||
List<String> headerList = parseCsvLine(removeUtf8Bom(headerLine));
|
List<String> headerList = parseCsvLine(removeUtf8Bom(headerLine));
|
||||||
Map<String, Integer> headerIndex = buildHeaderIndex(headerList);
|
Map<String, Integer> headerIndex = buildHeaderIndex(headerList);
|
||||||
assertRequiredHeader(headerIndex, "device_category", "device_category");
|
assertRequiredHeader(headerIndex, "point_id", "point_id");
|
||||||
assertRequiredHeader(headerIndex, "device_id", "device_id");
|
|
||||||
assertRequiredHeader(headerIndex, "data_key", "data_key");
|
assertRequiredHeader(headerIndex, "data_key", "data_key");
|
||||||
assertRequiredHeader(headerIndex, "point_desc", "point_desc");
|
assertRequiredHeader(headerIndex, "point_desc", "point_desc");
|
||||||
|
|
||||||
@ -446,8 +576,9 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
|||||||
List<String> valueList = parseCsvLine(line);
|
List<String> valueList = parseCsvLine(line);
|
||||||
EmsPointConfig pointConfig = new EmsPointConfig();
|
EmsPointConfig pointConfig = new EmsPointConfig();
|
||||||
pointConfig.setSiteId(siteId);
|
pointConfig.setSiteId(siteId);
|
||||||
pointConfig.setDeviceCategory(getRequiredString(valueList, headerIndex, "device_category", lineNo));
|
pointConfig.setPointId(getRequiredString(valueList, headerIndex, "point_id", lineNo));
|
||||||
pointConfig.setDeviceId(getRequiredString(valueList, headerIndex, "device_id", lineNo));
|
pointConfig.setDeviceCategory(getString(valueList, headerIndex, "device_category"));
|
||||||
|
pointConfig.setDeviceId(getString(valueList, headerIndex, "device_id"));
|
||||||
pointConfig.setDataKey(getRequiredString(valueList, headerIndex, "data_key", lineNo));
|
pointConfig.setDataKey(getRequiredString(valueList, headerIndex, "data_key", lineNo));
|
||||||
pointConfig.setPointDesc(getRequiredString(valueList, headerIndex, "point_desc", lineNo));
|
pointConfig.setPointDesc(getRequiredString(valueList, headerIndex, "point_desc", lineNo));
|
||||||
String registerAddress = getString(valueList, headerIndex, "register_address");
|
String registerAddress = getString(valueList, headerIndex, "register_address");
|
||||||
@ -555,6 +686,9 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
|||||||
case "siteid":
|
case "siteid":
|
||||||
case "站点id":
|
case "站点id":
|
||||||
return "site_id";
|
return "site_id";
|
||||||
|
case "pointid":
|
||||||
|
case "点位id":
|
||||||
|
return "point_id";
|
||||||
case "devicecategory":
|
case "devicecategory":
|
||||||
case "设备类型":
|
case "设备类型":
|
||||||
return "device_category";
|
return "device_category";
|
||||||
@ -643,6 +777,12 @@ public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
|||||||
if (pointConfig == null) {
|
if (pointConfig == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
pointConfig.setPointId(StringUtils.trimToNull(pointConfig.getPointId()));
|
||||||
|
if (StringUtils.isBlank(pointConfig.getPointId())) {
|
||||||
|
throw new ServiceException("点位ID不能为空");
|
||||||
|
}
|
||||||
|
pointConfig.setDeviceCategory(StringUtils.trimToNull(pointConfig.getDeviceCategory()));
|
||||||
|
pointConfig.setDeviceId(StringUtils.trimToNull(pointConfig.getDeviceId()));
|
||||||
pointConfig.setPointType(normalizePointType(pointConfig.getPointType()));
|
pointConfig.setPointType(normalizePointType(pointConfig.getPointType()));
|
||||||
pointConfig.setCalcExpression(StringUtils.trimToNull(pointConfig.getCalcExpression()));
|
pointConfig.setCalcExpression(StringUtils.trimToNull(pointConfig.getCalcExpression()));
|
||||||
if ("calc".equals(pointConfig.getPointType())) {
|
if ("calc".equals(pointConfig.getPointType())) {
|
||||||
|
|||||||
@ -0,0 +1,87 @@
|
|||||||
|
package com.xzzn.ems.service.impl;
|
||||||
|
|
||||||
|
import com.xzzn.common.utils.DateUtils;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsStrategyRuntimeConfig;
|
||||||
|
import com.xzzn.ems.mapper.EmsStrategyRuntimeConfigMapper;
|
||||||
|
import com.xzzn.ems.service.IEmsStrategyRuntimeConfigService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策略运行参数配置Service业务层处理
|
||||||
|
*
|
||||||
|
* @author xzzn
|
||||||
|
* @date 2026-02-13
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class EmsStrategyRuntimeConfigServiceImpl implements IEmsStrategyRuntimeConfigService {
|
||||||
|
|
||||||
|
private static final BigDecimal DEFAULT_SOC_DOWN = BigDecimal.ZERO;
|
||||||
|
private static final BigDecimal DEFAULT_SOC_UP = new BigDecimal("100");
|
||||||
|
private static final BigDecimal DEFAULT_ANTI_REVERSE_THRESHOLD = new BigDecimal("30");
|
||||||
|
private static final BigDecimal DEFAULT_ANTI_REVERSE_RANGE_PERCENT = new BigDecimal("20");
|
||||||
|
private static final BigDecimal DEFAULT_ANTI_REVERSE_UP = new BigDecimal("100");
|
||||||
|
private static final BigDecimal DEFAULT_ANTI_REVERSE_POWER_DOWN_PERCENT = new BigDecimal("10");
|
||||||
|
private static final BigDecimal DEFAULT_ANTI_REVERSE_HARD_STOP_THRESHOLD = new BigDecimal("20");
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EmsStrategyRuntimeConfigMapper runtimeConfigMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EmsStrategyRuntimeConfig getBySiteId(String siteId) {
|
||||||
|
EmsStrategyRuntimeConfig config = runtimeConfigMapper.selectBySiteId(siteId);
|
||||||
|
if (config == null) {
|
||||||
|
return buildDefaultConfig(siteId);
|
||||||
|
}
|
||||||
|
fillMissingWithDefault(config, siteId);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int saveBySiteId(EmsStrategyRuntimeConfig config) {
|
||||||
|
fillMissingWithDefault(config, config.getSiteId());
|
||||||
|
EmsStrategyRuntimeConfig exist = runtimeConfigMapper.selectBySiteId(config.getSiteId());
|
||||||
|
if (exist == null) {
|
||||||
|
config.setCreateTime(DateUtils.getNowDate());
|
||||||
|
return runtimeConfigMapper.insert(config);
|
||||||
|
}
|
||||||
|
config.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
return runtimeConfigMapper.updateBySiteId(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmsStrategyRuntimeConfig buildDefaultConfig(String siteId) {
|
||||||
|
EmsStrategyRuntimeConfig config = new EmsStrategyRuntimeConfig();
|
||||||
|
fillMissingWithDefault(config, siteId);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillMissingWithDefault(EmsStrategyRuntimeConfig config, String siteId) {
|
||||||
|
if (StringUtils.isNotEmpty(siteId)) {
|
||||||
|
config.setSiteId(siteId);
|
||||||
|
}
|
||||||
|
if (config.getSocDown() == null) {
|
||||||
|
config.setSocDown(DEFAULT_SOC_DOWN);
|
||||||
|
}
|
||||||
|
if (config.getSocUp() == null) {
|
||||||
|
config.setSocUp(DEFAULT_SOC_UP);
|
||||||
|
}
|
||||||
|
if (config.getAntiReverseThreshold() == null) {
|
||||||
|
config.setAntiReverseThreshold(DEFAULT_ANTI_REVERSE_THRESHOLD);
|
||||||
|
}
|
||||||
|
if (config.getAntiReverseRangePercent() == null) {
|
||||||
|
config.setAntiReverseRangePercent(DEFAULT_ANTI_REVERSE_RANGE_PERCENT);
|
||||||
|
}
|
||||||
|
if (config.getAntiReverseUp() == null) {
|
||||||
|
config.setAntiReverseUp(DEFAULT_ANTI_REVERSE_UP);
|
||||||
|
}
|
||||||
|
if (config.getAntiReversePowerDownPercent() == null) {
|
||||||
|
config.setAntiReversePowerDownPercent(DEFAULT_ANTI_REVERSE_POWER_DOWN_PERCENT);
|
||||||
|
}
|
||||||
|
if (config.getAntiReverseHardStopThreshold() == null) {
|
||||||
|
config.setAntiReverseHardStopThreshold(DEFAULT_ANTI_REVERSE_HARD_STOP_THRESHOLD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -92,6 +92,9 @@ public class EmsStrategyTempServiceImpl implements IEmsStrategyTempService
|
|||||||
temp.setStartTime(timeConfig.getStartTime());
|
temp.setStartTime(timeConfig.getStartTime());
|
||||||
temp.setEndTime(timeConfig.getEndTime());
|
temp.setEndTime(timeConfig.getEndTime());
|
||||||
temp.setChargeDischargePower(timeConfig.getChargeDischargePower());
|
temp.setChargeDischargePower(timeConfig.getChargeDischargePower());
|
||||||
|
// 每个时间段可独立配置SOC上下限;为空时兼容旧的模板级配置
|
||||||
|
temp.setSdcDown(timeConfig.getSdcDown() != null ? timeConfig.getSdcDown() : publicTemp.getSdcDown());
|
||||||
|
temp.setSdcUp(timeConfig.getSdcUp() != null ? timeConfig.getSdcUp() : publicTemp.getSdcUp());
|
||||||
temp.setChargeStatus(timeConfig.getChargeStatus());
|
temp.setChargeStatus(timeConfig.getChargeStatus());
|
||||||
emsStrategyTempMapper.insertEmsStrategyTemp(temp);
|
emsStrategyTempMapper.insertEmsStrategyTemp(temp);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -176,11 +176,15 @@ public class GeneralQueryServiceImpl implements IGeneralQueryService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<GeneralQueryDataVo> queryPointCurve(EmsPointConfig config, int dataUnit, Date startDate, Date endDate) {
|
private List<GeneralQueryDataVo> queryPointCurve(EmsPointConfig config, int dataUnit, Date startDate, Date endDate) {
|
||||||
if (config == null || config.getSiteId() == null || config.getDeviceId() == null || config.getDataKey() == null) {
|
if (config == null || config.getSiteId() == null || config.getDeviceId() == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
String influxPointKey = resolveInfluxPointKey(config);
|
||||||
|
if (influxPointKey == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
List<InfluxPointDataWriter.PointValue> values = influxPointDataWriter.queryCurveData(
|
List<InfluxPointDataWriter.PointValue> values = influxPointDataWriter.queryCurveData(
|
||||||
config.getSiteId(), config.getDeviceId(), config.getDataKey(), startDate, endDate
|
config.getSiteId(), config.getDeviceId(), influxPointKey, startDate, endDate
|
||||||
);
|
);
|
||||||
if (values == null || values.isEmpty()) {
|
if (values == null || values.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@ -205,6 +209,16 @@ public class GeneralQueryServiceImpl implements IGeneralQueryService
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String resolveInfluxPointKey(EmsPointConfig config) {
|
||||||
|
if (config == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (config.getPointId() != null && !"".equals(config.getPointId().trim())) {
|
||||||
|
return config.getPointId().trim();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private String buildDisplayDeviceId(EmsPointConfig config) {
|
private String buildDisplayDeviceId(EmsPointConfig config) {
|
||||||
String pointName = config.getPointName() == null || "".equals(config.getPointName().trim())
|
String pointName = config.getPointName() == null || "".equals(config.getPointName().trim())
|
||||||
? config.getDataKey() : config.getPointName().trim();
|
? config.getDataKey() : config.getPointName().trim();
|
||||||
|
|||||||
@ -13,6 +13,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="stopCommand" column="stop_command" />
|
<result property="stopCommand" column="stop_command" />
|
||||||
<result property="startPower" column="start_power" />
|
<result property="startPower" column="start_power" />
|
||||||
<result property="stopPower" column="stop_power" />
|
<result property="stopPower" column="stop_power" />
|
||||||
|
<result property="powerMultiplier" column="power_multiplier" />
|
||||||
<result property="clusterNum" column="cluster_num" />
|
<result property="clusterNum" column="cluster_num" />
|
||||||
<result property="clusterPointAddress" column="cluster_point_address" />
|
<result property="clusterPointAddress" column="cluster_point_address" />
|
||||||
<result property="createBy" column="create_by" />
|
<result property="createBy" column="create_by" />
|
||||||
@ -23,7 +24,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectEmsPcsSettingVo">
|
<sql id="selectEmsPcsSettingVo">
|
||||||
select id, device_setting_id, point_address, power_address, start_command, stop_command, start_power, stop_power, cluster_num, cluster_point_address, create_by, create_time, update_by, update_time, remark from ems_pcs_setting
|
select id, device_setting_id, point_address, power_address, start_command, stop_command, start_power, stop_power, power_multiplier, cluster_num, cluster_point_address, create_by, create_time, update_by, update_time, remark from ems_pcs_setting
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="selectEmsPcsSettingList" parameterType="EmsPcsSetting" resultMap="EmsPcsSettingResult">
|
<select id="selectEmsPcsSettingList" parameterType="EmsPcsSetting" resultMap="EmsPcsSettingResult">
|
||||||
@ -36,6 +37,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="stopCommand != null and stopCommand != ''"> and stop_command = #{stopCommand}</if>
|
<if test="stopCommand != null and stopCommand != ''"> and stop_command = #{stopCommand}</if>
|
||||||
<if test="startPower != null "> and start_power = #{startPower}</if>
|
<if test="startPower != null "> and start_power = #{startPower}</if>
|
||||||
<if test="stopPower != null "> and stop_power = #{stopPower}</if>
|
<if test="stopPower != null "> and stop_power = #{stopPower}</if>
|
||||||
|
<if test="powerMultiplier != null "> and power_multiplier = #{powerMultiplier}</if>
|
||||||
<if test="clusterNum != null "> and cluster_num = #{clusterNum}</if>
|
<if test="clusterNum != null "> and cluster_num = #{clusterNum}</if>
|
||||||
<if test="clusterPointAddress != null and clusterPointAddress != ''"> and cluster_point_address = #{clusterPointAddress}</if>
|
<if test="clusterPointAddress != null and clusterPointAddress != ''"> and cluster_point_address = #{clusterPointAddress}</if>
|
||||||
</where>
|
</where>
|
||||||
@ -61,6 +63,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="stopCommand != null">stop_command,</if>
|
<if test="stopCommand != null">stop_command,</if>
|
||||||
<if test="startPower != null">start_power,</if>
|
<if test="startPower != null">start_power,</if>
|
||||||
<if test="stopPower != null">stop_power,</if>
|
<if test="stopPower != null">stop_power,</if>
|
||||||
|
<if test="powerMultiplier != null">power_multiplier,</if>
|
||||||
<if test="clusterNum != null">cluster_num,</if>
|
<if test="clusterNum != null">cluster_num,</if>
|
||||||
<if test="clusterPointAddress != null">cluster_point_address,</if>
|
<if test="clusterPointAddress != null">cluster_point_address,</if>
|
||||||
<if test="createBy != null">create_by,</if>
|
<if test="createBy != null">create_by,</if>
|
||||||
@ -77,6 +80,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="stopCommand != null">#{stopCommand},</if>
|
<if test="stopCommand != null">#{stopCommand},</if>
|
||||||
<if test="startPower != null">#{startPower},</if>
|
<if test="startPower != null">#{startPower},</if>
|
||||||
<if test="stopPower != null">#{stopPower},</if>
|
<if test="stopPower != null">#{stopPower},</if>
|
||||||
|
<if test="powerMultiplier != null">#{powerMultiplier},</if>
|
||||||
<if test="clusterNum != null">#{clusterNum},</if>
|
<if test="clusterNum != null">#{clusterNum},</if>
|
||||||
<if test="clusterPointAddress != null">#{clusterPointAddress},</if>
|
<if test="clusterPointAddress != null">#{clusterPointAddress},</if>
|
||||||
<if test="createBy != null">#{createBy},</if>
|
<if test="createBy != null">#{createBy},</if>
|
||||||
@ -97,6 +101,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="stopCommand != null">stop_command = #{stopCommand},</if>
|
<if test="stopCommand != null">stop_command = #{stopCommand},</if>
|
||||||
<if test="startPower != null">start_power = #{startPower},</if>
|
<if test="startPower != null">start_power = #{startPower},</if>
|
||||||
<if test="stopPower != null">stop_power = #{stopPower},</if>
|
<if test="stopPower != null">stop_power = #{stopPower},</if>
|
||||||
|
<if test="powerMultiplier != null">power_multiplier = #{powerMultiplier},</if>
|
||||||
<if test="clusterNum != null">cluster_num = #{clusterNum},</if>
|
<if test="clusterNum != null">cluster_num = #{clusterNum},</if>
|
||||||
<if test="clusterPointAddress != null">cluster_point_address = #{clusterPointAddress},</if>
|
<if test="clusterPointAddress != null">cluster_point_address = #{clusterPointAddress},</if>
|
||||||
<if test="createBy != null">create_by = #{createBy},</if>
|
<if test="createBy != null">create_by = #{createBy},</if>
|
||||||
@ -129,6 +134,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="stopCommand != null">stop_command = #{stopCommand},</if>
|
<if test="stopCommand != null">stop_command = #{stopCommand},</if>
|
||||||
<if test="startPower != null">start_power = #{startPower},</if>
|
<if test="startPower != null">start_power = #{startPower},</if>
|
||||||
<if test="stopPower != null">stop_power = #{stopPower},</if>
|
<if test="stopPower != null">stop_power = #{stopPower},</if>
|
||||||
|
<if test="powerMultiplier != null">power_multiplier = #{powerMultiplier},</if>
|
||||||
<if test="clusterNum != null">cluster_num = #{clusterNum},</if>
|
<if test="clusterNum != null">cluster_num = #{clusterNum},</if>
|
||||||
<if test="clusterPointAddress != null">cluster_point_address = #{clusterPointAddress},</if>
|
<if test="clusterPointAddress != null">cluster_point_address = #{clusterPointAddress},</if>
|
||||||
<if test="createBy != null">create_by = #{createBy},</if>
|
<if test="createBy != null">create_by = #{createBy},</if>
|
||||||
@ -140,4 +146,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
where device_setting_id = #{deviceSettingId}
|
where device_setting_id = #{deviceSettingId}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@ -0,0 +1,116 @@
|
|||||||
|
<?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.xzzn.ems.mapper.EmsPointCalcConfigMapper">
|
||||||
|
|
||||||
|
<resultMap type="EmsPointCalcConfig" id="EmsPointCalcConfigResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="siteId" column="site_id"/>
|
||||||
|
<result property="deviceCategory" column="device_category"/>
|
||||||
|
<result property="pointName" column="point_name"/>
|
||||||
|
<result property="dataKey" column="data_key"/>
|
||||||
|
<result property="pointDesc" column="point_desc"/>
|
||||||
|
<result property="dataUnit" column="data_unit"/>
|
||||||
|
<result property="calcExpression" column="calc_expression"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectEmsPointCalcConfigVo">
|
||||||
|
select id, site_id, device_category, point_name, data_key, point_desc, data_unit, calc_expression,
|
||||||
|
create_by, create_time, update_by, update_time, remark
|
||||||
|
from ems_point_calc_config
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectEmsPointCalcConfigById" parameterType="Long" resultMap="EmsPointCalcConfigResult">
|
||||||
|
<include refid="selectEmsPointCalcConfigVo"/>
|
||||||
|
where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectEmsPointCalcConfigList" parameterType="EmsPointCalcConfig" resultMap="EmsPointCalcConfigResult">
|
||||||
|
<include refid="selectEmsPointCalcConfigVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="siteId != null and siteId != ''">and site_id = #{siteId}</if>
|
||||||
|
<if test="deviceCategory != null and deviceCategory != ''">and device_category = #{deviceCategory}</if>
|
||||||
|
<if test="dataKey != null and dataKey != ''">and data_key like concat('%', #{dataKey}, '%')</if>
|
||||||
|
<if test="pointDesc != null and pointDesc != ''">and point_desc like concat('%', #{pointDesc}, '%')</if>
|
||||||
|
</where>
|
||||||
|
order by update_time desc, id desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertEmsPointCalcConfig" parameterType="EmsPointCalcConfig" useGeneratedKeys="true" keyProperty="id">
|
||||||
|
insert into ems_point_calc_config
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="siteId != null">site_id,</if>
|
||||||
|
<if test="deviceCategory != null">device_category,</if>
|
||||||
|
<if test="pointName != null">point_name,</if>
|
||||||
|
<if test="dataKey != null">data_key,</if>
|
||||||
|
<if test="pointDesc != null">point_desc,</if>
|
||||||
|
<if test="dataUnit != null">data_unit,</if>
|
||||||
|
<if test="calcExpression != null">calc_expression,</if>
|
||||||
|
<if test="createBy != null">create_by,</if>
|
||||||
|
<if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if>
|
||||||
|
<if test="updateTime != null">update_time,</if>
|
||||||
|
<if test="remark != null">remark,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="siteId != null">#{siteId},</if>
|
||||||
|
<if test="deviceCategory != null">#{deviceCategory},</if>
|
||||||
|
<if test="pointName != null">#{pointName},</if>
|
||||||
|
<if test="dataKey != null">#{dataKey},</if>
|
||||||
|
<if test="pointDesc != null">#{pointDesc},</if>
|
||||||
|
<if test="dataUnit != null">#{dataUnit},</if>
|
||||||
|
<if test="calcExpression != null">#{calcExpression},</if>
|
||||||
|
<if test="createBy != null">#{createBy},</if>
|
||||||
|
<if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if>
|
||||||
|
<if test="updateTime != null">#{updateTime},</if>
|
||||||
|
<if test="remark != null">#{remark},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateEmsPointCalcConfig" parameterType="EmsPointCalcConfig">
|
||||||
|
update ems_point_calc_config
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="siteId != null">site_id = #{siteId},</if>
|
||||||
|
<if test="deviceCategory != null">device_category = #{deviceCategory},</if>
|
||||||
|
<if test="pointName != null">point_name = #{pointName},</if>
|
||||||
|
<if test="dataKey != null">data_key = #{dataKey},</if>
|
||||||
|
<if test="pointDesc != null">point_desc = #{pointDesc},</if>
|
||||||
|
<if test="dataUnit != null">data_unit = #{dataUnit},</if>
|
||||||
|
<if test="calcExpression != null">calc_expression = #{calcExpression},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||||
|
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
</trim>
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteEmsPointCalcConfigById" parameterType="Long">
|
||||||
|
delete from ems_point_calc_config where id = #{id}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<delete id="deleteEmsPointCalcConfigByIds" parameterType="String">
|
||||||
|
delete from ems_point_calc_config where id in
|
||||||
|
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<select id="countBySiteId" resultType="int">
|
||||||
|
select count(1)
|
||||||
|
from ems_point_calc_config
|
||||||
|
where site_id = #{siteId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<delete id="deleteBySiteId">
|
||||||
|
delete from ems_point_calc_config
|
||||||
|
where site_id = #{siteId}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
<resultMap type="EmsPointConfig" id="EmsPointConfigResult">
|
<resultMap type="EmsPointConfig" id="EmsPointConfigResult">
|
||||||
<result property="id" column="id"/>
|
<result property="id" column="id"/>
|
||||||
|
<result property="pointId" column="point_id"/>
|
||||||
<result property="siteId" column="site_id"/>
|
<result property="siteId" column="site_id"/>
|
||||||
<result property="deviceCategory" column="device_category"/>
|
<result property="deviceCategory" column="device_category"/>
|
||||||
<result property="deviceId" column="device_id"/>
|
<result property="deviceId" column="device_id"/>
|
||||||
@ -29,7 +30,7 @@
|
|||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectEmsPointConfigVo">
|
<sql id="selectEmsPointConfigVo">
|
||||||
select id, site_id, device_category, device_id, point_name, data_key, point_desc, register_address,
|
select id, point_id, site_id, device_category, device_id, point_name, data_key, point_desc, register_address,
|
||||||
data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression,
|
data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression,
|
||||||
create_by, create_time, update_by, update_time, remark
|
create_by, create_time, update_by, update_time, remark
|
||||||
from ems_point_config
|
from ems_point_config
|
||||||
@ -44,6 +45,7 @@
|
|||||||
<include refid="selectEmsPointConfigVo"/>
|
<include refid="selectEmsPointConfigVo"/>
|
||||||
<where>
|
<where>
|
||||||
<if test="siteId != null and siteId != ''">and site_id = #{siteId}</if>
|
<if test="siteId != null and siteId != ''">and site_id = #{siteId}</if>
|
||||||
|
<if test="pointId != null and pointId != ''">and point_id = #{pointId}</if>
|
||||||
<if test="deviceCategory != null and deviceCategory != ''">and device_category = #{deviceCategory}</if>
|
<if test="deviceCategory != null and deviceCategory != ''">and device_category = #{deviceCategory}</if>
|
||||||
<if test="deviceId != null and deviceId != ''">and device_id = #{deviceId}</if>
|
<if test="deviceId != null and deviceId != ''">and device_id = #{deviceId}</if>
|
||||||
<if test="dataKey != null and dataKey != ''">and data_key like concat('%', #{dataKey}, '%')</if>
|
<if test="dataKey != null and dataKey != ''">and data_key like concat('%', #{dataKey}, '%')</if>
|
||||||
@ -57,6 +59,7 @@
|
|||||||
<insert id="insertEmsPointConfig" parameterType="EmsPointConfig" useGeneratedKeys="true" keyProperty="id">
|
<insert id="insertEmsPointConfig" parameterType="EmsPointConfig" useGeneratedKeys="true" keyProperty="id">
|
||||||
insert into ems_point_config
|
insert into ems_point_config
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="pointId != null">point_id,</if>
|
||||||
<if test="siteId != null">site_id,</if>
|
<if test="siteId != null">site_id,</if>
|
||||||
<if test="deviceCategory != null">device_category,</if>
|
<if test="deviceCategory != null">device_category,</if>
|
||||||
<if test="deviceId != null">device_id,</if>
|
<if test="deviceId != null">device_id,</if>
|
||||||
@ -79,6 +82,7 @@
|
|||||||
<if test="remark != null">remark,</if>
|
<if test="remark != null">remark,</if>
|
||||||
</trim>
|
</trim>
|
||||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="pointId != null">#{pointId},</if>
|
||||||
<if test="siteId != null">#{siteId},</if>
|
<if test="siteId != null">#{siteId},</if>
|
||||||
<if test="deviceCategory != null">#{deviceCategory},</if>
|
<if test="deviceCategory != null">#{deviceCategory},</if>
|
||||||
<if test="deviceId != null">#{deviceId},</if>
|
<if test="deviceId != null">#{deviceId},</if>
|
||||||
@ -102,9 +106,44 @@
|
|||||||
</trim>
|
</trim>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
<insert id="insertBatchEmsPointConfig">
|
||||||
|
insert into ems_point_config (
|
||||||
|
point_id, site_id, device_category, device_id, point_name, data_key, point_desc, register_address,
|
||||||
|
data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression,
|
||||||
|
create_by, create_time, update_by, update_time, remark
|
||||||
|
)
|
||||||
|
values
|
||||||
|
<foreach collection="list" item="item" separator=",">
|
||||||
|
(
|
||||||
|
#{item.pointId},
|
||||||
|
#{item.siteId},
|
||||||
|
#{item.deviceCategory},
|
||||||
|
#{item.deviceId},
|
||||||
|
#{item.pointName},
|
||||||
|
#{item.dataKey},
|
||||||
|
#{item.pointDesc},
|
||||||
|
#{item.registerAddress},
|
||||||
|
#{item.dataUnit},
|
||||||
|
#{item.dataA},
|
||||||
|
#{item.dataK},
|
||||||
|
#{item.dataB},
|
||||||
|
#{item.dataBit},
|
||||||
|
#{item.isAlarm},
|
||||||
|
#{item.pointType},
|
||||||
|
#{item.calcExpression},
|
||||||
|
#{item.createBy},
|
||||||
|
now(),
|
||||||
|
#{item.updateBy},
|
||||||
|
now(),
|
||||||
|
#{item.remark}
|
||||||
|
)
|
||||||
|
</foreach>
|
||||||
|
</insert>
|
||||||
|
|
||||||
<update id="updateEmsPointConfig" parameterType="EmsPointConfig">
|
<update id="updateEmsPointConfig" parameterType="EmsPointConfig">
|
||||||
update ems_point_config
|
update ems_point_config
|
||||||
<trim prefix="SET" suffixOverrides=",">
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="pointId != null">point_id = #{pointId},</if>
|
||||||
<if test="siteId != null">site_id = #{siteId},</if>
|
<if test="siteId != null">site_id = #{siteId},</if>
|
||||||
<if test="deviceCategory != null">device_category = #{deviceCategory},</if>
|
<if test="deviceCategory != null">device_category = #{deviceCategory},</if>
|
||||||
<if test="deviceId != null">device_id = #{deviceId},</if>
|
<if test="deviceId != null">device_id = #{deviceId},</if>
|
||||||
@ -151,12 +190,12 @@
|
|||||||
|
|
||||||
<insert id="copyTemplateToSite">
|
<insert id="copyTemplateToSite">
|
||||||
insert into ems_point_config (
|
insert into ems_point_config (
|
||||||
site_id, device_category, device_id, point_name, data_key, point_desc, register_address,
|
point_id, site_id, device_category, device_id, point_name, data_key, point_desc, register_address,
|
||||||
data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression,
|
data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression,
|
||||||
create_by, create_time, update_by, update_time, remark
|
create_by, create_time, update_by, update_time, remark
|
||||||
)
|
)
|
||||||
select
|
select
|
||||||
#{targetSiteId}, device_category, device_id, point_name, data_key, point_desc, register_address,
|
concat('PT_', replace(uuid(), '-', '')), #{targetSiteId}, device_category, device_id, point_name, data_key, point_desc, register_address,
|
||||||
data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression,
|
data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression,
|
||||||
#{operName}, now(), #{operName}, now(), remark
|
#{operName}, now(), #{operName}, now(), remark
|
||||||
from ems_point_config
|
from ems_point_config
|
||||||
@ -228,4 +267,13 @@
|
|||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectBySiteIdAndPointIds" resultMap="EmsPointConfigResult">
|
||||||
|
<include refid="selectEmsPointConfigVo"/>
|
||||||
|
where site_id = #{siteId}
|
||||||
|
and point_id in
|
||||||
|
<foreach collection="pointIds" item="pointId" open="(" separator="," close=")">
|
||||||
|
#{pointId}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@ -9,6 +9,8 @@
|
|||||||
<result property="siteId" column="site_id"/>
|
<result property="siteId" column="site_id"/>
|
||||||
<result property="fieldCode" column="field_code"/>
|
<result property="fieldCode" column="field_code"/>
|
||||||
<result property="dataPoint" column="data_point"/>
|
<result property="dataPoint" column="data_point"/>
|
||||||
|
<result property="fixedDataPoint" column="fixed_data_point"/>
|
||||||
|
<result property="useFixedDisplay" column="use_fixed_display"/>
|
||||||
<result property="createBy" column="create_by"/>
|
<result property="createBy" column="create_by"/>
|
||||||
<result property="createTime" column="create_time"/>
|
<result property="createTime" column="create_time"/>
|
||||||
<result property="updateBy" column="update_by"/>
|
<result property="updateBy" column="update_by"/>
|
||||||
@ -17,7 +19,7 @@
|
|||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<select id="selectBySiteId" resultMap="EmsSiteMonitorPointMatchResult">
|
<select id="selectBySiteId" resultMap="EmsSiteMonitorPointMatchResult">
|
||||||
select id, site_id, field_code, data_point, create_by, create_time, update_by, update_time, remark
|
select id, site_id, field_code, data_point, fixed_data_point, use_fixed_display, create_by, create_time, update_by, update_time, remark
|
||||||
from ems_site_monitor_point_match
|
from ems_site_monitor_point_match
|
||||||
where site_id = #{siteId}
|
where site_id = #{siteId}
|
||||||
order by id asc
|
order by id asc
|
||||||
@ -30,10 +32,10 @@
|
|||||||
|
|
||||||
<insert id="insertBatch">
|
<insert id="insertBatch">
|
||||||
insert into ems_site_monitor_point_match
|
insert into ems_site_monitor_point_match
|
||||||
(site_id, field_code, data_point, create_by, create_time, update_by, update_time)
|
(site_id, field_code, data_point, fixed_data_point, use_fixed_display, create_by, create_time, update_by, update_time)
|
||||||
values
|
values
|
||||||
<foreach collection="list" item="item" separator=",">
|
<foreach collection="list" item="item" separator=",">
|
||||||
(#{item.siteId}, #{item.fieldCode}, #{item.dataPoint}, #{item.createBy}, now(), #{item.updateBy}, now())
|
(#{item.siteId}, #{item.fieldCode}, #{item.dataPoint}, #{item.fixedDataPoint}, #{item.useFixedDisplay}, #{item.createBy}, now(), #{item.updateBy}, now())
|
||||||
</foreach>
|
</foreach>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,98 @@
|
|||||||
|
<?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.xzzn.ems.mapper.EmsStrategyRuntimeConfigMapper">
|
||||||
|
|
||||||
|
<resultMap type="EmsStrategyRuntimeConfig" id="EmsStrategyRuntimeConfigResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="siteId" column="site_id"/>
|
||||||
|
<result property="socDown" column="soc_down"/>
|
||||||
|
<result property="socUp" column="soc_up"/>
|
||||||
|
<result property="antiReverseThreshold" column="anti_reverse_threshold"/>
|
||||||
|
<result property="antiReverseRangePercent" column="anti_reverse_range_percent"/>
|
||||||
|
<result property="antiReverseUp" column="anti_reverse_up"/>
|
||||||
|
<result property="antiReversePowerDownPercent" column="anti_reverse_power_down_percent"/>
|
||||||
|
<result property="antiReverseHardStopThreshold" column="anti_reverse_hard_stop_threshold"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
<result property="remark" column="remark"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectVo">
|
||||||
|
select id,
|
||||||
|
site_id,
|
||||||
|
soc_down,
|
||||||
|
soc_up,
|
||||||
|
anti_reverse_threshold,
|
||||||
|
anti_reverse_range_percent,
|
||||||
|
anti_reverse_up,
|
||||||
|
anti_reverse_power_down_percent,
|
||||||
|
anti_reverse_hard_stop_threshold,
|
||||||
|
create_by,
|
||||||
|
create_time,
|
||||||
|
update_by,
|
||||||
|
update_time,
|
||||||
|
remark
|
||||||
|
from ems_strategy_runtime_config
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectBySiteId" parameterType="String" resultMap="EmsStrategyRuntimeConfigResult">
|
||||||
|
<include refid="selectVo"/>
|
||||||
|
where site_id = #{siteId}
|
||||||
|
limit 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insert" parameterType="EmsStrategyRuntimeConfig" useGeneratedKeys="true" keyProperty="id">
|
||||||
|
insert into ems_strategy_runtime_config
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="siteId != null and siteId != ''">site_id,</if>
|
||||||
|
<if test="socDown != null">soc_down,</if>
|
||||||
|
<if test="socUp != null">soc_up,</if>
|
||||||
|
<if test="antiReverseThreshold != null">anti_reverse_threshold,</if>
|
||||||
|
<if test="antiReverseRangePercent != null">anti_reverse_range_percent,</if>
|
||||||
|
<if test="antiReverseUp != null">anti_reverse_up,</if>
|
||||||
|
<if test="antiReversePowerDownPercent != null">anti_reverse_power_down_percent,</if>
|
||||||
|
<if test="antiReverseHardStopThreshold != null">anti_reverse_hard_stop_threshold,</if>
|
||||||
|
<if test="createBy != null">create_by,</if>
|
||||||
|
<if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateBy != null">update_by,</if>
|
||||||
|
<if test="updateTime != null">update_time,</if>
|
||||||
|
<if test="remark != null">remark,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="siteId != null and siteId != ''">#{siteId},</if>
|
||||||
|
<if test="socDown != null">#{socDown},</if>
|
||||||
|
<if test="socUp != null">#{socUp},</if>
|
||||||
|
<if test="antiReverseThreshold != null">#{antiReverseThreshold},</if>
|
||||||
|
<if test="antiReverseRangePercent != null">#{antiReverseRangePercent},</if>
|
||||||
|
<if test="antiReverseUp != null">#{antiReverseUp},</if>
|
||||||
|
<if test="antiReversePowerDownPercent != null">#{antiReversePowerDownPercent},</if>
|
||||||
|
<if test="antiReverseHardStopThreshold != null">#{antiReverseHardStopThreshold},</if>
|
||||||
|
<if test="createBy != null">#{createBy},</if>
|
||||||
|
<if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateBy != null">#{updateBy},</if>
|
||||||
|
<if test="updateTime != null">#{updateTime},</if>
|
||||||
|
<if test="remark != null">#{remark},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateBySiteId" parameterType="EmsStrategyRuntimeConfig">
|
||||||
|
update ems_strategy_runtime_config
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="socDown != null">soc_down = #{socDown},</if>
|
||||||
|
<if test="socUp != null">soc_up = #{socUp},</if>
|
||||||
|
<if test="antiReverseThreshold != null">anti_reverse_threshold = #{antiReverseThreshold},</if>
|
||||||
|
<if test="antiReverseRangePercent != null">anti_reverse_range_percent = #{antiReverseRangePercent},</if>
|
||||||
|
<if test="antiReverseUp != null">anti_reverse_up = #{antiReverseUp},</if>
|
||||||
|
<if test="antiReversePowerDownPercent != null">anti_reverse_power_down_percent = #{antiReversePowerDownPercent},</if>
|
||||||
|
<if test="antiReverseHardStopThreshold != null">anti_reverse_hard_stop_threshold = #{antiReverseHardStopThreshold},</if>
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||||
|
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
</trim>
|
||||||
|
where site_id = #{siteId}
|
||||||
|
</update>
|
||||||
|
</mapper>
|
||||||
Reference in New Issue
Block a user