增加站点设备多项统计接口

This commit is contained in:
zhangyue 2026-07-28 15:24:10 +08:00
parent 0e92650804
commit fe786d39ce
19 changed files with 2187 additions and 15 deletions

View File

@ -9,6 +9,7 @@ import org.jeecg.common.api.vo.Result;
import org.jeecg.common.config.TenantContext; import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.PollutionConstants; import org.jeecg.common.constant.PollutionConstants;
import org.jeecg.common.dto.AlertSummaryDTO; import org.jeecg.common.dto.AlertSummaryDTO;
import org.jeecg.common.dto.SurvSummaryDTO;
import org.jeecg.common.entity.SurvDeviceDeploy; import org.jeecg.common.entity.SurvDeviceDeploy;
import org.jeecg.common.entity.SurvDisplayInfo; import org.jeecg.common.entity.SurvDisplayInfo;
import org.jeecg.common.entity.SurvPestlightAlert; import org.jeecg.common.entity.SurvPestlightAlert;
@ -17,10 +18,8 @@ import org.jeecg.common.util.DateTimeRangeUtil;
import org.jeecg.common.vo.PestLightAlertVo; import org.jeecg.common.vo.PestLightAlertVo;
import org.jeecg.common.vo.result.DataCenterDataSummary; import org.jeecg.common.vo.result.DataCenterDataSummary;
import org.jeecg.common.vo.statistic.AlertSummaryVo; import org.jeecg.common.vo.statistic.AlertSummaryVo;
import org.jeecg.modules.appmana.service.ISurvAlertRecordService; import org.jeecg.common.vo.statistic.SurvSummaryVo;
import org.jeecg.modules.appmana.service.ISurvDeviceDeployService; import org.jeecg.modules.appmana.service.*;
import org.jeecg.modules.appmana.service.ISurvPestlightAlertService;
import org.jeecg.modules.appmana.service.ISurvStationInfoService;
import org.jeecg.modules.appmana.service.impl.CommonServiceImpl; import org.jeecg.modules.appmana.service.impl.CommonServiceImpl;
import org.jeecg.modules.appmana.service.impl.IotCommonP3ServiceImpl; import org.jeecg.modules.appmana.service.impl.IotCommonP3ServiceImpl;
import org.jeecg.modules.appmana.utils.MonitoringDataRichTextBuilder; import org.jeecg.modules.appmana.utils.MonitoringDataRichTextBuilder;
@ -48,12 +47,13 @@ public class DataCenterController {
@Autowired @Autowired
private CommonServiceImpl commonService; private CommonServiceImpl commonService;
@Autowired
private ISurvAlertRecordService survAlertRecordService;
@Autowired @Autowired
private ISurvStationInfoService survStationInfoService; private ISurvStationInfoService survStationInfoService;
/** /**
* 获取所有大屏信息 * 获取所有大屏信息
*/ */
@ -83,11 +83,12 @@ public class DataCenterController {
* 获取设备统计监测统计数据 * 获取设备统计监测统计数据
*/ */
@PostMapping(value = "/deviceAlertStatistic") @PostMapping(value = "/deviceAlertStatistic")
public Result<AlertSummaryVo> deviceAlertStatistic(@RequestBody AlertSummaryDTO alertSummaryDTO) { public Result<SurvSummaryVo> deviceAlertStatistic(@RequestBody SurvSummaryDTO survSummaryDTO) {
alertSummaryDTO.setTenantId(TenantContext.getTenant()); survSummaryDTO.setTenantId(TenantContext.getTenant());
AlertSummaryVo alertSummaryVo = survAlertRecordService.getSummary(alertSummaryDTO); SurvSummaryVo survSummaryVo = commonService.getSurvSummary(survSummaryDTO);
return Result.OK(alertSummaryVo);
return Result.OK(survSummaryVo);
} }
/** /**

View File

@ -6,6 +6,7 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result; import org.jeecg.common.api.vo.Result;
import org.jeecg.common.dto.SurvSummaryDTO;
import org.jeecg.common.entity.PollutionSetVo; import org.jeecg.common.entity.PollutionSetVo;
import org.jeecg.common.entity.SurvDeviceDeploy; import org.jeecg.common.entity.SurvDeviceDeploy;
import org.jeecg.common.iot.common.VOIntegrateStatistic; import org.jeecg.common.iot.common.VOIntegrateStatistic;
@ -16,6 +17,7 @@ import org.jeecg.common.vo.CommonDataTrans;
import org.jeecg.common.vo.VOBigScreenSurvQ; import org.jeecg.common.vo.VOBigScreenSurvQ;
import org.jeecg.common.vo.VOHisResult; import org.jeecg.common.vo.VOHisResult;
import org.jeecg.common.vo.inner.*; import org.jeecg.common.vo.inner.*;
import org.jeecg.common.vo.statistic.SurvSummaryVo;
import org.jeecg.modules.appmana.service.ISurvDeviceDeployService; import org.jeecg.modules.appmana.service.ISurvDeviceDeployService;
import org.jeecg.modules.appmana.service.impl.CommonServiceImpl; import org.jeecg.modules.appmana.service.impl.CommonServiceImpl;
import org.jeecg.modules.appmana.service.impl.IotCommonP3ServiceImpl; import org.jeecg.modules.appmana.service.impl.IotCommonP3ServiceImpl;
@ -180,4 +182,16 @@ public class InnerController {
return new ArrayList<>(); return new ArrayList<>();
} }
} }
@ApiOperation(value = "13. 站点设备多项统计图", notes = "")
@ApiOperationSupport(order = 13)
@PostMapping(value = "/stationDeviceSummary")
public SurvSummaryVo stationDeviceSummary(@RequestBody SurvSummaryDTO survSummaryDTO) {
if(survSummaryDTO!=null){
return commonService.getSurvSummary(survSummaryDTO);
}else {
return new SurvSummaryVo();
}
}
} }

View File

@ -0,0 +1,38 @@
package org.jeecg.modules.appmana.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.jeecg.common.dto.statistic.FlexibleTimeQueryDTO;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 灵活监测数据Mapper
*/
@Mapper
public interface FlexibleMonitorMapper extends BaseMapper<Object> {
/**
* 灵活时间维度统计核心方法
*/
List<Map<String, Object>> getFlexibleTimeStats(@Param("query") FlexibleTimeQueryDTO query);
/**
* 检查表是否存在
*/
Integer checkTableExists(@Param("tableName") String tableName);
/**
* 获取表的数值列信息
*/
List<Map<String, String>> getTableColumns(@Param("tableName") String tableName);
/**
* 获取表统计信息
*/
Map<String, Object> getStatistics(@Param("tableName") String tableName);
}

View File

@ -0,0 +1,237 @@
<?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="org.jeecg.modules.appmana.mapper.FlexibleMonitorMapper">
<!-- ============================================================ -->
<!-- 1. 核心查询灵活时间维度统计MySQL 8.4 版本) -->
<!-- ============================================================ -->
<select id="getFlexibleTimeStats" resultType="java.util.LinkedHashMap">
<bind name="timeCol" value="query.timeColumn != null ? query.timeColumn : 'collect_time'"/>
<bind name="dimension" value="query.dimension.name()"/>
<bind name="fillEmpty" value="query.fillEmpty != null ? query.fillEmpty : true"/>
<bind name="emptyVal" value="query.emptyValue != null ? query.emptyValue : 0"/>
<!-- 判断是否使用自定义时间点 -->
<choose>
<when test="query.customTimePoints != null and query.customTimePoints.size() > 0">
<bind name="useCustomPoints" value="true"/>
</when>
<otherwise>
<bind name="useCustomPoints" value="false"/>
</otherwise>
</choose>
WITH RECURSIVE
<!-- ======== CTE 1: 生成时间序列 ======== -->
TimeGen AS (
<choose>
<when test="useCustomPoints">
<!-- 使用自定义时间点 -->
SELECT * FROM (VALUES
<foreach collection="query.customTimePoints" item="point" separator=",">
(#{point})
</foreach>
) AS Points(TimePoint)
</when>
<otherwise>
<!-- 自动生成时间序列 -->
<choose>
<when test="dimension == 'MINUTE'">
SELECT DATE_FORMAT(#{query.startTime}, '%Y-%m-%d %H:%i:00') AS TimePoint
UNION ALL
SELECT DATE_ADD(TimePoint, INTERVAL 1 MINUTE)
FROM TimeGen
WHERE TimePoint &lt; DATE_FORMAT(#{query.endTime}, '%Y-%m-%d %H:%i:00')
</when>
<when test="dimension == 'HOUR'">
SELECT DATE_FORMAT(#{query.startTime}, '%Y-%m-%d %H:00:00') AS TimePoint
UNION ALL
SELECT DATE_ADD(TimePoint, INTERVAL 1 HOUR)
FROM TimeGen
WHERE TimePoint &lt; DATE_FORMAT(#{query.endTime}, '%Y-%m-%d %H:00:00')
</when>
<when test="dimension == 'DAY'">
SELECT DATE_FORMAT(#{query.startTime}, '%Y-%m-%d 00:00:00') AS TimePoint
UNION ALL
SELECT DATE_ADD(TimePoint, INTERVAL 1 DAY)
FROM TimeGen
WHERE TimePoint &lt; DATE_FORMAT(#{query.endTime}, '%Y-%m-%d 00:00:00')
</when>
<when test="dimension == 'WEEK'">
SELECT DATE_FORMAT(#{query.startTime}, '%Y-%m-%d 00:00:00') AS TimePoint
UNION ALL
SELECT DATE_ADD(TimePoint, INTERVAL 1 WEEK)
FROM TimeGen
WHERE TimePoint &lt; DATE_FORMAT(#{query.endTime}, '%Y-%m-%d 00:00:00')
</when>
<when test="dimension == 'MONTH'">
SELECT DATE_FORMAT(#{query.startTime}, '%Y-%m-01 00:00:00') AS TimePoint
UNION ALL
SELECT DATE_ADD(TimePoint, INTERVAL 1 MONTH)
FROM TimeGen
WHERE TimePoint &lt; DATE_FORMAT(#{query.endTime}, '%Y-%m-01 00:00:00')
</when>
<when test="dimension == 'YEAR'">
SELECT DATE_FORMAT(#{query.startTime}, '%Y-01-01 00:00:00') AS TimePoint
UNION ALL
SELECT DATE_ADD(TimePoint, INTERVAL 1 YEAR)
FROM TimeGen
WHERE TimePoint &lt; DATE_FORMAT(#{query.endTime}, '%Y-01-01 00:00:00')
</when>
<otherwise>
-- 默认按小时
SELECT DATE_FORMAT(#{query.startTime}, '%Y-%m-%d %H:00:00') AS TimePoint
UNION ALL
SELECT DATE_ADD(TimePoint, INTERVAL 1 HOUR)
FROM TimeGen
WHERE TimePoint &lt; DATE_FORMAT(#{query.endTime}, '%Y-%m-%d %H:00:00')
</otherwise>
</choose>
</otherwise>
</choose>
),
<!-- ======== CTE 2: 聚合原始数据 ======== -->
Aggregated AS (
SELECT
<choose>
<when test="dimension == 'MINUTE'">
DATE_FORMAT(${timeCol}, '%Y-%m-%d %H:%i:00') AS TimePoint,
</when>
<when test="dimension == 'HOUR'">
DATE_FORMAT(${timeCol}, '%Y-%m-%d %H:00:00') AS TimePoint,
</when>
<when test="dimension == 'DAY'">
DATE_FORMAT(${timeCol}, '%Y-%m-%d 00:00:00') AS TimePoint,
</when>
<when test="dimension == 'WEEK'">
DATE_FORMAT(${timeCol}, '%Y-%m-%d 00:00:00') AS TimePoint,
</when>
<when test="dimension == 'MONTH'">
DATE_FORMAT(${timeCol}, '%Y-%m-01 00:00:00') AS TimePoint,
</when>
<when test="dimension == 'YEAR'">
DATE_FORMAT(${timeCol}, '%Y-01-01 00:00:00') AS TimePoint,
</when>
<otherwise>
DATE_FORMAT(${timeCol}, '%Y-%m-%d %H:00:00') AS TimePoint,
</otherwise>
</choose>
<foreach collection="query.valueColumns" item="col" separator=",">
MAX(${col}) AS ${col}_max,
MIN(${col}) AS ${col}_min,
AVG(${col}) AS ${col}_avg,
COUNT(${col}) AS ${col}_count
</foreach>
FROM ${query.tableName}
WHERE 1=1
<if test="query.startTime != null and query.endTime != null">
AND ${timeCol} >= #{query.startTime}
AND ${timeCol} &lt; #{query.endTime}
</if>
<if test="query.deviceColumn != null and query.deviceColumn != ''
and query.deviceId != null and query.deviceId != ''">
AND ${query.deviceColumn} = #{query.deviceId}
</if>
<!-- 如果使用自定义时间点,也过滤数据 -->
<if test="useCustomPoints and query.customTimePoints != null">
AND ${timeCol} >= (SELECT MIN(TimePoint) FROM TimeGen)
AND ${timeCol} &lt; (SELECT MAX(TimePoint) FROM TimeGen)
</if>
GROUP BY
<choose>
<when test="dimension == 'MINUTE'">
DATE_FORMAT(${timeCol}, '%Y-%m-%d %H:%i:00')
</when>
<when test="dimension == 'HOUR'">
DATE_FORMAT(${timeCol}, '%Y-%m-%d %H:00:00')
</when>
<when test="dimension == 'DAY'">
DATE_FORMAT(${timeCol}, '%Y-%m-%d 00:00:00')
</when>
<when test="dimension == 'WEEK'">
DATE_FORMAT(${timeCol}, '%Y-%m-%d 00:00:00')
</when>
<when test="dimension == 'MONTH'">
DATE_FORMAT(${timeCol}, '%Y-%m-01 00:00:00')
</when>
<when test="dimension == 'YEAR'">
DATE_FORMAT(${timeCol}, '%Y-01-01 00:00:00')
</when>
<otherwise>
DATE_FORMAT(${timeCol}, '%Y-%m-%d %H:00:00')
</otherwise>
</choose>
)
<!-- ======== 最终查询:左连接填充空值 ======== -->
SELECT
TimeGen.TimePoint AS time_point,
<choose>
<when test="fillEmpty">
<!-- 填充空值 -->
<foreach collection="query.valueColumns" item="col" separator=",">
IFNULL(Aggregated.${col}_max, ${emptyVal}) AS ${col}_max,
IFNULL(Aggregated.${col}_min, ${emptyVal}) AS ${col}_min,
IFNULL(Aggregated.${col}_avg, ${emptyVal}) AS ${col}_avg,
IFNULL(Aggregated.${col}_count, 0) AS ${col}_count
</foreach>
</when>
<otherwise>
<!-- 不填充保留NULL -->
<foreach collection="query.valueColumns" item="col" separator=",">
Aggregated.${col}_max AS ${col}_max,
Aggregated.${col}_min AS ${col}_min,
Aggregated.${col}_avg AS ${col}_avg,
Aggregated.${col}_count AS ${col}_count
</foreach>
</otherwise>
</choose>
FROM TimeGen
LEFT JOIN Aggregated ON TimeGen.TimePoint = Aggregated.TimePoint
ORDER BY TimeGen.TimePoint ASC
</select>
<!-- ============================================================ -->
<!-- 2. 检查表是否存在 -->
<!-- ============================================================ -->
<select id="checkTableExists" resultType="java.lang.Integer">
SELECT COUNT(1)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #{tableName}
AND TABLE_SCHEMA = DATABASE()
</select>
<!-- ============================================================ -->
<!-- 3. 获取表的数值列信息 -->
<!-- ============================================================ -->
<select id="getTableColumns" resultType="java.util.HashMap">
SELECT
COLUMN_NAME AS columnName,
DATA_TYPE AS dataType,
IS_NULLABLE AS isNullable,
NUMERIC_PRECISION AS numericPrecision,
NUMERIC_SCALE AS numericScale
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #{tableName}
AND TABLE_SCHEMA = DATABASE()
AND DATA_TYPE IN ('int', 'bigint', 'smallint', 'tinyint',
'decimal', 'numeric', 'float', 'double',
'real', 'money', 'smallmoney')
ORDER BY ORDINAL_POSITION
</select>
<!-- ============================================================ -->
<!-- 4. 获取表统计信息 -->
<!-- ============================================================ -->
<select id="getStatistics" resultType="java.util.HashMap">
SELECT
COUNT(1) AS totalRecords,
MIN(collect_time) AS earliestTime,
MAX(collect_time) AS latestTime,
COUNT(DISTINCT device_code) AS deviceCount
FROM ${tableName}
</select>
</mapper>

View File

@ -0,0 +1,202 @@
package org.jeecg.modules.appmana.service;
import org.jeecg.common.dto.statistic.FlexibleTimeQueryDTO;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 灵活时间维度监测数据统计服务
*/
public interface FlexibleMonitorService {
// ==================== 核心方法 ====================
/**
* 最底层通用方法所有其他方法最终都调这个方法
*/
List<Map<String, Object>> getFlexibleTimeStats(FlexibleTimeQueryDTO query);
// ==================== 按小时统计 ====================
/**
* 查询最近N小时数据最常用
*
* @param tableName 表名
* @param timeColumn 时间字段名collect_time, create_time, record_time
* @param deviceColumn 设备字段名device_code, device_id
* @param deviceId 设备ID
* @param valueColumns 监测列列表
* @param hours 查询多少小时默认24
*/
List<Map<String, Object>> queryHourlyStats(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
Integer hours
);
/**
* 查询指定时间范围的按小时统计数据
*/
List<Map<String, Object>> queryHourlyStatsByRange(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
LocalDateTime startTime,
LocalDateTime endTime
);
// ==================== 按天统计 ====================
/**
* 查询最近N天数据
*/
List<Map<String, Object>> queryDailyStats(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
Integer days
);
/**
* 查询指定时间范围的按天统计数据
*/
List<Map<String, Object>> queryDailyStatsByRange(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
LocalDateTime startTime,
LocalDateTime endTime
);
// ==================== 按月统计 ====================
/**
* 查询最近N个月数据
*/
List<Map<String, Object>> queryMonthlyStats(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
Integer months
);
/**
* 查询指定时间范围的按月统计数据
*/
List<Map<String, Object>> queryMonthlyStatsByRange(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
LocalDateTime startTime,
LocalDateTime endTime
);
// ==================== 按年统计 ====================
/**
* 查询最近N年数据
*/
List<Map<String, Object>> queryYearlyStats(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
Integer years
);
/**
* 查询指定时间范围的按年统计数据
*/
List<Map<String, Object>> queryYearlyStatsByRange(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
LocalDateTime startTime,
LocalDateTime endTime
);
// ==================== 按分钟统计 ====================
/**
* 查询最近N分钟数据实时监控用
*/
List<Map<String, Object>> queryMinuteStats(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
Integer minutes
);
// ==================== 自定义时间点 ====================
/**
* 使用自定义时间点数组查询只查指定时间点的数据
*/
List<Map<String, Object>> queryStatsWithCustomPoints(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
List<LocalDateTime> timePoints
);
// ==================== 多设备对比 ====================
/**
* 批量查询多个设备对比用
*/
Map<String, List<Map<String, Object>>> queryMultiDeviceStats(
String tableName,
String timeColumn,
String deviceColumn,
List<String> deviceIds,
List<String> valueColumns,
FlexibleTimeQueryDTO.TimeDimension dimension,
Integer timeRange,
LocalDateTime startTime,
LocalDateTime endTime
);
// ==================== 辅助方法 ====================
/**
* 自动识别表中的监测列数值类型
*/
List<String> autoDetectColumns(String tableName);
/**
* 获取表统计信息
*/
Map<String, Object> getTableStatistics(String tableName);
}

View File

@ -1,20 +1,24 @@
package org.jeecg.modules.appmana.service.impl; package org.jeecg.modules.appmana.service.impl;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.config.TenantContext; import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CommonConstants; import org.jeecg.common.constant.*;
import org.jeecg.common.constant.DeviceReadConstants;
import org.jeecg.common.constant.PollutionConstants;
import org.jeecg.common.constant.enums.PollutionEnum; import org.jeecg.common.constant.enums.PollutionEnum;
import org.jeecg.common.dto.CommonDTO; import org.jeecg.common.dto.CommonDTO;
import org.jeecg.common.dto.SurvSummaryDTO;
import org.jeecg.common.entity.*; import org.jeecg.common.entity.*;
import org.jeecg.common.util.*;
import org.jeecg.common.vo.VOHisResult; import org.jeecg.common.vo.VOHisResult;
import org.jeecg.common.vo.iot.common.SurvItemInfo;
import org.jeecg.common.vo.statistic.AlertReport; import org.jeecg.common.vo.statistic.AlertReport;
import org.jeecg.common.vo.statistic.AlertSummaryVo;
import org.jeecg.common.vo.statistic.ScreenIndexSummaryDetailVo; import org.jeecg.common.vo.statistic.ScreenIndexSummaryDetailVo;
import org.jeecg.common.vo.statistic.SurvSummaryVo;
import org.jeecg.modules.appmana.service.*; import org.jeecg.modules.appmana.service.*;
import org.jeecg.modules.appmana.utils.HttpServletRequestUtil; import org.jeecg.modules.appmana.utils.HttpServletRequestUtil;
import org.jeecg.modules.appmana.utils.MonitoringDataRichTextBuilder; import org.jeecg.modules.appmana.utils.MonitoringDataRichTextBuilder;
@ -29,6 +33,7 @@ import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
@Service @Service
@Slf4j @Slf4j
@ -47,6 +52,10 @@ public class CommonServiceImpl {
@Lazy @Lazy
private SurvConfigServiceImpl configService; private SurvConfigServiceImpl configService;
@Autowired
@Lazy
private SurvDeviceDeployServiceImpl deviceDeployService;
@Autowired @Autowired
@Lazy @Lazy
private ScEquZhibiaoServiceImpl zhibiaoService; private ScEquZhibiaoServiceImpl zhibiaoService;
@ -55,6 +64,9 @@ public class CommonServiceImpl {
@Lazy @Lazy
private ISurvAlertRecordService alertRecordService; private ISurvAlertRecordService alertRecordService;
@Autowired
private FlexibleMonitorService flexibleMonitorService;
/** /**
* 获取监测设备的数据 * 获取监测设备的数据
*/ */
@ -458,4 +470,302 @@ public class CommonServiceImpl {
return MonitoringDataRichTextBuilder.buildRichText(stats); return MonitoringDataRichTextBuilder.buildRichText(stats);
} }
public SurvSummaryVo getSurvSummary(SurvSummaryDTO survSummaryDTO) {
SurvSummaryVo survSummaryVo = new SurvSummaryVo();
Map<String, SurvItemInfo> itemInfo = new HashMap<>();
List<SurvItemInfo> itemList = new ArrayList<>();
List<String> timeList = new ArrayList<>();
Map<String,List<String>> dataMap = new HashMap<>();
if(StringUtils.isNotBlank(survSummaryDTO.getStationCode())){
//获取站点下的所有设备
List<String> deployTypes = new ArrayList<>();
deployTypes.add(PollutionConstants.SOIL_SURV);
deployTypes.add(PollutionConstants.AIR_SURV);
deployTypes.add(PollutionConstants.WATER_QULITY);
deployTypes.add(PollutionConstants.STINK);
deployTypes.add(PollutionConstants.WATER_LIVE);
deployTypes.add(PollutionConstants.WATER_ORIENT);
List<SurvDeviceDeploy> deviceList = deviceDeployService.getDeviceListByStation(survSummaryDTO.getStationCode(),deployTypes);
if(deviceList!=null && !deviceList.isEmpty()){
for (SurvDeviceDeploy deploy : deviceList) {
survSummaryDTO.setDeployId(deploy.getId());
SurvSummaryVo temp = getDeviceSummary(deploy,survSummaryDTO.getSummaryMode(),survSummaryDTO.getStartTime(),survSummaryDTO.getEndTime());
itemInfo.putAll(temp.getItemInfo());
itemList.addAll(temp.getItemList());
dataMap.putAll(temp.getDataMap());
timeList = temp.getTimeList();
}
survSummaryVo.setItemInfo(itemInfo);
survSummaryVo.setItemList(itemList);
survSummaryVo.setDataMap(dataMap);
survSummaryVo.setTimeList(timeList);
}
}else{
SurvDeviceDeploy deploy = deviceDeployService.getById(survSummaryDTO.getDeployId());
Assert.notNull(deploy,"设备不存在");
survSummaryVo = getDeviceSummary(deploy,survSummaryDTO.getSummaryMode(),survSummaryDTO.getStartTime(),survSummaryDTO.getEndTime());
}
return survSummaryVo;
}
public SurvSummaryVo getDeviceSummary(SurvDeviceDeploy deploy,String summaryMode,String startTime,String endTime) {
SurvSummaryVo survSummaryVo = new SurvSummaryVo();
String tableName = "";
String timeColumn = "";
String deviceIdColumn = "";
String timeFormat = "";
LocalDateTime startDate = null;
LocalDateTime endDate = null;
if(StringUtils.isBlank(summaryMode)){
summaryMode = IotConstants.month_days;//默认月查询
}
List<ScEquZhibiao> zhibiaoList = zhibiaoService.getListByEquid(deploy.getId());
Map<String,ScEquZhibiao> zhibiaoMap = new HashMap<>();
List<String> zhibiaoKeys = new ArrayList<>();
List<SurvItemInfo> survItemInfos = new ArrayList<>();
if (zhibiaoList!=null && !zhibiaoList.isEmpty()){
zhibiaoList.forEach(zhibiao ->{
zhibiaoMap.put(zhibiao.getEntityField(),zhibiao);
zhibiaoKeys.add(zhibiao.getEntityField());
SurvItemInfo survItemInfo = new SurvItemInfo();
PollutionEnum pollutionEnum = PollutionEnum.catchPollution(zhibiao.getEntityField());
survItemInfo.setItemName(zhibiao.getName());
survItemInfo.setColor(pollutionEnum.getColor());
survItemInfo.setHighVal(zhibiao.getValHeight()!=null ?zhibiao.getValHeight()+"":null);
survItemInfo.setLowVal(zhibiao.getValLow()!=null?zhibiao.getValLow()+"":null);
survItemInfo.setUnit(zhibiao.getNuit());
survItemInfo.setEntity(zhibiao.getEntityField());
survItemInfo.setPid(zhibiao.getEleKey());
survItemInfos.add(survItemInfo);
});
}
Map<String, SurvItemInfo> itemMap = survItemInfos.stream()
.collect(Collectors.toMap(SurvItemInfo::getEntity, itemss -> itemss));
survSummaryVo.setItemList(survItemInfos);
survSummaryVo.setItemInfo(itemMap);
switch (deploy.getDeployType()){
case PollutionConstants.SOIL_SURV:
case PollutionConstants.WATER_QULITY:
tableName = "surv_hisdata_soil";
timeColumn = "DATA_DATE_TIME";
deviceIdColumn = "DEPLOY_ID";
break;
case PollutionConstants.AIR_SURV:
tableName = "surv_hisdata_air";
timeColumn = "DATA_DATE_TIME";
deviceIdColumn = "DEPLOY_ID";
break;
case PollutionConstants.STINK:
tableName = "surv_hisdata_vocs";
timeColumn = "DATA_DATE_TIME";
deviceIdColumn = "DEPLOY_ID";
break;
case PollutionConstants.WATER_LIVE:
tableName = "surv_hisdata_livestockwater";
timeColumn = "DATA_DATE_TIME";
deviceIdColumn = "DEVICE_ID";
break;
case PollutionConstants.WATER_ORIENT:
tableName = "surv_hisdata_orientwater";
timeColumn = "DATA_DATE_TIME";
deviceIdColumn = "DEVICE_ID";
break;
default:
break;
}
List<String> dbFields = NamingConverter.camelsToDbFields(zhibiaoKeys);
List<Map<String, Object>> result = new ArrayList<>();
if(IotConstants.day_hours.equals(summaryMode)){
boolean isNow = true;
timeFormat = "d日H时";
if(StringUtils.isNotBlank(startTime)){
isNow = false;
startDate = DateParseUtils.parseToLocalDateTime(startTime+" 00:00:00","yyyy-MM-dd HH:mm:ss");
}
if(StringUtils.isNotBlank(endTime)){
endDate = DateParseUtils.parseToLocalDateTime(endTime+" 23:59:59","yyyy-MM-dd HH:mm:ss").withNano(999999000);
}
if(isNow){
result = flexibleMonitorService.queryHourlyStats(
tableName, // 表名
timeColumn, // 时间字段
deviceIdColumn, // 设备字段
deploy.getId(), // 设备ID
dbFields, // 监测列
24
);
}else{
result = flexibleMonitorService.queryHourlyStatsByRange(
tableName, // 表名
timeColumn, // 时间字段
deviceIdColumn, // 设备字段
deploy.getId(), // 设备ID
dbFields, // 监测列
startDate,
endDate
);
}
}
else if(IotConstants.custom_days.equals(summaryMode)){
boolean isNow = true;
timeFormat = "M月d日";
if(StringUtils.isNotBlank(startTime)){
isNow = false;
startDate = DateParseUtils.parseToLocalDateTime(startTime+" 00:00:00","yyyy-MM-dd HH:mm:ss");
}
if(StringUtils.isNotBlank(endTime)){
endDate = DateParseUtils.parseToLocalDateTime(endTime+" 23:59:59","yyyy-MM-dd HH:mm:ss");
}
if(isNow){
result = flexibleMonitorService.queryDailyStats(
tableName, // 表名
timeColumn, // 时间字段
deviceIdColumn, // 设备字段
deploy.getId(), // 设备ID
dbFields, // 监测列
30
);
}else{
result = flexibleMonitorService.queryDailyStatsByRange(
tableName, // 表名
timeColumn, // 时间字段
deviceIdColumn, // 设备字段
deploy.getId(), // 设备ID
dbFields, // 监测列
startDate,
endDate
);
}
}
else if(IotConstants.month_days.equals(summaryMode)){
boolean isNow = true;
timeFormat = "M月d日";
if(StringUtils.isNotBlank(startTime)){
isNow = false;
startDate = DateParseUtils.parseToLocalDateTime(startTime+"-01 00:00:00","yyyy-MM-dd HH:mm:ss");
}
if(StringUtils.isNotBlank(endTime)){
endDate = DateParseUtils.parseToLocalDateTime(endTime+"-01 23:59:59","yyyy-MM-dd HH:mm:ss");
endDate = DateTimeRangeUtil.getMonthEnd(endDate).withNano(999999000);
}
if(isNow){
result = flexibleMonitorService.queryDailyStats(
tableName, // 表名
timeColumn, // 时间字段
deviceIdColumn, // 设备字段
deploy.getId(), // 设备ID
dbFields, // 监测列
30
);
}else{
result = flexibleMonitorService.queryDailyStatsByRange(
tableName, // 表名
timeColumn, // 时间字段
deviceIdColumn, // 设备字段
deploy.getId(), // 设备ID
dbFields, // 监测列
startDate,
endDate
);
}
}
else if(IotConstants.year_months.equals(summaryMode)){
boolean isNow = true;
timeFormat = "yy年M月";
if(StringUtils.isNotBlank(startTime)){
isNow = false;
startDate = DateParseUtils.parseToLocalDateTime(startTime+"-01-01 00:00:00","yyyy-MM-dd HH:mm:ss");
}
if(StringUtils.isNotBlank(endTime)){
endDate = DateParseUtils.parseToLocalDateTime(endTime+"-12-31 23:59:59","yyyy-MM-dd HH:mm:ss");
endDate = DateTimeRangeUtil.getYearEnd(endDate).withNano(999999000);
}
if(isNow){
result = flexibleMonitorService.queryMonthlyStats(
tableName, // 表名
timeColumn, // 时间字段
deviceIdColumn, // 设备字段
deploy.getId(), // 设备ID
dbFields, // 监测列
3
);
}else{
result = flexibleMonitorService.queryMonthlyStatsByRange(
tableName, // 表名
timeColumn, // 时间字段
deviceIdColumn, // 设备字段
deploy.getId(), // 设备ID
dbFields, // 监测列
startDate,
endDate
);
}
}
List<String> timeList = new ArrayList<>();
Map<String,List<String>> dataMap = new HashMap<>();
if(result!=null && !result.isEmpty()){
for (Map<String, Object> item : result) {
String timePoint = item.get(StatisticConstants.RESULT_TIME_COLUMN).toString();
timeList.add(timePoint);
for (String db : dbFields) {
String dbKey = db+StatisticConstants.RESULT_VALUE_MAX;
String value = item.get(dbKey).toString();
String zhibiaoKey = NamingConverter.dbFieldToCamel(dbKey.replace(StatisticConstants.RESULT_VALUE_MAX,""));
List<String> zhibiaoData = dataMap.get(zhibiaoKey);
if(zhibiaoData==null){
zhibiaoData = new ArrayList<>();
}
zhibiaoData.add(value);
dataMap.put(zhibiaoKey,zhibiaoData);
}
}
}
timeList = DateRangeUtil.convertDateFormatStream(timeList,"yyyy-MM-dd HH:mm:ss",timeFormat);
survSummaryVo.setTimeList(timeList);
survSummaryVo.setDataMap(dataMap);
return survSummaryVo;
}
} }

View File

@ -0,0 +1,394 @@
package org.jeecg.modules.appmana.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.dto.statistic.FlexibleTimeQueryDTO;
import org.jeecg.modules.appmana.mapper.FlexibleMonitorMapper;
import org.jeecg.modules.appmana.service.FlexibleMonitorService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
@Slf4j
@Service
public class FlexibleMonitorServiceImpl implements FlexibleMonitorService {
@Resource
private FlexibleMonitorMapper flexibleMonitorMapper;
// ==================== 核心方法 ====================
@Override
public List<Map<String, Object>> getFlexibleTimeStats(FlexibleTimeQueryDTO query) {
// 参数自动补全
autoCompleteParams(query);
logQueryInfo(query);
long start = System.currentTimeMillis();
List<Map<String, Object>> result = flexibleMonitorMapper.getFlexibleTimeStats(query);
log.info("查询完成,耗时: {}ms, 记录数: {}", System.currentTimeMillis() - start, result.size());
return result;
}
// ==================== 按小时统计 ====================
@Override
public List<Map<String, Object>> queryHourlyStats(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
Integer hours) {
if (hours == null) hours = 24;
LocalDateTime endTime = LocalDateTime.now();
LocalDateTime startTime = endTime.minusHours(hours);
return queryHourlyStatsByRange(tableName, timeColumn, deviceColumn, deviceId, valueColumns, startTime, endTime);
}
@Override
public List<Map<String, Object>> queryHourlyStatsByRange(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
LocalDateTime startTime,
LocalDateTime endTime) {
FlexibleTimeQueryDTO query = buildQuery(
tableName, timeColumn, deviceColumn, deviceId, valueColumns,
FlexibleTimeQueryDTO.TimeDimension.HOUR, startTime, endTime
);
return getFlexibleTimeStats(query);
}
// ==================== 按天统计 ====================
@Override
public List<Map<String, Object>> queryDailyStats(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
Integer days) {
if (days == null) days = 30;
LocalDateTime endTime = LocalDateTime.now();
LocalDateTime startTime = endTime.minusDays(days);
return queryDailyStatsByRange(tableName, timeColumn, deviceColumn, deviceId, valueColumns, startTime, endTime);
}
@Override
public List<Map<String, Object>> queryDailyStatsByRange(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
LocalDateTime startTime,
LocalDateTime endTime) {
FlexibleTimeQueryDTO query = buildQuery(
tableName, timeColumn, deviceColumn, deviceId, valueColumns,
FlexibleTimeQueryDTO.TimeDimension.DAY, startTime, endTime
);
return getFlexibleTimeStats(query);
}
// ==================== 按月统计 ====================
@Override
public List<Map<String, Object>> queryMonthlyStats(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
Integer months) {
if (months == null) months = 12;
LocalDateTime endTime = LocalDateTime.now();
LocalDateTime startTime = endTime.minusMonths(months);
return queryMonthlyStatsByRange(tableName, timeColumn, deviceColumn, deviceId, valueColumns, startTime, endTime);
}
@Override
public List<Map<String, Object>> queryMonthlyStatsByRange(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
LocalDateTime startTime,
LocalDateTime endTime) {
FlexibleTimeQueryDTO query = buildQuery(
tableName, timeColumn, deviceColumn, deviceId, valueColumns,
FlexibleTimeQueryDTO.TimeDimension.MONTH, startTime, endTime
);
return getFlexibleTimeStats(query);
}
// ==================== 按年统计 ====================
@Override
public List<Map<String, Object>> queryYearlyStats(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
Integer years) {
if (years == null) years = 5;
LocalDateTime endTime = LocalDateTime.now();
LocalDateTime startTime = endTime.minusYears(years);
return queryYearlyStatsByRange(tableName, timeColumn, deviceColumn, deviceId, valueColumns, startTime, endTime);
}
@Override
public List<Map<String, Object>> queryYearlyStatsByRange(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
LocalDateTime startTime,
LocalDateTime endTime) {
FlexibleTimeQueryDTO query = buildQuery(
tableName, timeColumn, deviceColumn, deviceId, valueColumns,
FlexibleTimeQueryDTO.TimeDimension.YEAR, startTime, endTime
);
return getFlexibleTimeStats(query);
}
// ==================== 按分钟统计 ====================
@Override
public List<Map<String, Object>> queryMinuteStats(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
Integer minutes) {
if (minutes == null) minutes = 60;
LocalDateTime endTime = LocalDateTime.now();
LocalDateTime startTime = endTime.minusMinutes(minutes);
FlexibleTimeQueryDTO query = buildQuery(
tableName, timeColumn, deviceColumn, deviceId, valueColumns,
FlexibleTimeQueryDTO.TimeDimension.MINUTE, startTime, endTime
);
return getFlexibleTimeStats(query);
}
// ==================== 自定义时间点 ====================
@Override
public List<Map<String, Object>> queryStatsWithCustomPoints(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
List<LocalDateTime> timePoints) {
if (timePoints == null || timePoints.isEmpty()) {
throw new IllegalArgumentException("时间点数组不能为空");
}
FlexibleTimeQueryDTO query = new FlexibleTimeQueryDTO();
query.setTableName(tableName);
query.setTimeColumn(timeColumn);
query.setDeviceColumn(deviceColumn);
query.setDeviceId(deviceId);
query.setValueColumns(valueColumns);
query.setDimension(FlexibleTimeQueryDTO.TimeDimension.HOUR);
query.setCustomTimePoints(timePoints);
query.setFillEmpty(true);
query.setEmptyValue(0);
return getFlexibleTimeStats(query);
}
// ==================== 多设备对比 ====================
@Override
public Map<String, List<Map<String, Object>>> queryMultiDeviceStats(
String tableName,
String timeColumn,
String deviceColumn,
List<String> deviceIds,
List<String> valueColumns,
FlexibleTimeQueryDTO.TimeDimension dimension,
Integer timeRange,
LocalDateTime startTime,
LocalDateTime endTime) {
if (deviceIds == null || deviceIds.isEmpty()) {
throw new IllegalArgumentException("设备ID列表不能为空");
}
// 如果没有指定时间范围根据维度自动计算
if (startTime == null || endTime == null) {
endTime = LocalDateTime.now();
if (timeRange == null) timeRange = getDefaultTimeRange(dimension);
switch (dimension) {
case MINUTE:
startTime = endTime.minusMinutes(timeRange);
break;
case HOUR:
startTime = endTime.minusHours(timeRange);
break;
case DAY:
startTime = endTime.minusDays(timeRange);
break;
case MONTH:
startTime = endTime.minusMonths(timeRange);
break;
case YEAR:
startTime = endTime.minusYears(timeRange);
break;
default:
startTime = endTime.minusHours(24);
}
}
Map<String, List<Map<String, Object>>> resultMap = new LinkedHashMap<>();
for (String deviceId : deviceIds) {
FlexibleTimeQueryDTO query = buildQuery(
tableName, timeColumn, deviceColumn, deviceId, valueColumns,
dimension, startTime, endTime
);
List<Map<String, Object>> data = getFlexibleTimeStats(query);
resultMap.put(deviceId, data);
}
return resultMap;
}
// ==================== 辅助方法 ====================
@Override
public List<String> autoDetectColumns(String tableName) {
Integer count = flexibleMonitorMapper.checkTableExists(tableName);
if (count == null || count == 0) {
throw new IllegalArgumentException("表不存在: " + tableName);
}
List<Map<String, String>> columns = flexibleMonitorMapper.getTableColumns(tableName);
List<String> excludeColumns = Arrays.asList(
"id", "create_time", "update_time", "delete_flag", "version",
"collect_time", "record_time", "device_id", "device_code",
"tenant_id", "org_id", "status", "sort", "remark",
"is_deleted", "creator", "modifier", "create_by", "update_by"
);
return columns.stream()
.map(col -> col.get("columnName"))
.filter(col -> !excludeColumns.contains(col.toLowerCase()))
.sorted()
.collect(java.util.stream.Collectors.toList());
}
@Override
public Map<String, Object> getTableStatistics(String tableName) {
return flexibleMonitorMapper.getStatistics(tableName);
}
// ==================== 私有方法 ====================
/**
* 构建查询对象
*/
private FlexibleTimeQueryDTO buildQuery(
String tableName,
String timeColumn,
String deviceColumn,
String deviceId,
List<String> valueColumns,
FlexibleTimeQueryDTO.TimeDimension dimension,
LocalDateTime startTime,
LocalDateTime endTime) {
FlexibleTimeQueryDTO query = new FlexibleTimeQueryDTO();
query.setTableName(tableName);
query.setTimeColumn(timeColumn);
query.setDeviceColumn(deviceColumn);
query.setDeviceId(deviceId);
query.setValueColumns(valueColumns);
query.setDimension(dimension);
query.setStartTime(startTime);
query.setEndTime(endTime);
query.setFillEmpty(true);
query.setEmptyValue(0);
query.setAvgScale(2);
return query;
}
/**
* 根据维度获取默认时间范围
*/
private int getDefaultTimeRange(FlexibleTimeQueryDTO.TimeDimension dimension) {
switch (dimension) {
case MINUTE: return 60;
case HOUR: return 24;
case DAY: return 30;
case MONTH: return 12;
case YEAR: return 5;
default: return 24;
}
}
/**
* 自动补全参数
*/
private void autoCompleteParams(FlexibleTimeQueryDTO query) {
if (query.getFillEmpty() == null) query.setFillEmpty(true);
if (query.getEmptyValue() == null) query.setEmptyValue(0);
if (query.getTimeColumn() == null) query.setTimeColumn("DATA_DATE_TIME");
if (query.getAvgScale() == null) query.setAvgScale(2);
if (query.getDeviceColumn() == null && query.getDeviceId() != null) {
query.setDeviceColumn("DEPLOY_ID");
}
}
/**
* 记录日志
*/
private void logQueryInfo(FlexibleTimeQueryDTO query) {
log.info("=== 灵活时间统计查询 ===");
log.info("表: {}, 时间字段: {}, 设备: {}",
query.getTableName(), query.getTimeColumn(), query.getDeviceId());
log.info("维度: {}, 监测列: {}, 小数位数: {}",
query.getDimension(), query.getValueColumns(), query.getAvgScale());
}
}

View File

@ -1,6 +1,7 @@
package org.jeecg.system.applet.client; package org.jeecg.system.applet.client;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import org.jeecg.common.dto.SurvSummaryDTO;
import org.jeecg.common.entity.PollutionSetVo; import org.jeecg.common.entity.PollutionSetVo;
import org.jeecg.common.iot.common.VOIntegrateStatistic; import org.jeecg.common.iot.common.VOIntegrateStatistic;
import org.jeecg.common.iot.common.VOSurvIntegrateParam; import org.jeecg.common.iot.common.VOSurvIntegrateParam;
@ -11,6 +12,7 @@ import org.jeecg.common.vo.VOBigScreenSurvQ;
import org.jeecg.common.vo.VOHisResult; import org.jeecg.common.vo.VOHisResult;
import org.jeecg.common.vo.inner.*; import org.jeecg.common.vo.inner.*;
import org.jeecg.common.vo.iot.common.Result; import org.jeecg.common.vo.iot.common.Result;
import org.jeecg.common.vo.statistic.SurvSummaryVo;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@ -93,4 +95,11 @@ public interface ZhAdminFeignClient {
*/ */
@PostMapping("/appmana/inner/api/constructStink") @PostMapping("/appmana/inner/api/constructStink")
List<CommonDataTrans> constructStink(@RequestBody ConstructStink constructStink); List<CommonDataTrans> constructStink(@RequestBody ConstructStink constructStink);
/**
* 站点设备多项统计图
*/
@PostMapping("/appmana/inner/api/stationDeviceSummary")
SurvSummaryVo stationDeviceSummary(@RequestBody SurvSummaryDTO survSummaryDTO);
} }

View File

@ -3,9 +3,12 @@ package org.jeecg.system.applet.controller;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.dto.SurvSummaryDTO;
import org.jeecg.common.util.R; import org.jeecg.common.util.R;
import org.jeecg.common.vo.statistic.AlertSummaryVo; import org.jeecg.common.vo.statistic.AlertSummaryVo;
import org.jeecg.common.vo.statistic.SurvSummaryVo;
import org.jeecg.system.applet.annotation.ApiLogin; import org.jeecg.system.applet.annotation.ApiLogin;
import org.jeecg.system.applet.client.ZhAdminFeignClient;
import org.jeecg.system.applet.dto.AlertSummaryDTO; import org.jeecg.system.applet.dto.AlertSummaryDTO;
import org.jeecg.system.applet.service.ISurvAlertRecordService; import org.jeecg.system.applet.service.ISurvAlertRecordService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -28,6 +31,21 @@ import org.springframework.web.bind.annotation.RestController;
public class SurvAlertRecordController { public class SurvAlertRecordController {
@Autowired @Autowired
private ISurvAlertRecordService survAlertRecordService; private ISurvAlertRecordService survAlertRecordService;
@Autowired
private ZhAdminFeignClient zhAdminFeignClient;
/**
* 站点设备
*
* @return
*/
@ApiOperation(value="预警曲线", notes="预警曲线")
@PostMapping(value = "/alertSummary")
@ApiLogin
public R<SurvSummaryVo> alertSummary(@RequestBody SurvSummaryDTO survSummaryDTO) {
SurvSummaryVo survSummaryVo = zhAdminFeignClient.stationDeviceSummary(survSummaryDTO);
return R.ok(survSummaryVo);
}
/** /**
* 监控摄像头分页列表查询 * 监控摄像头分页列表查询
@ -35,9 +53,9 @@ public class SurvAlertRecordController {
* @return * @return
*/ */
@ApiOperation(value="预警曲线", notes="预警曲线") @ApiOperation(value="预警曲线", notes="预警曲线")
@PostMapping(value = "/alertSummary") @PostMapping(value = "/alertSummary2")
@ApiLogin @ApiLogin
public R<AlertSummaryVo> alertSummary(@RequestBody AlertSummaryDTO alertSummaryDTO) { public R<AlertSummaryVo> alertSummary2(@RequestBody AlertSummaryDTO alertSummaryDTO) {
AlertSummaryVo alertSummaryVo = survAlertRecordService.getSummary(alertSummaryDTO); AlertSummaryVo alertSummaryVo = survAlertRecordService.getSummary(alertSummaryDTO);
return R.ok(alertSummaryVo); return R.ok(alertSummaryVo);
} }

View File

@ -99,6 +99,11 @@ public interface IotConstants {
*/ */
String month_days = "monthDays"; String month_days = "monthDays";
/**
* 1月日数据
*/
String custom_days = "customDays";
/** /**
* 1年月数据 * 1年月数据
*/ */

View File

@ -0,0 +1,24 @@
package org.jeecg.common.constant;
public interface StatisticConstants {
/*
* 时间点列名
*/
String RESULT_TIME_COLUMN = "time_point";
/*
* 最大值后缀
*/
String RESULT_VALUE_MAX = "_max";
/*
* 最小值后缀
*/
String RESULT_VALUE_MIN = "_min";
/*
* 平均值后缀
*/
String RESULT_VALUE_AVG = "_avg";
}

View File

@ -0,0 +1,28 @@
package org.jeecg.common.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 监测统计曲线统一参数
*/
@Data
public class SurvSummaryDTO {
@ApiModelProperty("站点编号")
private String stationCode;
@ApiModelProperty("设备ID")
private String deployId;
@ApiModelProperty("统计模式")
private String summaryMode;
@ApiModelProperty("开始时间")
private String startTime;
@ApiModelProperty("结束时间")
private String endTime;
@ApiModelProperty("租户ID")
private String tenantId;
}

View File

@ -0,0 +1,66 @@
package org.jeecg.common.dto.statistic;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
/**
* 灵活时间维度查询参数
*/
@Data
public class FlexibleTimeQueryDTO {
// ========== 基础配置 ==========
/** 表名 */
private String tableName;
/** 时间列名 */
private String timeColumn = "DATA_DATE_TIME";
/** 设备列名 */
private String deviceColumn;
/** 设备ID */
private String deviceId;
/** 监测列列表 */
private List<String> valueColumns;
// ========== 时间维度配置 ==========
/** 时间维度HOUR, DAY, MONTH, YEAR, MINUTE, WEEK */
private TimeDimension dimension;
// ========== 方式一时间范围模式 ==========
/** 开始时间 */
private LocalDateTime startTime;
/** 结束时间 */
private LocalDateTime endTime;
// ========== 方式二自定义时间点数组模式 ==========
/** 自定义时间点数组 */
private List<LocalDateTime> customTimePoints;
// ========== 其他配置 ==========
/** 是否填充空值默认true */
private Boolean fillEmpty = true;
/** 空值填充内容默认0 */
private Object emptyValue = 0;
/** 平均值保留小数位数默认2 */
private Integer avgScale = 2;
// ========== 枚举时间维度 ==========
public enum TimeDimension {
MINUTE, // 分钟
HOUR, // 小时
DAY, //
WEEK, //
MONTH, //
YEAR //
}
}

View File

@ -0,0 +1,36 @@
package org.jeecg.common.dto.statistic;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* 多设备查询参数
*/
@Data
public class MultiDeviceQueryDTO {
/** 表名 */
private String tableName;
/** 设备列名 */
private String deviceColumn = "DEPLOY_ID";
/** 时间列名 */
private String timeColumn = "DATA_DATE_TIME";
/** 设备ID列表 */
private List<String> deviceIds;
/** 监测列列表 */
private List<String> valueColumns;
/** 时间维度 */
private FlexibleTimeQueryDTO.TimeDimension dimension = FlexibleTimeQueryDTO.TimeDimension.HOUR;
/** 开始时间 */
private Date startTime;
/** 结束时间 */
private Date endTime;
}

View File

@ -0,0 +1,31 @@
package org.jeecg.common.dto.statistic;
import lombok.Data;
import java.util.Date;
/**
* 时间点DTO
*/
@Data
public class TimePointDTO {
/** 时间 */
private Date time;
/** 格式化后的时间 */
private String formattedTime;
/** 时间戳 */
private Long timestamp;
/** 显示标签 */
private String label;
public TimePointDTO() {}
public TimePointDTO(Date time, String formattedTime) {
this.time = time;
this.formattedTime = formattedTime;
this.timestamp = time != null ? time.getTime() : null;
}
}

View File

@ -0,0 +1,440 @@
package org.jeecg.common.util;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
/**
* 日期时间工具类
* 专注于日期时间的格式化和解析所有异常内部处理
*
* @author Your Name
* @date 2026-07-28
*/
public class DateParseUtils {
// 常用日期时间格式常量
public static final String PATTERN_YMD = "yyyy-MM-dd";
public static final String PATTERN_YMDHMS = "yyyy-MM-dd HH:mm:ss";
public static final String PATTERN_YMDHMS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
public static final String PATTERN_YMD_SLASH = "yyyy/MM/dd";
public static final String PATTERN_YMDHMS_SLASH = "yyyy/MM/dd HH:mm:ss";
public static final String PATTERN_YMD_CHINESE = "yyyy年MM月dd日";
public static final String PATTERN_YMDHMS_CHINESE = "yyyy年MM月dd日 HH时mm分ss秒";
public static final String PATTERN_YMD_NO_SEPARATOR = "yyyyMMdd";
public static final String PATTERN_YMDHMS_NO_SEPARATOR = "yyyyMMddHHmmss";
public static final String PATTERN_HMS = "HH:mm:ss";
public static final String PATTERN_HM = "HH:mm";
// 默认时区系统默认时区
private static final ZoneId DEFAULT_ZONE = ZoneId.systemDefault();
// ======================== LocalDateTime 格式化 ========================
/**
* 格式化 LocalDateTime
*
* @param dateTime LocalDateTime 对象
* @param pattern 日期时间格式
* @return 格式化后的字符串如果参数为null则返回空字符串
*/
public static String formatLocalDateTime(LocalDateTime dateTime, String pattern) {
if (dateTime == null || pattern == null || pattern.isEmpty()) {
return "";
}
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return dateTime.format(formatter);
} catch (Exception e) {
return "";
}
}
/**
* 格式化 LocalDateTime使用默认格式 yyyy-MM-dd HH:mm:ss
*
* @param dateTime LocalDateTime 对象
* @return 格式化后的字符串如果参数为null则返回空字符串
*/
public static String formatLocalDateTime(LocalDateTime dateTime) {
return formatLocalDateTime(dateTime, PATTERN_YMDHMS);
}
// ======================== LocalDate 格式化 ========================
/**
* 格式化 LocalDate
*
* @param date LocalDate 对象
* @param pattern 日期格式
* @return 格式化后的字符串如果参数为null则返回空字符串
*/
public static String formatLocalDate(LocalDate date, String pattern) {
if (date == null || pattern == null || pattern.isEmpty()) {
return "";
}
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return date.format(formatter);
} catch (Exception e) {
return "";
}
}
/**
* 格式化 LocalDate使用默认格式 yyyy-MM-dd
*
* @param date LocalDate 对象
* @return 格式化后的字符串如果参数为null则返回空字符串
*/
public static String formatLocalDate(LocalDate date) {
return formatLocalDate(date, PATTERN_YMD);
}
// ======================== LocalTime 格式化 ========================
/**
* 格式化 LocalTime
*
* @param time LocalTime 对象
* @param pattern 时间格式
* @return 格式化后的字符串如果参数为null则返回空字符串
*/
public static String formatLocalTime(LocalTime time, String pattern) {
if (time == null || pattern == null || pattern.isEmpty()) {
return "";
}
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return time.format(formatter);
} catch (Exception e) {
return "";
}
}
/**
* 格式化 LocalTime使用默认格式 HH:mm:ss
*
* @param time LocalTime 对象
* @return 格式化后的字符串如果参数为null则返回空字符串
*/
public static String formatLocalTime(LocalTime time) {
return formatLocalTime(time, PATTERN_HMS);
}
// ======================== Date 格式化 ========================
/**
* 格式化 Date
*
* @param date Date 对象
* @param pattern 日期时间格式
* @return 格式化后的字符串如果参数为null则返回空字符串
*/
public static String formatDate(Date date, String pattern) {
if (date == null || pattern == null || pattern.isEmpty()) {
return "";
}
try {
LocalDateTime dateTime = dateToLocalDateTime(date);
return formatLocalDateTime(dateTime, pattern);
} catch (Exception e) {
return "";
}
}
/**
* 格式化 Date使用默认格式 yyyy-MM-dd HH:mm:ss
*
* @param date Date 对象
* @return 格式化后的字符串如果参数为null则返回空字符串
*/
public static String formatDate(Date date) {
return formatDate(date, PATTERN_YMDHMS);
}
// ======================== 解析为 LocalDateTime ========================
/**
* 解析字符串为 LocalDateTime
*
* @param text 日期时间字符串
* @param pattern 日期时间格式
* @return LocalDateTime 对象解析失败返回 null
*/
public static LocalDateTime parseToLocalDateTime(String text, String pattern) {
if (text == null || text.isEmpty() || pattern == null || pattern.isEmpty()) {
return null;
}
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return LocalDateTime.parse(text, formatter);
} catch (DateTimeParseException e) {
return null;
} catch (Exception e) {
return null;
}
}
/**
* 解析字符串为 LocalDateTime支持多种格式尝试
*
* @param text 日期时间字符串
* @param patterns 多种日期时间格式
* @return LocalDateTime 对象所有格式都解析失败返回 null
*/
public static LocalDateTime parseToLocalDateTime(String text, String... patterns) {
if (text == null || text.isEmpty() || patterns == null || patterns.length == 0) {
return null;
}
for (String pattern : patterns) {
LocalDateTime result = parseToLocalDateTime(text, pattern);
if (result != null) {
return result;
}
}
return null;
}
// ======================== 解析为 LocalDate ========================
/**
* 解析字符串为 LocalDate
*
* @param text 日期字符串
* @param pattern 日期格式
* @return LocalDate 对象解析失败返回 null
*/
public static LocalDate parseToLocalDate(String text, String pattern) {
if (text == null || text.isEmpty() || pattern == null || pattern.isEmpty()) {
return null;
}
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return LocalDate.parse(text, formatter);
} catch (DateTimeParseException e) {
return null;
} catch (Exception e) {
return null;
}
}
/**
* 解析字符串为 LocalDate支持多种格式尝试
*
* @param text 日期字符串
* @param patterns 多种日期格式
* @return LocalDate 对象所有格式都解析失败返回 null
*/
public static LocalDate parseToLocalDate(String text, String... patterns) {
if (text == null || text.isEmpty() || patterns == null || patterns.length == 0) {
return null;
}
for (String pattern : patterns) {
LocalDate result = parseToLocalDate(text, pattern);
if (result != null) {
return result;
}
}
return null;
}
// ======================== 解析为 LocalTime ========================
/**
* 解析字符串为 LocalTime
*
* @param text 时间字符串
* @param pattern 时间格式
* @return LocalTime 对象解析失败返回 null
*/
public static LocalTime parseToLocalTime(String text, String pattern) {
if (text == null || text.isEmpty() || pattern == null || pattern.isEmpty()) {
return null;
}
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return LocalTime.parse(text, formatter);
} catch (DateTimeParseException e) {
return null;
} catch (Exception e) {
return null;
}
}
/**
* 解析字符串为 LocalTime支持多种格式尝试
*
* @param text 时间字符串
* @param patterns 多种时间格式
* @return LocalTime 对象所有格式都解析失败返回 null
*/
public static LocalTime parseToLocalTime(String text, String... patterns) {
if (text == null || text.isEmpty() || patterns == null || patterns.length == 0) {
return null;
}
for (String pattern : patterns) {
LocalTime result = parseToLocalTime(text, pattern);
if (result != null) {
return result;
}
}
return null;
}
// ======================== 解析为 Date ========================
/**
* 解析字符串为 Date
*
* @param text 日期时间字符串
* @param pattern 日期时间格式
* @return Date 对象解析失败返回 null
*/
public static Date parseToDate(String text, String pattern) {
if (text == null || text.isEmpty() || pattern == null || pattern.isEmpty()) {
return null;
}
LocalDateTime dateTime = parseToLocalDateTime(text, pattern);
if (dateTime == null) {
return null;
}
return localDateTimeToDate(dateTime);
}
/**
* 解析字符串为 Date支持多种格式尝试
*
* @param text 日期时间字符串
* @param patterns 多种日期时间格式
* @return Date 对象所有格式都解析失败返回 null
*/
public static Date parseToDate(String text, String... patterns) {
if (text == null || text.isEmpty() || patterns == null || patterns.length == 0) {
return null;
}
for (String pattern : patterns) {
Date result = parseToDate(text, pattern);
if (result != null) {
return result;
}
}
return null;
}
// ======================== Date LocalDateTime 互转 ========================
/**
* Date LocalDateTime
*
* @param date Date 对象
* @return LocalDateTime 对象如果参数为null则返回null
*/
public static LocalDateTime dateToLocalDateTime(Date date) {
if (date == null) {
return null;
}
try {
return LocalDateTime.ofInstant(date.toInstant(), DEFAULT_ZONE);
} catch (Exception e) {
return null;
}
}
/**
* LocalDateTime Date
*
* @param dateTime LocalDateTime 对象
* @return Date 对象如果参数为null则返回null
*/
public static Date localDateTimeToDate(LocalDateTime dateTime) {
if (dateTime == null) {
return null;
}
try {
return Date.from(dateTime.atZone(DEFAULT_ZONE).toInstant());
} catch (Exception e) {
return null;
}
}
/**
* Date LocalDate
*
* @param date Date 对象
* @return LocalDate 对象如果参数为null则返回null
*/
public static LocalDate dateToLocalDate(Date date) {
if (date == null) {
return null;
}
try {
return dateToLocalDateTime(date).toLocalDate();
} catch (Exception e) {
return null;
}
}
/**
* LocalDate Date时间部分为00:00:00
*
* @param localDate LocalDate 对象
* @return Date 对象如果参数为null则返回null
*/
public static Date localDateToDate(LocalDate localDate) {
if (localDate == null) {
return null;
}
try {
return localDateTimeToDate(localDate.atStartOfDay());
} catch (Exception e) {
return null;
}
}
// ======================== 常用便捷方法 ========================
/**
* 获取当前时间的格式化字符串
*
* @param pattern 日期时间格式
* @return 格式化后的当前时间字符串
*/
public static String getCurrentTime(String pattern) {
return formatLocalDateTime(LocalDateTime.now(), pattern);
}
/**
* 获取当前时间的格式化字符串默认格式 yyyy-MM-dd HH:mm:ss
*
* @return 格式化后的当前时间字符串
*/
public static String getCurrentTime() {
return getCurrentTime(PATTERN_YMDHMS);
}
/**
* 获取当前日期的格式化字符串
*
* @param pattern 日期格式
* @return 格式化后的当前日期字符串
*/
public static String getCurrentDate(String pattern) {
return formatLocalDate(LocalDate.now(), pattern);
}
/**
* 获取当前日期的格式化字符串默认格式 yyyy-MM-dd
*
* @return 格式化后的当前日期字符串
*/
public static String getCurrentDate() {
return getCurrentDate(PATTERN_YMD);
}
}

View File

@ -0,0 +1,271 @@
package org.jeecg.common.util;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 数据库字段与驼峰命名转换工具类
* 支持下划线命名(snake_case)和驼峰命名(camelCase)之间的互相转换
*
* @author Your Name
* @date 2026-07-28
*/
public class NamingConverter {
private static final Pattern CAMEL_PATTERN = Pattern.compile("[A-Z]");
private static final Pattern UNDERSCORE_PATTERN = Pattern.compile("_([a-z])");
/**
* 将数据库字段名下划线命名转换为驼峰命名
* 例如user_name -> userName
*
* @param dbField 数据库字段名下划线命名
* @return 驼峰命名字符串
*/
public static String dbFieldToCamel(String dbField) {
if (dbField == null || dbField.isEmpty()) {
return dbField;
}
// 如果字段名全部大写先转为小写
String field = dbField.toLowerCase();
// 处理下划线后跟字母的情况
Matcher matcher = UNDERSCORE_PATTERN.matcher(field);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
String replacement = matcher.group(1).toUpperCase();
matcher.appendReplacement(result, replacement);
}
matcher.appendTail(result);
return result.toString();
}
/**
* 将数据库字段名下划线命名转换为驼峰命名首字母大写
* 例如user_name -> UserName
*
* @param dbField 数据库字段名下划线命名
* @return 首字母大写的驼峰命名字符串
*/
public static String dbFieldToPascal(String dbField) {
String camel = dbFieldToCamel(dbField);
if (camel == null || camel.isEmpty()) {
return camel;
}
return camel.substring(0, 1).toUpperCase() + camel.substring(1);
}
/**
* 将驼峰命名转换为数据库字段名下划线命名
* 例如userName -> user_name
*
* @param camelName 驼峰命名字符串
* @return 数据库字段名下划线命名
*/
public static String camelToDbField(String camelName) {
if (camelName == null || camelName.isEmpty()) {
return camelName;
}
// 在大写字母前添加下划线然后转为小写
Matcher matcher = CAMEL_PATTERN.matcher(camelName);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
String replacement = "_" + matcher.group().toLowerCase();
matcher.appendReplacement(result, replacement);
}
matcher.appendTail(result);
// 如果以大写字母开头会多一个下划线需要去掉
String dbField = result.toString();
if (dbField.startsWith("_")) {
dbField = dbField.substring(1);
}
return dbField;
}
/**
* 将驼峰命名转换为数据库字段名下划线命名全部大写
* 例如userName -> USER_NAME
*
* @param camelName 驼峰命名字符串
* @return 大写下划线命名字符串
*/
public static String camelToDbFieldUpper(String camelName) {
return camelToDbField(camelName).toUpperCase();
}
// ======================== 批量转换方法数组 ========================
/**
* 批量转换将下划线命名的数组转换为驼峰命名数组
*
* @param dbFields 数据库字段名数组
* @return 驼峰命名字符串数组
*/
public static String[] dbFieldsToCamels(String[] dbFields) {
if (dbFields == null) {
return null;
}
String[] result = new String[dbFields.length];
for (int i = 0; i < dbFields.length; i++) {
result[i] = dbFieldToCamel(dbFields[i]);
}
return result;
}
/**
* 批量转换将驼峰命名的数组转换为下划线命名数组
*
* @param camelNames 驼峰命名字符串数组
* @return 数据库字段名数组
*/
public static String[] camelsToDbFields(String[] camelNames) {
if (camelNames == null) {
return null;
}
String[] result = new String[camelNames.length];
for (int i = 0; i < camelNames.length; i++) {
result[i] = camelToDbField(camelNames[i]);
}
return result;
}
// ======================== 批量转换方法List ========================
/**
* 批量转换将下划线命名的List转换为驼峰命名List
*
* @param dbFields 数据库字段名List
* @return 驼峰命名字符串List
*/
public static List<String> dbFieldsToCamels(List<String> dbFields) {
if (dbFields == null) {
return null;
}
List<String> result = new ArrayList<>(dbFields.size());
for (String dbField : dbFields) {
result.add(dbFieldToCamel(dbField));
}
return result;
}
/**
* 批量转换将驼峰命名的List转换为下划线命名List
*
* @param camelNames 驼峰命名字符串List
* @return 数据库字段名List
*/
public static List<String> camelsToDbFields(List<String> camelNames) {
if (camelNames == null) {
return null;
}
List<String> result = new ArrayList<>(camelNames.size());
for (String camelName : camelNames) {
result.add(camelToDbField(camelName));
}
return result;
}
/**
* 批量转换将下划线命名的List转换为驼峰命名List首字母大写
*
* @param dbFields 数据库字段名List
* @return 帕斯卡命名字符串List
*/
public static List<String> dbFieldsToPascals(List<String> dbFields) {
if (dbFields == null) {
return null;
}
List<String> result = new ArrayList<>(dbFields.size());
for (String dbField : dbFields) {
result.add(dbFieldToPascal(dbField));
}
return result;
}
/**
* 批量转换将驼峰命名的List转换为大写下划线命名List
*
* @param camelNames 驼峰命名字符串List
* @return 大写下划线命名字符串List
*/
public static List<String> camelsToDbFieldsUpper(List<String> camelNames) {
if (camelNames == null) {
return null;
}
List<String> result = new ArrayList<>(camelNames.size());
for (String camelName : camelNames) {
result.add(camelToDbFieldUpper(camelName));
}
return result;
}
/**
* 在原有的List上直接进行转换修改原List
* 将下划线命名的List转换为驼峰命名
*
* @param dbFields 数据库字段名List会被修改
* @return 转换后的List原List的引用
*/
public static List<String> convertDbFieldsToCamelsInPlace(List<String> dbFields) {
if (dbFields == null) {
return null;
}
for (int i = 0; i < dbFields.size(); i++) {
dbFields.set(i, dbFieldToCamel(dbFields.get(i)));
}
return dbFields;
}
/**
* 在原有的List上直接进行转换修改原List
* 将驼峰命名的List转换为下划线命名
*
* @param camelNames 驼峰命名字符串List会被修改
* @return 转换后的List原List的引用
*/
public static List<String> convertCamelsToDbFieldsInPlace(List<String> camelNames) {
if (camelNames == null) {
return null;
}
for (int i = 0; i < camelNames.size(); i++) {
camelNames.set(i, camelToDbField(camelNames.get(i)));
}
return camelNames;
}
// ======================== 格式判断方法 ========================
/**
* 判断字符串是否为下划线命名格式
*
* @param str 要检查的字符串
* @return true表示是下划线命名格式
*/
public static boolean isUnderScoreFormat(String str) {
if (str == null || str.isEmpty()) {
return false;
}
return str.contains("_");
}
/**
* 判断字符串是否为驼峰命名格式
*
* @param str 要检查的字符串
* @return true表示是驼峰命名格式
*/
public static boolean isCamelFormat(String str) {
if (str == null || str.isEmpty()) {
return false;
}
return !str.contains("_") && !str.equals(str.toLowerCase());
}
}

View File

@ -0,0 +1,24 @@
package org.jeecg.common.vo.statistic;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.jeecg.common.vo.iot.common.SurvItemInfo;
import java.util.List;
import java.util.Map;
/**
*
* 监测统计曲线统一格式
*/
@Data
public class SurvSummaryVo {
@ApiModelProperty("监测项信息")
private Map<String,SurvItemInfo> itemInfo;
@ApiModelProperty("监测项列表")
private List<SurvItemInfo> itemList;
@ApiModelProperty("X轴数据")
private List<String> timeList;
@ApiModelProperty("Y轴数据")
private Map<String,List<String>> dataMap;
}

View File

@ -0,0 +1,24 @@
package org.jeecg.common.vo.statistic;
import lombok.Data;
import java.util.Date;
import java.util.Map;
/**
* 时间统计结果VO
*/
@Data
public class TimeStatsVO {
/** 时间点 */
private Date timePoint;
/** 格式化后的时间 */
private String timePointFormatted;
/** 动态监测项数据 */
private Map<String, Object> metrics;
/** 记录数 */
private Long recordCount;
}