Compare commits
No commits in common. "38379d9638fe40e62aae64a14c83f0de8c88fa11" and "5ddf1ddc5ddf90e89cee6bab858ec17f3e787d6b" have entirely different histories.
38379d9638
...
5ddf1ddc5d
@ -0,0 +1,55 @@
|
|||||||
|
package com.das.modules.page.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import com.das.modules.page.domian.dto.TrendAnalyseDto;
|
||||||
|
import com.das.modules.page.domian.dto.TrendContrastDto;
|
||||||
|
import com.das.modules.page.service.StatisticalAnalysisService;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequestMapping("/api/page/statistical")
|
||||||
|
@RestController
|
||||||
|
public class StatisticalAnalysisController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StatisticalAnalysisService statisticalAnalysisService;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 趋势分析 (单机分析)Excel导出
|
||||||
|
* @param param 查询条件
|
||||||
|
*/
|
||||||
|
@PostMapping("/trendAnalyseExport")
|
||||||
|
public void trendAnalyseExport(@RequestBody List<TrendAnalyseDto> param ,HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
statisticalAnalysisService.trendAnalyseExport(param, request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功率曲线Excel导出
|
||||||
|
* @param param 查询条件
|
||||||
|
*/
|
||||||
|
@PostMapping("/powerCurveExport")
|
||||||
|
public void powerCurveExport(@RequestBody TrendAnalyseDto param ,HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
statisticalAnalysisService.powerCurveExport(param, request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 趋势对比(多机对比) Excel导出
|
||||||
|
* @param param 查询条件
|
||||||
|
*/
|
||||||
|
@PostMapping("/trendContrastExport")
|
||||||
|
public void trendContrastExport(@RequestBody TrendContrastDto param , HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
statisticalAnalysisService.trendContrastExport(param, request, response);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.das.modules.page.service;
|
||||||
|
|
||||||
|
import com.das.modules.page.domian.dto.TrendAnalyseDto;
|
||||||
|
import com.das.modules.page.domian.dto.TrendContrastDto;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface StatisticalAnalysisService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 趋势分析Excel导出
|
||||||
|
* @param param 查询条件
|
||||||
|
*/
|
||||||
|
void trendAnalyseExport(List<TrendAnalyseDto> param, HttpServletRequest request, HttpServletResponse response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功率曲线Excel导出
|
||||||
|
* @param param 查询条件
|
||||||
|
*/
|
||||||
|
void powerCurveExport(TrendAnalyseDto param, HttpServletRequest request, HttpServletResponse response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 趋势对比Excel导出
|
||||||
|
* @param param 查询条件
|
||||||
|
*/
|
||||||
|
void trendContrastExport(TrendContrastDto param, HttpServletRequest request, HttpServletResponse response);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,807 @@
|
|||||||
|
package com.das.modules.page.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.poi.excel.ExcelUtil;
|
||||||
|
import cn.hutool.poi.excel.ExcelWriter;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.das.common.constant.StatisticalAnalysisConstant;
|
||||||
|
import com.das.common.constant.StatisticalAnalysisFunctionConstant;
|
||||||
|
import com.das.common.exceptions.ServiceException;
|
||||||
|
import com.das.common.utils.BeanCopyUtils;
|
||||||
|
import com.das.modules.curve.domain.entity.CurveItemEntity;
|
||||||
|
import com.das.modules.curve.service.TheoreticalPowerCurveService;
|
||||||
|
import com.das.modules.data.domain.SnapshotValueQueryParam;
|
||||||
|
import com.das.modules.data.domain.TSValueQueryParam;
|
||||||
|
import com.das.modules.data.domain.WindowValueQueryParam;
|
||||||
|
import com.das.modules.data.service.DataService;
|
||||||
|
import com.das.modules.equipment.entity.SysIotModelField;
|
||||||
|
import com.das.modules.equipment.mapper.SysIotModelFieldMapper;
|
||||||
|
import com.das.modules.page.domian.dto.TrendAnalyseDto;
|
||||||
|
import com.das.modules.page.domian.dto.TrendContrastDto;
|
||||||
|
import com.das.modules.page.service.StatisticalAnalysisService;
|
||||||
|
import jakarta.servlet.ServletOutputStream;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.poi.ss.usermodel.ClientAnchor;
|
||||||
|
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||||
|
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||||
|
import org.apache.poi.ss.util.CellRangeAddress;
|
||||||
|
import org.apache.poi.xddf.usermodel.chart.*;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFChart;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFDrawing;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DataService dataService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TheoreticalPowerCurveService theoreticalPowerCurveService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SysIotModelFieldMapper sysIotModelFieldMapper;
|
||||||
|
|
||||||
|
private final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 趋势分析Excel导出
|
||||||
|
*
|
||||||
|
* @param param 查询条件
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void trendAnalyseExport(List<TrendAnalyseDto> param, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
//根据条件获取历史数据
|
||||||
|
List<Map<String, Map<String, Map<String, Object>>>> mapsList = new ArrayList<>();
|
||||||
|
for (TrendAnalyseDto trendAnalyseDto : param) {
|
||||||
|
//瞬时值
|
||||||
|
if (trendAnalyseDto.getCalFunction().equals(StatisticalAnalysisFunctionConstant.INTERPOLATION)){
|
||||||
|
TSValueQueryParam tsValueQueryParam = new TSValueQueryParam();
|
||||||
|
BeanCopyUtils.copy(trendAnalyseDto,tsValueQueryParam);
|
||||||
|
Map<String, Map<String, Map<String, Object>>> resultMap = dataService.queryTimeSeriesValues(tsValueQueryParam);
|
||||||
|
mapsList.add(resultMap);
|
||||||
|
}else {
|
||||||
|
//其他
|
||||||
|
WindowValueQueryParam windowValueQueryParam = new WindowValueQueryParam();
|
||||||
|
BeanCopyUtils.copy(trendAnalyseDto,windowValueQueryParam);
|
||||||
|
Map<String, Map<String, Map<String, Object>>> stringMapMap = dataService.queryWindowsValues(windowValueQueryParam);
|
||||||
|
mapsList.add(stringMapMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//获取Excel的列
|
||||||
|
LinkedHashMap<String, String> map = getTrendColumnName(param);
|
||||||
|
List<Map<String, Object>> dataList = new ArrayList<>();
|
||||||
|
// 遍历数据,填充Excel数据集
|
||||||
|
setTrendAnalyseExcelValue(mapsList, dataList);
|
||||||
|
ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx");
|
||||||
|
//设置Excel样式
|
||||||
|
setExcelStyle(writer, map, dataList);
|
||||||
|
//下载Excel
|
||||||
|
downloadExcel(response, writer,StatisticalAnalysisConstant.TREND_ANALYSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功率曲线Excel导出
|
||||||
|
*
|
||||||
|
* @param param 查询条件
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void powerCurveExport(TrendAnalyseDto param, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
//获取理论数据
|
||||||
|
List<CurveItemEntity> curveItemEntitieList = theoreticalPowerCurveService.
|
||||||
|
queryCurveItemByParent(param.getMadeinfactory(), param.getModel());
|
||||||
|
//根据条件获取历史数据
|
||||||
|
TSValueQueryParam tsValueQueryParam = new TSValueQueryParam();
|
||||||
|
BeanCopyUtils.copy(param,tsValueQueryParam);
|
||||||
|
Map<String, Map<String, Map<String, Object>>> resultMap = dataService.queryTimeSeriesValues(tsValueQueryParam);
|
||||||
|
//显示曲线,需要计算功率的平均值
|
||||||
|
if (param.getDisplayCurve()==1){
|
||||||
|
try {
|
||||||
|
List<Double> windSpeedList = new ArrayList<>();
|
||||||
|
List<Double> powerList = new ArrayList<>();
|
||||||
|
getPowerCurveValueList(resultMap, powerList, windSpeedList);
|
||||||
|
List<Map<String, List<Double>>> maps = calculateAverages(windSpeedList, powerList);
|
||||||
|
setPowerCurveValueList(resultMap, maps);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("计算功率曲线平均值失败:"+e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<Map<String, Object>> dataList = new ArrayList<>();
|
||||||
|
//填充功率曲线,Excel的数据集
|
||||||
|
setPowerCurveExcelValue(resultMap, dataList, curveItemEntitieList);
|
||||||
|
//获取功率曲线的列
|
||||||
|
LinkedHashMap<String, String> map = getPowerCurveColumnName(param);
|
||||||
|
ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx");
|
||||||
|
//设置Excel样式
|
||||||
|
setExcelStyle(writer, map, dataList);
|
||||||
|
//下载Excel
|
||||||
|
downloadExcel(response, writer,StatisticalAnalysisConstant.POWER_CURVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 趋势对比Excel导出
|
||||||
|
* @param param 查询条件
|
||||||
|
* @return TD数据库数据
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void trendContrastExport(TrendContrastDto param, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
Map<String, Map<String, Map<String, Object>>> maps = null;
|
||||||
|
//瞬时值,历史区间数据查询
|
||||||
|
if (param.getCalFunction().equals(StatisticalAnalysisFunctionConstant.INTERPOLATION)){
|
||||||
|
TSValueQueryParam tsValueQueryParam = new TSValueQueryParam();
|
||||||
|
BeanCopyUtils.copy(param,tsValueQueryParam);
|
||||||
|
maps = dataService.queryTimeSeriesValues(tsValueQueryParam);
|
||||||
|
}else {
|
||||||
|
WindowValueQueryParam windowparam = new WindowValueQueryParam();
|
||||||
|
BeanCopyUtils.copy(param,windowparam);
|
||||||
|
maps = dataService.queryWindowsValues(windowparam);
|
||||||
|
}
|
||||||
|
//自定义别名 别名的key和实体类中的名称要对应上!
|
||||||
|
LinkedHashMap<String, String> map = gettrendContrastColumnName(param);
|
||||||
|
List<Map<String, Object>> dataList = new ArrayList<>();
|
||||||
|
// 遍历数据,将数据添加到dataList中
|
||||||
|
setTrendContrastExcelValue(maps, dataList);
|
||||||
|
ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx");
|
||||||
|
//设置Excel样式
|
||||||
|
setExcelStyle(writer, map, dataList);
|
||||||
|
//下载Excel
|
||||||
|
downloadExcel(response, writer,StatisticalAnalysisConstant.TREND_CONTRAST);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置Excel样式
|
||||||
|
*
|
||||||
|
* @param writer ExcelWriter
|
||||||
|
* @param map 表格的列
|
||||||
|
* @param dataList Excel数据集
|
||||||
|
*/
|
||||||
|
private void setExcelStyle(ExcelWriter writer, LinkedHashMap<String, String> map, List<Map<String, Object>> dataList) {
|
||||||
|
//自定义别名 别名的key和实体类中的名称要对应上!
|
||||||
|
writer.setHeaderAlias(map);
|
||||||
|
//水平居中对齐,垂直中间对齐
|
||||||
|
writer.getStyleSet().setAlign(HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||||
|
//所有单元格宽25个字符
|
||||||
|
writer.setColumnWidth(-1, 25);
|
||||||
|
// 一次性写出内容,使用默认样式,强制输出标题
|
||||||
|
writer.write(dataList, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 趋势分析-遍历数据,填充Excel和图表数据集
|
||||||
|
* @param mapsList 测点历史数据
|
||||||
|
* @param dataList Excel数据集
|
||||||
|
*/
|
||||||
|
private void setTrendAnalyseExcelValue(List<Map<String, Map<String, Map<String, Object>>>> mapsList,
|
||||||
|
List<Map<String, Object>> dataList) {
|
||||||
|
for (int i = 0; i < mapsList.size(); i++) {
|
||||||
|
List<String> timesListstr = new ArrayList<>();
|
||||||
|
List<Double> valuesList = new ArrayList<>();
|
||||||
|
int num = i + 1;
|
||||||
|
String pointName = null;
|
||||||
|
Map<String, Map<String, Map<String, Object>>> stringMapMap = mapsList.get(i);
|
||||||
|
for (Map.Entry<String, Map<String, Map<String, Object>>> stringMapEntry : stringMapMap.entrySet()) {
|
||||||
|
for (Map.Entry<String, Map<String, Object>> mapEntry : stringMapEntry.getValue().entrySet()) {
|
||||||
|
pointName = mapEntry.getKey();
|
||||||
|
for (Map.Entry<String, Object> stringObjectEntry : mapEntry.getValue().entrySet()) {
|
||||||
|
String key1 = stringObjectEntry.getKey();
|
||||||
|
if (key1.equals("times")) {
|
||||||
|
List<Long> times = (List<Long>) stringObjectEntry.getValue();
|
||||||
|
List<String> liststr = times.stream()
|
||||||
|
.map(timestamp -> new Date(timestamp))
|
||||||
|
.map(date -> sdf.format(date))
|
||||||
|
.toList();
|
||||||
|
timesListstr.addAll(liststr);
|
||||||
|
}
|
||||||
|
if (key1.equals("values")) {
|
||||||
|
List<Double> values = (List<Double>) stringObjectEntry.getValue();
|
||||||
|
valuesList.addAll(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String pointNameKey = pointName + num;
|
||||||
|
String timeKey = "time" + num;
|
||||||
|
if (i == 0) {
|
||||||
|
for (int j = 0; j < timesListstr.size(); j++) {
|
||||||
|
Map<String, Object> dataMap = new HashMap<>();
|
||||||
|
dataMap.put(timeKey, timesListstr.get(j));
|
||||||
|
dataMap.put(pointNameKey, valuesList.get(j));
|
||||||
|
dataList.add(dataMap);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dataList.size()< timesListstr.size()){
|
||||||
|
for (int j = dataList.size(); j < timesListstr.size(); j++) {
|
||||||
|
Map<String, Object> dataMap = new HashMap<>();
|
||||||
|
dataMap.put(timeKey, timesListstr.get(j));
|
||||||
|
dataMap.put(pointNameKey, valuesList.get(j));
|
||||||
|
dataList.add(dataMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j = 0; j < timesListstr.size(); j++) {
|
||||||
|
Map<String, Object> stringObjectMap = dataList.get(j);
|
||||||
|
stringObjectMap.put(timeKey, timesListstr.get(j));
|
||||||
|
stringObjectMap.put(pointNameKey, valuesList.get(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 趋势对比填充Excel数据集
|
||||||
|
*
|
||||||
|
* @param dataList Excel数据集
|
||||||
|
* @param maps 测点数据
|
||||||
|
*/
|
||||||
|
private void setTrendContrastExcelValue(Map<String, Map<String, Map<String, Object>>> maps,
|
||||||
|
List<Map<String, Object>> dataList) {
|
||||||
|
Map<String,Integer> mapKey = new HashMap<>();
|
||||||
|
int num =1;
|
||||||
|
int flagNum = 0;
|
||||||
|
for (Map.Entry<String, Map<String, Map<String, Object>>> stringMapEntry : maps.entrySet()) {
|
||||||
|
for (Map.Entry<String, Map<String, Object>> mapEntry : stringMapEntry.getValue().entrySet()) {
|
||||||
|
List<String> timesListstr = new ArrayList<>();
|
||||||
|
List<Double> valuesList = new ArrayList<>();
|
||||||
|
String key = mapEntry.getKey();
|
||||||
|
if (mapKey.containsKey(key)){
|
||||||
|
num++;
|
||||||
|
String str = key + num;
|
||||||
|
mapKey.put(str, num );
|
||||||
|
key=str;
|
||||||
|
}else {
|
||||||
|
mapKey.put(key, num);
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, Object> stringObjectEntry : mapEntry.getValue().entrySet()) {
|
||||||
|
String key1 = stringObjectEntry.getKey();
|
||||||
|
if (key1.equals("times")) {
|
||||||
|
List<Long> times = (List<Long>) stringObjectEntry.getValue();
|
||||||
|
List<String> liststr = times.stream()
|
||||||
|
.map(timestamp -> new Date(timestamp))
|
||||||
|
.map(date -> sdf.format(date))
|
||||||
|
.toList();
|
||||||
|
timesListstr.addAll(liststr);
|
||||||
|
}
|
||||||
|
if (key1.equals("values")) {
|
||||||
|
List<Double> values = (List<Double>) stringObjectEntry.getValue();
|
||||||
|
valuesList.addAll(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flagNum == 0) {
|
||||||
|
for (int j = 0; j < timesListstr.size(); j++) {
|
||||||
|
Map<String, Object> dataMap = new HashMap<>();
|
||||||
|
dataMap.put("time", timesListstr.get(j));
|
||||||
|
dataMap.put(key, valuesList.get(j));
|
||||||
|
dataList.add(dataMap);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int j = 0; j < timesListstr.size(); j++) {
|
||||||
|
Map<String, Object> stringObjectMap = dataList.get(j);
|
||||||
|
stringObjectMap.put(key, valuesList.get(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flagNum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 趋势-获取表格的列
|
||||||
|
* @param param 查询条件
|
||||||
|
* @return 表格的列
|
||||||
|
*/
|
||||||
|
private LinkedHashMap<String, String> getTrendColumnName(List<TrendAnalyseDto> param) {
|
||||||
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
|
for (int i = 0; i < param.size(); i++) {
|
||||||
|
TrendAnalyseDto trendAnalyseDto = param.get(i);
|
||||||
|
String timeName = trendAnalyseDto.getTimeName();
|
||||||
|
int num = i + 1;
|
||||||
|
map.put("time" + num, "时间" + num);
|
||||||
|
for (SnapshotValueQueryParam device : trendAnalyseDto.getDevices()) {
|
||||||
|
//获取属性名称
|
||||||
|
for (String attribute : device.getAttributes()) {
|
||||||
|
map.put(attribute + num, timeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 趋势对比-获取表格的列
|
||||||
|
*
|
||||||
|
* @param param 查询条件
|
||||||
|
* @return 表格的列
|
||||||
|
*/
|
||||||
|
private LinkedHashMap<String, String> gettrendContrastColumnName(TrendContrastDto param) {
|
||||||
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
|
map.put("time", "时间");
|
||||||
|
List<String> strList = new ArrayList<>();
|
||||||
|
for (SnapshotValueQueryParam device : param.getDevices()) {
|
||||||
|
strList.addAll(device.getAttributes());
|
||||||
|
}
|
||||||
|
int num =1;
|
||||||
|
for (String code : strList) {
|
||||||
|
QueryWrapper<SysIotModelField> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("attribute_code", code);
|
||||||
|
List<SysIotModelField> sysIotModelFields = sysIotModelFieldMapper.selectVoList(queryWrapper);
|
||||||
|
for (SysIotModelField sysIotModelField : sysIotModelFields) {
|
||||||
|
if (map.containsKey(sysIotModelField.getAttributeCode())){
|
||||||
|
num++;
|
||||||
|
map.put(sysIotModelField.getAttributeCode()+num, sysIotModelField.getAttributeName()+num );
|
||||||
|
}else {
|
||||||
|
map.put(sysIotModelField.getAttributeCode(), sysIotModelField.getAttributeName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取功率曲线的列
|
||||||
|
* @return Excel的列
|
||||||
|
*/
|
||||||
|
private LinkedHashMap<String, String> getPowerCurveColumnName(TrendAnalyseDto param) {
|
||||||
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
|
map.put("time", "时间");
|
||||||
|
if (param.getWindSource().equals("原始风速")){
|
||||||
|
map.put("AvgWindSpeed_10min", "原始风速");
|
||||||
|
}else {
|
||||||
|
map.put("AvgWindSpeedCal_10min", "处理后风速");
|
||||||
|
}
|
||||||
|
map.put("AvgActivePower_10min", "功率");
|
||||||
|
map.put("theoryIWindSpeed", "理论风速");
|
||||||
|
map.put("theoryIGenPower", "理论功率");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功率曲线-遍历数据,填充Excel数据集
|
||||||
|
*
|
||||||
|
* @param maps 测点历史数据
|
||||||
|
* @param dataList Excel数据集
|
||||||
|
* @param curveItemEntitieList 理论数据
|
||||||
|
*/
|
||||||
|
private void setPowerCurveExcelValue(Map<String, Map<String, Map<String, Object>>> maps,
|
||||||
|
List<Map<String, Object>> dataList, List<CurveItemEntity> curveItemEntitieList) {
|
||||||
|
for (Map.Entry<String, Map<String, Map<String, Object>>> stringMapEntry : maps.entrySet()) {
|
||||||
|
int flagNum = 0;
|
||||||
|
for (Map.Entry<String, Map<String, Object>> mapEntry : stringMapEntry.getValue().entrySet()) {
|
||||||
|
List<String> timesListstr = new ArrayList<>();
|
||||||
|
List<Double> valuesList = new ArrayList<>();
|
||||||
|
String key = mapEntry.getKey();
|
||||||
|
for (Map.Entry<String, Object> stringObjectEntry : mapEntry.getValue().entrySet()) {
|
||||||
|
String key1 = stringObjectEntry.getKey();
|
||||||
|
if (key1.equals("times")) {
|
||||||
|
List<Long> times = (List<Long>) stringObjectEntry.getValue();
|
||||||
|
List<String> liststr = times.stream()
|
||||||
|
.map(timestamp -> new Date(timestamp))
|
||||||
|
.map(date -> sdf.format(date))
|
||||||
|
.toList();
|
||||||
|
timesListstr.addAll(liststr);
|
||||||
|
}
|
||||||
|
if (key1.equals("values")) {
|
||||||
|
List<Double> values = (List<Double>) stringObjectEntry.getValue();
|
||||||
|
valuesList.addAll(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flagNum == 0) {
|
||||||
|
for (int j = 0; j < timesListstr.size(); j++) {
|
||||||
|
Map<String, Object> dataMap = new HashMap<>();
|
||||||
|
dataMap.put("time", timesListstr.get(j));
|
||||||
|
dataMap.put(key, valuesList.get(j));
|
||||||
|
dataList.add(dataMap);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int j = 0; j < timesListstr.size(); j++) {
|
||||||
|
Map<String, Object> stringObjectMap = dataList.get(j);
|
||||||
|
stringObjectMap.put(key, valuesList.get(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flagNum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//转换为map
|
||||||
|
List<Map<String, Object>> listMap = curveItemEntitieList.stream()
|
||||||
|
.map(entity -> {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put("theoryIWindSpeed", entity.getPower());
|
||||||
|
map.put("theoryIGenPower", entity.getSpeed());
|
||||||
|
return map;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (listMap.size() > dataList.size()) {
|
||||||
|
for (int i = 0; i < listMap.size(); i++) {
|
||||||
|
Map<String, Object> stringObjectMap1 = listMap.get(i);
|
||||||
|
if (dataList.size() > i) {
|
||||||
|
Map<String, Object> stringObjectMap = dataList.get(i);
|
||||||
|
stringObjectMap.put("theoryIWindSpeed", stringObjectMap1.get("theoryIWindSpeed"));
|
||||||
|
stringObjectMap.put("theoryIGenPower", stringObjectMap1.get("theoryIGenPower"));
|
||||||
|
}else {
|
||||||
|
HashMap<String, Object> theoryMaps = new HashMap<>();
|
||||||
|
theoryMaps.put("theoryIWindSpeed", stringObjectMap1.get("theoryIWindSpeed"));
|
||||||
|
theoryMaps.put("theoryIGenPower", stringObjectMap1.get("theoryIGenPower"));
|
||||||
|
dataList.add(theoryMaps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < dataList.size(); i++) {
|
||||||
|
Map<String, Object> dataMap = dataList.get(i);
|
||||||
|
if (listMap.size() > i) {
|
||||||
|
Map<String, Object> stringObjectMap1 = listMap.get(i);
|
||||||
|
dataMap.put("theoryIWindSpeed", stringObjectMap1.get("theoryIWindSpeed"));
|
||||||
|
dataMap.put("theoryIGenPower", stringObjectMap1.get("theoryIGenPower"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载Excel
|
||||||
|
*
|
||||||
|
* @param response 响应对象
|
||||||
|
* @param writer Excel对象
|
||||||
|
* @param title 标题
|
||||||
|
*/
|
||||||
|
private void downloadExcel(HttpServletResponse response, ExcelWriter writer,String title) {
|
||||||
|
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||||
|
response.setContentType("application/vnd.ms-excel");
|
||||||
|
// 清除缓存
|
||||||
|
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||||
|
response.setHeader("Pragma", "no-cache");
|
||||||
|
response.setDateHeader("Expires", 0);
|
||||||
|
try {
|
||||||
|
// 设置请求头属性
|
||||||
|
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(title+"-"+System.currentTimeMillis()+".xls", StandardCharsets.UTF_8));
|
||||||
|
ServletOutputStream out = response.getOutputStream();
|
||||||
|
// 写出到文件
|
||||||
|
writer.flush(out, true);
|
||||||
|
// 关闭writer,释放内存
|
||||||
|
writer.close();
|
||||||
|
// 此处记得关闭输出Servlet流
|
||||||
|
IoUtil.close(out);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ServiceException("文件下载失败==" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取图表类别集
|
||||||
|
* @param map Excel的列
|
||||||
|
* @return 图表类别集
|
||||||
|
*/
|
||||||
|
private List<String> getCharKey(LinkedHashMap<String, String> map) {
|
||||||
|
//获取图表类别集
|
||||||
|
List<String> chartKey = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, String> stringStringEntry : map.entrySet()) {
|
||||||
|
String value = stringStringEntry.getValue();
|
||||||
|
if (!value.contains("时间")){
|
||||||
|
chartKey.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chartKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成折线图,并插入到Excel中
|
||||||
|
* @param writer Sheet对象
|
||||||
|
* @param data 测点数据集合
|
||||||
|
* @param titleText 标题
|
||||||
|
* @param chartKey 类别数据集
|
||||||
|
*/
|
||||||
|
private static void addChartToExcel(ExcelWriter writer, List<Map<String, Object>> data,
|
||||||
|
String titleText,List<String> chartKey) {
|
||||||
|
try {
|
||||||
|
if (CollectionUtils.isEmpty(data)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 获取Sheet对象
|
||||||
|
XSSFSheet sheet = (XSSFSheet) writer.getSheet();
|
||||||
|
// 创建绘图区域
|
||||||
|
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||||
|
int columnCount = sheet.getRow(0).getPhysicalNumberOfCells() + 1;
|
||||||
|
//图表位置,插入到最后一列+1
|
||||||
|
ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, columnCount, 0, 15, 15);
|
||||||
|
// 创建图表
|
||||||
|
XSSFChart xssfChart = drawing.createChart(anchor);
|
||||||
|
// 设置图表标题
|
||||||
|
xssfChart.setTitleText(titleText);
|
||||||
|
// 创建数据系列
|
||||||
|
XDDFChartLegend legend = xssfChart.getOrAddLegend();
|
||||||
|
legend.setPosition(LegendPosition.TOP_RIGHT);
|
||||||
|
XDDFCategoryAxis bottomAxis = xssfChart.createCategoryAxis(AxisPosition.BOTTOM);
|
||||||
|
XDDFValueAxis leftAxis = xssfChart.createValueAxis(AxisPosition.LEFT);
|
||||||
|
leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
|
||||||
|
XDDFLineChartData chartData = (XDDFLineChartData) xssfChart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
|
||||||
|
// 遍历每个系列并添加数据
|
||||||
|
setChartData(data, titleText, chartKey, chartData, sheet);
|
||||||
|
xssfChart.plot(chartData);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成散点图,并插入到 Excel 中
|
||||||
|
* @param writer Sheet 对象
|
||||||
|
* @param data 测点数据集合
|
||||||
|
* @param titleText 标题
|
||||||
|
* @param chartKey 类别数据集
|
||||||
|
*/
|
||||||
|
private static void addScattersChartToExcel(ExcelWriter writer, List<Map<String, Object>> data,
|
||||||
|
String titleText, List<String> chartKey) {
|
||||||
|
try {
|
||||||
|
if (CollectionUtils.isEmpty(data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 获取 Sheet 对象
|
||||||
|
XSSFSheet sheet = (XSSFSheet) writer.getSheet();
|
||||||
|
// 创建绘图区域
|
||||||
|
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||||
|
int columnCount = sheet.getRow(0).getPhysicalNumberOfCells() + 1;
|
||||||
|
// 图表位置,插入到最后一列+1
|
||||||
|
ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, columnCount, 0, 15, 15);
|
||||||
|
// 创建图表
|
||||||
|
XSSFChart xssfChart = drawing.createChart(anchor);
|
||||||
|
// 设置图表标题
|
||||||
|
xssfChart.setTitleText(titleText);
|
||||||
|
// 创建数据系列
|
||||||
|
XDDFChartLegend legend = xssfChart.getOrAddLegend();
|
||||||
|
legend.setPosition(LegendPosition.TOP_RIGHT);
|
||||||
|
XDDFValueAxis bottomAxis = xssfChart.createValueAxis(AxisPosition.BOTTOM);
|
||||||
|
XDDFValueAxis leftAxis = xssfChart.createValueAxis(AxisPosition.LEFT);
|
||||||
|
leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
|
||||||
|
// 创建散点图数据
|
||||||
|
XDDFScatterChartData chartData = (XDDFScatterChartData) xssfChart.createData(ChartTypes.SCATTER, bottomAxis, leftAxis);
|
||||||
|
// 遍历每个系列并添加数据
|
||||||
|
setChartDataForScatter(data, titleText, chartKey, chartData, sheet);
|
||||||
|
// 确保散点图数据点之间不连线
|
||||||
|
for (XDDFChartData.Series series : chartData.getSeries()) {
|
||||||
|
if (series instanceof XDDFScatterChartData.Series) {
|
||||||
|
XDDFScatterChartData.Series scatterSeries = (XDDFScatterChartData.Series) series;
|
||||||
|
scatterSeries.setSmooth(false);
|
||||||
|
scatterSeries.setMarkerStyle(MarkerStyle.CIRCLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xssfChart.plot(chartData);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为散点图设置数据系列
|
||||||
|
* @param data 测点数据集合
|
||||||
|
* @param titleText 标题
|
||||||
|
* @param chartKey 类别数据集
|
||||||
|
* @param chartData 散点图数据对象
|
||||||
|
* @param sheet Excel Sheet 对象
|
||||||
|
*/
|
||||||
|
private static void setChartDataForScatter(List<Map<String, Object>> data, String titleText, List<String> chartKey,
|
||||||
|
XDDFScatterChartData chartData, XSSFSheet sheet) {
|
||||||
|
for (String key : chartKey) {
|
||||||
|
XDDFDataSource<Double> xAxisData = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
|
||||||
|
new CellRangeAddress(1, data.size(), 0, 0));
|
||||||
|
XDDFNumericalDataSource<Double> yAxisData = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
|
||||||
|
new CellRangeAddress(1, data.size(), chartKey.indexOf(key) + 1, chartKey.indexOf(key) + 1));
|
||||||
|
XDDFScatterChartData.Series series = (XDDFScatterChartData.Series) chartData.addSeries(xAxisData, yAxisData);
|
||||||
|
series.setTitle(key, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 给每个类别,添加数据
|
||||||
|
* @param data 测点数据
|
||||||
|
* @param titleText 标题
|
||||||
|
* @param chartKey 类别key
|
||||||
|
* @param chartData 图表数据
|
||||||
|
* @param sheet sheet对象
|
||||||
|
*/
|
||||||
|
private static void setChartData(List<Map<String, Object>> data, String titleText, List<String> chartKey, XDDFLineChartData chartData, XSSFSheet sheet) {
|
||||||
|
if (titleText.equals(StatisticalAnalysisConstant.TREND_ANALYSE)) {
|
||||||
|
int strStartRow = 0;
|
||||||
|
int strEndCol = 0;
|
||||||
|
int numStartRow = 1;
|
||||||
|
int numEndCol = 1;
|
||||||
|
for (int i = 0; i < chartKey.size(); i++) {
|
||||||
|
XDDFLineChartData.Series series = (XDDFLineChartData.Series) chartData.addSeries(
|
||||||
|
createStringDataReference(sheet, 1, data.size(), strStartRow, strEndCol), // 类别(X轴)
|
||||||
|
createNumericDataReference(sheet, 1, data.size(), numStartRow, numEndCol) // 值(Y轴)
|
||||||
|
);
|
||||||
|
series.setTitle(chartKey.get(i), null);
|
||||||
|
strStartRow += 2;
|
||||||
|
strEndCol += 2;
|
||||||
|
numStartRow += 2;
|
||||||
|
numEndCol += 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < chartKey.size(); i++) {
|
||||||
|
XDDFLineChartData.Series series = (XDDFLineChartData.Series) chartData.addSeries(
|
||||||
|
createStringDataReference(sheet, 1, data.size(), 0, 0), // 类别(X轴)
|
||||||
|
createNumericDataReference(sheet, 1, data.size(), i + 1, i + 1) // 值(Y轴)
|
||||||
|
);
|
||||||
|
series.setTitle(chartKey.get(i), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建字符串数据引用
|
||||||
|
* @return XDDFDataSource<String>
|
||||||
|
*/
|
||||||
|
private static XDDFDataSource<String> createStringDataReference(XSSFSheet sheet, int startRow, int endRow, int startCol, int endCol) {
|
||||||
|
CellRangeAddress ref = new CellRangeAddress(startRow, endRow, startCol, endCol);
|
||||||
|
return XDDFDataSourcesFactory.fromStringCellRange(sheet, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建值数据引用
|
||||||
|
* @return XDDFNumericalDataSource<Double>
|
||||||
|
*/
|
||||||
|
private static XDDFNumericalDataSource<Double> createNumericDataReference(XSSFSheet sheet, int startRow, int endRow, int startCol, int endCol) {
|
||||||
|
CellRangeAddress ref = new CellRangeAddress(startRow, endRow, startCol, endCol);
|
||||||
|
return XDDFDataSourcesFactory.fromNumericCellRange(sheet, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算平均功率
|
||||||
|
*/
|
||||||
|
public static List<Map<String,List<Double>>> calculateAverages(List<Double> windSpeeds, List<Double> powers) {
|
||||||
|
// 找出最大的风速
|
||||||
|
double maxWindSpeed = Double.MIN_VALUE;
|
||||||
|
for (double windSpeed : windSpeeds) {
|
||||||
|
if (windSpeed > maxWindSpeed) {
|
||||||
|
maxWindSpeed = windSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double interval = 0.5;
|
||||||
|
List<Map<String,List<Double>>> result = new ArrayList<>();
|
||||||
|
Map<String,List<Double>> dataMap = new HashMap<>();
|
||||||
|
List<Double> windSpeedList = new ArrayList<>();
|
||||||
|
List<Double> powerList = new ArrayList<>();
|
||||||
|
// 从 0 开始,以 interval 为步长遍历风速
|
||||||
|
for (double windSpeed = 0; windSpeed <= maxWindSpeed; windSpeed += interval) {
|
||||||
|
double sumPower = 0;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
// 遍历输入列表,计算满足风速范围的功率总和和计数
|
||||||
|
for (int i = 0; i < windSpeeds.size(); i++) {
|
||||||
|
double currentWindSpeed = windSpeeds.get(i);
|
||||||
|
double currentPower = powers.get(i);
|
||||||
|
|
||||||
|
if (currentWindSpeed >= windSpeed && currentWindSpeed < windSpeed + interval) {
|
||||||
|
sumPower += currentPower;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果计数大于 0,计算平均值并添加到结果列表
|
||||||
|
if (count > 0) {
|
||||||
|
double averagePower = sumPower / count;
|
||||||
|
windSpeedList.add(windSpeed + interval);
|
||||||
|
powerList.add(averagePower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataMap.put("windSpeed", windSpeedList);
|
||||||
|
dataMap.put("power", powerList);
|
||||||
|
result.add(dataMap);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据size删除List<String> value1的值
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private static List<String> delTimes(Map.Entry<String, Object> stringObjectEntry, List<Map<String, List<Double>>> maps) {
|
||||||
|
int powerSize = maps.get(0).get("power").size();
|
||||||
|
List<String> value1 = (List<String>) stringObjectEntry.getValue();
|
||||||
|
List<String> collect = IntStream.range(0, value1.size())
|
||||||
|
.filter(i -> i < powerSize)
|
||||||
|
.mapToObj(value1::get)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return collect;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void getPowerCurveValueList(Map<String, Map<String, Map<String, Object>>> resultMap,
|
||||||
|
List<Double> powerList, List<Double> windSpeedList) {
|
||||||
|
for (Map.Entry<String, Map<String, Map<String, Object>>> stringMapEntry : resultMap.entrySet()) {
|
||||||
|
for (Map.Entry<String, Map<String, Object>> mapEntry : stringMapEntry.getValue().entrySet()) {
|
||||||
|
String key = mapEntry.getKey();
|
||||||
|
Map<String, Object> value = mapEntry.getValue();
|
||||||
|
//功率
|
||||||
|
if (key.equals("AvgActivePower_10min")) {
|
||||||
|
for (Map.Entry<String, Object> stringObjectEntry : value.entrySet()) {
|
||||||
|
if (stringObjectEntry.getKey().equals("values")) {
|
||||||
|
List<Float> values = (List<Float>) stringObjectEntry.getValue();
|
||||||
|
List<Double> doubleList = values.stream()
|
||||||
|
.map(Float::doubleValue)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
powerList.addAll(doubleList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key.equals("AvgWindSpeed_10min") || key.equals("AvgWindSpeedCal_10min")){
|
||||||
|
for (Map.Entry<String, Object> stringObjectEntry : value.entrySet()) {
|
||||||
|
if (stringObjectEntry.getKey().equals("values")){
|
||||||
|
List<Float> values = (List<Float>) stringObjectEntry.getValue();
|
||||||
|
List<Double> doubleList = values.stream()
|
||||||
|
.map(Float::doubleValue)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
windSpeedList.addAll(doubleList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setPowerCurveValueList(Map<String, Map<String, Map<String, Object>>> resultMap,
|
||||||
|
List<Map<String, List<Double>>> maps) {
|
||||||
|
if (CollectionUtils.isEmpty(maps)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, Map<String, Map<String, Object>>> stringMapEntry : resultMap.entrySet()) {
|
||||||
|
for (Map.Entry<String, Map<String, Object>> mapEntry : stringMapEntry.getValue().entrySet()) {
|
||||||
|
String key = mapEntry.getKey();
|
||||||
|
Map<String, Object> value = mapEntry.getValue();
|
||||||
|
//功率
|
||||||
|
if (key.equals("AvgActivePower_10min")) {
|
||||||
|
for (Map.Entry<String, Object> stringObjectEntry : value.entrySet()) {
|
||||||
|
if (stringObjectEntry.getKey().equals("values")) {
|
||||||
|
stringObjectEntry.setValue(maps.get(0).get("power"));
|
||||||
|
}
|
||||||
|
if (stringObjectEntry.getKey().equals("times")){
|
||||||
|
List<String> collect = delTimes(stringObjectEntry, maps);
|
||||||
|
stringObjectEntry.setValue(collect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key.equals("AvgWindSpeed_10min") || key.equals("AvgWindSpeedCal_10min")){
|
||||||
|
for (Map.Entry<String, Object> stringObjectEntry : value.entrySet()) {
|
||||||
|
if (stringObjectEntry.getKey().equals("values")){
|
||||||
|
stringObjectEntry.setValue(maps.get(0).get("windSpeed"));
|
||||||
|
}
|
||||||
|
if (stringObjectEntry.getKey().equals("times")){
|
||||||
|
List<String> collect = delTimes(stringObjectEntry, maps);
|
||||||
|
stringObjectEntry.setValue(collect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -105,7 +105,7 @@
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="getBindDeviceByLink" resultMap="EquipmentMap">
|
<select id="getBindDeviceByLink" resultMap="EquipmentMap">
|
||||||
select se.id ,se."name",se.iot_model_id,se.iot_addr,min(imp.porder) as porder from sys_imptabmapping imp
|
select se.id ,se."name",se.iot_model_id,se.iot_addr,min( imp.porder) as porder from sys_imptabmapping imp
|
||||||
left join sys_equipment se on imp.equipment_id = se.id
|
left join sys_equipment se on imp.equipment_id = se.id
|
||||||
where link_id = #{linkId}
|
where link_id = #{linkId}
|
||||||
group by se.id ,se."name",se.iot_model_id,se.iot_addr order by porder
|
group by se.id ,se."name",se.iot_model_id,se.iot_addr order by porder
|
||||||
|
Binary file not shown.
@ -8,7 +8,6 @@ VITE_BASE_PATH = './'
|
|||||||
# 本地
|
# 本地
|
||||||
# VITE_APP_PROXY=[["/api","http://192.168.130.22:8080/api"]]
|
# VITE_APP_PROXY=[["/api","http://192.168.130.22:8080/api"]]
|
||||||
# 线上
|
# 线上
|
||||||
# VITE_APP_PROXY=[["/api","https://192.168.151.18:6379/api"]]
|
|
||||||
VITE_APP_PROXY=[["/api","https://test.jsspisoft.com/api"]]
|
VITE_APP_PROXY=[["/api","https://test.jsspisoft.com/api"]]
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,8 +24,6 @@ export const getModelListReq = (data: GetModelType) => {
|
|||||||
url: '/api/equipment/model/list',
|
url: '/api/equipment/model/list',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
}, {
|
|
||||||
showErrorMessage: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,8 +32,6 @@ export const addModelReq = (data: AddModelType) => {
|
|||||||
url: '/api/equipment/model/add',
|
url: '/api/equipment/model/add',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
}, {
|
|
||||||
showErrorMessage: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,8 +40,6 @@ export const updateModelReq = (data: UpdateModelType) => {
|
|||||||
url: '/api/equipment/model/update',
|
url: '/api/equipment/model/update',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
}, {
|
|
||||||
showErrorMessage: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,8 +59,6 @@ export const getModelAttributeListReq = (data: GetModelAttributeType) => {
|
|||||||
url: '/api/equipment/model/attribute/list',
|
url: '/api/equipment/model/attribute/list',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
}, {
|
|
||||||
showErrorMessage: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,8 +67,6 @@ export const addModelAttributeReq = (data: AddModelAttributeType) => {
|
|||||||
url: '/api/equipment/model/attribute/add',
|
url: '/api/equipment/model/attribute/add',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
}, {
|
|
||||||
showErrorMessage: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,8 +75,6 @@ export const updateModelAttributeReq = (data: UpdateModelAttributeType) => {
|
|||||||
url: '/api/equipment/model/attribute/update',
|
url: '/api/equipment/model/attribute/update',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
}, {
|
|
||||||
showErrorMessage: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,8 +83,6 @@ export const delModelAttributeReq = (data: DelModelAttributeType) => {
|
|||||||
url: '/api/equipment/model/attribute/delete',
|
url: '/api/equipment/model/attribute/delete',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
}, {
|
|
||||||
showErrorMessage: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,8 +91,6 @@ export const getModelServiceListReq = (data: GetModelServiceType) => {
|
|||||||
url: '/api/equipment/model/service/list',
|
url: '/api/equipment/model/service/list',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
}, {
|
|
||||||
showErrorMessage: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,8 +99,6 @@ export const addModelServiceReq = (data: AddModelServiceType) => {
|
|||||||
url: '/api/equipment/model/service/add',
|
url: '/api/equipment/model/service/add',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
}, {
|
|
||||||
showErrorMessage: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,8 +107,6 @@ export const updateModelServiceReq = (data: UpdateModelServiceType) => {
|
|||||||
url: '/api/equipment/model/service/update',
|
url: '/api/equipment/model/service/update',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
}, {
|
|
||||||
showErrorMessage: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,8 +115,6 @@ export const delModelServiceReq = (data: DelModelAttributeType) => {
|
|||||||
url: '/api/equipment/model/service/delete',
|
url: '/api/equipment/model/service/delete',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
}, {
|
|
||||||
showErrorMessage: false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,10 +131,7 @@ export const uploadModelReq = (data: FormData, v: string) => {
|
|||||||
token,
|
token,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ customEncrypt: true }
|
||||||
customEncrypt: true,
|
|
||||||
showErrorMessage: false
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +157,7 @@ export const getRealValueListReq = (data: { deviceId: string, attributes?: (stri
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
timeout: 60 * 1000
|
timeout: 60 * 1000
|
||||||
}, {
|
},{
|
||||||
showErrorMessage: false
|
showErrorMessage: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -193,7 +168,7 @@ export const getRealValueRangeReq = (data: { startTime: number, endTime: number,
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
timeout: 60 * 1000
|
timeout: 60 * 1000
|
||||||
}, {
|
},{
|
||||||
showErrorMessage: false
|
showErrorMessage: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -253,6 +253,8 @@
|
|||||||
class="tablePart"
|
class="tablePart"
|
||||||
height="calc(100% - 18px)"
|
height="calc(100% - 18px)"
|
||||||
ref="myTable"
|
ref="myTable"
|
||||||
|
@mouseover.native="clearScroll"
|
||||||
|
@mouseleave.native="createScroll"
|
||||||
>
|
>
|
||||||
<el-table-column fixed prop="time" label="时间" />
|
<el-table-column fixed prop="time" label="时间" />
|
||||||
<el-table-column prop="alertcontent" label="告警信息" />
|
<el-table-column prop="alertcontent" label="告警信息" />
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="DeviceModel">
|
<div class="DeviceModel">
|
||||||
<el-dialog v-model="modelDialogVisible" :title="modelDialogTitle" :width="400" @close="cancelModelForm" :close-on-click-modal="false" draggable>
|
<el-dialog v-model="modelDialogVisible" :title="modelDialogTitle" :width="400" @close="cancelModelForm">
|
||||||
<el-form ref="modelFormRef" :model="modelForm" :rules="modelFormRules" label-width="110">
|
<el-form ref="modelFormRef" :model="modelForm" :rules="modelFormRules" label-width="110">
|
||||||
<el-form-item prop="iotModelName" :label="ModelFieldsEnums['iotModelName']">
|
<el-form-item prop="iotModelName" :label="ModelFieldsEnums['iotModelName']">
|
||||||
<el-input
|
<el-input
|
||||||
@ -32,7 +32,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer v-if="modelDialogState !== ModelDialogTitleStateType['detail']">
|
<template #footer v-if="modelDialogState !== ModelDialogTitleStateType['detail']">
|
||||||
<el-button type="primary" @click="submitModelForm" :loading="submitModelLoading">保存</el-button>
|
<el-button type="primary" @click="submitModelForm">保存</el-button>
|
||||||
<el-button @click="cancelModelForm">取消</el-button>
|
<el-button @click="cancelModelForm">取消</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@ -212,7 +212,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
<el-dialog v-model="attributeVisible" :title="attributeFormTitle" @close="closeAttributeForm" :width="600" draggable :close-on-click-modal="false">
|
<el-dialog v-model="attributeVisible" :title="attributeFormTitle" @close="closeAttributeForm" :width="600">
|
||||||
<el-form ref="attributeFormRef" :model="attributeForm" label-width="100" :rules="attributeAndServiceRules">
|
<el-form ref="attributeFormRef" :model="attributeForm" label-width="100" :rules="attributeAndServiceRules">
|
||||||
<el-form-item :label="ModelAttributeFieldsEnums['attributeName']" prop="attributeName">
|
<el-form-item :label="ModelAttributeFieldsEnums['attributeName']" prop="attributeName">
|
||||||
<el-input v-model="attributeForm.attributeName" :placeholder="'请输入' + ModelAttributeFieldsEnums['attributeName']"></el-input>
|
<el-input v-model="attributeForm.attributeName" :placeholder="'请输入' + ModelAttributeFieldsEnums['attributeName']"></el-input>
|
||||||
@ -285,11 +285,11 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button type="primary" @click="submitAttributeForm" :loading="submitAttributeLoading">保存</el-button>
|
<el-button type="primary" @click="submitAttributeForm">保存</el-button>
|
||||||
<el-button @click="closeAttributeForm">取消</el-button>
|
<el-button @click="closeAttributeForm">取消</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog v-model="serviceVisible" :title="serviceFormTitle" @close="closeServiceForm" :width="600" draggable :close-on-click-modal="false">
|
<el-dialog v-model="serviceVisible" :title="serviceFormTitle" @close="closeServiceForm" :width="600">
|
||||||
<el-form ref="serviceFormRef" :model="serviceForm" label-width="100" :rules="attributeAndServiceRules">
|
<el-form ref="serviceFormRef" :model="serviceForm" label-width="100" :rules="attributeAndServiceRules">
|
||||||
<el-form-item :label="ModelServiceFieldsEnums['serviceName']" prop="serviceName">
|
<el-form-item :label="ModelServiceFieldsEnums['serviceName']" prop="serviceName">
|
||||||
<el-input v-model="serviceForm.serviceName" :placeholder="'请输入' + ModelServiceFieldsEnums['serviceName']"></el-input>
|
<el-input v-model="serviceForm.serviceName" :placeholder="'请输入' + ModelServiceFieldsEnums['serviceName']"></el-input>
|
||||||
@ -308,7 +308,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button type="primary" @click="submitServiceForm" :loading="submitServiceLoading">保存</el-button>
|
<el-button type="primary" @click="submitServiceForm">保存</el-button>
|
||||||
<el-button @click="closeServiceForm">取消</el-button>
|
<el-button @click="closeServiceForm">取消</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@ -441,11 +441,7 @@ const modelFormRules = {
|
|||||||
iotModelCode: [{ required: true, message: '请输入物模型编码', trigger: 'blur' }],
|
iotModelCode: [{ required: true, message: '请输入物模型编码', trigger: 'blur' }],
|
||||||
objectType: [{ required: true, message: '请选择物模型类型', trigger: 'blur' }],
|
objectType: [{ required: true, message: '请选择物模型类型', trigger: 'blur' }],
|
||||||
}
|
}
|
||||||
const submitModelLoading = ref(false)
|
|
||||||
const submitModelForm = () => {
|
const submitModelForm = () => {
|
||||||
modelFormRef.value?.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
submitModelLoading.value = true
|
|
||||||
if (modelDialogState.value === ModelDialogTitleStateType['add']) {
|
if (modelDialogState.value === ModelDialogTitleStateType['add']) {
|
||||||
addModelReq(modelForm.value)
|
addModelReq(modelForm.value)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@ -460,9 +456,6 @@ const submitModelForm = () => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
ElMessage.error(err?.response?.data?.msg ?? '新增失败')
|
ElMessage.error(err?.response?.data?.msg ?? '新增失败')
|
||||||
})
|
})
|
||||||
.finally(() => {
|
|
||||||
submitModelLoading.value = false
|
|
||||||
})
|
|
||||||
} else if (modelDialogState.value === ModelDialogTitleStateType['edit']) {
|
} else if (modelDialogState.value === ModelDialogTitleStateType['edit']) {
|
||||||
updateModelReq(modelForm.value)
|
updateModelReq(modelForm.value)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@ -477,12 +470,7 @@ const submitModelForm = () => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
ElMessage.error(err?.response?.data?.msg ?? '修改失败')
|
ElMessage.error(err?.response?.data?.msg ?? '修改失败')
|
||||||
})
|
})
|
||||||
.finally(() => {
|
|
||||||
submitModelLoading.value = false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
const getModelList = (name?: string) => {
|
const getModelList = (name?: string) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@ -849,11 +837,9 @@ const closeAttributeForm = () => {
|
|||||||
attributeForm.value = JSON.parse(JSON.stringify(originAttributeForm))
|
attributeForm.value = JSON.parse(JSON.stringify(originAttributeForm))
|
||||||
attributeFormRef.value?.resetFields()
|
attributeFormRef.value?.resetFields()
|
||||||
}
|
}
|
||||||
const submitAttributeLoading = ref(false)
|
|
||||||
const submitAttributeForm = () => {
|
const submitAttributeForm = () => {
|
||||||
attributeFormRef.value?.validate((valid: boolean) => {
|
attributeFormRef.value?.validate((valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
submitAttributeLoading.value = true
|
|
||||||
const copyFormData = JSON.parse(JSON.stringify(attributeForm.value))
|
const copyFormData = JSON.parse(JSON.stringify(attributeForm.value))
|
||||||
copyFormData.highSpeed = copyFormData.highSpeed ? 1 : 0
|
copyFormData.highSpeed = copyFormData.highSpeed ? 1 : 0
|
||||||
copyFormData.visible = copyFormData.visible ? 1 : 0
|
copyFormData.visible = copyFormData.visible ? 1 : 0
|
||||||
@ -878,9 +864,6 @@ const submitAttributeForm = () => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
ElMessage.error(err?.response?.data?.msg ?? '新增失败')
|
ElMessage.error(err?.response?.data?.msg ?? '新增失败')
|
||||||
})
|
})
|
||||||
.finally(() => {
|
|
||||||
submitAttributeLoading.value = false
|
|
||||||
})
|
|
||||||
} else if (attributeFormTitle.value === AttributeDialogTitleStateType['edit']) {
|
} else if (attributeFormTitle.value === AttributeDialogTitleStateType['edit']) {
|
||||||
updateModelAttributeReq(copyFormData)
|
updateModelAttributeReq(copyFormData)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@ -895,9 +878,6 @@ const submitAttributeForm = () => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
ElMessage.error(err?.response?.data?.msg ?? '修改失败')
|
ElMessage.error(err?.response?.data?.msg ?? '修改失败')
|
||||||
})
|
})
|
||||||
.finally(() => {
|
|
||||||
submitAttributeLoading.value = false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -925,11 +905,9 @@ const closeServiceForm = () => {
|
|||||||
serviceForm.value = JSON.parse(JSON.stringify(originServiceForm))
|
serviceForm.value = JSON.parse(JSON.stringify(originServiceForm))
|
||||||
serviceFormRef.value?.resetFields()
|
serviceFormRef.value?.resetFields()
|
||||||
}
|
}
|
||||||
const submitServiceLoading = ref(false)
|
|
||||||
const submitServiceForm = () => {
|
const submitServiceForm = () => {
|
||||||
serviceFormRef.value?.validate((valid: boolean) => {
|
serviceFormRef.value?.validate((valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
submitServiceLoading.value = true
|
|
||||||
if (serviceFormTitle.value === serviceDialogTitleStateType['add']) {
|
if (serviceFormTitle.value === serviceDialogTitleStateType['add']) {
|
||||||
serviceForm.value.iotModelId = curContextMenuTreeData.value!.id!
|
serviceForm.value.iotModelId = curContextMenuTreeData.value!.id!
|
||||||
addModelServiceReq(serviceForm.value)
|
addModelServiceReq(serviceForm.value)
|
||||||
@ -945,9 +923,6 @@ const submitServiceForm = () => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
ElMessage.error(err?.response?.data?.msg ?? '新增失败')
|
ElMessage.error(err?.response?.data?.msg ?? '新增失败')
|
||||||
})
|
})
|
||||||
.finally(() => {
|
|
||||||
submitServiceLoading.value = false
|
|
||||||
})
|
|
||||||
} else if (serviceFormTitle.value === serviceDialogTitleStateType['edit']) {
|
} else if (serviceFormTitle.value === serviceDialogTitleStateType['edit']) {
|
||||||
updateModelServiceReq(serviceForm.value)
|
updateModelServiceReq(serviceForm.value)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@ -962,9 +937,6 @@ const submitServiceForm = () => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
ElMessage.error(err?.response?.data?.msg ?? '修改失败')
|
ElMessage.error(err?.response?.data?.msg ?? '修改失败')
|
||||||
})
|
})
|
||||||
.finally(() => {
|
|
||||||
submitServiceLoading.value = false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -132,7 +132,7 @@
|
|||||||
<div class="imgName">全场有功</div>
|
<div class="imgName">全场有功</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="num">{{ realDataList.windfarmactivepower }}</div>
|
<div class="num">33</div>
|
||||||
<div class="unit">MW</div>
|
<div class="unit">MW</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -142,7 +142,7 @@
|
|||||||
<div class="imgName">AGC目标值</div>
|
<div class="imgName">AGC目标值</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="num">{{ realDataListSetValue.AgcTarget }}</div>
|
<div class="num">6</div>
|
||||||
<div class="unit">MW</div>
|
<div class="unit">MW</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -150,8 +150,8 @@
|
|||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="name">AGC投入/退出</div>
|
<div class="name">AGC投入/退出</div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<div class="smallDot" :class="realDataList.operationstatusagc ? 'successColor' : 'defaultColor'"></div>
|
<div class="smallDot" :class="agcOnOff ? 'successColor' : 'defaultColor'"></div>
|
||||||
<div class="smallDot" :class="realDataList.operationstatusagc ? 'defaultColor' : 'errorColor'"></div>
|
<div class="smallDot" :class="agcOnOff ? 'defaultColor' : 'errorColor'"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
@ -176,26 +176,26 @@
|
|||||||
<div class="check">
|
<div class="check">
|
||||||
<div class="left">AGC增闭锁</div>
|
<div class="left">AGC增闭锁</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="dot" :class="realDataList.activepowerincdisabled ? 'successColor' : 'errorColor'"></div>
|
<div class="dot" :class="agcAdd ? 'successColor' : 'errorColor'"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="check">
|
<div class="check">
|
||||||
<div class="left">AGC减闭锁</div>
|
<div class="left">AGC减闭锁</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="dot" :class="realDataList.activepowerdecdisabled ? 'successColor' : 'errorColor'"></div>
|
<div class="dot" :class="agcSub ? 'successColor' : 'errorColor'"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="check">
|
<div class="check">
|
||||||
<div class="left">AGC可增有功</div>
|
<div class="left">AGC可增有功</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="num">{{ realDataList.activepowerinccapacity }}</div>
|
<div class="num">5</div>
|
||||||
<div class="unit">MW</div>
|
<div class="unit">MW</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="check">
|
<div class="check">
|
||||||
<div class="left">AGC可减有功</div>
|
<div class="left">AGC可减有功</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="num">{{ realDataList.activepowerdeccapacity }}</div>
|
<div class="num">5</div>
|
||||||
<div class="unit">MW</div>
|
<div class="unit">MW</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -222,7 +222,7 @@
|
|||||||
<div class="imgName">全场无功</div>
|
<div class="imgName">全场无功</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="num">{{ realDataList.windfarmreactivepower }}</div>
|
<div class="num">33</div>
|
||||||
<div class="unit">MVar</div>
|
<div class="unit">MVar</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -232,7 +232,7 @@
|
|||||||
<div class="imgName">AVC目标值</div>
|
<div class="imgName">AVC目标值</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="num">{{ realDataListSetValue.AvcTarget }}</div>
|
<div class="num">6</div>
|
||||||
<div class="unit">MVar</div>
|
<div class="unit">MVar</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -240,8 +240,8 @@
|
|||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="name">AVC投入/退出</div>
|
<div class="name">AVC投入/退出</div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<div class="smallDot" :class="realDataList.operationstatusavc ? 'successColor' : 'defaultColor'"></div>
|
<div class="smallDot" :class="avcOnOff ? 'successColor' : 'defaultColor'"></div>
|
||||||
<div class="smallDot" :class="realDataList.operationstatusavc ? 'defaultColor' : 'errorColor'"></div>
|
<div class="smallDot" :class="avcOnOff ? 'defaultColor' : 'errorColor'"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
@ -266,26 +266,26 @@
|
|||||||
<div class="check">
|
<div class="check">
|
||||||
<div class="left">AVC增闭锁</div>
|
<div class="left">AVC增闭锁</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="dot" :class="realDataList.reactivepowerincdisabled ? 'successColor' : 'errorColor'"></div>
|
<div class="dot" :class="avcAdd ? 'successColor' : 'errorColor'"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="check">
|
<div class="check">
|
||||||
<div class="left">AVC减闭锁</div>
|
<div class="left">AVC减闭锁</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="dot" :class="realDataList.reactivepowerdecdisabled ? 'successColor' : 'errorColor'"></div>
|
<div class="dot" :class="avcSub ? 'successColor' : 'errorColor'"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="check">
|
<div class="check">
|
||||||
<div class="left">AVC可增无功</div>
|
<div class="left">AVC可增无功</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="num">{{ realDataList.reactivepowerinccapacity }}</div>
|
<div class="num">5</div>
|
||||||
<div class="unit">MVar</div>
|
<div class="unit">MVar</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="check">
|
<div class="check">
|
||||||
<div class="left">AVC可减无功</div>
|
<div class="left">AVC可减无功</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="num">{{ realDataList.reactivepowerdeccapacity }}</div>
|
<div class="num">5</div>
|
||||||
<div class="unit">MVar</div>
|
<div class="unit">MVar</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -306,7 +306,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted, nextTick, reactive } from 'vue'
|
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
|
||||||
import { getAirBlowerListReq } from '/@/api/backend/airBlower/request'
|
import { getAirBlowerListReq } from '/@/api/backend/airBlower/request'
|
||||||
import { getRealValueListReq, getRealValueRangeReq } from '/@/api/backend/deviceModel/request'
|
import { getRealValueListReq, getRealValueRangeReq } from '/@/api/backend/deviceModel/request'
|
||||||
import { getRealTimeState, getCutDecimalsValue, getEnumToValue } from '/@/views/backend/equipment/airBlower/utils'
|
import { getRealTimeState, getCutDecimalsValue, getEnumToValue } from '/@/views/backend/equipment/airBlower/utils'
|
||||||
@ -770,7 +770,7 @@ const getRangeValueList = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const getRealDataForChart = () => {
|
const getRealData = () => {
|
||||||
const params = [
|
const params = [
|
||||||
{
|
{
|
||||||
deviceId: tableData.value[0].irn,
|
deviceId: tableData.value[0].irn,
|
||||||
@ -784,12 +784,13 @@ const getRealDataForChart = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let autoUpdateChartTimer: any = null
|
let autoUpdateChartTimer: any = null
|
||||||
|
|
||||||
const autoUpdateChart = () => {
|
const autoUpdateChart = () => {
|
||||||
if (!autoUpdateChartTimer) {
|
if (!autoUpdateChartTimer) {
|
||||||
autoUpdateChartTimer = setInterval(() => {
|
autoUpdateChartTimer = setInterval(() => {
|
||||||
getRealDataForChart()
|
getRealData()
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -840,13 +841,13 @@ const infoList = ref([
|
|||||||
const activeName = ref('list')
|
const activeName = ref('list')
|
||||||
const handleClick = (tabName: any) => {
|
const handleClick = (tabName: any) => {
|
||||||
if (tabName === 'chart') {
|
if (tabName === 'chart') {
|
||||||
console.log(tabName)
|
console.log(tabName);
|
||||||
|
|
||||||
stopAutoUpdate()
|
stopAutoUpdate()
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
createChart()
|
createChart()
|
||||||
})
|
})
|
||||||
} else if (tabName === 'list') {
|
}else if( tabName === 'list'){
|
||||||
autoUpdateAirBlower()
|
autoUpdateAirBlower()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -869,71 +870,15 @@ const resizeFn = () => {
|
|||||||
const stopAutoUpdate = () => {
|
const stopAutoUpdate = () => {
|
||||||
timer && clearInterval(timer)
|
timer && clearInterval(timer)
|
||||||
timer = null
|
timer = null
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const realDataListSetValue = reactive({
|
|
||||||
AgcTarget: '0',
|
|
||||||
AvcTarget: '0',
|
|
||||||
})
|
|
||||||
const realDataList = reactive({
|
|
||||||
windfarmactivepower: '',
|
|
||||||
operationstatusagc: '',
|
|
||||||
RemoteCtrlStatusAgc: '',
|
|
||||||
activepowerincdisabled: '',
|
|
||||||
activepowerdecdisabled: '',
|
|
||||||
activepowerinccapacity: '',
|
|
||||||
activepowerdeccapacity: '',
|
|
||||||
windfarmreactivepower: '',
|
|
||||||
operationstatusavc: '',
|
|
||||||
RemoteCtrlStatusAvc: '',
|
|
||||||
reactivepowerincdisabled: '',
|
|
||||||
reactivepowerdecdisabled: '',
|
|
||||||
reactivepowerinccapacity: '',
|
|
||||||
reactivepowerdeccapacity: '',
|
|
||||||
})
|
|
||||||
const getRealDataForList = () => {
|
|
||||||
const deviceId = '1881630608594132993'
|
|
||||||
const attrs = Object.keys(realDataList) as (keyof typeof realDataList)[]
|
|
||||||
const params = [
|
|
||||||
{
|
|
||||||
deviceId,
|
|
||||||
attributes: attrs,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
getRealValueListReq(params).then((res) => {
|
|
||||||
if (res.data) {
|
|
||||||
console.log(res.data, 'res.data')
|
|
||||||
const data = res.data[deviceId]
|
|
||||||
attrs.forEach((item) => {
|
|
||||||
realDataList[item] = data?.[item] ?? '-'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
let listTimer: any = null
|
|
||||||
const autoUpdateList = () => {
|
|
||||||
if (!listTimer) {
|
|
||||||
getRealDataForList()
|
|
||||||
listTimer = setInterval(() => {
|
|
||||||
getRealDataForList()
|
|
||||||
}, 2000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const clearListTimer = () => {
|
|
||||||
listTimer && clearInterval(listTimer)
|
|
||||||
listTimer = null
|
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getContainerHeight()
|
getContainerHeight()
|
||||||
autoUpdateList()
|
|
||||||
autoUpdateAirBlower()
|
autoUpdateAirBlower()
|
||||||
window.addEventListener('resize', resizeFn)
|
window.addEventListener('resize', resizeFn)
|
||||||
})
|
})
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener('resize', resizeFn)
|
window.removeEventListener('resize', resizeFn)
|
||||||
stopAutoUpdate()
|
stopAutoUpdate()
|
||||||
clearListTimer()
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
<div class="pointDialogColTitle">风机列表</div>
|
<div class="pointDialogColTitle">风机列表</div>
|
||||||
<div class="pointDialogColContent">
|
<div class="pointDialogColContent">
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
<el-checkbox-group v-model="selectWindBlower" :max="searchData.interval === 'NONE' ? 1 : 99">
|
<el-checkbox-group v-model="selectWindBlower">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-for="v in windBlowerOptions"
|
v-for="v in windBlowerOptions"
|
||||||
:key="v.value"
|
:key="v.value"
|
||||||
|
@ -443,11 +443,7 @@ const getSafeImagePath = (item, type) => {
|
|||||||
}
|
}
|
||||||
.wind-default {
|
.wind-default {
|
||||||
background-image: linear-gradient(180deg, #f0f6ff 0%, #ffffff 50%);
|
background-image: linear-gradient(180deg, #f0f6ff 0%, #ffffff 50%);
|
||||||
border: 1px solid #ffffff;
|
border: 1px solid #e1edf6;
|
||||||
// border: 1px solid #e1edf6;
|
|
||||||
opacity: 1;
|
|
||||||
background: transparent;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.wind-offline {
|
.wind-offline {
|
||||||
background-image: linear-gradient(180deg, #dddddd 0%, #ffffff 93%);
|
background-image: linear-gradient(180deg, #dddddd 0%, #ffffff 93%);
|
||||||
@ -479,7 +475,6 @@ const getSafeImagePath = (item, type) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 170px;
|
width: 170px;
|
||||||
// width: 170px;
|
|
||||||
height: 110px;
|
height: 110px;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
|
@ -2,32 +2,7 @@
|
|||||||
<div class="report" style="width: 100%; height: 100%">
|
<div class="report" style="width: 100%; height: 100%">
|
||||||
<div class="topForm">
|
<div class="topForm">
|
||||||
<div class="forms">
|
<div class="forms">
|
||||||
<div>
|
<el-space>
|
||||||
<el-space style="margin-top: 10px">
|
|
||||||
<div style="min-width: 30px">模板</div>
|
|
||||||
<el-select v-model="template" placeholder="请选择模板" class="templateSelect commonSelect">
|
|
||||||
<el-option v-for="v in reportTemplateList" :key="v.value" :label="v.label" :value="v.value" @click="changeTemplate">
|
|
||||||
<template #default>
|
|
||||||
<div class="tamplateOption">
|
|
||||||
<span>{{ v.label }}</span>
|
|
||||||
<el-icon style="color: red" @click="delReportTemplate(v.value)">
|
|
||||||
<Delete />
|
|
||||||
</el-icon>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
<div style="width: 20px"></div>
|
|
||||||
<!-- <div>{{ t('statAnalysis.attributes') }}</div>
|
|
||||||
<el-input
|
|
||||||
style="width: 200px; height: 40px"
|
|
||||||
v-model="currentChoose"
|
|
||||||
:placeholder="'请选择' + t('statAnalysis.attributes')"
|
|
||||||
></el-input>
|
|
||||||
<el-button type="primary" size="small" :icon="Plus" circle @click="chooseMeasurePoint"> </el-button> -->
|
|
||||||
</el-space>
|
|
||||||
</div>
|
|
||||||
<el-space class="parameters">
|
|
||||||
<div style="min-width: 30px">{{ t('statAnalysis.deviceId') }}</div>
|
<div style="min-width: 30px">{{ t('statAnalysis.deviceId') }}</div>
|
||||||
<el-select
|
<el-select
|
||||||
v-model="windBlowerValue"
|
v-model="windBlowerValue"
|
||||||
@ -65,7 +40,31 @@
|
|||||||
<el-option v-for="v in calFunctions" :key="v.value" :label="v.label" :value="v.value"></el-option>
|
<el-option v-for="v in calFunctions" :key="v.value" :label="v.label" :value="v.value"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-space>
|
</el-space>
|
||||||
|
<div>
|
||||||
|
<el-space style="margin-top: 10px">
|
||||||
|
<div style="min-width: 30px">模板</div>
|
||||||
|
<el-select v-model="template" placeholder="请选择模板" class="templateSelect commonSelect">
|
||||||
|
<el-option v-for="v in reportTemplateList" :key="v.value" :label="v.label" :value="v.value" @click="changeTemplate">
|
||||||
|
<template #default>
|
||||||
|
<div class="tamplateOption">
|
||||||
|
<span>{{ v.label }}</span>
|
||||||
|
<el-icon style="color: red" @click="delReportTemplate(v.value)">
|
||||||
|
<Delete />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
<div style="width: 20px"></div>
|
||||||
|
<!-- <div>{{ t('statAnalysis.attributes') }}</div>
|
||||||
|
<el-input
|
||||||
|
style="width: 200px; height: 40px"
|
||||||
|
v-model="currentChoose"
|
||||||
|
:placeholder="'请选择' + t('statAnalysis.attributes')"
|
||||||
|
></el-input>
|
||||||
|
<el-button type="primary" size="small" :icon="Plus" circle @click="chooseMeasurePoint"> </el-button> -->
|
||||||
|
</el-space>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<el-button class="button" :icon="Search" @click="queryHistoryData" type="primary">查询</el-button>
|
<el-button class="button" :icon="Search" @click="queryHistoryData" type="primary">查询</el-button>
|
||||||
@ -690,8 +689,4 @@ onMounted(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
.parameters{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user