This commit is contained in:
zhouhuang 2024-12-26 10:10:18 +08:00
commit b56230fc42
20 changed files with 703 additions and 134 deletions

View File

@ -6,9 +6,9 @@ package com.das.common.constant;
public interface StatisticalAnalysisConstant { public interface StatisticalAnalysisConstant {
String TREND_ANALYSE = "趋势分析"; String TREND_ANALYSE = "单机分析";
String POWER_CURVE = "功率曲线"; String POWER_CURVE = "功率曲线";
String TREND_CONTRAST = "趋势对比"; String TREND_CONTRAST = "多机对比";
} }

View File

@ -0,0 +1,16 @@
package com.das.common.constant;
/**
* 统计分析
*/
public interface StatisticalAnalysisFunctionConstant {
String INTERPOLATION = "interpolation";
String AVERAGE = "average";
String MAX = "max";
String min = "min";
}

View File

@ -10,6 +10,7 @@ import com.das.modules.equipment.domain.dto.SysEquipmentDto;
import com.das.modules.equipment.domain.dto.SysGenExtPropsDto; import com.das.modules.equipment.domain.dto.SysGenExtPropsDto;
import com.das.modules.equipment.domain.vo.EquipmentTypeVo; import com.das.modules.equipment.domain.vo.EquipmentTypeVo;
import com.das.modules.equipment.domain.vo.SysEquipmentVo; import com.das.modules.equipment.domain.vo.SysEquipmentVo;
import com.das.modules.equipment.domain.vo.SysGenExtPropsVo;
import com.das.modules.equipment.entity.SysEquipmentDocs; import com.das.modules.equipment.entity.SysEquipmentDocs;
import com.das.modules.equipment.entity.SysGenExtProps; import com.das.modules.equipment.entity.SysGenExtProps;
import com.das.modules.equipment.service.SysEquipmentService; import com.das.modules.equipment.service.SysEquipmentService;
@ -148,7 +149,7 @@ public class EquipmentController {
* @return 所有附属属性 * @return 所有附属属性
*/ */
@PostMapping("/extProps/add") @PostMapping("/extProps/add")
public R<SysGenExtProps> addSysEquipmentExtProps(@RequestBody SysGenExtPropsDto sysGenExtPropsDto) { public R<SysGenExtPropsVo> addSysEquipmentExtProps(@RequestBody SysGenExtPropsDto sysGenExtPropsDto) {
//判断是否有权限 //判断是否有权限
boolean hasPermission = StpUtil.hasPermission(SysAuthorityIds.SYS_AUTHORITY_ID_DEVICE_MGR.toString()); boolean hasPermission = StpUtil.hasPermission(SysAuthorityIds.SYS_AUTHORITY_ID_DEVICE_MGR.toString());
if(!hasPermission){ if(!hasPermission){
@ -162,7 +163,7 @@ public class EquipmentController {
* @return 所有附属属性 * @return 所有附属属性
*/ */
@PostMapping("/extProps/update") @PostMapping("/extProps/update")
public R<SysGenExtProps> updateSysEquipmentExtProps(@RequestBody SysGenExtPropsDto sysGenExtPropsDto) { public R<SysGenExtPropsVo> updateSysEquipmentExtProps(@RequestBody SysGenExtPropsDto sysGenExtPropsDto) {
//判断是否有权限 //判断是否有权限
boolean hasPermission = StpUtil.hasPermission(SysAuthorityIds.SYS_AUTHORITY_ID_DEVICE_MGR.toString()); boolean hasPermission = StpUtil.hasPermission(SysAuthorityIds.SYS_AUTHORITY_ID_DEVICE_MGR.toString());
if(!hasPermission){ if(!hasPermission){
@ -176,7 +177,7 @@ public class EquipmentController {
* @return 所有附属属性 * @return 所有附属属性
*/ */
@PostMapping("/extProps/query") @PostMapping("/extProps/query")
public R<SysGenExtProps> querySysEquipmentExtProps(@RequestBody SysGenExtPropsDto sysGenExtPropsDto) { public R<SysGenExtPropsVo> querySysEquipmentExtProps(@RequestBody SysGenExtPropsDto sysGenExtPropsDto) {
//判断是否有权限 //判断是否有权限
boolean hasPermission = StpUtil.hasPermission(SysAuthorityIds.SYS_AUTHORITY_ID_DEVICE_MGR.toString()); boolean hasPermission = StpUtil.hasPermission(SysAuthorityIds.SYS_AUTHORITY_ID_DEVICE_MGR.toString());
if(!hasPermission){ if(!hasPermission){
@ -197,8 +198,8 @@ public class EquipmentController {
} }
@RequestMapping(value = "/file/upload", method = RequestMethod.POST) @RequestMapping(value = "/file/upload", method = RequestMethod.POST)
public R<List<SysEquipmentDocs>> addFile(Long deviceId, String component,String folderName, List<MultipartFile> fileList) throws Exception { public R<List<SysEquipmentDocs>> addFile(String folderName, List<MultipartFile> fileList){
List<SysEquipmentDocs> upload = sysEquipmentService.upload(deviceId, component,folderName, fileList); List<SysEquipmentDocs> upload = sysEquipmentService.upload(folderName, fileList);
return R.success(upload); return R.success(upload);
} }
@ -208,23 +209,13 @@ public class EquipmentController {
return R.success(fileList); return R.success(fileList);
} }
@RequestMapping(value = "/file/read", method = RequestMethod.POST) @RequestMapping(value = "/file/read", method = RequestMethod.GET)
public void readFile(String path, HttpServletResponse response) throws IOException { public void readFile(String path, HttpServletResponse response) throws IOException {
if (StringUtils.isBlank(path)){ if (StringUtils.isBlank(path)){
throw new ServiceException("请输入浏览的文件路径"); throw new ServiceException("请输入浏览的文件路径");
} }
response.setContentType("application/octet-stream"); response.setContentType("application/octet-stream");
sysEquipmentService.readFileToSteam(path, response.getOutputStream()); sysEquipmentService.readFileToSteam(path, response.getOutputStream());
} }
@RequestMapping(value = "/file/delete", method = RequestMethod.GET)
public void deleteFile(String path, HttpServletResponse response) throws IOException {
if (StringUtils.isBlank(path)){
throw new ServiceException("请输入浏览的文件路径");
}
response.setContentType("application/octet-stream");
sysEquipmentService.readFileToSteam(path, response.getOutputStream());
}
} }

View File

@ -4,12 +4,15 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.das.modules.equipment.entity.SysEquipmentDocs;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.List;
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@ -67,4 +70,6 @@ public class SysGenExtPropsDto {
private String mainControlSystemManufacturer; private String mainControlSystemManufacturer;
private String mainControlSystemSoftwareVersion; private String mainControlSystemSoftwareVersion;
private List<SysEquipmentDocs> sysEquipmentDocsList;
} }

View File

@ -0,0 +1,71 @@
package com.das.modules.equipment.domain.vo;
import com.das.modules.equipment.entity.SysEquipmentDocs;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SysGenExtPropsVo {
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
private String pitchSystemModel;
private String pitchSystemManufacturer;
private String blade1Model;
private String blade1Manufacturer;
private String blade1BearingModel;
private String blade1BearingManufacturer;
private String blade2Model;
private String blade2Manufacturer;
private String blade2BearingModel;
private String blade2BearingManufacturer;
private String blade3Model;
private String blade3Manufacturer;
private String blade3BearingModel;
private String blade3BearingManufacturer;
private String mainBearingModel;
private String mainBearingManufacturer;
private String gearboxModel;
private String gearboxManufacturer;
private String generatorModel;
private String generatorManufacturer;
private String converterModel;
private String converterManufacturer;
private String mainControlSystemModel;
private String mainControlSystemManufacturer;
private String mainControlSystemSoftwareVersion;
private List<SysEquipmentDocs> sysEquipmentDocsList;
}

View File

@ -4,6 +4,7 @@ import com.das.common.utils.PageDataInfo;
import com.das.modules.equipment.domain.dto.SysEquipmentDto; import com.das.modules.equipment.domain.dto.SysEquipmentDto;
import com.das.modules.equipment.domain.dto.SysGenExtPropsDto; import com.das.modules.equipment.domain.dto.SysGenExtPropsDto;
import com.das.modules.equipment.domain.vo.SysEquipmentVo; import com.das.modules.equipment.domain.vo.SysEquipmentVo;
import com.das.modules.equipment.domain.vo.SysGenExtPropsVo;
import com.das.modules.equipment.entity.SysEquipmentDocs; import com.das.modules.equipment.entity.SysEquipmentDocs;
import com.das.modules.equipment.entity.SysGenExtProps; import com.das.modules.equipment.entity.SysGenExtProps;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@ -32,19 +33,17 @@ public interface SysEquipmentService {
void importSysEquipment(String parentEquipmentId,MultipartFile file) throws IOException, ParseException; void importSysEquipment(String parentEquipmentId,MultipartFile file) throws IOException, ParseException;
SysGenExtProps creatSysEquipmentExtProps(SysGenExtPropsDto sysGenExtPropsDto); SysGenExtPropsVo creatSysEquipmentExtProps(SysGenExtPropsDto sysGenExtPropsDto);
SysGenExtProps updateSysEquipmentExtProps(SysGenExtPropsDto sysGenExtPropsDto); SysGenExtPropsVo updateSysEquipmentExtProps(SysGenExtPropsDto sysGenExtPropsDto);
void deleteSysEquipmentExtProps(Long id); void deleteSysEquipmentExtProps(Long id);
SysGenExtProps querySysEquipmentExtProps(Long id); SysGenExtPropsVo querySysEquipmentExtProps(Long id);
List<SysEquipmentDocs> upload(Long deviceId, String component,String folderName, List<MultipartFile> fileList) throws Exception; List<SysEquipmentDocs> upload(String folderName, List<MultipartFile> fileList);
List<SysEquipmentDocs> getFileList(Long deviceId, String component); List<SysEquipmentDocs> getFileList(Long deviceId, String component);
void readFileToSteam(String path, OutputStream stream); void readFileToSteam(String path, OutputStream stream);
void deleteFile(String path);
} }

View File

@ -9,6 +9,7 @@ import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter; import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.das.common.config.SessionUtil; import com.das.common.config.SessionUtil;
import com.das.common.constant.EquipmentTypeIds; import com.das.common.constant.EquipmentTypeIds;
import com.das.common.constant.FileConstants; import com.das.common.constant.FileConstants;
@ -28,6 +29,7 @@ import com.das.modules.equipment.domain.dto.SysEquipmentDto;
import com.das.modules.equipment.domain.dto.SysGenExtPropsDto; import com.das.modules.equipment.domain.dto.SysGenExtPropsDto;
import com.das.modules.equipment.domain.excel.SysEquipmentExcel; import com.das.modules.equipment.domain.excel.SysEquipmentExcel;
import com.das.modules.equipment.domain.vo.SysEquipmentVo; import com.das.modules.equipment.domain.vo.SysEquipmentVo;
import com.das.modules.equipment.domain.vo.SysGenExtPropsVo;
import com.das.modules.equipment.entity.SysEquipment; import com.das.modules.equipment.entity.SysEquipment;
import com.das.modules.equipment.entity.SysEquipmentDocs; import com.das.modules.equipment.entity.SysEquipmentDocs;
import com.das.modules.equipment.entity.SysGenExtProps; import com.das.modules.equipment.entity.SysGenExtProps;
@ -46,6 +48,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -65,6 +68,7 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Service @Service
@ -396,25 +400,69 @@ public class SysEquipmentServiceImpl implements SysEquipmentService {
} }
@Override @Override
public SysGenExtProps creatSysEquipmentExtProps(SysGenExtPropsDto sysGenExtPropsDto) { public SysGenExtPropsVo creatSysEquipmentExtProps(SysGenExtPropsDto sysGenExtPropsDto) {
if (sysGenExtPropsDto.getId() == null) { if (sysGenExtPropsDto.getId() == null) {
throw new ServiceException("设备id不能为空"); throw new ServiceException("设备id不能为空");
} }
SysGenExtProps sysEquipmentExtProps = new SysGenExtProps(); SysGenExtProps sysEquipmentExtProps = new SysGenExtProps();
BeanCopyUtils.copy(sysGenExtPropsDto, sysEquipmentExtProps); BeanCopyUtils.copy(sysGenExtPropsDto, sysEquipmentExtProps);
sysGenExtPropsMapper.insert(sysEquipmentExtProps); sysGenExtPropsMapper.insert(sysEquipmentExtProps);
return sysEquipmentExtProps; List<SysEquipmentDocs> sysEquipmentDocsList = sysGenExtPropsDto.getSysEquipmentDocsList();
if (CollectionUtils.isNotEmpty(sysEquipmentDocsList)){
for (SysEquipmentDocs item : sysEquipmentDocsList){
item.setUpdateTime(new Date());
item.setDeviceId(sysGenExtPropsDto.getId());
sysEquipmentDocsMapper.insert(item);
}
}
QueryWrapper<SysEquipmentDocs> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deviceid",sysGenExtPropsDto.getId());
List<SysEquipmentDocs> resultList = sysEquipmentDocsMapper.selectList(queryWrapper);
SysGenExtPropsVo sysGenExtPropsVo = new SysGenExtPropsVo();
BeanCopyUtils.copy(sysEquipmentExtProps,sysGenExtPropsVo);
sysGenExtPropsVo.setSysEquipmentDocsList(resultList);
return sysGenExtPropsVo;
} }
@Override @Override
public SysGenExtProps updateSysEquipmentExtProps(SysGenExtPropsDto sysGenExtPropsDto) { public SysGenExtPropsVo updateSysEquipmentExtProps(SysGenExtPropsDto sysGenExtPropsDto) {
if (sysGenExtPropsDto.getId() == null) { if (sysGenExtPropsDto.getId() == null) {
throw new ServiceException("设备id不能为空"); throw new ServiceException("设备id不能为空");
} }
SysGenExtProps sysEquipmentExtProps = new SysGenExtProps(); SysGenExtProps sysEquipmentExtProps = new SysGenExtProps();
BeanCopyUtils.copy(sysGenExtPropsDto, sysEquipmentExtProps); BeanCopyUtils.copy(sysGenExtPropsDto, sysEquipmentExtProps);
sysGenExtPropsMapper.updateById(sysEquipmentExtProps); sysGenExtPropsMapper.updateById(sysEquipmentExtProps);
return sysEquipmentExtProps; List<SysEquipmentDocs> sysEquipmentDocsList = sysGenExtPropsDto.getSysEquipmentDocsList();
if (CollectionUtils.isNotEmpty(sysEquipmentDocsList)){
List<SysEquipmentDocs> insertList = sysEquipmentDocsList.stream().filter(item -> item.getId() == null).collect(Collectors.toList());
sysEquipmentDocsList.removeAll(insertList);
if (CollectionUtils.isNotEmpty(sysEquipmentDocsList)){
List<Long> collect = sysEquipmentDocsList.stream().map(SysEquipmentDocs::getId).collect(Collectors.toList());
QueryWrapper<SysEquipmentDocs> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deviceid",sysGenExtPropsDto.getId());
List<SysEquipmentDocs> sysEquipmentDocs = sysEquipmentDocsMapper.selectList(queryWrapper);
List<SysEquipmentDocs> collectDelete = sysEquipmentDocs.stream().filter(item -> !collect.contains(item.getId())).collect(Collectors.toList());
//删除minio文件和数据库记录
for (SysEquipmentDocs item : collectDelete){
sysEquipmentDocsMapper.deleteById(item.getId());
deleteFile(item);
}
}
for (SysEquipmentDocs item : insertList){
item.setUpdateTime(new Date());
item.setDeviceId(sysGenExtPropsDto.getId());
sysEquipmentDocsMapper.insert(item);
}
}
QueryWrapper<SysEquipmentDocs> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deviceid",sysGenExtPropsDto.getId());
List<SysEquipmentDocs> resultList = sysEquipmentDocsMapper.selectList(queryWrapper);
SysGenExtPropsVo sysGenExtPropsVo = new SysGenExtPropsVo();
BeanCopyUtils.copy(sysEquipmentExtProps,sysGenExtPropsVo);
sysGenExtPropsVo.setSysEquipmentDocsList(resultList);
return sysGenExtPropsVo;
} }
@Override @Override
@ -426,7 +474,13 @@ public class SysEquipmentServiceImpl implements SysEquipmentService {
List<SysEquipmentDocs> sysEquipmentDocsList = sysEquipmentDocsMapper.selectList(queryWrapper); List<SysEquipmentDocs> sysEquipmentDocsList = sysEquipmentDocsMapper.selectList(queryWrapper);
if (CollectionUtils.isNotEmpty(sysEquipmentDocsList)){ if (CollectionUtils.isNotEmpty(sysEquipmentDocsList)){
for (SysEquipmentDocs item : sysEquipmentDocsList){ for (SysEquipmentDocs item : sysEquipmentDocsList){
deleteFile(item.getUrl()); try {
minioViewsServcie.removeFile(minioAutoProperties.getPublicBucket(),item.getUrl(),false);
}
catch (Exception e){
log.error("删除文件失败{}",e);
}
deleteFile(item);
sysEquipmentDocsMapper.deleteById(item.getId()); sysEquipmentDocsMapper.deleteById(item.getId());
} }
@ -434,27 +488,39 @@ public class SysEquipmentServiceImpl implements SysEquipmentService {
} }
@Override @Override
public SysGenExtProps querySysEquipmentExtProps(Long id) { public SysGenExtPropsVo querySysEquipmentExtProps(Long id) {
return sysGenExtPropsMapper.selectById(id); SysGenExtProps sysGenExtProps = sysGenExtPropsMapper.selectById(id);
QueryWrapper<SysEquipmentDocs> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deviceid",id);
List<SysEquipmentDocs> resultList = sysEquipmentDocsMapper.selectList(queryWrapper);
SysGenExtPropsVo sysGenExtPropsVo = new SysGenExtPropsVo();
BeanCopyUtils.copy(sysGenExtProps,sysGenExtPropsVo);
sysGenExtPropsVo.setSysEquipmentDocsList(resultList);
return sysGenExtPropsVo;
} }
@Override @Override
public List<SysEquipmentDocs> upload(Long deviceId, String component, String folderName, List<MultipartFile> fileList) throws Exception { public List<SysEquipmentDocs> upload(String folderName, List<MultipartFile> fileList){
List<SysEquipmentDocs> result = new ArrayList<>(); List<SysEquipmentDocs> result = new ArrayList<>();
for (MultipartFile file : fileList) { for (MultipartFile file : fileList) {
DeviceInfoCache deviceInfoCache = equipmentCache.getDeviceInfoCacheById(deviceId); Long picId = IdWorker.getId();
String parent = FileConstants.FILE_SEPARATOR + "WindTurbine" + FileConstants.FILE_SEPARATOR + deviceInfoCache.getDeviceCode() + FileConstants.FILE_SEPARATOR + "pic"; String originalFilename = file.getOriginalFilename();
if (StringUtils.isEmpty(originalFilename)){
throw new ServiceException("文件名不存在,请检查");
}
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
String fileName = picId+suffix;
String parent = FileConstants.FILE_SEPARATOR + "WindTurbine" + FileConstants.FILE_SEPARATOR + "pic" + FileConstants.FILE_SEPARATOR + fileName;
File scale = null; File scale = null;
try { try {
String url = minioViewsServcie.upload(minioAutoProperties.getPublicBucket(), parent, folderName, file); minioViewsServcie.uploadFile(minioAutoProperties.getPublicBucket(), file,parent,"application/octet-stream");
scale = scale(file); scale = scale(file);
String scaleFileName = scale.getName(); String scaleParent = FileConstants.FILE_SEPARATOR + "WindTurbine" + FileConstants.FILE_SEPARATOR + "thumbnailPic" + FileConstants.FILE_SEPARATOR + fileName;
String scaleName = scaleFileName.substring(scaleFileName.lastIndexOf("_") + 1);
String scaleParent = FileConstants.FILE_SEPARATOR + "WindTurbine" + FileConstants.FILE_SEPARATOR + deviceInfoCache.getDeviceCode() + FileConstants.FILE_SEPARATOR + "thumbnailPic" + FileConstants.FILE_SEPARATOR + scaleName;
minioViewsServcie.uploadTemFile(minioAutoProperties.getPublicBucket(), scale, scaleParent); minioViewsServcie.uploadTemFile(minioAutoProperties.getPublicBucket(), scale, scaleParent);
String fileName = url.substring(url.lastIndexOf("/") + 1); SysEquipmentDocs sysEquipmentDocs = new SysEquipmentDocs();
SysEquipmentDocs sysEquipmentDocs = saveDocs(deviceId, component, fileName, url); sysEquipmentDocs.setUrl(parent);
SysEquipmentDocs sysEquipmentDocsScale = saveDocs(deviceId, component, scaleName, scaleParent); SysEquipmentDocs sysEquipmentDocsScale = new SysEquipmentDocs();
sysEquipmentDocsScale.setUrl(scaleParent);
result.add(sysEquipmentDocs); result.add(sysEquipmentDocs);
result.add(sysEquipmentDocsScale); result.add(sysEquipmentDocsScale);
} catch (Exception e) { } catch (Exception e) {
@ -482,13 +548,10 @@ public class SysEquipmentServiceImpl implements SysEquipmentService {
minioViewsServcie.readFileToStream(path, stream); minioViewsServcie.readFileToStream(path, stream);
} }
@Override public void deleteFile(SysEquipmentDocs sysEquipmentDocs) {
public void deleteFile(String path) {
try { try {
minioViewsServcie.removeFile(minioAutoProperties.getPublicBucket(), path,false); sysEquipmentDocsMapper.deleteById(sysEquipmentDocs.getId());
//删除缩略图 minioViewsServcie.removeFile(minioAutoProperties.getPublicBucket(), sysEquipmentDocs.getUrl(),false);
String thumbnailPath = path.replace("pic", "thumbnailPic");
minioViewsServcie.removeFile(minioAutoProperties.getPublicBucket(), thumbnailPath,false);
}catch (Exception e){ }catch (Exception e){
log.error("文件删除失败"); log.error("文件删除失败");
} }
@ -510,20 +573,24 @@ public class SysEquipmentServiceImpl implements SysEquipmentService {
// 创建临时文件名称基于原始文件名 // 创建临时文件名称基于原始文件名
File tempFile = File.createTempFile("thumbnail_", "_" + originalFileName); File tempFile = File.createTempFile("thumbnail_", "_" + originalFileName);
InputStream inputStream = file.getInputStream(); InputStream inputStream = file.getInputStream();
File mulFile = null;
try { try {
File mulFile = new File(System.getProperty("java.io.tmpdir") + "/" + file.getOriginalFilename()); mulFile = new File(System.getProperty("java.io.tmpdir") + "/" + file.getOriginalFilename());
// 将MultipartFile写入临时文件 // 将MultipartFile写入临时文件
file.transferTo(mulFile); file.transferTo(mulFile);
// 生成缩略图 // 生成缩略图
ImgUtil.scale(mulFile, tempFile, 700, 700, null); ImgUtil.scale(mulFile, tempFile, 700, 700, null);
} finally { } finally {
IoUtil.close(inputStream); IoUtil.close(inputStream);
if (mulFile != null && mulFile.exists()){
mulFile.delete();
}
} }
return tempFile; return tempFile;
} }
public SysEquipmentDocs saveDocs(Long deviceId, String component,String fileName,String url){ public SysEquipmentDocs deleteDocs(Long deviceId, String component,String fileName,String url){
SysEquipmentDocs sysEquipmentDocs = new SysEquipmentDocs(); SysEquipmentDocs sysEquipmentDocs = new SysEquipmentDocs();
sysEquipmentDocs.setDeviceId(deviceId); sysEquipmentDocs.setDeviceId(deviceId);
sysEquipmentDocs.setName(fileName); sysEquipmentDocs.setName(fileName);

View File

@ -200,7 +200,7 @@ public class MinioViewsServcie {
public void readFileToStream(String path, OutputStream stream) { public void readFileToStream(String path, OutputStream stream) {
try (GetObjectResponse res = minioClient.getObject( try (GetObjectResponse res = minioClient.getObject(
GetObjectArgs.builder().bucket(minioProperties.getBucket()).object(path).build())) { GetObjectArgs.builder().bucket(minioProperties.getPublicBucket()).object(path).build())) {
res.transferTo(stream); res.transferTo(stream);
} catch (Exception e) { } catch (Exception e) {
log.error("minio读取文件失败", e); log.error("minio读取文件失败", e);

View File

@ -26,7 +26,7 @@ public class StatisticalAnalysisController {
/** /**
* 趋势分析Excel导出 * 趋势分析 (单机分析)Excel导出
* @param param 查询条件 * @param param 查询条件
*/ */
@PostMapping("/trendAnalyseExport") @PostMapping("/trendAnalyseExport")
@ -45,7 +45,7 @@ public class StatisticalAnalysisController {
/** /**
* 趋势对比Excel导出 * 趋势对比(多机对比) Excel导出
* @param param 查询条件 * @param param 查询条件
*/ */
@PostMapping("/trendContrastExport") @PostMapping("/trendContrastExport")

View File

@ -38,6 +38,7 @@ public class TrendAnalyseDto
private String timeName; private String timeName;
/** /**
* 设备属性列表 * 设备属性列表
*/ */
@ -52,4 +53,11 @@ public class TrendAnalyseDto
* 模型 * 模型
*/ */
private String model; private String model;
private String calFunction;
private String windSource;
//是否显示曲线,0不显示,1显示
private int displayCurve;
} }

View File

@ -33,11 +33,12 @@ public class TrendContrastDto
/** /**
* 设备属性列表 * 设备属性列表
*/ */
private List<SnapshotValueQueryParam> devices; private List<SnapshotValueQueryParam> devices;
private String calFunction;
} }

View File

@ -4,15 +4,16 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.hutool.poi.excel.ExcelUtil; import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter; import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.das.common.constant.StatisticalAnalysisConstant; import com.das.common.constant.StatisticalAnalysisConstant;
import com.das.common.constant.StatisticalAnalysisFunctionConstant;
import com.das.common.exceptions.ServiceException; import com.das.common.exceptions.ServiceException;
import com.das.common.utils.BeanCopyUtils; import com.das.common.utils.BeanCopyUtils;
import com.das.modules.curve.domain.entity.CurveItemEntity; import com.das.modules.curve.domain.entity.CurveItemEntity;
import com.das.modules.curve.service.TheoreticalPowerCurveService; import com.das.modules.curve.service.TheoreticalPowerCurveService;
import com.das.modules.data.domain.SnapshotValueQueryParam; import com.das.modules.data.domain.SnapshotValueQueryParam;
import com.das.modules.data.domain.TSValueQueryParam; 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.data.service.DataService;
import com.das.modules.equipment.entity.SysIotModelField; import com.das.modules.equipment.entity.SysIotModelField;
import com.das.modules.equipment.mapper.SysIotModelFieldMapper; import com.das.modules.equipment.mapper.SysIotModelFieldMapper;
@ -22,6 +23,7 @@ import com.das.modules.page.service.StatisticalAnalysisService;
import jakarta.servlet.ServletOutputStream; import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.ClientAnchor; import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.HorizontalAlignment;
@ -33,6 +35,7 @@ import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing; import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.jetbrains.annotations.NotNull;
import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils; import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart; import org.jfree.chart.JFreeChart;
@ -56,7 +59,9 @@ import java.text.SimpleDateFormat;
import java.util.List; import java.util.List;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream;
@Slf4j
@Service @Service
public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisService { public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisService {
@ -81,10 +86,19 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
//根据条件获取历史数据 //根据条件获取历史数据
List<Map<String, Map<String, Map<String, Object>>>> mapsList = new ArrayList<>(); List<Map<String, Map<String, Map<String, Object>>>> mapsList = new ArrayList<>();
for (TrendAnalyseDto trendAnalyseDto : param) { for (TrendAnalyseDto trendAnalyseDto : param) {
TSValueQueryParam tsValueQueryParam = new TSValueQueryParam(); //瞬时值
BeanCopyUtils.copy(trendAnalyseDto,tsValueQueryParam); if (trendAnalyseDto.getCalFunction().equals(StatisticalAnalysisFunctionConstant.INTERPOLATION)){
Map<String, Map<String, Map<String, Object>>> resultMap = dataService.queryTimeSeriesValues(tsValueQueryParam); TSValueQueryParam tsValueQueryParam = new TSValueQueryParam();
mapsList.add(resultMap); 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的列 //获取Excel的列
LinkedHashMap<String, String> map = getTrendColumnName(param); LinkedHashMap<String, String> map = getTrendColumnName(param);
@ -119,23 +133,43 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
TSValueQueryParam tsValueQueryParam = new TSValueQueryParam(); TSValueQueryParam tsValueQueryParam = new TSValueQueryParam();
BeanCopyUtils.copy(param,tsValueQueryParam); BeanCopyUtils.copy(param,tsValueQueryParam);
Map<String, Map<String, Map<String, Object>>> resultMap = dataService.queryTimeSeriesValues(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<>(); List<Map<String, Object>> dataList = new ArrayList<>();
//填充功率曲线,Excel的数据集 //填充功率曲线,Excel的数据集
setPowerCurveExcelValue(resultMap, dataList, curveItemEntitieList); setPowerCurveExcelValue(resultMap, dataList, curveItemEntitieList);
//获取功率曲线的列 //获取功率曲线的列
LinkedHashMap<String, String> map = getPowerCurveColumnName(); LinkedHashMap<String, String> map = getPowerCurveColumnName(param);
//获取图表类别集 //获取图表类别集
List<String> chartKey = getCharKey(map); List<String> chartKey = getCharKey(map);
ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx"); ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx");
//设置Excel样式 //设置Excel样式
setExcelStyle(writer, map, dataList); setExcelStyle(writer, map, dataList);
//生成折线图 //生成折线图
addChartToExcel(writer,dataList,StatisticalAnalysisConstant.POWER_CURVE,chartKey); if (param.getDisplayCurve()==1){
addChartToExcel(writer,dataList,StatisticalAnalysisConstant.POWER_CURVE,chartKey);
}else {
//生成散点图
addScattersChartToExcel(writer,dataList,StatisticalAnalysisConstant.POWER_CURVE,chartKey);
}
//下载Excel //下载Excel
downloadExcel(response, writer,StatisticalAnalysisConstant.POWER_CURVE); downloadExcel(response, writer,StatisticalAnalysisConstant.POWER_CURVE);
} }
/** /**
* 趋势对比Excel导出 * 趋势对比Excel导出
* @param param 查询条件 * @param param 查询条件
@ -143,10 +177,17 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
*/ */
@Override @Override
public void trendContrastExport(TrendContrastDto param, HttpServletRequest request, HttpServletResponse response) { public void trendContrastExport(TrendContrastDto param, HttpServletRequest request, HttpServletResponse response) {
//根据条件获取历史数据 Map<String, Map<String, Map<String, Object>>> maps = null;
TSValueQueryParam tsValueQueryParam = new TSValueQueryParam(); //瞬时值,历史区间数据查询
BeanCopyUtils.copy(param,tsValueQueryParam); if (param.getCalFunction().equals(StatisticalAnalysisFunctionConstant.INTERPOLATION)){
Map<String, Map<String, Map<String, Object>>> maps = dataService.queryTimeSeriesValues(tsValueQueryParam); 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和实体类中的名称要对应上 //自定义别名 别名的key和实体类中的名称要对应上
LinkedHashMap<String, String> map = gettrendContrastColumnName(param); LinkedHashMap<String, String> map = gettrendContrastColumnName(param);
List<Map<String, Object>> dataList = new ArrayList<>(); List<Map<String, Object>> dataList = new ArrayList<>();
@ -374,11 +415,15 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
* 获取功率曲线的列 * 获取功率曲线的列
* @return Excel的列 * @return Excel的列
*/ */
private LinkedHashMap<String, String> getPowerCurveColumnName() { private LinkedHashMap<String, String> getPowerCurveColumnName(TrendAnalyseDto param) {
LinkedHashMap<String, String> map = new LinkedHashMap<>(); LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("time", "时间"); map.put("time", "时间");
map.put("iWindSpeed", "风速"); if (param.getWindSource().equals("原始风速")){
map.put("iGenPower", "功率"); map.put("AvgWindSpeed_10min", "原始风速");
}else {
map.put("AvgWindSpeedCal_10min", "处理后风速");
}
map.put("AvgActivePower_10min", "功率");
map.put("theoryIWindSpeed", "理论风速"); map.put("theoryIWindSpeed", "理论风速");
map.put("theoryIGenPower", "理论功率"); map.put("theoryIGenPower", "理论功率");
return map; return map;
@ -607,6 +652,74 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
} }
} }
/**
* 生成散点图,并插入到 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 data 测点数据
@ -661,5 +774,138 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic
CellRangeAddress ref = new CellRangeAddress(startRow, endRow, startCol, endCol); CellRangeAddress ref = new CellRangeAddress(startRow, endRow, startCol, endCol);
return XDDFDataSourcesFactory.fromNumericCellRange(sheet, ref); 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);
}
}
}
}
}
}
} }

View File

@ -39,7 +39,7 @@ export const runAirBlowerReq = (
}) })
} }
export const getReportTemplateListReq = (data: { category: '单机报表' | '多机报表'; pageNum: number; pageSize: number }) => { export const getReportTemplateListReq = (data: { category: '单机报表' | '多机报表' | '统计查询'; pageNum: number; pageSize: number }) => {
return createAxios< return createAxios<
never, never,
Promise<{ Promise<{
@ -47,7 +47,7 @@ export const getReportTemplateListReq = (data: { category: '单机报表' | '多
msg: string msg: string
data: { data: {
total: number total: number
rows: { id: string; category: '单机报表' | '多机报表'; template: string }[] rows: { id: string; category: '单机报表' | '多机报表' | '统计查询'; template: string }[]
code: number code: number
msg: string msg: string
} }
@ -60,7 +60,7 @@ export const getReportTemplateListReq = (data: { category: '单机报表' | '多
}) })
} }
export const addReportTemplateListReq = (data: { category: '单机报表' | '多机报表'; template: string }) => { export const addReportTemplateListReq = (data: { category: '单机报表' | '多机报表' | '统计查询'; template: string }) => {
return createAxios< return createAxios<
never, never,
Promise<{ Promise<{

View File

@ -94,13 +94,16 @@
@change="getcurrentPage" @change="getcurrentPage"
></el-pagination> ></el-pagination>
</div> </div>
<el-dialog v-model="malFunctionVisible" title="故障录波" width="1000" :destroy-on-close="true">
<MalFunction v-model:visible="malFunctionVisible" :alarms="alarms" class="malDialog"></MalFunction>
</el-dialog>
</el-main> </el-main>
</el-container> </el-container>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, onMounted, computed } from 'vue' import { reactive, ref, onMounted, computed, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { Search } from '@element-plus/icons-vue' import { Search } from '@element-plus/icons-vue'
import { AlarmsFieldsEnums, AlarmsTableType, GetAlarmsTableParam } from './type' import { AlarmsFieldsEnums, AlarmsTableType, GetAlarmsTableParam } from './type'
@ -108,14 +111,16 @@ import { getAlarmListReq, eventComfirm } from '/@/api/backend/alarms/request'
import { queryfaultCodeDict, theoreticalpowerCurveList } from '/@/api/backend/theoreticalpowerCurve/request' import { queryfaultCodeDict, theoreticalpowerCurveList } from '/@/api/backend/theoreticalpowerCurve/request'
import { equipList } from '/@/api/backend/realData/request' import { equipList } from '/@/api/backend/realData/request'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useRouter, useRoute } from 'vue-router' import MalFunction from '/@/views/backend/malfunction/index.vue'
const router = useRouter()
const { t } = useI18n() const { t } = useI18n()
import { useAdminInfo } from '/@/stores/adminInfo' import { useAdminInfo } from '/@/stores/adminInfo'
const adminInfo = useAdminInfo() const adminInfo = useAdminInfo()
const malFunctionVisible = ref(false)
// //
const alarms = ref({
eventTime: '',
deviceId: '',
})
const timeRange = ref([new Date().setHours(0, 0, 0, 0), new Date()]) const timeRange = ref([new Date().setHours(0, 0, 0, 0), new Date()])
const shortcuts = [ const shortcuts = [
@ -395,13 +400,9 @@ const getfaultCodeDict = async (data: any) => {
} }
const openDefalt = (row: any) => { const openDefalt = (row: any) => {
router.push({ const { eventTime, deviceId } = row
name: 'faultRecord', alarms.value = { eventTime, deviceId }
query: { malFunctionVisible.value = true
eventTime: row.eventTime,
deviceId: row.deviceId,
},
})
} }
</script> </script>
@ -511,6 +512,9 @@ $paginationHeight: 32px;
justify-content: right; justify-content: right;
background-color: #fff; background-color: #fff;
} }
.malDialog {
height: 540px;
}
} }
} }
.modelOperate { .modelOperate {

View File

@ -8,7 +8,7 @@
<div class="homeHeader"> <div class="homeHeader">
<div class="cardLabel">风机矩阵</div> <div class="cardLabel">风机矩阵</div>
<div class="cardBtn"> <div class="cardBtn">
<el-radio-group v-model="overviewSlotData"> <el-radio-group v-model="overviewSlotData" @change="changeUpdate">
<el-radio value="">全部</el-radio> <el-radio value="">全部</el-radio>
<el-radio value="一期">一期</el-radio> <el-radio value="一期">一期</el-radio>
<el-radio value="二期">二期</el-radio> <el-radio value="二期">二期</el-radio>
@ -363,6 +363,9 @@ const StatusListData = () => {
} }
}) })
} }
const changeUpdate=()=>{
StatusListData()
}
let autoUpdateForSecondTimer: any = null let autoUpdateForSecondTimer: any = null

View File

@ -68,12 +68,13 @@
</el-row> </el-row>
</div> </div>
<div class="fanlist-bottom"> <div class="fanlist-bottom">
<span :style="item.attributeMap.locked == 1 ? 'max-width:120px;' : 'max-width:150px;'"> <el-tooltip
v-if="item.attributeMap.firsttriggeredcode"
:content="item.attributeMap.firsttriggeredcode">
<span :style="item.attributeMap.locked == 1 ? 'max-width:120px;' : 'max-width:150px;'">
{{ item.attributeMap.firsttriggeredcode }} {{ item.attributeMap.firsttriggeredcode }}
</span> </span>
<!-- <span :style="item.attributeMap.locked == 1 ? 'max-width:120px;' : 'max-width:150px;'"> </el-tooltip>
{{ getFaultDescription(item) }}
</span>-->
<!-- <el-tag class="tag-panel is-danger">已锁定</el-tag>--> <!-- <el-tag class="tag-panel is-danger">已锁定</el-tag>-->
<el-tag v-if="item.attributeMap.locked === 1" class="tag-panel is-danger">已锁定</el-tag> <el-tag v-if="item.attributeMap.locked === 1" class="tag-panel is-danger">已锁定</el-tag>
</div> </div>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="malfunction"> <div class="malfunction">
<el-container class="container"> <el-container class="container">
<el-aside class="aside"> <el-aside class="aside" v-show="!props.visible">
<div class="searchTree"> <div class="searchTree">
<el-input v-model="searchTreeValue" clearable placeholder="搜索" :suffix-icon="Search" @change="searchTree"> </el-input> <el-input v-model="searchTreeValue" clearable placeholder="搜索" :suffix-icon="Search" @change="searchTree"> </el-input>
</div> </div>
@ -179,6 +179,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineProps, PropType } from 'vue'
import { ref, reactive, computed, onMounted, nextTick, onUnmounted } from 'vue' import { ref, reactive, computed, onMounted, nextTick, onUnmounted } from 'vue'
import { dayjs, ElMessage, FormInstance, TreeInstance } from 'element-plus' import { dayjs, ElMessage, FormInstance, TreeInstance } from 'element-plus'
import { Search, Setting } from '@element-plus/icons-vue' import { Search, Setting } from '@element-plus/icons-vue'
@ -194,15 +195,26 @@ import { equipList } from '/@/api/backend/temperature/request'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { tableItemData } from './type' import { tableItemData } from './type'
import ContextMenu from '/@/views/backend/auth/model/contextMenu.vue' import ContextMenu from '/@/views/backend/auth/model/contextMenu.vue'
import { useRouter, useRoute } from 'vue-router'
const route = useRoute()
const defaultProps = { const defaultProps = {
children: 'children', children: 'children',
label: 'label', label: 'label',
} }
const props = defineProps({
alarms: {
type: Object as PropType<{ eventTime: string; deviceId: string }>,
default: () => ({
eventTime: undefined,
deviceId: undefined,
}),
},
visible: {
type: Boolean,
default: false,
},
})
const contextMenuInfo = reactive({ const contextMenuInfo = reactive({
visible: false, visible: false,
pos: { pos: {
@ -313,8 +325,8 @@ const getTreeDataList = () => {
}) })
}) })
} }
const initDatestart = route.query.eventTime ? dayjs(Number(route.query.eventTime)) : dayjs().startOf('month') const initDatestart = props.alarms.eventTime ? dayjs(Number(props.alarms.eventTime)) : dayjs().startOf('month')
const initDateend = route.query.eventTime ? dayjs(Number(route.query.eventTime)) : dayjs() const initDateend = props.alarms.eventTime ? dayjs(Number(props.alarms.eventTime)) : dayjs()
const searchData = reactive<{ fileName: ''; date: Date[] }>({ const searchData = reactive<{ fileName: ''; date: Date[] }>({
fileName: '', fileName: '',
@ -907,7 +919,7 @@ const checkTab = () => {
onMounted(() => { onMounted(() => {
getTreeDataList().then((data: any) => { getTreeDataList().then((data: any) => {
const queryId = route.query.deviceId ?? data.id const queryId = props.alarms.deviceId ?? data.id
treeRef.value && treeRef.value.setCurrentKey(queryId, true) treeRef.value && treeRef.value.setCurrentKey(queryId, true)
curTreeData.value = treeRef.value?.getCurrentNode() curTreeData.value = treeRef.value?.getCurrentNode()
getListForAirBlower() getListForAirBlower()

View File

@ -393,6 +393,7 @@ const statAnalysisOperate = () => {
const statAnalysisExport = () => { const statAnalysisExport = () => {
const params = statAnalysisFatory.value ? statAnalysisFatory.value : statAnalysisDeviceId.value const params = statAnalysisFatory.value ? statAnalysisFatory.value : statAnalysisDeviceId.value
const windSource = statAnalysisSelectOptions.speedSource.filter((item: any) => item.value == statAnalysisSpeedSource.value)
const requestData = { const requestData = {
devices: [ devices: [
{ {
@ -404,6 +405,8 @@ const statAnalysisExport = () => {
endTime: new Date(statAnalysisTime.value[1]).getTime(), endTime: new Date(statAnalysisTime.value[1]).getTime(),
madeinfactory: params.split(':')[0], madeinfactory: params.split(':')[0],
model: params.split(':')[1], model: params.split(':')[1],
windSource: windSource[0]['label'],
displayCurve: AvgWindSpeedSwitch ? 0 : 1,
} }
powerCurveExport(requestData).then((res: any) => { powerCurveExport(requestData).then((res: any) => {
const downloadUrl = window.URL.createObjectURL(res) const downloadUrl = window.URL.createObjectURL(res)

View File

@ -588,6 +588,7 @@ const statAnalysisExport = () => {
startTime: new Date(time[0]).getTime(), startTime: new Date(time[0]).getTime(),
endTime: new Date(time[1]).getTime(), endTime: new Date(time[1]).getTime(),
timeName: customName[index], timeName: customName[index],
calFunction: statAnalysisSelect.calFunction,
} }
requestData.push(devices) requestData.push(devices)
} }

View File

@ -1,51 +1,75 @@
<template> <template>
<div class="contain"> <div class="contain">
<el-header class="headerPart"> <el-header>
<div class="topLeft"> <div class="headerPart">
<div class="selectPart"> <div class="topLeft">
<span>{{ t('statAnalysis.time') }}</span> <div class="selectPart">
<el-date-picker <span>{{ t('statAnalysis.time') }}</span>
class="statAnalysisSelect" <el-date-picker
v-model="statAnalysisTime" class="statAnalysisSelect"
:type="statAnalysisInterval == '1d' ? 'daterange' : 'datetimerange'" v-model="statAnalysisTime"
:value-format="statAnalysisInterval == '1d' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'" :type="statAnalysisInterval == '1d' ? 'daterange' : 'datetimerange'"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]" :value-format="statAnalysisInterval == '1d' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
:teleported="false" :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]"
:shortcuts="shortcuts" :teleported="false"
/> :shortcuts="shortcuts"
/>
</div>
<div class="selectPart">
<span>{{ t('statAnalysis.interval') }}</span>
<el-select v-model="statAnalysisInterval" :placeholder="'请选择' + t('statAnalysis.interval')" class="statAnalysisSelect">
<el-option v-for="v in statAnalysisSelectOptions.interval" :key="v.value" :label="v.label" :value="v.value"></el-option>
</el-select>
</div>
<div class="selectPart">
<span>{{ t('statAnalysis.calFunction') }}</span>
<el-select
:disabled="statAnalysisInterval == 'NONE'"
v-model="statAnalysisSelectcalFunction"
:placeholder="'请选择' + t('statAnalysis.calFunction')"
class="statAnalysisSelect"
>
<el-option
v-for="v in statAnalysisSelectOptions.calFunction"
:key="v.value"
:label="v.label"
:value="v.value"
></el-option>
</el-select>
</div>
<el-button type="primary" :icon="Crop" class="addline" @click="openMeasure">测点选择</el-button>
</div> </div>
<div class="selectPart"> <div class="topRight">
<span>{{ t('statAnalysis.interval') }}</span> <el-button type="primary" :loading="isLoading" @click="statAnalysisOperate()">{{ t('statAnalysis.search') }}</el-button>
<el-select v-model="statAnalysisInterval" :placeholder="'请选择' + t('statAnalysis.interval')" class="statAnalysisSelect"> <el-button style="color: #0064aa" @click="statAnalysisExport()">{{ t('statAnalysis.export') }}</el-button>
<el-option v-for="v in statAnalysisSelectOptions.interval" :key="v.value" :label="v.label" :value="v.value"></el-option> <el-button class="button" :icon="Notebook" type="primary" @click="addReportTemplate" plain>保存为模板</el-button>
</el-select>
</div> </div>
<div class="selectPart">
<span>{{ t('statAnalysis.calFunction') }}</span>
<el-select
:disabled="statAnalysisInterval == 'NONE'"
v-model="statAnalysisSelectcalFunction"
:placeholder="'请选择' + t('statAnalysis.calFunction')"
class="statAnalysisSelect"
>
<el-option v-for="v in statAnalysisSelectOptions.calFunction" :key="v.value" :label="v.label" :value="v.value"></el-option>
</el-select>
</div>
<el-button type="primary" :icon="Crop" class="addline" @click="openMeasure">测点选择</el-button>
</div> </div>
<div class="topRight"> <div>
<el-button type="primary" :loading="isLoading" @click="statAnalysisOperate()">{{ t('statAnalysis.search') }}</el-button> <el-space style="margin: 10px 20px">
<el-button style="color: #0064aa" @click="statAnalysisExport()">{{ t('statAnalysis.export') }}</el-button> <div style="min-width: 30px">模板</div>
<el-select v-model="template" placeholder="请选择模板" class="templateSelect" @change="changeTemplate" clearable>
<el-option v-for="v in reportTemplateList" :key="v.id" :label="v.name" :value="v.id">
<template #default>
<div class="tamplateOption">
<span>{{ v.name }}</span>
<el-icon style="color: red" @click="delReportTemplate(v.id)">
<Delete />
</el-icon>
</div>
</template>
</el-option>
</el-select>
</el-space>
</div> </div>
</el-header> </el-header>
<div class="main"> <div class="main">
<div <div
ref="chartContainer" ref="chartContainer"
style="height: calc(100% - 140px); width: calc(100% - 60px); border: 1px solid rgb(217, 217, 217); margin: 40px" style="height: calc(100% - 140px); width: calc(100% - 60px); border: 1px solid rgb(217, 217, 217); margin: 80px 40px"
></div> ></div>
</div> </div>
<el-dialog v-model="showMeasure" title="选择测点" width="1200" top="0" :destroy-on-close="true">
<el-dialog v-model="showMeasure" title="选择测点" width="1200" top="0">
<div class="measureSlot"> <div class="measureSlot">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
@ -66,6 +90,7 @@
<el-table-column prop="name" label="风机名称" /> <el-table-column prop="name" label="风机名称" />
</el-table> </el-table>
<el-table <el-table
ref="tableDataMidRef"
:data="tableDataMid" :data="tableDataMid"
v-model:selection="selectedMid" v-model:selection="selectedMid"
@selection-change="handleSelectionChange2" @selection-change="handleSelectionChange2"
@ -76,6 +101,7 @@
<el-table-column prop="name" label="风机名称" /> <el-table-column prop="name" label="风机名称" />
</el-table> </el-table>
<el-table <el-table
ref="tableDataRightRef"
:data="tableDataRight" :data="tableDataRight"
v-model:selection="selectedRight" v-model:selection="selectedRight"
@selection-change="handleSelectionChange1" @selection-change="handleSelectionChange1"
@ -140,13 +166,20 @@
<script setup lang="ts"> <script setup lang="ts">
import { markRaw, reactive, ref, watch, nextTick, onMounted, computed } from 'vue' import { markRaw, reactive, ref, watch, nextTick, onMounted, computed } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { queryWindTurbinesPages, historyReq, trendContrastExport, windowReq } from '/@/api/backend/statAnalysis/request' import {
import { ElMessage, ElMenu } from 'element-plus' queryWindTurbinesPages,
import { DArrowRight, Plus, Crop, Close } from '@element-plus/icons-vue' historyReq,
trendContrastExport,
windowReq,
getReportTemplateListReq,
addReportTemplateListReq,
delReportTemplateListReq,
} from '/@/api/backend/statAnalysis/request'
import { ElMessage, ElMenu, ElMessageBox, backtopEmits } from 'element-plus'
import { DArrowRight, Plus, Crop, Notebook, Delete } from '@element-plus/icons-vue'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { getModelAttributeListReq } from '/@/api/backend/deviceModel/request' import { getModelAttributeListReq } from '/@/api/backend/deviceModel/request'
import { getCutDecimalsValue } from '/@/views/backend/equipment/airBlower/utils' import { getCutDecimalsValue } from '/@/views/backend/equipment/airBlower/utils'
const { t } = useI18n() const { t } = useI18n()
const statAnalysisInterval = ref('1h') const statAnalysisInterval = ref('1h')
@ -236,6 +269,8 @@ onMounted(() => {
statAnalysisOperate() statAnalysisOperate()
}) })
}) })
getReportTemplateList()
}) })
const tableDataLeft = ref([]) const tableDataLeft = ref([])
const tableDataRight = ref([]) const tableDataRight = ref([])
@ -414,6 +449,8 @@ const getDateRange = (type: 'week' | 'month') => {
} }
const tableDataLeftRef = ref() const tableDataLeftRef = ref()
const tableDataMidRef = ref()
const tableDataRightRef = ref()
const openMeasure = () => { const openMeasure = () => {
showMeasure.value = true showMeasure.value = true
pageSetting.current = 1 pageSetting.current = 1
@ -421,6 +458,12 @@ const openMeasure = () => {
selectedLeft.value.forEach((item) => { selectedLeft.value.forEach((item) => {
tableDataLeftRef.value?.toggleRowSelection(item, true) tableDataLeftRef.value?.toggleRowSelection(item, true)
}) })
selectedMid.value.forEach((item) => {
tableDataMidRef.value?.toggleRowSelection(item, true)
})
selectedRight.value.forEach((item) => {
tableDataRightRef.value?.toggleRowSelection(item, true)
})
initSelect() initSelect()
}) })
} }
@ -587,6 +630,96 @@ const timestampToTime = (timestamp: any) => {
let m = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() let m = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
return Y + M + D + h + m return Y + M + D + h + m
} }
const addReportTemplate = () => {
ElMessageBox.prompt('请输入模板名称', '添加模板', {
confirmButtonText: '提交',
cancelButtonText: '取消',
inputPattern: /\S/,
inputErrorMessage: '模板名称不能为空',
}).then(({ value }) => {
const tem = {
name: value,
interval: statAnalysisInterval.value,
calFunction: statAnalysisSelectcalFunction.value,
multipleSelection: multipleSelection.value,
selectedLeft: selectedLeft.value,
selectedMid: selectedMid.value,
selectedRight: selectedRight.value,
}
const data = {
category: '统计查询' as const,
template: JSON.stringify(tem),
}
addReportTemplateListReq(data).then((res) => {
if (res.success) {
ElMessage.success('添加成功!')
getReportTemplateList()
}
})
})
}
const template = ref('')
const reportTemplateList = ref([
{
name: '',
id: '',
interval: '',
calFunction: '',
},
])
const getReportTemplateList = () => {
getReportTemplateListReq({
pageNum: 1,
pageSize: 1000,
category: '统计查询',
}).then((res) => {
if (res.success) {
reportTemplateList.value = res.data.rows.map((item) => {
const tem = item.template ? JSON.parse(item.template) : {}
return {
name: tem.name,
id: item.id,
interval: tem.interval,
calFunction: tem.calFunction,
multipleSelection: tem.multipleSelection,
selectedLeft: tem.selectedLeft,
selectedMid: tem.selectedMid,
selectedRight: tem.selectedRight,
}
})
}
})
}
const delReportTemplate = (id: string) => {
ElMessageBox.confirm('确定删除该模板吗?', '删除模板', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
delReportTemplateListReq({ id }).then((res) => {
if (res.success) {
ElMessage.success('删除成功!')
getReportTemplateList()
template.value = ''
}
})
})
}
const changeTemplate = (val: string) => {
const target: any = reportTemplateList.value.find((item) => item.id === val)
if (target) {
multipleSelection.value = target.multipleSelection
statAnalysisInterval.value = target.interval
statAnalysisSelectcalFunction.value = target.calFunction
selectedLeft.value = tableDataLeft.value.filter((item: any) => target.selectedLeft.some((selected: any) => selected.irn === item.irn))
selectedMid.value = tableDataMid.value.filter((item: any) => target.selectedMid.some((selected: any) => selected.irn === item.irn))
selectedRight.value = tableDataRight.value.filter((item: any) => target.selectedRight.some((selected: any) => selected.irn === item.irn))
}
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.statAnalysis { .statAnalysis {
@ -633,6 +766,9 @@ const timestampToTime = (timestamp: any) => {
} }
} }
} }
.templateSelect {
width: 200px;
}
.selectPart { .selectPart {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -746,4 +882,9 @@ const timestampToTime = (timestamp: any) => {
} }
} }
} }
.tamplateOption {
display: flex;
align-items: center;
justify-content: space-between;
}
</style> </style>