Merge branch 'main' of https://git.jsspisoft.com/ry-das
@ -316,7 +316,12 @@ bool CRYDevice::publish_sensor_data(const std::string traceId, const char* comma
|
||||
std::string outputConfig = Json::writeString(builder, jsonRoot);
|
||||
if (traceId != "")
|
||||
{
|
||||
vLog(LOG_DEBUG, "send cmd: %s, payload: %d, %128s\n", command, outputConfig.length(), outputConfig.c_str());
|
||||
vLog(LOG_DEBUG, "send cmd: %s, payload: %d\n", command, outputConfig.length());
|
||||
} else {
|
||||
std::string com = command;
|
||||
if (com == "deviceEvent") {
|
||||
vLog(LOG_DEBUG, "send cmd: %s, payload: %d\n", command, outputConfig.length());
|
||||
}
|
||||
}
|
||||
int rc = websocket_write(outputConfig.c_str(), outputConfig.length());
|
||||
if (rc != 0) {
|
||||
@ -2014,7 +2019,7 @@ bool CRYDevice::publishdeviceEventData(void)
|
||||
}
|
||||
|
||||
if (root.size()) {
|
||||
//return publish_sensor_data("", "deviceEvent", root);
|
||||
return publish_sensor_data("", "deviceEvent", root);
|
||||
//vLog(LOG_DEBUG, "%s", root.toStyledString().c_str());
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.das.modules.calc.domain.vo;
|
||||
package com.das.modules.cache.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@ -9,6 +9,7 @@ import lombok.Data;
|
||||
public class DeviceInfoCache {
|
||||
private Long deviceId;
|
||||
private String deviceCode;
|
||||
private String deviceName;
|
||||
private Integer objectType;
|
||||
private Long parentDeviceId;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package com.das.modules.calc.service;
|
||||
package com.das.modules.cache.service;
|
||||
|
||||
import com.das.modules.calc.domain.vo.DeviceInfoCache;
|
||||
import com.das.modules.cache.domain.DeviceInfoCache;
|
||||
import com.das.modules.equipment.entity.SysEquipment;
|
||||
import com.das.modules.equipment.mapper.SysEquipmentMapper;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
@ -61,6 +61,7 @@ public class CacheService {
|
||||
DeviceInfoCache deviceInfoCache = new DeviceInfoCache();
|
||||
deviceInfoCache.setDeviceId(equipment.getId());
|
||||
deviceInfoCache.setDeviceCode(equipment.getCode());
|
||||
deviceInfoCache.setDeviceName(equipment.getName());
|
||||
deviceInfoCache.setObjectType(equipment.getObjectType());
|
||||
deviceInfoCache.setParentDeviceId(equipment.getParentEquipmentId());
|
||||
deviceInfoCaches.add(deviceInfoCache);
|
||||
@ -68,8 +69,7 @@ public class CacheService {
|
||||
deviceCodeIndex.put(deviceInfoCache.getDeviceCode(),i);
|
||||
//创建Id索引
|
||||
deviceIdIndex.put(equipment.getId(),i);
|
||||
//关联风场缓存
|
||||
// if (equipment.getObjectType().equals()
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
package com.das.modules.calc.functions;
|
||||
|
||||
import com.das.modules.calc.domain.vo.DeviceInfoCache;
|
||||
import com.das.modules.calc.service.CacheService;
|
||||
import com.das.modules.cache.domain.DeviceInfoCache;
|
||||
import com.das.modules.cache.service.CacheService;
|
||||
import com.das.modules.data.domain.SnapshotValueQueryParam;
|
||||
import com.das.modules.data.service.DataService;
|
||||
import com.googlecode.aviator.runtime.function.AbstractFunction;
|
||||
import com.googlecode.aviator.runtime.type.*;
|
||||
import com.googlecode.aviator.utils.Env;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -1,11 +1,9 @@
|
||||
package com.das.modules.calc.functions;
|
||||
|
||||
import com.das.modules.calc.domain.vo.DeviceInfoCache;
|
||||
import com.das.modules.calc.service.CacheService;
|
||||
import com.das.modules.data.domain.SnapshotValueQueryParam;
|
||||
import com.das.modules.cache.domain.DeviceInfoCache;
|
||||
import com.das.modules.cache.service.CacheService;
|
||||
import com.das.modules.data.service.DataService;
|
||||
import com.das.modules.node.domain.bo.CalculateRTData;
|
||||
import com.googlecode.aviator.runtime.function.AbstractFunction;
|
||||
import com.googlecode.aviator.runtime.function.AbstractVariadicFunction;
|
||||
import com.googlecode.aviator.runtime.function.FunctionUtils;
|
||||
import com.googlecode.aviator.runtime.type.AviatorObject;
|
||||
@ -79,7 +77,7 @@ public class FunctionSaveCalcData extends AbstractVariadicFunction {
|
||||
dataList.add(dt);
|
||||
}
|
||||
|
||||
// dataService.updateCalFieldData(dataList);
|
||||
dataService.updateCalFieldData(dataList);
|
||||
return AviatorRuntimeJavaType.valueOf(0);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.das.modules.calc.service;
|
||||
|
||||
import com.das.modules.cache.service.CacheService;
|
||||
import com.das.modules.calc.domain.entity.CalcModule;
|
||||
import com.googlecode.aviator.AviatorEvaluatorInstance;
|
||||
import com.googlecode.aviator.Expression;
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.das.modules.calc.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.das.modules.cache.service.CacheService;
|
||||
import com.das.modules.calc.domain.entity.CalcModule;
|
||||
import com.das.modules.calc.functions.FunctionRealData;
|
||||
import com.das.modules.calc.functions.FunctionSaveCalcData;
|
||||
|
@ -11,6 +11,7 @@ import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
@ -31,8 +32,6 @@ public class TDEngineService {
|
||||
|
||||
private HikariDataSource hikariDataSource;
|
||||
|
||||
private DataServiceImpl dataService;
|
||||
|
||||
@Value("${tdengine.url}")
|
||||
private String url;
|
||||
|
||||
@ -348,10 +347,11 @@ public class TDEngineService {
|
||||
sb.setLength(0);
|
||||
sb.append("insert into ");
|
||||
for (CalculateRTData dv : list) {
|
||||
sb.append("c");
|
||||
sb.append("c_");
|
||||
sb.append(dv.getDeviceId());
|
||||
sb.append("_").append(dv.getIotModelField());
|
||||
sb.append(" using c_");
|
||||
sb.append(dataService.deviceModelMap.get(dv.getDeviceId().toString()));
|
||||
sb.append(dv.getModelCode());
|
||||
sb.append("_").append(dv.getIotModelField());
|
||||
sb.append(" tags (");
|
||||
sb.append(dv.getDeviceId());
|
||||
|
@ -175,6 +175,7 @@ public class DataServiceImpl implements DataService {
|
||||
for (CalculateRTData value : list) {
|
||||
String key = String.format("RT:%s:%s", value.getDeviceId(), value.getIotModelField().toLowerCase());
|
||||
keyValueMap.put(key, value.getDataValue());
|
||||
value.setModelCode(deviceModelMap.get(value.getDeviceId().toString()));
|
||||
}
|
||||
adminRedisTemplate.mSet(keyValueMap);
|
||||
tdEngineService.updateCalFieldValues(list);
|
||||
|
@ -15,6 +15,7 @@ import com.das.common.utils.PageQuery;
|
||||
import com.das.common.utils.SequenceUtils;
|
||||
import com.das.modules.auth.domain.vo.SysUserVo;
|
||||
import com.das.modules.auth.mapper.SysOrgMapper;
|
||||
import com.das.modules.data.service.impl.DataServiceImpl;
|
||||
import com.das.modules.equipment.domain.dto.SysEquipmentDto;
|
||||
import com.das.modules.equipment.domain.excel.SysEquipmentExcel;
|
||||
import com.das.modules.equipment.domain.vo.SysEquipmentVo;
|
||||
@ -58,6 +59,9 @@ public class SysEquipmentServiceImpl implements SysEquipmentService {
|
||||
@Autowired
|
||||
private SysIotModelMapper sysIotModelMapper;
|
||||
|
||||
@Autowired
|
||||
private DataServiceImpl dataService;
|
||||
|
||||
@Override
|
||||
public SysEquipmentVo creatSysEquipment(SysEquipmentDto sysEquipmentDto) {
|
||||
//去除空格
|
||||
@ -76,6 +80,10 @@ public class SysEquipmentServiceImpl implements SysEquipmentService {
|
||||
sysEquipment.setUpdatedBy(sysUserVo.getAccount());
|
||||
sysEquipment.setRevision(1);
|
||||
sysEquipmentMapper.insert(sysEquipment);
|
||||
//物模型不为空 增加设备物模型mapping缓存
|
||||
if (sysEquipment.getIotModelId() != null){
|
||||
dataService.deviceModelMap.put(sysEquipment.getId().toString(),dataService.iotModelMap.get(sysEquipment.getIotModelId().toString()));
|
||||
}
|
||||
SysEquipmentVo sysEquipmentVo = new SysEquipmentVo();
|
||||
BeanCopyUtils.copy(sysEquipment, sysEquipmentVo);
|
||||
return sysEquipmentVo;
|
||||
@ -98,6 +106,9 @@ public class SysEquipmentServiceImpl implements SysEquipmentService {
|
||||
sysEquipment.setUpdatedTime(new Date());
|
||||
sysEquipment.setUpdatedBy(sysUserVo.getAccount());
|
||||
sysEquipmentMapper.updateById(sysEquipment);
|
||||
if (oldSysEquipment.getIotModelId() == null && sysEquipment.getIotModelId() != null){
|
||||
dataService.deviceModelMap.put(sysEquipment.getId().toString(),dataService.iotModelMap.get(sysEquipment.getIotModelId().toString()));
|
||||
}
|
||||
SysEquipmentVo sysEquipmentVo = new SysEquipmentVo();
|
||||
BeanCopyUtils.copy(sysEquipment, sysEquipmentVo);
|
||||
return sysEquipmentVo;
|
||||
@ -110,6 +121,8 @@ public class SysEquipmentServiceImpl implements SysEquipmentService {
|
||||
throw new RuntimeException("该设备下有子设备,不能删除");
|
||||
}
|
||||
sysEquipmentMapper.deleteById(sysEquipmentDto.getId());
|
||||
//删除缓存
|
||||
dataService.deviceModelMap.remove(sysEquipmentDto.getId().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -277,12 +290,30 @@ public class SysEquipmentServiceImpl implements SysEquipmentService {
|
||||
}
|
||||
}
|
||||
sysEquipmentMapper.insertBatch(addSysEquipmentList);
|
||||
for (SysEquipment item : addSysEquipmentList){
|
||||
if (item.getIotModelId() != null){
|
||||
String modelCode = dataService.iotModelMap.get(item.getIotModelId().toString());
|
||||
dataService.deviceModelMap.put(item.getId().toString(),modelCode);
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateSysEquipmentList)) {
|
||||
sysEquipmentMapper.updateBatchById(updateSysEquipmentList);
|
||||
for (SysEquipment item : updateSysEquipmentList){
|
||||
if (item.getIotModelId() != null){
|
||||
String modelCode = dataService.iotModelMap.get(item.getIotModelId().toString());
|
||||
dataService.deviceModelMap.put(item.getId().toString(),modelCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(delSysEquipmentList)) {
|
||||
// 删除设备
|
||||
sysEquipmentMapper.deleteBatchIds(delSysEquipmentList);
|
||||
for (SysEquipment item : updateSysEquipmentList){
|
||||
if (item.getIotModelId() != null){
|
||||
String modelCode = dataService.iotModelMap.get(item.getIotModelId().toString());
|
||||
dataService.deviceModelMap.put(item.getId().toString(),modelCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,4 +20,6 @@ public class CalculateRTData {
|
||||
private Object dataValue;
|
||||
|
||||
private String iotModelField;
|
||||
|
||||
private String modelCode;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import com.das.common.constant.MeasType;
|
||||
import com.das.common.constant.SysAuthorityIds;
|
||||
import com.das.common.exceptions.ServiceException;
|
||||
import com.das.common.result.R;
|
||||
import com.das.modules.operation.domain.CommandInfoDto;
|
||||
import com.das.modules.operation.domain.dto.CommandInfoDto;
|
||||
import com.das.modules.operation.service.OperationService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -0,0 +1,36 @@
|
||||
package com.das.modules.operation.controller;
|
||||
|
||||
import com.das.common.result.R;
|
||||
import com.das.common.utils.PageDataInfo;
|
||||
import com.das.modules.operation.domain.dto.EventLogDto;
|
||||
import com.das.modules.operation.domain.vo.SysOperationLogVo;
|
||||
import com.das.modules.operation.service.OperationLogService;
|
||||
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;
|
||||
|
||||
@Slf4j
|
||||
@RequestMapping("/api/operation")
|
||||
@RestController
|
||||
public class OperationLogController {
|
||||
|
||||
@Autowired
|
||||
private OperationLogService operationLogService;
|
||||
|
||||
/**
|
||||
* 获取事件记录
|
||||
*/
|
||||
@PostMapping("/getEventLogList")
|
||||
public R<PageDataInfo<SysOperationLogVo>> getEventLogList(@RequestBody EventLogDto eventLogDto) {
|
||||
if (eventLogDto.getPageNum() ==null){
|
||||
eventLogDto.setPageNum(1);
|
||||
}
|
||||
if (eventLogDto.getPageSize() ==null){
|
||||
eventLogDto.setPageSize(30);
|
||||
}
|
||||
return R.success(operationLogService.getEventLogList(eventLogDto));
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.das.modules.operation.domain;
|
||||
package com.das.modules.operation.domain.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
@ -0,0 +1,22 @@
|
||||
package com.das.modules.operation.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class EventLogDto {
|
||||
|
||||
private String startTime;
|
||||
|
||||
|
||||
private String endTime;
|
||||
|
||||
private String windTurbinesCode;
|
||||
|
||||
private String userName;
|
||||
|
||||
private Integer pageNum;
|
||||
|
||||
private Integer pageSize;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.das.modules.operation.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
@Data
|
||||
public class SysOperationLogVo {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 记录id
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 操作人账号
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 操作人名称
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date optTime;
|
||||
/**
|
||||
* 操作人IP地址
|
||||
*/
|
||||
private String ipAddress;
|
||||
/**
|
||||
* 操作设备id
|
||||
*/
|
||||
private Long deviceId;
|
||||
/**
|
||||
* 设备属性编码
|
||||
*/
|
||||
private String attributeCode;
|
||||
/**
|
||||
* 设备属性名称
|
||||
*/
|
||||
private String attributeName;
|
||||
/**
|
||||
* 操作描述
|
||||
*/
|
||||
private String optDesc;
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -43,4 +43,6 @@ public class SysManualStatus extends BaseEntity {
|
||||
*/
|
||||
@TableField("status")
|
||||
private Integer status;
|
||||
|
||||
private Integer count;
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
package com.das.modules.operation.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.das.modules.auth.mapper.BaseMapperPlus;
|
||||
import com.das.modules.operation.entity.SysManualStatus;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysManualStatusMapper extends BaseMapper<SysManualStatus> {
|
||||
public interface SysManualStatusMapper extends BaseMapperPlus<SysManualStatus,SysManualStatus> {
|
||||
|
||||
int sysManualStatusInsertOrUpdate(SysManualStatus sysManualStatus);
|
||||
}
|
||||
|
@ -1,9 +1,18 @@
|
||||
package com.das.modules.operation.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.das.modules.auth.mapper.BaseMapperPlus;
|
||||
import com.das.modules.operation.domain.dto.EventLogDto;
|
||||
import com.das.modules.operation.domain.vo.SysOperationLogVo;
|
||||
import com.das.modules.operation.entity.SysOperationLog;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@Mapper
|
||||
public interface SysOperationLogMapper extends BaseMapper<SysOperationLog> {
|
||||
public interface SysOperationLogMapper extends BaseMapperPlus<SysOperationLog,SysOperationLog> {
|
||||
|
||||
IPage<SysOperationLogVo> getEventLogList(IPage<SysOperationLogVo> page ,
|
||||
@Param("info") EventLogDto eventLogDto);
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
package com.das.modules.operation.service;
|
||||
|
||||
import com.das.common.utils.PageDataInfo;
|
||||
import com.das.modules.operation.domain.dto.EventLogDto;
|
||||
import com.das.modules.operation.domain.vo.SysOperationLogVo;
|
||||
|
||||
public interface OperationLogService {
|
||||
|
||||
PageDataInfo<SysOperationLogVo> getEventLogList(EventLogDto eventLogDto);
|
||||
}
|
@ -12,7 +12,7 @@ import com.das.modules.node.disruptor.TerminalMessageEventHandler;
|
||||
import com.das.modules.node.domain.bo.TerminalMessage;
|
||||
import com.das.modules.node.domain.vo.SysNodeVo;
|
||||
import com.das.modules.node.mapper.SysNodeMapper;
|
||||
import com.das.modules.operation.domain.CommandInfoDto;
|
||||
import com.das.modules.operation.domain.dto.CommandInfoDto;
|
||||
import com.das.modules.operation.entity.SysManualStatus;
|
||||
import com.das.modules.operation.entity.SysOperationLog;
|
||||
import com.das.modules.operation.mapper.SysManualStatusMapper;
|
||||
@ -71,11 +71,11 @@ public class OperationService {
|
||||
sysManualStatus.setDeviceId(cmdInfo.getDeviceId());
|
||||
sysManualStatus.setAttributeCode(cmdInfo.getServiceCode());
|
||||
sysManualStatus.setStatus( Integer.valueOf(cmdInfo.getOpValue().toString()));
|
||||
sysManualStatusMapper.insert(sysManualStatus);
|
||||
sysManualStatusMapper.sysManualStatusInsertOrUpdate(sysManualStatus);
|
||||
// 2、更新redis RT实时数据值
|
||||
String key = String.format("RT:%s:%s", cmdInfo.getDeviceId(), cmdInfo.getServiceCode().toLowerCase());
|
||||
// 存入redis
|
||||
adminRedisTemplate.set(key, cmdInfo.getOpValue());
|
||||
adminRedisTemplate.set(key, cmdInfo.getOpValue());
|
||||
} else {
|
||||
sendCommand(cmdInfo); //发送命令消息
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.das.modules.operation.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.das.common.utils.PageDataInfo;
|
||||
import com.das.common.utils.PageQuery;
|
||||
import com.das.modules.operation.domain.dto.EventLogDto;
|
||||
import com.das.modules.operation.domain.vo.SysOperationLogVo;
|
||||
import com.das.modules.operation.mapper.SysOperationLogMapper;
|
||||
import com.das.modules.operation.service.OperationLogService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class OperationLogServiceImpl implements OperationLogService {
|
||||
|
||||
@Autowired
|
||||
private SysOperationLogMapper sysOperationLogMapper;
|
||||
|
||||
/**
|
||||
* 获取事件记录
|
||||
*/
|
||||
@Override
|
||||
public PageDataInfo<SysOperationLogVo> getEventLogList(EventLogDto eventLogDto) {
|
||||
PageQuery pageQuery = new PageQuery();
|
||||
pageQuery.setPageNum(eventLogDto.getPageNum());
|
||||
pageQuery.setPageSize(eventLogDto.getPageSize());
|
||||
IPage<SysOperationLogVo> iPage = sysOperationLogMapper.getEventLogList(pageQuery.build(), eventLogDto);
|
||||
return PageDataInfo.build(iPage.getRecords(), iPage.getTotal());
|
||||
}
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
package com.das.modules.page.controller;
|
||||
|
||||
import com.das.common.result.R;
|
||||
import com.das.modules.page.domian.HomeWindFarmRealDataVo;
|
||||
import com.das.modules.page.domian.HomeWindTurbineMatrixDataVoVo;
|
||||
import com.das.modules.data.domain.TSValueQueryParam;
|
||||
import com.das.modules.page.domian.dto.WindFarmRealDataDto;
|
||||
import com.das.modules.page.domian.vo.HomeWindFarmRealDataVo;
|
||||
import com.das.modules.page.domian.vo.HomeWindTurbineMatrixDataVoVo;
|
||||
import com.das.modules.page.service.HomeService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -13,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 首页相关Controller
|
||||
@ -46,4 +48,12 @@ public class HomeController {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取历史数据(1.获取功率趋势的曲线,2.发电量日 趋势的曲线)
|
||||
*/
|
||||
@PostMapping("/getHistoryData")
|
||||
public R<Map<String, Map<String, Map<String, Object>>>> getHistoryData(@RequestBody TSValueQueryParam param) {
|
||||
return R.success(homeService.getHistoryData(param));
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.das.modules.page.domian;
|
||||
package com.das.modules.page.domian.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.das.modules.page.domian;
|
||||
package com.das.modules.page.domian.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
@ -1,10 +1,12 @@
|
||||
package com.das.modules.page.service;
|
||||
|
||||
import com.das.modules.page.domian.HomeWindFarmRealDataVo;
|
||||
import com.das.modules.page.domian.HomeWindTurbineMatrixDataVoVo;
|
||||
import com.das.modules.data.domain.TSValueQueryParam;
|
||||
import com.das.modules.page.domian.dto.WindFarmRealDataDto;
|
||||
import com.das.modules.page.domian.vo.HomeWindFarmRealDataVo;
|
||||
import com.das.modules.page.domian.vo.HomeWindTurbineMatrixDataVoVo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface HomeService {
|
||||
/**
|
||||
@ -22,30 +24,13 @@ public interface HomeService {
|
||||
*/
|
||||
HomeWindFarmRealDataVo getWindFarmRealData(WindFarmRealDataDto windFarmRealDataDto);
|
||||
|
||||
/**
|
||||
* 接口3: 获取功率趋势的曲线
|
||||
* 页面左下角【功率趋势】
|
||||
* 测点:WindFarmActivePower全场总有功功率、WindFarmAvgWindSpeed 全场平均风速
|
||||
* 时间间隔 5分钟
|
||||
* 时间区间从 今天的00:00:00 到 现在的时间
|
||||
*/
|
||||
|
||||
/**
|
||||
* 接口4: 发电量日 趋势的曲线
|
||||
* 页面右中角【发电量趋势】中的日
|
||||
* 测点:WindFarmDayProdEnergy 日发电量
|
||||
* 时间间隔 1天
|
||||
* 时间区间从 本月1号 到月末31号 一个月一天一条记录
|
||||
* 同期就是去年对应时间
|
||||
* 获取历史数据(1.获取功率趋势的曲线,2.发电量日趋势的曲线)
|
||||
*/
|
||||
Map<String, Map<String, Map<String, Object>>> getHistoryData(TSValueQueryParam param);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 接口5: 发电量月 趋势的曲线
|
||||
* 页面右中角【发电量趋势】中的日
|
||||
* 测点:WIndFarmMonthProdEnergy 月发电量
|
||||
* 时间间隔 1月
|
||||
* 时间区间从 今年的1月1日 到 年底12月31日 一年每个月一条记录
|
||||
* 同期就是去年对应时间
|
||||
*/
|
||||
|
||||
}
|
||||
|
@ -2,15 +2,19 @@ package com.das.modules.page.service.impl;
|
||||
|
||||
|
||||
import com.das.common.constant.EquipmentTypeIds;
|
||||
import com.das.common.utils.JsonUtils;
|
||||
import com.das.modules.data.domain.SnapshotValueQueryParam;
|
||||
import com.das.modules.data.domain.TSValueQueryParam;
|
||||
import com.das.modules.data.service.impl.DataServiceImpl;
|
||||
import com.das.modules.equipment.domain.dto.SysEquipmentDto;
|
||||
import com.das.modules.equipment.domain.vo.SysEquipmentVo;
|
||||
import com.das.modules.equipment.mapper.SysEquipmentMapper;
|
||||
import com.das.modules.page.domian.HomeWindFarmRealDataVo;
|
||||
import com.das.modules.page.domian.HomeWindTurbineMatrixDataVoVo;
|
||||
import com.das.modules.page.domian.dto.WindFarmRealDataDto;
|
||||
import com.das.modules.page.domian.vo.HomeWindFarmRealDataVo;
|
||||
import com.das.modules.page.domian.vo.HomeWindTurbineMatrixDataVoVo;
|
||||
import com.das.modules.page.service.HomeService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -18,6 +22,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class HomeServiceImpl implements HomeService {
|
||||
|
||||
@ -145,4 +150,35 @@ public class HomeServiceImpl implements HomeService {
|
||||
}
|
||||
return homeWindFarmRealDataVo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取历史数据(1.获取功率趋势的曲线,2.发电量日 趋势的曲线)
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Map<String, Map<String, Object>>> getHistoryData(TSValueQueryParam param) {
|
||||
List<SnapshotValueQueryParam> devices = param.getDevices();
|
||||
for (SnapshotValueQueryParam device : devices) {
|
||||
if (StringUtils.isBlank(device.getDeviceId())){
|
||||
//查询数据库中风电场设备,取第一个风电场
|
||||
SysEquipmentDto sysEquipmentDto = new SysEquipmentDto();
|
||||
sysEquipmentDto.setObjectType(EquipmentTypeIds.EQUIPMENT_TYPE_WIND_FARM);
|
||||
List<SysEquipmentVo> list = sysEquipmentMapper.queryEquipmentList(sysEquipmentDto);
|
||||
if(list.isEmpty()){
|
||||
throw new RuntimeException("系统中没有风电场台账信息");
|
||||
}
|
||||
device.setDeviceId(list.get(0).getId().toString());
|
||||
}
|
||||
}
|
||||
Map<String, Map<String, Map<String, Object>>> mapResult = dataServiceImpl.queryTimeSeriesValues(param);
|
||||
if (log.isDebugEnabled()){
|
||||
log.debug("/api/home/getHistoryData is calling");
|
||||
log.debug("参数:"+JsonUtils.toJsonString(param));
|
||||
log.debug("返回值:"+JsonUtils.toJsonString(mapResult));
|
||||
}
|
||||
return mapResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
100
das/src/main/resources/application-dev.yml
Normal file
@ -0,0 +1,100 @@
|
||||
server:
|
||||
port: 8080
|
||||
# SpringBoot中我们既可以使用Tomcat作为Http服务,也可以用Undertow来代替。Undertow在高并发业务场景中,性能优于Tomcat
|
||||
undertow:
|
||||
threads:
|
||||
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
|
||||
io: 16
|
||||
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
|
||||
worker: 400
|
||||
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
|
||||
# 每块buffer的空间大小,越小的空间被利用越充分
|
||||
buffer-size: 1024
|
||||
# HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的
|
||||
max-http-post-size: -1
|
||||
# 是否分配的直接内存
|
||||
direct-buffers: true
|
||||
|
||||
sa-token:
|
||||
# token有效期,单位秒
|
||||
expireTime: 7200
|
||||
refreshExpireTime: 604800
|
||||
# 是否允许同一账号多终端登录,默认为true
|
||||
is-concurrent: true
|
||||
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: das
|
||||
#json格式化全局配置,相当于@JsonFormat
|
||||
jackson:
|
||||
time-zone: GMT+8
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
# 指定默认包含的熟悉,NON_NULL表示只序列化非空属性
|
||||
default-property-inclusion: non_null
|
||||
# 配置文件上传大小限制
|
||||
servlet:
|
||||
multipart:
|
||||
# 单个文件最大大小
|
||||
max-file-size: 1024MB
|
||||
# 多个文件总大小
|
||||
max-request-size: 2048MB
|
||||
datasource:
|
||||
url: jdbc:postgresql://192.168.109.102:5432/das
|
||||
username: das
|
||||
password: qwaszx12
|
||||
# # redis相关配置
|
||||
data:
|
||||
redis:
|
||||
host: 192.168.109.195
|
||||
database: 0
|
||||
port: 6379
|
||||
password:
|
||||
client-type: lettuce
|
||||
|
||||
|
||||
# 配置 xml 文件所在位置 配置全局的 主键策略,默认为 ASSIGN_ID 默认为 【雪花算法】 , auto 自增
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath*:/mapper/**/*.xml
|
||||
# 搜索指定包别名
|
||||
typeAliasesPackage: com.das.**.entity
|
||||
global-config:
|
||||
# 关闭MP3.0自带的banner
|
||||
banner: false
|
||||
db-config:
|
||||
id-type: ASSIGN_ID
|
||||
# 逻辑删除
|
||||
logic-not-delete-value: 0
|
||||
logic-delete-value: 1
|
||||
#字段策略
|
||||
insert-strategy: not_null
|
||||
update-strategy: not_null
|
||||
where-strategy: not_empty
|
||||
#驼峰下划线转换
|
||||
table-underline: true
|
||||
# 开启驼峰命名 默认开启驼峰命名
|
||||
# mybatis-plus配置控制台打印完整带参数SQL语句
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
cache-enabled: false
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
# 验证码相关
|
||||
captcha:
|
||||
enabled: true
|
||||
verify-type: calculate
|
||||
expire: 120
|
||||
|
||||
das:
|
||||
aes:
|
||||
key: b6967ee87b86d85a
|
||||
|
||||
logging:
|
||||
level:
|
||||
com:
|
||||
das: DEBUG
|
||||
|
||||
tdengine:
|
||||
password: taosdata
|
||||
url: jdbc:TAOS-RS://192.168.109.160:6041/das
|
||||
username: root
|
24
das/src/main/resources/mapper/SysManualStatusMapper.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<?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.das.modules.operation.mapper.SysManualStatusMapper">
|
||||
|
||||
|
||||
<insert id="sysManualStatusInsertOrUpdate" parameterType="com.das.modules.operation.entity.SysManualStatus">
|
||||
<selectKey keyProperty="count" resultType="int" order="BEFORE">
|
||||
select count(*) FROM sys_manual_status where device_id =#{deviceId} and attribute_code =#{attributeCode}
|
||||
</selectKey>
|
||||
<if test="count == 0">
|
||||
INSERT INTO public.sys_manual_status
|
||||
(id, device_id, attribute_code, status)
|
||||
VALUES(#{id}, #{deviceId}, #{attributeCode}, #{status})
|
||||
</if>
|
||||
<if test="count > 0">
|
||||
UPDATE public.sys_manual_status
|
||||
SET status=#{status}
|
||||
WHERE device_id=#{deviceId} AND attribute_code=#{attributeCode}
|
||||
</if>
|
||||
</insert>
|
||||
|
||||
|
||||
|
||||
</mapper>
|
58
das/src/main/resources/mapper/SysOperationLogMapper.xml
Normal file
@ -0,0 +1,58 @@
|
||||
<?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.das.modules.operation.mapper.SysOperationLogMapper">
|
||||
|
||||
<resultMap type="com.das.modules.operation.domain.vo.SysOperationLogVo" id="EnumValuesMap">
|
||||
<result property="id" column="id" jdbcType="BIGINT"/>
|
||||
<result property="userId" column="user_id" jdbcType="VARCHAR"/>
|
||||
<result property="userName" column="user_name" jdbcType="VARCHAR"/>
|
||||
<result property="optTime" column="opt_time" jdbcType="VARCHAR"/>
|
||||
<result property="ipAddress" column="ip_address" jdbcType="VARCHAR"/>
|
||||
<result property="deviceId" column="device_id" jdbcType="BIGINT"/>
|
||||
<result property="attributeCode" column="attribute_code" jdbcType="VARCHAR"/>
|
||||
<result property="attributeName" column="attribute_name" jdbcType="VARCHAR"/>
|
||||
<result property="optDesc" column="opt_desc" jdbcType="VARCHAR"/>
|
||||
<result property="name" column="name" jdbcType="VARCHAR"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="getEventLogList" resultMap="EnumValuesMap">
|
||||
select
|
||||
sol.*,
|
||||
se."name"
|
||||
from sys_operation_log sol
|
||||
left join
|
||||
sys_equipment se on sol.device_id = se.id
|
||||
<where>
|
||||
<if test="info.startTime != null and info.endTime != null">
|
||||
and sol.opt_time >= to_timestamp(#{info.startTime}, 'YYYY-MM-DD HH24:MI:SS')
|
||||
and sol.opt_time <= to_timestamp(#{info.endTime}, 'YYYY-MM-DD HH24:MI:SS')
|
||||
</if>
|
||||
<if test="info.windTurbinesCode != null and info.windTurbinesCode != ''">
|
||||
and se.code =#{info.windTurbinesCode}
|
||||
</if>
|
||||
<if test="info.userName != null and info.userName != ''">
|
||||
and sol.user_name like concat('%',#{info.userName},'%')
|
||||
</if>
|
||||
</where>
|
||||
order by sol.opt_time desc
|
||||
</select>
|
||||
|
||||
<!-- <select id="getEventLogList" resultMap="EnumValuesMap">-->
|
||||
<!-- select e.* from sys_operation_log e-->
|
||||
<!-- <where>-->
|
||||
<!-- <if test="info.startTime != null and info.endTime != null">-->
|
||||
<!-- and e.opt_time >= to_timestamp(#{info.startTime}, 'YYYY-MM-DD HH24:MI:SS')-->
|
||||
<!-- and e.opt_time <= to_timestamp(#{info.endTime}, 'YYYY-MM-DD HH24:MI:SS')-->
|
||||
<!-- </if>-->
|
||||
<!-- <if test="info.attributeCode != null and info.attributeCode != ''">-->
|
||||
<!-- and e.attribute_code =#{info.attributeCode}-->
|
||||
<!-- </if>-->
|
||||
<!-- <if test="info.userName != null and info.userName != ''">-->
|
||||
<!-- and e.user_name like concat('%',#{info.userName},'%')-->
|
||||
<!-- </if>-->
|
||||
<!-- </where>-->
|
||||
<!-- order by e.opt_time desc-->
|
||||
<!-- </select>-->
|
||||
|
||||
|
||||
</mapper>
|
@ -4,6 +4,8 @@
|
||||
- [设备管理接口](api/equipment.md)
|
||||
- [节点管理接口](api/node.md)
|
||||
- [数据访问接口](api/data.md)
|
||||
- [数据字段接口](api/enumPage.md)
|
||||
- [人工操作接口](api/operation.md)
|
||||
- [页面访问接口](api/pages/)
|
||||
- [首页接口](api/pages/home.md)
|
||||
- [数据采集](datacollect/)
|
||||
|
195
docs/api/operation.md
Normal file
@ -0,0 +1,195 @@
|
||||
# 操作相关模块
|
||||
|
||||
## API接口一览表
|
||||
|
||||
| 接口分类 | 接口描述 | API接口 | 权限 |
|
||||
|---------|-----------------| ------------------------------------- | --------------------------- |
|
||||
| 2.1操作记录 | 2.1.1获取相关操作记录 | /api/operation/getEventLogList | |
|
||||
| 2.2手动操作 | 2.2.1设备遥控操作 下令 | /api/operation/command | SYS_AUTHORITY_ID_DEVICE_CTRL|
|
||||
| | 2.2.2设备遥调操作 下令 | /api/operation/setPoint | SYS_AUTHORITY_ID_DEVICE_CTRL|
|
||||
| | 2.2.3设备手工至位 不下令 | /api/operation/manualCommand | SYS_AUTHORITY_ID_DEVICE_CTRL|
|
||||
|
||||
|
||||
### 2.1 操作相关模块接口
|
||||
|
||||
#### 2.1.1 获取相关操作记录
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/operation/getEventLogList
|
||||
|
||||
请求参数
|
||||
|
||||
```json
|
||||
{
|
||||
"startTime": "2024-10-21 23:00:00:00",
|
||||
"endTime": "2024-10-31 23:00:00:00",YES
|
||||
"windTurbinesCode": "SC-01",
|
||||
"userName": "张三",
|
||||
"pageNum": 1,
|
||||
"pageSize": 10
|
||||
}
|
||||
```
|
||||
入参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
| ------------ |---------|-----|--------|
|
||||
| startTime | String | YES | 开始时间 |
|
||||
| endTime | String | YES | 结束时间 |
|
||||
| windTurbinesCode | String | YES | 风机编号 |
|
||||
| userName | String | YES | 操作人员 |
|
||||
| pageNum | Integer | NO | 当前页 |
|
||||
| pageSize | Integer | NO | 每页显示大小 |
|
||||
|
||||
返回报文
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"success": true,
|
||||
"data": {
|
||||
"total": 2,
|
||||
"rows": [
|
||||
{
|
||||
"id": "1851903283326214146",
|
||||
"userName": "张三",
|
||||
"optTime": "2024-10-31 16:25:24",
|
||||
"deviceId": 863256444266222,
|
||||
"attributeCode": "testCode",
|
||||
"attributeName": "测试遥控2",
|
||||
"optDesc": "手动调试2",
|
||||
"name": "A-001"
|
||||
}
|
||||
],
|
||||
"code": 200,
|
||||
"msg": "查询成功"
|
||||
},
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
返参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
|---------------|--------| ---- |--------|
|
||||
| id | Long | 否 | id |
|
||||
| optTime | String | 否 | 时间 |
|
||||
| attributeCode | String | 否 | 风机编号 |
|
||||
| attributeName | String | 否 | 操作类型 |
|
||||
| optDesc | String | 否 | 操作详情 |
|
||||
| userName | String | 否 | 操作员 |
|
||||
| deviceId | Long | 否 | 操作设备id |
|
||||
| name | String | 否 | 设备名称 |
|
||||
|
||||
|
||||
### 2.2 手动操作相关接口
|
||||
|
||||
#### 2.2.1 设备遥控操作 下令
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/operation/command
|
||||
|
||||
请求参数
|
||||
|
||||
```json
|
||||
{
|
||||
"deviceId": 863256444266222,
|
||||
"serviceCode": "setTurbineStop",
|
||||
"serviceName": "风机停机指令",
|
||||
"optDesc": "风机停机",
|
||||
"opValue": 0
|
||||
}
|
||||
```
|
||||
入参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
| ------------ |---------|-----|------|
|
||||
| deviceId | Long | NO | 设备id |
|
||||
| serviceCode | String | NO | 命令编码 |
|
||||
| serviceName | String | YES | 遥控名称 |
|
||||
| optDesc | String | YES | 风机停机、风机启动等操作描述 |
|
||||
| opValue | Integer | NO | 遥控值 |
|
||||
|
||||
返回报文
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"success": true,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2.2 设备遥调操作 下令
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/operation/setPoint
|
||||
|
||||
请求参数
|
||||
|
||||
```json
|
||||
{
|
||||
"deviceId": 863256444266222,
|
||||
"serviceCode": "setGenSpeedLimitValue",
|
||||
"serviceName": "发电机转速给定值",
|
||||
"optDesc": "发电机转速给定值:12.45",
|
||||
"opValue": 12.45
|
||||
}
|
||||
```
|
||||
入参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
| ------------ |---------|-----|------|
|
||||
| deviceId | Long | NO | 设备id |
|
||||
| serviceCode | String | NO | 命令编码 |
|
||||
| serviceName | String | YES | 遥控名称 |
|
||||
| optDesc | String | YES | 设定值描述 |
|
||||
| opValue | Integer | NO | 遥控值 |
|
||||
|
||||
返回报文
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"success": true,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2.3 设备手工至位 不下令
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/operation/manualCommand
|
||||
|
||||
请求参数
|
||||
|
||||
```json
|
||||
{
|
||||
"deviceId": 863256444266222,
|
||||
"serviceCode": "Locked",
|
||||
"serviceName": "风机被锁定",
|
||||
"optDesc": "风机锁定",
|
||||
"opValue": 1
|
||||
}
|
||||
```
|
||||
入参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
| ------------ |---------|-----|------|
|
||||
| deviceId | Long | NO | 设备id |
|
||||
| serviceCode | String | NO | 命令编码 |
|
||||
| serviceName | String | YES | 遥控名称 |
|
||||
| optDesc | String | YES | 风机锁定、风机解锁类似这样的描述 |
|
||||
| opValue | Integer | NO | 遥控值 |
|
||||
|
||||
返回报文
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"success": true,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
@ -2,25 +2,19 @@
|
||||
|
||||
## API接口一览表
|
||||
|
||||
| 接口分类 | 接口描述 | 查询条件 | API接口 | 权限 |
|
||||
|--------|-------------|------------------------------| ---------------------------- | ---------------------------- |
|
||||
| 2.1 首页 | 2.1.1风场概况 | 实时数据,没有入参 | /api/home/windFarmOverview | |
|
||||
| | 2.1.2今日运行状态 | 实时数据,没有入参 | /api/home/currentDayStatus | |
|
||||
| | 2.1.3功率趋势 | 当天24小时数据,5分钟间隔 | /api/home/powerTrends | |
|
||||
| | 2.1.4风机矩阵 | 实时数据,没有参数 | /api/home/windTurbineMatrix | |
|
||||
| | 2.1.5发电量概况 | 昨日数据; | /api/home/generationOverview | |
|
||||
| | 2.1.6发电量趋势 | 日: 当前月的每日数据;同期是去年数据;月:当年每月月数据,12个月; | /api/home/generationTrend | |
|
||||
| | 2.1.7实时告警 | 近一个月内所有的报警数据,滚动显示;已确认的数据 按钮灰色;未确认的显示确认按钮 | /api/home/realTimeAlert | |
|
||||
| | 2.1.8实时告警确认 | 告警记录ID | /api/home/realTimeAlertConfirm | |
|
||||
| 接口分类 | 接口描述 | 查询条件 | API接口 | 权限 |
|
||||
|--------|----------------|-----------| ---------------------------- | ---------------------------- |
|
||||
| 2.1 首页 | 2.1.1风机矩阵 | 实时数据,没有入参 | /api/home/getWindTurbineMatrixData | |
|
||||
| | 2.1.2获取风电场实时数据 | 风电场id | /api/home/getWindFarmRealData | |
|
||||
|
||||
|
||||
## 2.1 首页相关接口
|
||||
|
||||
### 2.1.1 风场概况
|
||||
### 2.1.1 风机矩阵
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/home/windFarmOverview
|
||||
> /api/home/getWindTurbineMatrixData
|
||||
|
||||
请求参数
|
||||
|
||||
@ -32,366 +26,157 @@ POST 请求接口
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"success": true,
|
||||
"data":
|
||||
{
|
||||
"power": 56.2,
|
||||
"windSpeed": 45.3,
|
||||
"dailyUsageHours": 20,
|
||||
"monthlyUsageHours": 78
|
||||
}
|
||||
"code": 200,
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"irn": "1846101273013739522",
|
||||
"name": "A-001",
|
||||
"modelId": "1807685851882508289",
|
||||
"model": "倍福1.5",
|
||||
"belongLine": "线路1",
|
||||
"standard": 1,
|
||||
"nominalCapacity": 66.23,
|
||||
"attributeMap": {
|
||||
"iwindspeed": 10.84000015258789,
|
||||
"iturbineoperationmode": 6,
|
||||
"iyplevel": 0,
|
||||
"ikwhthisday": 0,
|
||||
"igenpower": 0,
|
||||
"gridlostdetected": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
返参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
| ------------- |---------| ---- |--------|
|
||||
| power | Double | 否 | 功率 |
|
||||
| windSpeed | Double | 否 | 风速 |
|
||||
| dailyUsageHours | Integer | 否 | 日利用小时数 |
|
||||
| monthlyUsageHours | Integer | 否 | 月利用小时数 |
|
||||
| ------------ |---------| ---- |--------|
|
||||
| standard | Integer | 否 | 是否标杆 |
|
||||
| nominalCapacity | Double | 否 | 容量 |
|
||||
| iwindspeed | Double | 否 | 风速 |
|
||||
| iyplevel | Double | 否 | 偏航运行模式 |
|
||||
| ikwhthisday | Double | 否 | 日发电量 |
|
||||
| igenpower | Double | 否 | 有功功率 |
|
||||
| gridlostdetected | Double | 否 | 风机电网掉电 |
|
||||
|
||||
|
||||
|
||||
|
||||
### 2.1.2 今日运行状态
|
||||
### 2.1.2 获取风电场实时数据
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/home/currentDayStatus
|
||||
> /api/home/getWindFarmRealData
|
||||
|
||||
请求参数
|
||||
```json
|
||||
{
|
||||
"windFarmId":1846101273013739522
|
||||
}
|
||||
```
|
||||
入参描述
|
||||
|
||||
无
|
||||
|
||||
注:实时数据,没有入参
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
| ------------ |------| ---- |------|
|
||||
| windFarmId | Long | yes | 风场id |
|
||||
|
||||
返回报文
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"success": true,
|
||||
"data":
|
||||
{
|
||||
"windTurbineNum": 40,
|
||||
"installedCapacity": 45.32,
|
||||
"runCapacity": 20.2,
|
||||
"runNum": 78,
|
||||
"standbyCapacity": 63.2,
|
||||
"standbyNum": 35,
|
||||
"faultCapacity": 56.4,
|
||||
"faultNum": 53,
|
||||
"offlineCapacity": 16.4,
|
||||
"offlineNum": 20
|
||||
}
|
||||
"code": 200,
|
||||
"success": true,
|
||||
"data": {
|
||||
"windFarmId": 1848624295633317890,
|
||||
"attributeMap": {
|
||||
"windfarmactivepower": 111.01,
|
||||
"windfarmavgwindspeed": 111.01,
|
||||
"windfarmdayoperationhours": 111.01,
|
||||
"windfarmmonthoperationhours": 111.01,
|
||||
"windfarmdayprodenergy": 111.01,
|
||||
"windfarmmonthprodenergy": 111.01,
|
||||
"windfarmyearprodenergy": 111.01,
|
||||
"windfarmtotalprodenergy": 111.01
|
||||
}
|
||||
},
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
返参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
| ------------- |---------| ---- |------|
|
||||
| windTurbineNum | Integer | 否 | 风机台数 |
|
||||
| installedCapacity | Double | 否 | 装机容量 |
|
||||
| runCapacity | Double | 否 | 运行容量 |
|
||||
| runNum | Integer | 否 | 运行台数 |
|
||||
| standbyCapacity | Double | 否 | 待机容量 |
|
||||
| standbyNum | Integer | 否 | 待机台数 |
|
||||
| faultCapacity | Double | 否 | 故障容量 |
|
||||
| faultNum | Integer | 否 | 故障台数 |
|
||||
| offlineCapacity | Double | 否 | 离线容量 |
|
||||
| offlineNum | Integer | 否 | 离线台数 |
|
||||
| windFarmId | Long | 否 | 风场id |
|
||||
| windfarmactivepower | Double | 否 | 功率 |
|
||||
| windfarmavgwindspeed | Double | 否 | 平均风速 |
|
||||
| windfarmdayoperationhours | Double | 否 | 日利用小时 |
|
||||
| windfarmmonthoperationhours | Double | 否 | 月利用小时 |
|
||||
| windfarmdayprodenergy | Double | 否 | 日发电量 |
|
||||
| windfarmmonthprodenergy | Double | 否 | 月发电量 |
|
||||
| windfarmyearprodenergy | Double | 否 | 年发电量 |
|
||||
| windfarmtotalprodenergy | Double | 否 | 总发电量 |
|
||||
|
||||
|
||||
### 2.1.3 功率趋势
|
||||
### 2.1.3 获取风电场历史数据
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/home/powerTrends
|
||||
> /api/home/getHistoryData
|
||||
|
||||
请求参数
|
||||
|
||||
无
|
||||
|
||||
注:当天24小时数据,5分钟间隔
|
||||
|
||||
返回报文
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"power": 12.6,
|
||||
"windSpeed": 56.3,
|
||||
"dataTime": "2024-10-17 00:00:00"
|
||||
},
|
||||
{
|
||||
"power": 10.6,
|
||||
"windSpeed": 16.3,
|
||||
"dataTime": "2024-10-17 00:05:00"
|
||||
}
|
||||
]
|
||||
"startTime": "123452435324242",
|
||||
"endTime": "123452435924242",
|
||||
"devices": [
|
||||
{
|
||||
"deviceId":"129476828342323",
|
||||
"attributes":["power","windSpeed"]
|
||||
},
|
||||
{
|
||||
"deviceId":"129476828342324",
|
||||
"attributes":["power","dailyUsageHours"]
|
||||
}
|
||||
],
|
||||
"interval": "5m"
|
||||
}
|
||||
```
|
||||
|
||||
返参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
|-------------|--------| ---- |------|
|
||||
| power | Double | 否 | 功率 |
|
||||
| windSpeed | Double | 否 | 风速 |
|
||||
| dataTime | String | 否 | 数据时间 |
|
||||
|
||||
### 2.1.4 风机矩阵
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/home/windTurbineMatrix
|
||||
|
||||
请求参数
|
||||
|
||||
无
|
||||
|
||||
注:实时数据
|
||||
|
||||
返回报文
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"power": 12.6,
|
||||
"windSpeed": 56.3,
|
||||
"dayGeneration": 56.2,
|
||||
"windStatus": "并网",
|
||||
"standard": 1,
|
||||
"windTurbine": "GDWT00001"
|
||||
},
|
||||
{
|
||||
"power": 12.6,
|
||||
"windSpeed": 56.3,
|
||||
"dayGeneration": 56.2,
|
||||
"windStatus": "待机",
|
||||
"standard": 1,
|
||||
"windTurbine": "GDWT00002"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
返参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
|-------------|---------| ---- |---------|
|
||||
| power | Double | 否 | 功率 |
|
||||
| windSpeed | Double | 否 | 风速 |
|
||||
| dayGeneration | Double | 否 | 日发电量 |
|
||||
| windStatus | String | 否 | 风机状态 |
|
||||
| standard | Integer | 否 | 是否为标杆机组 |
|
||||
| windTurbine | String | 否 | 风机编码 |
|
||||
|
||||
### 2.1.5 发电量概况
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/home/generationOverview
|
||||
|
||||
请求参数
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"requestTime":"2024-10-16"
|
||||
}
|
||||
```
|
||||
|
||||
入参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
| ------------ | -------- | ---- |------|
|
||||
| requestTime | String | yes | 请求时间 |
|
||||
|
||||
注:请求时间默认为:昨日时间
|
||||
|
||||
| startTime | String | no | 开始时间戳 |
|
||||
| endTime | String | no | 结束时间戳 |
|
||||
| devices.deviceId | String | no | 设备ID |
|
||||
| devices.attributes | StringArray | no | 要查询实时数据的设备属性列表 |
|
||||
| interval | String | yes | 抽样间隔,1a(毫秒),1s(秒),1m(分),1h(小时),1d(天),1w(周)。 忽略或者值为空时,返回原始数据(不抽样) |
|
||||
| endTime | String | no | 结束时间戳 |
|
||||
返回报文
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"success": true,
|
||||
"data":
|
||||
{
|
||||
"dailyGeneration": 63.2,
|
||||
"dayGeneration": 56.2,
|
||||
"monthGeneration": 60.2,
|
||||
"yearGeneration": 200.6,
|
||||
"totalGeneration": 500.6
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"success": true,
|
||||
"data": {
|
||||
//设备ID
|
||||
"129476828342323":{
|
||||
//属性名
|
||||
"power": {
|
||||
//时间戳列表
|
||||
"times": [123452435924242,123452435924342,123452435924442,123452435924542],
|
||||
//值列表
|
||||
"values": [123.23,35.21,34.56,67]
|
||||
} ,
|
||||
//属性名
|
||||
"windSpeed": {
|
||||
"times": [123452435924242,123452435924342,123452435924442,123452435924542],
|
||||
"values": [123.23,35.21,34.56,67]
|
||||
}
|
||||
|
||||
},
|
||||
.......
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
返参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
|-------------|---------| ---- |-------|
|
||||
| dailyGeneration | Double | 否 | 当日发电量 |
|
||||
| dayGeneration | Double | 否 | 日发电量 |
|
||||
| monthGeneration | Double | 否 | 月发电量 |
|
||||
| yearGeneration | Double | 否 | 年发电量 |
|
||||
| totalGeneration | Double | 否 | 总发电量 |
|
||||
|
||||
### 2.1.6 发电量趋势
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/home/generationTrend
|
||||
|
||||
请求参数
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"timeType":"日"
|
||||
}
|
||||
```
|
||||
注: 日:当前月的每日数据;同期是去年数据;月:当年每月月数据,12个月;
|
||||
|
||||
入参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
| ------------ | -------- | ---- |------|
|
||||
| timeType | String | yes | 时间类型 |
|
||||
|
||||
|
||||
返回报文
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"currentPeriod": 56.3,
|
||||
"samePeriod": 63.5,
|
||||
"generationTime": "2024-10-01"
|
||||
},
|
||||
{
|
||||
"currentPeriod": 66.3,
|
||||
"samePeriod": 73.5,
|
||||
"generationTime": "2024-10-02"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
返参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
|-------------|---------| ---- |-------|
|
||||
| currentPeriod | Double | 否 | 本期 |
|
||||
| samePeriod | Double | 否 | 同期 |
|
||||
| generationTime | Double | 否 | 发电量时间 |
|
||||
|
||||
### 2.1.7 实时告警
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/home/realTimeAlert
|
||||
|
||||
请求参数
|
||||
|
||||
无
|
||||
|
||||
注:近一个月内所有的报警数据,滚动显示;已确认的数据 按钮灰色;未确认的显示确认按钮
|
||||
|
||||
返回报文
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"alertTime": "2024-10-16 12:16:42",
|
||||
"windTurbine": "SC-01",
|
||||
"alertContent": "故障",
|
||||
"alertId": 4562366,
|
||||
"confirmStatus": 0
|
||||
},
|
||||
{
|
||||
"alertTime": "2024-10-16 12:16:42",
|
||||
"windTurbine": "SC-01",
|
||||
"alertContent": "待机",
|
||||
"alertId": 4562366555,
|
||||
"confirmStatus": 1
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
```
|
||||
返参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
|-------------|---------| ---- |------|
|
||||
| alertTime | String | 否 | 告警时间 |
|
||||
| windTurbine | String | 否 | 风机编码 |
|
||||
| alertContent | String | 否 | 告警内容 |
|
||||
| alertId | Long | 否 | 告警id |
|
||||
| confirmStatus | Integer | 否 | 确认状态 |
|
||||
|
||||
### 2.1.8 实时告警-确认
|
||||
|
||||
POST 请求接口
|
||||
|
||||
> /api/home/realTimeAlertConfirm
|
||||
|
||||
请求参数
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"alertId":45566222
|
||||
}
|
||||
```
|
||||
|
||||
入参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
| ------------ |------| ---- |------|
|
||||
| alertId | Long | yes | 告警id |
|
||||
|
||||
|
||||
|
||||
返回报文
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"success": true,
|
||||
"data": [
|
||||
|
||||
]
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
返参描述
|
||||
|
||||
| 参数名 | 参数类型 | 可选 | 描述 |
|
||||
|-------------|---------| ---- |-------|
|
||||
|
||||
|
BIN
docs/deploy/asserts/image-10.png
Normal file
After Width: | Height: | Size: 263 KiB |
BIN
docs/deploy/asserts/image-11.png
Normal file
After Width: | Height: | Size: 615 KiB |
BIN
docs/deploy/asserts/image-2.png
Normal file
After Width: | Height: | Size: 598 KiB |
BIN
docs/deploy/asserts/image-3.png
Normal file
After Width: | Height: | Size: 606 KiB |
BIN
docs/deploy/asserts/image-4.png
Normal file
After Width: | Height: | Size: 389 KiB |
BIN
docs/deploy/asserts/image-5.png
Normal file
After Width: | Height: | Size: 365 KiB |
BIN
docs/deploy/asserts/image-6.png
Normal file
After Width: | Height: | Size: 423 KiB |
BIN
docs/deploy/asserts/image-7.png
Normal file
After Width: | Height: | Size: 348 KiB |
BIN
docs/deploy/asserts/image-8.png
Normal file
After Width: | Height: | Size: 348 KiB |
BIN
docs/deploy/asserts/image-9.png
Normal file
After Width: | Height: | Size: 419 KiB |
@ -1,3 +1,51 @@
|
||||
# OpenEuler 24.03 (LTS) 安装部署
|
||||
|
||||
!> 等待更新
|
||||
## 操作系统安装
|
||||
|
||||
OpenEuler的安装和Centos差不多,这里不详细说明了,就把几个建议步骤说下,这样可以减少后期手动配置的麻烦。
|
||||
|
||||

|
||||
|
||||
> 语言这里选 `English`。
|
||||
|
||||

|
||||
|
||||
> `Keyboard` 不修改。
|
||||
|
||||
> `Installation Source` 不修改。
|
||||
|
||||
> `Installation Destination` 这里要配置磁盘分区。(不是一定要这样配置,会的随意配置)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
点左下角的`+`,新建分区
|
||||
|
||||

|
||||
|
||||
`Mount Point`填: /das, 大小不用填,默认会使用剩余所有空间。
|
||||
|
||||

|
||||
|
||||
点击 `Done`完成分区配置。
|
||||
|
||||
> `Lanage Support` 这个需要勾上中文。
|
||||
|
||||

|
||||
|
||||
> `Software Selection` 这里基础环境选择"Server", 右侧再勾上一个开发工具包,以防后续内网环境下编译安装程序时需要。
|
||||
|
||||

|
||||
|
||||
> `Network & Hostname` 根据实际情况配置。
|
||||
|
||||
> `Time & Date` 时区不用修改了。
|
||||
|
||||
下面的root账号密码设置下,普通用户就不用创建了。
|
||||
|
||||
## 系统配置
|
||||
|
||||
!> 未完待续
|
@ -1,8 +1,19 @@
|
||||
<template>
|
||||
<el-aside v-if="!navTabs.state.tabFullScreen" :class="'layout-aside-' + config.layout.layoutMode + ' ' + (config.layout.shrink ? 'shrink' : '')">
|
||||
<el-aside
|
||||
v-if="!navTabs.state.tabFullScreen"
|
||||
:class="[
|
||||
config.layout.menuCollapse ? '' : 'layout-aside-collapse',
|
||||
'layout-aside-' + config.layout.layoutMode + ' ' + (config.layout.shrink ? 'shrink' : ''),
|
||||
]"
|
||||
>
|
||||
<Logo v-if="config.layout.menuShowTopBar" />
|
||||
|
||||
<MenuVerticalChildren v-if="config.layout.layoutMode == 'Double'" />
|
||||
<MenuVertical v-else />
|
||||
<div class="layout-toggle-bar" @click="onMenuCollapse">
|
||||
<div class="layout-toggle-bar__top"></div>
|
||||
<div class="layout-toggle-bar__bottom"></div>
|
||||
</div>
|
||||
</el-aside>
|
||||
</template>
|
||||
|
||||
@ -22,6 +33,14 @@ const config = useConfig()
|
||||
const navTabs = useNavTabs()
|
||||
|
||||
const menuWidth = computed(() => config.menuWidth())
|
||||
|
||||
const onMenuCollapse = () => {
|
||||
if (config.layout.menuCollapse) {
|
||||
config.setLayout('menuCollapse', false)
|
||||
} else {
|
||||
config.setLayout('menuCollapse', true)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@ -43,6 +62,7 @@ const menuWidth = computed(() => config.menuWidth())
|
||||
overflow: hidden;
|
||||
transition: width 0.3s ease;
|
||||
width: v-bind(menuWidth);
|
||||
position: relative;
|
||||
}
|
||||
.shrink {
|
||||
position: fixed;
|
||||
@ -50,4 +70,60 @@ const menuWidth = computed(() => config.menuWidth())
|
||||
left: 0;
|
||||
z-index: 9999999;
|
||||
}
|
||||
.layout-toggle-bar {
|
||||
cursor: pointer;
|
||||
height: 72px;
|
||||
width: 32px;
|
||||
position: absolute;
|
||||
top: calc(50% - 36px);
|
||||
|
||||
right: -9px;
|
||||
.layout-toggle-bar__top {
|
||||
background-color: rgba(191, 191, 191, 1);
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
border-radius: 2px;
|
||||
height: 38px;
|
||||
left: 14px;
|
||||
transition:
|
||||
background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
.layout-toggle-bar__bottom {
|
||||
background-color: rgba(191, 191, 191, 1);
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
border-radius: 2px;
|
||||
height: 38px;
|
||||
left: 14px;
|
||||
top: 34px;
|
||||
transition:
|
||||
background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
&:hover {
|
||||
.layout-toggle-bar__top {
|
||||
background-color: rgba(153, 153, 153, 1);
|
||||
transform: rotate(-12deg) scale(1.15) translateY(-2px);
|
||||
}
|
||||
.layout-toggle-bar__bottom {
|
||||
background-color: rgba(153, 153, 153, 1);
|
||||
transform: rotate(12deg) scale(1.15) translateY(2px);
|
||||
}
|
||||
}
|
||||
}
|
||||
.layout-aside-collapse {
|
||||
.layout-toggle-bar {
|
||||
&:hover {
|
||||
.layout-toggle-bar__top {
|
||||
background-color: rgba(153, 153, 153, 1);
|
||||
transform: rotate(12deg) scale(1.15) translateY(-2px);
|
||||
}
|
||||
.layout-toggle-bar__bottom {
|
||||
background-color: rgba(153, 153, 153, 1);
|
||||
transform: rotate(-12deg) scale(1.15) translateY(2px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -29,6 +29,10 @@ const state = reactive({
|
||||
defaultActive: '',
|
||||
})
|
||||
|
||||
const width = computed(() => {
|
||||
return config.layout.menuCollapse ? '5px' : '20px'
|
||||
})
|
||||
|
||||
const verticalMenusScrollbarHeight = computed(() => {
|
||||
let menuTopBarHeight = 0
|
||||
if (config.layout.menuShowTopBar) {
|
||||
@ -70,7 +74,8 @@ onBeforeRouteUpdate((to) => {
|
||||
}
|
||||
.layouts-menu-vertical {
|
||||
border: 0;
|
||||
padding: 10px 20px 30px 20px;
|
||||
width: 100%;
|
||||
padding: 10px v-bind(width) 30px v-bind(width);
|
||||
--el-menu-bg-color: transparent;
|
||||
--el-menu-active-color: #ffffff;
|
||||
li,
|
||||
|
@ -350,7 +350,7 @@ const menu = [
|
||||
],
|
||||
},
|
||||
]
|
||||
debugger
|
||||
|
||||
function transformNode(menu: any) {
|
||||
menu = menu.map((node: any) => {
|
||||
return {
|
||||
|
@ -10,7 +10,7 @@ export const useConfig = defineStore(
|
||||
/* 全局 */
|
||||
showDrawer: false,
|
||||
// 是否收缩布局(小屏设备)
|
||||
shrink: false,
|
||||
shrink: true,
|
||||
// 后台布局方式,可选值<Default|Classic|Streamline|Double>
|
||||
layoutMode: 'Classic',
|
||||
// 后台主页面切换动画,可选值<slide-right|slide-left|el-fade-in-linear|el-fade-in|el-zoom-in-center|el-zoom-in-top|el-zoom-in-bottom>
|
||||
@ -70,7 +70,7 @@ export const useConfig = defineStore(
|
||||
return layout.menuCollapse ? '0px' : layout.menuWidth + 'px'
|
||||
}
|
||||
// 菜单是否折叠
|
||||
return layout.menuCollapse ? '64px' : layout.menuWidth + 'px'
|
||||
return layout.menuCollapse ? '74px' : layout.menuWidth + 'px'
|
||||
}
|
||||
|
||||
function setLang(val: string) {
|
||||
|
@ -218,12 +218,12 @@ const queryWindBlower = () => {
|
||||
}
|
||||
})
|
||||
windBlowerValue.value = windBlowerList.value.map((item) => item.irn)
|
||||
reportTableData.value = windBlowerList.value.map((val) => {
|
||||
return {
|
||||
deviceId: val.irn,
|
||||
id: shortUuid(),
|
||||
}
|
||||
})
|
||||
// reportTableData.value = windBlowerList.value.map((val) => {
|
||||
// return {
|
||||
// deviceId: val.irn,
|
||||
// id: shortUuid(),
|
||||
// }
|
||||
// })
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -236,7 +236,7 @@ const selectWindBlower = (val: any) => {
|
||||
}
|
||||
})
|
||||
windBlowerValue.value = rankWindBlowerValue
|
||||
reportTableData.value = reportTableData.value.filter((item: any) => windBlowerValue.value.includes(item.deviceId))
|
||||
// reportTableData.value = reportTableData.value.filter((item: any) => windBlowerValue.value.includes(item.deviceId))
|
||||
} else {
|
||||
reportTableData.value = []
|
||||
}
|
||||
@ -394,6 +394,7 @@ const queryHistoryData = () => {
|
||||
reportTableData.value = lastResults.flat()
|
||||
if (!reportTableData.value.length) {
|
||||
ElMessage.warning('查询数据为空!')
|
||||
reportTableData.value = []
|
||||
}
|
||||
} else {
|
||||
ElMessage.warning('查询数据为空!')
|
||||
@ -434,7 +435,7 @@ const generateMissingData = (data: any, deviceIds: any) => {
|
||||
if (!deviceData.length) {
|
||||
const generatedData = firstNonEmptyArray.map((item: any) => {
|
||||
const generatedItem = {
|
||||
id: item.id + 1,
|
||||
id: shortUuid(),
|
||||
time: item.time,
|
||||
deviceId: deviceId,
|
||||
} as any
|
||||
|
308
ui/dasadmin/src/views/backend/report/RunningReport.vue
Normal file
@ -0,0 +1,308 @@
|
||||
<template>
|
||||
<div class="report" style="width: 100%; height: 100%">
|
||||
<div class="topForm">
|
||||
<div class="forms">
|
||||
<el-space>
|
||||
<div style="min-width: 30px">时间</div>
|
||||
<el-date-picker
|
||||
v-if="selectedIndex == 0"
|
||||
style="height: 40px"
|
||||
v-model="timeValue"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="选择日期"
|
||||
/>
|
||||
<el-date-picker v-else style="height: 40px" v-model="timeValue" type="month" value-format="YYYY-MM" placeholder="选择月份" />
|
||||
<div style="width: 20px"></div>
|
||||
<div class="buttons">
|
||||
<el-button class="button" :icon="Search" @click="queryHistoryData" type="primary">查询</el-button>
|
||||
<el-button class="button" :icon="Upload" type="primary" plain>导出</el-button>
|
||||
</div>
|
||||
</el-space>
|
||||
<div class="reportButtons">
|
||||
<el-button
|
||||
v-for="(button, index) in buttons"
|
||||
:key="index"
|
||||
:type="selectedIndex === index ? 'primary' : 'default'"
|
||||
@click="selectButton(index)"
|
||||
size="small"
|
||||
>
|
||||
{{ button }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-table
|
||||
class="mainReport"
|
||||
:columns="reportTableColumn"
|
||||
:data="reportTableData"
|
||||
:row-key="(row: any) => row.id"
|
||||
:row-style="tableRowClassName"
|
||||
v-loading="reportLoading"
|
||||
>
|
||||
<el-table-column prop="time" label="时间" fixed width="180px" align="center"> </el-table-column>
|
||||
<el-table-column
|
||||
v-for="item in reportTableColumn.length ? reportTableColumn : [{ prop: '', label: '', unit: '' }]"
|
||||
:key="item.prop"
|
||||
:label="item.label"
|
||||
:prop="item.prop"
|
||||
align="center"
|
||||
:width="150"
|
||||
>
|
||||
<template #header="scope">
|
||||
<div class="header-cell">
|
||||
<div style="margin-right: 2px">
|
||||
{{ item.label }} <br />
|
||||
{{ item.unit ? `(${item.unit})` : '' }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
{{ scope.row[item.prop] || scope.row[item.prop] === 0 ? scope.row[item.prop] : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, nextTick, onMounted } from 'vue'
|
||||
import { ElMessage, TableInstance } from 'element-plus'
|
||||
import { Search, Upload } from '@element-plus/icons-vue'
|
||||
import { WindBlowerList } from './type'
|
||||
import { queryWindTurbinesPages, historyReq } from '/@/api/backend/statAnalysis/request'
|
||||
import { shortUuid } from '/@/utils/random'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
const selectedIndex = ref(0)
|
||||
const buttons = ['日报', '月报']
|
||||
const attributeCodes = ref(['iKWhThisDay', 'iOperationHoursDay', 'iWindSpeed'])
|
||||
const selectButton = (index: number) => {
|
||||
if (selectedIndex.value == index) return
|
||||
selectedIndex.value = index
|
||||
refreshBaseTable()
|
||||
}
|
||||
const refreshBaseTable = () => {
|
||||
timeValue.value = ''
|
||||
reportTableColumn.value = []
|
||||
reportTableData.value = []
|
||||
if (selectedIndex.value == 0) {
|
||||
attributeCodes.value = ['iKWhThisDay', 'iOperationHoursDay', 'iWindSpeed']
|
||||
windBlowerList.value.forEach((item: WindBlowerList) => {
|
||||
const generateEach = [
|
||||
{ prop: item.irn + 'iKWhThisDay', label: item.name + '风机发电量', irn: item.irn, name: 'iKWhThisDay', unit: 'kWh' },
|
||||
{ prop: item.irn + 'iOperationHoursDay', label: item.name + '风机等效小时', irn: item.irn, name: 'iOperationHoursDay', unit: 'h' },
|
||||
{ prop: item.irn + 'iWindSpeed', label: item.name + '风机平均风速', irn: item.irn, name: 'iWindSpeed', unit: 'm/s' },
|
||||
]
|
||||
reportTableColumn.value.push(...generateEach)
|
||||
})
|
||||
} else {
|
||||
attributeCodes.value = ['DayProdEnergy', 'DayOperationHours', 'iWindSpeed']
|
||||
windBlowerList.value.forEach((item: WindBlowerList) => {
|
||||
const generateEach = [
|
||||
{ prop: item.irn + 'DayProdEnergy', label: item.name + '风机发电量', irn: item.irn, name: 'DayProdEnergy', unit: 'kWh' },
|
||||
{ prop: item.irn + 'DayOperationHours', label: item.name + '风机等效小时', irn: item.irn, name: 'DayOperationHours', unit: 'h' },
|
||||
{ prop: item.irn + 'iWindSpeed', label: item.name + '风机平均风速', irn: item.irn, name: 'iWindSpeed', unit: 'm/s' },
|
||||
]
|
||||
reportTableColumn.value.push(...generateEach)
|
||||
})
|
||||
}
|
||||
}
|
||||
const tableRowClassName = ({ rowIndex }: any) => {
|
||||
if (rowIndex % 2 === 1) {
|
||||
return { background: '#ebf3f9' }
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
const windBlowerList = ref<WindBlowerList[]>([])
|
||||
// 时间
|
||||
const timeValue = ref('')
|
||||
// 间隔
|
||||
const interval = ref('')
|
||||
// 测点名称
|
||||
const queryWindBlower = () => {
|
||||
queryWindTurbinesPages().then((res) => {
|
||||
if (res.code == 200) {
|
||||
windBlowerList.value = res.data.map((item: WindBlowerList) => {
|
||||
const generateEach = [
|
||||
{ prop: item.irn + 'iKWhThisDay', label: item.name + '风机发电量', irn: item.irn, name: 'iKWhThisDay', unit: 'kWh' },
|
||||
{
|
||||
prop: item.irn + 'iOperationHoursDay',
|
||||
label: item.name + '风机等效小时',
|
||||
irn: item.irn,
|
||||
name: 'iOperationHoursDay',
|
||||
unit: 'h',
|
||||
},
|
||||
{ prop: item.irn + 'iWindSpeed', label: item.name + '风机平均风速', irn: item.irn, name: 'iWindSpeed', unit: 'm/s' },
|
||||
]
|
||||
// DayProdEnergy
|
||||
// DayOperationHours
|
||||
reportTableColumn.value.push(...generateEach)
|
||||
return {
|
||||
irn: item.irn,
|
||||
name: item.name ?? '-',
|
||||
modelId: item.modelId,
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const reportLoading = ref(false)
|
||||
const reportTableColumn = ref([]) as any
|
||||
|
||||
const reportTableData = ref([] as any)
|
||||
|
||||
const getFirstAndLastDate = (dateString: String) => {
|
||||
const [year, month] = dateString.split('-').map(Number)
|
||||
const firstDate = new Date(year, month - 1, 1)
|
||||
const lastDate = new Date(year, month, 0)
|
||||
const formattedFirstDate = `${year}-${String(month).padStart(2, '0')}-${String(firstDate.getDate()).padStart(2, '0')}`
|
||||
const formattedLastDate = `${year}-${String(month).padStart(2, '0')}-${String(lastDate.getDate()).padStart(2, '0')}`
|
||||
return [formattedFirstDate, formattedLastDate]
|
||||
}
|
||||
|
||||
const queryHistoryData = () => {
|
||||
if (!timeValue.value.length) return ElMessage.warning('请选择时间!')
|
||||
reportLoading.value = true
|
||||
const requestData = {
|
||||
interval: '',
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
devices: windBlowerList.value.map((deviceId: any) => {
|
||||
return {
|
||||
deviceId: deviceId.irn,
|
||||
attributes: [...attributeCodes.value],
|
||||
}
|
||||
}),
|
||||
} as any
|
||||
|
||||
if (selectedIndex.value == 0) {
|
||||
requestData.interval = '1h'
|
||||
requestData.startTime = new Date(timeValue.value + ' 00:00:00').getTime()
|
||||
requestData.endTime = new Date(timeValue.value + ' 23:59:59').getTime()
|
||||
} else {
|
||||
requestData.interval = '1d'
|
||||
requestData.startTime = new Date(getFirstAndLastDate(timeValue.value)[0] + ' 00:00:00').getTime()
|
||||
requestData.endTime = new Date(getFirstAndLastDate(timeValue.value)[1] + ' 23:59:59').getTime()
|
||||
}
|
||||
reportLoading.value = true
|
||||
|
||||
historyReq(requestData).then((res) => {
|
||||
if (res.code == 200) {
|
||||
const result = res.data
|
||||
if (Object.keys(result)?.length) {
|
||||
const transResults = [] as any
|
||||
windBlowerList.value.forEach((device: any) => {
|
||||
const realResult = result[device.irn]
|
||||
if (realResult) {
|
||||
let tableData = [] as any
|
||||
attributeCodes.value.forEach((item: any) => {
|
||||
if (Object.keys(realResult).includes(item)) {
|
||||
tableData.push({
|
||||
name: item,
|
||||
times: realResult[item].times,
|
||||
value: realResult[item].values,
|
||||
deviceId: device.irn,
|
||||
prop: device.irn + item,
|
||||
})
|
||||
}
|
||||
})
|
||||
const processedData = new Map()
|
||||
if (tableData.length) {
|
||||
tableData.forEach(({ name, times, value, deviceId, prop }: any) => {
|
||||
times.forEach((time: number, index: number) => {
|
||||
if (!processedData.has(time)) {
|
||||
processedData.set(time, { id: shortUuid(), time: timestampToTime(time), deviceId, prop })
|
||||
}
|
||||
processedData.get(time)[prop] = value[index]
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return transResults.push(Array.from(processedData.values()))
|
||||
} else {
|
||||
return transResults.push([])
|
||||
}
|
||||
})
|
||||
const mergedData = transResults.flat().reduce((acc: any, current: any) => {
|
||||
const found = acc.find((item: any) => item.time === current.time)
|
||||
if (found) {
|
||||
Object.keys(current).forEach((key) => {
|
||||
if (key !== 'id' && key !== 'time' && key !== 'prop') {
|
||||
found[key] = current[key]
|
||||
}
|
||||
})
|
||||
} else {
|
||||
acc.push({ ...current })
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
reportTableData.value = mergedData
|
||||
if (!reportTableData.value.length) {
|
||||
ElMessage.warning('查询数据为空!')
|
||||
reportTableData.value = []
|
||||
}
|
||||
reportLoading.value = false
|
||||
} else {
|
||||
ElMessage.warning('查询数据为空!')
|
||||
reportTableData.value = []
|
||||
reportLoading.value = false
|
||||
}
|
||||
} else {
|
||||
reportLoading.value = false
|
||||
ElMessage.warning('查询失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 时间转换
|
||||
const timestampToTime = (timestamp: any) => {
|
||||
let timestamps = timestamp ? timestamp : null
|
||||
let date = new Date(timestamps)
|
||||
let Y = date.getFullYear() + '-'
|
||||
let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'
|
||||
let D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' '
|
||||
let h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':'
|
||||
let m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':'
|
||||
let s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
|
||||
return Y + M + D + h + m + s
|
||||
}
|
||||
onMounted(() => {
|
||||
queryWindBlower()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.topForm {
|
||||
// height: 90px;
|
||||
.buttons {
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
flex: 1;
|
||||
}
|
||||
.reportButtons {
|
||||
width: 100%;
|
||||
margin: 5px;
|
||||
padding-right: 5px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
.mainReport {
|
||||
width: 100%;
|
||||
height: calc(100% - 110px);
|
||||
}
|
||||
|
||||
.commonSelect {
|
||||
min-width: 250px;
|
||||
:deep(.el-select__wrapper) {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
height: 40px;
|
||||
}
|
||||
</style>
|
@ -312,7 +312,7 @@ const reportTableColumn = ref([
|
||||
},
|
||||
])
|
||||
|
||||
const reportTableData = ref([])
|
||||
const reportTableData = ref([]) as any
|
||||
const idCounter = ref(0)
|
||||
const queryHistoryData = () => {
|
||||
if (!windBlowerValue.value) return ElMessage.warning('请选择风机!')
|
||||
@ -359,10 +359,15 @@ const queryHistoryData = () => {
|
||||
})
|
||||
})
|
||||
}
|
||||
reportTableData.value = Array.from(processedData.values()) as any
|
||||
reportTableData.value = Array.from(processedData.values())
|
||||
if (!reportTableData.value.length) {
|
||||
ElMessage.warning('查询数据为空!')
|
||||
reportTableData.value = []
|
||||
}
|
||||
reportLoading.value = false
|
||||
} else {
|
||||
ElMessage.warning('查询数据为空!')
|
||||
reportTableData.value = []
|
||||
reportLoading.value = false
|
||||
}
|
||||
} else {
|
||||
|
@ -2,7 +2,9 @@
|
||||
<div class="report">
|
||||
<el-container class="mainContainer">
|
||||
<el-tabs v-model="activeIndex" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane label="运行报表" name="1" class="runningReport"> 运行报表 </el-tab-pane>
|
||||
<el-tab-pane label="运行报表" name="1" class="runningReport">
|
||||
<RunningReport v-if="activeIndex == '1'"></RunningReport>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="单机报表" name="2" class="singleReport">
|
||||
<SingleReport v-if="activeIndex == '2'"></SingleReport>
|
||||
</el-tab-pane>
|
||||
@ -18,12 +20,13 @@
|
||||
import { ref } from 'vue'
|
||||
import SingleReport from './SingleReport.vue'
|
||||
import MulipleReport from './MulipleReport.vue'
|
||||
import RunningReport from './RunningReport.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
import { useAdminInfo } from '/@/stores/adminInfo'
|
||||
const adminInfo = useAdminInfo()
|
||||
|
||||
const activeIndex = ref('2')
|
||||
const activeIndex = ref('1')
|
||||
const handleClick = (val: any) => {
|
||||
activeIndex.value = val.props.name
|
||||
}
|
||||
@ -45,12 +48,7 @@ const handleClick = (val: any) => {
|
||||
height: calc(100% - 80px);
|
||||
}
|
||||
}
|
||||
.runningReport {
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
}
|
||||
}
|
||||
.runningReport,
|
||||
.singleReport,
|
||||
.mltipleReport {
|
||||
width: 100%;
|
||||
|
@ -43,8 +43,6 @@ import { reactive, ref, watch, defineEmits, onMounted, nextTick } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { ModelAttributeFieldsEnums, GetModelAttributeType } from '/@/views/backend/auth/model/type'
|
||||
import { getModelAttributeListReq, getRealValueListReq } from '/@/api/backend/deviceModel/request'
|
||||
import { queryWindTurbinesPages, historyReq } from '/@/api/backend/statAnalysis/request'
|
||||
import { WindBlowerList, RequestData, Devices } from './type'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
const props = defineProps({
|
||||
@ -95,12 +93,6 @@ const tableColumn = [
|
||||
const tableData = ref<any[]>([])
|
||||
const emit = defineEmits(['handleSelections'])
|
||||
const selectedRows = ref([] as any)
|
||||
// const handleSelectionChange = (selection) => {
|
||||
// selectedRows.value = selection
|
||||
// emit('handleSelections', selectedRows.value)
|
||||
// }
|
||||
const windBlowerValue = ref('')
|
||||
const windBlowerList = ref<WindBlowerList[]>([])
|
||||
const selectWindBlower = (val: any) => {
|
||||
getCompleteData()
|
||||
}
|
||||
@ -246,37 +238,12 @@ const pageSetting = reactive({
|
||||
const getcurrentPage = () => {
|
||||
getCompleteData()
|
||||
}
|
||||
const queryWindBlower = () => {
|
||||
return new Promise((resolve) => {
|
||||
queryWindTurbinesPages().then((res) => {
|
||||
if (res.code == 200) {
|
||||
windBlowerList.value = res.data.map((item: WindBlowerList) => {
|
||||
return {
|
||||
irn: item.irn,
|
||||
name: item.name ?? '-',
|
||||
modelId: item.modelId,
|
||||
}
|
||||
})
|
||||
if (windBlowerList.value.length) {
|
||||
windBlowerValue.value = windBlowerList.value[0].irn
|
||||
}
|
||||
resolve(windBlowerList.value)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
if (props.isMultiple) {
|
||||
queryWindBlower().then((res) => {
|
||||
getCompleteData()
|
||||
})
|
||||
} else {
|
||||
getCompleteData()
|
||||
}
|
||||
getCompleteData()
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -305,9 +272,7 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
// queryWindBlower()
|
||||
})
|
||||
onMounted(() => {})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -61,7 +61,7 @@ const props = defineProps({
|
||||
},
|
||||
})
|
||||
|
||||
const selectedIndex = ref(null)
|
||||
const selectedIndex: any = ref(null)
|
||||
const tableColumn = [
|
||||
{
|
||||
type: 'selection',
|
||||
@ -98,12 +98,12 @@ const tableColumn = [
|
||||
]
|
||||
const tableData = ref<any[]>([])
|
||||
const emit = defineEmits(['handleRadioChange'])
|
||||
const handleRadioChange = (row) => {
|
||||
const handleRadioChange = (row: any) => {
|
||||
selectedIndex.value = row.attributeCode
|
||||
emit('handleRadioChange', row)
|
||||
}
|
||||
const getAttributeList = () => {
|
||||
const requestData: GetModelAttributeType = {
|
||||
const requestData: any = {
|
||||
iotModelId: props.iotModelId,
|
||||
pageNum: pageSetting.current,
|
||||
pageSize: pageSetting.pageSize,
|
||||
|
@ -3,6 +3,7 @@
|
||||
<el-menu :default-active="activeIndex" class="headerList" mode="horizontal" @select="handleSelect">
|
||||
<el-menu-item v-for="(item, index) in headerList" :index="index" :key="index"> {{ item }} </el-menu-item>
|
||||
</el-menu>
|
||||
<PowerCurveAnalysis v-if="activeIndex == 0"></PowerCurveAnalysis>
|
||||
<TrendAnalysis v-if="activeIndex == 1"></TrendAnalysis>
|
||||
<TrendComparison v-if="activeIndex == 2"></TrendComparison>
|
||||
</div>
|
||||
@ -13,12 +14,13 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useConfig } from '/@/stores/config'
|
||||
import TrendAnalysis from './trendAnalysis.vue'
|
||||
import TrendComparison from './trendComparison.vue'
|
||||
import PowerCurveAnalysis from './powerCurveAnalysis.vue'
|
||||
const config = useConfig()
|
||||
const activeIndex = ref(1)
|
||||
const activeIndex = ref(0)
|
||||
const { t } = useI18n()
|
||||
const headerList = [t('statAnalysis.PowerCurveAnalysis'), t('statAnalysis.trendAnalysis'), t('statAnalysis.trendComparison')]
|
||||
|
||||
const handleSelect = (index) => {
|
||||
const handleSelect = (index: number) => {
|
||||
activeIndex.value = index
|
||||
}
|
||||
</script>
|
||||
|
@ -0,0 +1,348 @@
|
||||
<template>
|
||||
<div class="contain">
|
||||
<el-header class="headerPart">
|
||||
<div class="topLeft">
|
||||
<div class="selectPart">
|
||||
<span>{{ t('statAnalysis.deviceId') }}</span>
|
||||
<el-select v-model="statAnalysisDeviceId" :placeholder="'请选择' + t('statAnalysis.deviceId')" class="statAnalysisSelect">
|
||||
<el-option v-for="v in statAnalysisSelectOptions.deviceId" :key="v.value" :label="v.label" :value="v.value"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="topRight">
|
||||
<el-button type="primary" @click="statAnalysisOperate()">{{ t('statAnalysis.search') }}</el-button>
|
||||
<el-button style="color: #0064aa" @click="statAnalysiImport()">{{ t('statAnalysis.import') }}</el-button>
|
||||
<el-button style="color: #0064aa" @click="statAnalysisExport()">{{ t('statAnalysis.export') }}</el-button>
|
||||
</div>
|
||||
</el-header>
|
||||
<div class="timeColumns">
|
||||
<div class="headerPart">
|
||||
<div class="topLeft">
|
||||
<div class="selectPart">
|
||||
<span>{{ t('statAnalysis.time') }}</span>
|
||||
<el-date-picker
|
||||
class="datetime-picker"
|
||||
v-model="statAnalysisTime"
|
||||
:type="statAnalysisInterval == '1d' ? 'daterange' : 'datetimerange'"
|
||||
:value-format="statAnalysisInterval == '1d' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
||||
:teleported="false"
|
||||
:shortcuts="shortcuts"
|
||||
/>
|
||||
</div>
|
||||
<div class="selectPart">
|
||||
<span>{{ t('statAnalysis.interval') }}</span>
|
||||
<el-select v-model="statAnalysisInterval" :placeholder="'请选择' + t('statAnalysis.interval')" class="statAnalysisSelect">
|
||||
<el-option v-for="v in statAnalysisSelectOptions.interval" :key="v.value" :label="v.label" :value="v.value"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="chartContainer" style="width: 100%; height: 400px; border: 1px solid rgb(217, 217, 217)"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { queryWindTurbinesPages, historyReq } from '/@/api/backend/statAnalysis/request'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import * as echarts from 'echarts'
|
||||
import { index } from '/@/api/backend'
|
||||
const { t } = useI18n()
|
||||
const statAnalysisTime = ref('')
|
||||
const statAnalysisInterval = ref('')
|
||||
const statAnalysisDeviceId = ref('')
|
||||
const statAnalysisSelectOptions: any = reactive({
|
||||
interval: [
|
||||
{ label: '五分钟', value: '5m' },
|
||||
{ label: '十五分钟', value: '15m' },
|
||||
{ label: '一小时', value: '1h' },
|
||||
{ label: '一天', value: '1d' },
|
||||
{ label: '原始', value: 'NONE' },
|
||||
],
|
||||
deviceId: [],
|
||||
})
|
||||
|
||||
const chartContainer = ref<HTMLElement | null>(null)
|
||||
|
||||
const option: any = {
|
||||
tooltip: {
|
||||
formatter: function (params: any) {
|
||||
return '功率:' + params.value[0] + 'KW ' + ' <br/>' + '风速:' + params.value[1] + 'm/s'
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
icon: 'circle',
|
||||
itemGap: 20,
|
||||
itemWidth: 8,
|
||||
itemHeight: 8,
|
||||
data: [],
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
name: 'KW',
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
name: 'm/s',
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
series: [],
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '3%',
|
||||
},
|
||||
}
|
||||
|
||||
const chart: any = ref(null)
|
||||
onMounted(() => {
|
||||
if (chartContainer.value) {
|
||||
chart.value = echarts.init(chartContainer.value)
|
||||
chart.value.setOption(option)
|
||||
}
|
||||
queryWindTurbines()
|
||||
})
|
||||
const queryWindTurbines = () => {
|
||||
queryWindTurbinesPages().then((res) => {
|
||||
if (res.code == 200) {
|
||||
statAnalysisSelectOptions.deviceId = res.data.map((item: any) => {
|
||||
return {
|
||||
value: item.irn,
|
||||
label: item.name ?? '-',
|
||||
iotModelId: item.modelId,
|
||||
}
|
||||
})
|
||||
// console.log(statAnalysisSelectOptions.deviceId)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
window.onresize = () => {
|
||||
chart.value.resize()
|
||||
}
|
||||
|
||||
const shortcuts = [
|
||||
{
|
||||
text: '今天',
|
||||
value: () => {
|
||||
const start = getFormattedDate(0) + ' 00:00:00'
|
||||
const end = new Date()
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '昨天',
|
||||
value: () => {
|
||||
const start = getFormattedDate(-1) + ' 00:00:00'
|
||||
const end = getFormattedDate(-1) + ' 23:59:59'
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '前3天',
|
||||
value: () => {
|
||||
const start = getFormattedDate(-3) + ' 00:00:00'
|
||||
const end = getFormattedDate(-1) + ' 23:59:59'
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '本周',
|
||||
value: () => {
|
||||
return getDateRange('week')
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '本月',
|
||||
value: () => {
|
||||
return getDateRange('month')
|
||||
},
|
||||
},
|
||||
]
|
||||
const getFormattedDate = (offset: number) => {
|
||||
const date = new Date()
|
||||
date.setDate(date.getDate() + offset)
|
||||
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
const getDateRange = (type: 'week' | 'month') => {
|
||||
const today = new Date()
|
||||
if (type === 'week') {
|
||||
const dayOfWeek = today.getDay()
|
||||
const startOfWeek = new Date(today)
|
||||
startOfWeek.setDate(today.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1))
|
||||
startOfWeek.setHours(0, 0, 0, 0)
|
||||
const endOfWeek = new Date(startOfWeek)
|
||||
endOfWeek.setDate(startOfWeek.getDate() + 6)
|
||||
endOfWeek.setHours(23, 59, 59, 999)
|
||||
return [startOfWeek, endOfWeek]
|
||||
}
|
||||
if (type === 'month') {
|
||||
const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1)
|
||||
startOfMonth.setHours(0, 0, 0, 0)
|
||||
const endOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0)
|
||||
endOfMonth.setHours(23, 59, 59, 999)
|
||||
return [startOfMonth, endOfMonth]
|
||||
}
|
||||
}
|
||||
|
||||
const statAnalysisOperate = () => {
|
||||
option.series = []
|
||||
chart.value.setOption(option, { notMerge: true })
|
||||
|
||||
const requestData = {
|
||||
devices: [
|
||||
{
|
||||
deviceId: statAnalysisDeviceId.value,
|
||||
attributes: ['iGenPower', 'iWindSpeed'],
|
||||
},
|
||||
],
|
||||
interval: statAnalysisInterval.value,
|
||||
startTime: new Date(statAnalysisTime.value[0]).getTime(),
|
||||
endTime: new Date(statAnalysisTime.value[1]).getTime(),
|
||||
}
|
||||
historyDataReq(requestData)
|
||||
}
|
||||
const historyDataReq = (data: any) => {
|
||||
historyReq(data).then((res) => {
|
||||
if (res.code == 200) {
|
||||
const resData = res.data[statAnalysisDeviceId.value]
|
||||
console.log(resData)
|
||||
if (resData) {
|
||||
const iGenPower = resData['iGenPower']['values']
|
||||
const iWindSpeed = resData['iWindSpeed']['values']
|
||||
const seriesData = iGenPower.map((item: any, index: number) => {
|
||||
return [item, iWindSpeed[index]]
|
||||
})
|
||||
const series = {
|
||||
type: 'scatter',
|
||||
data: seriesData,
|
||||
}
|
||||
option.series.push(series)
|
||||
console.log('🚀 ~ historyReq ~ option:', option)
|
||||
|
||||
chart.value.setOption(option)
|
||||
}
|
||||
} else {
|
||||
ElMessage.warning('查询失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const statAnalysisExport = () => {}
|
||||
const statAnalysiImport = () => {}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.statAnalysis {
|
||||
height: 100%;
|
||||
.headerPart {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.topLeft {
|
||||
display: flex;
|
||||
.icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.selectPart {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
margin-right: 20px;
|
||||
span {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.customName {
|
||||
width: fit-content;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.statAnalysisSelect {
|
||||
width: 200px;
|
||||
:deep(.el-select__wrapper) {
|
||||
height: 40px;
|
||||
}
|
||||
:deep(.el-input__inner) {
|
||||
height: 38px;
|
||||
}
|
||||
}
|
||||
.max,
|
||||
.min,
|
||||
.average {
|
||||
border-radius: 6px;
|
||||
height: 40px;
|
||||
width: 72px;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
}
|
||||
.max {
|
||||
background: rgba(254, 55, 49, 0.2);
|
||||
border: 1px solid #fe3731;
|
||||
color: #fe3731;
|
||||
}
|
||||
.min {
|
||||
background: rgba(0, 160, 150, 0.2);
|
||||
border: 1px solid #00a096;
|
||||
color: #00a096;
|
||||
}
|
||||
.average {
|
||||
background: rgba(0, 100, 170, 0.2);
|
||||
border: 1px solid #0064aa;
|
||||
color: #0064aa;
|
||||
}
|
||||
}
|
||||
.dialog-footer button:first-child {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.topRight {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.el-button {
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.timeColumns {
|
||||
max-height: 120px;
|
||||
overflow: hidden;
|
||||
.headerPart {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
&.expand {
|
||||
max-height: max-content;
|
||||
height: auto;
|
||||
overflow: inherit;
|
||||
}
|
||||
}
|
||||
.timeColumns.expand + div.ralIcon {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
.ralIcon {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
#myEChart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -24,12 +24,7 @@
|
||||
</div>
|
||||
<div class="selectPart">
|
||||
<span>{{ t('statAnalysis.interval') }}</span>
|
||||
<el-select
|
||||
v-model="statAnalysisSelect.interval"
|
||||
@change="selectstatAnalysis('interval')"
|
||||
:placeholder="'请选择' + t('statAnalysis.interval')"
|
||||
class="statAnalysisSelect"
|
||||
>
|
||||
<el-select v-model="statAnalysisSelect.interval" :placeholder="'请选择' + t('statAnalysis.interval')" class="statAnalysisSelect">
|
||||
<el-option v-for="v in statAnalysisSelectOptions.interval" :key="v.value" :label="v.label" :value="v.value"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
@ -83,7 +78,7 @@
|
||||
<div v-if="times.length > 2" class="ralIcon" @click="handleClick">
|
||||
<el-icon :size="20" color="#0064AA"><DArrowRight /></el-icon>
|
||||
</div>
|
||||
<div ref="chartContainer" style="width: 100%; height: 400px"></div>
|
||||
<div ref="chartContainer" style="width: 100%; height: 400px; border: 1px solid rgb(217, 217, 217)"></div>
|
||||
<el-dialog v-model="showMeasure" title="测点名称" :width="800">
|
||||
<template #header>
|
||||
<div class="measureSlotHeader">
|
||||
@ -103,10 +98,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onUnmounted, reactive, ref, watch, nextTick, onMounted, computed } from 'vue'
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { queryWindTurbinesPages, historyReq } from '/@/api/backend/statAnalysis/request'
|
||||
import { ElMessage, ElMenu } from 'element-plus'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { DArrowRight, Plus, Delete } from '@element-plus/icons-vue'
|
||||
import MeasurementPage from './analysisAttributes.vue'
|
||||
import * as echarts from 'echarts'
|
||||
@ -118,23 +113,22 @@ const statAnalysisSelect = reactive({
|
||||
interval: '',
|
||||
time: '',
|
||||
})
|
||||
const times = reactive([{ time: '' }])
|
||||
const addTime = (index) => {
|
||||
const times: any = reactive([{ time: '' }])
|
||||
const addTime = (index: any) => {
|
||||
times.push({ time: '' })
|
||||
customName.push(String(index + 2))
|
||||
customName.push(statAnalysisSelect.attributes + String(index + 2))
|
||||
}
|
||||
const switchTime = (index) => {
|
||||
const switchTime = (index: number) => {
|
||||
times.splice(index, 1)
|
||||
customName.splice(index, 1)
|
||||
calculate.splice(index, 1)
|
||||
xData.splice(index, 1)
|
||||
}
|
||||
const timechange = (value) => {
|
||||
const timechange = (value: any) => {
|
||||
const count = getTimeIntervals(times[0][0], times[0][1])
|
||||
const count1 = getTimeIntervals(times[value][0], times[value][1])
|
||||
if (count !== count1) {
|
||||
times[value] = { time: '' }
|
||||
value = ElMessage.warning('查询时间点错误,请重新输入')
|
||||
ElMessage.warning('查询时间点错误,请重新输入')
|
||||
}
|
||||
}
|
||||
const isExpand = ref(false)
|
||||
@ -145,7 +139,7 @@ const handleClick = () => {
|
||||
const iotModelId = ref('')
|
||||
const irn = ref('')
|
||||
const attributesChange = () => {
|
||||
const row = statAnalysisSelectOptions.deviceId.filter((item) => {
|
||||
const row: any = statAnalysisSelectOptions.deviceId.filter((item: any) => {
|
||||
return item.value == statAnalysisSelect.deviceId
|
||||
})
|
||||
if (row.length) {
|
||||
@ -163,11 +157,11 @@ const deviceIdChange = () => {
|
||||
}
|
||||
|
||||
const showMeasure = ref(false)
|
||||
const selectedAttrRow = ref({
|
||||
const selectedAttrRow: any = ref({
|
||||
attributeCode: '',
|
||||
attributeName: '',
|
||||
})
|
||||
const handleRadioChange = (value) => {
|
||||
const handleRadioChange = (value: any) => {
|
||||
const { attributeCode, attributeName } = { ...value }
|
||||
selectedAttrRow.attributeCode = attributeCode
|
||||
selectedAttrRow.attributeName = attributeName
|
||||
@ -176,11 +170,14 @@ const selectstatAnalysisAttributes = () => {
|
||||
statAnalysisSelect.attributes = selectedAttrRow.attributeName
|
||||
statAnalysisSelect.attributeCode = selectedAttrRow.attributeCode
|
||||
showMeasure.value = false
|
||||
customName.forEach((item: any, index: number, arr: any) => {
|
||||
arr[index] = statAnalysisSelect.attributes + String(index + 1)
|
||||
})
|
||||
}
|
||||
|
||||
const chartContainer = ref<HTMLElement | null>(null)
|
||||
|
||||
const option = {
|
||||
const option: any = {
|
||||
tooltip: {},
|
||||
legend: {
|
||||
icon: 'circle',
|
||||
@ -190,7 +187,6 @@ const option = {
|
||||
data: [],
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [],
|
||||
},
|
||||
yAxis: {
|
||||
@ -203,7 +199,7 @@ const option = {
|
||||
},
|
||||
}
|
||||
|
||||
const statAnalysisSelectOptions = reactive({
|
||||
const statAnalysisSelectOptions: any = reactive({
|
||||
interval: [
|
||||
{ label: '五分钟', value: '5m' },
|
||||
{ label: '十五分钟', value: '15m' },
|
||||
@ -213,8 +209,8 @@ const statAnalysisSelectOptions = reactive({
|
||||
],
|
||||
deviceId: [],
|
||||
})
|
||||
const customName = reactive(['1'])
|
||||
const chart = ref(null)
|
||||
const customName = reactive([statAnalysisSelect.attributes + '1'])
|
||||
const chart: any = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
if (chartContainer.value) {
|
||||
@ -226,7 +222,7 @@ onMounted(() => {
|
||||
const queryWindTurbines = () => {
|
||||
queryWindTurbinesPages().then((res) => {
|
||||
if (res.code == 200) {
|
||||
statAnalysisSelectOptions.deviceId = res.data.map((item) => {
|
||||
statAnalysisSelectOptions.deviceId = res.data.map((item: any) => {
|
||||
return {
|
||||
value: item.irn,
|
||||
label: item.name ?? '-',
|
||||
@ -241,11 +237,6 @@ window.onresize = () => {
|
||||
chart.value.resize()
|
||||
}
|
||||
|
||||
const handleSelect = (index) => {
|
||||
activeIndex.value = index
|
||||
}
|
||||
const selectstatAnalysis = () => {}
|
||||
|
||||
const shortcuts = [
|
||||
{
|
||||
text: '今天',
|
||||
@ -284,7 +275,7 @@ const shortcuts = [
|
||||
},
|
||||
},
|
||||
]
|
||||
const getFormattedDate = (offset) => {
|
||||
const getFormattedDate = (offset: number) => {
|
||||
const date = new Date()
|
||||
date.setDate(date.getDate() + offset)
|
||||
|
||||
@ -313,9 +304,9 @@ const getDateRange = (type: 'week' | 'month') => {
|
||||
return [startOfMonth, endOfMonth]
|
||||
}
|
||||
}
|
||||
const getTimeIntervals = (startTimestamp, endTimestamp) => {
|
||||
const startDate = new Date(startTimestamp)
|
||||
const endDate = new Date(endTimestamp)
|
||||
const getTimeIntervals = (startTimestamp: number, endTimestamp: number) => {
|
||||
const startDate: any = new Date(startTimestamp)
|
||||
const endDate: any = new Date(endTimestamp)
|
||||
let count = 0
|
||||
|
||||
switch (statAnalysisSelect.interval) {
|
||||
@ -332,7 +323,7 @@ const getTimeIntervals = (startTimestamp, endTimestamp) => {
|
||||
count = Math.floor((endDate - startDate) / (1 * 60 * 60 * 1000))
|
||||
break
|
||||
case '1d':
|
||||
count = c((endDate - startDate) / (1 * 24 * 60 * 60 * 1000))
|
||||
count = Math.floor((endDate - startDate) / (1 * 24 * 60 * 60 * 1000))
|
||||
break
|
||||
// default:
|
||||
// throw new Error('Invalid interval')
|
||||
@ -340,14 +331,14 @@ const getTimeIntervals = (startTimestamp, endTimestamp) => {
|
||||
|
||||
return count
|
||||
}
|
||||
const calculate = reactive([{ max: '', min: '', average: '' }])
|
||||
var xDatas = []
|
||||
const calculate: any = reactive([{ max: '', min: '', average: '' }])
|
||||
var xDatas: any = []
|
||||
const statAnalysisOperate = () => {
|
||||
option.series = []
|
||||
option.legend.data = []
|
||||
xDatas = []
|
||||
chart.value.setOption(option, { notMerge: true })
|
||||
times.forEach((time, index) => {
|
||||
times.forEach((time: any, index: number) => {
|
||||
if (time[0] && time[1]) {
|
||||
const requestData = {
|
||||
devices: [
|
||||
@ -365,7 +356,7 @@ const statAnalysisOperate = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const historyDataReq = (data, index) => {
|
||||
const historyDataReq = (data: any, index: number) => {
|
||||
historyReq(data).then((res) => {
|
||||
if (res.code == 200) {
|
||||
const deviceId = statAnalysisSelect.deviceId
|
||||
@ -374,19 +365,15 @@ const historyDataReq = (data, index) => {
|
||||
if (resData) {
|
||||
const xData = resData['times']
|
||||
const yData = resData['values']
|
||||
calculate[index] = {
|
||||
max: Math.floor(Math.max(...yData)),
|
||||
min: Math.floor(Math.min(...yData)),
|
||||
average: Math.floor(yData.reduce((a, b) => a + b, 0) / yData.length),
|
||||
}
|
||||
calculate[index] = calculateStats(yData)
|
||||
xDatas.push({
|
||||
series: String(customName[index]),
|
||||
data: xData,
|
||||
})
|
||||
option.tooltip = {
|
||||
show: true,
|
||||
formatter: function (params) {
|
||||
const matchData = xDatas.filter((x) => x.series == params.seriesName)
|
||||
formatter: function (params: any) {
|
||||
const matchData = xDatas.filter((x: any) => x.series == params.seriesName)
|
||||
const x = timestampToTime(matchData[0]['data'][params.dataIndex])
|
||||
return `${params.marker} ${params.seriesName} <br/> ${x} <b>${params.data}</b>`
|
||||
},
|
||||
@ -413,7 +400,19 @@ const historyDataReq = (data, index) => {
|
||||
const statAnalysisExport = () => {}
|
||||
const statAnalysiImport = () => {}
|
||||
|
||||
const timestampToTime = (timestamp) => {
|
||||
function calculateStats(numbers: any) {
|
||||
const max = Math.max(...numbers)
|
||||
const min = Math.min(...numbers)
|
||||
const sum = numbers.reduce((acc: number, current: number) => acc + current, 0)
|
||||
const average = sum / numbers.length
|
||||
|
||||
return {
|
||||
max: max.toFixed(2),
|
||||
min: min.toFixed(2),
|
||||
average: average.toFixed(2),
|
||||
}
|
||||
}
|
||||
const timestampToTime = (timestamp: any) => {
|
||||
timestamp = timestamp ? timestamp : null
|
||||
let date = new Date(timestamp)
|
||||
let Y = date.getFullYear() + '-'
|
||||
@ -482,7 +481,7 @@ const timestampToTime = (timestamp) => {
|
||||
color: #0064aa;
|
||||
}
|
||||
.customName {
|
||||
width: 80px;
|
||||
width: fit-content;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@
|
||||
<div v-if="statAnalysisDeviceId.length > 2" class="ralIcon" @click="handleClick">
|
||||
<el-icon :size="20" color="#0064AA"><DArrowRight /></el-icon>
|
||||
</div>
|
||||
<div ref="chartContainer" style="width: 100%; height: 400px"></div>
|
||||
<div ref="chartContainer" style="width: 100%; height: 400px; border: 1px solid rgb(217, 217, 217)"></div>
|
||||
<el-dialog v-model="showMeasure" title="测点名称" :width="800">
|
||||
<template #header>
|
||||
<div class="measureSlotHeader">
|
||||
@ -116,8 +116,8 @@ const statAnalysisTime = ref('')
|
||||
const statAnalysisInterval = ref('')
|
||||
const statAnalysisDeviceId = reactive([''])
|
||||
const statAnalysisAttributes = reactive([''])
|
||||
const statAnalysisAttributeCode = reactive([])
|
||||
const statAnalysisSelectOptions = reactive({
|
||||
const statAnalysisAttributeCode: any = reactive([])
|
||||
const statAnalysisSelectOptions: any = reactive({
|
||||
interval: [
|
||||
{ label: '五分钟', value: '5m' },
|
||||
{ label: '十五分钟', value: '15m' },
|
||||
@ -128,13 +128,12 @@ const statAnalysisSelectOptions = reactive({
|
||||
deviceId: [],
|
||||
})
|
||||
const openModelIndex = ref(0)
|
||||
const selectediotModelId = ref('')
|
||||
const addDevice = (index) => {
|
||||
const addDevice = (index: number) => {
|
||||
statAnalysisDeviceId.push('')
|
||||
statAnalysisAttributes.push('')
|
||||
customName.push(String(index + 2))
|
||||
}
|
||||
const switchDevice = (index) => {
|
||||
const switchDevice = (index: number) => {
|
||||
statAnalysisDeviceId.splice(index, 1)
|
||||
statAnalysisAttributes.splice(index, 1)
|
||||
statAnalysisAttributeCode.splice(index, 1)
|
||||
@ -148,8 +147,8 @@ const handleClick = () => {
|
||||
}
|
||||
const iotModelId = ref('')
|
||||
const irn = ref('')
|
||||
const selectAtteibutes = (index) => {
|
||||
const row = statAnalysisSelectOptions.deviceId.filter((item) => {
|
||||
const selectAtteibutes = (index: number) => {
|
||||
const row = statAnalysisSelectOptions.deviceId.filter((item: any) => {
|
||||
return item.value == statAnalysisDeviceId[index]
|
||||
})
|
||||
if (row.length) {
|
||||
@ -162,7 +161,7 @@ const selectAtteibutes = (index) => {
|
||||
}
|
||||
}
|
||||
|
||||
const deviceIdChange = (index) => {
|
||||
const deviceIdChange = (index: number) => {
|
||||
statAnalysisAttributeCode[index] = ''
|
||||
statAnalysisAttributes[index] = ''
|
||||
}
|
||||
@ -172,7 +171,7 @@ const selectedAttrRow = reactive({
|
||||
attributeCode: '',
|
||||
attributeName: '',
|
||||
})
|
||||
const handleRadioChange = (value) => {
|
||||
const handleRadioChange = (value: any) => {
|
||||
const { attributeCode, attributeName } = { ...value }
|
||||
selectedAttrRow.attributeCode = attributeCode
|
||||
selectedAttrRow.attributeName = attributeName
|
||||
@ -181,11 +180,14 @@ const selectstatAnalysisAttributes = () => {
|
||||
statAnalysisAttributes[openModelIndex.value] = selectedAttrRow.attributeName
|
||||
statAnalysisAttributeCode[openModelIndex.value] = selectedAttrRow.attributeCode
|
||||
showMeasure.value = false
|
||||
customName.forEach((item: any, index: number, arr: any) => {
|
||||
arr[openModelIndex.value] = statAnalysisAttributes[openModelIndex.value] + String(index + 1)
|
||||
})
|
||||
}
|
||||
|
||||
const chartContainer = ref<HTMLElement | null>(null)
|
||||
|
||||
const option = {
|
||||
const option: any = {
|
||||
tooltip: {},
|
||||
legend: {
|
||||
icon: 'circle',
|
||||
@ -195,7 +197,6 @@ const option = {
|
||||
data: [],
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [],
|
||||
axisLabel: {
|
||||
rotate: 15,
|
||||
@ -212,7 +213,7 @@ const option = {
|
||||
}
|
||||
|
||||
const customName = reactive(['1'])
|
||||
const chart = ref(null)
|
||||
const chart: any = ref(null)
|
||||
onMounted(() => {
|
||||
if (chartContainer.value) {
|
||||
chart.value = echarts.init(chartContainer.value)
|
||||
@ -223,7 +224,7 @@ onMounted(() => {
|
||||
const queryWindTurbines = () => {
|
||||
queryWindTurbinesPages().then((res) => {
|
||||
if (res.code == 200) {
|
||||
statAnalysisSelectOptions.deviceId = res.data.map((item) => {
|
||||
statAnalysisSelectOptions.deviceId = res.data.map((item: any) => {
|
||||
return {
|
||||
value: item.irn,
|
||||
label: item.name ?? '-',
|
||||
@ -238,11 +239,6 @@ window.onresize = () => {
|
||||
chart.value.resize()
|
||||
}
|
||||
|
||||
const handleSelect = (index) => {
|
||||
activeIndex.value = index
|
||||
}
|
||||
const selectstatAnalysis = () => {}
|
||||
|
||||
const shortcuts = [
|
||||
{
|
||||
text: '今天',
|
||||
@ -281,7 +277,7 @@ const shortcuts = [
|
||||
},
|
||||
},
|
||||
]
|
||||
const getFormattedDate = (offset) => {
|
||||
const getFormattedDate = (offset: number) => {
|
||||
const date = new Date()
|
||||
date.setDate(date.getDate() + offset)
|
||||
|
||||
@ -315,8 +311,8 @@ const statAnalysisOperate = () => {
|
||||
option.series = []
|
||||
chart.value.setOption(option, { notMerge: true })
|
||||
const attributes = statAnalysisAttributeCode
|
||||
const devices = statAnalysisDeviceId.reduce((deviceId, curr, index) => {
|
||||
const existing = deviceId.find((item) => item.deviceId === curr)
|
||||
const devices = statAnalysisDeviceId.reduce((deviceId: any, curr, index) => {
|
||||
const existing: any = deviceId.find((item: any) => item.deviceId === curr)
|
||||
if (existing) {
|
||||
existing.attributes.push(statAnalysisAttributeCode[index])
|
||||
} else {
|
||||
@ -330,10 +326,10 @@ const statAnalysisOperate = () => {
|
||||
startTime: new Date(statAnalysisTime.value[0]).getTime(),
|
||||
endTime: new Date(statAnalysisTime.value[1]).getTime(),
|
||||
}
|
||||
historyDataReq(requestData, devices)
|
||||
historyDataReq(requestData)
|
||||
}
|
||||
const calculate = reactive([{ max: '', min: '', average: '' }])
|
||||
const historyDataReq = (data, devices) => {
|
||||
const calculate: any = reactive([{ max: '', min: '', average: '' }])
|
||||
const historyDataReq = (data: any) => {
|
||||
historyReq(data).then((res) => {
|
||||
if (res.code == 200) {
|
||||
const resData = res.data
|
||||
@ -353,13 +349,9 @@ const historyDataReq = (data, devices) => {
|
||||
type: 'line',
|
||||
data: yData,
|
||||
}
|
||||
calculate[dataIndex] = {
|
||||
max: Math.floor(Math.max(...yData)),
|
||||
min: Math.floor(Math.min(...yData)),
|
||||
average: Math.floor(yData.reduce((a, b) => a + b, 0) / yData.length),
|
||||
}
|
||||
calculate[dataIndex] = calculateStats(yData)
|
||||
option.legend.data.push(customName[dataIndex])
|
||||
option.xAxis.data = xData.map((item) => timestampToTime(item))
|
||||
option.xAxis.data = xData.map((item: any) => timestampToTime(item))
|
||||
option.series.push(seriesData)
|
||||
chart.value.setOption(option)
|
||||
})
|
||||
@ -371,17 +363,28 @@ const historyDataReq = (data, devices) => {
|
||||
})
|
||||
}
|
||||
|
||||
const findAllOccurrences = (arr, target) => {
|
||||
return arr.map((value, index) => (value === target ? index : -1)).filter((index) => index !== -1)
|
||||
const findAllOccurrences = (arr: any, target: any) => {
|
||||
return arr.map((value: any, index: number) => (value === target ? index : -1)).filter((index: number) => index !== -1)
|
||||
}
|
||||
|
||||
const getCommonElements = (arr1, arr2) => {
|
||||
return arr1.filter((item) => arr2.some((x) => x === item))
|
||||
const getCommonElements = (arr1: any, arr2: any) => {
|
||||
return arr1.filter((item: any) => arr2.some((x: any) => x === item))
|
||||
}
|
||||
const statAnalysisExport = () => {}
|
||||
const statAnalysiImport = () => {}
|
||||
function calculateStats(numbers: any) {
|
||||
const max = Math.max(...numbers)
|
||||
const min = Math.min(...numbers)
|
||||
const sum = numbers.reduce((acc: number, current: number) => acc + current, 0)
|
||||
const average = sum / numbers.length
|
||||
|
||||
const timestampToTime = (timestamp) => {
|
||||
return {
|
||||
max: max.toFixed(2),
|
||||
min: min.toFixed(2),
|
||||
average: average.toFixed(2),
|
||||
}
|
||||
}
|
||||
const timestampToTime = (timestamp: any) => {
|
||||
timestamp = timestamp ? timestamp : null
|
||||
let date = new Date(timestamp)
|
||||
let Y = date.getFullYear() + '-'
|
||||
@ -417,7 +420,7 @@ const timestampToTime = (timestamp) => {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.customName {
|
||||
width: 80px;
|
||||
width: fit-content;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.statAnalysisSelect {
|
||||
|
@ -57,23 +57,26 @@ const viteConfig = ({ mode }: ConfigEnv): UserConfig => {
|
||||
...createProxy(VITE_APP_PROXY),
|
||||
},
|
||||
},
|
||||
esbuild: {
|
||||
drop: ['console', 'debugger'],
|
||||
},
|
||||
build: {
|
||||
cssCodeSplit: false,
|
||||
sourcemap: false,
|
||||
outDir: VITE_OUT_DIR,
|
||||
emptyOutDir: true,
|
||||
chunkSizeWarningLimit: 1500,
|
||||
terserOptions: {
|
||||
compress: {
|
||||
keep_infinity: true,
|
||||
// Used to delete console in production environment
|
||||
drop_console: true,
|
||||
drop_debugger: true,
|
||||
},
|
||||
output: {
|
||||
comments: true, // 去掉注释内容
|
||||
},
|
||||
},
|
||||
// terserOptions: {
|
||||
// compress: {
|
||||
// keep_infinity: true,
|
||||
// // Used to delete console in production environment
|
||||
// drop_console: true,
|
||||
// drop_debugger: true,
|
||||
// },
|
||||
// output: {
|
||||
// comments: true, // 去掉注释内容
|
||||
// },
|
||||
// },
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
|