Compare commits
3 Commits
6545b4f947
...
21673ecd1e
| Author | SHA1 | Date | |
|---|---|---|---|
| 21673ecd1e | |||
| 66de6fe77c | |||
| 63ed2641ee |
@ -0,0 +1,96 @@
|
|||||||
|
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.EmsPointConfig;
|
||||||
|
import com.xzzn.ems.domain.vo.ImportPointTemplateRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.PointConfigCurveRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.PointConfigLatestValueRequest;
|
||||||
|
import com.xzzn.ems.service.IEmsPointConfigService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ems/pointConfig")
|
||||||
|
public class EmsPointConfigController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IEmsPointConfigService pointConfigService;
|
||||||
|
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo list(EmsPointConfig pointConfig) {
|
||||||
|
startPage();
|
||||||
|
List<EmsPointConfig> list = pointConfigService.selectPointConfigList(pointConfig);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||||
|
return success(pointConfigService.selectPointConfigById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "点位配置", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody EmsPointConfig pointConfig) {
|
||||||
|
return toAjax(pointConfigService.insertPointConfig(pointConfig, getUsername()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "点位配置", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody EmsPointConfig pointConfig) {
|
||||||
|
return toAjax(pointConfigService.updatePointConfig(pointConfig, getUsername()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "点位配置", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||||
|
return toAjax(pointConfigService.deletePointConfigByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "点位配置", businessType = BusinessType.IMPORT)
|
||||||
|
@PostMapping("/importTemplateBySite")
|
||||||
|
public AjaxResult importTemplateBySite(@Valid @RequestBody ImportPointTemplateRequest request) {
|
||||||
|
return success(pointConfigService.importTemplateBySite(request, getUsername()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "点位配置", businessType = BusinessType.IMPORT)
|
||||||
|
@PostMapping("/importCsv")
|
||||||
|
public AjaxResult importCsv(@RequestParam String siteId,
|
||||||
|
@RequestParam(required = false) Boolean overwrite,
|
||||||
|
@RequestParam("file") MultipartFile file) {
|
||||||
|
return success(pointConfigService.importCsvBySite(siteId, overwrite, file, getUsername()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/registerAddress")
|
||||||
|
public AjaxResult getRegisterAddress(@RequestParam String siteId,
|
||||||
|
@RequestParam String deviceCategory,
|
||||||
|
@RequestParam String deviceId,
|
||||||
|
@RequestParam String dataKey) {
|
||||||
|
return success(pointConfigService.getRegisterAddress(siteId, deviceCategory, deviceId, dataKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/latestValues")
|
||||||
|
public AjaxResult latestValues(@RequestBody PointConfigLatestValueRequest request) {
|
||||||
|
return success(pointConfigService.getLatestValues(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/curve")
|
||||||
|
public AjaxResult curve(@RequestBody PointConfigCurveRequest request) {
|
||||||
|
return success(pointConfigService.getCurveData(request));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,8 +7,12 @@ import javax.validation.Valid;
|
|||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import com.xzzn.common.annotation.Log;
|
import com.xzzn.common.annotation.Log;
|
||||||
@ -19,6 +23,7 @@ import com.xzzn.ems.domain.EmsPointMatch;
|
|||||||
import com.xzzn.ems.domain.vo.DevicePointMatchExportVo;
|
import com.xzzn.ems.domain.vo.DevicePointMatchExportVo;
|
||||||
import com.xzzn.ems.domain.vo.DevicePointMatchVo;
|
import com.xzzn.ems.domain.vo.DevicePointMatchVo;
|
||||||
import com.xzzn.ems.domain.vo.ImportPointDataRequest;
|
import com.xzzn.ems.domain.vo.ImportPointDataRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.ImportPointTemplateRequest;
|
||||||
import com.xzzn.ems.service.IEmsPointMatchService;
|
import com.xzzn.ems.service.IEmsPointMatchService;
|
||||||
import com.xzzn.common.utils.poi.ExcelUtil;
|
import com.xzzn.common.utils.poi.ExcelUtil;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -49,6 +54,58 @@ public class EmsPointMatchController extends BaseController
|
|||||||
util.exportExcel(response, list, "点位匹配数据");
|
util.exportExcel(response, list, "点位匹配数据");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询点位配置列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/list")
|
||||||
|
public com.xzzn.common.core.page.TableDataInfo list(EmsPointMatch emsPointMatch)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<EmsPointMatch> list = emsPointMatchService.selectPointMatchConfigList(emsPointMatch);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询点位配置详情
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||||
|
{
|
||||||
|
return success(emsPointMatchService.selectPointMatchById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增点位配置
|
||||||
|
*/
|
||||||
|
@Log(title = "点位配置", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public AjaxResult add(@RequestBody EmsPointMatch emsPointMatch)
|
||||||
|
{
|
||||||
|
emsPointMatch.setCreateBy(getUsername());
|
||||||
|
return toAjax(emsPointMatchService.insertPointMatch(emsPointMatch));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改点位配置
|
||||||
|
*/
|
||||||
|
@Log(title = "点位配置", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public AjaxResult edit(@RequestBody EmsPointMatch emsPointMatch)
|
||||||
|
{
|
||||||
|
emsPointMatch.setUpdateBy(getUsername());
|
||||||
|
return toAjax(emsPointMatchService.updatePointMatch(emsPointMatch));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除点位配置
|
||||||
|
*/
|
||||||
|
@Log(title = "点位配置", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public AjaxResult remove(@PathVariable Long[] ids)
|
||||||
|
{
|
||||||
|
return toAjax(emsPointMatchService.deletePointMatchByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传点位清单
|
* 上传点位清单
|
||||||
* @param file
|
* @param file
|
||||||
@ -85,4 +142,18 @@ public class EmsPointMatchController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据站点导入模板点位配置
|
||||||
|
* @param request 请求参数
|
||||||
|
* @return 导入结果
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:user:import')")
|
||||||
|
@Log(title = "点位配置", businessType = BusinessType.IMPORT)
|
||||||
|
@PostMapping("/importTemplateBySite")
|
||||||
|
public AjaxResult importTemplateBySite(@Valid @RequestBody ImportPointTemplateRequest request)
|
||||||
|
{
|
||||||
|
String message = emsPointMatchService.importTemplateBySite(request, getUsername());
|
||||||
|
return success(message);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import com.xzzn.ems.domain.vo.DeviceUpdateRequest;
|
|||||||
import com.xzzn.ems.domain.vo.DevicesSettingVo;
|
import com.xzzn.ems.domain.vo.DevicesSettingVo;
|
||||||
import com.xzzn.ems.domain.vo.PointDataRequest;
|
import com.xzzn.ems.domain.vo.PointDataRequest;
|
||||||
import com.xzzn.ems.domain.vo.PointQueryResponse;
|
import com.xzzn.ems.domain.vo.PointQueryResponse;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteMonitorProjectPointMappingSaveRequest;
|
||||||
import com.xzzn.ems.domain.vo.SiteDeviceListVo;
|
import com.xzzn.ems.domain.vo.SiteDeviceListVo;
|
||||||
import com.xzzn.ems.service.IEmsDeviceSettingService;
|
import com.xzzn.ems.service.IEmsDeviceSettingService;
|
||||||
import com.xzzn.ems.service.IEmsSiteService;
|
import com.xzzn.ems.service.IEmsSiteService;
|
||||||
@ -59,6 +60,26 @@ public class EmsSiteConfigController extends BaseController{
|
|||||||
return getDataTable(list);
|
return getDataTable(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增站点
|
||||||
|
*/
|
||||||
|
@PostMapping("/addSite")
|
||||||
|
public AjaxResult addSite(@RequestBody EmsSiteSetting emsSiteSetting)
|
||||||
|
{
|
||||||
|
emsSiteSetting.setCreateBy(getUsername());
|
||||||
|
return toAjax(iEmsSiteService.addSite(emsSiteSetting));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑站点
|
||||||
|
*/
|
||||||
|
@PostMapping("/updateSite")
|
||||||
|
public AjaxResult updateSite(@RequestBody EmsSiteSetting emsSiteSetting)
|
||||||
|
{
|
||||||
|
emsSiteSetting.setUpdateBy(getUsername());
|
||||||
|
return toAjax(iEmsSiteService.updateSite(emsSiteSetting));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取设备列表-分页
|
* 获取设备列表-分页
|
||||||
*/
|
*/
|
||||||
@ -192,6 +213,25 @@ public class EmsSiteConfigController extends BaseController{
|
|||||||
return success(iEmsDeviceSettingService.getDeviceListBySiteAndCategory(siteId, deviceCategory));
|
return success(iEmsDeviceSettingService.getDeviceListBySiteAndCategory(siteId, deviceCategory));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单站监控项目点位映射
|
||||||
|
*/
|
||||||
|
@GetMapping("/getSingleMonitorProjectPointMapping")
|
||||||
|
public AjaxResult getSingleMonitorProjectPointMapping(@RequestParam String siteId)
|
||||||
|
{
|
||||||
|
return success(iEmsDeviceSettingService.getSiteMonitorProjectPointMapping(siteId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存单站监控项目点位映射
|
||||||
|
*/
|
||||||
|
@PostMapping("/saveSingleMonitorProjectPointMapping")
|
||||||
|
public AjaxResult saveSingleMonitorProjectPointMapping(@RequestBody SiteMonitorProjectPointMappingSaveRequest request)
|
||||||
|
{
|
||||||
|
int rows = iEmsDeviceSettingService.saveSiteMonitorProjectPointMapping(request, getUsername());
|
||||||
|
return AjaxResult.success(rows);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PCS设备开关机
|
* PCS设备开关机
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import com.xzzn.ems.domain.vo.BatteryDataStatsListVo;
|
|||||||
import com.xzzn.ems.domain.vo.DateSearchRequest;
|
import com.xzzn.ems.domain.vo.DateSearchRequest;
|
||||||
import com.xzzn.ems.domain.vo.RunningGraphRequest;
|
import com.xzzn.ems.domain.vo.RunningGraphRequest;
|
||||||
import com.xzzn.ems.domain.vo.SiteBatteryDataList;
|
import com.xzzn.ems.domain.vo.SiteBatteryDataList;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteMonitorDataSaveRequest;
|
||||||
|
import com.xzzn.ems.service.IEmsDeviceSettingService;
|
||||||
import com.xzzn.ems.service.IEmsSiteService;
|
import com.xzzn.ems.service.IEmsSiteService;
|
||||||
import com.xzzn.ems.service.IEmsStatsReportService;
|
import com.xzzn.ems.service.IEmsStatsReportService;
|
||||||
import com.xzzn.ems.service.ISingleSiteService;
|
import com.xzzn.ems.service.ISingleSiteService;
|
||||||
@ -33,6 +35,8 @@ public class EmsSiteMonitorController extends BaseController{
|
|||||||
private IEmsSiteService iEmsSiteService;
|
private IEmsSiteService iEmsSiteService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IEmsStatsReportService iemsStatsReportService;
|
private IEmsStatsReportService iemsStatsReportService;
|
||||||
|
@Autowired
|
||||||
|
private IEmsDeviceSettingService iEmsDeviceSettingService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取单站首页数据
|
* 获取单站首页数据
|
||||||
@ -228,4 +232,31 @@ public class EmsSiteMonitorController extends BaseController{
|
|||||||
return error("缺少必传项");
|
return error("缺少必传项");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控项目点位配置查询
|
||||||
|
*/
|
||||||
|
@GetMapping("/getProjectPointMapping")
|
||||||
|
public AjaxResult getProjectPointMapping(@RequestParam String siteId)
|
||||||
|
{
|
||||||
|
return success(iEmsDeviceSettingService.getSiteMonitorProjectPointMapping(siteId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控项目展示数据查询(配置字段 + 字段值)
|
||||||
|
*/
|
||||||
|
@GetMapping("/getProjectDisplayData")
|
||||||
|
public AjaxResult getProjectDisplayData(@RequestParam String siteId)
|
||||||
|
{
|
||||||
|
return success(iEmsDeviceSettingService.getSiteMonitorProjectDisplay(siteId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控项目展示数据写入
|
||||||
|
*/
|
||||||
|
@PostMapping("/saveProjectDisplayData")
|
||||||
|
public AjaxResult saveProjectDisplayData(@RequestBody SiteMonitorDataSaveRequest request)
|
||||||
|
{
|
||||||
|
return AjaxResult.success(iEmsDeviceSettingService.saveSiteMonitorProjectData(request, getUsername()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import com.xzzn.ems.domain.EmsMqttTopicConfig;
|
|||||||
import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper;
|
import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper;
|
||||||
import com.xzzn.ems.service.IDDSDataProcessService;
|
import com.xzzn.ems.service.IDDSDataProcessService;
|
||||||
import com.xzzn.ems.service.IDeviceDataProcessService;
|
import com.xzzn.ems.service.IDeviceDataProcessService;
|
||||||
import com.xzzn.ems.service.IEmsMqttMessageService;
|
|
||||||
import com.xzzn.ems.service.IEmsStrategyService;
|
import com.xzzn.ems.service.IEmsStrategyService;
|
||||||
import com.xzzn.ems.service.IFXXAlarmDataProcessService;
|
import com.xzzn.ems.service.IFXXAlarmDataProcessService;
|
||||||
import com.xzzn.ems.service.IFXXDataProcessService;
|
import com.xzzn.ems.service.IFXXDataProcessService;
|
||||||
@ -27,6 +26,7 @@ import org.eclipse.paho.client.mqttv3.MqttException;
|
|||||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@ -38,9 +38,6 @@ public class MqttMessageController implements MqttPublisher, MqttSubscriber {
|
|||||||
|
|
||||||
private final MqttLifecycleManager mqttLifecycleManager;
|
private final MqttLifecycleManager mqttLifecycleManager;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IEmsMqttMessageService emsMqttMessageService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IFXXDataProcessService fXXDataProcessService;
|
private IFXXDataProcessService fXXDataProcessService;
|
||||||
|
|
||||||
@ -61,6 +58,8 @@ public class MqttMessageController implements MqttPublisher, MqttSubscriber {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisCache redisCache;
|
private RedisCache redisCache;
|
||||||
|
@Autowired
|
||||||
|
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public MqttMessageController(MqttLifecycleManager mqttLifecycleManager) {
|
public MqttMessageController(MqttLifecycleManager mqttLifecycleManager) {
|
||||||
@ -136,51 +135,32 @@ public class MqttMessageController implements MqttPublisher, MqttSubscriber {
|
|||||||
private void handleSystemStatus(String topic, MqttMessage message) {
|
private void handleSystemStatus(String topic, MqttMessage message) {
|
||||||
String payload = new String(message.getPayload());
|
String payload = new String(message.getPayload());
|
||||||
System.out.println("[SYSTEM] Status update: " + payload);
|
System.out.println("[SYSTEM] Status update: " + payload);
|
||||||
|
|
||||||
try {
|
|
||||||
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Failed to process system status message: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理设备数据
|
// 处理设备数据
|
||||||
private void handleDeviceData(String topic, MqttMessage message) {
|
private void handleDeviceData(String topic, MqttMessage message) {
|
||||||
String payload = new String(message.getPayload());
|
String payload = new String(message.getPayload());
|
||||||
log.error("[DEVICE] data: " + payload);
|
threadPoolTaskExecutor.execute(() -> {
|
||||||
|
log.debug("[DEVICE] data: {}", payload);
|
||||||
try {
|
try {
|
||||||
// 业务处理逻辑
|
|
||||||
// if (topic.startsWith("021_DDS")) {
|
|
||||||
// dDSDataProcessService.handleDdsData(payload);
|
|
||||||
// } else if (topic.startsWith("021_FXX")) {
|
|
||||||
// fXXDataProcessService.handleFxData(payload);
|
|
||||||
// }
|
|
||||||
deviceDataProcessService.handleDeviceData(payload, getSiteIdByTopic(topic));
|
deviceDataProcessService.handleDeviceData(payload, getSiteIdByTopic(topic));
|
||||||
|
|
||||||
emsMqttMessageService.insertMqttOriginalMessage(topic, payload);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to process device data message: " + e.getMessage(), e);
|
log.error("Failed to process device data message: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理告警数据
|
// 处理告警数据
|
||||||
private void handleAlarmData(String topic, MqttMessage message) {
|
private void handleAlarmData(String topic, MqttMessage message) {
|
||||||
String payload = new String(message.getPayload());
|
String payload = new String(message.getPayload());
|
||||||
System.out.println("[DEVICE] data: " + payload);
|
threadPoolTaskExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
// 业务处理逻辑
|
|
||||||
// if (topic.startsWith("021_FXX")) {
|
|
||||||
// fXXAlarmDataProcessService.handleFxAlarmData(payload);
|
|
||||||
// }
|
|
||||||
deviceDataProcessService.handleAlarmData(payload, getSiteIdByTopic(topic));
|
deviceDataProcessService.handleAlarmData(payload, getSiteIdByTopic(topic));
|
||||||
|
|
||||||
emsMqttMessageService.insertMqttOriginalMessage(topic, payload);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("Failed to process device alarm data message: {}", e.getMessage(), e);
|
||||||
log.error("Failed to process device alarm data message: " + e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,78 +171,67 @@ public class MqttMessageController implements MqttPublisher, MqttSubscriber {
|
|||||||
siteId = topicConfig.getSiteId();
|
siteId = topicConfig.getSiteId();
|
||||||
redisCache.setCacheObject(RedisKeyConstants.SITE_ID + topic, siteId);
|
redisCache.setCacheObject(RedisKeyConstants.SITE_ID + topic, siteId);
|
||||||
}
|
}
|
||||||
log.info("当前处理数据站点:" + siteId + ",topic: " + topic);
|
|
||||||
return siteId;
|
return siteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理运行策略数据:云端-本地
|
// 处理运行策略数据:云端-本地
|
||||||
private void handleStrategyData(String topic, MqttMessage message) {
|
private void handleStrategyData(String topic, MqttMessage message) {
|
||||||
String payload = new String(message.getPayload());
|
String payload = new String(message.getPayload());
|
||||||
System.out.println("[处理运行策略数据] data: " + payload);
|
threadPoolTaskExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
// 业务处理逻辑
|
|
||||||
iMqttSyncLogService.handleMqttStrategyData(payload);
|
iMqttSyncLogService.handleMqttStrategyData(payload);
|
||||||
|
|
||||||
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to process strategy data message: " + e.getMessage(), e);
|
log.error("Failed to process strategy data message: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理设备保护告警策略数据:云端-本地
|
// 处理设备保护告警策略数据:云端-本地
|
||||||
private void handleFaultProtPlanData(String topic, MqttMessage message) {
|
private void handleFaultProtPlanData(String topic, MqttMessage message) {
|
||||||
String payload = new String(message.getPayload());
|
String payload = new String(message.getPayload());
|
||||||
System.out.println("[处理设备保护告警策略数据] data: " + payload);
|
threadPoolTaskExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
// 业务处理逻辑
|
|
||||||
iMqttSyncLogService.handleMqttPlanData(payload);
|
iMqttSyncLogService.handleMqttPlanData(payload);
|
||||||
|
|
||||||
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to process fault plan data message: " + e.getMessage(), e);
|
log.error("Failed to process fault plan data message: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理保护策略告警信息:本地-云端
|
// 处理保护策略告警信息:本地-云端
|
||||||
private void handleFaultAlarmData(String topic, MqttMessage message) {
|
private void handleFaultAlarmData(String topic, MqttMessage message) {
|
||||||
String payload = new String(message.getPayload());
|
String payload = new String(message.getPayload());
|
||||||
System.out.println("[处理本地保护策略告警信息到云端] data: " + payload);
|
threadPoolTaskExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
// 业务处理逻辑
|
|
||||||
iMqttSyncLogService.handleFaultAlarmData(payload);
|
iMqttSyncLogService.handleFaultAlarmData(payload);
|
||||||
|
|
||||||
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to process fault plan alarm data message: " + e.getMessage(), e);
|
log.error("Failed to process fault plan alarm data message: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理保护策略下发日志:本地-云端
|
// 处理保护策略下发日志:本地-云端
|
||||||
private void handleFaultPlanIssueData(String topic, MqttMessage message) {
|
private void handleFaultPlanIssueData(String topic, MqttMessage message) {
|
||||||
String payload = new String(message.getPayload());
|
String payload = new String(message.getPayload());
|
||||||
System.out.println("[处理本地保护策略下发日志到云端] data: " + payload);
|
threadPoolTaskExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
// 业务处理逻辑
|
|
||||||
iMqttSyncLogService.handleFaultPlanIssueData(payload);
|
iMqttSyncLogService.handleFaultPlanIssueData(payload);
|
||||||
|
|
||||||
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to process fault plan issue log message: " + e.getMessage(), e);
|
log.error("Failed to process fault plan issue log message: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理设备状态变更日志:本地-云端
|
// 处理设备状态变更日志:本地-云端
|
||||||
private void handleDeviceChangeLogData(String topic, MqttMessage message) {
|
private void handleDeviceChangeLogData(String topic, MqttMessage message) {
|
||||||
String payload = new String(message.getPayload());
|
String payload = new String(message.getPayload());
|
||||||
System.out.println("[处理本地的保护策略告警信息到云端] data: " + payload);
|
threadPoolTaskExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
// 业务处理逻辑
|
|
||||||
iMqttSyncLogService.handleDeviceChangeLogData(payload);
|
iMqttSyncLogService.handleDeviceChangeLogData(payload);
|
||||||
|
|
||||||
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to process device change log message: " + e.getMessage(), e);
|
log.error("Failed to process device change log message: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -199,6 +199,20 @@ mqtt:
|
|||||||
topic:
|
topic:
|
||||||
siteId:
|
siteId:
|
||||||
|
|
||||||
|
influxdb:
|
||||||
|
enabled: true
|
||||||
|
url: http://122.51.194.184:8086/
|
||||||
|
api-token: F2XcmBzZsWcz90ikU2_t7UXY2fzWuf2ruVp1BkusNkIS_gwrQZuiaIjl33XQMQajm7vSI6TQSRnpPSx5CXThlA==
|
||||||
|
write-method: POST
|
||||||
|
read-method: GET
|
||||||
|
write-path: /api/v2/write
|
||||||
|
query-path: /query
|
||||||
|
org: ems
|
||||||
|
bucket: point_data
|
||||||
|
database: ems_point_data
|
||||||
|
retention-policy: autogen
|
||||||
|
measurement: mqtt_point_data
|
||||||
|
|
||||||
modbus:
|
modbus:
|
||||||
pool:
|
pool:
|
||||||
max-total: 20
|
max-total: 20
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<!-- 日志存放路径 -->
|
<!-- 日志存放路径 -->
|
||||||
<property name="log.path" value="/etc/xzzn/logs" />
|
<property name="log.path" value="logs" />
|
||||||
<!-- 日志输出格式 -->
|
<!-- 日志输出格式 -->
|
||||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
||||||
|
|
||||||
|
|||||||
@ -122,4 +122,10 @@ public class RedisKeyConstants
|
|||||||
|
|
||||||
/** 每个设备最新数据-设置失效时间-判断是否正常同步数据 */
|
/** 每个设备最新数据-设置失效时间-判断是否正常同步数据 */
|
||||||
public static final String SYNC_DATA_ALARM = "SYNC_DATA_ALARM_";
|
public static final String SYNC_DATA_ALARM = "SYNC_DATA_ALARM_";
|
||||||
|
|
||||||
|
/** 点位配置缓存(按站点+设备) */
|
||||||
|
public static final String POINT_CONFIG_DEVICE = "POINT_CONFIG_DEVICE_";
|
||||||
|
|
||||||
|
/** 单站监控最新数据(按站点+模块) */
|
||||||
|
public static final String SITE_MONITOR_LATEST = "SITE_MONITOR_LATEST_";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,21 +3,37 @@ package com.xzzn.framework.manager;
|
|||||||
import com.xzzn.ems.service.IEmsAlarmRecordsService;
|
import com.xzzn.ems.service.IEmsAlarmRecordsService;
|
||||||
import org.eclipse.paho.client.mqttv3.*;
|
import org.eclipse.paho.client.mqttv3.*;
|
||||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||||
|
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.boot.ApplicationArguments;
|
import org.springframework.boot.ApplicationArguments;
|
||||||
import org.springframework.boot.ApplicationRunner;
|
import org.springframework.boot.ApplicationRunner;
|
||||||
import org.springframework.context.SmartLifecycle;
|
import org.springframework.context.SmartLifecycle;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle, MqttCallback {
|
public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle, MqttCallbackExtended {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(MqttLifecycleManager.class);
|
||||||
|
private static final long RECONNECT_DELAY_SECONDS = 5;
|
||||||
|
|
||||||
private final MqttConnectOptions connectOptions;
|
private final MqttConnectOptions connectOptions;
|
||||||
private final IEmsAlarmRecordsService iEmsAlarmRecordsService;
|
private final IEmsAlarmRecordsService iEmsAlarmRecordsService;
|
||||||
|
private final ScheduledExecutorService reconnectExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
|
||||||
|
Thread thread = new Thread(r);
|
||||||
|
thread.setName("mqtt-reconnect");
|
||||||
|
thread.setDaemon(true);
|
||||||
|
return thread;
|
||||||
|
});
|
||||||
|
private final AtomicBoolean reconnectScheduled = new AtomicBoolean(false);
|
||||||
|
private volatile ScheduledFuture<?> reconnectFuture;
|
||||||
private MqttClient mqttClient;
|
private MqttClient mqttClient;
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
|
|
||||||
@ -41,7 +57,9 @@ public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle,
|
|||||||
if (running) return;
|
if (running) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String clientId = connectOptions.getUserName() + "-" + System.currentTimeMillis();
|
String prefix = connectOptions.getUserName() == null || connectOptions.getUserName().isEmpty()
|
||||||
|
? "mqtt-client" : connectOptions.getUserName();
|
||||||
|
String clientId = prefix + "-" + System.currentTimeMillis();
|
||||||
mqttClient = new MqttClient(
|
mqttClient = new MqttClient(
|
||||||
connectOptions.getServerURIs()[0],
|
connectOptions.getServerURIs()[0],
|
||||||
clientId,
|
clientId,
|
||||||
@ -51,27 +69,28 @@ public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle,
|
|||||||
mqttClient.setCallback(this);
|
mqttClient.setCallback(this);
|
||||||
mqttClient.connect(connectOptions);
|
mqttClient.connect(connectOptions);
|
||||||
|
|
||||||
// 重连后自动重新订阅
|
|
||||||
resubscribeAll();
|
resubscribeAll();
|
||||||
|
|
||||||
running = true;
|
running = true;
|
||||||
System.out.println("MQTT client connected to: " + connectOptions.getServerURIs()[0]);
|
log.info("MQTT client connected to: {}", connectOptions.getServerURIs()[0]);
|
||||||
} catch (MqttException e) {
|
} catch (MqttException e) {
|
||||||
System.err.println("MQTT connection failed: " + e.getMessage());
|
running = false;
|
||||||
// 添加重试逻辑
|
log.error("MQTT connection failed: {}", e.getMessage(), e);
|
||||||
|
scheduleReconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
cancelReconnectTask();
|
||||||
if (mqttClient != null && mqttClient.isConnected()) {
|
if (mqttClient != null && mqttClient.isConnected()) {
|
||||||
try {
|
try {
|
||||||
mqttClient.disconnect();
|
mqttClient.disconnect();
|
||||||
mqttClient.close();
|
mqttClient.close();
|
||||||
} catch (MqttException e) {
|
} catch (MqttException e) {
|
||||||
System.err.println("Error disconnecting MQTT client: " + e.getMessage());
|
log.warn("Error disconnecting MQTT client: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
reconnectExecutor.shutdownNow();
|
||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,9 +102,17 @@ public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle,
|
|||||||
// MQTT 回调方法
|
// MQTT 回调方法
|
||||||
@Override
|
@Override
|
||||||
public void connectionLost(Throwable cause) {
|
public void connectionLost(Throwable cause) {
|
||||||
System.err.println("MQTT connection lost: " + cause.getMessage());
|
log.warn("MQTT connection lost: {}", cause == null ? "unknown" : cause.getMessage(), cause);
|
||||||
running = false;
|
running = false;
|
||||||
// 自动重连由 MqttConnectOptions 处理
|
scheduleReconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connectComplete(boolean reconnect, String serverURI) {
|
||||||
|
running = true;
|
||||||
|
cancelReconnectTask();
|
||||||
|
log.info("MQTT connection complete, reconnect: {}, serverURI: {}", reconnect, serverURI);
|
||||||
|
resubscribeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -106,14 +133,16 @@ public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle,
|
|||||||
try {
|
try {
|
||||||
if (mqttClient != null && mqttClient.isConnected()) {
|
if (mqttClient != null && mqttClient.isConnected()) {
|
||||||
mqttClient.subscribe(topic, qos);
|
mqttClient.subscribe(topic, qos);
|
||||||
|
log.info("MQTT subscribe success, topic: {}, qos: {}", topic, qos);
|
||||||
|
} else {
|
||||||
|
log.warn("MQTT subscribe deferred, client not connected, topic: {}", topic);
|
||||||
}
|
}
|
||||||
subscriptions.put(topic, new SubscriptionInfo(listener, qos));
|
subscriptions.put(topic, new SubscriptionInfo(listener, qos));
|
||||||
} catch (MqttException e) {
|
} catch (MqttException e) {
|
||||||
System.err.println("Subscribe failed: " + e.getMessage());
|
log.error("Subscribe failed, topic: {}, err: {}", topic, e.getMessage(), e);
|
||||||
// 订阅失败-增加告警
|
|
||||||
iEmsAlarmRecordsService.addSubFailedAlarmRecord(topic);
|
iEmsAlarmRecordsService.addSubFailedAlarmRecord(topic);
|
||||||
|
scheduleReconnect();
|
||||||
}
|
}
|
||||||
// 订阅成功了-校验是否存在未处理或者处理中的订阅失败信息
|
|
||||||
iEmsAlarmRecordsService.checkFailedRecord(topic);
|
iEmsAlarmRecordsService.checkFailedRecord(topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,12 +164,52 @@ public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle,
|
|||||||
subscriptions.forEach((topic, info) -> {
|
subscriptions.forEach((topic, info) -> {
|
||||||
try {
|
try {
|
||||||
mqttClient.subscribe(topic, info.getQos());
|
mqttClient.subscribe(topic, info.getQos());
|
||||||
|
log.info("MQTT resubscribe success, topic: {}, qos: {}", topic, info.getQos());
|
||||||
} catch (MqttException e) {
|
} catch (MqttException e) {
|
||||||
System.err.println("Resubscribe failed for topic: " + topic);
|
log.error("Resubscribe failed for topic: {}, err: {}", topic, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void scheduleReconnect() {
|
||||||
|
if (mqttClient == null || reconnectExecutor.isShutdown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!reconnectScheduled.compareAndSet(false, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reconnectFuture = reconnectExecutor.scheduleWithFixedDelay(() -> {
|
||||||
|
if (mqttClient == null) {
|
||||||
|
cancelReconnectTask();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mqttClient.isConnected()) {
|
||||||
|
cancelReconnectTask();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
log.info("MQTT reconnecting...");
|
||||||
|
mqttClient.connect(connectOptions);
|
||||||
|
running = true;
|
||||||
|
cancelReconnectTask();
|
||||||
|
resubscribeAll();
|
||||||
|
log.info("MQTT reconnect success.");
|
||||||
|
} catch (MqttException e) {
|
||||||
|
running = false;
|
||||||
|
log.warn("MQTT reconnect failed: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}, RECONNECT_DELAY_SECONDS, RECONNECT_DELAY_SECONDS, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelReconnectTask() {
|
||||||
|
reconnectScheduled.set(false);
|
||||||
|
ScheduledFuture<?> future = reconnectFuture;
|
||||||
|
if (future != null && !future.isCancelled()) {
|
||||||
|
future.cancel(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 订阅信息内部类
|
// 订阅信息内部类
|
||||||
private static class SubscriptionInfo {
|
private static class SubscriptionInfo {
|
||||||
private final IMqttMessageListener listener;
|
private final IMqttMessageListener listener;
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package com.xzzn.generator.controller;
|
package com.xzzn.generator.controller;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -18,10 +17,6 @@ import org.springframework.web.bind.annotation.PutMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import com.alibaba.druid.DbType;
|
|
||||||
import com.alibaba.druid.sql.SQLUtils;
|
|
||||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
|
||||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
|
|
||||||
import com.xzzn.common.annotation.Log;
|
import com.xzzn.common.annotation.Log;
|
||||||
import com.xzzn.common.core.controller.BaseController;
|
import com.xzzn.common.core.controller.BaseController;
|
||||||
import com.xzzn.common.core.domain.AjaxResult;
|
import com.xzzn.common.core.domain.AjaxResult;
|
||||||
@ -29,7 +24,6 @@ import com.xzzn.common.core.page.TableDataInfo;
|
|||||||
import com.xzzn.common.core.text.Convert;
|
import com.xzzn.common.core.text.Convert;
|
||||||
import com.xzzn.common.enums.BusinessType;
|
import com.xzzn.common.enums.BusinessType;
|
||||||
import com.xzzn.common.utils.SecurityUtils;
|
import com.xzzn.common.utils.SecurityUtils;
|
||||||
import com.xzzn.common.utils.sql.SqlUtil;
|
|
||||||
import com.xzzn.generator.config.GenConfig;
|
import com.xzzn.generator.config.GenConfig;
|
||||||
import com.xzzn.generator.domain.GenTable;
|
import com.xzzn.generator.domain.GenTable;
|
||||||
import com.xzzn.generator.domain.GenTableColumn;
|
import com.xzzn.generator.domain.GenTableColumn;
|
||||||
@ -121,43 +115,6 @@ public class GenController extends BaseController
|
|||||||
return success();
|
return success();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建表结构(保存)
|
|
||||||
*/
|
|
||||||
@PreAuthorize("@ss.hasRole('admin')")
|
|
||||||
@Log(title = "创建表", businessType = BusinessType.OTHER)
|
|
||||||
@PostMapping("/createTable")
|
|
||||||
public AjaxResult createTableSave(String sql)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SqlUtil.filterKeyword(sql);
|
|
||||||
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);
|
|
||||||
List<String> tableNames = new ArrayList<>();
|
|
||||||
for (SQLStatement sqlStatement : sqlStatements)
|
|
||||||
{
|
|
||||||
if (sqlStatement instanceof MySqlCreateTableStatement)
|
|
||||||
{
|
|
||||||
MySqlCreateTableStatement createTableStatement = (MySqlCreateTableStatement) sqlStatement;
|
|
||||||
if (genTableService.createTable(createTableStatement.toString()))
|
|
||||||
{
|
|
||||||
String tableName = createTableStatement.getTableName().replaceAll("`", "");
|
|
||||||
tableNames.add(tableName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames.toArray(new String[tableNames.size()]));
|
|
||||||
String operName = SecurityUtils.getUsername();
|
|
||||||
genTableService.importGenTable(tableList, operName);
|
|
||||||
return AjaxResult.success();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
return AjaxResult.error("创建表结构异常");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改保存代码生成业务
|
* 修改保存代码生成业务
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -81,11 +81,4 @@ public interface GenTableMapper
|
|||||||
*/
|
*/
|
||||||
public int deleteGenTableByIds(Long[] ids);
|
public int deleteGenTableByIds(Long[] ids);
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建表
|
|
||||||
*
|
|
||||||
* @param sql 表结构
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public int createTable(String sql);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -149,18 +149,6 @@ public class GenTableServiceImpl implements IGenTableService
|
|||||||
genTableColumnMapper.deleteGenTableColumnByIds(tableIds);
|
genTableColumnMapper.deleteGenTableColumnByIds(tableIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建表
|
|
||||||
*
|
|
||||||
* @param sql 创建表语句
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean createTable(String sql)
|
|
||||||
{
|
|
||||||
return genTableMapper.createTable(sql) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入表结构
|
* 导入表结构
|
||||||
*
|
*
|
||||||
|
|||||||
@ -66,14 +66,6 @@ public interface IGenTableService
|
|||||||
*/
|
*/
|
||||||
public void deleteGenTableByIds(Long[] tableIds);
|
public void deleteGenTableByIds(Long[] tableIds);
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建表
|
|
||||||
*
|
|
||||||
* @param sql 创建表语句
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public boolean createTable(String sql);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入表结构
|
* 导入表结构
|
||||||
*
|
*
|
||||||
|
|||||||
@ -171,10 +171,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
)
|
)
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
<update id="createTable">
|
|
||||||
${sql}
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<update id="updateGenTable" parameterType="GenTable">
|
<update id="updateGenTable" parameterType="GenTable">
|
||||||
update gen_table
|
update gen_table
|
||||||
<set>
|
<set>
|
||||||
|
|||||||
@ -27,6 +27,12 @@
|
|||||||
<artifactId>jaxb-runtime</artifactId>
|
<artifactId>jaxb-runtime</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.influxdb</groupId>
|
||||||
|
<artifactId>influxdb-java</artifactId>
|
||||||
|
<version>2.24</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
217
ems-system/src/main/java/com/xzzn/ems/domain/EmsPointConfig.java
Normal file
217
ems-system/src/main/java/com/xzzn/ems/domain/EmsPointConfig.java
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
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_point_config
|
||||||
|
*/
|
||||||
|
public class EmsPointConfig extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Excel(name = "站点ID")
|
||||||
|
private String siteId;
|
||||||
|
|
||||||
|
@Excel(name = "设备类型")
|
||||||
|
private String deviceCategory;
|
||||||
|
|
||||||
|
@Excel(name = "设备ID")
|
||||||
|
private String deviceId;
|
||||||
|
|
||||||
|
@Excel(name = "点位名称")
|
||||||
|
private String pointName;
|
||||||
|
|
||||||
|
@Excel(name = "数据键")
|
||||||
|
private String dataKey;
|
||||||
|
|
||||||
|
@Excel(name = "点位描述")
|
||||||
|
private String pointDesc;
|
||||||
|
|
||||||
|
@Excel(name = "寄存器地址")
|
||||||
|
private String registerAddress;
|
||||||
|
|
||||||
|
@Excel(name = "单位")
|
||||||
|
private String dataUnit;
|
||||||
|
|
||||||
|
@Excel(name = "A系数")
|
||||||
|
private BigDecimal dataA;
|
||||||
|
|
||||||
|
@Excel(name = "K系数")
|
||||||
|
private BigDecimal dataK;
|
||||||
|
|
||||||
|
@Excel(name = "B系数")
|
||||||
|
private BigDecimal dataB;
|
||||||
|
|
||||||
|
@Excel(name = "位偏移")
|
||||||
|
private Integer dataBit;
|
||||||
|
|
||||||
|
@Excel(name = "是否报警点位", readConverterExp = "0=否,1=是")
|
||||||
|
private Integer isAlarm;
|
||||||
|
|
||||||
|
@Excel(name = "点位类型")
|
||||||
|
private String pointType;
|
||||||
|
|
||||||
|
@Excel(name = "计算表达式")
|
||||||
|
private String calcExpression;
|
||||||
|
|
||||||
|
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 String getDeviceCategory() {
|
||||||
|
return deviceCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceCategory(String deviceCategory) {
|
||||||
|
this.deviceCategory = deviceCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceId(String deviceId) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPointName() {
|
||||||
|
return pointName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointName(String pointName) {
|
||||||
|
this.pointName = pointName;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 getRegisterAddress() {
|
||||||
|
return registerAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegisterAddress(String registerAddress) {
|
||||||
|
this.registerAddress = registerAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataUnit() {
|
||||||
|
return dataUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataUnit(String dataUnit) {
|
||||||
|
this.dataUnit = dataUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getDataA() {
|
||||||
|
return dataA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataA(BigDecimal dataA) {
|
||||||
|
this.dataA = dataA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getDataK() {
|
||||||
|
return dataK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataK(BigDecimal dataK) {
|
||||||
|
this.dataK = dataK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getDataB() {
|
||||||
|
return dataB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataB(BigDecimal dataB) {
|
||||||
|
this.dataB = dataB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getDataBit() {
|
||||||
|
return dataBit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataBit(Integer dataBit) {
|
||||||
|
this.dataBit = dataBit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getIsAlarm() {
|
||||||
|
return isAlarm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsAlarm(Integer isAlarm) {
|
||||||
|
this.isAlarm = isAlarm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPointType() {
|
||||||
|
return pointType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointType(String pointType) {
|
||||||
|
this.pointType = pointType;
|
||||||
|
}
|
||||||
|
|
||||||
|
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("siteId", getSiteId())
|
||||||
|
.append("deviceCategory", getDeviceCategory())
|
||||||
|
.append("deviceId", getDeviceId())
|
||||||
|
.append("pointName", getPointName())
|
||||||
|
.append("dataKey", getDataKey())
|
||||||
|
.append("pointDesc", getPointDesc())
|
||||||
|
.append("registerAddress", getRegisterAddress())
|
||||||
|
.append("dataUnit", getDataUnit())
|
||||||
|
.append("dataA", getDataA())
|
||||||
|
.append("dataK", getDataK())
|
||||||
|
.append("dataB", getDataB())
|
||||||
|
.append("dataBit", getDataBit())
|
||||||
|
.append("isAlarm", getIsAlarm())
|
||||||
|
.append("pointType", getPointType())
|
||||||
|
.append("calcExpression", getCalcExpression())
|
||||||
|
.append("createBy", getCreateBy())
|
||||||
|
.append("createTime", getCreateTime())
|
||||||
|
.append("updateBy", getUpdateBy())
|
||||||
|
.append("updateTime", getUpdateTime())
|
||||||
|
.append("remark", getRemark())
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.xzzn.ems.domain;
|
||||||
|
|
||||||
|
import com.xzzn.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控展示数据对象(按分组落到 ems_site_monitor_data_home/sbjk/tjbb)
|
||||||
|
*/
|
||||||
|
public class EmsSiteMonitorData extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String siteId;
|
||||||
|
private String fieldCode;
|
||||||
|
private String fieldValue;
|
||||||
|
private Date valueTime;
|
||||||
|
|
||||||
|
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 String getFieldCode() {
|
||||||
|
return fieldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldCode(String fieldCode) {
|
||||||
|
this.fieldCode = fieldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFieldValue() {
|
||||||
|
return fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldValue(String fieldValue) {
|
||||||
|
this.fieldValue = fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getValueTime() {
|
||||||
|
return valueTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValueTime(Date valueTime) {
|
||||||
|
this.valueTime = valueTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
package com.xzzn.ems.domain;
|
||||||
|
|
||||||
|
import com.xzzn.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控配置项定义对象 ems_site_monitor_item
|
||||||
|
*/
|
||||||
|
public class EmsSiteMonitorItem extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String moduleCode;
|
||||||
|
private String moduleName;
|
||||||
|
private String menuCode;
|
||||||
|
private String menuName;
|
||||||
|
private String sectionName;
|
||||||
|
private String fieldCode;
|
||||||
|
private String fieldName;
|
||||||
|
private Integer sortNo;
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModuleCode() {
|
||||||
|
return moduleCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModuleCode(String moduleCode) {
|
||||||
|
this.moduleCode = moduleCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModuleName() {
|
||||||
|
return moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModuleName(String moduleName) {
|
||||||
|
this.moduleName = moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMenuCode() {
|
||||||
|
return menuCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuCode(String menuCode) {
|
||||||
|
this.menuCode = menuCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMenuName() {
|
||||||
|
return menuName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuName(String menuName) {
|
||||||
|
this.menuName = menuName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSectionName() {
|
||||||
|
return sectionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSectionName(String sectionName) {
|
||||||
|
this.sectionName = sectionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFieldCode() {
|
||||||
|
return fieldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldCode(String fieldCode) {
|
||||||
|
this.fieldCode = fieldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFieldName() {
|
||||||
|
return fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldName(String fieldName) {
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSortNo() {
|
||||||
|
return sortNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortNo(Integer sortNo) {
|
||||||
|
this.sortNo = sortNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Integer status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package com.xzzn.ems.domain;
|
||||||
|
|
||||||
|
import com.xzzn.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控字段点位映射对象 ems_site_monitor_point_match
|
||||||
|
*/
|
||||||
|
public class EmsSiteMonitorPointMatch extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String siteId;
|
||||||
|
private String fieldCode;
|
||||||
|
private String dataPoint;
|
||||||
|
|
||||||
|
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 String getFieldCode() {
|
||||||
|
return fieldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldCode(String fieldCode) {
|
||||||
|
this.fieldCode = fieldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataPoint() {
|
||||||
|
return dataPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataPoint(String dataPoint) {
|
||||||
|
this.dataPoint = dataPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -54,6 +54,9 @@ public class EmsSiteSetting extends BaseEntity
|
|||||||
@Excel(name = "站点id")
|
@Excel(name = "站点id")
|
||||||
private String siteId;
|
private String siteId;
|
||||||
|
|
||||||
|
/** 授权状态:true-已授权,false-未授权 */
|
||||||
|
private Boolean authorized;
|
||||||
|
|
||||||
public void setId(Long id)
|
public void setId(Long id)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@ -144,6 +147,16 @@ public class EmsSiteSetting extends BaseEntity
|
|||||||
return siteId;
|
return siteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAuthorized(Boolean authorized)
|
||||||
|
{
|
||||||
|
this.authorized = authorized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getAuthorized()
|
||||||
|
{
|
||||||
|
return authorized;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||||
@ -161,6 +174,7 @@ public class EmsSiteSetting extends BaseEntity
|
|||||||
.append("createTime", getCreateTime())
|
.append("createTime", getCreateTime())
|
||||||
.append("updateTime", getUpdateTime())
|
.append("updateTime", getUpdateTime())
|
||||||
.append("siteId", getSiteId())
|
.append("siteId", getSiteId())
|
||||||
|
.append("authorized", getAuthorized())
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
public class GeneralQueryPointOptionVo {
|
||||||
|
private String pointName;
|
||||||
|
private String dataKey;
|
||||||
|
private String pointDesc;
|
||||||
|
|
||||||
|
public String getPointName() {
|
||||||
|
return pointName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointName(String pointName) {
|
||||||
|
this.pointName = pointName;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按站点导入点位模板请求参数
|
||||||
|
*/
|
||||||
|
public class ImportPointTemplateRequest {
|
||||||
|
|
||||||
|
/** 目标站点ID */
|
||||||
|
@NotBlank(message = "站点ID不能为空")
|
||||||
|
private String siteId;
|
||||||
|
|
||||||
|
/** 是否覆盖目标站点已有点位配置 */
|
||||||
|
private Boolean overwrite;
|
||||||
|
|
||||||
|
public String getSiteId() {
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteId(String siteId) {
|
||||||
|
this.siteId = siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getOverwrite() {
|
||||||
|
return overwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOverwrite(Boolean overwrite) {
|
||||||
|
this.overwrite = overwrite;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
public class PointConfigCurveRequest {
|
||||||
|
private String siteId;
|
||||||
|
private String deviceId;
|
||||||
|
private String dataKey;
|
||||||
|
private String rangeType;
|
||||||
|
private String startTime;
|
||||||
|
private String endTime;
|
||||||
|
|
||||||
|
public String getSiteId() {
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteId(String siteId) {
|
||||||
|
this.siteId = siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceId(String deviceId) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataKey() {
|
||||||
|
return dataKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataKey(String dataKey) {
|
||||||
|
this.dataKey = dataKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRangeType() {
|
||||||
|
return rangeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRangeType(String rangeType) {
|
||||||
|
this.rangeType = rangeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStartTime() {
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartTime(String startTime) {
|
||||||
|
this.startTime = startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEndTime() {
|
||||||
|
return endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndTime(String endTime) {
|
||||||
|
this.endTime = endTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class PointConfigCurveValueVo {
|
||||||
|
private Date dataTime;
|
||||||
|
private Object pointValue;
|
||||||
|
|
||||||
|
public Date getDataTime() {
|
||||||
|
return dataTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataTime(Date dataTime) {
|
||||||
|
this.dataTime = dataTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getPointValue() {
|
||||||
|
return pointValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointValue(Object pointValue) {
|
||||||
|
this.pointValue = pointValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
public class PointConfigLatestValueItemVo {
|
||||||
|
private String siteId;
|
||||||
|
private String deviceId;
|
||||||
|
private String dataKey;
|
||||||
|
|
||||||
|
public String getSiteId() {
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteId(String siteId) {
|
||||||
|
this.siteId = siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceId(String deviceId) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataKey() {
|
||||||
|
return dataKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataKey(String dataKey) {
|
||||||
|
this.dataKey = dataKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PointConfigLatestValueRequest {
|
||||||
|
private List<PointConfigLatestValueItemVo> points;
|
||||||
|
|
||||||
|
public List<PointConfigLatestValueItemVo> getPoints() {
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPoints(List<PointConfigLatestValueItemVo> points) {
|
||||||
|
this.points = points;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class PointConfigLatestValueVo {
|
||||||
|
private String siteId;
|
||||||
|
private String deviceId;
|
||||||
|
private String dataKey;
|
||||||
|
private Object pointValue;
|
||||||
|
private Date dataTime;
|
||||||
|
|
||||||
|
public String getSiteId() {
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteId(String siteId) {
|
||||||
|
this.siteId = siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceId(String deviceId) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataKey() {
|
||||||
|
return dataKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataKey(String dataKey) {
|
||||||
|
this.dataKey = dataKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getPointValue() {
|
||||||
|
return pointValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointValue(Object pointValue) {
|
||||||
|
this.pointValue = pointValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDataTime() {
|
||||||
|
return dataTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataTime(Date dataTime) {
|
||||||
|
this.dataTime = dataTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,6 +14,7 @@ public class PointNameRequest {
|
|||||||
private String deviceCategory;
|
private String deviceCategory;
|
||||||
|
|
||||||
private String pointName;
|
private String pointName;
|
||||||
|
private List<String> pointNames;
|
||||||
|
|
||||||
/** 数据分组 1-分钟 2-小时 3-天 */
|
/** 数据分组 1-分钟 2-小时 3-天 */
|
||||||
private int dataUnit;
|
private int dataUnit;
|
||||||
@ -50,6 +51,14 @@ public class PointNameRequest {
|
|||||||
this.pointName = pointName;
|
this.pointName = pointName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getPointNames() {
|
||||||
|
return pointNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointNames(List<String> pointNames) {
|
||||||
|
this.pointNames = pointNames;
|
||||||
|
}
|
||||||
|
|
||||||
public int getDataUnit() {
|
public int getDataUnit() {
|
||||||
return dataUnit;
|
return dataUnit;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class SiteMonitorDataSaveItemVo {
|
||||||
|
private String fieldCode;
|
||||||
|
private String fieldValue;
|
||||||
|
private Date valueTime;
|
||||||
|
|
||||||
|
public String getFieldCode() {
|
||||||
|
return fieldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldCode(String fieldCode) {
|
||||||
|
this.fieldCode = fieldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFieldValue() {
|
||||||
|
return fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldValue(String fieldValue) {
|
||||||
|
this.fieldValue = fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getValueTime() {
|
||||||
|
return valueTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValueTime(Date valueTime) {
|
||||||
|
this.valueTime = valueTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SiteMonitorDataSaveRequest {
|
||||||
|
private String siteId;
|
||||||
|
private List<SiteMonitorDataSaveItemVo> items;
|
||||||
|
|
||||||
|
public String getSiteId() {
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteId(String siteId) {
|
||||||
|
this.siteId = siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SiteMonitorDataSaveItemVo> getItems() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItems(List<SiteMonitorDataSaveItemVo> items) {
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控展示数据(配置项 + 当前值)
|
||||||
|
*/
|
||||||
|
public class SiteMonitorProjectDisplayVo extends SiteMonitorProjectPointMappingVo {
|
||||||
|
private String fieldValue;
|
||||||
|
private Date valueTime;
|
||||||
|
|
||||||
|
public String getFieldValue() {
|
||||||
|
return fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldValue(String fieldValue) {
|
||||||
|
this.fieldValue = fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getValueTime() {
|
||||||
|
return valueTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValueTime(Date valueTime) {
|
||||||
|
this.valueTime = valueTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SiteMonitorProjectPointMappingSaveRequest {
|
||||||
|
|
||||||
|
private String siteId;
|
||||||
|
|
||||||
|
private List<SiteMonitorProjectPointMappingVo> mappings;
|
||||||
|
|
||||||
|
public String getSiteId() {
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteId(String siteId) {
|
||||||
|
this.siteId = siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SiteMonitorProjectPointMappingVo> getMappings() {
|
||||||
|
return mappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMappings(List<SiteMonitorProjectPointMappingVo> mappings) {
|
||||||
|
this.mappings = mappings;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
package com.xzzn.ems.domain.vo;
|
||||||
|
|
||||||
|
public class SiteMonitorProjectPointMappingVo {
|
||||||
|
|
||||||
|
private String moduleCode;
|
||||||
|
|
||||||
|
private String moduleName;
|
||||||
|
|
||||||
|
private String menuCode;
|
||||||
|
|
||||||
|
private String menuName;
|
||||||
|
|
||||||
|
private String sectionName;
|
||||||
|
|
||||||
|
private String fieldCode;
|
||||||
|
|
||||||
|
private String fieldName;
|
||||||
|
|
||||||
|
private String dataPoint;
|
||||||
|
|
||||||
|
public String getModuleCode() {
|
||||||
|
return moduleCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModuleCode(String moduleCode) {
|
||||||
|
this.moduleCode = moduleCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModuleName() {
|
||||||
|
return moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModuleName(String moduleName) {
|
||||||
|
this.moduleName = moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFieldCode() {
|
||||||
|
return fieldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMenuCode() {
|
||||||
|
return menuCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuCode(String menuCode) {
|
||||||
|
this.menuCode = menuCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMenuName() {
|
||||||
|
return menuName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMenuName(String menuName) {
|
||||||
|
this.menuName = menuName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSectionName() {
|
||||||
|
return sectionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSectionName(String sectionName) {
|
||||||
|
this.sectionName = sectionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldCode(String fieldCode) {
|
||||||
|
this.fieldCode = fieldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFieldName() {
|
||||||
|
return fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldName(String fieldName) {
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataPoint() {
|
||||||
|
return dataPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataPoint(String dataPoint) {
|
||||||
|
this.dataPoint = dataPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package com.xzzn.ems.mapper;
|
||||||
|
|
||||||
|
import com.xzzn.ems.domain.EmsPointConfig;
|
||||||
|
import com.xzzn.ems.domain.vo.GeneralQueryPointOptionVo;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface EmsPointConfigMapper {
|
||||||
|
EmsPointConfig selectEmsPointConfigById(Long id);
|
||||||
|
|
||||||
|
List<EmsPointConfig> selectEmsPointConfigList(EmsPointConfig emsPointConfig);
|
||||||
|
|
||||||
|
int insertEmsPointConfig(EmsPointConfig emsPointConfig);
|
||||||
|
|
||||||
|
int updateEmsPointConfig(EmsPointConfig emsPointConfig);
|
||||||
|
|
||||||
|
int deleteEmsPointConfigById(Long id);
|
||||||
|
|
||||||
|
int deleteEmsPointConfigByIds(Long[] ids);
|
||||||
|
|
||||||
|
int countBySiteId(@Param("siteId") String siteId);
|
||||||
|
|
||||||
|
int deleteBySiteId(@Param("siteId") String siteId);
|
||||||
|
|
||||||
|
int copyTemplateToSite(@Param("templateSiteId") String templateSiteId,
|
||||||
|
@Param("targetSiteId") String targetSiteId,
|
||||||
|
@Param("operName") String operName);
|
||||||
|
|
||||||
|
String getRegisterAddress(@Param("siteId") String siteId,
|
||||||
|
@Param("deviceCategory") String deviceCategory,
|
||||||
|
@Param("deviceId") String deviceId,
|
||||||
|
@Param("dataKey") String dataKey);
|
||||||
|
|
||||||
|
List<GeneralQueryPointOptionVo> getPointNameList(@Param("siteIds") List<String> siteIds,
|
||||||
|
@Param("deviceCategory") String deviceCategory,
|
||||||
|
@Param("deviceId") String deviceId,
|
||||||
|
@Param("pointName") String pointName);
|
||||||
|
|
||||||
|
List<EmsPointConfig> getConfigListForGeneralQuery(@Param("siteIds") List<String> siteIds,
|
||||||
|
@Param("deviceCategory") String deviceCategory,
|
||||||
|
@Param("pointNames") List<String> pointNames,
|
||||||
|
@Param("deviceIds") List<String> deviceIds);
|
||||||
|
}
|
||||||
@ -67,4 +67,12 @@ public interface EmsPointEnumMatchMapper
|
|||||||
public List<EmsPointEnumMatch> selectList(@Param("siteId") String siteId,
|
public List<EmsPointEnumMatch> selectList(@Param("siteId") String siteId,
|
||||||
@Param("deviceCategory") String deviceCategory,
|
@Param("deviceCategory") String deviceCategory,
|
||||||
@Param("matchField") String matchField);
|
@Param("matchField") String matchField);
|
||||||
|
|
||||||
|
int countBySiteId(@Param("siteId") String siteId);
|
||||||
|
|
||||||
|
int deleteBySiteId(@Param("siteId") String siteId);
|
||||||
|
|
||||||
|
int copyTemplateToSite(@Param("templateSiteId") String templateSiteId,
|
||||||
|
@Param("targetSiteId") String targetSiteId,
|
||||||
|
@Param("operName") String operName);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -173,4 +173,14 @@ public interface EmsPointMatchMapper
|
|||||||
int getDevicePointAlarmNum(@Param("siteId") String siteId, @Param("deviceId") String deviceId, @Param("deviceCategory") String deviceCategory);
|
int getDevicePointAlarmNum(@Param("siteId") String siteId, @Param("deviceId") String deviceId, @Param("deviceCategory") String deviceCategory);
|
||||||
|
|
||||||
List<EmsPointMatch> selectDeviceStatusPoint(@Param("request") DeviceUpdateRequest request);
|
List<EmsPointMatch> selectDeviceStatusPoint(@Param("request") DeviceUpdateRequest request);
|
||||||
|
|
||||||
|
int countBySiteId(@Param("siteId") String siteId);
|
||||||
|
|
||||||
|
int deleteBySiteId(@Param("siteId") String siteId);
|
||||||
|
|
||||||
|
int copyTemplateToSite(@Param("templateSiteId") String templateSiteId,
|
||||||
|
@Param("targetSiteId") String targetSiteId,
|
||||||
|
@Param("operName") String operName);
|
||||||
|
|
||||||
|
List<EmsPointMatch> selectBySiteId(@Param("siteId") String siteId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.xzzn.ems.mapper;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控展示数据 Mapper
|
||||||
|
*/
|
||||||
|
public interface EmsSiteMonitorDataMapper {
|
||||||
|
String selectHistoryJsonByMinute(@Param("tableName") String tableName,
|
||||||
|
@Param("siteId") String siteId,
|
||||||
|
@Param("statisMinute") java.util.Date statisMinute);
|
||||||
|
|
||||||
|
int upsertHistoryJsonByMinute(@Param("tableName") String tableName,
|
||||||
|
@Param("siteId") String siteId,
|
||||||
|
@Param("statisMinute") java.util.Date statisMinute,
|
||||||
|
@Param("dataJson") String dataJson,
|
||||||
|
@Param("operName") String operName);
|
||||||
|
|
||||||
|
int updateHistoryHotColumns(@Param("tableName") String tableName,
|
||||||
|
@Param("siteId") String siteId,
|
||||||
|
@Param("statisMinute") java.util.Date statisMinute,
|
||||||
|
@Param("hotSoc") String hotSoc,
|
||||||
|
@Param("hotTotalActivePower") String hotTotalActivePower,
|
||||||
|
@Param("hotTotalReactivePower") String hotTotalReactivePower,
|
||||||
|
@Param("hotDayChargedCap") String hotDayChargedCap,
|
||||||
|
@Param("hotDayDisChargedCap") String hotDayDisChargedCap,
|
||||||
|
@Param("operName") String operName);
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.xzzn.ems.mapper;
|
||||||
|
|
||||||
|
import com.xzzn.ems.domain.EmsSiteMonitorItem;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控配置项定义 Mapper
|
||||||
|
*/
|
||||||
|
public interface EmsSiteMonitorItemMapper {
|
||||||
|
List<EmsSiteMonitorItem> selectEnabledList();
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.xzzn.ems.mapper;
|
||||||
|
|
||||||
|
import com.xzzn.ems.domain.EmsSiteMonitorPointMatch;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单站监控字段点位映射 Mapper
|
||||||
|
*/
|
||||||
|
public interface EmsSiteMonitorPointMatchMapper {
|
||||||
|
List<EmsSiteMonitorPointMatch> selectBySiteId(@Param("siteId") String siteId);
|
||||||
|
|
||||||
|
int deleteBySiteId(@Param("siteId") String siteId);
|
||||||
|
|
||||||
|
int insertBatch(@Param("list") List<EmsSiteMonitorPointMatch> list);
|
||||||
|
}
|
||||||
@ -6,7 +6,12 @@ import com.xzzn.ems.domain.vo.DeviceUpdateRequest;
|
|||||||
import com.xzzn.ems.domain.vo.DevicesSettingVo;
|
import com.xzzn.ems.domain.vo.DevicesSettingVo;
|
||||||
import com.xzzn.ems.domain.vo.PointDataRequest;
|
import com.xzzn.ems.domain.vo.PointDataRequest;
|
||||||
import com.xzzn.ems.domain.vo.PointQueryResponse;
|
import com.xzzn.ems.domain.vo.PointQueryResponse;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteMonitorDataSaveRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteMonitorProjectDisplayVo;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteMonitorProjectPointMappingSaveRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteMonitorProjectPointMappingVo;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -36,4 +41,14 @@ public interface IEmsDeviceSettingService
|
|||||||
public List<Map<String, Object>> getDeviceListBySiteAndCategory(String siteId, String deviceCategory);
|
public List<Map<String, Object>> getDeviceListBySiteAndCategory(String siteId, String deviceCategory);
|
||||||
|
|
||||||
public boolean updateDeviceStatus(DeviceUpdateRequest request);
|
public boolean updateDeviceStatus(DeviceUpdateRequest request);
|
||||||
|
|
||||||
|
public List<SiteMonitorProjectPointMappingVo> getSiteMonitorProjectPointMapping(String siteId);
|
||||||
|
|
||||||
|
public int saveSiteMonitorProjectPointMapping(SiteMonitorProjectPointMappingSaveRequest request, String operName);
|
||||||
|
|
||||||
|
public List<SiteMonitorProjectDisplayVo> getSiteMonitorProjectDisplay(String siteId);
|
||||||
|
|
||||||
|
public int saveSiteMonitorProjectData(SiteMonitorDataSaveRequest request, String operName);
|
||||||
|
|
||||||
|
public int syncSiteMonitorDataByMqtt(String siteId, String deviceId, String jsonData, Date valueTime);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
package com.xzzn.ems.service;
|
||||||
|
|
||||||
|
import com.xzzn.ems.domain.EmsPointConfig;
|
||||||
|
import com.xzzn.ems.domain.vo.ImportPointTemplateRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.PointConfigCurveRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.PointConfigCurveValueVo;
|
||||||
|
import com.xzzn.ems.domain.vo.PointConfigLatestValueRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.PointConfigLatestValueVo;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface IEmsPointConfigService {
|
||||||
|
List<EmsPointConfig> selectPointConfigList(EmsPointConfig pointConfig);
|
||||||
|
|
||||||
|
EmsPointConfig selectPointConfigById(Long id);
|
||||||
|
|
||||||
|
int insertPointConfig(EmsPointConfig pointConfig, String operName);
|
||||||
|
|
||||||
|
int updatePointConfig(EmsPointConfig pointConfig, String operName);
|
||||||
|
|
||||||
|
int deletePointConfigByIds(Long[] ids);
|
||||||
|
|
||||||
|
String importTemplateBySite(ImportPointTemplateRequest request, String operName);
|
||||||
|
|
||||||
|
String importCsvBySite(String siteId, Boolean overwrite, MultipartFile file, String operName);
|
||||||
|
|
||||||
|
String getRegisterAddress(String siteId, String deviceCategory, String deviceId, String dataKey);
|
||||||
|
|
||||||
|
List<PointConfigLatestValueVo> getLatestValues(PointConfigLatestValueRequest request);
|
||||||
|
|
||||||
|
List<PointConfigCurveValueVo> getCurveData(PointConfigCurveRequest request);
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@ import com.xzzn.ems.domain.EmsPointMatch;
|
|||||||
import com.xzzn.ems.domain.vo.DevicePointMatchExportVo;
|
import com.xzzn.ems.domain.vo.DevicePointMatchExportVo;
|
||||||
import com.xzzn.ems.domain.vo.DevicePointMatchVo;
|
import com.xzzn.ems.domain.vo.DevicePointMatchVo;
|
||||||
import com.xzzn.ems.domain.vo.ImportPointDataRequest;
|
import com.xzzn.ems.domain.vo.ImportPointDataRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.ImportPointTemplateRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 点位匹配Service接口
|
* 点位匹配Service接口
|
||||||
@ -40,4 +41,52 @@ public interface IEmsPointMatchService
|
|||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public List<DevicePointMatchVo> importDataByDevice(ImportPointDataRequest request, String operName);
|
public List<DevicePointMatchVo> importDataByDevice(ImportPointDataRequest request, String operName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按站点导入模板点位数据
|
||||||
|
* @param request 请求参数
|
||||||
|
* @param operName 操作人
|
||||||
|
* @return 导入结果信息
|
||||||
|
*/
|
||||||
|
public String importTemplateBySite(ImportPointTemplateRequest request, String operName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询点位配置列表
|
||||||
|
*
|
||||||
|
* @param emsPointMatch 点位配置
|
||||||
|
* @return 点位配置列表
|
||||||
|
*/
|
||||||
|
public List<EmsPointMatch> selectPointMatchConfigList(EmsPointMatch emsPointMatch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询点位配置详情
|
||||||
|
*
|
||||||
|
* @param id 主键ID
|
||||||
|
* @return 点位配置
|
||||||
|
*/
|
||||||
|
public EmsPointMatch selectPointMatchById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增点位配置
|
||||||
|
*
|
||||||
|
* @param emsPointMatch 点位配置
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertPointMatch(EmsPointMatch emsPointMatch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改点位配置
|
||||||
|
*
|
||||||
|
* @param emsPointMatch 点位配置
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updatePointMatch(EmsPointMatch emsPointMatch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除点位配置
|
||||||
|
*
|
||||||
|
* @param ids 主键集合
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deletePointMatchByIds(Long[] ids);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,4 +32,8 @@ public interface IEmsSiteService
|
|||||||
public List<Map<String,Object>> getAllPcsInfo(String siteId);
|
public List<Map<String,Object>> getAllPcsInfo(String siteId);
|
||||||
|
|
||||||
public List<Map<String,Object>> getParentCategoryDeviceId(String siteId, String deviceCategory);
|
public List<Map<String,Object>> getParentCategoryDeviceId(String siteId, String deviceCategory);
|
||||||
|
|
||||||
|
int addSite(EmsSiteSetting emsSiteSetting);
|
||||||
|
|
||||||
|
int updateSite(EmsSiteSetting emsSiteSetting);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ public interface IGeneralQueryService
|
|||||||
{
|
{
|
||||||
|
|
||||||
// 模糊查询获取点位名称List
|
// 模糊查询获取点位名称List
|
||||||
public List<String> getPointNameList(PointNameRequest request);
|
public List<GeneralQueryPointOptionVo> getPointNameList(PointNameRequest request);
|
||||||
|
|
||||||
// 根据条件获取点位数据变化
|
// 根据条件获取点位数据变化
|
||||||
public List<GeneralQueryResponse> getPointValueList(PointNameRequest request);
|
public List<GeneralQueryResponse> getPointValueList(PointNameRequest request);
|
||||||
|
|||||||
@ -0,0 +1,616 @@
|
|||||||
|
package com.xzzn.ems.service;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class InfluxPointDataWriter {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(InfluxPointDataWriter.class);
|
||||||
|
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
|
@Value("${influxdb.enabled:true}")
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
@Value("${influxdb.url:}")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@Value("${influxdb.username:}")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Value("${influxdb.password:}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Value("${influxdb.api-token:}")
|
||||||
|
private String apiToken;
|
||||||
|
|
||||||
|
@Value("${influxdb.database:ems_point_data}")
|
||||||
|
private String database;
|
||||||
|
|
||||||
|
@Value("${influxdb.retention-policy:autogen}")
|
||||||
|
private String retentionPolicy;
|
||||||
|
|
||||||
|
@Value("${influxdb.measurement:mqtt_point_data}")
|
||||||
|
private String measurement;
|
||||||
|
|
||||||
|
@Value("${influxdb.write-method:POST}")
|
||||||
|
private String writeMethod;
|
||||||
|
|
||||||
|
@Value("${influxdb.read-method:GET}")
|
||||||
|
private String readMethod;
|
||||||
|
|
||||||
|
@Value("${influxdb.write-path:/write}")
|
||||||
|
private String writePath;
|
||||||
|
|
||||||
|
@Value("${influxdb.query-path:/query}")
|
||||||
|
private String queryPath;
|
||||||
|
|
||||||
|
@Value("${influxdb.org:}")
|
||||||
|
private String org;
|
||||||
|
|
||||||
|
@Value("${influxdb.bucket:}")
|
||||||
|
private String bucket;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
if (!enabled) {
|
||||||
|
log.info("InfluxDB 写入已禁用");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (url == null || url.trim().isEmpty()) {
|
||||||
|
log.warn("InfluxDB URL 未配置,跳过初始化");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("InfluxDB 已启用 HTTP 接入, url: {}, database: {}", url, database);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeBatch(List<PointWritePayload> payloads) {
|
||||||
|
if (!enabled || payloads == null || payloads.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
StringBuilder body = new StringBuilder();
|
||||||
|
for (PointWritePayload payload : payloads) {
|
||||||
|
if (payload == null || payload.getPointValue() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
long time = payload.getDataTime() == null ? System.currentTimeMillis() : payload.getDataTime().getTime();
|
||||||
|
body.append(measurement)
|
||||||
|
.append(",site_id=").append(escapeLineTag(payload.getSiteId()))
|
||||||
|
.append(",device_id=").append(escapeLineTag(payload.getDeviceId()))
|
||||||
|
.append(",point_key=").append(escapeLineTag(payload.getPointKey()))
|
||||||
|
.append(" value=").append(payload.getPointValue().toPlainString())
|
||||||
|
.append(" ").append(time)
|
||||||
|
.append("\n");
|
||||||
|
}
|
||||||
|
if (body.length() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String writeUrl = buildWriteUrl();
|
||||||
|
if (isBlank(writeUrl)) {
|
||||||
|
log.warn("写入 InfluxDB 失败:v2 写入地址未构建成功,请检查 influxdb.org / influxdb.bucket 配置");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HttpResult result = executeRequest(methodOrDefault(writeMethod, "POST"), writeUrl, body.toString());
|
||||||
|
if (result.code < 200 || result.code >= 300) {
|
||||||
|
if (result.code == 404 && isV2WritePath() && isOrgOrBucketMissing(result.body)) {
|
||||||
|
if (ensureV2OrgAndBucket()) {
|
||||||
|
HttpResult retryResult = executeRequest(methodOrDefault(writeMethod, "POST"), writeUrl, body.toString());
|
||||||
|
if (retryResult.code >= 200 && retryResult.code < 300) {
|
||||||
|
log.info("InfluxDB org/bucket 自动创建成功,写入已恢复");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.warn("InfluxDB 重试写入失败,HTTP状态码: {}, url: {}, body: {}", retryResult.code, writeUrl, safeLog(retryResult.body));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.warn("写入 InfluxDB 失败,HTTP状态码: {}, url: {}, body: {}", result.code, writeUrl, safeLog(result.body));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("写入 InfluxDB 失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PointValue> queryCurveData(String siteId, String deviceId, String pointKey, Date startTime, Date endTime) {
|
||||||
|
if (!enabled) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
if (isBlank(siteId) || isBlank(deviceId) || isBlank(pointKey) || startTime == null || endTime == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
String normalizedSiteId = siteId.trim();
|
||||||
|
String normalizedDeviceId = deviceId.trim();
|
||||||
|
String normalizedPointKey = pointKey.trim();
|
||||||
|
|
||||||
|
String influxQl = String.format(
|
||||||
|
"SELECT \"value\" FROM \"%s\" WHERE \"site_id\" = '%s' AND \"device_id\" = '%s' AND \"point_key\" = '%s' " +
|
||||||
|
"AND time >= %dms AND time <= %dms ORDER BY time ASC",
|
||||||
|
measurement,
|
||||||
|
escapeTagValue(normalizedSiteId),
|
||||||
|
escapeTagValue(normalizedDeviceId),
|
||||||
|
escapeTagValue(normalizedPointKey),
|
||||||
|
startTime.getTime(),
|
||||||
|
endTime.getTime()
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
String queryUrl = buildQueryUrl(influxQl);
|
||||||
|
List<PointValue> values = parseInfluxQlResponse(executeRequestWithResponse(methodOrDefault(readMethod, "GET"), queryUrl));
|
||||||
|
if (!values.isEmpty()) {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兼容 dataKey 大小写差异,避免点位 key 字母大小写不一致导致查不到曲线
|
||||||
|
String regexQuery = String.format(
|
||||||
|
"SELECT \"value\" FROM \"%s\" WHERE \"site_id\" = '%s' AND \"device_id\" = '%s' AND \"point_key\" =~ /(?i)^%s$/ " +
|
||||||
|
"AND time >= %dms AND time <= %dms ORDER BY time ASC",
|
||||||
|
measurement,
|
||||||
|
escapeTagValue(normalizedSiteId),
|
||||||
|
escapeTagValue(normalizedDeviceId),
|
||||||
|
escapeRegex(normalizedPointKey),
|
||||||
|
startTime.getTime(),
|
||||||
|
endTime.getTime()
|
||||||
|
);
|
||||||
|
values = parseInfluxQlResponse(executeRequestWithResponse(methodOrDefault(readMethod, "GET"), buildQueryUrl(regexQuery)));
|
||||||
|
return values;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("查询 InfluxDB 曲线失败: {}", e.getMessage());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildWriteUrl() {
|
||||||
|
if (isV2WritePath()) {
|
||||||
|
return buildV2WriteUrl();
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder(trimTrailingSlash(url));
|
||||||
|
sb.append(normalizePath(writePath)).append("?db=").append(urlEncode(database));
|
||||||
|
if (!isBlank(retentionPolicy)) {
|
||||||
|
sb.append("&rp=").append(urlEncode(retentionPolicy));
|
||||||
|
}
|
||||||
|
sb.append("&precision=ms");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildQueryUrl(String influxQl) {
|
||||||
|
String queryDb = database;
|
||||||
|
if (isV2WritePath() && !isBlank(bucket)) {
|
||||||
|
queryDb = bucket;
|
||||||
|
}
|
||||||
|
StringBuilder queryUrl = new StringBuilder(trimTrailingSlash(url))
|
||||||
|
.append(normalizePath(queryPath))
|
||||||
|
.append("?db=").append(urlEncode(queryDb))
|
||||||
|
.append("&epoch=ms&q=").append(urlEncode(influxQl));
|
||||||
|
if (!isBlank(retentionPolicy)) {
|
||||||
|
queryUrl.append("&rp=").append(urlEncode(retentionPolicy));
|
||||||
|
}
|
||||||
|
return queryUrl.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildV2WriteUrl() {
|
||||||
|
String currentBucket = isBlank(bucket) ? database : bucket;
|
||||||
|
if (isBlank(org) || isBlank(currentBucket)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return trimTrailingSlash(url)
|
||||||
|
+ "/api/v2/write?org=" + urlEncode(org)
|
||||||
|
+ "&bucket=" + urlEncode(currentBucket)
|
||||||
|
+ "&precision=ms";
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpResult executeRequest(String method, String requestUrl, String body) throws Exception {
|
||||||
|
HttpURLConnection connection = openConnection(method, requestUrl, "text/plain; charset=UTF-8");
|
||||||
|
try {
|
||||||
|
if (body != null) {
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
try (OutputStream os = connection.getOutputStream()) {
|
||||||
|
os.write(body.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int code = connection.getResponseCode();
|
||||||
|
InputStream is = (code >= 200 && code < 300) ? connection.getInputStream() : connection.getErrorStream();
|
||||||
|
return new HttpResult(code, readStream(is));
|
||||||
|
} finally {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String executeRequestWithResponse(String method, String requestUrl) throws Exception {
|
||||||
|
HttpURLConnection connection = openConnection(method, requestUrl, "text/plain; charset=UTF-8");
|
||||||
|
try {
|
||||||
|
int code = connection.getResponseCode();
|
||||||
|
InputStream is = (code >= 200 && code < 300) ? connection.getInputStream() : connection.getErrorStream();
|
||||||
|
return readStream(is);
|
||||||
|
} finally {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readStream(InputStream is) throws Exception {
|
||||||
|
if (is == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
sb.append(line);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpResult executeJsonRequest(String method, String requestUrl, String jsonBody) throws Exception {
|
||||||
|
HttpURLConnection connection = openConnection(method, requestUrl, "application/json; charset=UTF-8");
|
||||||
|
try {
|
||||||
|
if (jsonBody != null) {
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
try (OutputStream os = connection.getOutputStream()) {
|
||||||
|
os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int code = connection.getResponseCode();
|
||||||
|
InputStream is = (code >= 200 && code < 300) ? connection.getInputStream() : connection.getErrorStream();
|
||||||
|
return new HttpResult(code, readStream(is));
|
||||||
|
} finally {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpURLConnection openConnection(String method, String requestUrl, String contentType) throws Exception {
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) new java.net.URL(requestUrl).openConnection();
|
||||||
|
connection.setRequestMethod(method);
|
||||||
|
connection.setConnectTimeout(5000);
|
||||||
|
connection.setReadTimeout(8000);
|
||||||
|
connection.setRequestProperty("Accept", "application/json");
|
||||||
|
connection.setRequestProperty("Content-Type", contentType);
|
||||||
|
if (!isBlank(apiToken)) {
|
||||||
|
connection.setRequestProperty("Authorization", "Token " + apiToken.trim());
|
||||||
|
} else if (!isBlank(username) || !isBlank(password)) {
|
||||||
|
String basic = java.util.Base64.getEncoder()
|
||||||
|
.encodeToString((safe(username) + ":" + safe(password)).getBytes(StandardCharsets.UTF_8));
|
||||||
|
connection.setRequestProperty("Authorization", "Basic " + basic);
|
||||||
|
}
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String escapeLineTag(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return value.replace("\\", "\\\\")
|
||||||
|
.replace(",", "\\,")
|
||||||
|
.replace(" ", "\\ ")
|
||||||
|
.replace("=", "\\=");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String trimTrailingSlash(String v) {
|
||||||
|
if (v == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String result = v.trim();
|
||||||
|
while (result.endsWith("/")) {
|
||||||
|
result = result.substring(0, result.length() - 1);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String urlEncode(String value) {
|
||||||
|
try {
|
||||||
|
return URLEncoder.encode(safe(value), StandardCharsets.UTF_8.name());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return safe(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String safe(String value) {
|
||||||
|
return value == null ? "" : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isV2WritePath() {
|
||||||
|
return "/api/v2/write".equals(normalizePath(writePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOrgOrBucketMissing(String responseBody) {
|
||||||
|
if (isBlank(responseBody)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String lower = responseBody.toLowerCase();
|
||||||
|
return (lower.contains("organization") && lower.contains("not found"))
|
||||||
|
|| (lower.contains("bucket") && lower.contains("not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean ensureV2OrgAndBucket() {
|
||||||
|
try {
|
||||||
|
if (isBlank(org)) {
|
||||||
|
log.warn("InfluxDB 自动创建 organization 失败:org 配置为空");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String currentBucket = isBlank(bucket) ? database : bucket;
|
||||||
|
String orgId = queryOrgId(org);
|
||||||
|
if (isBlank(orgId)) {
|
||||||
|
orgId = createOrg(org);
|
||||||
|
}
|
||||||
|
if (isBlank(orgId)) {
|
||||||
|
log.warn("InfluxDB 自动创建 organization 失败,org={}", org);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bucketExists(org, currentBucket)) {
|
||||||
|
if (!createBucket(orgId, currentBucket)) {
|
||||||
|
log.warn("InfluxDB 自动创建 bucket 失败,org={}, bucket={}", org, currentBucket);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.warn("InfluxDB 自动创建 org/bucket 异常: {}", ex.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String queryOrgId(String orgName) throws Exception {
|
||||||
|
String requestUrl = trimTrailingSlash(url) + "/api/v2/orgs?org=" + urlEncode(orgName);
|
||||||
|
HttpResult result = executeJsonRequest("GET", requestUrl, null);
|
||||||
|
if (result.code < 200 || result.code >= 300 || isBlank(result.body)) {
|
||||||
|
log.warn("查询 organization 失败,status={}, org={}, body={}", result.code, orgName, safeLog(result.body));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JsonNode root = OBJECT_MAPPER.readTree(result.body);
|
||||||
|
JsonNode orgs = root.path("orgs");
|
||||||
|
if (orgs.isArray() && orgs.size() > 0) {
|
||||||
|
JsonNode first = orgs.get(0);
|
||||||
|
if (first != null) {
|
||||||
|
String id = first.path("id").asText(null);
|
||||||
|
if (!isBlank(id)) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createOrg(String orgName) throws Exception {
|
||||||
|
String requestUrl = trimTrailingSlash(url) + "/api/v2/orgs";
|
||||||
|
Map<String, Object> payload = new HashMap<>();
|
||||||
|
payload.put("name", orgName);
|
||||||
|
String body = OBJECT_MAPPER.writeValueAsString(payload);
|
||||||
|
HttpResult result = executeJsonRequest("POST", requestUrl, body);
|
||||||
|
if ((result.code < 200 || result.code >= 300) || isBlank(result.body)) {
|
||||||
|
log.warn("创建 organization 失败,status={}, org={}, body={}", result.code, orgName, safeLog(result.body));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JsonNode root = OBJECT_MAPPER.readTree(result.body);
|
||||||
|
String id = root.path("id").asText(null);
|
||||||
|
return isBlank(id) ? null : id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean bucketExists(String orgName, String bucketName) throws Exception {
|
||||||
|
String requestUrl = trimTrailingSlash(url)
|
||||||
|
+ "/api/v2/buckets?name=" + urlEncode(bucketName)
|
||||||
|
+ "&org=" + urlEncode(orgName);
|
||||||
|
HttpResult result = executeJsonRequest("GET", requestUrl, null);
|
||||||
|
if (result.code < 200 || result.code >= 300 || isBlank(result.body)) {
|
||||||
|
log.warn("查询 bucket 失败,status={}, org={}, bucket={}, body={}", result.code, orgName, bucketName, safeLog(result.body));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
JsonNode root = OBJECT_MAPPER.readTree(result.body);
|
||||||
|
JsonNode buckets = root.path("buckets");
|
||||||
|
return buckets.isArray() && buckets.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean createBucket(String orgId, String bucketName) throws Exception {
|
||||||
|
String requestUrl = trimTrailingSlash(url) + "/api/v2/buckets";
|
||||||
|
Map<String, Object> payload = new HashMap<>();
|
||||||
|
payload.put("orgID", orgId);
|
||||||
|
payload.put("name", bucketName);
|
||||||
|
String body = OBJECT_MAPPER.writeValueAsString(payload);
|
||||||
|
HttpResult result = executeJsonRequest("POST", requestUrl, body);
|
||||||
|
if (result.code < 200 || result.code >= 300) {
|
||||||
|
log.warn("创建 bucket 失败,status={}, orgId={}, bucket={}, body={}", result.code, orgId, bucketName, safeLog(result.body));
|
||||||
|
}
|
||||||
|
return result.code >= 200 && result.code < 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String methodOrDefault(String method, String defaultMethod) {
|
||||||
|
return isBlank(method) ? defaultMethod : method.trim().toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizePath(String path) {
|
||||||
|
if (isBlank(path)) {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
String p = path.trim();
|
||||||
|
return p.startsWith("/") ? p : "/" + p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String safeLog(String body) {
|
||||||
|
if (body == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return body.length() > 200 ? body.substring(0, 200) : body;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date parseInfluxTime(Object timeObject) {
|
||||||
|
if (timeObject == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (timeObject instanceof Number) {
|
||||||
|
return new Date(((Number) timeObject).longValue());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Date.from(Instant.parse(String.valueOf(timeObject)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal toBigDecimal(Object valueObject) {
|
||||||
|
if (valueObject == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (valueObject instanceof BigDecimal) {
|
||||||
|
return (BigDecimal) valueObject;
|
||||||
|
}
|
||||||
|
if (valueObject instanceof Number) {
|
||||||
|
return new BigDecimal(valueObject.toString());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new BigDecimal(String.valueOf(valueObject));
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String escapeTagValue(String value) {
|
||||||
|
return value == null ? "" : value.replace("\\", "\\\\").replace("'", "\\'");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String escapeRegex(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return value.replace("\\", "\\\\")
|
||||||
|
.replace("/", "\\/")
|
||||||
|
.replace(".", "\\.")
|
||||||
|
.replace("(", "\\(")
|
||||||
|
.replace(")", "\\)")
|
||||||
|
.replace("[", "\\[")
|
||||||
|
.replace("]", "\\]")
|
||||||
|
.replace("{", "\\{")
|
||||||
|
.replace("}", "\\}")
|
||||||
|
.replace("^", "\\^")
|
||||||
|
.replace("$", "\\$")
|
||||||
|
.replace("*", "\\*")
|
||||||
|
.replace("+", "\\+")
|
||||||
|
.replace("?", "\\?")
|
||||||
|
.replace("|", "\\|");
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PointValue> parseInfluxQlResponse(String response) throws Exception {
|
||||||
|
if (isBlank(response)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<PointValue> values = new ArrayList<>();
|
||||||
|
JsonNode root = OBJECT_MAPPER.readTree(response);
|
||||||
|
JsonNode resultsNode = root.path("results");
|
||||||
|
if (!resultsNode.isArray()) {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (JsonNode result : resultsNode) {
|
||||||
|
JsonNode seriesArray = result.path("series");
|
||||||
|
if (!seriesArray.isArray()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (JsonNode series : seriesArray) {
|
||||||
|
JsonNode rows = series.path("values");
|
||||||
|
if (!rows.isArray()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (JsonNode row : rows) {
|
||||||
|
if (!row.isArray() || row.size() < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Date dataTime = parseInfluxTime(row.get(0).isNumber() ? row.get(0).asLong() : row.get(0).asText());
|
||||||
|
BigDecimal pointValue = toBigDecimal(row.get(1).isNumber() ? row.get(1).asText() : row.get(1).asText(null));
|
||||||
|
if (dataTime == null || pointValue == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
values.add(new PointValue(dataTime, pointValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlank(String value) {
|
||||||
|
return value == null || value.trim().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PointWritePayload {
|
||||||
|
private final String siteId;
|
||||||
|
private final String deviceId;
|
||||||
|
private final String pointKey;
|
||||||
|
private final BigDecimal pointValue;
|
||||||
|
private final Date dataTime;
|
||||||
|
|
||||||
|
public PointWritePayload(String siteId, String deviceId, String pointKey, BigDecimal pointValue, Date dataTime) {
|
||||||
|
this.siteId = siteId;
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.pointKey = pointKey;
|
||||||
|
this.pointValue = pointValue;
|
||||||
|
this.dataTime = dataTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSiteId() {
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPointKey() {
|
||||||
|
return pointKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getPointValue() {
|
||||||
|
return pointValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDataTime() {
|
||||||
|
return dataTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PointValue {
|
||||||
|
private final Date dataTime;
|
||||||
|
private final BigDecimal pointValue;
|
||||||
|
|
||||||
|
public PointValue(Date dataTime, BigDecimal pointValue) {
|
||||||
|
this.dataTime = dataTime;
|
||||||
|
this.pointValue = pointValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDataTime() {
|
||||||
|
return dataTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getPointValue() {
|
||||||
|
return pointValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class HttpResult {
|
||||||
|
private final int code;
|
||||||
|
private final String body;
|
||||||
|
|
||||||
|
private HttpResult(int code, String body) {
|
||||||
|
this.code = code;
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -48,12 +48,14 @@ import com.xzzn.ems.mapper.EmsEmsDataMapper;
|
|||||||
import com.xzzn.ems.mapper.EmsPcsAlarmDataMapper;
|
import com.xzzn.ems.mapper.EmsPcsAlarmDataMapper;
|
||||||
import com.xzzn.ems.mapper.EmsPcsBranchDataMapper;
|
import com.xzzn.ems.mapper.EmsPcsBranchDataMapper;
|
||||||
import com.xzzn.ems.mapper.EmsPcsDataMapper;
|
import com.xzzn.ems.mapper.EmsPcsDataMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsPointConfigMapper;
|
||||||
import com.xzzn.ems.mapper.EmsStackAlarmDataMapper;
|
import com.xzzn.ems.mapper.EmsStackAlarmDataMapper;
|
||||||
import com.xzzn.ems.mapper.EmsXfDataMapper;
|
import com.xzzn.ems.mapper.EmsXfDataMapper;
|
||||||
import com.xzzn.ems.service.IDeviceDataProcessService;
|
import com.xzzn.ems.service.IDeviceDataProcessService;
|
||||||
import com.xzzn.ems.service.IEmsAlarmRecordsService;
|
import com.xzzn.ems.service.IEmsAlarmRecordsService;
|
||||||
import com.xzzn.ems.service.IEmsDeviceSettingService;
|
import com.xzzn.ems.service.IEmsDeviceSettingService;
|
||||||
import com.xzzn.ems.service.IEmsEnergyPriceConfigService;
|
import com.xzzn.ems.service.IEmsEnergyPriceConfigService;
|
||||||
|
import com.xzzn.ems.service.InfluxPointDataWriter;
|
||||||
import com.xzzn.ems.utils.AbstractBatteryDataProcessor;
|
import com.xzzn.ems.utils.AbstractBatteryDataProcessor;
|
||||||
import com.xzzn.ems.utils.DevicePointMatchDataProcessor;
|
import com.xzzn.ems.utils.DevicePointMatchDataProcessor;
|
||||||
|
|
||||||
@ -68,16 +70,25 @@ import java.util.Arrays;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
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.ConcurrentHashMap;
|
import java.util.Collections;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -92,7 +103,13 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
private static final Pattern PATTERN = Pattern.compile("(BMSD\\d{2})(ZT|SOC|SOH|DL|DY|BDSC)");
|
private static final Pattern PATTERN = Pattern.compile("(BMSD\\d{2})(ZT|SOC|SOH|DL|DY|BDSC)");
|
||||||
// 匹配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 final Map<String, Integer> topicEmptyCounts = new ConcurrentHashMap<>();
|
private static final Pattern DB_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9_]+$");
|
||||||
|
private static final int POINT_QUEUE_CAPACITY = 100000;
|
||||||
|
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_ENQUEUE_RETRY_TIMES = 3;
|
||||||
|
private static final long POINT_ENQUEUE_RETRY_WAIT_MS = 10;
|
||||||
|
private static final long POINT_FLUSH_INTERVAL_MS = 100;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmsBatteryClusterMapper emsBatteryClusterMapper;
|
private EmsBatteryClusterMapper emsBatteryClusterMapper;
|
||||||
@ -103,6 +120,8 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EmsPcsDataMapper emsPcsDataMapper;
|
private EmsPcsDataMapper emsPcsDataMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private EmsPointConfigMapper emsPointConfigMapper;
|
||||||
|
@Autowired
|
||||||
private EmsPcsBranchDataMapper emsPcsBranchDataMapper;
|
private EmsPcsBranchDataMapper emsPcsBranchDataMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmsAmmeterDataMapper emsAmmeterDataMapper;
|
private EmsAmmeterDataMapper emsAmmeterDataMapper;
|
||||||
@ -147,17 +166,41 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisCache redisCache;
|
private RedisCache redisCache;
|
||||||
|
@Autowired
|
||||||
|
private InfluxPointDataWriter influxPointDataWriter;
|
||||||
|
private final BlockingQueue<PointDataRecord> pointDataQueue = new LinkedBlockingQueue<>(POINT_QUEUE_CAPACITY);
|
||||||
|
private final ScheduledExecutorService pointDataWriter = Executors.newSingleThreadScheduledExecutor(r -> {
|
||||||
|
Thread thread = new Thread(r);
|
||||||
|
thread.setName("point-data-writer");
|
||||||
|
thread.setDaemon(true);
|
||||||
|
return thread;
|
||||||
|
});
|
||||||
|
private final AtomicBoolean pointDataFlushing = new AtomicBoolean(false);
|
||||||
|
|
||||||
// 构造方法(调用父类构造)
|
// 构造方法(调用父类构造)
|
||||||
public DeviceDataProcessServiceImpl(ObjectMapper objectMapper) {
|
public DeviceDataProcessServiceImpl(ObjectMapper objectMapper) {
|
||||||
super(objectMapper);
|
super(objectMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void initPointDataBatchWriter() {
|
||||||
|
pointDataWriter.scheduleWithFixedDelay(this::flushPointDataSafely,
|
||||||
|
POINT_FLUSH_INTERVAL_MS, POINT_FLUSH_INTERVAL_MS, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void destroyPointDataBatchWriter() {
|
||||||
|
flushPointDataSafely();
|
||||||
|
pointDataWriter.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleDeviceData(String message, String siteId) {
|
public void handleDeviceData(String message, String siteId) {
|
||||||
JSONArray arraylist = parseJsonData(message);
|
JSONArray arraylist = parseJsonData(message);
|
||||||
if (arraylist == null) return;
|
if (arraylist == null) return;
|
||||||
// 过滤掉空数据(空数据不处理,直接返回
|
long startMs = System.currentTimeMillis();
|
||||||
|
log.info("开始处理设备数据, siteId: {}, messageSize: {}", siteId, arraylist.size());
|
||||||
|
Set<String> deviceIds = new LinkedHashSet<>();
|
||||||
|
|
||||||
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());
|
||||||
@ -167,36 +210,210 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
Long timestamp = obj.getLong("timestamp");
|
Long timestamp = obj.getLong("timestamp");
|
||||||
Date dataUpdateTime = DateUtils.convertUpdateTime(timestamp);
|
Date dataUpdateTime = DateUtils.convertUpdateTime(timestamp);
|
||||||
|
|
||||||
log.info("deviceId:" + deviceId);
|
if (StringUtils.isNotBlank(deviceId)) {
|
||||||
String deviceNumber = siteId + deviceId;
|
deviceIds.add(deviceId);
|
||||||
boolean isEmpty = checkJsonDataEmpty(jsonData);
|
}
|
||||||
if (isEmpty) {
|
if (checkJsonDataEmpty(jsonData)) {
|
||||||
// 增加失败计数
|
continue;
|
||||||
int failureCount = topicEmptyCounts.getOrDefault(deviceNumber, 0) + 1;
|
}
|
||||||
topicEmptyCounts.put(deviceNumber, failureCount);
|
|
||||||
|
|
||||||
log.warn("设备 {} topic内没有数据,当前连续次数: {}", deviceId, failureCount);
|
try {
|
||||||
|
// 保留每个设备最新一条原始报文,供“点位最新值”从 Redis 读取
|
||||||
|
redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceId, obj);
|
||||||
|
redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA + siteId + "_" + deviceId, obj, 1, TimeUnit.MINUTES);
|
||||||
|
|
||||||
// 连续5次失败触发报警
|
processPointConfigData(siteId, deviceId, jsonData, dataUpdateTime);
|
||||||
if (failureCount >= 5) {
|
iEmsDeviceSettingService.syncSiteMonitorDataByMqtt(siteId, deviceId, jsonData, dataUpdateTime);
|
||||||
// 添加设备告警
|
} catch (Exception e) {
|
||||||
iEmsAlarmRecordsService.addEmptyDataAlarmRecord(siteId, deviceId);
|
log.warn("点位映射数据处理失败,siteId: {}, deviceId: {}, err: {}",
|
||||||
log.error("设备 {} 连续 {} 次topic内没有数据,触发告警", deviceNumber, failureCount);
|
siteId, deviceId, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("结束处理设备数据, siteId: {}, deviceCount: {}, deviceIds: {}, costMs: {}",
|
||||||
|
siteId, deviceIds.size(), String.join(",", deviceIds), System.currentTimeMillis() - startMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processPointConfigData(String siteId, String deviceId, String jsonData, Date dataUpdateTime) {
|
||||||
|
if (StringUtils.isAnyBlank(siteId, deviceId, jsonData)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!DB_NAME_PATTERN.matcher(siteId).matches()) {
|
||||||
|
log.warn("站点ID不合法,跳过点位映射落库,siteId: {}", siteId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> dataMap = JSON.parseObject(jsonData, new TypeReference<Map<String, Object>>() {
|
||||||
|
});
|
||||||
|
if (org.apache.commons.collections4.MapUtils.isEmpty(dataMap)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<EmsPointConfig> pointConfigs = getPointConfigsWithCache(siteId, deviceId);
|
||||||
|
if (CollectionUtils.isEmpty(pointConfigs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, EmsPointConfig> configByDataKey = pointConfigs.stream()
|
||||||
|
.filter(cfg -> StringUtils.isNotBlank(cfg.getDataKey()))
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
cfg -> cfg.getDataKey().toUpperCase(),
|
||||||
|
cfg -> cfg,
|
||||||
|
(oldValue, newValue) -> oldValue
|
||||||
|
));
|
||||||
|
|
||||||
|
for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
|
||||||
|
String dataKey = entry.getKey();
|
||||||
|
if (StringUtils.isBlank(dataKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EmsPointConfig pointConfig = configByDataKey.get(dataKey.toUpperCase());
|
||||||
|
if (pointConfig == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal pointValue = StringUtils.getBigDecimal(entry.getValue());
|
||||||
|
if (pointValue == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 支持按配置进行二次转换:f(x)=A*x^2 + K*x + B
|
||||||
|
pointValue = convertPointValue(pointValue, pointConfig);
|
||||||
|
|
||||||
|
enqueuePointData(siteId, deviceId, pointConfig.getDataKey(), pointValue, dataUpdateTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enqueuePointData(String siteId, String deviceId, String pointKey, BigDecimal pointValue, Date dataTime) {
|
||||||
|
if (StringUtils.isAnyBlank(siteId, deviceId, pointKey) || pointValue == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PointDataRecord record = new PointDataRecord(siteId, deviceId, pointKey, pointValue, dataTime);
|
||||||
|
if (pointDataQueue.offer(record)) {
|
||||||
|
if (pointDataQueue.remainingCapacity() <= POINT_FLUSH_BATCH_SIZE) {
|
||||||
|
flushPointDataSafely();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 数据读取成功,重置计数器
|
|
||||||
topicEmptyCounts.remove(deviceNumber);
|
|
||||||
// 读取到数据后告警自恢复
|
|
||||||
iEmsAlarmRecordsService.deleteEmptyDataAlarmRecord(siteId, deviceId);
|
|
||||||
|
|
||||||
// 存放mqtt原始每个设备最晚一次数据,便于后面点位获取数据
|
// 队列压力较高时,优先触发冲刷并短暂重试,避免 MQTT 处理线程直接阻塞在数据库写入上。
|
||||||
redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceId, obj);
|
for (int i = 0; i < POINT_ENQUEUE_RETRY_TIMES; i++) {
|
||||||
// 存放每次同步数据,失效时间(同同步时间)-用于判断是否正常同步数据
|
flushPointDataSafely();
|
||||||
redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA + siteId + "_" + deviceId, obj, 1, TimeUnit.MINUTES);
|
try {
|
||||||
|
if (pointDataQueue.offer(record, POINT_ENQUEUE_RETRY_WAIT_MS, TimeUnit.MILLISECONDS)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException interruptedException) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 处理设备数据
|
log.warn("点位写入队列持续拥塞,降级同步写入 InfluxDB,siteId: {}, queueSize: {}",
|
||||||
processingDeviceData(siteId, deviceId, jsonData, dataUpdateTime);
|
siteId, pointDataQueue.size());
|
||||||
|
writePointDataToInflux(Collections.singletonList(record));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 void flushPointDataSafely() {
|
||||||
|
if (!pointDataFlushing.compareAndSet(false, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int drainedCount = 0;
|
||||||
|
while (drainedCount < POINT_FLUSH_MAX_DRAIN_PER_RUN) {
|
||||||
|
List<PointDataRecord> batch = new ArrayList<>(POINT_FLUSH_BATCH_SIZE);
|
||||||
|
pointDataQueue.drainTo(batch, POINT_FLUSH_BATCH_SIZE);
|
||||||
|
if (batch.isEmpty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
drainedCount += batch.size();
|
||||||
|
writePointDataToInflux(batch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointDataQueue.remainingCapacity() <= POINT_FLUSH_BATCH_SIZE) {
|
||||||
|
log.warn("点位写入队列积压较高,queueSize: {}", pointDataQueue.size());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("批量写入点位数据失败: {}", e.getMessage(), e);
|
||||||
|
} finally {
|
||||||
|
pointDataFlushing.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writePointDataToInflux(List<PointDataRecord> records) {
|
||||||
|
if (CollectionUtils.isEmpty(records)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<InfluxPointDataWriter.PointWritePayload> payloads = records.stream()
|
||||||
|
.map(item -> new InfluxPointDataWriter.PointWritePayload(
|
||||||
|
item.getSiteId(),
|
||||||
|
item.getDeviceId(),
|
||||||
|
item.getPointKey(),
|
||||||
|
item.getPointValue(),
|
||||||
|
item.getDataTime()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
influxPointDataWriter.writeBatch(payloads);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<EmsPointConfig> getPointConfigsWithCache(String siteId, String deviceId) {
|
||||||
|
String cacheKey = RedisKeyConstants.POINT_CONFIG_DEVICE + siteId + "_" + deviceId;
|
||||||
|
List<EmsPointConfig> cached = redisCache.getCacheObject(cacheKey);
|
||||||
|
if (cached != null) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
EmsPointConfig query = new EmsPointConfig();
|
||||||
|
query.setSiteId(siteId);
|
||||||
|
query.setDeviceId(deviceId);
|
||||||
|
List<EmsPointConfig> latest = emsPointConfigMapper.selectEmsPointConfigList(query);
|
||||||
|
List<EmsPointConfig> cacheValue = latest == null ? new ArrayList<>() : latest;
|
||||||
|
redisCache.setCacheObject(cacheKey, cacheValue);
|
||||||
|
return cacheValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PointDataRecord {
|
||||||
|
private final String siteId;
|
||||||
|
private final String deviceId;
|
||||||
|
private final String pointKey;
|
||||||
|
private final BigDecimal pointValue;
|
||||||
|
private final Date dataTime;
|
||||||
|
|
||||||
|
private PointDataRecord(String siteId, String deviceId, String pointKey, BigDecimal pointValue, Date dataTime) {
|
||||||
|
this.siteId = siteId;
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.pointKey = pointKey;
|
||||||
|
this.pointValue = pointValue;
|
||||||
|
this.dataTime = dataTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSiteId() {
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPointKey() {
|
||||||
|
return pointKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal getPointValue() {
|
||||||
|
return pointValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date getDataTime() {
|
||||||
|
return dataTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,7 +641,7 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
String status = dataStack.getWorkStatus();
|
String status = dataStack.getWorkStatus();
|
||||||
int result = 5;
|
int result = 5;
|
||||||
|
|
||||||
if (status != null && !status.trim().isEmpty()) {
|
if (status != null && !status.trim().isEmpty() && status.contains("null")) {
|
||||||
// 1.0 -> 1, 2.0 -> 2
|
// 1.0 -> 1, 2.0 -> 2
|
||||||
result = (int) Double.parseDouble(status.trim());
|
result = (int) Double.parseDouble(status.trim());
|
||||||
}
|
}
|
||||||
@ -880,7 +1097,7 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
//TODO 临时解决上送数据为浮点的问题 start
|
//TODO 临时解决上送数据为浮点的问题 start
|
||||||
String status = pcsData.getWorkStatus();
|
String status = pcsData.getWorkStatus();
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (status != null && !status.trim().isEmpty()) {
|
if (status != null && !status.trim().isEmpty() && status.contains("null")) {
|
||||||
// 1.0 -> 1, 2.0 -> 2
|
// 1.0 -> 1, 2.0 -> 2
|
||||||
result = (int) Double.parseDouble(status.trim());
|
result = (int) Double.parseDouble(status.trim());
|
||||||
}
|
}
|
||||||
@ -1020,7 +1237,7 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
log.info("临时解决上送数据为浮点的问题");
|
log.info("临时解决上送数据为浮点的问题");
|
||||||
String status = data.getWorkStatus();
|
String status = data.getWorkStatus();
|
||||||
int result = 5;
|
int result = 5;
|
||||||
if (status != null && !status.trim().isEmpty()) {
|
if (status != null && !status.trim().isEmpty() && status.contains("null")) {
|
||||||
// 1.0 -> 1, 2.0 -> 2
|
// 1.0 -> 1, 2.0 -> 2
|
||||||
result = (int) Double.parseDouble(status.trim());
|
result = (int) Double.parseDouble(status.trim());
|
||||||
}
|
}
|
||||||
@ -1908,12 +2125,12 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
|
|||||||
boolean flag = false;
|
boolean flag = false;
|
||||||
try {
|
try {
|
||||||
if (StringUtils.isEmpty(jsonData)) {
|
if (StringUtils.isEmpty(jsonData)) {
|
||||||
return true;
|
flag = true;
|
||||||
}
|
}
|
||||||
JsonNode jsonNode = objectMapper.readTree(jsonData);
|
JsonNode jsonNode = objectMapper.readTree(jsonData);
|
||||||
// 判断是否为空对象({})
|
// 判断是否为空对象({})
|
||||||
if (jsonNode.isObject() && jsonNode.isEmpty()) {
|
if (jsonNode.isObject() && jsonNode.isEmpty()) {
|
||||||
return true;
|
flag = true;
|
||||||
}
|
}
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|||||||
@ -17,15 +17,26 @@ 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.EmsPointMatch;
|
||||||
import com.xzzn.ems.domain.EmsPcsSetting;
|
import com.xzzn.ems.domain.EmsPcsSetting;
|
||||||
|
import com.xzzn.ems.domain.EmsSiteMonitorItem;
|
||||||
|
import com.xzzn.ems.domain.EmsSiteMonitorPointMatch;
|
||||||
import com.xzzn.ems.domain.vo.DeviceUpdateRequest;
|
import com.xzzn.ems.domain.vo.DeviceUpdateRequest;
|
||||||
import com.xzzn.ems.domain.vo.DevicesSettingVo;
|
import com.xzzn.ems.domain.vo.DevicesSettingVo;
|
||||||
import com.xzzn.ems.domain.vo.PointDataRequest;
|
import com.xzzn.ems.domain.vo.PointDataRequest;
|
||||||
import com.xzzn.ems.domain.vo.PointQueryResponse;
|
import com.xzzn.ems.domain.vo.PointQueryResponse;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteMonitorDataSaveItemVo;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteMonitorDataSaveRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteMonitorProjectDisplayVo;
|
||||||
|
import com.xzzn.ems.domain.vo.SiteMonitorProjectPointMappingSaveRequest;
|
||||||
|
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.EmsPointMatchMapper;
|
import com.xzzn.ems.mapper.EmsPointMatchMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsSiteMonitorDataMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsSiteMonitorItemMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsSiteMonitorPointMatchMapper;
|
||||||
import com.xzzn.ems.service.IEmsDeviceSettingService;
|
import com.xzzn.ems.service.IEmsDeviceSettingService;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@ -37,6 +48,7 @@ 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;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -56,6 +68,12 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
private static final Logger log = LoggerFactory.getLogger(EmsDeviceSettingServiceImpl.class);
|
private static final Logger log = LoggerFactory.getLogger(EmsDeviceSettingServiceImpl.class);
|
||||||
|
|
||||||
private static final String DDS_SITE_ID = "021_DDS_01";
|
private static final String DDS_SITE_ID = "021_DDS_01";
|
||||||
|
private static final String MODULE_HOME = "HOME";
|
||||||
|
private static final String MODULE_SBJK = "SBJK";
|
||||||
|
private static final String MODULE_TJBB = "TJBB";
|
||||||
|
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_TJBB = "ems_site_monitor_data_tjbb_his";
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmsDevicesSettingMapper emsDevicesMapper;
|
private EmsDevicesSettingMapper emsDevicesMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -70,6 +88,12 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
private EmsBatteryClusterServiceImpl emsBatteryClusterServiceImpl;
|
private EmsBatteryClusterServiceImpl emsBatteryClusterServiceImpl;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ModbusProcessor modbusProcessor;
|
private ModbusProcessor modbusProcessor;
|
||||||
|
@Autowired
|
||||||
|
private EmsSiteMonitorItemMapper emsSiteMonitorItemMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsSiteMonitorPointMatchMapper emsSiteMonitorPointMatchMapper;
|
||||||
|
@Autowired
|
||||||
|
private EmsSiteMonitorDataMapper emsSiteMonitorDataMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取设备详细信息
|
* 获取设备详细信息
|
||||||
@ -376,6 +400,439 @@ public class EmsDeviceSettingServiceImpl implements IEmsDeviceSettingService
|
|||||||
return emsDevicesMapper.getAllDeviceCategoryBySiteId(siteId);
|
return emsDevicesMapper.getAllDeviceCategoryBySiteId(siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SiteMonitorProjectPointMappingVo> getSiteMonitorProjectPointMapping(String siteId) {
|
||||||
|
List<SiteMonitorProjectPointMappingVo> result = new ArrayList<>();
|
||||||
|
if (StringUtils.isBlank(siteId)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
List<EmsSiteMonitorItem> itemList = emsSiteMonitorItemMapper.selectEnabledList();
|
||||||
|
if (itemList == null || itemList.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
List<EmsSiteMonitorPointMatch> mappingList = emsSiteMonitorPointMatchMapper.selectBySiteId(siteId);
|
||||||
|
Map<String, String> pointMap = mappingList.stream()
|
||||||
|
.filter(item -> StringUtils.isNotBlank(item.getFieldCode()))
|
||||||
|
.collect(Collectors.toMap(EmsSiteMonitorPointMatch::getFieldCode, EmsSiteMonitorPointMatch::getDataPoint, (a, b) -> b));
|
||||||
|
|
||||||
|
itemList.forEach(item -> {
|
||||||
|
SiteMonitorProjectPointMappingVo vo = new SiteMonitorProjectPointMappingVo();
|
||||||
|
vo.setModuleCode(item.getModuleCode());
|
||||||
|
vo.setModuleName(item.getModuleName());
|
||||||
|
vo.setMenuCode(item.getMenuCode());
|
||||||
|
vo.setMenuName(item.getMenuName());
|
||||||
|
vo.setSectionName(item.getSectionName());
|
||||||
|
vo.setFieldCode(item.getFieldCode());
|
||||||
|
vo.setFieldName(item.getFieldName());
|
||||||
|
vo.setDataPoint(pointMap.getOrDefault(item.getFieldCode(), ""));
|
||||||
|
result.add(vo);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int saveSiteMonitorProjectPointMapping(SiteMonitorProjectPointMappingSaveRequest request, String operName) {
|
||||||
|
if (request == null || StringUtils.isBlank(request.getSiteId())) {
|
||||||
|
throw new ServiceException("站点ID不能为空");
|
||||||
|
}
|
||||||
|
String siteId = request.getSiteId();
|
||||||
|
List<EmsSiteMonitorItem> itemList = emsSiteMonitorItemMapper.selectEnabledList();
|
||||||
|
if (itemList == null || itemList.isEmpty()) {
|
||||||
|
throw new ServiceException("单站监控配置项为空,请先初始化 ems_site_monitor_item");
|
||||||
|
}
|
||||||
|
Set<String> fieldCodeSet = itemList.stream().map(EmsSiteMonitorItem::getFieldCode).collect(Collectors.toSet());
|
||||||
|
emsSiteMonitorPointMatchMapper.deleteBySiteId(siteId);
|
||||||
|
|
||||||
|
if (request.getMappings() == null || request.getMappings().isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
List<EmsSiteMonitorPointMatch> saveList = new ArrayList<>();
|
||||||
|
for (SiteMonitorProjectPointMappingVo mapping : request.getMappings()) {
|
||||||
|
if (mapping == null || StringUtils.isBlank(mapping.getFieldCode()) || StringUtils.isBlank(mapping.getDataPoint())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String fieldCode = mapping.getFieldCode().trim();
|
||||||
|
if (!fieldCodeSet.contains(fieldCode)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EmsSiteMonitorPointMatch pointMatch = new EmsSiteMonitorPointMatch();
|
||||||
|
pointMatch.setSiteId(siteId);
|
||||||
|
pointMatch.setFieldCode(fieldCode);
|
||||||
|
pointMatch.setDataPoint(mapping.getDataPoint().trim());
|
||||||
|
pointMatch.setCreateBy(operName);
|
||||||
|
pointMatch.setUpdateBy(operName);
|
||||||
|
saveList.add(pointMatch);
|
||||||
|
}
|
||||||
|
if (saveList.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return emsSiteMonitorPointMatchMapper.insertBatch(saveList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SiteMonitorProjectDisplayVo> getSiteMonitorProjectDisplay(String siteId) {
|
||||||
|
List<SiteMonitorProjectPointMappingVo> mappingList = getSiteMonitorProjectPointMapping(siteId);
|
||||||
|
if (mappingList.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
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> tjbbLatestMap = safeRedisMap(redisCache.getCacheMap(buildSiteMonitorLatestRedisKey(siteId, MODULE_TJBB)));
|
||||||
|
|
||||||
|
List<SiteMonitorProjectDisplayVo> result = new ArrayList<>();
|
||||||
|
for (SiteMonitorProjectPointMappingVo mapping : mappingList) {
|
||||||
|
SiteMonitorProjectDisplayVo vo = new SiteMonitorProjectDisplayVo();
|
||||||
|
BeanUtils.copyProperties(mapping, vo);
|
||||||
|
Object cacheObj = null;
|
||||||
|
if (MODULE_HOME.equals(mapping.getModuleCode())) {
|
||||||
|
cacheObj = homeLatestMap.get(mapping.getFieldCode());
|
||||||
|
} else if (MODULE_SBJK.equals(mapping.getModuleCode())) {
|
||||||
|
cacheObj = sbjkLatestMap.get(mapping.getFieldCode());
|
||||||
|
} else if (MODULE_TJBB.equals(mapping.getModuleCode())) {
|
||||||
|
cacheObj = tjbbLatestMap.get(mapping.getFieldCode());
|
||||||
|
}
|
||||||
|
if (cacheObj != null) {
|
||||||
|
JSONObject snapshot = parseFieldSnapshot(cacheObj);
|
||||||
|
vo.setFieldValue(snapshot.getString("fieldValue"));
|
||||||
|
vo.setValueTime(parseValueTime(snapshot.get("valueTime")));
|
||||||
|
}
|
||||||
|
result.add(vo);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int saveSiteMonitorProjectData(SiteMonitorDataSaveRequest request, String operName) {
|
||||||
|
if (request == null || StringUtils.isBlank(request.getSiteId())) {
|
||||||
|
throw new ServiceException("站点ID不能为空");
|
||||||
|
}
|
||||||
|
if (request.getItems() == null || request.getItems().isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
List<EmsSiteMonitorItem> itemList = emsSiteMonitorItemMapper.selectEnabledList();
|
||||||
|
if (itemList == null || itemList.isEmpty()) {
|
||||||
|
throw new ServiceException("单站监控配置项为空,请先初始化 ems_site_monitor_item");
|
||||||
|
}
|
||||||
|
Set<String> fieldCodeSet = itemList.stream().map(EmsSiteMonitorItem::getFieldCode).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
Map<String, EmsSiteMonitorItem> itemMap = itemList.stream()
|
||||||
|
.collect(Collectors.toMap(EmsSiteMonitorItem::getFieldCode, item -> item, (a, b) -> a));
|
||||||
|
|
||||||
|
Date now = DateUtils.getNowDate();
|
||||||
|
Map<String, JSONObject> homeLatestUpdates = new HashMap<>();
|
||||||
|
Map<String, JSONObject> sbjkLatestUpdates = new HashMap<>();
|
||||||
|
Map<String, JSONObject> tjbbLatestUpdates = new HashMap<>();
|
||||||
|
Map<Date, JSONObject> homeHistoryByMinute = new HashMap<>();
|
||||||
|
Map<Date, JSONObject> sbjkHistoryByMinute = new HashMap<>();
|
||||||
|
Map<Date, JSONObject> tjbbHistoryByMinute = new HashMap<>();
|
||||||
|
for (SiteMonitorDataSaveItemVo item : request.getItems()) {
|
||||||
|
if (item == null || StringUtils.isBlank(item.getFieldCode())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String fieldCode = item.getFieldCode().trim();
|
||||||
|
if (!fieldCodeSet.contains(fieldCode)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EmsSiteMonitorItem itemDef = itemMap.get(fieldCode);
|
||||||
|
if (itemDef == null || StringUtils.isBlank(itemDef.getModuleCode())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Date valueTime = item.getValueTime() == null ? now : item.getValueTime();
|
||||||
|
JSONObject snapshot = buildFieldSnapshot(item.getFieldValue(), valueTime);
|
||||||
|
Date statisMinute = truncateToMinute(valueTime);
|
||||||
|
if (MODULE_HOME.equals(itemDef.getModuleCode())) {
|
||||||
|
homeLatestUpdates.put(fieldCode, snapshot);
|
||||||
|
mergeHistorySnapshot(homeHistoryByMinute, statisMinute, fieldCode, snapshot);
|
||||||
|
} else if (MODULE_SBJK.equals(itemDef.getModuleCode())) {
|
||||||
|
sbjkLatestUpdates.put(fieldCode, snapshot);
|
||||||
|
mergeHistorySnapshot(sbjkHistoryByMinute, statisMinute, fieldCode, snapshot);
|
||||||
|
} else if (MODULE_TJBB.equals(itemDef.getModuleCode())) {
|
||||||
|
tjbbLatestUpdates.put(fieldCode, snapshot);
|
||||||
|
mergeHistorySnapshot(tjbbHistoryByMinute, statisMinute, fieldCode, snapshot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (homeLatestUpdates.isEmpty() && sbjkLatestUpdates.isEmpty() && tjbbLatestUpdates.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int rows = 0;
|
||||||
|
if (!homeLatestUpdates.isEmpty()) {
|
||||||
|
upsertLatestToRedis(request.getSiteId(), MODULE_HOME, homeLatestUpdates);
|
||||||
|
rows += upsertHistoryByMinute(HISTORY_TABLE_HOME, request.getSiteId(), homeHistoryByMinute, operName);
|
||||||
|
}
|
||||||
|
if (!sbjkLatestUpdates.isEmpty()) {
|
||||||
|
upsertLatestToRedis(request.getSiteId(), MODULE_SBJK, sbjkLatestUpdates);
|
||||||
|
rows += upsertHistoryByMinute(HISTORY_TABLE_SBJK, request.getSiteId(), sbjkHistoryByMinute, operName);
|
||||||
|
}
|
||||||
|
if (!tjbbLatestUpdates.isEmpty()) {
|
||||||
|
upsertLatestToRedis(request.getSiteId(), MODULE_TJBB, tjbbLatestUpdates);
|
||||||
|
rows += upsertHistoryByMinute(HISTORY_TABLE_TJBB, request.getSiteId(), tjbbHistoryByMinute, operName);
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int syncSiteMonitorDataByMqtt(String siteId, String deviceId, String jsonData, Date valueTime) {
|
||||||
|
if (StringUtils.isAnyBlank(siteId, jsonData)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Map<String, Object> dataMap = JSON.parseObject(jsonData, new TypeReference<Map<String, Object>>() {});
|
||||||
|
if (dataMap == null || dataMap.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Map<String, Object> upperDataMap = new HashMap<>();
|
||||||
|
dataMap.forEach((k, v) -> {
|
||||||
|
if (StringUtils.isNotBlank(k)) {
|
||||||
|
upperDataMap.put(k.toUpperCase(), v);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
List<EmsSiteMonitorPointMatch> mappingList = emsSiteMonitorPointMatchMapper.selectBySiteId(siteId);
|
||||||
|
if (mappingList == null || mappingList.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
List<EmsSiteMonitorItem> itemList = emsSiteMonitorItemMapper.selectEnabledList();
|
||||||
|
if (itemList == null || itemList.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Map<String, EmsSiteMonitorItem> itemMap = itemList.stream()
|
||||||
|
.filter(item -> StringUtils.isNotBlank(item.getFieldCode()))
|
||||||
|
.collect(Collectors.toMap(EmsSiteMonitorItem::getFieldCode, item -> item, (a, b) -> a));
|
||||||
|
|
||||||
|
Date actualValueTime = valueTime == null ? DateUtils.getNowDate() : valueTime;
|
||||||
|
Date statisMinute = truncateToMinute(actualValueTime);
|
||||||
|
Map<String, JSONObject> homeLatestUpdates = new HashMap<>();
|
||||||
|
Map<String, JSONObject> sbjkLatestUpdates = new HashMap<>();
|
||||||
|
Map<String, JSONObject> tjbbLatestUpdates = new HashMap<>();
|
||||||
|
Map<Date, JSONObject> homeHistoryByMinute = new HashMap<>();
|
||||||
|
Map<Date, JSONObject> sbjkHistoryByMinute = new HashMap<>();
|
||||||
|
Map<Date, JSONObject> tjbbHistoryByMinute = new HashMap<>();
|
||||||
|
|
||||||
|
for (EmsSiteMonitorPointMatch mapping : mappingList) {
|
||||||
|
if (mapping == null || StringUtils.isAnyBlank(mapping.getFieldCode(), mapping.getDataPoint())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EmsSiteMonitorItem itemDef = itemMap.get(mapping.getFieldCode());
|
||||||
|
if (itemDef == null || StringUtils.isBlank(itemDef.getModuleCode())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String point = mapping.getDataPoint().trim();
|
||||||
|
Object value = upperDataMap.get(point.toUpperCase());
|
||||||
|
if (value == null && StringUtils.isNotBlank(deviceId)) {
|
||||||
|
value = upperDataMap.get((deviceId + point).toUpperCase());
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject snapshot = buildFieldSnapshot(String.valueOf(value), actualValueTime);
|
||||||
|
|
||||||
|
if (MODULE_HOME.equals(itemDef.getModuleCode())) {
|
||||||
|
homeLatestUpdates.put(mapping.getFieldCode(), snapshot);
|
||||||
|
mergeHistorySnapshot(homeHistoryByMinute, statisMinute, mapping.getFieldCode(), snapshot);
|
||||||
|
} else if (MODULE_SBJK.equals(itemDef.getModuleCode())) {
|
||||||
|
sbjkLatestUpdates.put(mapping.getFieldCode(), snapshot);
|
||||||
|
mergeHistorySnapshot(sbjkHistoryByMinute, statisMinute, mapping.getFieldCode(), snapshot);
|
||||||
|
} else if (MODULE_TJBB.equals(itemDef.getModuleCode())) {
|
||||||
|
tjbbLatestUpdates.put(mapping.getFieldCode(), snapshot);
|
||||||
|
mergeHistorySnapshot(tjbbHistoryByMinute, statisMinute, mapping.getFieldCode(), snapshot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rows = 0;
|
||||||
|
if (!homeLatestUpdates.isEmpty()) {
|
||||||
|
upsertLatestToRedis(siteId, MODULE_HOME, homeLatestUpdates);
|
||||||
|
rows += upsertHistoryByMinute(HISTORY_TABLE_HOME, siteId, homeHistoryByMinute, "mqtt");
|
||||||
|
}
|
||||||
|
if (!sbjkLatestUpdates.isEmpty()) {
|
||||||
|
upsertLatestToRedis(siteId, MODULE_SBJK, sbjkLatestUpdates);
|
||||||
|
rows += upsertHistoryByMinute(HISTORY_TABLE_SBJK, siteId, sbjkHistoryByMinute, "mqtt");
|
||||||
|
}
|
||||||
|
if (!tjbbLatestUpdates.isEmpty()) {
|
||||||
|
upsertLatestToRedis(siteId, MODULE_TJBB, tjbbLatestUpdates);
|
||||||
|
rows += upsertHistoryByMinute(HISTORY_TABLE_TJBB, siteId, tjbbHistoryByMinute, "mqtt");
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int upsertHistoryByMinute(String tableName, String siteId, Map<Date, JSONObject> minuteSnapshotMap, String operName) {
|
||||||
|
int rows = 0;
|
||||||
|
for (Map.Entry<Date, JSONObject> entry : minuteSnapshotMap.entrySet()) {
|
||||||
|
Date statisMinute = entry.getKey();
|
||||||
|
JSONObject merged = mergeHistoryRecord(tableName, siteId, statisMinute, entry.getValue());
|
||||||
|
rows += emsSiteMonitorDataMapper.upsertHistoryJsonByMinute(
|
||||||
|
tableName,
|
||||||
|
siteId,
|
||||||
|
statisMinute,
|
||||||
|
merged.toJSONString(),
|
||||||
|
operName
|
||||||
|
);
|
||||||
|
Map<String, String> hotColumns = extractHotColumns(merged);
|
||||||
|
rows += emsSiteMonitorDataMapper.updateHistoryHotColumns(
|
||||||
|
tableName,
|
||||||
|
siteId,
|
||||||
|
statisMinute,
|
||||||
|
hotColumns.get("hotSoc"),
|
||||||
|
hotColumns.get("hotTotalActivePower"),
|
||||||
|
hotColumns.get("hotTotalReactivePower"),
|
||||||
|
hotColumns.get("hotDayChargedCap"),
|
||||||
|
hotColumns.get("hotDayDisChargedCap"),
|
||||||
|
operName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject mergeHistoryRecord(String tableName, String siteId, Date statisMinute, JSONObject updates) {
|
||||||
|
String existingJson = emsSiteMonitorDataMapper.selectHistoryJsonByMinute(tableName, siteId, statisMinute);
|
||||||
|
JSONObject merged = StringUtils.isBlank(existingJson) ? new JSONObject() : JSON.parseObject(existingJson);
|
||||||
|
if (merged == null) {
|
||||||
|
merged = new JSONObject();
|
||||||
|
}
|
||||||
|
if (updates != null) {
|
||||||
|
merged.putAll(updates);
|
||||||
|
}
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void upsertLatestToRedis(String siteId, String moduleCode, Map<String, JSONObject> latestUpdates) {
|
||||||
|
if (latestUpdates == null || latestUpdates.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String redisKey = buildSiteMonitorLatestRedisKey(siteId, moduleCode);
|
||||||
|
Map<String, String> redisMap = new HashMap<>();
|
||||||
|
latestUpdates.forEach((fieldCode, snapshot) -> redisMap.put(fieldCode, snapshot.toJSONString()));
|
||||||
|
redisCache.setAllCacheMapValue(redisKey, redisMap);
|
||||||
|
redisCache.expire(redisKey, 7, TimeUnit.DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mergeHistorySnapshot(Map<Date, JSONObject> historyByMinute, Date statisMinute, String fieldCode, JSONObject snapshot) {
|
||||||
|
JSONObject minuteObj = historyByMinute.computeIfAbsent(statisMinute, k -> new JSONObject());
|
||||||
|
minuteObj.put(fieldCode, snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> safeRedisMap(Map<String, Object> source) {
|
||||||
|
return source == null ? new HashMap<>() : source;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> extractHotColumns(JSONObject merged) {
|
||||||
|
Map<String, String> result = new HashMap<>();
|
||||||
|
result.put("hotSoc", extractFieldValue(merged,
|
||||||
|
new String[]{"SBJK_SSYX__soc", "TJBB_DCDQX__soc_stat", "HOME__avgSoc"},
|
||||||
|
new String[]{"__soc", "__soc_stat", "__avgSoc"}));
|
||||||
|
result.put("hotTotalActivePower", extractFieldValue(merged,
|
||||||
|
new String[]{"SBJK_SSYX__totalActivePower"},
|
||||||
|
new String[]{"__totalActivePower", "__activePower", "__activePower_stat"}));
|
||||||
|
result.put("hotTotalReactivePower", extractFieldValue(merged,
|
||||||
|
new String[]{"SBJK_SSYX__totalReactivePower"},
|
||||||
|
new String[]{"__totalReactivePower", "__reactivePower", "__reactivePower_stat"}));
|
||||||
|
result.put("hotDayChargedCap", extractFieldValue(merged,
|
||||||
|
new String[]{"HOME__dayChargedCap", "SBJK_SSYX__dayChargedCap_rt", "TJBB_GLTJ__chargedCap_stat"},
|
||||||
|
new String[]{"__dayChargedCap", "__dayChargedCap_rt", "__chargedCap_stat"}));
|
||||||
|
result.put("hotDayDisChargedCap", extractFieldValue(merged,
|
||||||
|
new String[]{"HOME__dayDisChargedCap", "SBJK_SSYX__dayDisChargedCap_rt", "TJBB_GLTJ__disChargedCap_stat"},
|
||||||
|
new String[]{"__dayDisChargedCap", "__dayDisChargedCap_rt", "__disChargedCap_stat"}));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractFieldValue(JSONObject merged, String[] exactKeys, String[] suffixKeys) {
|
||||||
|
if (merged == null || merged.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (exactKeys != null) {
|
||||||
|
for (String key : exactKeys) {
|
||||||
|
String value = getSnapshotFieldValue(merged.get(key));
|
||||||
|
if (StringUtils.isNotBlank(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (suffixKeys != null) {
|
||||||
|
for (Map.Entry<String, Object> entry : merged.entrySet()) {
|
||||||
|
String fieldCode = entry.getKey();
|
||||||
|
if (StringUtils.isBlank(fieldCode)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (String suffix : suffixKeys) {
|
||||||
|
if (StringUtils.isNotBlank(suffix) && fieldCode.endsWith(suffix)) {
|
||||||
|
String value = getSnapshotFieldValue(entry.getValue());
|
||||||
|
if (StringUtils.isNotBlank(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSnapshotFieldValue(Object snapshotObj) {
|
||||||
|
if (snapshotObj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (snapshotObj instanceof JSONObject) {
|
||||||
|
return ((JSONObject) snapshotObj).getString("fieldValue");
|
||||||
|
}
|
||||||
|
if (snapshotObj instanceof Map) {
|
||||||
|
Object val = ((Map<?, ?>) snapshotObj).get("fieldValue");
|
||||||
|
return val == null ? null : String.valueOf(val);
|
||||||
|
}
|
||||||
|
return String.valueOf(snapshotObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject buildFieldSnapshot(String fieldValue, Date valueTime) {
|
||||||
|
JSONObject snapshot = new JSONObject();
|
||||||
|
snapshot.put("fieldValue", fieldValue);
|
||||||
|
snapshot.put("valueTime", valueTime == null ? null : valueTime.getTime());
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject parseFieldSnapshot(Object cacheObj) {
|
||||||
|
if (cacheObj == null) {
|
||||||
|
return new JSONObject();
|
||||||
|
}
|
||||||
|
if (cacheObj instanceof JSONObject) {
|
||||||
|
return (JSONObject) cacheObj;
|
||||||
|
}
|
||||||
|
if (cacheObj instanceof Map) {
|
||||||
|
return new JSONObject((Map) cacheObj);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
JSONObject snapshot = JSON.parseObject(String.valueOf(cacheObj));
|
||||||
|
return snapshot == null ? new JSONObject() : snapshot;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new JSONObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date parseValueTime(Object valueTimeObj) {
|
||||||
|
if (valueTimeObj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (valueTimeObj instanceof Date) {
|
||||||
|
return (Date) valueTimeObj;
|
||||||
|
}
|
||||||
|
if (valueTimeObj instanceof Number) {
|
||||||
|
return new Date(((Number) valueTimeObj).longValue());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return DateUtils.parseDate(valueTimeObj.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date truncateToMinute(Date date) {
|
||||||
|
Date source = date == null ? DateUtils.getNowDate() : date;
|
||||||
|
long millis = source.getTime();
|
||||||
|
long minuteMillis = 60_000L;
|
||||||
|
return new Date((millis / minuteMillis) * minuteMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildSiteMonitorLatestRedisKey(String siteId, String moduleCode) {
|
||||||
|
return RedisKeyConstants.SITE_MONITOR_LATEST + siteId + "_" + moduleCode;
|
||||||
|
}
|
||||||
|
|
||||||
// 辅助方法:根据值查找对应的对象(用于比较器中获取完整对象)
|
// 辅助方法:根据值查找对应的对象(用于比较器中获取完整对象)
|
||||||
private PointQueryResponse findByValue(List<PointQueryResponse> list, Object value) {
|
private PointQueryResponse findByValue(List<PointQueryResponse> list, Object value) {
|
||||||
return list.stream()
|
return list.stream()
|
||||||
|
|||||||
@ -0,0 +1,668 @@
|
|||||||
|
package com.xzzn.ems.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.xzzn.common.exception.ServiceException;
|
||||||
|
import com.xzzn.common.constant.RedisKeyConstants;
|
||||||
|
import com.xzzn.common.core.redis.RedisCache;
|
||||||
|
import com.xzzn.common.utils.DateUtils;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsPointConfig;
|
||||||
|
import com.xzzn.ems.domain.vo.ImportPointTemplateRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.PointConfigCurveRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.PointConfigCurveValueVo;
|
||||||
|
import com.xzzn.ems.domain.vo.PointConfigLatestValueItemVo;
|
||||||
|
import com.xzzn.ems.domain.vo.PointConfigLatestValueRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.PointConfigLatestValueVo;
|
||||||
|
import com.xzzn.ems.mapper.EmsPointConfigMapper;
|
||||||
|
import com.xzzn.ems.service.IEmsPointConfigService;
|
||||||
|
import com.xzzn.ems.service.InfluxPointDataWriter;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
|
||||||
|
private static final String TEMPLATE_SITE_ID = "DEFAULT";
|
||||||
|
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 DECIMAL_PATTERN = Pattern.compile("^-?\\d+(\\.\\d+)?$");
|
||||||
|
private static final Pattern CALC_EXPRESSION_PATTERN = Pattern.compile("^[0-9A-Za-z_+\\-*/().\\s]+$");
|
||||||
|
private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EmsPointConfigMapper emsPointConfigMapper;
|
||||||
|
@Autowired
|
||||||
|
private RedisCache redisCache;
|
||||||
|
@Autowired
|
||||||
|
private InfluxPointDataWriter influxPointDataWriter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<EmsPointConfig> selectPointConfigList(EmsPointConfig pointConfig) {
|
||||||
|
return emsPointConfigMapper.selectEmsPointConfigList(pointConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EmsPointConfig selectPointConfigById(Long id) {
|
||||||
|
return emsPointConfigMapper.selectEmsPointConfigById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertPointConfig(EmsPointConfig pointConfig, String operName) {
|
||||||
|
if (pointConfig == null || StringUtils.isBlank(pointConfig.getSiteId())) {
|
||||||
|
throw new ServiceException("站点ID不能为空");
|
||||||
|
}
|
||||||
|
normalizeAndValidatePointConfig(pointConfig);
|
||||||
|
pointConfig.setCreateBy(operName);
|
||||||
|
pointConfig.setUpdateBy(operName);
|
||||||
|
int rows = emsPointConfigMapper.insertEmsPointConfig(pointConfig);
|
||||||
|
if (rows > 0) {
|
||||||
|
invalidatePointConfigCache(pointConfig.getSiteId(), pointConfig.getDeviceId());
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updatePointConfig(EmsPointConfig pointConfig, String operName) {
|
||||||
|
EmsPointConfig oldConfig = pointConfig.getId() == null ? null : emsPointConfigMapper.selectEmsPointConfigById(pointConfig.getId());
|
||||||
|
normalizeAndValidatePointConfig(pointConfig);
|
||||||
|
pointConfig.setUpdateBy(operName);
|
||||||
|
int rows = emsPointConfigMapper.updateEmsPointConfig(pointConfig);
|
||||||
|
if (rows > 0) {
|
||||||
|
if (oldConfig != null) {
|
||||||
|
invalidatePointConfigCache(oldConfig.getSiteId(), oldConfig.getDeviceId());
|
||||||
|
}
|
||||||
|
invalidatePointConfigCache(pointConfig.getSiteId(), pointConfig.getDeviceId());
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deletePointConfigByIds(Long[] ids) {
|
||||||
|
if (ids != null) {
|
||||||
|
for (Long id : ids) {
|
||||||
|
EmsPointConfig oldConfig = emsPointConfigMapper.selectEmsPointConfigById(id);
|
||||||
|
if (oldConfig != null) {
|
||||||
|
invalidatePointConfigCache(oldConfig.getSiteId(), oldConfig.getDeviceId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return emsPointConfigMapper.deleteEmsPointConfigByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public String importTemplateBySite(ImportPointTemplateRequest request, String operName) {
|
||||||
|
String targetSiteId = request.getSiteId();
|
||||||
|
if (StringUtils.isBlank(targetSiteId)) {
|
||||||
|
throw new ServiceException("站点ID不能为空");
|
||||||
|
}
|
||||||
|
if (TEMPLATE_SITE_ID.equals(targetSiteId)) {
|
||||||
|
throw new ServiceException("模板站点不支持作为导入目标站点");
|
||||||
|
}
|
||||||
|
|
||||||
|
int templateCount = emsPointConfigMapper.countBySiteId(TEMPLATE_SITE_ID);
|
||||||
|
if (templateCount <= 0) {
|
||||||
|
throw new ServiceException("模板点位配置不存在,无法导入");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean overwrite = Boolean.TRUE.equals(request.getOverwrite());
|
||||||
|
int targetCount = emsPointConfigMapper.countBySiteId(targetSiteId);
|
||||||
|
if (targetCount > 0 && !overwrite) {
|
||||||
|
throw new ServiceException("目标站点已存在点位配置,请勾选“覆盖已存在数据”后重试");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetCount > 0) {
|
||||||
|
emsPointConfigMapper.deleteBySiteId(targetSiteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int importCount = emsPointConfigMapper.copyTemplateToSite(TEMPLATE_SITE_ID, targetSiteId, operName);
|
||||||
|
invalidatePointConfigCacheBySite(targetSiteId);
|
||||||
|
return String.format("导入成功:站点 %s,点位 %d 条", targetSiteId, importCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public String importCsvBySite(String siteId, Boolean overwrite, MultipartFile file, String operName) {
|
||||||
|
if (StringUtils.isBlank(siteId)) {
|
||||||
|
throw new ServiceException("站点ID不能为空");
|
||||||
|
}
|
||||||
|
if (!DB_NAME_PATTERN.matcher(siteId).matches()) {
|
||||||
|
throw new ServiceException(String.format("站点ID不合法(siteId=%s)", siteId));
|
||||||
|
}
|
||||||
|
if (TEMPLATE_SITE_ID.equals(siteId)) {
|
||||||
|
throw new ServiceException("模板站点不支持作为导入目标站点");
|
||||||
|
}
|
||||||
|
if (file == null || file.isEmpty()) {
|
||||||
|
throw new ServiceException("请上传CSV文件");
|
||||||
|
}
|
||||||
|
if (!StringUtils.endsWithIgnoreCase(file.getOriginalFilename(), ".csv")) {
|
||||||
|
throw new ServiceException("仅支持上传CSV文件");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean overwriteFlag = Boolean.TRUE.equals(overwrite);
|
||||||
|
int targetCount = emsPointConfigMapper.countBySiteId(siteId);
|
||||||
|
if (targetCount > 0 && !overwriteFlag) {
|
||||||
|
throw new ServiceException("目标站点已存在点位配置,请勾选“覆盖已存在点位数据”后重试");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<EmsPointConfig> pointConfigList = parseCsv(file, siteId);
|
||||||
|
if (pointConfigList.isEmpty()) {
|
||||||
|
throw new ServiceException("CSV没有可导入的数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetCount > 0) {
|
||||||
|
emsPointConfigMapper.deleteBySiteId(siteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int importCount = 0;
|
||||||
|
for (EmsPointConfig pointConfig : pointConfigList) {
|
||||||
|
pointConfig.setCreateBy(operName);
|
||||||
|
pointConfig.setUpdateBy(operName);
|
||||||
|
importCount += emsPointConfigMapper.insertEmsPointConfig(pointConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidatePointConfigCacheBySite(siteId);
|
||||||
|
return String.format("导入成功:站点 %s,点位 %d 条", siteId, importCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRegisterAddress(String siteId, String deviceCategory, String deviceId, String dataKey) {
|
||||||
|
if (StringUtils.isAnyBlank(siteId, deviceCategory, deviceId, dataKey)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return emsPointConfigMapper.getRegisterAddress(siteId, deviceCategory, deviceId, dataKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PointConfigLatestValueVo> getLatestValues(PointConfigLatestValueRequest request) {
|
||||||
|
List<PointConfigLatestValueVo> result = new ArrayList<>();
|
||||||
|
if (request == null || request.getPoints() == null || request.getPoints().isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Map<String, EmsPointConfig>> configMapCache = new HashMap<>();
|
||||||
|
for (PointConfigLatestValueItemVo item : request.getPoints()) {
|
||||||
|
if (item == null || StringUtils.isAnyBlank(item.getSiteId(), item.getDeviceId(), item.getDataKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PointConfigLatestValueVo latestValue = queryLatestValueFromRedis(item, configMapCache);
|
||||||
|
result.add(latestValue);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PointConfigCurveValueVo> getCurveData(PointConfigCurveRequest request) {
|
||||||
|
if (request == null || StringUtils.isAnyBlank(request.getSiteId(), request.getDeviceId(), request.getDataKey())) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
String siteId = StringUtils.trim(request.getSiteId());
|
||||||
|
String deviceId = StringUtils.trim(request.getDeviceId());
|
||||||
|
String dataKey = StringUtils.trim(request.getDataKey());
|
||||||
|
if (StringUtils.isAnyBlank(siteId, deviceId, dataKey)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
Date[] range = resolveTimeRange(request);
|
||||||
|
return queryCurveDataFromInflux(siteId, deviceId, dataKey, range[0], range[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PointConfigLatestValueVo queryLatestValueFromRedis(PointConfigLatestValueItemVo item,
|
||||||
|
Map<String, Map<String, EmsPointConfig>> configMapCache) {
|
||||||
|
PointConfigLatestValueVo vo = new PointConfigLatestValueVo();
|
||||||
|
vo.setSiteId(item.getSiteId());
|
||||||
|
vo.setDeviceId(item.getDeviceId());
|
||||||
|
vo.setDataKey(item.getDataKey());
|
||||||
|
|
||||||
|
String redisKey = RedisKeyConstants.ORIGINAL_MQTT_DATA + item.getSiteId() + "_" + item.getDeviceId();
|
||||||
|
Object raw = redisCache.getCacheObject(redisKey);
|
||||||
|
if (raw == null) {
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject root = toJsonObject(raw);
|
||||||
|
if (root == null) {
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
JSONObject dataObject = extractDataObject(root);
|
||||||
|
if (dataObject == null) {
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object rawValue = getValueIgnoreCase(dataObject, item.getDataKey());
|
||||||
|
BigDecimal pointValue = StringUtils.getBigDecimal(rawValue);
|
||||||
|
if (pointValue != null) {
|
||||||
|
EmsPointConfig pointConfig = getPointConfig(item.getSiteId(), item.getDeviceId(), item.getDataKey(), configMapCache);
|
||||||
|
vo.setPointValue(convertPointValue(pointValue, pointConfig));
|
||||||
|
}
|
||||||
|
vo.setDataTime(extractDataTime(root));
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PointConfigCurveValueVo> queryCurveDataFromInflux(String siteId, String deviceId, String dataKey, Date startTime, Date endTime) {
|
||||||
|
List<InfluxPointDataWriter.PointValue> values = influxPointDataWriter.queryCurveData(siteId, deviceId, dataKey, startTime, endTime);
|
||||||
|
if (values == null || values.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return values.stream().map(value -> {
|
||||||
|
PointConfigCurveValueVo vo = new PointConfigCurveValueVo();
|
||||||
|
vo.setDataTime(value.getDataTime());
|
||||||
|
vo.setPointValue(value.getPointValue());
|
||||||
|
return vo;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date[] resolveTimeRange(PointConfigCurveRequest request) {
|
||||||
|
LocalDateTime end = LocalDateTime.now();
|
||||||
|
String rangeType = StringUtils.defaultIfBlank(request.getRangeType(), "day").toLowerCase(Locale.ROOT);
|
||||||
|
LocalDateTime start;
|
||||||
|
if ("custom".equals(rangeType)) {
|
||||||
|
if (StringUtils.isAnyBlank(request.getStartTime(), request.getEndTime())) {
|
||||||
|
throw new ServiceException("自定义时间范围必须传入开始时间和结束时间");
|
||||||
|
}
|
||||||
|
start = parseDateTime(request.getStartTime());
|
||||||
|
end = parseDateTime(request.getEndTime());
|
||||||
|
} else if ("week".equals(rangeType)) {
|
||||||
|
start = end.minusDays(7);
|
||||||
|
} else if ("month".equals(rangeType)) {
|
||||||
|
start = end.minusDays(30);
|
||||||
|
} else {
|
||||||
|
start = end.minusDays(1);
|
||||||
|
}
|
||||||
|
if (start.isAfter(end)) {
|
||||||
|
throw new ServiceException("开始时间不能晚于结束时间");
|
||||||
|
}
|
||||||
|
return new Date[]{
|
||||||
|
Timestamp.valueOf(start),
|
||||||
|
Timestamp.valueOf(end)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalDateTime parseDateTime(String value) {
|
||||||
|
try {
|
||||||
|
return LocalDateTime.parse(value, DATETIME_FORMATTER);
|
||||||
|
} catch (DateTimeParseException ex) {
|
||||||
|
throw new ServiceException("时间格式错误,请使用 yyyy-MM-dd HH:mm:ss");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invalidatePointConfigCache(String siteId, String deviceId) {
|
||||||
|
if (StringUtils.isAnyBlank(siteId, deviceId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
redisCache.deleteObject(RedisKeyConstants.POINT_CONFIG_DEVICE + siteId + "_" + deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invalidatePointConfigCacheBySite(String siteId) {
|
||||||
|
if (StringUtils.isBlank(siteId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Collection<String> keys = redisCache.keys(RedisKeyConstants.POINT_CONFIG_DEVICE + siteId + "_*");
|
||||||
|
if (keys != null && !keys.isEmpty()) {
|
||||||
|
redisCache.deleteObject(keys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Date extractDataTime(JSONObject root) {
|
||||||
|
if (root == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Long timestamp = root.getLong("timestamp");
|
||||||
|
if (timestamp != null) {
|
||||||
|
return DateUtils.convertUpdateTime(timestamp);
|
||||||
|
}
|
||||||
|
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 EmsPointConfig getPointConfig(String siteId,
|
||||||
|
String deviceId,
|
||||||
|
String dataKey,
|
||||||
|
Map<String, Map<String, EmsPointConfig>> configMapCache) {
|
||||||
|
if (StringUtils.isAnyBlank(siteId, deviceId, dataKey)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String cacheKey = siteId + "|" + deviceId;
|
||||||
|
Map<String, EmsPointConfig> configByKey = configMapCache.get(cacheKey);
|
||||||
|
if (configByKey == null) {
|
||||||
|
EmsPointConfig query = new EmsPointConfig();
|
||||||
|
query.setSiteId(siteId);
|
||||||
|
query.setDeviceId(deviceId);
|
||||||
|
List<EmsPointConfig> configList = emsPointConfigMapper.selectEmsPointConfigList(query);
|
||||||
|
configByKey = new HashMap<>();
|
||||||
|
if (configList != null) {
|
||||||
|
for (EmsPointConfig config : configList) {
|
||||||
|
if (config != null && StringUtils.isNotBlank(config.getDataKey())) {
|
||||||
|
configByKey.put(config.getDataKey().toUpperCase(Locale.ROOT), config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configMapCache.put(cacheKey, configByKey);
|
||||||
|
}
|
||||||
|
return configByKey.get(dataKey.toUpperCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 List<EmsPointConfig> parseCsv(MultipartFile file, String siteId) {
|
||||||
|
List<EmsPointConfig> result = new ArrayList<>();
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8))) {
|
||||||
|
String headerLine = reader.readLine();
|
||||||
|
if (StringUtils.isBlank(headerLine)) {
|
||||||
|
throw new ServiceException("CSV表头不能为空");
|
||||||
|
}
|
||||||
|
List<String> headerList = parseCsvLine(removeUtf8Bom(headerLine));
|
||||||
|
Map<String, Integer> headerIndex = buildHeaderIndex(headerList);
|
||||||
|
assertRequiredHeader(headerIndex, "device_category", "device_category");
|
||||||
|
assertRequiredHeader(headerIndex, "device_id", "device_id");
|
||||||
|
assertRequiredHeader(headerIndex, "data_key", "data_key");
|
||||||
|
assertRequiredHeader(headerIndex, "point_desc", "point_desc");
|
||||||
|
|
||||||
|
String line;
|
||||||
|
int lineNo = 1;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
lineNo++;
|
||||||
|
if (StringUtils.isBlank(line)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<String> valueList = parseCsvLine(line);
|
||||||
|
EmsPointConfig pointConfig = new EmsPointConfig();
|
||||||
|
pointConfig.setSiteId(siteId);
|
||||||
|
pointConfig.setDeviceCategory(getRequiredString(valueList, headerIndex, "device_category", lineNo));
|
||||||
|
pointConfig.setDeviceId(getRequiredString(valueList, headerIndex, "device_id", lineNo));
|
||||||
|
pointConfig.setDataKey(getRequiredString(valueList, headerIndex, "data_key", lineNo));
|
||||||
|
pointConfig.setPointDesc(getRequiredString(valueList, headerIndex, "point_desc", lineNo));
|
||||||
|
String registerAddress = getString(valueList, headerIndex, "register_address");
|
||||||
|
pointConfig.setRegisterAddress(StringUtils.isBlank(registerAddress) ? "" : registerAddress);
|
||||||
|
pointConfig.setPointName(getString(valueList, headerIndex, "point_name"));
|
||||||
|
pointConfig.setDataUnit(getString(valueList, headerIndex, "data_unit"));
|
||||||
|
pointConfig.setDataA(getDecimal(valueList, headerIndex, "data_a", lineNo));
|
||||||
|
pointConfig.setDataK(getDecimal(valueList, headerIndex, "data_k", lineNo));
|
||||||
|
pointConfig.setDataB(getDecimal(valueList, headerIndex, "data_b", lineNo));
|
||||||
|
pointConfig.setDataBit(getInteger(valueList, headerIndex, "data_bit", lineNo));
|
||||||
|
pointConfig.setIsAlarm(getInteger(valueList, headerIndex, "is_alarm", lineNo));
|
||||||
|
pointConfig.setPointType(getString(valueList, headerIndex, "point_type"));
|
||||||
|
pointConfig.setCalcExpression(getString(valueList, headerIndex, "calc_expression"));
|
||||||
|
pointConfig.setRemark(getString(valueList, headerIndex, "remark"));
|
||||||
|
normalizeAndValidatePointConfig(pointConfig);
|
||||||
|
result.add(pointConfig);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ServiceException("CSV读取失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertRequiredHeader(Map<String, Integer> headerIndex, String headerKey, String headerName) {
|
||||||
|
if (!headerIndex.containsKey(headerKey)) {
|
||||||
|
throw new ServiceException("CSV缺少必填列: " + headerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Integer> buildHeaderIndex(List<String> headerList) {
|
||||||
|
Map<String, Integer> headerIndex = new HashMap<>();
|
||||||
|
for (int i = 0; i < headerList.size(); i++) {
|
||||||
|
String normalizedHeader = toCanonicalHeaderKey(headerList.get(i));
|
||||||
|
if (StringUtils.isBlank(normalizedHeader)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
headerIndex.putIfAbsent(normalizedHeader, i);
|
||||||
|
}
|
||||||
|
return headerIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getRequiredString(List<String> valueList, Map<String, Integer> headerIndex, String key, int lineNo) {
|
||||||
|
String value = getString(valueList, headerIndex, key);
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
throw new ServiceException(String.format("CSV第%d行字段[%s]不能为空", lineNo, key));
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getString(List<String> valueList, Map<String, Integer> headerIndex, String key) {
|
||||||
|
Integer index = headerIndex.get(key);
|
||||||
|
if (index == null || index < 0 || index >= valueList.size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String value = valueList.get(index);
|
||||||
|
return StringUtils.isBlank(value) ? null : value.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer getInteger(List<String> valueList, Map<String, Integer> headerIndex, String key, int lineNo) {
|
||||||
|
String value = getString(valueList, headerIndex, key);
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!INTEGER_PATTERN.matcher(value).matches()) {
|
||||||
|
throw new ServiceException(String.format("CSV第%d行字段[%s]必须是整数", lineNo, key));
|
||||||
|
}
|
||||||
|
return Integer.parseInt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal getDecimal(List<String> valueList, Map<String, Integer> headerIndex, String key, int lineNo) {
|
||||||
|
String value = getString(valueList, headerIndex, key);
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!DECIMAL_PATTERN.matcher(value).matches()) {
|
||||||
|
throw new ServiceException(String.format("CSV第%d行字段[%s]必须是数字", lineNo, key));
|
||||||
|
}
|
||||||
|
return new BigDecimal(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String removeUtf8Bom(String content) {
|
||||||
|
if (StringUtils.isBlank(content)) {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
if (content.charAt(0) == '\ufeff') {
|
||||||
|
return content.substring(1);
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeHeader(String header) {
|
||||||
|
if (header == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return header.trim().toLowerCase().replace("-", "_").replace(" ", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toCanonicalHeaderKey(String header) {
|
||||||
|
String normalized = normalizeHeader(header);
|
||||||
|
if (StringUtils.isBlank(normalized)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String compact = normalized.replace("_", "");
|
||||||
|
switch (compact) {
|
||||||
|
case "siteid":
|
||||||
|
case "站点id":
|
||||||
|
return "site_id";
|
||||||
|
case "devicecategory":
|
||||||
|
case "设备类型":
|
||||||
|
return "device_category";
|
||||||
|
case "deviceid":
|
||||||
|
case "设备id":
|
||||||
|
return "device_id";
|
||||||
|
case "pointname":
|
||||||
|
case "点位名称":
|
||||||
|
return "point_name";
|
||||||
|
case "datakey":
|
||||||
|
case "数据键":
|
||||||
|
return "data_key";
|
||||||
|
case "pointdesc":
|
||||||
|
case "点位描述":
|
||||||
|
return "point_desc";
|
||||||
|
case "registeraddress":
|
||||||
|
case "寄存器地址":
|
||||||
|
return "register_address";
|
||||||
|
case "dataunit":
|
||||||
|
case "datounit":
|
||||||
|
case "单位":
|
||||||
|
return "data_unit";
|
||||||
|
case "dataa":
|
||||||
|
case "datoa":
|
||||||
|
case "a系数":
|
||||||
|
return "data_a";
|
||||||
|
case "datak":
|
||||||
|
case "datok":
|
||||||
|
case "k系数":
|
||||||
|
return "data_k";
|
||||||
|
case "datab":
|
||||||
|
case "datob":
|
||||||
|
case "b系数":
|
||||||
|
return "data_b";
|
||||||
|
case "databit":
|
||||||
|
case "datobit":
|
||||||
|
case "位偏移":
|
||||||
|
return "data_bit";
|
||||||
|
case "isalarm":
|
||||||
|
case "报警点位":
|
||||||
|
return "is_alarm";
|
||||||
|
case "pointtype":
|
||||||
|
case "点位类型":
|
||||||
|
return "point_type";
|
||||||
|
case "calcexpression":
|
||||||
|
case "计算表达式":
|
||||||
|
return "calc_expression";
|
||||||
|
case "remark":
|
||||||
|
case "备注":
|
||||||
|
return "remark";
|
||||||
|
default:
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> parseCsvLine(String line) {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
if (line == null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
StringBuilder current = new StringBuilder();
|
||||||
|
boolean inQuotes = false;
|
||||||
|
for (int i = 0; i < line.length(); i++) {
|
||||||
|
char c = line.charAt(i);
|
||||||
|
if (c == '"') {
|
||||||
|
if (inQuotes && i + 1 < line.length() && line.charAt(i + 1) == '"') {
|
||||||
|
current.append('"');
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
inQuotes = !inQuotes;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == ',' && !inQuotes) {
|
||||||
|
result.add(current.toString());
|
||||||
|
current.setLength(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
current.append(c);
|
||||||
|
}
|
||||||
|
result.add(current.toString());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void normalizeAndValidatePointConfig(EmsPointConfig pointConfig) {
|
||||||
|
if (pointConfig == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pointConfig.setPointType(normalizePointType(pointConfig.getPointType()));
|
||||||
|
pointConfig.setCalcExpression(StringUtils.trimToNull(pointConfig.getCalcExpression()));
|
||||||
|
if ("calc".equals(pointConfig.getPointType())) {
|
||||||
|
if (StringUtils.isBlank(pointConfig.getCalcExpression())) {
|
||||||
|
throw new ServiceException("计算点必须填写计算表达式");
|
||||||
|
}
|
||||||
|
if (!CALC_EXPRESSION_PATTERN.matcher(pointConfig.getCalcExpression()).matches()) {
|
||||||
|
throw new ServiceException("计算表达式仅支持数字、字母、下划线、空格和四则运算符");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pointConfig.setCalcExpression(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizePointType(String pointType) {
|
||||||
|
String normalized = StringUtils.trimToEmpty(pointType).toLowerCase(Locale.ROOT);
|
||||||
|
if ("calc".equals(normalized) || "calculate".equals(normalized) || "计算点".equals(normalized)) {
|
||||||
|
return "calc";
|
||||||
|
}
|
||||||
|
return "data";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -12,6 +12,7 @@ import com.xzzn.ems.domain.EmsPointMatch;
|
|||||||
import com.xzzn.ems.domain.vo.DevicePointMatchExportVo;
|
import com.xzzn.ems.domain.vo.DevicePointMatchExportVo;
|
||||||
import com.xzzn.ems.domain.vo.DevicePointMatchVo;
|
import com.xzzn.ems.domain.vo.DevicePointMatchVo;
|
||||||
import com.xzzn.ems.domain.vo.ImportPointDataRequest;
|
import com.xzzn.ems.domain.vo.ImportPointDataRequest;
|
||||||
|
import com.xzzn.ems.domain.vo.ImportPointTemplateRequest;
|
||||||
import com.xzzn.ems.enums.DeviceMatchTable;
|
import com.xzzn.ems.enums.DeviceMatchTable;
|
||||||
import com.xzzn.ems.mapper.EmsPointEnumMatchMapper;
|
import com.xzzn.ems.mapper.EmsPointEnumMatchMapper;
|
||||||
import com.xzzn.ems.mapper.EmsPointMatchMapper;
|
import com.xzzn.ems.mapper.EmsPointMatchMapper;
|
||||||
@ -20,8 +21,10 @@ import com.xzzn.ems.utils.DevicePointMatchDataProcessor;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.validation.Validator;
|
import javax.validation.Validator;
|
||||||
@ -213,6 +216,99 @@ public class EmsPointMatchServiceImpl implements IEmsPointMatchService {
|
|||||||
return errorList;
|
return errorList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按站点导入模板点位
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @param operName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public String importTemplateBySite(ImportPointTemplateRequest request, String operName) {
|
||||||
|
String targetSiteId = request.getSiteId();
|
||||||
|
if (SITE_ID.equals(targetSiteId)) {
|
||||||
|
throw new ServiceException("模板站点不支持作为导入目标站点");
|
||||||
|
}
|
||||||
|
|
||||||
|
int templatePointCount = emsPointMatchMapper.countBySiteId(SITE_ID);
|
||||||
|
if (templatePointCount <= 0) {
|
||||||
|
throw new ServiceException("模板点位数据不存在,无法导入");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean overwrite = Boolean.TRUE.equals(request.getOverwrite());
|
||||||
|
int targetPointCount = emsPointMatchMapper.countBySiteId(targetSiteId);
|
||||||
|
if (targetPointCount > 0 && !overwrite) {
|
||||||
|
throw new ServiceException("目标站点已存在点位数据,请勾选“覆盖已存在数据”后重试");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetPointCount > 0) {
|
||||||
|
emsPointMatchMapper.deleteBySiteId(targetSiteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int targetEnumCount = emsPointEnumMatchMapper.countBySiteId(targetSiteId);
|
||||||
|
if (targetEnumCount > 0) {
|
||||||
|
emsPointEnumMatchMapper.deleteBySiteId(targetSiteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int importPointCount = emsPointMatchMapper.copyTemplateToSite(SITE_ID, targetSiteId, operName);
|
||||||
|
int importEnumCount = 0;
|
||||||
|
if (emsPointEnumMatchMapper.countBySiteId(SITE_ID) > 0) {
|
||||||
|
importEnumCount = emsPointEnumMatchMapper.copyTemplateToSite(SITE_ID, targetSiteId, operName);
|
||||||
|
}
|
||||||
|
|
||||||
|
syncSiteToRedis(targetSiteId);
|
||||||
|
return String.format("导入成功:站点 %s,点位 %d 条,枚举 %d 条", targetSiteId, importPointCount, importEnumCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<EmsPointMatch> selectPointMatchConfigList(EmsPointMatch emsPointMatch) {
|
||||||
|
return emsPointMatchMapper.selectEmsPointMatchList(emsPointMatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EmsPointMatch selectPointMatchById(Long id) {
|
||||||
|
return emsPointMatchMapper.selectEmsPointMatchById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertPointMatch(EmsPointMatch emsPointMatch) {
|
||||||
|
int rows = emsPointMatchMapper.insertEmsPointMatch(emsPointMatch);
|
||||||
|
if (rows > 0 && StringUtils.isNotBlank(emsPointMatch.getSiteId()) && StringUtils.isNotBlank(emsPointMatch.getDeviceCategory())) {
|
||||||
|
syncToRedis(emsPointMatch.getSiteId(), emsPointMatch.getDeviceId(), emsPointMatch.getDeviceCategory());
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updatePointMatch(EmsPointMatch emsPointMatch) {
|
||||||
|
int rows = emsPointMatchMapper.updateEmsPointMatch(emsPointMatch);
|
||||||
|
if (rows > 0 && StringUtils.isNotBlank(emsPointMatch.getSiteId()) && StringUtils.isNotBlank(emsPointMatch.getDeviceCategory())) {
|
||||||
|
syncToRedis(emsPointMatch.getSiteId(), emsPointMatch.getDeviceId(), emsPointMatch.getDeviceCategory());
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deletePointMatchByIds(Long[] ids) {
|
||||||
|
List<EmsPointMatch> deletedList = new ArrayList<>();
|
||||||
|
for (Long id : ids) {
|
||||||
|
EmsPointMatch pointMatch = emsPointMatchMapper.selectEmsPointMatchById(id);
|
||||||
|
if (pointMatch != null) {
|
||||||
|
deletedList.add(pointMatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int rows = emsPointMatchMapper.deleteEmsPointMatchByIds(ids);
|
||||||
|
if (rows > 0) {
|
||||||
|
deletedList.forEach(pointMatch -> {
|
||||||
|
if (StringUtils.isNotBlank(pointMatch.getSiteId()) && StringUtils.isNotBlank(pointMatch.getDeviceCategory())) {
|
||||||
|
syncToRedis(pointMatch.getSiteId(), pointMatch.getDeviceId(), pointMatch.getDeviceCategory());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean validDevicePointMatch(DevicePointMatchVo pointMatch, List<DevicePointMatchVo> errorList) {
|
private boolean validDevicePointMatch(DevicePointMatchVo pointMatch, List<DevicePointMatchVo> errorList) {
|
||||||
StringBuilder errorMsg = new StringBuilder();
|
StringBuilder errorMsg = new StringBuilder();
|
||||||
if (StringUtils.isBlank(pointMatch.getMatchField())) {
|
if (StringUtils.isBlank(pointMatch.getMatchField())) {
|
||||||
@ -238,6 +334,9 @@ public class EmsPointMatchServiceImpl implements IEmsPointMatchService {
|
|||||||
List<EmsPointMatch> pointMatchData = emsPointMatchMapper.getDevicePointMatchList(siteId, deviceId, deviceCategory);
|
List<EmsPointMatch> pointMatchData = emsPointMatchMapper.getDevicePointMatchList(siteId, deviceId, deviceCategory);
|
||||||
// log.info("同步点位匹配数据到Redis key:{} data:{}", pointMatchKey, pointMatchData);
|
// log.info("同步点位匹配数据到Redis key:{} data:{}", pointMatchKey, pointMatchData);
|
||||||
if (CollectionUtils.isEmpty(pointMatchData)) {
|
if (CollectionUtils.isEmpty(pointMatchData)) {
|
||||||
|
if (redisCache.hasKey(pointMatchKey)) {
|
||||||
|
redisCache.deleteObject(pointMatchKey);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (redisCache.hasKey(pointMatchKey)) {
|
if (redisCache.hasKey(pointMatchKey)) {
|
||||||
@ -247,6 +346,10 @@ public class EmsPointMatchServiceImpl implements IEmsPointMatchService {
|
|||||||
log.info("点位匹配数据同步完成 data:{}", JSON.toJSONString(redisCache.getCacheList(pointMatchKey)));
|
log.info("点位匹配数据同步完成 data:{}", JSON.toJSONString(redisCache.getCacheList(pointMatchKey)));
|
||||||
|
|
||||||
// 点位枚举匹配数据同步到Redis
|
// 点位枚举匹配数据同步到Redis
|
||||||
|
syncPointEnumToRedis(siteId, deviceCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncPointEnumToRedis(String siteId, String deviceCategory) {
|
||||||
String pointEnumMatchKey = DevicePointMatchDataProcessor.getPointEnumMacthCacheKey(siteId, deviceCategory);
|
String pointEnumMatchKey = DevicePointMatchDataProcessor.getPointEnumMacthCacheKey(siteId, deviceCategory);
|
||||||
List<EmsPointEnumMatch> pointEnumMatchList = emsPointEnumMatchMapper.selectList(siteId, deviceCategory, null);
|
List<EmsPointEnumMatch> pointEnumMatchList = emsPointEnumMatchMapper.selectList(siteId, deviceCategory, null);
|
||||||
if (!CollectionUtils.isEmpty(pointEnumMatchList)) {
|
if (!CollectionUtils.isEmpty(pointEnumMatchList)) {
|
||||||
@ -256,7 +359,22 @@ public class EmsPointMatchServiceImpl implements IEmsPointMatchService {
|
|||||||
redisCache.setCacheList(pointEnumMatchKey, pointEnumMatchList);
|
redisCache.setCacheList(pointEnumMatchKey, pointEnumMatchList);
|
||||||
log.info("点位枚举匹配数据同步完成 data:{}", JSON.toJSONString(redisCache.getCacheList(pointEnumMatchKey)));
|
log.info("点位枚举匹配数据同步完成 data:{}", JSON.toJSONString(redisCache.getCacheList(pointEnumMatchKey)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncSiteToRedis(String siteId) {
|
||||||
|
List<EmsPointMatch> sitePointList = emsPointMatchMapper.selectBySiteId(siteId);
|
||||||
|
if (CollectionUtils.isEmpty(sitePointList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Set<String> categorySet = new HashSet<>();
|
||||||
|
for (EmsPointMatch pointMatch : sitePointList) {
|
||||||
|
categorySet.add(pointMatch.getDeviceCategory());
|
||||||
|
if (StringUtils.isBlank(pointMatch.getDeviceId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
syncToRedis(siteId, pointMatch.getDeviceId(), pointMatch.getDeviceCategory());
|
||||||
|
}
|
||||||
|
categorySet.forEach(category -> syncPointEnumToRedis(siteId, category));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void savePointMatchEnum(String matchFieldEnum, String dataEnum, EmsPointMatch savePoint) {
|
private void savePointMatchEnum(String matchFieldEnum, String dataEnum, EmsPointMatch savePoint) {
|
||||||
|
|||||||
@ -2,7 +2,10 @@ package com.xzzn.ems.service.impl;
|
|||||||
|
|
||||||
import com.xzzn.common.constant.RedisKeyConstants;
|
import com.xzzn.common.constant.RedisKeyConstants;
|
||||||
import com.xzzn.common.core.redis.RedisCache;
|
import com.xzzn.common.core.redis.RedisCache;
|
||||||
|
import com.xzzn.common.exception.ServiceException;
|
||||||
import com.xzzn.common.enums.DeviceCategory;
|
import com.xzzn.common.enums.DeviceCategory;
|
||||||
|
import com.xzzn.common.utils.DateUtils;
|
||||||
|
import com.xzzn.common.utils.StringUtils;
|
||||||
import com.xzzn.ems.domain.EmsBatteryData;
|
import com.xzzn.ems.domain.EmsBatteryData;
|
||||||
import com.xzzn.ems.domain.EmsSiteSetting;
|
import com.xzzn.ems.domain.EmsSiteSetting;
|
||||||
import com.xzzn.ems.domain.vo.SiteDeviceListVo;
|
import com.xzzn.ems.domain.vo.SiteDeviceListVo;
|
||||||
@ -12,9 +15,11 @@ import com.xzzn.ems.mapper.EmsSiteSettingMapper;
|
|||||||
import com.xzzn.ems.service.IEmsSiteService;
|
import com.xzzn.ems.service.IEmsSiteService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 站点信息 服务层实现
|
* 站点信息 服务层实现
|
||||||
@ -23,6 +28,7 @@ import java.util.Map;
|
|||||||
@Service
|
@Service
|
||||||
public class EmsSiteServiceImpl implements IEmsSiteService
|
public class EmsSiteServiceImpl implements IEmsSiteService
|
||||||
{
|
{
|
||||||
|
private static final Pattern SITE_ID_PATTERN = Pattern.compile("^[A-Za-z0-9_]+$");
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmsSiteSettingMapper emsSiteMapper;
|
private EmsSiteSettingMapper emsSiteMapper;
|
||||||
@ -70,7 +76,14 @@ public class EmsSiteServiceImpl implements IEmsSiteService
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<EmsSiteSetting> getAllSiteInfoList(String siteName, String startTime, String endTime) {
|
public List<EmsSiteSetting> getAllSiteInfoList(String siteName, String startTime, String endTime) {
|
||||||
return emsSiteMapper.getSiteInfoList(siteName,startTime,endTime);
|
List<EmsSiteSetting> list = emsSiteMapper.getSiteInfoList(siteName,startTime,endTime);
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
for (EmsSiteSetting site : list) {
|
||||||
|
site.setAuthorized(Boolean.TRUE);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,4 +158,53 @@ public class EmsSiteServiceImpl implements IEmsSiteService
|
|||||||
List<Map<String,Object>> deviceIdList = emsDevicesMapper.getDeviceInfosBySiteIdAndCategory(siteId, parentCategory);
|
List<Map<String,Object>> deviceIdList = emsDevicesMapper.getDeviceInfosBySiteIdAndCategory(siteId, parentCategory);
|
||||||
return deviceIdList;
|
return deviceIdList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int addSite(EmsSiteSetting emsSiteSetting) {
|
||||||
|
validateSiteSetting(emsSiteSetting, true);
|
||||||
|
String siteId = emsSiteSetting.getSiteId();
|
||||||
|
EmsSiteSetting existing = emsSiteMapper.selectEmsSiteSettingBySiteId(siteId);
|
||||||
|
if (existing != null) {
|
||||||
|
throw new ServiceException("站点ID已存在,请更换后重试");
|
||||||
|
}
|
||||||
|
emsSiteSetting.setCreateTime(DateUtils.getNowDate());
|
||||||
|
return emsSiteMapper.insertEmsSiteSetting(emsSiteSetting);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int updateSite(EmsSiteSetting emsSiteSetting) {
|
||||||
|
if (emsSiteSetting == null || emsSiteSetting.getId() == null) {
|
||||||
|
throw new ServiceException("站点主键不能为空");
|
||||||
|
}
|
||||||
|
validateSiteSetting(emsSiteSetting, false);
|
||||||
|
EmsSiteSetting dbData = emsSiteMapper.selectEmsSiteSettingById(emsSiteSetting.getId());
|
||||||
|
if (dbData == null) {
|
||||||
|
throw new ServiceException("站点不存在");
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(emsSiteSetting.getSiteId())
|
||||||
|
&& !StringUtils.equals(emsSiteSetting.getSiteId(), dbData.getSiteId())) {
|
||||||
|
throw new ServiceException("不支持修改站点ID");
|
||||||
|
}
|
||||||
|
emsSiteSetting.setSiteId(dbData.getSiteId());
|
||||||
|
emsSiteSetting.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
return emsSiteMapper.updateEmsSiteSetting(emsSiteSetting);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateSiteSetting(EmsSiteSetting emsSiteSetting, boolean requireSiteId) {
|
||||||
|
if (emsSiteSetting == null) {
|
||||||
|
throw new ServiceException("参数不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(emsSiteSetting.getSiteName())) {
|
||||||
|
throw new ServiceException("站点名称不能为空");
|
||||||
|
}
|
||||||
|
if (requireSiteId && StringUtils.isBlank(emsSiteSetting.getSiteId())) {
|
||||||
|
throw new ServiceException("站点ID不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(emsSiteSetting.getSiteId()) && !SITE_ID_PATTERN.matcher(emsSiteSetting.getSiteId()).matches()) {
|
||||||
|
throw new ServiceException("站点ID仅支持字母、数字、下划线");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,16 +2,17 @@ package com.xzzn.ems.service.impl;
|
|||||||
|
|
||||||
import com.xzzn.common.enums.DeviceCategory;
|
import com.xzzn.common.enums.DeviceCategory;
|
||||||
import com.xzzn.common.utils.DateUtils;
|
import com.xzzn.common.utils.DateUtils;
|
||||||
|
import com.xzzn.ems.domain.EmsPointConfig;
|
||||||
import com.xzzn.ems.domain.EmsPointMatch;
|
import com.xzzn.ems.domain.EmsPointMatch;
|
||||||
import com.xzzn.ems.domain.vo.DevicePointDataList;
|
import com.xzzn.ems.domain.vo.*;
|
||||||
import com.xzzn.ems.domain.vo.GeneralQueryDataVo;
|
|
||||||
import com.xzzn.ems.domain.vo.GeneralQueryResponse;
|
|
||||||
import com.xzzn.ems.domain.vo.PointNameRequest;
|
|
||||||
import com.xzzn.ems.domain.vo.SiteBatteryListVo;
|
|
||||||
import com.xzzn.ems.mapper.EmsBatteryDataMonthMapper;
|
import com.xzzn.ems.mapper.EmsBatteryDataMonthMapper;
|
||||||
|
import com.xzzn.ems.mapper.EmsPointConfigMapper;
|
||||||
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
|
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
|
||||||
import com.xzzn.ems.mapper.EmsPointMatchMapper;
|
import com.xzzn.ems.mapper.EmsPointMatchMapper;
|
||||||
import com.xzzn.ems.service.IGeneralQueryService;
|
import com.xzzn.ems.service.IGeneralQueryService;
|
||||||
|
import com.xzzn.ems.service.InfluxPointDataWriter;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
@ -19,24 +20,9 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.temporal.TemporalAdjusters;
|
import java.time.temporal.TemporalAdjusters;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 综合查询 服务层实现
|
* 综合查询 服务层实现
|
||||||
*
|
*
|
||||||
@ -49,23 +35,29 @@ public class GeneralQueryServiceImpl implements IGeneralQueryService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EmsPointMatchMapper emsPointMatchMapper;
|
private EmsPointMatchMapper emsPointMatchMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private EmsPointConfigMapper emsPointConfigMapper;
|
||||||
|
@Autowired
|
||||||
private EmsDevicesSettingMapper emsDevicesSettingMapper;
|
private EmsDevicesSettingMapper emsDevicesSettingMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmsBatteryDataMonthMapper emsBatteryDataMonthMapper;
|
private EmsBatteryDataMonthMapper emsBatteryDataMonthMapper;
|
||||||
|
@Autowired
|
||||||
|
private InfluxPointDataWriter influxPointDataWriter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getPointNameList(PointNameRequest request) {
|
public List<GeneralQueryPointOptionVo> getPointNameList(PointNameRequest request) {
|
||||||
List<String> siteIds = request.getSiteIds();
|
List<String> siteIds = request.getSiteIds();
|
||||||
if (siteIds == null || siteIds.isEmpty()) {
|
if (siteIds == null || siteIds.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
String deviceCategory = request.getDeviceCategory();
|
String deviceCategory = request.getDeviceCategory();
|
||||||
if (deviceCategory == null) {
|
String deviceId = request.getDeviceId();
|
||||||
|
if ((deviceCategory == null || "".equals(deviceCategory.trim()))
|
||||||
|
&& (deviceId == null || "".equals(deviceId.trim()))) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return emsPointMatchMapper.getPointNameList(siteIds,deviceCategory,request.getPointName());
|
return emsPointConfigMapper.getPointNameList(siteIds, deviceCategory, deviceId, request.getPointName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -96,84 +88,140 @@ public class GeneralQueryServiceImpl implements IGeneralQueryService
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GeneralQueryResponse> getPointValueList(PointNameRequest request){
|
public List<GeneralQueryResponse> getPointValueList(PointNameRequest request){
|
||||||
List<GeneralQueryResponse> result = new ArrayList<>();
|
|
||||||
List<String> querySiteIds = new ArrayList<>();
|
|
||||||
|
|
||||||
List<String> siteIds = request.getSiteIds();
|
List<String> siteIds = request.getSiteIds();
|
||||||
String deviceId = request.getDeviceId();
|
if (siteIds == null || siteIds.isEmpty()) {
|
||||||
String deviceCategory = request.getDeviceCategory();
|
return Collections.emptyList();
|
||||||
// 处理点位名称
|
|
||||||
String pointName = request.getPointName();
|
|
||||||
// 根据入参获取点位对应的表和字段
|
|
||||||
List<EmsPointMatch> matchInfo = emsPointMatchMapper.getMatchInfo(siteIds,deviceId,deviceCategory,pointName);
|
|
||||||
if (CollectionUtils.isEmpty(matchInfo) && DeviceCategory.AMMETER.getCode().equals(deviceCategory)) {
|
|
||||||
pointName = processPointName(pointName);
|
|
||||||
matchInfo = emsPointMatchMapper.getMatchInfo(siteIds,deviceId,deviceCategory,pointName);
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isEmpty(matchInfo)) {
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
for (EmsPointMatch emsPointMatch : matchInfo) {
|
|
||||||
querySiteIds.add(emsPointMatch.getSiteId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单体电池特殊校验
|
String deviceCategory = request.getDeviceCategory();
|
||||||
Map<String,List<String>> siteDeviceMap = request.getSiteDeviceMap();
|
String requestDeviceId = request.getDeviceId();
|
||||||
if (DeviceCategory.BATTERY.getCode().equals(deviceCategory) && (siteDeviceMap == null || siteDeviceMap.size() == 0)) {
|
if ((deviceCategory == null || "".equals(deviceCategory.trim()))
|
||||||
return result;
|
&& (requestDeviceId == null || "".equals(requestDeviceId.trim()))
|
||||||
|
) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> pointNames = resolvePointNames(request);
|
||||||
|
if (pointNames.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理时间范围,如果未传根据数据单位设默认值
|
// 处理时间范围,如果未传根据数据单位设默认值
|
||||||
dealDataTime(request);
|
dealDataTime(request);
|
||||||
|
Date startDate = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, request.getStartDate());
|
||||||
|
Date endDate = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, request.getEndDate());
|
||||||
|
if (request.getDataUnit() == 3) {
|
||||||
|
endDate = DateUtils.adjustToEndOfDay(request.getEndDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> selectedDeviceIds = resolveSelectedDeviceIds(request);
|
||||||
|
List<EmsPointConfig> pointConfigs = emsPointConfigMapper.getConfigListForGeneralQuery(
|
||||||
|
siteIds, deviceCategory, pointNames, selectedDeviceIds
|
||||||
|
);
|
||||||
|
if (pointConfigs == null || pointConfigs.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GeneralQueryDataVo> dataVoList = new ArrayList<>();
|
||||||
|
for (EmsPointConfig pointConfig : pointConfigs) {
|
||||||
|
dataVoList.addAll(queryPointCurve(pointConfig, request.getDataUnit(), startDate, endDate));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataVoList.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.getDataUnit() == 1) {
|
||||||
try {
|
try {
|
||||||
// 不同的site_id根据设备类型和字段,默认取第一个匹配到的表和表字段只会有一个,
|
dataVoList = dealWithMinutesData(siteIds, dataVoList, deviceCategory, request.getStartDate(), request.getEndDate());
|
||||||
EmsPointMatch pointMatch = matchInfo.get(0);
|
|
||||||
String finalPointName = pointName;
|
|
||||||
Optional<EmsPointMatch> emsPointMatch = matchInfo.stream()
|
|
||||||
.filter(item -> finalPointName.equals(item.getPointName()) || finalPointName.equals(item.getDataPointName()))
|
|
||||||
.findFirst();
|
|
||||||
if (emsPointMatch.isPresent()) {
|
|
||||||
pointMatch = emsPointMatch.get();
|
|
||||||
}
|
|
||||||
String tableName = pointMatch.getMatchTable();
|
|
||||||
String tableField = pointMatch.getMatchField();
|
|
||||||
Long dataType = pointMatch.getDataType();
|
|
||||||
if (DeviceCategory.BATTERY.getCode().equals(deviceCategory)) {
|
|
||||||
// 单体电池数据特殊处理
|
|
||||||
result = generalQueryBatteryData(querySiteIds,tableName,tableField,request,deviceCategory,dataType);
|
|
||||||
} else {
|
|
||||||
// 其他设备数据
|
|
||||||
result = generalQueryCommonData(querySiteIds,tableName,tableField,request,deviceCategory,dataType);
|
|
||||||
}
|
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return convertCommonToResultList(dataVoList, 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> resolvePointNames(PointNameRequest request) {
|
||||||
|
List<String> names = new ArrayList<>();
|
||||||
|
if (request.getPointNames() != null && !request.getPointNames().isEmpty()) {
|
||||||
|
names.addAll(request.getPointNames());
|
||||||
|
} else if (request.getPointName() != null && !"".equals(request.getPointName().trim())) {
|
||||||
|
names.addAll(Arrays.stream(request.getPointName().split(","))
|
||||||
|
.map(String::trim)
|
||||||
|
.filter(s -> !s.isEmpty())
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
return names.stream().distinct().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> resolveSelectedDeviceIds(PointNameRequest request) {
|
||||||
|
List<String> selected = new ArrayList<>();
|
||||||
|
if (request.getDeviceId() != null && !"".equals(request.getDeviceId().trim())) {
|
||||||
|
selected.add(request.getDeviceId().trim());
|
||||||
|
}
|
||||||
|
Map<String, List<String>> siteDeviceMap = request.getSiteDeviceMap();
|
||||||
|
if (siteDeviceMap != null && !siteDeviceMap.isEmpty()) {
|
||||||
|
for (List<String> devices : siteDeviceMap.values()) {
|
||||||
|
if (devices == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (String deviceId : devices) {
|
||||||
|
if (deviceId != null && !"".equals(deviceId.trim())) {
|
||||||
|
selected.add(deviceId.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selected.stream().distinct().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<GeneralQueryDataVo> queryPointCurve(EmsPointConfig config, int dataUnit, Date startDate, Date endDate) {
|
||||||
|
if (config == null || config.getSiteId() == null || config.getDeviceId() == null || config.getDataKey() == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<InfluxPointDataWriter.PointValue> values = influxPointDataWriter.queryCurveData(
|
||||||
|
config.getSiteId(), config.getDeviceId(), config.getDataKey(), startDate, endDate
|
||||||
|
);
|
||||||
|
if (values == null || values.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每个时间桶取该桶最后一条值
|
||||||
|
Map<String, Object> latestByBucket = new LinkedHashMap<>();
|
||||||
|
for (InfluxPointDataWriter.PointValue value : values) {
|
||||||
|
latestByBucket.put(formatByDataUnit(value.getDataTime(), dataUnit), value.getPointValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GeneralQueryDataVo> result = new ArrayList<>();
|
||||||
|
String displayDeviceId = buildDisplayDeviceId(config);
|
||||||
|
for (Map.Entry<String, Object> entry : latestByBucket.entrySet()) {
|
||||||
|
GeneralQueryDataVo vo = new GeneralQueryDataVo();
|
||||||
|
vo.setSiteId(config.getSiteId());
|
||||||
|
vo.setDeviceId(displayDeviceId);
|
||||||
|
vo.setValueDate(entry.getKey());
|
||||||
|
vo.setPointValue(entry.getValue());
|
||||||
|
result.add(vo);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String processPointName(String pointName) {
|
private String buildDisplayDeviceId(EmsPointConfig config) {
|
||||||
// 特殊处理
|
String pointName = config.getPointName() == null || "".equals(config.getPointName().trim())
|
||||||
if ("正向有功电能".equals(pointName)) {
|
? config.getDataKey() : config.getPointName().trim();
|
||||||
pointName = "当前正向总有功电能";
|
return config.getDeviceId() + "-" + pointName;
|
||||||
}
|
}
|
||||||
if ("反向有功电能".equals(pointName)) {
|
|
||||||
pointName = "当前反向总有功电能";
|
private String formatByDataUnit(Date dataTime, int dataUnit) {
|
||||||
|
if (dataTime == null) {
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
if ("正向无功电能".equals(pointName)) {
|
if (dataUnit == 3) {
|
||||||
pointName = "当前正向总无功电能";
|
return new SimpleDateFormat("yyyy-MM-dd").format(dataTime);
|
||||||
}
|
}
|
||||||
if ("反向无功电能".equals(pointName)) {
|
if (dataUnit == 2) {
|
||||||
pointName = "当前反向总无功电能";
|
return new SimpleDateFormat("yyyy-MM-dd HH:00").format(dataTime);
|
||||||
}
|
}
|
||||||
if ("有功功率".equals(pointName)) {
|
return new SimpleDateFormat("yyyy-MM-dd HH:mm:00").format(dataTime);
|
||||||
pointName = "功率";
|
|
||||||
}
|
|
||||||
if ("无功功率".equals(pointName)) {
|
|
||||||
pointName = "总无功功率";
|
|
||||||
}
|
|
||||||
return pointName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<GeneralQueryResponse> generalQueryCommonData(List<String> querySiteIds, String tableName,
|
private List<GeneralQueryResponse> generalQueryCommonData(List<String> querySiteIds, String tableName,
|
||||||
|
|||||||
@ -0,0 +1,231 @@
|
|||||||
|
<?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.EmsPointConfigMapper">
|
||||||
|
|
||||||
|
<resultMap type="EmsPointConfig" id="EmsPointConfigResult">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="siteId" column="site_id"/>
|
||||||
|
<result property="deviceCategory" column="device_category"/>
|
||||||
|
<result property="deviceId" column="device_id"/>
|
||||||
|
<result property="pointName" column="point_name"/>
|
||||||
|
<result property="dataKey" column="data_key"/>
|
||||||
|
<result property="pointDesc" column="point_desc"/>
|
||||||
|
<result property="registerAddress" column="register_address"/>
|
||||||
|
<result property="dataUnit" column="data_unit"/>
|
||||||
|
<result property="dataA" column="data_a"/>
|
||||||
|
<result property="dataK" column="data_k"/>
|
||||||
|
<result property="dataB" column="data_b"/>
|
||||||
|
<result property="dataBit" column="data_bit"/>
|
||||||
|
<result property="isAlarm" column="is_alarm"/>
|
||||||
|
<result property="pointType" column="point_type"/>
|
||||||
|
<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="selectEmsPointConfigVo">
|
||||||
|
select 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
|
||||||
|
from ems_point_config
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectEmsPointConfigById" parameterType="Long" resultMap="EmsPointConfigResult">
|
||||||
|
<include refid="selectEmsPointConfigVo"/>
|
||||||
|
where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectEmsPointConfigList" parameterType="EmsPointConfig" resultMap="EmsPointConfigResult">
|
||||||
|
<include refid="selectEmsPointConfigVo"/>
|
||||||
|
<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="deviceId != null and deviceId != ''">and device_id = #{deviceId}</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>
|
||||||
|
<if test="pointType != null and pointType != ''">and point_type = #{pointType}</if>
|
||||||
|
<if test="registerAddress != null and registerAddress != ''">and register_address = #{registerAddress}</if>
|
||||||
|
</where>
|
||||||
|
order by update_time desc, id desc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertEmsPointConfig" parameterType="EmsPointConfig" useGeneratedKeys="true" keyProperty="id">
|
||||||
|
insert into ems_point_config
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="siteId != null">site_id,</if>
|
||||||
|
<if test="deviceCategory != null">device_category,</if>
|
||||||
|
<if test="deviceId != null">device_id,</if>
|
||||||
|
<if test="pointName != null">point_name,</if>
|
||||||
|
<if test="dataKey != null">data_key,</if>
|
||||||
|
<if test="pointDesc != null">point_desc,</if>
|
||||||
|
<if test="registerAddress != null">register_address,</if>
|
||||||
|
<if test="dataUnit != null">data_unit,</if>
|
||||||
|
<if test="dataA != null">data_a,</if>
|
||||||
|
<if test="dataK != null">data_k,</if>
|
||||||
|
<if test="dataB != null">data_b,</if>
|
||||||
|
<if test="dataBit != null">data_bit,</if>
|
||||||
|
<if test="isAlarm != null">is_alarm,</if>
|
||||||
|
<if test="pointType != null">point_type,</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="deviceId != null">#{deviceId},</if>
|
||||||
|
<if test="pointName != null">#{pointName},</if>
|
||||||
|
<if test="dataKey != null">#{dataKey},</if>
|
||||||
|
<if test="pointDesc != null">#{pointDesc},</if>
|
||||||
|
<if test="registerAddress != null">#{registerAddress},</if>
|
||||||
|
<if test="dataUnit != null">#{dataUnit},</if>
|
||||||
|
<if test="dataA != null">#{dataA},</if>
|
||||||
|
<if test="dataK != null">#{dataK},</if>
|
||||||
|
<if test="dataB != null">#{dataB},</if>
|
||||||
|
<if test="dataBit != null">#{dataBit},</if>
|
||||||
|
<if test="isAlarm != null">#{isAlarm},</if>
|
||||||
|
<if test="pointType != null">#{pointType},</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="updateEmsPointConfig" parameterType="EmsPointConfig">
|
||||||
|
update ems_point_config
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="siteId != null">site_id = #{siteId},</if>
|
||||||
|
<if test="deviceCategory != null">device_category = #{deviceCategory},</if>
|
||||||
|
<if test="deviceId != null">device_id = #{deviceId},</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="registerAddress != null">register_address = #{registerAddress},</if>
|
||||||
|
<if test="dataUnit != null">data_unit = #{dataUnit},</if>
|
||||||
|
<if test="dataA != null">data_a = #{dataA},</if>
|
||||||
|
<if test="dataK != null">data_k = #{dataK},</if>
|
||||||
|
<if test="dataB != null">data_b = #{dataB},</if>
|
||||||
|
<if test="dataBit != null">data_bit = #{dataBit},</if>
|
||||||
|
<if test="isAlarm != null">is_alarm = #{isAlarm},</if>
|
||||||
|
<if test="pointType != null">point_type = #{pointType},</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="deleteEmsPointConfigById" parameterType="Long">
|
||||||
|
delete from ems_point_config where id = #{id}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<delete id="deleteEmsPointConfigByIds" parameterType="String">
|
||||||
|
delete from ems_point_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_config
|
||||||
|
where site_id = #{siteId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<delete id="deleteBySiteId">
|
||||||
|
delete from ems_point_config
|
||||||
|
where site_id = #{siteId}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<insert id="copyTemplateToSite">
|
||||||
|
insert into ems_point_config (
|
||||||
|
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
|
||||||
|
)
|
||||||
|
select
|
||||||
|
#{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,
|
||||||
|
#{operName}, now(), #{operName}, now(), remark
|
||||||
|
from ems_point_config
|
||||||
|
where site_id = #{templateSiteId}
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<select id="getRegisterAddress" resultType="java.lang.String">
|
||||||
|
select register_address
|
||||||
|
from ems_point_config
|
||||||
|
where site_id = #{siteId}
|
||||||
|
and device_category = #{deviceCategory}
|
||||||
|
and device_id = #{deviceId}
|
||||||
|
and data_key = #{dataKey}
|
||||||
|
limit 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="getPointNameList" resultType="com.xzzn.ems.domain.vo.GeneralQueryPointOptionVo">
|
||||||
|
select point_name as pointName,
|
||||||
|
data_key as dataKey,
|
||||||
|
point_desc as pointDesc
|
||||||
|
from ems_point_config
|
||||||
|
where 1 = 1
|
||||||
|
<if test="siteIds != null and siteIds.size() > 0">
|
||||||
|
and site_id in
|
||||||
|
<foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
|
||||||
|
#{siteId}
|
||||||
|
</foreach>
|
||||||
|
</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="pointName != null and pointName != ''">
|
||||||
|
and (
|
||||||
|
point_name like concat('%', #{pointName}, '%')
|
||||||
|
or data_key like concat('%', #{pointName}, '%')
|
||||||
|
or point_desc like concat('%', #{pointName}, '%')
|
||||||
|
)
|
||||||
|
</if>
|
||||||
|
group by point_name, data_key, point_desc
|
||||||
|
order by point_name asc, data_key asc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="getConfigListForGeneralQuery" resultMap="EmsPointConfigResult">
|
||||||
|
<include refid="selectEmsPointConfigVo"/>
|
||||||
|
where 1 = 1
|
||||||
|
<if test="siteIds != null and siteIds.size() > 0">
|
||||||
|
and site_id in
|
||||||
|
<foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
|
||||||
|
#{siteId}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
<if test="deviceCategory != null and deviceCategory != ''">
|
||||||
|
and device_category = #{deviceCategory}
|
||||||
|
</if>
|
||||||
|
<if test="pointNames != null and pointNames.size() > 0">
|
||||||
|
and point_name in
|
||||||
|
<foreach collection="pointNames" item="pointName" open="(" separator="," close=")">
|
||||||
|
#{pointName}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
<if test="deviceIds != null and deviceIds.size() > 0">
|
||||||
|
and device_id in
|
||||||
|
<foreach collection="deviceIds" item="deviceId" open="(" separator="," close=")">
|
||||||
|
#{deviceId}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@ -119,4 +119,47 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="countBySiteId" resultType="int">
|
||||||
|
select count(1)
|
||||||
|
from ems_point_enum_match
|
||||||
|
where site_id = #{siteId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<delete id="deleteBySiteId">
|
||||||
|
delete from ems_point_enum_match
|
||||||
|
where site_id = #{siteId}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<insert id="copyTemplateToSite">
|
||||||
|
insert into ems_point_enum_match (
|
||||||
|
match_field,
|
||||||
|
site_id,
|
||||||
|
device_category,
|
||||||
|
enum_code,
|
||||||
|
enum_name,
|
||||||
|
enum_desc,
|
||||||
|
data_enum_code,
|
||||||
|
create_by,
|
||||||
|
create_time,
|
||||||
|
update_by,
|
||||||
|
update_time,
|
||||||
|
remark
|
||||||
|
)
|
||||||
|
select
|
||||||
|
match_field,
|
||||||
|
#{targetSiteId},
|
||||||
|
device_category,
|
||||||
|
enum_code,
|
||||||
|
enum_name,
|
||||||
|
enum_desc,
|
||||||
|
data_enum_code,
|
||||||
|
#{operName},
|
||||||
|
now(),
|
||||||
|
#{operName},
|
||||||
|
now(),
|
||||||
|
remark
|
||||||
|
from ems_point_enum_match
|
||||||
|
where site_id = #{templateSiteId}
|
||||||
|
</insert>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -577,4 +577,74 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="countBySiteId" resultType="int">
|
||||||
|
select count(1)
|
||||||
|
from ems_point_match
|
||||||
|
where site_id = #{siteId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<delete id="deleteBySiteId">
|
||||||
|
delete from ems_point_match
|
||||||
|
where site_id = #{siteId}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<insert id="copyTemplateToSite">
|
||||||
|
insert into ems_point_match (
|
||||||
|
point_name,
|
||||||
|
match_table,
|
||||||
|
match_field,
|
||||||
|
site_id,
|
||||||
|
device_category,
|
||||||
|
data_point,
|
||||||
|
data_point_name,
|
||||||
|
data_device,
|
||||||
|
data_unit,
|
||||||
|
ip_address,
|
||||||
|
ip_port,
|
||||||
|
data_type,
|
||||||
|
need_diff_device_id,
|
||||||
|
create_by,
|
||||||
|
create_time,
|
||||||
|
update_by,
|
||||||
|
update_time,
|
||||||
|
remark,
|
||||||
|
is_alarm,
|
||||||
|
device_id,
|
||||||
|
a,
|
||||||
|
k,
|
||||||
|
b
|
||||||
|
)
|
||||||
|
select
|
||||||
|
point_name,
|
||||||
|
match_table,
|
||||||
|
match_field,
|
||||||
|
#{targetSiteId},
|
||||||
|
device_category,
|
||||||
|
data_point,
|
||||||
|
data_point_name,
|
||||||
|
data_device,
|
||||||
|
data_unit,
|
||||||
|
ip_address,
|
||||||
|
ip_port,
|
||||||
|
data_type,
|
||||||
|
need_diff_device_id,
|
||||||
|
#{operName},
|
||||||
|
now(),
|
||||||
|
#{operName},
|
||||||
|
now(),
|
||||||
|
remark,
|
||||||
|
is_alarm,
|
||||||
|
device_id,
|
||||||
|
a,
|
||||||
|
k,
|
||||||
|
b
|
||||||
|
from ems_point_match
|
||||||
|
where site_id = #{templateSiteId}
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<select id="selectBySiteId" resultMap="EmsPointMatchResult">
|
||||||
|
<include refid="selectEmsPointMatchVo"/>
|
||||||
|
where site_id = #{siteId}
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
<?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.EmsSiteMonitorDataMapper">
|
||||||
|
|
||||||
|
<select id="selectHistoryJsonByMinute" resultType="java.lang.String">
|
||||||
|
select data_json
|
||||||
|
from ${tableName}
|
||||||
|
where site_id = #{siteId}
|
||||||
|
and statis_minute = #{statisMinute}
|
||||||
|
limit 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="upsertHistoryJsonByMinute">
|
||||||
|
insert into ${tableName} (
|
||||||
|
site_id, statis_minute, data_json, create_by, create_time, update_by, update_time
|
||||||
|
) values (
|
||||||
|
#{siteId}, #{statisMinute}, #{dataJson}, #{operName}, now(), #{operName}, now()
|
||||||
|
)
|
||||||
|
on duplicate key update
|
||||||
|
data_json = values(data_json),
|
||||||
|
update_by = values(update_by),
|
||||||
|
update_time = now()
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateHistoryHotColumns">
|
||||||
|
update ${tableName}
|
||||||
|
set hot_soc = #{hotSoc},
|
||||||
|
hot_total_active_power = #{hotTotalActivePower},
|
||||||
|
hot_total_reactive_power = #{hotTotalReactivePower},
|
||||||
|
hot_day_charged_cap = #{hotDayChargedCap},
|
||||||
|
hot_day_dis_charged_cap = #{hotDayDisChargedCap},
|
||||||
|
update_by = #{operName},
|
||||||
|
update_time = now()
|
||||||
|
where site_id = #{siteId}
|
||||||
|
and statis_minute = #{statisMinute}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
<?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.EmsSiteMonitorItemMapper">
|
||||||
|
|
||||||
|
<resultMap id="EmsSiteMonitorItemResult" type="com.xzzn.ems.domain.EmsSiteMonitorItem">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="moduleCode" column="module_code"/>
|
||||||
|
<result property="moduleName" column="module_name"/>
|
||||||
|
<result property="menuCode" column="menu_code"/>
|
||||||
|
<result property="menuName" column="menu_name"/>
|
||||||
|
<result property="sectionName" column="section_name"/>
|
||||||
|
<result property="fieldCode" column="field_code"/>
|
||||||
|
<result property="fieldName" column="field_name"/>
|
||||||
|
<result property="sortNo" column="sort_no"/>
|
||||||
|
<result property="status" column="status"/>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<select id="selectEnabledList" resultMap="EmsSiteMonitorItemResult">
|
||||||
|
select id, module_code, module_name, menu_code, menu_name, section_name, field_code, field_name, sort_no, status,
|
||||||
|
create_by, create_time, update_by, update_time, remark
|
||||||
|
from ems_site_monitor_item
|
||||||
|
where status = 1
|
||||||
|
order by sort_no asc, id asc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
<?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.EmsSiteMonitorPointMatchMapper">
|
||||||
|
|
||||||
|
<resultMap id="EmsSiteMonitorPointMatchResult" type="com.xzzn.ems.domain.EmsSiteMonitorPointMatch">
|
||||||
|
<result property="id" column="id"/>
|
||||||
|
<result property="siteId" column="site_id"/>
|
||||||
|
<result property="fieldCode" column="field_code"/>
|
||||||
|
<result property="dataPoint" column="data_point"/>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<select id="selectBySiteId" resultMap="EmsSiteMonitorPointMatchResult">
|
||||||
|
select id, site_id, field_code, data_point, create_by, create_time, update_by, update_time, remark
|
||||||
|
from ems_site_monitor_point_match
|
||||||
|
where site_id = #{siteId}
|
||||||
|
order by id asc
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<delete id="deleteBySiteId">
|
||||||
|
delete from ems_site_monitor_point_match
|
||||||
|
where site_id = #{siteId}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<insert id="insertBatch">
|
||||||
|
insert into ems_site_monitor_point_match
|
||||||
|
(site_id, field_code, data_point, create_by, create_time, update_by, update_time)
|
||||||
|
values
|
||||||
|
<foreach collection="list" item="item" separator=",">
|
||||||
|
(#{item.siteId}, #{item.fieldCode}, #{item.dataPoint}, #{item.createBy}, now(), #{item.updateBy}, now())
|
||||||
|
</foreach>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
Reference in New Issue
Block a user