Merge branch 'main' of https://git.jsspisoft.com/ry-das
This commit is contained in:
commit
2f665e5d3e
@ -0,0 +1,14 @@
|
||||
package com.das.common.constant;
|
||||
|
||||
/**
|
||||
* 统计分析
|
||||
*/
|
||||
public interface StatisticalAnalysisConstant {
|
||||
|
||||
|
||||
String TREND_ANALYSE = "趋势分析";
|
||||
|
||||
String POWER_CURVE = "功率曲线";
|
||||
|
||||
String TREND_CONTRAST = "趋势对比";
|
||||
}
|
@ -5,7 +5,9 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.das.common.result.R;
|
||||
import com.das.modules.equipment.entity.SysEquipment;
|
||||
import com.das.modules.fdr.domain.FileNode;
|
||||
import com.das.modules.fdr.domain.dto.FileDownloadDto;
|
||||
import com.das.modules.fdr.service.FaultRecorderService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -45,4 +47,10 @@ public class FaultRecorderController {
|
||||
|
||||
faultRecorderService.updateFdrConfig(sysEquipment);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/download", method = RequestMethod.POST)
|
||||
public void downloadFdrFile(@RequestBody FileDownloadDto fileDownloadDto, HttpServletResponse httpServletResponse) throws IOException {
|
||||
|
||||
faultRecorderService.download(fileDownloadDto.getUrl(),httpServletResponse);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.das.modules.fdr.domain.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class FileDownloadDto {
|
||||
|
||||
private String url;
|
||||
}
|
@ -2,6 +2,7 @@ package com.das.modules.fdr.service;
|
||||
|
||||
import com.das.modules.equipment.entity.SysEquipment;
|
||||
import com.das.modules.fdr.domain.FileNode;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -13,6 +14,8 @@ import java.util.Map;
|
||||
public interface FaultRecorderService {
|
||||
List<FileNode> getDirOrFileList(String name,String startTime, String endTime);
|
||||
|
||||
void download(String path, HttpServletResponse httpServletResponse) throws IOException;
|
||||
|
||||
Map<String, List<Object>> getDataCurve(String url, String deviceCode) throws IOException;
|
||||
|
||||
void updateFdrConfig(SysEquipment sysEquipment);
|
||||
@ -20,9 +23,4 @@ public interface FaultRecorderService {
|
||||
String upload(String parent, String folderName, MultipartFile file);
|
||||
|
||||
void readFileToSteam(String path, OutputStream stream);
|
||||
|
||||
void download(String path, Path tempDir);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import io.micrometer.common.util.StringUtils;
|
||||
import io.minio.*;
|
||||
import io.minio.errors.*;
|
||||
import io.minio.messages.Item;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -160,7 +161,7 @@ public class MinioViewsServcie {
|
||||
lastModifyTime = zonedDateTime.format(dateFormat);
|
||||
}
|
||||
if (parts.length > 0) {
|
||||
String nodeName = parts[0];
|
||||
String nodeName = parts[1];
|
||||
int type = isDir ? 0 : 1;
|
||||
itemName= isDir ? itemName.substring(0,itemName.lastIndexOf("/")) : itemName;
|
||||
FileNode node = new FileNode(nodeName, type,size,lastModifyTime,"/"+itemName);
|
||||
@ -185,22 +186,60 @@ public class MinioViewsServcie {
|
||||
}
|
||||
}
|
||||
|
||||
public void download(String path, Path tempDir) {
|
||||
public void download(String path, Path tempDir,HttpServletResponse httpServletResponse) {
|
||||
|
||||
File tempFile = null;
|
||||
try (InputStream inputStream = minioClient.getObject(GetObjectArgs.builder()
|
||||
.bucket(minioProperties.getBucket())
|
||||
.object(path)
|
||||
.build())) {
|
||||
|
||||
// 保存到临时文件夹
|
||||
File tempFile = tempDir.resolve(tempDir+path).toFile();
|
||||
FileUtil.writeFromStream(inputStream,tempFile);
|
||||
}
|
||||
catch (Exception ignored){
|
||||
tempFile = tempDir.resolve(tempDir + path).toFile();
|
||||
FileUtil.writeFromStream(inputStream, tempFile);
|
||||
writeFileToRes(tempFile, httpServletResponse);
|
||||
} catch (Exception ignored) {
|
||||
|
||||
} finally {
|
||||
assert tempFile != null;
|
||||
if (tempFile.exists()){
|
||||
tempFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void writeFileToRes(File downloadFile, HttpServletResponse response) throws IOException {
|
||||
// 检查文件是否存在
|
||||
if (!downloadFile.exists()) {
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取文件名
|
||||
String fileName = downloadFile.getName();
|
||||
|
||||
fileName = java.net.URLEncoder.encode(fileName, "UTF-8");
|
||||
|
||||
// 设置响应头
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setContentLength((int) downloadFile.length());
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
|
||||
|
||||
// 读取文件并写入响应的输出流
|
||||
try (FileInputStream inStream = new FileInputStream(downloadFile);
|
||||
OutputStream outStream = response.getOutputStream()) {
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead = -1;
|
||||
|
||||
while ((bytesRead = inStream.read(buffer)) != -1) {
|
||||
outStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 递归方式 计算文件的大小
|
||||
public long getTotalSizeOfFilesInDir(File file) {
|
||||
if (file.isFile()) {
|
||||
@ -229,4 +268,5 @@ public class MinioViewsServcie {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.das.modules.fdr.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.das.common.constant.FileConstants;
|
||||
import com.das.common.exceptions.ServiceException;
|
||||
@ -12,17 +11,16 @@ import com.das.modules.fdr.domain.FileNode;
|
||||
import com.das.modules.fdr.domain.vo.FdrFormatVo;
|
||||
import com.das.modules.fdr.service.FaultRecorderService;
|
||||
import com.das.modules.fdr.service.MinioViewsServcie;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.micrometer.common.util.StringUtils;
|
||||
import io.minio.GetObjectArgs;
|
||||
import io.minio.MinioClient;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.rmi.ServerException;
|
||||
import java.text.ParseException;
|
||||
@ -30,7 +28,6 @@ import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@ -75,8 +72,9 @@ public class FaultRecorderServiceImpl implements FaultRecorderService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(String path, Path tempDir) {
|
||||
minioViewsServcie.download(path, tempDir);
|
||||
public void download(String path,HttpServletResponse httpServletResponse) throws IOException {
|
||||
Path tempDir = Files.createTempDirectory(null);
|
||||
minioViewsServcie.download(path, tempDir,httpServletResponse);
|
||||
}
|
||||
|
||||
|
||||
@ -188,6 +186,8 @@ public class FaultRecorderServiceImpl implements FaultRecorderService {
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public long convertToTimestamp(String time, String pattern) throws ParseException {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
|
||||
return sdf.parse(time).getTime();
|
||||
|
@ -5,6 +5,7 @@ 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.exceptions.ServiceException;
|
||||
import com.das.common.utils.BeanCopyUtils;
|
||||
import com.das.modules.curve.domain.entity.CurveItemEntity;
|
||||
@ -20,9 +21,13 @@ import com.das.modules.page.service.StatisticalAnalysisService;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
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.usermodel.Workbook;
|
||||
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.XSSFClientAnchor;
|
||||
import org.apache.poi.xssf.usermodel.XSSFDrawing;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
@ -82,19 +87,22 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
//获取Excel的列
|
||||
LinkedHashMap<String, String> map = getTrendColumnName(param);
|
||||
List<Map<String, Object>> dataList = new ArrayList<>();
|
||||
//图表数据集
|
||||
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
|
||||
// 遍历数据,填充Excel和图表数据集
|
||||
setTrendAnalyseExcelValue(mapsList, dataList, map, dataset);
|
||||
// 遍历数据,填充Excel数据集
|
||||
setTrendAnalyseExcelValue(mapsList, dataList);
|
||||
//获取图表类别集
|
||||
List<String> chartKey = getCharKey(map);
|
||||
ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx");
|
||||
//设置Excel样式
|
||||
setExcelStyle(writer, map, dataList);
|
||||
// 使用JFreeChart生成折线图
|
||||
createChart(dataList, writer, dataset, "趋势分析");
|
||||
//生成折线图
|
||||
addChartToExcel(writer,dataList,StatisticalAnalysisConstant.TREND_ANALYSE,chartKey);
|
||||
//下载Excel
|
||||
downloadExcel(response, writer,"趋势分析");
|
||||
downloadExcel(response, writer,StatisticalAnalysisConstant.TREND_ANALYSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 功率曲线Excel导出
|
||||
*
|
||||
@ -114,15 +122,15 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
setPowerCurveExcelValue(resultMap, dataList, curveItemEntitieList);
|
||||
//获取功率曲线的列
|
||||
LinkedHashMap<String, String> map = getPowerCurveColumnName();
|
||||
//获取图表数据集
|
||||
DefaultCategoryDataset dataset = getDefaultCategoryDataset(dataList);
|
||||
//获取图表类别集
|
||||
List<String> chartKey = getCharKey(map);
|
||||
ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx");
|
||||
//设置Excel样式
|
||||
setExcelStyle(writer, map, dataList);
|
||||
//使用JFreeChart生成图表
|
||||
createChart(dataList, writer, dataset, "功率曲线分析");
|
||||
//生成折线图
|
||||
addChartToExcel(writer,dataList,StatisticalAnalysisConstant.POWER_CURVE,chartKey);
|
||||
//下载Excel
|
||||
downloadExcel(response, writer,"功率曲线分析");
|
||||
downloadExcel(response, writer,StatisticalAnalysisConstant.POWER_CURVE);
|
||||
}
|
||||
|
||||
|
||||
@ -140,44 +148,19 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
//自定义别名 别名的key和实体类中的名称要对应上!
|
||||
LinkedHashMap<String, String> map = gettrendContrastColumnName(param);
|
||||
List<Map<String, Object>> dataList = new ArrayList<>();
|
||||
//图表数据集
|
||||
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
|
||||
//图表类别集
|
||||
List<String> charKey = getCharKey(map);
|
||||
// 遍历数据,将数据添加到dataList中
|
||||
setTrendContrastExcelValue(maps, dataList, map, dataset);
|
||||
setTrendContrastExcelValue(maps, dataList);
|
||||
ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx");
|
||||
//设置Excel样式
|
||||
setExcelStyle(writer, map, dataList);
|
||||
// 使用JFreeChart生成折线图
|
||||
createChart(dataList, writer, dataset, "趋势对比");
|
||||
//生成折线图
|
||||
addChartToExcel(writer,dataList,StatisticalAnalysisConstant.TREND_CONTRAST,charKey);
|
||||
//下载Excel
|
||||
downloadExcel(response, writer,"趋势对比");
|
||||
downloadExcel(response, writer,StatisticalAnalysisConstant.TREND_CONTRAST);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图表数据集
|
||||
*
|
||||
* @param dataList 数据集
|
||||
* @return 图表数据集
|
||||
*/
|
||||
private DefaultCategoryDataset getDefaultCategoryDataset(List<Map<String, Object>> dataList) {
|
||||
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
|
||||
for (Map<String, Object> mapData : dataList) {
|
||||
Object time = mapData.get("time");
|
||||
Object speed = mapData.get("iWindSpeed");
|
||||
Object power = mapData.get("iGenPower");
|
||||
Object theorySpeed = mapData.get("theoryIWindSpeed");
|
||||
Object theoryPower = mapData.get("theoryIGenPower");
|
||||
if (speed != null && power != null) {
|
||||
dataset.addValue((Float) speed, "风速实际值", (String) time);
|
||||
dataset.addValue((Float) power, "功率实际值", (String) time);
|
||||
}
|
||||
if (theorySpeed != null && theoryPower != null) {
|
||||
dataset.addValue((Float) theorySpeed, "风速理论值", (String) time);
|
||||
dataset.addValue((Float) theoryPower, "功率理论值", (String) time);
|
||||
}
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -200,15 +183,11 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
|
||||
/**
|
||||
* 趋势分析-遍历数据,填充Excel和图表数据集
|
||||
*
|
||||
* @param mapsList 测点历史数据
|
||||
* @param dataList Excel数据集
|
||||
* @param map 表格的列
|
||||
* @param dataset 图表数据集
|
||||
*/
|
||||
private void setTrendAnalyseExcelValue(List<Map<String, Map<String, Map<String, Object>>>> mapsList,
|
||||
List<Map<String, Object>> dataList,
|
||||
LinkedHashMap<String, String> map, DefaultCategoryDataset dataset) {
|
||||
List<Map<String, Object>> dataList) {
|
||||
for (int i = 0; i < mapsList.size(); i++) {
|
||||
List<String> timesListstr = new ArrayList<>();
|
||||
List<Double> valuesList = new ArrayList<>();
|
||||
@ -237,10 +216,6 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
}
|
||||
String pointNameKey = pointName + num;
|
||||
String timeKey = "time" + num;
|
||||
//添加图表的数据集
|
||||
for (int j = 0; j < timesListstr.size(); j++) {
|
||||
dataset.addValue(valuesList.get(j), map.get(pointNameKey), timesListstr.get(j));
|
||||
}
|
||||
if (i == 0) {
|
||||
for (int j = 0; j < timesListstr.size(); j++) {
|
||||
Map<String, Object> dataMap = new HashMap<>();
|
||||
@ -258,16 +233,31 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图表类别集
|
||||
* @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 dataList Excel数据集
|
||||
* @param map 表格的列
|
||||
* @param dataset Excel数据集
|
||||
* @param maps 测点数据
|
||||
*/
|
||||
private void setTrendContrastExcelValue(Map<String, Map<String, Map<String, Object>>> maps,
|
||||
List<Map<String, Object>> dataList,
|
||||
LinkedHashMap<String, String> map, DefaultCategoryDataset dataset) {
|
||||
List<Map<String, Object>> dataList) {
|
||||
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()) {
|
||||
@ -303,19 +293,12 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
}
|
||||
}
|
||||
flagNum++;
|
||||
//生成图表的数据集
|
||||
for (int j = 0; j < timesListstr.size(); j++) {
|
||||
dataset.addValue(valuesList.get(j), map.get(key), timesListstr.get(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 趋势-获取表格的列
|
||||
* *
|
||||
*
|
||||
* @param param 查询条件
|
||||
* @return 表格的列
|
||||
*/
|
||||
@ -360,8 +343,7 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
|
||||
/**
|
||||
* 获取功率曲线的列
|
||||
*
|
||||
* @return
|
||||
* @return Excel的列
|
||||
*/
|
||||
private LinkedHashMap<String, String> getPowerCurveColumnName() {
|
||||
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||
@ -458,6 +440,7 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
*
|
||||
* @param response 响应对象
|
||||
* @param writer Excel对象
|
||||
* @param title 标题
|
||||
*/
|
||||
private void downloadExcel(HttpServletResponse response, ExcelWriter writer,String title) {
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
@ -468,7 +451,7 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
response.setDateHeader("Expires", 0);
|
||||
try {
|
||||
// 设置请求头属性
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(title+".xls", StandardCharsets.UTF_8));
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(title+"-"+System.currentTimeMillis()+".xls", StandardCharsets.UTF_8));
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
// 写出到文件
|
||||
writer.flush(out, true);
|
||||
@ -482,8 +465,7 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用JFreeChart生成折线图
|
||||
*
|
||||
* 使用JFreeChart生成折线图(图片),已弃用
|
||||
* @param data excel数据集
|
||||
* @param writer excel对象
|
||||
* @param dataset 图表数据集
|
||||
@ -554,6 +536,95 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成折线图,并插入到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 {
|
||||
// 获取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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 给每个类别,添加数据
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,8 +93,11 @@ const onClickSubMenu = (menu: RouteRecordRaw) => {
|
||||
padding: 0 v-bind(padding);
|
||||
}
|
||||
}
|
||||
:deep(.el-sub-menu__title) {
|
||||
padding: 0 v-bind(padding);
|
||||
.el-sub-menu {
|
||||
:deep(.el-sub-menu__title) {
|
||||
height: v-bind(height);
|
||||
padding: 0 v-bind(padding);
|
||||
}
|
||||
}
|
||||
.el-sub-menu .icon,
|
||||
.el-menu-item .icon {
|
||||
|
@ -14,7 +14,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, nextTick, onMounted, reactive, onUnmounted } from 'vue'
|
||||
import { ref, computed, nextTick, onMounted, reactive, onUnmounted, watch } from 'vue'
|
||||
import MenuTree from '/@/layouts/backend/components/menus/menuTree.vue'
|
||||
import { useRoute, onBeforeRouteUpdate, type RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
import { layoutMenuRef, layoutMenuScrollbarRef } from '/@/stores/refs'
|
||||
@ -40,6 +40,9 @@ onUnmounted(() => {
|
||||
// 组件卸载前移除监听器
|
||||
window.removeEventListener('resize', resizeHandler)
|
||||
})
|
||||
watch([() => config.layout.menuCollapse], () => {
|
||||
resizeHandler()
|
||||
})
|
||||
const resizeHandler = () => {
|
||||
width.value = config.layout.menuCollapse ? '5px' : window.screen.width < 1920 ? '10px' : '20px'
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<div>功率</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :sm="24" :lg="6" class="small-panel">
|
||||
<div :sm="24" :lg="6" class="small-panel windtitle">
|
||||
<img class="small-panel-pic" src="~assets/dashboard/viewW.png" alt="" />
|
||||
<div class="small-base">
|
||||
<div>
|
||||
@ -504,6 +504,7 @@ const StatusListData = () => {
|
||||
ikwhthisday: item.attributeMap.ikwhthisday,
|
||||
iturbineoperationmode: state,
|
||||
locked: item.attributeMap.locked,
|
||||
irotorspeed:item.attributeMap.irotorspeed,
|
||||
},
|
||||
}
|
||||
})
|
||||
@ -1157,8 +1158,8 @@ const computedHeight = reactive({
|
||||
const sizeChange = () => {
|
||||
const rect = HomeHight.value?.getBoundingClientRect()
|
||||
if (!rect) return
|
||||
computedHeight.powerHeight = rect.height - 636 + 'px'
|
||||
computedHeight.alarmHeight = rect.height - 580 + 'px'
|
||||
computedHeight.powerHeight = rect.height - 630 + 'px'
|
||||
computedHeight.alarmHeight = rect.height - 578 + 'px'
|
||||
computedHeight.centerHeight = rect.height - 0 + 'px'
|
||||
if (window.screen.width < 1360) {
|
||||
computedHeight.alarmHeight = '200px'
|
||||
@ -1211,7 +1212,6 @@ $labelHeight: 38px;
|
||||
width: 100%;
|
||||
height: $labelHeight;
|
||||
font-size: 18px;
|
||||
line-height: 18px;
|
||||
font-weight: 600;
|
||||
color: #4e5969;
|
||||
line-height: 38px;
|
||||
@ -1220,13 +1220,18 @@ $labelHeight: 38px;
|
||||
}
|
||||
.default-main {
|
||||
width: 100%;
|
||||
// height: 100%;
|
||||
// min-height: 920px;
|
||||
height: 100%;
|
||||
min-height: 920px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
color: #4e5969;
|
||||
background-color: #f2f3f5;
|
||||
overflow: hidden;
|
||||
.el-row{
|
||||
width: calc(100% - 0px);
|
||||
.el-col{
|
||||
height: calc(100% - 10px);
|
||||
}
|
||||
}
|
||||
.content-number {
|
||||
color: #333333;
|
||||
font-size: 20px;
|
||||
@ -1315,7 +1320,7 @@ $labelHeight: 38px;
|
||||
@include cardDefaultStyle;
|
||||
@include cardlabel;
|
||||
width: 100%;
|
||||
min-height: 298px;
|
||||
min-height: 290px;
|
||||
height: v-bind('computedHeight.powerHeight');
|
||||
.chartBox {
|
||||
height: calc(100% - $labelHeight);
|
||||
@ -1326,14 +1331,15 @@ $labelHeight: 38px;
|
||||
}
|
||||
}
|
||||
.matrix {
|
||||
/* @include cardDefaultStyle;
|
||||
@include cardlabel;*/
|
||||
background: url('/@/assets/dashboard/bg1.png') no-repeat #ffffff;
|
||||
background-size: 100% 100%;
|
||||
min-height: 900px;
|
||||
width: 100%;
|
||||
height: v-bind('computedHeight.centerHeight');
|
||||
margin-bottom: 0;
|
||||
.el-scrollbar{
|
||||
height: calc(100% - 20px);
|
||||
}
|
||||
}
|
||||
.summarize {
|
||||
padding: 10px;
|
||||
@ -1341,7 +1347,6 @@ $labelHeight: 38px;
|
||||
background-color: #fff;
|
||||
margin-bottom: 20px;
|
||||
word-break: keep-all;
|
||||
/*@include cardDefaultStyle;*/
|
||||
@include cardlabel;
|
||||
min-height: 224px;
|
||||
.summarize-panel-list {
|
||||
@ -1375,14 +1380,8 @@ $labelHeight: 38px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.cardContentRight {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.trend {
|
||||
/* @include cardDefaultStyle;
|
||||
@include cardlabel;*/
|
||||
min-height: 300px;
|
||||
height: 335px;
|
||||
overflow: hidden;
|
||||
@ -1428,12 +1427,13 @@ $labelHeight: 38px;
|
||||
/* @include cardDefaultStyle;
|
||||
@include cardlabel;*/
|
||||
/*height: 370px;*/
|
||||
min-height: 350px;
|
||||
min-height: 340px;
|
||||
height: v-bind('computedHeight.alarmHeight');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 1920px) {
|
||||
.default-main {
|
||||
.trend {
|
||||
@ -1443,20 +1443,36 @@ $labelHeight: 38px;
|
||||
}
|
||||
@media screen and (max-width: 1280px) {
|
||||
.default-main {
|
||||
/*height: auto !important;*/
|
||||
overflow: none;
|
||||
.windtitle{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.summarize {
|
||||
.summarize-panel {
|
||||
margin: 2px !important;
|
||||
.summarize-panel-base {
|
||||
white-space: normal !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 1366px) {
|
||||
.default-main {
|
||||
.summarize {
|
||||
word-break: break-all !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 1360px) {
|
||||
.default-main {
|
||||
font-size: 11px !important;
|
||||
.overview {
|
||||
.small-panel {
|
||||
.small-base {
|
||||
margin-left: 0px !important;
|
||||
font-size: 11px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1491,6 +1507,9 @@ $labelHeight: 38px;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
.grid-content {
|
||||
.cardLabel{
|
||||
font-size: 16px !important;
|
||||
}
|
||||
.panelBg {
|
||||
/* padding: 10px !important;*/
|
||||
margin-bottom: 10px !important;
|
||||
@ -1507,7 +1526,7 @@ $labelHeight: 38px;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.matrix {
|
||||
height: 908px !important;
|
||||
height: 900px !important;
|
||||
}
|
||||
:deep(.el-tabs__header) {
|
||||
margin-top: -33px !important;
|
||||
|
@ -28,7 +28,7 @@
|
||||
<div class="fanlist-pic">
|
||||
<div class="mask">
|
||||
<div class="heart"><img src="~assets/dashboard/leaf2.png" alt=""></div>
|
||||
<div class="leafs" :style="animationDuration">
|
||||
<div class="leafs" :style="getAnimationStyle(item)">
|
||||
<div class="leaf_1"> <img src="~assets/dashboard/leaf1.png" alt=""></div>
|
||||
<div class="leaf_2"><img src="~assets/dashboard/leaf1.png" alt=""></div>
|
||||
<div class="leaf_3"><img src="~assets/dashboard/leaf1.png" alt=""></div>
|
||||
@ -68,7 +68,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref,reactive,defineProps, defineEmits} from 'vue'
|
||||
import {defineProps, defineEmits,onMounted,onUnmounted} from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { adminBaseRoutePath } from '/@/router/static/adminBase'
|
||||
|
||||
@ -79,11 +79,19 @@ const props = defineProps({
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['StatusListData'])
|
||||
const rotationspeed = 4;
|
||||
const animationDuration=reactive({
|
||||
'animation-duration': rotationspeed+'s',
|
||||
})
|
||||
|
||||
|
||||
const getAnimationStyle = (item) => {
|
||||
const irotorspeed = item.attributeMap?.irotorspeed ?? 0;
|
||||
const animationDuration = 1 / irotorspeed * 10;
|
||||
return {
|
||||
'animation-duration': `${animationDuration}s`,
|
||||
'animation-timing-function': 'linear',
|
||||
'animation-iteration-count': 'infinite',
|
||||
'animation-direction': 'normaL',
|
||||
};
|
||||
};
|
||||
|
||||
const handleDoubleClick = (row) => {
|
||||
if (!router.hasRoute('windTurbine')) {
|
||||
router.addRoute('admin', {
|
||||
@ -108,7 +116,6 @@ const handleDoubleClick = (row) => {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@ -241,8 +248,8 @@ const handleDoubleClick = (row) => {
|
||||
height: 46px;
|
||||
/*animation-duration: 1s;*/
|
||||
animation-name: leafRotate;
|
||||
animation-iteration-count: infinite;
|
||||
animation-timing-function: linear;
|
||||
/*animation-iteration-count: infinite;
|
||||
animation-timing-function: linear;*/
|
||||
.leaf_1 {
|
||||
width: 9px;
|
||||
height: 19px;
|
||||
@ -299,4 +306,18 @@ const handleDoubleClick = (row) => {
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1680px) {
|
||||
.FanList-content{
|
||||
.FanList-panel{
|
||||
.fanlist-text{
|
||||
font-size: 12px !important;
|
||||
.content-number{
|
||||
font-size: 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user