Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
13ea8bf945
@ -0,0 +1,19 @@
|
||||
package com.das.common.constant;
|
||||
|
||||
/**
|
||||
* 事件等级
|
||||
*
|
||||
*/
|
||||
public interface EventLevelConstant {
|
||||
|
||||
/**
|
||||
* 告警
|
||||
*/
|
||||
Integer ALARM = 0;
|
||||
|
||||
/**
|
||||
* 故障
|
||||
*/
|
||||
Integer FAULT = 1;
|
||||
|
||||
}
|
@ -8,6 +8,8 @@ public class DeviceEventInfo {
|
||||
|
||||
private Long eventId;
|
||||
|
||||
private Integer eventType;
|
||||
|
||||
private Integer eventLevel;
|
||||
|
||||
private String eventText;
|
||||
|
@ -18,6 +18,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.sql.*;
|
||||
@ -95,7 +96,7 @@ public class TDEngineService {
|
||||
}
|
||||
}
|
||||
|
||||
public void createCalStable(String iotmodel, String iotModelField,String dataType) {
|
||||
public void createCalStable(String iotmodel, String iotModelField, String dataType) {
|
||||
try (Connection conn = hikariDataSource.getConnection();
|
||||
Statement pstmt = conn.createStatement()) {
|
||||
StringBuilder sb = new StringBuilder(1024 * 1024);
|
||||
@ -251,9 +252,9 @@ public class TDEngineService {
|
||||
for (IotModelFieldVo info : list) {
|
||||
String iotModelCode = info.getIotModelCode();
|
||||
Map<String, String> calFieldMap = calculateIotFieldMap.get(iotModelCode);
|
||||
if (calFieldMap.keySet().size() != 0){
|
||||
for (String key : calFieldMap.keySet()){
|
||||
createCalStable(iotModelCode,key,calFieldMap.get(key));
|
||||
if (calFieldMap.keySet().size() != 0) {
|
||||
for (String key : calFieldMap.keySet()) {
|
||||
createCalStable(iotModelCode, key, calFieldMap.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -385,7 +386,9 @@ public class TDEngineService {
|
||||
for (DeviceEventInfo dv : list) {
|
||||
sb.append("E_");
|
||||
sb.append(dv.getDeviceId());
|
||||
sb.append(" using event_info tags ('");
|
||||
sb.append(" using event_info tags (");
|
||||
sb.append(dv.getDeviceId());
|
||||
sb.append(",'");
|
||||
sb.append(dv.getDeviceCode());
|
||||
sb.append("','");
|
||||
sb.append(dv.getDeviceName());
|
||||
@ -394,6 +397,8 @@ public class TDEngineService {
|
||||
sb.append(",");
|
||||
sb.append(dv.getEventId());
|
||||
sb.append(",");
|
||||
sb.append(dv.getEventType());
|
||||
sb.append(",");
|
||||
sb.append(dv.getEventLevel());
|
||||
sb.append(",'");
|
||||
sb.append(dv.getEventText());
|
||||
@ -460,11 +465,11 @@ public class TDEngineService {
|
||||
Map<String, Map<String, Map<String, Object>>> result = new HashMap<>();
|
||||
Map<String, Map<String, Object>> valueMap = new HashMap<>();
|
||||
for (String item : fieldList) {
|
||||
Map<String,Object> timeValueMap = new HashMap<>();
|
||||
Map<String, Object> timeValueMap = new HashMap<>();
|
||||
List<Long> times = new ArrayList<>();
|
||||
List<Object> objects = new ArrayList<>();
|
||||
timeValueMap.put("times",times);
|
||||
timeValueMap.put("values",objects);
|
||||
timeValueMap.put("times", times);
|
||||
timeValueMap.put("values", objects);
|
||||
valueMap.put(item, timeValueMap);
|
||||
}
|
||||
StringBuffer sb = new StringBuffer(2048);
|
||||
@ -529,7 +534,6 @@ public class TDEngineService {
|
||||
|
||||
public Map<String, Map<String, Map<String, Object>>> fetchLowHistoryCurve(Long irn, Date startTime, Date endTime, String interval, List<String> fieldList) {
|
||||
SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
String tbName = String.format("l%d", irn);
|
||||
Date now = new Date();
|
||||
if (endTime.after(now)) {
|
||||
@ -538,11 +542,11 @@ public class TDEngineService {
|
||||
Map<String, Map<String, Map<String, Object>>> result = new HashMap<>();
|
||||
Map<String, Map<String, Object>> valueMap = new HashMap<>();
|
||||
for (String item : fieldList) {
|
||||
Map<String,Object> timeValueMap = new HashMap<>();
|
||||
Map<String, Object> timeValueMap = new HashMap<>();
|
||||
List<Long> times = new ArrayList<>();
|
||||
List<Object> objects = new ArrayList<>();
|
||||
timeValueMap.put("times",times);
|
||||
timeValueMap.put("values",objects);
|
||||
timeValueMap.put("times", times);
|
||||
timeValueMap.put("values", objects);
|
||||
valueMap.put(item, timeValueMap);
|
||||
}
|
||||
StringBuffer sb = new StringBuffer(2048);
|
||||
@ -605,6 +609,73 @@ public class TDEngineService {
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<DeviceEventInfo> queryEvent(Integer eventLevel, Long startTime, Long endTime, List<String> deviceCodeList) {
|
||||
List<DeviceEventInfo> result = new ArrayList<>();
|
||||
StringBuffer sb = new StringBuffer(2048);
|
||||
sb.append("select t.* from event_info t where ");
|
||||
sb.append(String.format(" t.event_time >= %d and t.event_time < %d", startTime, endTime));
|
||||
if (eventLevel != null) {
|
||||
sb.append(String.format(" and t.event_level = %d", eventLevel));
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(deviceCodeList)) {
|
||||
sb.append(" and t.device_code in (");
|
||||
for (int i = 0; i < deviceCodeList.size(); i++) {
|
||||
if (i == deviceCodeList.size() - 1) {
|
||||
sb.append("'").append(deviceCodeList.get(i)).append("')");
|
||||
} else {
|
||||
sb.append("'").append(deviceCodeList.get(i)).append("',");
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(" order by t.updatetime");
|
||||
log.debug(sb.toString());
|
||||
try (Connection conn = hikariDataSource.getConnection();
|
||||
Statement smt = conn.createStatement();
|
||||
ResultSet rs = smt.executeQuery(sb.toString())) {
|
||||
while (rs.next()) {
|
||||
DeviceEventInfo deviceEventInfo = new DeviceEventInfo();
|
||||
deviceEventInfo.setUpdateTime(rs.getLong("event_time"));
|
||||
deviceEventInfo.setDeviceId(rs.getString("event_id"));
|
||||
deviceEventInfo.setEventLevel(rs.getInt("event_level"));
|
||||
deviceEventInfo.setEventType(rs.getInt("event_type"));
|
||||
deviceEventInfo.setEventText(rs.getString("event_text"));
|
||||
deviceEventInfo.setConfirmed(rs.getInt("confirmed"));
|
||||
deviceEventInfo.setConfirmAccount(rs.getString("confirm_account"));
|
||||
deviceEventInfo.setConfirmTime(rs.getLong("confirm_time"));
|
||||
deviceEventInfo.setDeviceCode(rs.getString("device_code"));
|
||||
deviceEventInfo.setDeviceId(rs.getString("device_id"));
|
||||
result.add(deviceEventInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("获取数据异常", e);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void confirmEvent(DeviceEventInfo deviceEventInfo) {
|
||||
StringBuffer sb = new StringBuffer(2048);
|
||||
sb.append("insert into e_");
|
||||
sb.append(deviceEventInfo.getDeviceId());
|
||||
sb.append(" USING event_info (device_id)TAGS (null) (event_time,event_id,confirmed,confirm_account,confirm_time) VALUES (");
|
||||
sb.append(deviceEventInfo.getUpdateTime());
|
||||
sb.append(",");
|
||||
sb.append(deviceEventInfo.getEventId());
|
||||
sb.append(",");
|
||||
sb.append(deviceEventInfo.getConfirmed());
|
||||
sb.append(",'");
|
||||
sb.append(deviceEventInfo.getConfirmAccount());
|
||||
sb.append("',");
|
||||
sb.append(deviceEventInfo.getConfirmTime());
|
||||
sb.append(")");
|
||||
try (Connection conn = hikariDataSource.getConnection();
|
||||
Statement pstmt = conn.createStatement()) {
|
||||
pstmt.executeUpdate(sb.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("新增超级表列失败:{},失败原因{}", sb.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String convertInterval(String interval) {
|
||||
if (!StringUtils.hasText(interval)) {
|
||||
interval = "1m";
|
||||
|
@ -51,7 +51,7 @@ public class DataServiceImpl implements DataService {
|
||||
//key:modelId value:modelCode
|
||||
public ConcurrentHashMap<String, String> iotModelMap = new ConcurrentHashMap<>(10000);
|
||||
|
||||
//key:modelId value:fieldCode fieldName
|
||||
//key:modelCode value:fieldCode fieldName
|
||||
public ConcurrentHashMap<String, Map<String, String>> fieldCodeNameMap = new ConcurrentHashMap<>(10000);
|
||||
|
||||
//key:modelCode value:FiledCode,dataType
|
||||
|
@ -0,0 +1,52 @@
|
||||
package com.das.modules.event.controller;
|
||||
|
||||
import com.das.common.result.R;
|
||||
import com.das.common.utils.JsonUtils;
|
||||
import com.das.modules.data.domain.DeviceEventInfo;
|
||||
import com.das.modules.event.domain.EventQueryParam;
|
||||
import com.das.modules.event.service.EventService;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 告警event相关controller
|
||||
*/
|
||||
@Slf4j
|
||||
@RequestMapping("/api/event")
|
||||
@RestController
|
||||
public class EventController {
|
||||
|
||||
@Autowired
|
||||
private EventService eventService;
|
||||
|
||||
/**
|
||||
* 查询设备告警信息列表
|
||||
* @param param 查询条件
|
||||
* @return TD数据库数据
|
||||
*/
|
||||
@PostMapping("/query")
|
||||
public R<List<DeviceEventInfo>> queryEvent(@RequestBody @Valid EventQueryParam param) {
|
||||
if (log.isDebugEnabled()){
|
||||
log.debug("/api/event/query is calling");
|
||||
log.debug(JsonUtils.toJsonString(param));
|
||||
}
|
||||
return R.success(eventService.queryEvent(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认告警信息
|
||||
* @param deviceEventInfo 确认信息
|
||||
*/
|
||||
@PostMapping("/confirm")
|
||||
public void confirmEvent(@RequestBody DeviceEventInfo deviceEventInfo){
|
||||
eventService.confirmEvent(deviceEventInfo);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.das.modules.event.domain;
|
||||
|
||||
import com.das.modules.data.domain.SnapshotValueQueryParam;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 时序数据查询实体
|
||||
*/
|
||||
@Data
|
||||
public class EventQueryParam
|
||||
{
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private String startTime;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private String endTime;
|
||||
|
||||
/**
|
||||
* 事件等级
|
||||
*/
|
||||
private Integer eventLevel;
|
||||
|
||||
/**
|
||||
* 设备编码列表
|
||||
*/
|
||||
private List<String> deviceCode;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.das.modules.event.service;
|
||||
|
||||
import com.das.modules.data.domain.DeviceEventInfo;
|
||||
import com.das.modules.event.domain.EventQueryParam;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface EventService {
|
||||
List<DeviceEventInfo> queryEvent(EventQueryParam param);
|
||||
|
||||
void confirmEvent(DeviceEventInfo deviceEventInfo);
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.das.modules.event.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.das.common.config.SessionUtil;
|
||||
import com.das.common.exceptions.ServiceException;
|
||||
import com.das.modules.auth.domain.vo.SysUserVo;
|
||||
import com.das.modules.data.domain.DeviceEventInfo;
|
||||
import com.das.modules.data.service.TDEngineService;
|
||||
import com.das.modules.event.domain.EventQueryParam;
|
||||
import com.das.modules.event.service.EventService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class EventServiceImpl implements EventService {
|
||||
|
||||
@Autowired
|
||||
private TDEngineService tdEngineService;
|
||||
|
||||
@Override
|
||||
public List<DeviceEventInfo> queryEvent(EventQueryParam param) {
|
||||
if (param.getStartTime() == null || param.getEndTime() ==null){
|
||||
throw new ServiceException("查询时间不能为空");
|
||||
}
|
||||
List<DeviceEventInfo> deviceEventInfos = tdEngineService.queryEvent(param.getEventLevel(), Long.valueOf(param.getStartTime()), Long.valueOf(param.getEndTime()), param.getDeviceCode());
|
||||
return deviceEventInfos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void confirmEvent(DeviceEventInfo deviceEventInfo) {
|
||||
Long confirmTime = System.currentTimeMillis();
|
||||
deviceEventInfo.setConfirmTime(confirmTime);
|
||||
SysUserVo sysUserVo = (SysUserVo) StpUtil.getTokenSession().get(SessionUtil.SESSION_USER_KEY);
|
||||
deviceEventInfo.setConfirmAccount(sysUserVo.getAccount());
|
||||
tdEngineService.confirmEvent(deviceEventInfo);
|
||||
}
|
||||
}
|
@ -315,6 +315,7 @@ public class NodeMessageServiceImpl implements NodeMessageService {
|
||||
if (StringUtils.isEmpty(fieldName)){
|
||||
log.debug("未查询到物模型属性code,设备id:{}",item.getDeviceId());
|
||||
}
|
||||
deviceEventInfo.setEventType(item.getEventType());
|
||||
deviceEventInfo.setEventLevel(0);
|
||||
deviceEventInfo.setConfirmed(0);
|
||||
if (!StringUtils.isEmpty(eventType) && eventType.equals("遥信变位")){
|
||||
@ -334,20 +335,16 @@ public class NodeMessageServiceImpl implements NodeMessageService {
|
||||
}catch (Exception e){
|
||||
log.error("事件信息存入Td失败,失败原因{}",e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String getEventType(int eventType) {
|
||||
switch (eventType) {
|
||||
case 0:
|
||||
return "遥信变位";
|
||||
case 1:
|
||||
return "越上限";
|
||||
case 2:
|
||||
return "越下限";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return switch (eventType) {
|
||||
case 0 -> "遥信变位";
|
||||
case 1 -> "越上限";
|
||||
case 2 -> "越下限";
|
||||
case 3 -> "越上上限";
|
||||
case 4 -> "越下下限";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -409,9 +409,7 @@ const initpowerChart = () => {
|
||||
axisLabel: {
|
||||
//x轴文字的配置
|
||||
show: true,
|
||||
textStyle: {
|
||||
color: '#4E5969',
|
||||
},
|
||||
color: '#4E5969',
|
||||
interval: 'auto',
|
||||
//rotate: 45
|
||||
},
|
||||
@ -442,9 +440,7 @@ const initpowerChart = () => {
|
||||
axisLabel: {
|
||||
//x轴文字的配置
|
||||
show: true,
|
||||
textStyle: {
|
||||
color: '#4E5969',
|
||||
},
|
||||
color: '#4E5969',
|
||||
},
|
||||
axisTick: { show: false },
|
||||
splitLine: {
|
||||
@ -472,9 +468,7 @@ const initpowerChart = () => {
|
||||
axisLabel: {
|
||||
//x轴文字的配置
|
||||
show: true,
|
||||
textStyle: {
|
||||
color: '#4E5969',
|
||||
},
|
||||
color: '#4E5969',
|
||||
},
|
||||
axisTick: { show: false },
|
||||
splitLine: {
|
||||
@ -623,9 +617,7 @@ const initTrendChart = (type: 'day' | 'month') => {
|
||||
axisLabel: {
|
||||
//x轴文字的配置
|
||||
show: true,
|
||||
textStyle: {
|
||||
color: '#4E5969',
|
||||
},
|
||||
color: '#4E5969',
|
||||
},
|
||||
splitLine: {
|
||||
//分割线配置
|
||||
@ -654,9 +646,7 @@ const initTrendChart = (type: 'day' | 'month') => {
|
||||
axisLabel: {
|
||||
//x轴文字的配置
|
||||
show: true,
|
||||
textStyle: {
|
||||
color: '#4E5969',
|
||||
},
|
||||
color: '#4E5969',
|
||||
},
|
||||
axisTick: { show: false },
|
||||
splitLine: {
|
||||
@ -1403,7 +1393,7 @@ const sendManualCommand = (type: 1 | 0) => {
|
||||
deviceId: route.query.irn as string,
|
||||
serviceCode: 'Locked',
|
||||
serviceName,
|
||||
optDesc: serviceName +',设定值为:'+ type,
|
||||
optDesc: serviceName + ',设定值为:' + type,
|
||||
opValue: type,
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
|
@ -93,6 +93,7 @@ export type GetModelAttributeType = {
|
||||
iotModelId: string
|
||||
attributeCode?: string
|
||||
attributeName?: string
|
||||
attributeType?: ModelAttributeType
|
||||
pageSize?: number
|
||||
pageNum?: number
|
||||
orderColumn?: string
|
||||
|
@ -523,7 +523,7 @@ const initpowerChart = () => {
|
||||
top: 50,
|
||||
right: 23,
|
||||
bottom: 10,
|
||||
left: 18,
|
||||
left: 25,
|
||||
containLabel: true,
|
||||
},
|
||||
tooltip: {
|
||||
|
@ -444,6 +444,12 @@
|
||||
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
|
||||
></el-switch>
|
||||
</div>
|
||||
<el-tabs v-model="measureData.measureType" class="measureTabs">
|
||||
<el-tab-pane label="模拟量" :name="138"></el-tab-pane>
|
||||
<el-tab-pane label="离散量" :name="140"></el-tab-pane>
|
||||
<el-tab-pane label="累计量" :name="139"></el-tab-pane>
|
||||
<el-tab-pane label="计算量" :name="199"></el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
<div class="measureSlot">
|
||||
@ -452,6 +458,7 @@
|
||||
:deviceId="measureData.deviceId"
|
||||
:iotModelId="measureData.iotModelId"
|
||||
:autoUpdate="measureData.autoUpdate"
|
||||
:attributeType="measureData.measureType"
|
||||
></MeasurementPage>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@ -478,6 +485,7 @@ import { useAdminInfo } from '/@/stores/adminInfo'
|
||||
import { encrypt_aes, generateRandomNumber } from '/@/utils/crypto'
|
||||
import ControlPage from './control.vue'
|
||||
import MeasurementPage from './measurement.vue'
|
||||
import { ModelAttributeType } from '/@/views/backend/auth/model/type'
|
||||
|
||||
const adminInfo = useAdminInfo()
|
||||
interface Tree {
|
||||
@ -993,10 +1001,16 @@ const openControl = (data: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
const measureData = reactive({
|
||||
const measureData = reactive<{
|
||||
deviceId: string
|
||||
iotModelId: string
|
||||
autoUpdate: boolean
|
||||
measureType: ModelAttributeType
|
||||
}>({
|
||||
deviceId: '',
|
||||
iotModelId: '',
|
||||
autoUpdate: false,
|
||||
measureType: 138,
|
||||
})
|
||||
const showMeasure = ref(false)
|
||||
const openMeasure = (data: any) => {
|
||||
@ -1008,6 +1022,7 @@ const openMeasure = (data: any) => {
|
||||
ElMessage.warning('该设备没有绑定物模型!')
|
||||
}
|
||||
}
|
||||
|
||||
watch(showMeasure, (newVal: boolean) => {
|
||||
!newVal && (measureData.autoUpdate = false)
|
||||
})
|
||||
@ -1107,5 +1122,8 @@ $paginationHeight: 32px;
|
||||
.measureSlotHeaderRight {
|
||||
margin-left: 20px;
|
||||
}
|
||||
.measureTabs {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -11,8 +11,15 @@
|
||||
:sortable="item.sortable"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div v-if="item.prop === 'realTimeValue'">
|
||||
<el-button @click="openChart(scope.row)" text type="primary">{{ scope.row.realTimeValue }}</el-button>
|
||||
<div v-if="item.prop === 'realTimeValue'" class="realTimeValue">
|
||||
<div class="realTimeValueText">{{ scope.row.realTimeValue }}</div>
|
||||
</div>
|
||||
<div v-if="item.prop === 'operate'" @click="openLineChart(scope.row)" class="operate">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="20px" height="20px" viewBox="0 0 1024 1024" version="1.1">
|
||||
<path
|
||||
d="M896 896H96a32 32 0 0 1-32-32V224a32 32 0 0 1 64 0v608h768a32 32 0 1 1 0 64zM247.008 640a32 32 0 0 1-20.992-56.192l200.992-174.24a32 32 0 0 1 42.272 0.288l172.128 153.44 229.088-246.304a32 32 0 0 1 46.88 43.616l-250.432 269.216a31.936 31.936 0 0 1-44.704 2.08l-174.56-155.52-179.744 155.84a31.872 31.872 0 0 1-20.928 7.776z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -30,32 +37,63 @@
|
||||
></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog v-model="lineChartVisible" title="历史曲线" @close="closeLineChart" :width="910">
|
||||
<el-form :inline="true" :model="seachOptions" :rules="searchRules" ref="searchFormRef">
|
||||
<div class="searchPart">
|
||||
<div>
|
||||
<el-form-item prop="datePickerValue" label="历史区间:">
|
||||
<el-date-picker
|
||||
v-model="seachOptions.datePickerValue"
|
||||
type="datetimerange"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
date-format="YYYY/MM/DD"
|
||||
time-format="HH:mm:ss"
|
||||
:shortcuts="shortcuts"
|
||||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div>
|
||||
<el-form-item prop="interval" label="时间间隔:">
|
||||
<el-select v-model="seachOptions.interval" placeholder="请选择时间间隔" style="width: 100px">
|
||||
<el-option label="原始" value="40s"></el-option>
|
||||
<el-option label="5分钟" value="5m"></el-option>
|
||||
<el-option label="15分钟" value="15m"></el-option>
|
||||
<el-option label="1小时" value="1h"></el-option>
|
||||
<el-option label="1天" value="1d"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-button type="primary" @click="getChartData">查询</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="chartPart">
|
||||
<div class="lineChart" ref="chartRef"></div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { reactive, ref, watch, onMounted } from 'vue'
|
||||
import { ElMessage, FormInstance, dayjs } from 'element-plus'
|
||||
import type { ModelAttributeFieldsEnums, GetModelAttributeType } from '/@/views/backend/auth/model/type'
|
||||
import { ModelAttributeType } from '/@/views/backend/auth/model/type'
|
||||
import { getModelAttributeListReq, getRealValueListReq } from '/@/api/backend/deviceModel/request'
|
||||
import * as echarts from 'echarts'
|
||||
import { getRealValueRangeReq } from '/@/api/backend/deviceModel/request'
|
||||
|
||||
const props = defineProps({
|
||||
iotModelId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
deviceId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
autoUpdate: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
const props = withDefaults(
|
||||
defineProps<{ iotModelId: string; deviceId: string; show: boolean; autoUpdate: boolean; attributeType: ModelAttributeType }>(),
|
||||
{
|
||||
iotModelId: '',
|
||||
deviceId: '',
|
||||
show: false,
|
||||
autoUpdate: false,
|
||||
attributeType: 138,
|
||||
}
|
||||
)
|
||||
|
||||
const tableColumn = [
|
||||
{
|
||||
@ -92,6 +130,13 @@ const tableColumn = [
|
||||
align: 'center',
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: '历史曲线',
|
||||
prop: 'operate',
|
||||
align: 'center',
|
||||
width: 80,
|
||||
sortable: false,
|
||||
},
|
||||
]
|
||||
const tableData = ref<any[]>([])
|
||||
|
||||
@ -102,6 +147,7 @@ const getAttributeList = () => {
|
||||
pageSize: pageSetting.pageSize,
|
||||
orderColumn: sortData.orderColumn,
|
||||
orderType: sortData.orderType,
|
||||
attributeType: props.attributeType,
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
@ -195,14 +241,19 @@ const pageSetting = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
pageSizes: [10, 20, 30],
|
||||
pageSizes: [20, 50, 100],
|
||||
})
|
||||
|
||||
const getcurrentPage = () => {
|
||||
getCompleteData()
|
||||
}
|
||||
|
||||
const openChart = (data: any) => {}
|
||||
const openLineChart = (data: any) => {
|
||||
lineChartVisible.value = true
|
||||
searchInfo.attr = data.attributeCode
|
||||
searchInfo.name = data.attributeName
|
||||
searchInfo.unit = data.unit
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
@ -234,6 +285,224 @@ watch(
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const searchFormRef = ref<FormInstance>()
|
||||
const lineChartVisible = ref(false)
|
||||
const searchInfo = reactive({
|
||||
unit: '',
|
||||
name: '',
|
||||
attr: '',
|
||||
})
|
||||
const shortcuts = [
|
||||
{
|
||||
text: '今天',
|
||||
value: () => {
|
||||
const start = dayjs().startOf('day').toDate()
|
||||
const end = dayjs().endOf('day').toDate()
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '昨天',
|
||||
value: () => {
|
||||
const start = dayjs().subtract(1, 'day').startOf('day').toDate()
|
||||
const end = dayjs().subtract(1, 'day').endOf('day').toDate()
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '前三天',
|
||||
value: () => {
|
||||
const start = dayjs().subtract(4, 'day').startOf('day').toDate()
|
||||
const end = dayjs().subtract(1, 'day').endOf('day').toDate()
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
]
|
||||
const getChartData = () => {
|
||||
searchFormRef.value?.validate((valid) => {
|
||||
if (valid) {
|
||||
getRealValueRangeReq({
|
||||
startTime: dayjs(seachOptions.datePickerValue[0]).valueOf(),
|
||||
endTime: dayjs(seachOptions.datePickerValue[1]).valueOf(),
|
||||
devices: [
|
||||
{
|
||||
deviceId: props.deviceId,
|
||||
attributes: [searchInfo.attr],
|
||||
},
|
||||
],
|
||||
interval: seachOptions.interval,
|
||||
}).then((res) => {
|
||||
initChart(res.data?.[props.deviceId]?.[searchInfo.attr])
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const chartRef = ref()
|
||||
let chartInstance: any = null
|
||||
const seachOptions = reactive({
|
||||
datePickerValue: [0, 0],
|
||||
interval: '5m',
|
||||
})
|
||||
|
||||
const searchRules = {
|
||||
datePickerValue: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (!value[0] || !value[1]) {
|
||||
callback(new Error('请选择时间范围'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
},
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
interval: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入时间间隔',
|
||||
trigger: 'input',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const initChart = (data: { values: number[]; times: number[] }) => {
|
||||
chartInstance && chartInstance.clear()
|
||||
|
||||
chartInstance = chartInstance ? chartInstance : echarts.init(chartRef.value)
|
||||
const times = data?.times.map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
|
||||
|
||||
const option = {
|
||||
grid: {
|
||||
top: 50,
|
||||
right: 23,
|
||||
bottom: 10,
|
||||
left: 18,
|
||||
containLabel: true,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#dadada',
|
||||
width: 1,
|
||||
type: 'solid',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
//x轴文字的配置
|
||||
show: true,
|
||||
color: '#4E5969',
|
||||
interval: 'auto',
|
||||
//rotate: 45
|
||||
},
|
||||
splitLine: {
|
||||
//分割线配置
|
||||
show: false,
|
||||
lineStyle: {
|
||||
color: '#999999',
|
||||
},
|
||||
},
|
||||
data: times ?? [],
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: searchInfo.unit,
|
||||
nameTextStyle: {
|
||||
color: '#4E5969',
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
lineStyle: {
|
||||
color: '#dadada',
|
||||
width: 0,
|
||||
type: 'solid',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
//x轴文字的配置
|
||||
show: true,
|
||||
color: '#4E5969',
|
||||
},
|
||||
axisTick: { show: false },
|
||||
splitLine: {
|
||||
interval: 50,
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#dadada',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
legend: {
|
||||
data: [searchInfo.name],
|
||||
textStyle: {
|
||||
color: '#73767a',
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: searchInfo.name,
|
||||
type: 'line',
|
||||
barWidth: 20,
|
||||
itemStyle: {
|
||||
color: '#00A7EB',
|
||||
barBorderRadius: 2,
|
||||
},
|
||||
smooth: 0.6,
|
||||
symbol: 'none',
|
||||
data: data?.values ?? [],
|
||||
},
|
||||
],
|
||||
}
|
||||
chartInstance.setOption(option)
|
||||
}
|
||||
|
||||
const closeLineChart = () => {
|
||||
chartInstance && chartInstance.clear()
|
||||
searchFormRef.value!.resetFields()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.attributeType,
|
||||
() => {
|
||||
getCompleteData()
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped lang="scss">
|
||||
.realTimeValueText {
|
||||
color: #0064aa;
|
||||
}
|
||||
|
||||
.operate {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.searchPart {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.chartPart {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
.lineChart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user