Просмотр исходного кода

1.新增oss处理
2.新增边坡项目-报表管理查询接口
3.修改报表阈值管理查询(数据库设计修改)

lengfaqiang 2 лет назад
Родитель
Сommit
6bd70d1095
37 измененных файлов с 2999 добавлено и 106 удалено
  1. 1 0
      slope-common/pom.xml
  2. 10 0
      slope-common/slope-common-core/pom.xml
  3. 3 0
      slope-common/slope-common-core/src/main/java/com/sckw/core/model/enums/DictEnum.java
  4. 31 0
      slope-common/slope-common-core/src/main/java/com/sckw/core/model/vo/PublicBaseIdsList.java
  5. 34 0
      slope-common/slope-common-core/src/main/java/com/sckw/core/model/vo/PublicBaseList.java
  6. 1540 0
      slope-common/slope-common-core/src/main/java/com/sckw/core/utils/FileUtils.java
  7. 54 0
      slope-common/slope-common-core/src/main/java/com/sckw/core/utils/StringUtils.java
  8. 2 1
      slope-common/slope-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  9. 12 0
      slope-common/slope-common-excel/pom.xml
  10. 38 0
      slope-common/slope-common-excel/src/main/java/com/sckw/excel/config/easyexcel/ExcelStyleHandler.java
  11. 266 2
      slope-common/slope-common-excel/src/main/java/com/sckw/excel/utils/ExcelUtil.java
  12. 42 0
      slope-common/slope-common-oss/pom.xml
  13. 25 0
      slope-common/slope-common-oss/src/main/java/com/sckw/oss/config/FileListConfig.java
  14. 34 0
      slope-common/slope-common-oss/src/main/java/com/sckw/oss/config/FileOssConfig.java
  15. 43 2
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/controller/AlarmController.java
  16. 1 1
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/controller/LogController.java
  17. 20 0
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/dao/mysql/KwsAlarmDetailMapper.java
  18. 1 0
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/dao/tdengine/SlopeDataMapper.java
  19. 11 35
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/dos/mysql/KwsAlarm.java
  20. 93 0
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/dos/mysql/KwsAlarmDetail.java
  21. 25 0
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/param/AlarmLogThresholdQuery.java
  22. 1 2
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/param/StatementQuery.java
  23. 1 1
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/vo/AlarmLogThresholdVO.java
  24. 33 19
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/vo/KwsAlarmVO.java
  25. 39 0
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/vo/ThresholdDeviceLogVO.java
  26. 47 0
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/vo/ThresholdRecordDetailVO.java
  27. 122 0
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/vo/excel/KwsAlarmExportVO.java
  28. 147 26
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/KwsAlarmService.java
  29. 13 5
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/LogService.java
  30. 10 1
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/ProjectService.java
  31. 1 0
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/ReportService.java
  32. 10 0
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/ReportTemplateService.java
  33. 60 0
      slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/task/ReportTemplateTaskService.java
  34. 8 1
      slope-modules/slope-detection/src/main/resources/bootstrap-lfdc.yml
  35. 209 0
      slope-modules/slope-detection/src/main/resources/mapper/mysql/KwsAlarmDetailMapper.xml
  36. 3 9
      slope-modules/slope-detection/src/main/resources/mapper/mysql/KwsAlarmMapper.xml
  37. 9 1
      slope-modules/slope-detection/src/main/resources/mapper/tdengine/SlopeDataMapper.xml

+ 1 - 0
slope-common/pom.xml

@@ -23,6 +23,7 @@
         <module>slope-common-datasource</module>
         <module>slope-common-startup</module>
         <module>slope-common-log</module>
+        <module>slope-common-oss</module>
     </modules>
 
     <properties>

+ 10 - 0
slope-common/slope-common-core/pom.xml

@@ -16,6 +16,7 @@
     <properties>
         <maven.compiler.source>17</maven.compiler.source>
         <maven.compiler.target>17</maven.compiler.target>
+        <oss.version>2.2.0.RELEASE</oss.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
 
@@ -41,6 +42,15 @@
             </exclusions>
         </dependency>
 
+
+        <!--alibaba oss-->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
+            <version>${oss.version}</version>
+        </dependency>
+
+
         <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>

+ 3 - 0
slope-common/slope-common-core/src/main/java/com/sckw/core/model/enums/DictEnum.java

@@ -11,6 +11,9 @@ public enum DictEnum {
     THRESHOLD_TYPE("threshold_type", "预警字段类型"),
     DEVICE_TYPE("device_type", "设备类型"),
     MODEL_PART("model_part", "检测要素"),
+    THRESHOLD_LEVEL("threshold_level", "告警等级"),
+    ALARM_TYPE("alarm_type", "告警类型"),
+    ALARM_DETAIL_TYPE("alarm_detail_type", "告警明细类型"),
     ;
     private final String codeType;
     private final String name;

+ 31 - 0
slope-common/slope-common-core/src/main/java/com/sckw/core/model/vo/PublicBaseIdsList.java

@@ -0,0 +1,31 @@
+package com.sckw.core.model.vo;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+/**
+ * @author lfdc
+ * @description
+ * @date 2023-08-15 19:08:14
+ */
+@Data
+public class PublicBaseIdsList {
+    /**
+     * 数据id 逗号隔开
+     */
+    @NotBlank(message = "数据id不能为空")
+    private String ids;
+
+    @NotNull(message = "当前页不能为空")
+    private Integer page;
+    @NotNull(message = "没页条数不能为空")
+    private Integer pageSize;
+
+    /**
+     * 备注
+     */
+    @Length(max = 200, message = "备注长度错误最大长度:{max}")
+    private String remark;
+}

+ 34 - 0
slope-common/slope-common-core/src/main/java/com/sckw/core/model/vo/PublicBaseList.java

@@ -0,0 +1,34 @@
+package com.sckw.core.model.vo;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+/**
+ * @author lfdc
+ * @description
+ * @date 2023-08-15 19:08:14
+ */
+@Data
+public class PublicBaseList {
+    /**
+     * 数据id 逗号隔开
+     */
+    @NotBlank(message = "数据id不能为空")
+    private String id;
+
+//    private String type;
+
+    @NotNull(message = "当前页不能为空")
+    private Integer page;
+
+    @NotNull(message = "没页条数不能为空")
+    private Integer pageSize;
+
+    /**
+     * 备注
+     */
+    @Length(max = 200, message = "备注长度错误最大长度:{max}")
+    private String remark;
+}

+ 1540 - 0
slope-common/slope-common-core/src/main/java/com/sckw/core/utils/FileUtils.java

@@ -0,0 +1,1540 @@
+package com.sckw.core.utils;
+
+import cn.hutool.core.date.DateTime;
+import com.aliyun.oss.*;
+import com.aliyun.oss.model.*;
+import com.sckw.core.model.constant.NumberConstant;
+import com.sckw.core.model.constant.StringConstant;
+import com.sckw.core.model.enums.AliyunOssFileTypeEnum;
+import com.sckw.core.model.enums.FileEnum;
+import com.sckw.core.model.file.FileInfo;
+import jakarta.annotation.PostConstruct;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.tomcat.util.http.fileupload.FileItem;
+import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.text.DecimalFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileUtils
+ * @description Oss文件工具类
+ * @company sckw
+ * @date 2023-06-05 09:06:57
+ */
+@Slf4j
+@Component
+@Configuration
+public class FileUtils {
+
+    private static String BASE_DIR = "slope/";
+
+    //oss客户端连接
+    private static OSS ossclient = null;
+
+
+    private static String DEFAULT_ENDPOINT = "oss-cn-chengdu.aliyuncs.com";
+    private static String DEFAULT_ACCESS_KEY_ID = "LTAI5tPEbubCGq5Rdwygbz4Q";
+    private static String DEFAULT_ACCESS_KEY_SECRET = "7mQLWMaBJeZPRV1SRGogctYGXwppjQ";
+    private static String DEFAULT_BUCKET_NAME = "kaiwu-saas";
+
+    private static String endpoint;
+    private static String accessKeyId;
+    private static String accessKeySecret;
+    private static String bucketName;
+    private static FileUtils fileUtils;
+
+    @Value("${aliyun.oss.endpoint}")
+    private String oss_endpoint;
+
+    @Value("${aliyun.oss.accessKeyId}")
+    private String oss_accessKeyId;
+
+    @Value("${aliyun.oss.secret}")
+    private String oss_accessKeySecret;
+
+    @Value("${aliyun.oss.bucket}")
+    public String oss_bucketName;
+
+    private static void defaultOss() {
+        if (StringUtils.isBlank(endpoint)) {
+            endpoint = DEFAULT_ENDPOINT;
+        }
+        if (StringUtils.isBlank(accessKeyId)) {
+            accessKeyId = DEFAULT_ACCESS_KEY_ID;
+        }
+        if (StringUtils.isBlank(accessKeySecret)) {
+            accessKeySecret = DEFAULT_ACCESS_KEY_SECRET;
+        }
+        if (StringUtils.isBlank(bucketName)) {
+            bucketName = DEFAULT_BUCKET_NAME;
+        }
+    }
+
+    @PostConstruct
+    public void init() {
+        endpoint = this.oss_endpoint;
+        accessKeyId = this.oss_accessKeyId;
+        accessKeySecret = this.oss_accessKeySecret;
+        bucketName = this.oss_bucketName;
+    }
+
+//    @PostConstruct
+//    public void setEndpoint() {
+//        endpoint = this.oss_endpoint;
+//    }
+//
+//    @PostConstruct
+//    public void setAccessKeyId() {
+//        accessKeyId = this.oss_accessKeyId;
+//    }
+//
+//    @PostConstruct
+//    public void setAccessKeySecret() {
+//        accessKeySecret = this.oss_accessKeySecret;
+//    }
+//
+//    @PostConstruct
+//    public void setBucketName() {
+//        bucketName = this.oss_bucketName;
+//    }
+
+    public static FileInfo getFileDataList(MultipartFile file) {
+        FileInfo fileInfo = new FileInfo();
+        String oFileName = file.getOriginalFilename();
+        BigDecimal fileSize = FileUtils.getFileSize(file, StringConstant.KB);
+        fileInfo.setFileSize(fileSize);
+        fileInfo.setFileOriginalName(oFileName);
+        fileInfo.setFileSuffix(FilenameUtils.getExtension(oFileName));
+        return fileInfo;
+    }
+
+
+    /**
+     * 获取oss 地址前缀
+     *
+     * @return
+     */
+    public static String getOSSAddressPrefix() {
+        defaultOss();
+        return StringConstant.HTTPS_STRING
+                + StringConstant.COLON
+                + StringConstant.LEFT_SEPARATORS
+                + bucketName
+                + StringConstant.POINT
+                + endpoint
+                + StringConstant.LEFT_SEPARATOR;
+    }
+
+    /**
+     * 分割上传地址 目前仅用于oss
+     *
+     * @param replace 上传的绝对路径
+     * @return 分割后的相对路径
+     */
+    public static String replaceAll(String replace) {
+        if (StringUtils.isBlank(replace)) {
+            return null;
+        }
+        return replace.replaceAll(getOSSAddressPrefix(), "");
+    }
+
+    /**
+     * 拼接上传地址 目前仅用于oss
+     *
+     * @param replace 相对路径url
+     * @return 绝对路径url
+     */
+    public static String splice(String replace) {
+        StringBuilder stringBuilder = new StringBuilder();
+        if (StringUtils.isBlank(replace)) {
+            return null;
+        }
+        return stringBuilder.append(getOSSAddressPrefix()).append(replace).toString();
+    }
+
+
+    /**
+     * 分割上传地址 目前仅用于oss
+     *
+     * @param replace 上传的绝对路径
+     * @return 分割后的相对路径
+     */
+    public static String replaceAllBatch(String replace) {
+        StringBuilder stringBuilder = new StringBuilder();
+        if (StringUtils.isBlank(replace)) {
+            return null;
+        }
+        String[] split = replace.split(",");
+        if (split.length > 0) {
+            for (int i = 0; i < split.length; i++) {
+                if (i != (split.length - 1)) {
+                    stringBuilder.append(split[i].replaceAll(getOSSAddressPrefix(), "")).append(",");
+                } else {
+                    stringBuilder.append(split[i].replaceAll(getOSSAddressPrefix(), ""));
+                }
+
+            }
+            return stringBuilder.toString();
+        }
+        return null;
+    }
+
+    /**
+     * 拼接上传地址 目前仅用于oss
+     *
+     * @param replace 相对路径url
+     * @return 绝对路径url
+     */
+    public static String spliceBatch(String replace) {
+        StringBuilder stringBuilder = new StringBuilder();
+        if (StringUtils.isBlank(replace)) {
+            return null;
+        }
+        String[] split = replace.split(",");
+        if (split.length > 0) {
+            for (int i = 0; i < split.length; i++) {
+                if (i != (split.length - 1)) {
+                    stringBuilder.append(getOSSAddressPrefix()).append(split[i]).append(",");
+                } else {
+                    stringBuilder.append(getOSSAddressPrefix()).append(split[i]);
+                }
+            }
+            return stringBuilder.toString();
+        }
+        return null;
+    }
+
+
+    /**
+     * 获取指定文件或文件夹的后缀名
+     *
+     * @param fileName 文件名称
+     * @return
+     */
+    public static String getFileSuffix(String fileName) {
+        //例如:abc.png  截取后:.png
+        return fileName.substring(fileName.lastIndexOf("."));
+    }
+
+//    public static MultipartFile fileToMultipartFile(File file) {
+//        FileItem fileItem = creatFileItem(file);
+//        MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
+//        return multipartFile;
+//    }
+
+    public static FileItem creatFileItem(File file) {
+
+        DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory(16, null);
+        FileItem fileItem = diskFileItemFactory.createItem("textField", "application/zip", true, file.getName());
+
+        int bytesRead = 0;
+        byte[] buffer = new byte[8192];
+
+        try {
+            FileInputStream fileInputStream = new FileInputStream(file);
+            OutputStream outputStream = fileItem.getOutputStream();
+            while ((bytesRead = fileInputStream.read(buffer, 0, 8192)) != -1) {
+                outputStream.write(buffer, 0, bytesRead);
+            }
+            Files.copy(file.toPath(), outputStream);
+            outputStream.close();
+            fileInputStream.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return fileItem;
+    }
+
+    /**
+     * 文件上传
+     *
+     * @param file     文件
+     * @param fileEnum 上传使用的枚举
+     * @return
+     */
+    public static Map<String, String> uploadFileByInfo(MultipartFile file, FileEnum fileEnum) {
+        Map<String, String> infoMap = new HashMap<>(NumberConstant.SIXTEEN);
+        //创建OSSClient实例
+        defaultOss();
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        try {
+            //容器不存在,就创建
+            if (!ossClient.doesBucketExist(bucketName)) {
+                ossClient.createBucket(bucketName);
+                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
+                createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
+                ossClient.createBucket(createBucketRequest);
+            }
+            //上传文件流
+            InputStream inputStream = file.getInputStream();
+            String fileName = FilenameUtils.getBaseName(file.getOriginalFilename());
+            //生成随机唯一值,使用uuid,添加到文件名称里面 改成使用加密
+//            fileName = PasswordUtils.md5(fileName);
+            fileName = PasswordUtils.md5(fileName);
+            String fileSuffix = FileUtils.getFileSuffix(file.getOriginalFilename());
+            //不带后缀
+            infoMap.put("fileMd5", fileName);
+            infoMap.put("fileName", fileName + fileSuffix);
+            //按照当前日期,创建文件夹,上传到创建文件夹里面
+            String timeUrl = new DateTime().toString("yyyyMMdd");
+            fileName = timeUrl + "/" + fileName;
+            String filePath = BASE_DIR + fileName + fileSuffix;
+            //调用方法实现上传
+            ossClient.putObject(bucketName, filePath, inputStream);
+            //获取上传后的文件地址
+            //String url1 = getUrl(ossClient, bucketName, filePath);
+            //关闭OSSClient。
+            ossClient.shutdown();
+            //上传之后文件路径
+            //String url = "https://" + bucketName + "." + endpoint + "/" + filePath;
+            //绝对路径 "https://kaiwu-saas.oss-cn-chengdu.aliyuncs.com/+ filePath;"
+            StringBuilder stringBuilder = new StringBuilder();
+            stringBuilder.append(StringConstant.HTTPS_STRING)
+                    .append(StringConstant.COLON)
+                    .append(StringConstant.LEFT_SEPARATORS)
+                    .append(bucketName)
+                    .append(StringConstant.POINT)
+                    .append(endpoint)
+                    .append(StringConstant.LEFT_SEPARATOR);
+//            String url = stringBuilder.append(filePath).toString();
+            //相对路径
+            String url = filePath;
+            //返回 上传文件地址
+            infoMap.put("filePath", url);
+        } catch (IOException e) {
+            infoMap.put("filePath", null);
+            //关闭OSSClient。
+            ossClient.shutdown();
+            e.printStackTrace();
+            log.error("oss-upload-file-error:{}", e.getMessage(), e);
+            throw new RuntimeException("oss-upload-file-error:" + e.getMessage());
+        }
+        return infoMap;
+    }
+
+
+    /**
+     * 文件上传
+     *
+     * @param file     文件
+     * @param fileEnum 上传使用的枚举
+     * @return
+     */
+    public static Map<String, String> uploadFileByInfo(File file, FileEnum fileEnum) {
+        Map<String, String> infoMap = new HashMap<>(NumberConstant.SIXTEEN);
+        //创建OSSClient实例
+        defaultOss();
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        try {
+            //容器不存在,就创建
+            if (!ossClient.doesBucketExist(bucketName)) {
+                ossClient.createBucket(bucketName);
+                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
+                createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
+                ossClient.createBucket(createBucketRequest);
+            }
+            //上传文件流
+
+//            InputStream inputStream = file.getInputStream();
+            InputStream inputStream = new FileInputStream(file);
+            String fileName = FilenameUtils.getBaseName(file.getName());
+            //生成随机唯一值,使用uuid,添加到文件名称里面 改成使用加密
+//            fileName = PasswordUtils.md5(fileName);
+            fileName = PasswordUtils.md5(fileName);
+            String fileSuffix = FileUtils.getFileSuffix(file.getName());
+            //不带后缀
+            infoMap.put("fileMd5", fileName);
+            infoMap.put("fileName", fileName + fileSuffix);
+            //按照当前日期,创建文件夹,上传到创建文件夹里面
+            String timeUrl = new DateTime().toString("yyyyMMdd");
+            fileName = timeUrl + "/" + fileName;
+            String filePath = BASE_DIR + fileName + fileSuffix;
+            //调用方法实现上传
+            ossClient.putObject(bucketName, filePath, inputStream);
+            //获取上传后的文件地址
+            //String url1 = getUrl(ossClient, bucketName, filePath);
+            //关闭OSSClient。
+            ossClient.shutdown();
+            //上传之后文件路径
+            //String url = "https://" + bucketName + "." + endpoint + "/" + filePath;
+            //绝对路径 "https://kaiwu-saas.oss-cn-chengdu.aliyuncs.com/+ filePath;"
+            StringBuilder stringBuilder = new StringBuilder();
+            stringBuilder.append(StringConstant.HTTPS_STRING)
+                    .append(StringConstant.COLON)
+                    .append(StringConstant.LEFT_SEPARATORS)
+                    .append(bucketName)
+                    .append(StringConstant.POINT)
+                    .append(endpoint)
+                    .append(StringConstant.LEFT_SEPARATOR);
+//            String url = stringBuilder.append(filePath).toString();
+            //相对路径
+            String url = filePath;
+            //返回 上传文件地址
+            infoMap.put("filePath", url);
+        } catch (IOException e) {
+            infoMap.put("filePath", null);
+            //关闭OSSClient。
+            ossClient.shutdown();
+            e.printStackTrace();
+            log.error("oss-upload-file-error:{}", e.getMessage(), e);
+            throw new RuntimeException("oss-upload-file-error:" + e.getMessage());
+        }
+        return infoMap;
+    }
+
+    /**
+     * 上传文件
+     * <p>
+     * kll/uploads/年月日/md5(file).xxx
+     *
+     * @param file
+     * @param fileEnum
+     * @return
+     */
+    public static String uploadFile(MultipartFile file, FileEnum fileEnum) {
+        // 私有云要关闭CNAME
+        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
+        conf.setSupportCname(false);
+        try {
+            //创建OSSClient实例
+            defaultOss();
+            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+
+            //容器不存在,就创建
+            if (!ossClient.doesBucketExist(bucketName)) {
+                ossClient.createBucket(bucketName);
+                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
+                createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
+                ossClient.createBucket(createBucketRequest);
+            }
+            //上传文件流
+            InputStream inputStream = file.getInputStream();
+            String fileName = file.getOriginalFilename();
+            //生成随机唯一值,使用uuid,添加到文件名称里面
+            long uuid = new IdWorker(1).nextId();
+//            fileName = String.valueOf(uuid) + fileName;
+            fileName = PasswordUtils.md5(fileName);
+            //按照当前日期,创建文件夹,上传到创建文件夹里面
+            //2021/02/02/01.jpgossClient = {OSSClient@13049}
+            String timeUrl = new DateTime().toString("yyyyMMdd");
+            fileName = timeUrl + "/" + fileName;
+            String filePath = BASE_DIR + fileName;
+            /**设置上传内容类型*/
+            ObjectMetadata objectMeta = new ObjectMetadata();
+            objectMeta.setContentType(FileUtils.getContentTypeByOSS(file.getOriginalFilename()));
+            //调用方法实现上传
+            ossClient.putObject(bucketName, filePath, inputStream, objectMeta);
+            //上传后的文件地址
+//            String url1 = getUrl(ossClient, bucketName, filePath);
+//            System.out.println(url1);
+            //关闭OSSClient。
+            ossClient.shutdown();
+            //上传之后文件路径
+            //https://yygh-atguigu.oss-cn-beijing.aliyuncs.com/01.jpg
+            String url = "https://" + bucketName + "." + endpoint + "/" + filePath;
+            //返回 上传文件地址
+            return url;
+        } catch (IOException e) {
+            e.printStackTrace();
+            log.error("oss-upload-file-error:{}", e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * 文件上传
+     *
+     * @param inputStream      文件流
+     * @param originalFilename 文件原名称
+     * @param fileEnum         上传文件类型/地址枚举
+     * @return
+     */
+    public static Map<String, String> uploadFileByInfo(InputStream inputStream, String originalFilename, FileEnum fileEnum) {
+        Map<String, String> infoMap = new HashMap<>(NumberConstant.SIXTEEN);
+        //创建OSSClient实例
+        defaultOss();
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        try {
+            //容器不存在,就创建
+            if (!ossClient.doesBucketExist(bucketName)) {
+                ossClient.createBucket(bucketName);
+                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
+                createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
+                ossClient.createBucket(createBucketRequest);
+            }
+            //上传文件流
+            String fileName = FilenameUtils.getBaseName(originalFilename);
+            //生成随机唯一值,使用uuid,添加到文件名称里面 改成使用加密
+//            fileName = PasswordUtils.md5(fileName);
+            fileName = PasswordUtils.md5(fileName);
+            String fileSuffix = FileUtils.getFileSuffix(originalFilename);
+            //不带后缀
+            infoMap.put("fileMd5", fileName);
+            infoMap.put("fileName", fileName + fileSuffix);
+            //按照当前日期,创建文件夹,上传到创建文件夹里面
+            //2021/02/02/01.jpg
+            String timeUrl = new DateTime().toString("yyyyMMdd");
+            fileName = timeUrl + "/" + fileName;
+            String filePath = BASE_DIR + fileName + fileSuffix;
+            //调用方法实现上传
+            ossClient.putObject(bucketName, filePath, inputStream);
+            //上传后的文件地址
+//            String url1 = getUrl(ossClient, bucketName, filePath);
+            //关闭OSSClient。
+            ossClient.shutdown();
+            //上传之后文件路径
+//            String url = "https://" + bucketName + "." + endpoint + "/" + filePath;
+            //绝对路径 "https://kaiwu-saas.oss-cn-chengdu.aliyuncs.com/+ filePath;"
+//            String url = StringConstant.HTTPS_STRING+StringConstant.COLON+StringConstant.LEFT_SEPARATORS + bucketName + StringConstant.POINT + endpoint + StringConstant.LEFT_SEPARATOR+ filePath;
+            //相对路径
+            String url = filePath;
+            //返回 上传文件地址
+            infoMap.put("filePath", url);
+        } catch (Exception e) {
+            infoMap.put("filePath", null);
+            //关闭OSSClient。
+            ossClient.shutdown();
+            e.printStackTrace();
+            log.error("oss-upload-file-error:{}", e.getMessage(), e);
+            throw new RuntimeException("oss-upload-file-error:" + e.getMessage());
+        }
+        return infoMap;
+    }
+
+
+    /**
+     * 文件上传
+     *
+     * @param file     文件流
+     * @param fileInfo 文件对象
+     * @param fileEnum 文件枚举-暂时不使用
+     * @return
+     */
+    public static FileInfo uploadFileInfo(MultipartFile file, FileInfo fileInfo, FileEnum fileEnum) {
+        //创建OSSClient实例
+        defaultOss();
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        try {
+            //容器不存在,就创建
+            if (!ossClient.doesBucketExist(bucketName)) {
+                ossClient.createBucket(bucketName);
+                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
+                createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
+                ossClient.createBucket(createBucketRequest);
+            }
+            //上传文件流
+            InputStream inputStream = file.getInputStream();
+            String fileName = FilenameUtils.getBaseName(file.getOriginalFilename());
+            //生成随机唯一值,使用uuid,添加到文件名称里面 改成使用加密
+            //fileName = PasswordUtils.md5(fileName);
+            fileName = PasswordUtils.md5(fileName) + System.currentTimeMillis();
+            String fileSuffix = FileUtils.getFileSuffix(file.getOriginalFilename());
+            //不带后缀
+            fileInfo.setFileMd5(fileName);
+            fileInfo.setFileName(fileName + fileSuffix);
+            //按照当前日期,创建文件夹,上传到创建文件夹里面
+            String timeUrl = new DateTime().toString(StringConstant.DATE_YYYYMMDD);
+            fileName = timeUrl + StringConstant.LEFT_SEPARATOR + fileName;
+            String filePath = BASE_DIR + fileName + fileSuffix;
+            //调用方法实现上传
+            ossClient.putObject(bucketName, filePath, inputStream);
+            //获取上传后的文件地址
+            //String url1 = getUrl(ossClient, bucketName, filePath);
+            //关闭OSSClient。
+            ossClient.shutdown();
+            //上传之后文件路径
+            //String url = "https://" + bucketName + "." + endpoint + "/" + filePath;
+            //绝对路径 "https://kaiwu-saas.oss-cn-chengdu.aliyuncs.com/+ filePath;"
+            StringBuilder stringBuilder = new StringBuilder();
+            stringBuilder.append(StringConstant.HTTPS_STRING)
+                    .append(StringConstant.COLON)
+                    .append(StringConstant.LEFT_SEPARATORS)
+                    .append(bucketName)
+                    .append(StringConstant.POINT)
+                    .append(endpoint)
+                    .append(StringConstant.LEFT_SEPARATOR);
+            String fileAbsolutePath = stringBuilder.append(filePath).toString();
+            fileInfo.setFileAbsolutePath(fileAbsolutePath);
+            //相对路径
+            String url = filePath;
+            //返回 上传文件地址
+            fileInfo.setFilePath(url);
+        } catch (IOException e) {
+            fileInfo.setFilePath(null);
+            //关闭OSSClient。
+            ossClient.shutdown();
+            e.printStackTrace();
+            log.error("oss-upload-file-error:{}", e.getMessage(), e);
+            throw new RuntimeException("oss-upload-file-error:" + e.getMessage());
+        }
+        return fileInfo;
+    }
+
+
+    /**
+     * 获取文件上传大小
+     *
+     * @param file
+     * @return
+     */
+    public static String getFileSize(MultipartFile file) {
+        long size = file.getSize();
+        DecimalFormat df = new DecimalFormat("#.00");
+        String fileSizeString;
+        if (size < 1024) {
+            fileSizeString = df.format((double) size) + "B";
+        } else if (size < 1048576) {
+            fileSizeString = df.format((double) size / 1024) + "KB";
+        } else if (size < 1073741824) {
+            fileSizeString = df.format((double) size / 1048576) + "MB";
+        } else {
+            fileSizeString = df.format((double) size / 1073741824) + "GB";
+        }
+        return fileSizeString;
+    }
+
+    /**
+     * 获取文件上传大小
+     *
+     * @param file 当前默认使用 kb
+     * @return
+     */
+    public static BigDecimal getFileSize(MultipartFile file, String type) {
+        long size = file.getSize();
+        BigDecimal bigDecimal = new BigDecimal(NumberConstant.ZERO);
+        if (StringUtils.isBlank(type)) {
+            type = StringConstant.KB;
+        }
+        switch (type) {
+            case "B":
+                bigDecimal = new BigDecimal((double) size);
+                break;
+            case "KB":
+                bigDecimal = new BigDecimal((double) size / 1024);
+                break;
+            case "MB":
+                bigDecimal = new BigDecimal((double) size / 1048576);
+                break;
+            case "GB":
+                bigDecimal = new BigDecimal((double) size / 1073741824);
+                break;
+            default:
+                throw new RuntimeException("file size error");
+        }
+        return bigDecimal.setScale(6, RoundingMode.HALF_UP);
+    }
+
+    /**
+     * 获得阿里云OSS客户端对象
+     *
+     * @param ossEndpoint
+     * @param accessId
+     * @param accessKey
+     * @return
+     */
+    public static OSS getOssClient(String ossEndpoint, String accessId, String accessKey) {
+        if (ossclient == null) {
+            ossclient = new OSSClientBuilder().build(ossEndpoint, accessId, accessKey);
+        }
+        return ossclient;
+    }
+
+    /**
+     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
+     *
+     * @param fileName 文件名
+     * @return 文件的contentType
+     */
+    public static String getContentType(String fileName) {
+        // 文件的后缀名
+        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
+        log.info("getContentType->fileName={},fileExtension={}", fileName, fileExtension);
+        for (AliyunOssFileTypeEnum e : AliyunOssFileTypeEnum.values()) {
+            if (e.getCode().equalsIgnoreCase(fileExtension)) {
+                return e.getText();
+            }
+        }
+        // 默认返回类型
+        return AliyunOssFileTypeEnum.TXT.getText();
+    }
+
+    /**
+     * @param fileName
+     * @param response
+     */
+    public static void downOSSFile(String fileName, HttpServletResponse response) {
+        BufferedInputStream input = null;
+        OutputStream outputStream = null;
+        defaultOss();
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+//        OSSObject ossObject = ossClient.getObject(bucketName, folder + fileName);
+        OSSObject ossObject = ossClient.getObject(bucketName, fileName);
+        try {
+            response.reset();
+            response.setCharacterEncoding("utf-8");
+            response.setContentType("application/x-msdownload");
+            response.addHeader("Content-Disposition",
+                    "attachment;filename=" + new String(fileName.getBytes("gb2312"), "ISO8859-1"));
+
+            input = new BufferedInputStream(ossObject.getObjectContent());
+            byte[] buffBytes = new byte[1024];
+            outputStream = response.getOutputStream();
+            int read = 0;
+            while ((read = input.read(buffBytes)) != -1) {
+                outputStream.write(buffBytes, 0, read);
+            }
+            outputStream.flush();
+            // 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
+            ossObject.close();
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        } finally {
+            try {
+                if (outputStream != null) {
+                    outputStream.close();
+                }
+                if (input != null) {
+                    input.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        ossClient.shutdown();
+    }
+
+
+    /**
+     * 通过文件名字下载
+     *
+     * @param response response
+     * @param fileName 文件名字,带后缀,例子:postman.txt
+     *                 文件全路径 kll/uploads/20230605/146325493677821952598454132.txt 去除“https://kaiwu-saas.oss-cn-chengdu.aliyuncs.com/”
+     */
+    public static void downloadByFileName(HttpServletResponse response, String fileName) {
+        defaultOss();
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        OSSObject ossObject = ossClient.getObject(bucketName, fileName);
+        boolean exist = ossClient.doesObjectExist(bucketName, fileName);
+        if (!exist) {
+            throw new RuntimeException("下载文件不存在!");
+        }
+        String contentType = ossObject.getObjectMetadata().getContentType();
+        String contentType1 = getContentType(fileName);
+//        System.out.println("contentType:" + contentType);
+//        System.out.println("contentType1:" + contentType1);
+        //设置响应内容类型,当设置了ContentType为“image/jpg”时,浏览器可以直接显示图片;
+//        response.setContentType(contentType);
+        BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
+        try {
+            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
+            //通知浏览器以附件形式下载
+//            fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8").replaceAll("\\+", "%20"));
+            byte[] car = new byte[1024];
+            int len = 0;
+            while ((len = in.read(car)) != -1) {
+                out.write(car, 0, len);
+            }
+            out.flush();
+            out.close();
+            in.close();
+            ossClient.shutdown();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 创建存储空间
+     *
+     * @param ossClient  OSS连接
+     * @param bucketName 存储空间
+     * @return
+     */
+    public static String createBucketName(OSS ossClient, String bucketName) {
+        // 存储空间
+        final String bucketNames = bucketName;
+        if (!ossClient.doesBucketExist(bucketName)) {
+            // 创建存储空间
+            Bucket bucket = ossClient.createBucket(bucketName);
+            log.info("创建存储空间成功");
+            return bucket.getName();
+        }
+        return bucketNames;
+    }
+
+
+    /**
+     * 删除存储空间bucketName
+     *
+     * @param ossClient  oss对象
+     * @param bucketName 存储空间
+     */
+    public static void deleteBucket(OSS ossClient, String bucketName) {
+        ossClient.deleteBucket(bucketName);
+        log.info("删除" + bucketName + "Bucket成功");
+    }
+
+
+    /**
+     * 创建模拟文件夹:多级目录
+     *
+     * @param ossClient  oss连接
+     * @param bucketName 存储空间
+     * @param folder     模拟文件夹名如"upload/2023/01/11/"
+     * @return 文件夹名
+     */
+    public static String createFolder(OSS ossClient, String bucketName, String folder) {
+        // 文件夹名
+        final String keySuffixWithSlash = folder;
+        // 判断文件夹是否存在,不存在则创建
+        if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
+            // 创建文件夹
+            ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
+            log.info("创建文件夹成功");
+            // 得到文件夹名
+            OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
+            String fileDir = object.getKey();
+            return fileDir;
+        }
+        return keySuffixWithSlash;
+    }
+
+
+    /**
+     * 根据key删除OSS服务器上的文件
+     *
+     * @param ossClient  oss连接
+     * @param bucketName 存储空间
+     * @param key        Bucket下的文件的路径名+文件名 如:"upload/2023/01/11/cake.jpg"
+     */
+    public static void deleteObject(OSS ossClient, String bucketName, String key) {
+        ossClient.deleteObject(bucketName, key);
+        log.info("删除" + bucketName + "下的文件" + key + "成功");
+    }
+
+
+    /**
+     * 上传文件
+     *
+     * @param ossClient  oss连接
+     * @param bucketName 存储空间
+     * @param ossPath    上传文件相对路径+文件名如"upload/2023/01/11/cake.jpg"
+     * @param is         以输入流的形式上传文件
+     * @param fileName   上传文件后新文件名
+     * @return String 返回的唯一MD5数字签名
+     */
+    public static String uploadFileOss(OSS ossClient, String bucketName, String ossPath, InputStream is, String fileName) {
+        try {
+            // 文件大小
+            long fileSize = is.available();
+            // 创建上传Object的Metadata
+            ObjectMetadata metadata = new ObjectMetadata();
+            // 上传的文件的长度
+            metadata.setContentLength(is.available());
+            // 指定该Object被下载时的网页的缓存行为
+            metadata.setCacheControl("no-cache");
+            // 指定该Object下设置Header
+            metadata.setHeader("Pragma", "no-cache");
+            // 指定该Object被下载时的内容编码格式
+            metadata.setContentEncoding("utf-8");
+            // 文件的MIME,定义文件的类型及网页编码,决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成,
+            // 如果没有扩展名则填默认值application/octet-stream
+            metadata.setContentType(getContentType(fileName));
+            // 指定该Object被下载时的名称(指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称)
+            metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte");
+            //上传文件到OSS时需要指定包含文件后缀在内的完整路径如ossPath="upload/2023/01/11/cake.jpg"
+            PutObjectResult putResult = ossClient.putObject(bucketName, ossPath, is, metadata);
+            // 解析结果
+            String resultStr = putResult.getETag();
+            log.info("唯一MD5数字签名:" + resultStr);
+            //上传文件后相对路径如"upload/2023/01/11/cake.jpg"
+            String path = ossPath;
+            return path;
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
+            return null;
+        }
+    }
+
+
+    /**
+     * 下载文件到本地
+     *
+     * @param ossClient     oss连接
+     * @param bucketName    存储空间
+     * @param key           Bucket下的文件的路径名+文件名 如:"upload/2023/01/11/cake.jpg"
+     * @param localFilePath 下载本地文件绝对路径如"C:\Users\Administrator\Desktop\oss-download\xxx.pdf"
+     */
+    public static void downloadFileOss(OSS ossClient, String bucketName, String key, String localFilePath) {
+        try {
+            //创建本地文件
+            File file = new File(localFilePath);
+            GetObjectRequest objectRequest = new GetObjectRequest(bucketName, key);
+            //下载OSS文件到本地文件,若指定的本地文件存在则覆盖,否则新建
+            ossClient.getObject(objectRequest, file);
+            log.info("下载文件到本地成功");
+        } catch (OSSException e) {
+            e.printStackTrace();
+        } catch (ClientException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    /**
+     * 获取上传文件对象
+     * 备注:最重要的是获取上传文件的输出流InputStream
+     *
+     * @param ossClient  oss连接
+     * @param bucketName 存储空间
+     * @param key        Bucket下的文件的路径名+文件名 如:"upload/2023/01/11/cake.jpg"
+     * @return
+     */
+    public static OSSObject getObject(OSS ossClient, String bucketName, String key) {
+        OSSObject object = null;
+        try {
+            object = ossClient.getObject(bucketName, key);
+            //文件大小
+            long fileSize = object.getObjectMetadata().getContentLength();
+            //文件相对路径
+            String ossPath = object.getKey();
+            //文件输入流
+            InputStream is = object.getObjectContent();
+            log.info("success to getObject,fileSize:" + fileSize + "\nossPath:" + ossPath + "\ninputStream:" + is);
+        } catch (OSSException e) {
+            e.printStackTrace();
+        } catch (ClientException e) {
+            e.printStackTrace();
+        }
+        return object;
+    }
+
+
+    /**
+     * 获取上传文件url
+     *
+     * @param ossClient  oss连接
+     * @param bucketName bucketName
+     * @param key        文件全路径
+     * @return
+     */
+    public static String getUrl(OSS ossClient, String bucketName, String key) {
+        //设置URl过期时间为99年:3600L*1000*24*365*99
+        Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 99);
+        GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, key);
+        generatePresignedUrlRequest.setExpiration(expiration);
+        URL url = ossClient.generatePresignedUrl(generatePresignedUrlRequest);
+        String returnUrl = url.toString();
+        return returnUrl;
+    }
+
+
+    public static void downloadByFileName(String objectName) {
+        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。关于其他Region对应的Endpoint信息,请参见访问域名和数据中心。
+//        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
+        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
+//        String accessKeyId = "yourAccessKeyId";
+//        String accessKeySecret = "yourAccessKeySecret";
+        // 填写Bucket名称,例如examplebucket。
+//        String bucketName = "examplebucket";
+        // 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
+//        String objectName = "exampledir/exampleobject.txt";
+
+        // 创建OSSClient实例。
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        try {
+            // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
+            OSSObject ossObject = ossClient.getObject(bucketName, objectName);
+            // 读取文件内容。
+            System.out.println("Object content:");
+            BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
+            while (true) {
+                String line = reader.readLine();
+                if (line == null) {
+                    break;
+                }
+
+                System.out.println("\n" + line);
+            }
+            // 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
+            reader.close();
+            // ossObject对象使用完毕后必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
+            ossObject.close();
+
+        } catch (OSSException oe) {
+            System.out.println("Caught an OSSException, which means your request made it to OSS, "
+                    + "but was rejected with an error response for some reason.");
+            System.out.println("Error Message:" + oe.getErrorMessage());
+            System.out.println("Error Code:" + oe.getErrorCode());
+            System.out.println("Request ID:" + oe.getRequestId());
+            System.out.println("Host ID:" + oe.getHostId());
+        } catch (Throwable ce) {
+            System.out.println("Caught an ClientException, which means the client encountered "
+                    + "a serious internal problem while trying to communicate with OSS, "
+                    + "such as not being able to access the network.");
+            System.out.println("Error Message:" + ce.getMessage());
+        } finally {
+            if (ossClient != null) {
+                ossClient.shutdown();
+            }
+        }
+    }
+
+
+    /**
+     * 通过oss的完整key下载
+     *
+     * @param response   response
+     * @param objectName oss完整的key,例子:fj_wechat_web/public/postman.txt
+     */
+    public static void downloadByObjectName(HttpServletResponse response, String objectName) {
+//        String endpointStr = "http://" + endpoint + ".aliyuncs.com";
+        String endpointStr = "http://" + endpoint;
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        OSSObject ossObject = ossClient.getObject(bucketName, objectName);
+
+        BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
+
+        try {
+            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
+            //通知浏览器以附件形式下载
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("postman.txt", "utf-8"));
+
+            byte[] car = new byte[1024];
+            int len;
+            while ((len = in.read(car)) != -1) {
+                out.write(car, 0, len);
+            }
+            out.flush();
+            out.close();
+            in.close();
+            ossClient.shutdown();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 通过oss的完整key下载
+     *
+     * @param response response
+     * @param url      全路径的url地址 kll/uploads/20230621/07ccbec381a011d121a215719199ac49.html
+     */
+    public static void downloadByUrl(HttpServletResponse response, String url) {
+        downloadByFileName(response, url);
+    }
+
+    /**
+     * @param @param ossFilePath oss上的文件路径(全路径)
+     * @param @param newFilePath 本地文件路径 (全路径)
+     * @return void    返回类型
+     * @Title:downloadToFile
+     * @Description: 下载文件到本地
+     */
+    public static void downloadToFile(String endPoint, String accessKeyId, String accessKeySecret, String bucketName, String ossFilePath, String newFilePath) {
+        //实例化OSSClient对象
+        OSSClient ossClient = (OSSClient) new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
+        try {
+            // 指定路径如果没有则创建并添加
+            File file = new File(newFilePath);
+            //获取父目录
+            File fileParent = file.getParentFile();
+            //判断是否存在
+            if (!fileParent.exists()) {
+                // 创建父目录文件
+                fileParent.mkdirs();
+            }
+            file.createNewFile();
+            // 下载Object到本地文件,并保存到指定的本地路径中。如果指定的本地文件存在会覆盖,不存在则新建。
+            // 如果未指定本地路径,则下载后的文件默认保存到示例程序所属项目对应本地路径中。
+            ossClient.getObject(new GetObjectRequest(bucketName, ossFilePath), new File(newFilePath));
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (ossClient != null) {
+                ossClient.shutdown();
+            }
+        }
+    }
+
+    /**
+     * 判断文件是否存在
+     *
+     * @param fileName 文件名:postman.txt
+     * @return true文件存在,false文件不存在
+     */
+    public boolean isExitByFileName(String fileName) {
+//        String endpointStr = "http://" + endpoint + ".aliyuncs.com";
+        String endpointStr = "http://" + endpoint;
+        OSS ossClient = new OSSClientBuilder().build(endpointStr, accessKeyId, accessKeySecret);
+        return ossClient.doesObjectExist(bucketName, BASE_DIR + fileName);
+    }
+
+    /**
+     * 判断文件是否存在
+     *
+     * @param url 能直接访问的完整url
+     * @return true文件存在,false文件不存在
+     */
+    public boolean isExitByUrl(String url) {
+        return isExitByFileName(getFileNameByUrl(url));
+    }
+
+    /**
+     * 通过url获取文件名
+     *
+     * @param url 能够直接访问的url
+     * @return 文件名:postman.txt
+     */
+    public static String getFileNameByUrl(String url) {
+        String[] split = url.split("/");
+        return split[split.length - 1];
+    }
+
+    /**
+     * 字符串转成file文件
+     *
+     * @param text
+     * @param file
+     * @return
+     */
+    public static File stringByFile(String text, File file) {
+        if (file.exists()) {
+            file.delete();
+        }
+        BufferedReader br = null;
+        BufferedWriter bw = null;
+        try {
+            br = new BufferedReader(new StringReader(text));
+            bw = new BufferedWriter(new FileWriter(file));
+            //字符缓冲区
+            char[] buf = new char[1024 * 64];
+            int len;
+            while ((len = br.read(buf)) != -1) {
+                bw.write(buf, 0, len);
+            }
+            bw.flush();
+            br.close();
+            bw.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return file;
+    }
+
+    /**
+     * file转byte
+     */
+    public static byte[] file2byte(File file) {
+        byte[] buffer = null;
+        try {
+            FileInputStream fis = new FileInputStream(file);
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            byte[] b = new byte[1024];
+            int n;
+            while ((n = fis.read(b)) != -1) {
+                bos.write(b, 0, n);
+            }
+            fis.close();
+            bos.close();
+            buffer = bos.toByteArray();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return buffer;
+    }
+
+    /**
+     * byte 转file
+     */
+    public static File byte2File(byte[] buf, String filePath, String fileName) {
+        BufferedOutputStream bos = null;
+        FileOutputStream fos = null;
+        File file = null;
+        try {
+            File dir = new File(filePath);
+            if (!dir.exists() && dir.isDirectory()) {
+                dir.mkdirs();
+            }
+            file = new File(filePath + File.separator + fileName);
+            fos = new FileOutputStream(file);
+            bos = new BufferedOutputStream(fos);
+            bos.write(buf);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (bos != null) {
+                try {
+                    bos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return file;
+    }
+
+    /**
+     * multipartFile转File
+     **/
+    public static File multipartFile2File(MultipartFile multipartFile) {
+        File file = null;
+        if (multipartFile != null) {
+            try {
+                file = File.createTempFile("tmp", null);
+                multipartFile.transferTo(file);
+                System.gc();
+                file.deleteOnExit();
+            } catch (Exception e) {
+                e.printStackTrace();
+                log.warn("multipartFile转File发生异常:" + e);
+            }
+        }
+        return file;
+    }
+
+
+    /**
+     * 删除文件
+     *
+     * @param url 示例:'download/file.xsl' oss服务器文件路径以及文件名
+     *            https://kaiwu-saas.oss-cn-chengdu.aliyuncs.com/kll/uploads/20230621/07ccbec381a011d121a215719199ac49.html
+     *            删除时,去掉默认前缀,只需要相对路径 “kll/uploads/20230621/07ccbec381a011d121a215719199ac49.html”
+     */
+    public static void remove(String url) {
+        try {
+            // 创建OSSClient实例。
+            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+            // 判断当前文件url 是否存在
+            boolean exist = ossClient.doesObjectExist(bucketName, url);
+            if (!exist) {
+                System.out.println("文件不存在");
+            } else {
+                // 删除文件。
+                ossClient.deleteObject(bucketName, url);
+                // 关闭OSSClient。
+                ossClient.shutdown();
+
+            }
+        } catch (Exception e) {
+            System.out.println(e);
+        }
+
+    }
+
+
+    /**
+     * 获取OSS连接
+     *
+     * @return
+     */
+    private static void getOSSClient() {
+        if (ossclient == null) {
+            ossclient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        }
+    }
+
+    /**
+     * 根据key删除OSS服务器上的文件
+     * <p>
+     * param ossClient oss连接
+     * param bucketName 存储空间
+     * param folder 模拟文件夹名 如"qj_nanjing/"
+     * param key Bucket下的文件的路径名+文件名 如:"upload/cake.jpg"
+     */
+    public static void deleteFile(String bucketName, String folder, String key) {
+        //获取OSS存储client
+        getOSSClient();
+        ossclient.deleteObject(bucketName, folder + key);
+        log.info("删除" + bucketName + "下的文件" + folder + key + "成功");
+    }
+
+    /**
+     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
+     * param fileName 文件名
+     * return 文件的 contentType
+     */
+    public static String getContentTypeByOSS(String fileName) {
+        // 文件的后缀名
+        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
+        if (".bmp".equalsIgnoreCase(fileExtension)) {
+            return "image/bmp";
+        }
+        if (".gif".equalsIgnoreCase(fileExtension)) {
+            return "image/gif";
+        }
+        if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
+                || ".png".equalsIgnoreCase(fileExtension)) {
+            return "image/jpeg";
+        }
+        if (".png".equalsIgnoreCase(fileExtension)) {
+            return "image/png";
+        }
+        if (".html".equalsIgnoreCase(fileExtension)) {
+            return "text/html";
+        }
+        if (".txt".equalsIgnoreCase(fileExtension)) {
+            return "text/plain";
+        }
+        if (".vsd".equalsIgnoreCase(fileExtension)) {
+            return "application/vnd.visio";
+        }
+        if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
+            return "application/vnd.ms-powerpoint";
+        }
+        if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
+            return "application/msword";
+        }
+        if (".xml".equalsIgnoreCase(fileExtension)) {
+            return "text/xml";
+        }
+        // 默认返回类型
+        return null;
+    }
+
+
+    /**
+     * 下载文件,此处主要是给Controller层提供一个OSS的Object类
+     * objectName示例:download/file.xsl,()这里是oss文件列表中 文件路径和文件名
+     */
+    public static OSSObject downloadOssFile(OutputStream os, String objectName) {
+        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        OSSObject ossObject = ossClient.getObject(bucketName, objectName);
+        return ossObject;
+
+    }
+
+    final static String IMG_FORMAT = "png_jpg_bmp_gif_tif_jpeg_PNG_JPG_BMP_GIF_TIF_JPEG_HEIC_heic";
+    final static String IMG_FORMAT_NUMBER = "8950_ffd8_424d_4749_4d4d_4949_5249";
+
+
+    /**
+     * 针对图片内容的格式效验。
+     * 分别以:
+     * 1:判断后缀名的方式判断是否为图片
+     * 2:以魔术数字进行判断
+     * 3:以imageIO流的方式验证是否为图片
+     *
+     * @param mFile
+     * @return boolean
+     * @author lihao
+     */
+    public static boolean isImage(MultipartFile mFile) {
+        File file = null;
+        InputStream is = null;
+        Image img = null;
+        byte[] bt = new byte[2];
+        try {
+            file = multipartFile2File(mFile);
+            is = new FileInputStream(file);
+            is.read(bt);
+            img = ImageIO.read(file);
+        } catch (IOException e) {
+            return false;
+        }
+
+        //获取文件后缀进行判断
+        String suffix = mFile.getOriginalFilename().substring(mFile.getOriginalFilename().lastIndexOf(".") + 1);
+        if (IMG_FORMAT.indexOf(suffix) == -1) {
+            return false;
+        }
+
+        //以魔术数字进行判断
+        StringBuilder stringBuilder = new StringBuilder();
+        for (int i = 0; i < bt.length; i++) {
+            int v = bt[i] & 0xFF;//byte to int
+            String hv = Integer.toHexString(v);
+            if (hv.length() < 2) {
+                stringBuilder.append(0);
+            }
+            stringBuilder.append(hv);
+        }
+        System.out.println(stringBuilder.toString());
+        if (IMG_FORMAT_NUMBER.indexOf(stringBuilder.toString()) == -1) {
+            return false;
+        }
+
+        //以imageIO流的方式对图片进行格式检查
+        if (img == null || img.getWidth(null) <= 0 || img.getHeight(null) <= 0) {
+            return false;
+        }
+        if (file.exists()) {
+            file.delete();
+        }
+        return true;
+    }
+
+    /**
+     * 给图片添加水印、可设置水印图片旋转角度
+     *
+     * @param logoText 水印文字
+     * @param degree   水印图片旋转角度
+     * @param clarity  透明度(小于1的数)越接近0越透明
+     * @param mFile    被操作的图片
+     */
+    public byte[] waterMarkByText(String logoText,
+                                  Integer degree,
+                                  Float clarity, MultipartFile mFile) {
+        // 图片流
+        InputStream inputStream = null;
+        ByteArrayOutputStream byteStream = null;
+        Image srcImg = null;
+        File file = null;
+        byte[] byteImg = new byte[0];
+
+        //水印添加位置坐标 1像素=1磅*DPI/72 显示屏dpi 大多是72 少数96  这里不对
+        Integer width, height;
+        Integer fontSize = 50;
+        Integer rightButtomOffset = fontSize * 72 / 72 * 6;
+
+        try {
+            file = File.createTempFile("tmp", null);
+            mFile.transferTo(file);
+            srcImg = ImageIO.read(file);
+            width = srcImg.getWidth(null) - rightButtomOffset;
+            height = srcImg.getHeight(null);
+            BufferedImage buffImg = new BufferedImage(srcImg.getWidth(null),
+                    srcImg.getHeight(null), BufferedImage.TYPE_INT_RGB);
+            // 得到画笔对象
+            Graphics2D g = buffImg.createGraphics();
+            // 设置对线段的锯齿状边缘处理
+            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+                    RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+            g.drawImage(
+                    srcImg.getScaledInstance(srcImg.getWidth(null),
+                            srcImg.getHeight(null), Image.SCALE_SMOOTH), 0, 0,
+                    null);
+            if (null != degree) {
+                // 设置水印旋转
+                g.rotate(Math.toRadians(degree),
+                        (double) buffImg.getWidth() / 2,
+                        (double) buffImg.getHeight() / 2);
+            }
+            // 设置颜色
+            g.setColor(Color.red);
+            // 设置 Font
+            g.setFont(new Font("宋体", Font.BOLD, fontSize));
+            float alpha = clarity;
+            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
+                    alpha));
+            // 第一参数->设置的内容,后面两个参数->文字在图片上的坐标位置(x,y) .
+            g.drawString(logoText, width, height);
+            g.dispose();
+            // 生成图片
+            ImageIO.write(buffImg, "JPG", file);
+            inputStream = new FileInputStream(file);
+            byteStream = new ByteArrayOutputStream();
+            int ch;
+            while ((ch = inputStream.read()) != -1) {
+                byteStream.write(ch);
+            }
+            byteImg = byteStream.toByteArray();
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (null != inputStream) {
+                    inputStream.close();
+                }
+                if (null != byteStream) {
+                    byteStream.close();
+                }
+                if (file.exists()) {
+                    file.delete();
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return byteImg;
+    }
+
+    // 测试
+    public static void main(String[] args) throws FileNotFoundException {
+        //阿里云OSS账号自行到阿里云官网申请
+        String ossEndpoint = "XXX";
+        String accessId = "XXX";
+        String accessKey = "XXX";
+        String bucketName = "test";
+        // 初始化OSSClient
+//        OSS ossClient = AliyunOSSClientUtil.getOssClient(ossEndpoint, accessId, accessKey);
+        OSS ossClient = FileUtils.getOssClient(ossEndpoint, accessId, accessKey);
+
+
+        //测试创建多级目录
+        /*String tmpDir = "upload/2023/01/11/";
+        String folder = createFolder(ossClient, bucketName, tmpDir);
+        System.out.println("folder:"+folder);*/
+
+
+        //测试删除文件
+        /*String key="upload/2023/01/11/xxx.pdf";
+        deleteObject(ossClient,bucketName,key);*/
+
+
+        //测试上传文件
+        /*String pathAndname = "C:\\Users\\Administrator\\Desktop\\测试文件上传\\xxx.pdf";
+        File file = new File(pathAndname);
+        //原始文件名:带后缀
+        String oldfilename = file.getName();
+        //新文件名:带后缀
+        String newfilename = "9065df0f3ab72419b36d2dec088e11d6.pdf";//可以自行生成随机唯一文件名
+        String newpath = "C:\\Users\\Administrator\\Desktop\\upload\\2023\\01\\11\\";
+        String ossPath = newpath + newfilename;
+        InputStream is = new FileInputStream(file);
+        String absolutePath = uploadFileOss(ossClient, bucketName, ossPath, is, newfilename);
+        System.out.println("absolutePath:"+absolutePath);*/
+
+
+        //测试获取文件url
+        /*String key="upload/2023/01/11/9065df0f3ab72419b36d2dec088e11d6.pdf";
+        String url = getUrl(ossClient, bucketName, key);
+        System.out.println("url:"+url);*/
+
+
+        //测试获取上传对象
+        /*String key = "upload/2023/01/11/9065df0f3ab72419b36d2dec088e11d6.pdf";
+        getObject(ossClient, bucketName, key);*/
+
+
+        //测试下载文件到本地
+        /*String key = "upload/2023/01/11/9065df0f3ab72419b36d2dec088e11d6.pdf";
+        String localFilePath = "C:\\Users\\Administrator\\Desktop\\oss-download\\xxx.pdf";
+        downloadFileOss(ossClient, bucketName, key, localFilePath);*/
+    }
+
+}

+ 54 - 0
slope-common/slope-common-core/src/main/java/com/sckw/core/utils/StringUtils.java

@@ -837,6 +837,60 @@ public class StringUtils {
         return stringBuffer.toString();
     }
 
+    /**
+     * 切割查询的数据
+     * @param list 需要切割的数据
+     * @param len 按照什么长度切割
+     * @param <T>
+     * @return
+     */
+    public static <T> List<List<T>> splitList(List<T> list, int len) {
+        if (list == null || list.size() == 0 || len < 1) {
+            return null;
+        }
+        List<List<T>> result = new ArrayList<List<T>>();
+        int size = list.size();
+        int count = (size + len - 1) / len;
+        for (int i = 0; i < count; i++) {
+            List<T> subList = list.subList(i * len, (Math.min((i + 1) * len, size)));
+            result.add(subList);
+        }
+        return result;
+    }
+
+    /**
+     * 集合平均分组
+     * @param source 源集合
+     * @param n 分成n个集合
+     * @param <T> 集合类型
+     * @return 平均分组后的集合
+     */
+    public static <T> List<List<T>> groupList(List<T> source, int n) {
+        if (source == null || source.size() == 0 || n < 1) {
+            return null;
+        }
+        if (source.size() < n) {
+            return Collections.singletonList(source);
+        }
+        List<List<T>> result = new ArrayList<List<T>>();
+        int number = source.size() / n;
+        int remaider = source.size() % n;
+        // 偏移量,每有一个余数分配,就要往右偏移一位
+        int offset = 0;
+        for (int i = 0; i < n;i++) {
+            List<T> list1 = null;
+            if (remaider > 0){
+                list1 = source.subList(i * number + offset,(i + 1) * number + offset + 1);
+                remaider--;
+                offset++;
+            }else {
+                list1 = source.subList(i * number + offset, (i+1) * number + offset);
+            }
+            result.add(list1);
+        }
+        return result;
+    }
+
     public static void main(String[] args) {
         Map<String, Object> map = new HashMap<>();
         map.put("projectName","项目名称");

+ 2 - 1
slope-common/slope-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -4,4 +4,5 @@ com.sckw.core.exception.GlobalSystemExceptionHandler
 com.sckw.core.config.MybatisPlusConfig
 com.sckw.core.config.JacksonConfig
 com.sckw.core.filter.ExceptionFilterConfig
-com.sckw.core.aspect.LogAspect
+com.sckw.core.aspect.LogAspect
+com.sckw.core.utils.FileUtils

+ 12 - 0
slope-common/slope-common-excel/pom.xml

@@ -31,6 +31,14 @@
             <artifactId>easyexcel</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <version>4.3.14.RELEASE</version>
+            <scope>test</scope>
+        </dependency>
+
+
         <!--cglib-->
         <dependency>
             <groupId>cglib</groupId>
@@ -52,5 +60,9 @@
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-context</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+        </dependency>
     </dependencies>
 </project>

+ 38 - 0
slope-common/slope-common-excel/src/main/java/com/sckw/excel/config/easyexcel/ExcelStyleHandler.java

@@ -0,0 +1,38 @@
+package com.sckw.excel.config.easyexcel;
+
+import com.alibaba.excel.metadata.Head;
+import com.alibaba.excel.write.metadata.style.WriteCellStyle;
+import com.alibaba.excel.write.metadata.style.WriteFont;
+import com.alibaba.excel.write.style.AbstractVerticalCellStyleStrategy;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+/**
+ * @author lfdc
+ * @description 自定义样式handler
+ * @date 2023-11-13 17:11:44
+ */
+public class ExcelStyleHandler extends AbstractVerticalCellStyleStrategy {
+
+    @Override
+    protected WriteCellStyle contentCellStyle(Head head) {
+        // 内容的策略
+        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
+        // 居中
+        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
+        // 背景白色
+        contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
+        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
+        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
+        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
+        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
+        WriteFont contentWriteFont = new WriteFont();
+        // 字体大小
+        contentWriteFont.setFontHeightInPoints((short) 12);
+        // 字体样式
+        contentWriteFont.setFontName("等线");
+        contentWriteCellStyle.setWriteFont(contentWriteFont);
+        return contentWriteCellStyle;
+    }
+}

+ 266 - 2
slope-common/slope-common-excel/src/main/java/com/sckw/excel/utils/ExcelUtil.java

@@ -3,26 +3,42 @@ package com.sckw.excel.utils;
 import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.ExcelWriter;
 import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.metadata.Head;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
 import com.alibaba.excel.write.metadata.WriteSheet;
+import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
+import com.alibaba.excel.write.metadata.style.WriteCellStyle;
+import com.alibaba.excel.write.metadata.style.WriteFont;
+import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
+import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
 import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
 import com.alibaba.fastjson.JSONObject;
+import com.aliyun.oss.ServiceException;
+import com.sckw.core.exception.BusinessException;
 import com.sckw.core.model.constant.Global;
 import com.sckw.core.model.constant.NumberConstant;
+import com.sckw.core.model.enums.FileEnum;
+import com.sckw.core.utils.FileUtils;
 import com.sckw.core.web.response.HttpResult;
 import com.sckw.excel.annotation.ExcelContext;
 import com.sckw.excel.annotation.ExcelSelected;
 import com.sckw.excel.config.easyexcel.*;
 import jakarta.servlet.http.HttpServletResponse;
+import lombok.Cleanup;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.ss.usermodel.*;
+import org.springframework.mock.web.MockMultipartFile;
 import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
+import java.io.*;
 import java.lang.reflect.Field;
 import java.net.URLEncoder;
 import java.time.LocalDateTime;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -191,6 +207,146 @@ public class ExcelUtil {
 
     }
 
+
+    /**
+     * 每个sheet的容量,即超过60000时就会把数据分sheet
+     */
+    private static final int PAGE_SIZE = 60000;
+
+
+    /**
+     * 导出报表(使用注解方式设置Excel头数据)
+     * 用于生成excel文件流并上传oss
+     *
+     * @param response   响应请求
+     * @param data       报表数据
+     * @param fileName   文件名字
+     * @param excelClass 报表实体类的Class(根据该Class的属性来设置Excel的头属性)
+     */
+    public static String exportByExcelUploadingToOss(HttpServletResponse response, List<?> data, String fileName, Class<?> excelClass) throws IOException {
+        @Cleanup ByteArrayOutputStream os = new ByteArrayOutputStream();
+        log.info("报表导出Size: " + data.size() + "条。");
+        String sheetName = excelClass.getAnnotation(ExcelContext.class).sheetName();
+        // 把查询到的数据按设置的sheet的容量进行切割
+        List<? extends List<?>> lists = com.sckw.core.utils.StringUtils.splitList(data, PAGE_SIZE);
+        // 设置响应头
+        ExcelUtil.setHead(response, fileName, excelClass);
+        // 格式化Excel数据
+        // EasyExcelBasic.formatExcel():设置Excel的格式
+        // EasyExcelBasic.ExcelWidthStyleStrategy():设置头部单元格宽度
+        ExcelWriter excelWriter = com.alibaba.excel.EasyExcel.write(os, excelClass)
+                .autoCloseStream(Boolean.FALSE)
+                .registerConverter(new LongStringConverter())
+                //设置导出excel的单元格格式为文本
+                .registerWriteHandler(new RowWriteHandlerImpl())
+                // 自定义列宽、行高
+                .registerWriteHandler(new CustomCellWeightWeightConfig())
+//                .registerWriteHandler(formatExcel())
+                .registerWriteHandler(new ExcelUtil.ExcelWidthStyleStrategy()).build();
+
+        // 浏览器访问url直接下载文件的方式
+        //ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), excelClass).registerWriteHandler(com.example.utils.easyexcel.EasyExcel.formatExcel()).registerWriteHandler(new com.example.utils.easyexcel.EasyExcel.ExcelWidthStyleStrategy()).build();
+
+        ExcelWriterSheetBuilder excelWriterSheetBuilder;
+        WriteSheet writeSheet;
+        for (int i = 1; i <= lists.size(); ++i) {
+            excelWriterSheetBuilder = new ExcelWriterSheetBuilder(excelWriter);
+            excelWriterSheetBuilder.sheetNo(i).sheetName(sheetName + i);
+            writeSheet = excelWriterSheetBuilder.build();
+            excelWriter.write(lists.get(i - 1), writeSheet);
+        }
+        // 必须要finish才会写入,不finish只会创建empty的文件
+        excelWriter.finish();
+
+        byte[] content = os.toByteArray();
+        @Cleanup InputStream is = new ByteArrayInputStream(content);
+
+        // 文件落地,
+        // @Cleanup:lombok关用来测试文件的格式和数据的完整性流注解
+        //FileOutputStream fileOutputStream = new FileOutputStream("/data/logs/" + fileName + ".xlsx");
+        //@Cleanup BufferedInputStream bis = new BufferedInputStream(is);
+        //@Cleanup BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
+        //byte[] buff = new byte[2048];
+        //int bytesRead;
+        //while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
+        //    bos.write(buff, 0, bytesRead);
+        // }
+        //log.info("文件落地磁盘");
+
+
+        // 文件上传到OSS
+        Map<String, String> map = FileUtils.uploadFileByInfo(is, fileName, FileEnum.FILE_STORE_TYPE_ALIYUN);
+        System.out.println(com.alibaba.fastjson2.JSONObject.toJSONString(map));
+        String ossAddressPrefix = FileUtils.getOSSAddressPrefix();
+        if (map != null && (map.get("filePath") != null)) {
+            ossAddressPrefix = ossAddressPrefix + map.get("filePath");
+        }
+        return ossAddressPrefix;
+    }
+
+    /**
+     * 设置响应头
+     *
+     * @param response 回应的请求数据
+     * @param fileName 文件名字
+     */
+    public static void setHead(HttpServletResponse response, String fileName, Class<?> excelClass) {
+        ExcelContext excelContext = excelClass.getAnnotation(ExcelContext.class);
+        response.setContentType("application/vnd.ms-excel");
+        response.setCharacterEncoding("utf-8");
+        try {
+            // 这里URLEncoder.encode可以防止中文乱码
+            buildResponse(response, excelContext.fileName());
+            fileName = URLEncoder.encode(fileName, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+            log.error("编码异常");
+        }
+        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
+
+    }
+
+    /**
+     * 设置Excel的格式
+     *
+     * @return 格式化后的Excel
+     */
+    public static HorizontalCellStyleStrategy formatExcel() {
+        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
+        headWriteCellStyle.setFillBackgroundColor(IndexedColors.WHITE.getIndex());
+        WriteFont headWriteFont = new WriteFont();
+        headWriteFont.setFontHeightInPoints((short) 10);
+        headWriteCellStyle.setWriteFont(headWriteFont);
+        // 内容的策略
+        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
+        WriteFont contentWriteFont = new WriteFont();
+        // 字体大小
+        contentWriteFont.setFontHeightInPoints((short) 10);
+        contentWriteCellStyle.setWriteFont(contentWriteFont);
+        // 设置自动换行
+        contentWriteCellStyle.setWrapped(true);
+        // 设置垂直居中
+        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+        // 设置水平居中
+        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
+
+        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
+
+    }
+
+    /**
+     * 设置头部单元格宽度
+     */
+    public static class ExcelWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {
+
+        @Override
+        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
+            // 设置宽度
+            Sheet sheet = writeSheetHolder.getSheet();
+            sheet.setColumnWidth(cell.getColumnIndex(), 5000);
+        }
+    }
+
     //    private static void buildResponse(HttpServletResponse response, String fileName,HttpServletRequest request) throws UnsupportedEncodingException {
 //        response.reset();
 //        response.setContentType("application/octet-stream");
@@ -260,4 +416,112 @@ public class ExcelUtil {
         return selectedMap;
     }
 
+    /**
+     * 导出Excel返回FileInputStream
+     */
+    public static FileInputStream exportExcelStream(Class<?> clazz, List<?> list) {
+        try {
+            // 临时目录 临时文件名
+            String tmp = System.getProperty("java.io.tmpdir");
+            String fileName = String.valueOf(new Date().getTime());
+            File file = new File(tmp + fileName + ".xlsx");
+            FileOutputStream fileOutputStream = new FileOutputStream(file);
+            ExcelWriter excelWriter = EasyExcel.write(fileOutputStream)
+                    .registerWriteHandler(new CustomCellWeightWeightConfig())
+                    .registerWriteHandler(new RowWriteHandlerImpl())
+                    .registerWriteHandler(new ExcelStyleHandler())
+                    .build();
+            WriteSheet writeSheet = EasyExcel.writerSheet(1, fileName).head(clazz).build();
+            excelWriter.write(list, writeSheet);
+            excelWriter.finish();
+            return new FileInputStream(file);
+        } catch (Exception e) {
+            throw new ServiceException("导出Excel异常");
+        }
+    }
+
+
+    public static <T> MultipartFile exportReturnToFileNew(List<T> data, Class<T> clazz, HttpServletResponse response) throws IOException {
+        Assert.notNull(clazz, "clazz can't be null");
+        Assert.isTrue(data != null && !data.isEmpty(), "data can't be empty");
+        ExcelContext excelContext = clazz.getAnnotation(ExcelContext.class);
+        buildResponse(response, excelContext.fileName());
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        EasyExcel.write(byteArrayOutputStream)
+                .autoCloseStream(Boolean.FALSE)
+                .registerConverter(new LongStringConverter())
+                //设置导出excel的单元格格式为文本
+                .registerWriteHandler(new RowWriteHandlerImpl())
+                // 自定义列宽、行高
+                .registerWriteHandler(new CustomCellWeightWeightConfig())
+                .sheet(excelContext.sheetName())
+                .doWrite(data);
+
+        MultipartFile file = new MockMultipartFile("file", excelContext.sheetName() + ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", byteArrayOutputStream.toByteArray());
+//        String fileName = URLEncoder.encode(excelContext.fileName() + "-" + DateUtil.localDateTimeToString(LocalDateTime.now()), "UTF-8").replaceAll("\\+", "%20");
+//        MultipartFile multipartFile = new MockMultipartFile("file", fileName + ".xlsx",
+//                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+//                byteArrayOutputStream.toByteArray());
+        return file;
+    }
+
+    /**
+     * 默认样式策略策略
+     *
+     * @return
+     */
+    private static HorizontalCellStyleStrategy defaultStylePolicyPolicy() {
+        // 头的策略
+        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
+        // 背景设置为浅蓝色
+        headWriteCellStyle.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
+        //设置水平对齐方式
+        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
+        //设置字体为微软雅黑
+        WriteFont headWriteFont = new WriteFont();
+        headWriteFont.setFontName("宋体");
+        headWriteCellStyle.setWriteFont(headWriteFont);
+
+        // 内容的策略
+        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
+        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
+        //设置字体为微软雅黑
+        WriteFont contentWriteFont = new WriteFont();
+        contentWriteFont.setFontName("宋体");
+        contentWriteCellStyle.setWriteFont(contentWriteFont);
+
+        // 这个策略是 头是头的样式 内容是内容的样式
+        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
+    }
+
+    public static <T> File exportReturnToFile(List<T> data, Class<T> clazz, String fileName) {
+        File file = null;
+        //名称拆分前后缀
+        //1.判断文件名是否有扩展
+        try {
+            if (StringUtils.isBlank(fileName)) {
+                file = File.createTempFile(fileName, "");
+            } else {
+                String[] parts = fileName.split("\\.");
+                String extension = "." + parts[parts.length - 1];
+                String name = fileName.substring(0, fileName.length() - extension.length() - 1);
+                file = File.createTempFile(name, extension);
+            }
+        } catch (IOException e) {
+            log.error("文件生成失败,文件名异常.异常信息:{}", e.getMessage());
+            throw new BusinessException("文件生成失败,文件名异常");
+        }
+
+        HorizontalCellStyleStrategy horizontalCellStyleStrategy = defaultStylePolicyPolicy();
+
+        //导出
+        EasyExcel.write(file, clazz)
+                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
+                .registerWriteHandler(horizontalCellStyleStrategy)
+                .sheet()
+                .doWrite(data);
+        return file;
+    }
+
+
 }

+ 42 - 0
slope-common/slope-common-oss/pom.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.sckw</groupId>
+        <artifactId>slope-common</artifactId>
+        <version>1.0.0</version>
+    </parent>
+
+    <artifactId>slope-common-oss</artifactId>
+
+    <properties>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.sckw</groupId>
+            <artifactId>slope-common-core</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-context</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 25 - 0
slope-common/slope-common-oss/src/main/java/com/sckw/oss/config/FileListConfig.java

@@ -0,0 +1,25 @@
+package com.sckw.oss.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @author lfdc
+ * @description 文件上传获取配置yml信息
+ * @date 2023-08-10 09:08:41
+ */
+@Getter
+@Setter
+@Component
+@RefreshScope
+@ConfigurationProperties(prefix = "file.list")
+public class FileListConfig {
+    List<String> oss;
+    List<String> aliyun;
+    List<String> qiniu;
+}

+ 34 - 0
slope-common/slope-common-oss/src/main/java/com/sckw/oss/config/FileOssConfig.java

@@ -0,0 +1,34 @@
+package com.sckw.oss.config;
+
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author lfdc
+ * @description 文件上传获取配置yml信息
+ * @date 2023-08-10 09:08:41
+ */
+@Getter
+@Setter
+@Component
+@RefreshScope
+@ConfigurationProperties(prefix = "aliyun.oss")
+public class FileOssConfig {
+    private OssData oss;
+
+    @Data
+    public static class OssData {
+
+        private String endpoint;
+
+        private String accessKeyId;
+
+        private String secret;
+
+        public String bucket;
+    }
+}

+ 43 - 2
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/controller/AlarmController.java

@@ -2,10 +2,17 @@ package com.sckw.slope.detection.controller;
 
 import com.alibaba.fastjson2.JSONObject;
 import com.sckw.core.annotation.Log;
+import com.sckw.core.model.vo.BaseList;
+import com.sckw.core.model.vo.PublicBaseList;
+import com.sckw.core.web.constant.HttpStatus;
 import com.sckw.core.web.response.HttpResult;
+import com.sckw.excel.annotation.ExcelContext;
+import com.sckw.excel.utils.ExcelUtil;
 import com.sckw.slope.detection.model.param.AlarmLogThresholdQuery;
+import com.sckw.slope.detection.model.vo.excel.KwsAlarmExportVO;
 import com.sckw.slope.detection.service.KwsAlarmService;
 import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.Valid;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -14,6 +21,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  * @author lfdc
  * @description 报警Controller
@@ -31,13 +43,42 @@ public class AlarmController {
     @RequestMapping(name = "告警日志-系统日志", value = "/logSelectAll", method = RequestMethod.POST)
     public HttpResult logSelectAll(@Valid @RequestBody AlarmLogThresholdQuery query) {
         log.info("告警日志-系统日志 logSelectAll param {}", JSONObject.toJSONString(query));
-       return HttpResult.ok(kwsAlarmService.logSelectAll(query));
+        return HttpResult.ok(kwsAlarmService.logSelectAll(query));
     }
 
     @Log(description = "告警查询-分页")
     @RequestMapping(name = "告警查询-分页", value = "/select", method = RequestMethod.POST)
     public HttpResult select(@Valid @RequestBody AlarmLogThresholdQuery query, HttpServletRequest request) {
         log.info("告警查询-分页 select param {}", JSONObject.toJSONString(query));
-        return HttpResult.ok(kwsAlarmService.select(query,request));
+        return HttpResult.ok(kwsAlarmService.select(query, request));
+    }
+
+    @Log(description = "告警已读")
+    @RequestMapping(name = "告警已读", value = "/read", method = RequestMethod.POST)
+    public HttpResult read(@Valid @RequestBody BaseList baseList, HttpServletRequest request) {
+        log.info("告警已读 read param {}", JSONObject.toJSONString(baseList));
+        return kwsAlarmService.read(baseList, request);
+    }
+
+    @Log(description = "告警导出")
+    @RequestMapping(name = "告警导出", value = "/export", method = RequestMethod.POST)
+    public HttpResult export(@Valid @RequestBody AlarmLogThresholdQuery query, HttpServletRequest request, HttpServletResponse response) throws IOException {
+        log.info("告警导出 export param {}", JSONObject.toJSONString(query));
+        List<KwsAlarmExportVO> export = kwsAlarmService.export(query, request, response);
+        if (org.springframework.util.CollectionUtils.isEmpty(export)) {
+            return HttpResult.ok(HttpStatus.SUCCESS_CODE, "暂无数据,请确认");
+        }
+        ExcelContext excelContext = KwsAlarmExportVO.class.getAnnotation(ExcelContext.class);
+        String filePath = ExcelUtil.exportByExcelUploadingToOss(response, export, excelContext.fileName() + ".xlsx", KwsAlarmExportVO.class);
+        Map<String, String> filePathMap = new HashMap<>();
+        filePathMap.put("filePath", filePath);
+        return HttpResult.ok(HttpStatus.SUCCESS_CODE, "导出成功", filePathMap);
+    }
+
+    @Log(description = "告警日志-告警明细")
+    @RequestMapping(name = "告警日志-告警明细", value = "/thresholdDetail", method = RequestMethod.POST)
+    public HttpResult thresholdDetail(@Valid @RequestBody PublicBaseList baseList, HttpServletRequest request) {
+        log.info("告警日志-告警明细 threshold_detail param {}", baseList);
+        return HttpResult.ok(kwsAlarmService.thresholdDetail(baseList, request));
     }
 }

+ 1 - 1
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/controller/LogController.java

@@ -46,6 +46,6 @@ public class LogController {
     @Log(description = "日志查询-元数据日志")
     @RequestMapping(name = "日志查询-元数据日志", value = "/selectMetadata", method = RequestMethod.GET)
     public HttpResult selectMetadata(@RequestParam(("page")) Integer page , @RequestParam("pageSize") Integer pageSize, HttpServletRequest request) {
-        return logService.selectMetadata(page,pageSize,request);
+        return HttpResult.ok(logService.selectMetadata(page,pageSize,request));
     }
 }

+ 20 - 0
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/dao/mysql/KwsAlarmDetailMapper.java

@@ -0,0 +1,20 @@
+package com.sckw.slope.detection.dao.mysql;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.sckw.slope.detection.model.dos.mysql.KwsAlarmDetail;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+@DS("mysql")
+public interface KwsAlarmDetailMapper extends BaseMapper<KwsAlarmDetail> {
+    int deleteByPrimaryKey(Long id);
+
+    int insertSelective(KwsAlarmDetail record);
+
+    KwsAlarmDetail selectByPrimaryKey(Long id);
+
+    int updateByPrimaryKeySelective(KwsAlarmDetail record);
+
+    int updateByPrimaryKey(KwsAlarmDetail record);
+}

+ 1 - 0
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/dao/tdengine/SlopeDataMapper.java

@@ -36,4 +36,5 @@ public interface SlopeDataMapper extends BaseMapper<SlopeData> {
 
     List<SlopeDataVo> selectListByMaster(@Param("page") Integer page, @Param("pageSize") Integer pageSize);
 
+    List<SlopeDataVo> selectListByMasterCount(Integer newPage, Integer pageSize);
 }

+ 11 - 35
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/dos/mysql/KwsAlarm.java

@@ -17,34 +17,30 @@ import java.time.LocalDateTime;
 public class KwsAlarm implements Serializable {
     private Long id;
 
-    /**
-     * 触发的id(阈值id或者设备id)
-     */
-    private Long pid;
+
 
     /**
      * 企业id
      */
     private String companyId;
 
+    /**
+     * 矿山id
+     */
     private String mountainId;
 
-
-    private String projectId;
     /**
-     * 告警标题
+     * 项目id
      */
-    private String title;
-
+    private String projectId;
     /**
-     * 告警触发数值
+     * 设备id
      */
-    private String val;
-
+    private Long deviceId;
     /**
-     * 告警内容
+     * 告警标题
      */
-    private String content;
+    private String title;
 
     /**
      * 告警等级
@@ -56,21 +52,6 @@ public class KwsAlarm implements Serializable {
      */
     private Integer type;
 
-    /**
-     * 纬度
-     */
-    private String lat;
-
-    /**
-     * 经度
-     */
-    private String lng;
-
-    /**
-     * 海拔
-     */
-    private String alt;
-
     /**
      * 创建时间
      */
@@ -83,15 +64,10 @@ public class KwsAlarm implements Serializable {
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
     private LocalDateTime updateTime;
 
-    /**
-     * 触发次数
-     */
-    private Integer triggerTimes;
-
     /**
      * 状态
      */
-    private Byte status;
+    private int status;
 
     private static final long serialVersionUID = 1L;
 

+ 93 - 0
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/dos/mysql/KwsAlarmDetail.java

@@ -0,0 +1,93 @@
+package com.sckw.slope.detection.model.dos.mysql;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 告警详情
+ */
+@Data
+@TableName("kws_alarm_detail")
+public class KwsAlarmDetail implements Serializable {
+
+    private Long id;
+
+
+    private String mountainId;
+
+
+    private String companyId;
+
+    private Long projectId;
+
+    /**
+     * 告警id
+     */
+    private Long alarmId;
+
+    private Long pid;
+
+    /**
+     * 告警等级
+     */
+    private Integer level;
+
+    private String val;
+
+    private String itemName;
+
+    /**
+     * 告警标题
+     */
+
+    private String title;
+
+    /**
+     * 告警内容
+     */
+
+    private String content;
+
+    /**
+     * 1数据告警  2设备告警
+     */
+    private Integer type;
+
+    /**
+     * 纬度
+     */
+
+    private String lat;
+
+    /**
+     * 经度
+     */
+
+    private String lng;
+
+    /**
+     * 海拔
+     */
+
+    private String alt;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 修改时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 状态
+     */
+    private int status;
+
+    private static final long serialVersionUID = 1L;
+}

+ 25 - 0
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/param/AlarmLogThresholdQuery.java

@@ -18,14 +18,39 @@ public class AlarmLogThresholdQuery implements Serializable {
      */
     private String projectId;
 
+    /**
+     * 项目名称
+     */
+    private String projectName;
+
     @NotNull(message = "当前页不能为空")
     private int page;
 
     @NotNull(message = "每页条数不能为空")
     private int pageSize;
 
+    /**
+     * 告警级别
+     */
+    private int alarmLevel;
+
+    /**
+     * 告警明细
+     */
+    private String alarmInfo;
+
     /**
      * 设备id
      */
     private String deviceId;
+
+    /**
+     * 设备名称
+     */
+    private String deviceName;
+
+    /**
+     * 状态(告警类型(1:当前,2历史))
+     */
+    private int status;
 }

+ 1 - 2
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/param/StatementQuery.java

@@ -1,7 +1,6 @@
 package com.sckw.slope.detection.model.param;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
-import jakarta.validation.constraints.NotBlank;
 import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
@@ -19,7 +18,7 @@ public class StatementQuery {
     /**
      * 项目id
      */
-    @NotBlank(message = "项目id不能为空")
+//    @NotBlank(message = "项目id不能为空")
     private String projectId;
     /**
      * 项目名称

+ 1 - 1
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/vo/AlarmLogThresholdVO.java

@@ -38,7 +38,7 @@ public class AlarmLogThresholdVO implements Serializable {
     /**
      * 告警等级
      */
-    private Integer level;
+    private String level;
 
     /**
      * 创建时间

+ 33 - 19
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/vo/KwsAlarmVO.java

@@ -13,12 +13,11 @@ import java.time.LocalDateTime;
  */
 @Data
 public class KwsAlarmVO implements Serializable {
-    private Long id;
 
     /**
      * 触发的id(阈值id或者设备id)
      */
-    private Long pid;
+    private Long id;
 
     /**
      * 企业id
@@ -27,12 +26,11 @@ public class KwsAlarmVO implements Serializable {
 
     private String mountainId;
 
-
     private String projectId;
-    /**
-     * 告警标题
-     */
-    private String title;
+//    /**
+//     * 告警标题
+//     */
+//    private String title;
 
     /**
      * 告警触发数值
@@ -47,12 +45,12 @@ public class KwsAlarmVO implements Serializable {
     /**
      * 告警等级
      */
-    private Integer level;
+    private String level;
 
     /**
      * 1数据告警  2设备告警
      */
-    private Integer type;
+    private String type;
 
     /**
      * 纬度
@@ -70,26 +68,42 @@ public class KwsAlarmVO implements Serializable {
     private String alt;
 
     /**
-     * 创建时间
+     * 触发次数
      */
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
-    private LocalDateTime createTime;
+    private Integer triggerTimes;
 
     /**
-     * 创建时间
+     * 状态
      */
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
-    private LocalDateTime updateTime;
+    private int status;
 
     /**
-     * 触发次数
+     * 设备名称
      */
-    private Integer triggerTimes;
+    private String deviceName;
 
     /**
-     * 状态
+     * 项目名称
      */
-    private Byte status;
+    private String projectName;
+
+    /**
+     * 告警类型
+     */
+    private String alarmLevel;
+
+    /**
+     * 开始时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+    private LocalDateTime startTime;
+
+    /**
+     * 结束时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
+    private LocalDateTime endTime;
+
 
     private static final long serialVersionUID = 1L;
 }

+ 39 - 0
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/vo/ThresholdDeviceLogVO.java

@@ -0,0 +1,39 @@
+package com.sckw.slope.detection.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author lfdc
+ * @description 数据看板-数据中心-告警通知
+ * @date 2023-11-13 08:11:41
+ */
+@Data
+public class ThresholdDeviceLogVO implements Serializable {
+    /**
+     * id : ID
+     * deviceName : 设备名称
+     * projectName : 项目名称
+     * alarmLevel : 告警类型
+     * type : 1数据告警  2设备告警
+     * title : 标题
+     * triggerTimes : 触发次数
+     * startTime : 开始时间
+     * endTime : 结束时间
+     * status : 状态
+     */
+
+    private String id;
+    private String deviceName;
+    private String projectName;
+    private String alarmLevel;
+    private String type;
+    private String title;
+    private String triggerTimes;
+    private String startTime;
+    private String endTime;
+    private String status;
+
+
+}

+ 47 - 0
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/vo/ThresholdRecordDetailVO.java

@@ -0,0 +1,47 @@
+package com.sckw.slope.detection.model.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * @author lfdc
+ * @description 告警记录明细数据
+ * @date 2023-11-14 14:11:06
+ */
+@Data
+public class ThresholdRecordDetailVO implements Serializable {
+    /**
+     * ID
+     */
+    private Long id;
+    /**
+     * 告警类型
+     */
+    private String alarmLevel;
+    /**
+     * 监测类型
+     */
+    private String type;
+    /**
+     * 当前值
+     */
+    private String value;
+    private String itemName;
+    /**
+     * 短信手机号
+     */
+    private String phone;
+    /**
+     * 告警地点
+     */
+    private String location;
+    /**
+     * 告警产生时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+}

+ 122 - 0
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/model/vo/excel/KwsAlarmExportVO.java

@@ -0,0 +1,122 @@
+package com.sckw.slope.detection.model.vo.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.sckw.excel.annotation.ExcelContext;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * @author lfdc
+ * @description 告警导出vo
+ * @date 2023-11-13 10:11:57
+ */
+@Data
+@ExcelContext(fileName = "告警数据", sheetName = "告警数据")
+public class KwsAlarmExportVO implements Serializable {
+    /**
+     * 触发的id(阈值id或者设备id)
+     */
+    @ExcelProperty("id")
+    private Long id;
+
+    /**
+     * 企业id
+     */
+    private String companyId;
+
+    private String mountainId;
+
+    private String projectId;
+//    /**
+//     * 告警标题
+//     */
+//    private String title;
+
+    /**
+     * 告警触发数值
+     */
+    @ExcelProperty("告警触发数值")
+    private String val;
+
+    /**
+     * 告警内容
+     */
+    @ExcelProperty("告警内容")
+    private String content;
+
+    /**
+     * 告警等级
+     */
+    @ExcelProperty("告警等级")
+    private String level;
+
+    /**
+     * 1数据告警  2设备告警
+     */
+    @ExcelProperty("告警类型")
+    private String type;
+
+    /**
+     * 纬度
+     */
+    private String lat;
+
+    /**
+     * 经度
+     */
+    private String lng;
+
+    /**
+     * 海拔
+     */
+    private String alt;
+
+    /**
+     * 触发次数
+     */
+    @ExcelProperty("触发次数")
+    private Integer triggerTimes;
+
+    /**
+     * 状态
+     */
+    private int status;
+
+    /**
+     * 设备名称
+     */
+    @ExcelProperty("设备名称")
+    private String deviceName;
+
+    /**
+     * 项目名称
+     */
+    @ExcelProperty("项目名称")
+    private String projectName;
+
+    /**
+     * 告警类型
+     */
+    @ExcelProperty("告警类型")
+    private String alarmLevel;
+
+    /**
+     * 开始时间
+     */
+    @ExcelProperty("开始时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime startTime;
+
+    /**
+     * 结束时间
+     */
+    @ExcelProperty("结束时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime endTime;
+
+
+    private static final long serialVersionUID = 1L;
+}

+ 147 - 26
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/KwsAlarmService.java

@@ -1,22 +1,28 @@
 package com.sckw.slope.detection.service;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
+import com.sckw.core.model.enums.DictEnum;
 import com.sckw.core.model.page.PageRes;
-import com.sckw.slope.detection.dao.mysql.KwsAlarmMapper;
-import com.sckw.slope.detection.dao.mysql.KwsDeviceMapper;
-import com.sckw.slope.detection.dao.mysql.KwsProjectMapper;
-import com.sckw.slope.detection.model.dos.mysql.KwsAlarm;
-import com.sckw.slope.detection.model.dos.mysql.KwsDevice;
-import com.sckw.slope.detection.model.dos.mysql.KwsProject;
+import com.sckw.core.model.vo.BaseList;
+import com.sckw.core.model.vo.PublicBaseList;
+import com.sckw.core.web.response.HttpResult;
+import com.sckw.slope.detection.dao.mysql.*;
+import com.sckw.slope.detection.model.dos.mysql.*;
 import com.sckw.slope.detection.model.dto.HeaderData;
+import com.sckw.slope.detection.model.dto.SystemDict;
 import com.sckw.slope.detection.model.param.AlarmLogThresholdQuery;
 import com.sckw.slope.detection.model.vo.AlarmLogThresholdVO;
 import com.sckw.slope.detection.model.vo.KwsAlarmVO;
+import com.sckw.slope.detection.model.vo.ThresholdRecordDetailVO;
+import com.sckw.slope.detection.model.vo.excel.KwsAlarmExportVO;
 import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
@@ -24,7 +30,6 @@ import org.springframework.util.CollectionUtils;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 /**
  * @author lfdc
@@ -41,6 +46,9 @@ public class KwsAlarmService {
     @Autowired
     KwsDeviceMapper deviceMapper;
 
+    @Autowired
+    KwsThresholdMapper thresholdMapper;
+
     @Autowired
     KwsProjectMapper projectMapper;
 
@@ -57,6 +65,7 @@ public class KwsAlarmService {
         if (CollectionUtils.isEmpty(kwsAlarms)) {
             return PageRes.build(info, kwsAlarms);
         }
+        Map<String, SystemDict> thresholdLevel = commonService.getDictByDictCode(DictEnum.THRESHOLD_LEVEL);
         if (!CollectionUtils.isEmpty(kwsAlarms)) {
             kwsAlarms.forEach(KwsAlarm -> {
                 AlarmLogThresholdVO vo = new AlarmLogThresholdVO();
@@ -66,8 +75,9 @@ public class KwsAlarmService {
                 KwsProject project = projectMapper.selectById(Long.parseLong(KwsAlarm.getProjectId()));
                 vo.setProjectId(KwsAlarm.getProjectId());
                 vo.setProjectName(project == null ? null : project.getName());
-                vo.setContent(KwsAlarm.getContent());
-                vo.setLevel(KwsAlarm.getLevel());
+//                vo.setContent(KwsAlarm.getContent());
+                vo.setLevel(KwsAlarm.getLevel() == null ? null :
+                        (thresholdLevel == null ? String.valueOf(KwsAlarm.getLevel()) : thresholdLevel.get(KwsAlarm.getLevel()).getLabel()));
                 vo.setCreateTime(KwsAlarm.getCreateTime());
                 list.add(vo);
             });
@@ -78,30 +88,141 @@ public class KwsAlarmService {
     public PageRes select(AlarmLogThresholdQuery query, HttpServletRequest request) {
         HeaderData headerData = commonService.getHeaderData(request);
         PageHelper.startPage(query.getPage(), query.getPageSize());
-        List<KwsAlarm> list = alarmMapper.selectList(new LambdaQueryWrapper<KwsAlarm>()
-                .eq(StringUtils.isNotBlank(headerData.getMountainId()), KwsAlarm::getMountainId, headerData.getMountainId()));
+
+        LambdaQueryWrapper<KwsAlarm> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StringUtils.isNotBlank(headerData.getMountainId()), KwsAlarm::getMountainId, headerData.getMountainId())
+                .eq(KwsAlarm::getStatus, query.getStatus());
+        if (StringUtils.isNotBlank(query.getProjectId())) {
+            wrapper.eq(KwsAlarm::getProjectId, Long.parseLong(query.getProjectId()));
+        }
+        List<KwsAlarm> list = alarmMapper.selectList(wrapper);
+        List<KwsAlarmVO> alarmVOS = new ArrayList<>();
         PageInfo<KwsAlarm> info = new PageInfo<KwsAlarm>();
         if (CollectionUtils.isEmpty(list)) {
-            return PageRes.build(info, list);
+            return PageRes.build(info, alarmVOS);
         }
-        Map<Integer, List<KwsAlarm>> listMap = list.stream().collect(Collectors.groupingBy(KwsAlarm::getType));
-        List<KwsAlarm> kwsAlarms = new ArrayList<>();
-        List<KwsAlarmVO> alarmVOS = new ArrayList<>();
-        if (listMap.get(1) != null) {
-            kwsAlarms = listMap.get(1);
-            for (KwsAlarm kwsAlarm : kwsAlarms) {
-                Long deviceId = kwsAlarm.getPid();
-                KwsDevice kwsDevice = deviceMapper.selectById(deviceId);
-                KwsProject project = projectMapper.selectById(Long.parseLong(kwsAlarm.getProjectId()));
+        Map<String, SystemDict> thresholdLevel = commonService.getDictByDictCode(DictEnum.THRESHOLD_LEVEL);
+        Map<String, SystemDict> alarmType = commonService.getDictByDictCode(DictEnum.ALARM_TYPE);
+        Map<String, SystemDict> alarmDetailType = commonService.getDictByDictCode(DictEnum.ALARM_DETAIL_TYPE);
+        for (KwsAlarm kwsAlarm : list) {
+            KwsDevice kwsDevice = deviceMapper.selectOne(new LambdaQueryWrapper<KwsDevice>()
+                    .eq(StringUtils.isNotBlank(headerData.getMountainId()), KwsDevice::getMountainId, headerData.getMountainId())
+                    .eq(KwsDevice::getId, kwsAlarm.getDeviceId()));
+            KwsProject project = projectMapper.selectOne(new LambdaQueryWrapper<KwsProject>()
+                    .eq(KwsProject::getId, Long.parseLong(kwsAlarm.getProjectId()))
+                    .eq(StringUtils.isNotBlank(headerData.getMountainId()), KwsProject::getMountainId, headerData.getMountainId())
+            );
+            KwsAlarmVO vo = new KwsAlarmVO();
+            BeanUtils.copyProperties(kwsAlarm, vo);
+            vo.setLevel(kwsAlarm.getLevel() == null ? null :
+                    (thresholdLevel == null ? String.valueOf(kwsAlarm.getLevel()) : thresholdLevel.get(String.valueOf(kwsAlarm.getLevel())).getLabel()));
+            vo.setType(kwsAlarm.getType() == null ? null :
+                    (alarmType == null ? String.valueOf(kwsAlarm.getType()) : alarmType.get(String.valueOf(kwsAlarm.getType())).getLabel()));
+            vo.setDeviceName(kwsDevice == null ? kwsAlarm.getDeviceId().toString() : kwsDevice.getName());
+            vo.setProjectName(project == null ? kwsAlarm.getProjectId() : project.getName());
+            vo.setAlarmLevel(kwsAlarm.getTitle() == null ? null :
+                    (alarmDetailType == null ? kwsAlarm.getTitle() : alarmDetailType.get(kwsAlarm.getTitle()).getLabel()));
+            vo.setStartTime(kwsAlarm.getCreateTime());
+            vo.setEndTime(kwsAlarm.getUpdateTime());
+            Long count = alarmDetailMapper.selectCount(new LambdaQueryWrapper<KwsAlarmDetail>().eq(KwsAlarmDetail::getAlarmId, kwsAlarm.getId()));
+            vo.setTriggerTimes(count.intValue());
+            alarmVOS.add(vo);
+        }
+//        Map<Integer, List<KwsAlarm>> listMap = list.stream().collect(Collectors.groupingBy(KwsAlarm::getType));
+        return PageRes.build(info, alarmVOS);
+    }
 
-            }
+    public HttpResult read(BaseList baseList, HttpServletRequest request) {
+        String ids = baseList.getIds();
+        List<Long> list = com.sckw.core.utils.StringUtils.splitStrToList(ids, Long.class);
+        list.forEach(id -> {
+            int update = alarmMapper.update(null, new LambdaUpdateWrapper<KwsAlarm>()
+                    .eq(KwsAlarm::getStatus, 1)
+            );
+        });
+        return HttpResult.ok("消息已读");
+    }
+
+    public List<KwsAlarmExportVO> export(AlarmLogThresholdQuery query, HttpServletRequest request, HttpServletResponse response) {
+        HeaderData headerData = commonService.getHeaderData(request);
+        LambdaQueryWrapper<KwsAlarm> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StringUtils.isNotBlank(headerData.getMountainId()), KwsAlarm::getMountainId, headerData.getMountainId())
+                .eq(KwsAlarm::getStatus, query.getStatus());
+        if (StringUtils.isNotBlank(query.getProjectId())) {
+            wrapper.eq(KwsAlarm::getProjectId, Long.parseLong(query.getProjectId()));
+        }
+        List<KwsAlarm> list = alarmMapper.selectList(wrapper);
+        List<KwsAlarmExportVO> alarmVOS = new ArrayList<>();
+        if (CollectionUtils.isEmpty(list)) {
+            return alarmVOS;
         }
-        if (listMap.get(2) != null) {
-            kwsAlarms = listMap.get(2);
+        Map<String, SystemDict> thresholdLevel = commonService.getDictByDictCode(DictEnum.THRESHOLD_LEVEL);
+        Map<String, SystemDict> alarmType = commonService.getDictByDictCode(DictEnum.ALARM_TYPE);
+        Map<String, SystemDict> alarmDetailType = commonService.getDictByDictCode(DictEnum.ALARM_DETAIL_TYPE);
+        for (KwsAlarm kwsAlarm : list) {
+            KwsDevice kwsDevice = deviceMapper.selectOne(new LambdaQueryWrapper<KwsDevice>()
+                    .eq(StringUtils.isNotBlank(headerData.getMountainId()), KwsDevice::getMountainId, headerData.getMountainId())
+                    .eq(KwsDevice::getId, kwsAlarm.getDeviceId()));
+            KwsProject project = projectMapper.selectOne(new LambdaQueryWrapper<KwsProject>()
+                    .eq(KwsProject::getId, Long.parseLong(kwsAlarm.getProjectId()))
+                    .eq(StringUtils.isNotBlank(headerData.getMountainId()), KwsProject::getMountainId, headerData.getMountainId())
+            );
+            KwsAlarmExportVO vo = new KwsAlarmExportVO();
+            BeanUtils.copyProperties(kwsAlarm, vo);
+            vo.setLevel(kwsAlarm.getLevel() == null ? null :
+                    (thresholdLevel == null ? String.valueOf(kwsAlarm.getLevel()) : thresholdLevel.get(String.valueOf(kwsAlarm.getLevel())).getLabel()));
+            vo.setType(kwsAlarm.getType() == null ? null :
+                    (alarmType == null ? String.valueOf(kwsAlarm.getType()) : alarmType.get(String.valueOf(kwsAlarm.getType())).getLabel()));
+            vo.setDeviceName(kwsDevice == null ? kwsAlarm.getDeviceId().toString() : kwsDevice.getName());
+            vo.setProjectName(project == null ? kwsAlarm.getProjectId() : project.getName());
+            vo.setAlarmLevel(kwsAlarm.getTitle() == null ? null :
+                    (alarmDetailType == null ? kwsAlarm.getTitle() : alarmDetailType.get(kwsAlarm.getTitle()).getLabel()));
+            vo.setStartTime(kwsAlarm.getCreateTime());
+            vo.setEndTime(kwsAlarm.getUpdateTime());
+            Long count = alarmDetailMapper.selectCount(new LambdaQueryWrapper<KwsAlarmDetail>().eq(KwsAlarmDetail::getAlarmId, kwsAlarm.getId()));
+            vo.setTriggerTimes(count.intValue());
+            alarmVOS.add(vo);
         }
-        if (!CollectionUtils.isEmpty(kwsAlarms) && kwsAlarms.size() > 0) {
+        return alarmVOS;
+    }
+
+    @Autowired
+    KwsAlarmDetailMapper alarmDetailMapper;
 
+    public PageRes thresholdDetail(PublicBaseList baseList, HttpServletRequest request) {
+        String id = baseList.getId();
+        KwsAlarm kwsAlarm = alarmMapper.selectById(id);
+        PageHelper.startPage(baseList.getPage(), baseList.getPageSize());
+        List<KwsAlarmDetail> detailList = alarmDetailMapper.selectList(new LambdaQueryWrapper<KwsAlarmDetail>()
+                .eq(KwsAlarmDetail::getAlarmId, Long.parseLong(id)));
+        PageInfo<ThresholdRecordDetailVO> info = new PageInfo();
+        if (!CollectionUtils.isEmpty(detailList)) {
+            return PageRes.build(info, detailList);
         }
-        return null;
+        List<ThresholdRecordDetailVO> list = new ArrayList<>();
+        Map<String, SystemDict> dictByDictCode = commonService.getDictByDictCode(DictEnum.MODEL_PART);
+        Map<String, SystemDict> alarmType = commonService.getDictByDictCode(DictEnum.ALARM_TYPE);
+        if ("1".equals(kwsAlarm.getType())) {
+
+        } else {
+            for (KwsAlarmDetail detail : detailList) {
+                Long pid = detail.getPid();
+                KwsThreshold kwsThreshold = thresholdMapper.selectById(pid);
+                ThresholdRecordDetailVO vo = new ThresholdRecordDetailVO();
+                vo.setId(kwsThreshold.getId());
+                vo.setAlarmLevel(detail.getType() == null ? null :
+                        (alarmType == null ? String.valueOf(detail.getType()) : alarmType.get(String.valueOf(detail.getType())).getLabel()));
+                vo.setType(detail.getItemName() == null ? null :
+                        (dictByDictCode == null ? detail.getItemName() : dictByDictCode.get(detail.getItemName()).getLabel()));
+                vo.setValue(detail.getVal());
+                vo.setItemName(kwsThreshold.getItemName());
+                vo.setPhone(kwsThreshold.getPhones());
+                KwsDevice kwsDevice = deviceMapper.selectById(kwsThreshold.getDeviceId());
+                vo.setLocation(kwsDevice == null ? null : kwsDevice.getLogicAlt() + " " + kwsDevice.getLogicLat() + "" + kwsDevice.getLogicLng());
+                vo.setCreateTime(detail.getCreateTime());
+                list.add(vo);
+            }
+        }
+        return PageRes.build(info, list);
     }
 }

+ 13 - 5
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/LogService.java

@@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.sckw.core.model.enums.MessageLogEnum;
 import com.sckw.core.model.page.PageRes;
+import com.sckw.core.model.page.PageResult;
 import com.sckw.core.web.response.HttpResult;
 import com.sckw.slope.detection.dao.mysql.KwsLogMapper;
 import com.sckw.slope.detection.dao.tdengine.SlopeDataMapper;
@@ -70,15 +71,22 @@ public class LogService {
         List<Map<String, String>> returnList = new ArrayList<>();
         for (String s : typeList) {
             Map<String, String> map = new HashMap<>();
-            map.put(s, MessageLogEnum.getEnumTitleByCode(s));
+            map.put("name", MessageLogEnum.getEnumTitleByCode(s));
+            map.put("value", s);
             returnList.add(map);
         }
         return HttpResult.ok(returnList);
     }
 
-    public HttpResult selectMetadata(Integer page, Integer pageSize, HttpServletRequest request) {
-        page = (page - 1) * pageSize;
-        List<SlopeDataVo> list = slopeDataMapper.selectListByMaster(page, pageSize);
-        return HttpResult.ok(list);
+    public PageResult selectMetadata(Integer page, Integer pageSize, HttpServletRequest request) {
+        Integer newPage = (page - 1) * pageSize;
+        List<SlopeDataVo> list = slopeDataMapper.selectListByMaster(newPage, pageSize);
+        List<SlopeDataVo> listByMasterCount = slopeDataMapper.selectListByMasterCount(newPage, pageSize);
+        Long count = 0L;
+        if (!CollectionUtils.isEmpty(listByMasterCount)) {
+            count = listByMasterCount.stream().count();
+        }
+        PageResult build = PageResult.build(page, pageSize, count, list);
+        return build;
     }
 }

+ 10 - 1
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/ProjectService.java

@@ -1151,7 +1151,16 @@ public class ProjectService {
         if (!CollectionUtils.isEmpty(kwsProjects)) {
             projectMap = kwsProjects.stream().collect(Collectors.toMap(KwsProject::getId, KwsProject::getName));
         }
-        return HttpResult.ok(projectMap);
+        List<Map<String, Object>> returnList = new ArrayList<>();
+        if (projectMap != null) {
+            for (Map.Entry<Long, String> longStringEntry : projectMap.entrySet()) {
+                Map<String, Object> map = new HashMap<>();
+                map.put("name", longStringEntry.getValue());
+                map.put("value", longStringEntry.getKey());
+                returnList.add(map);
+            }
+        }
+        return HttpResult.ok(returnList);
     }
 
     @Autowired

+ 1 - 0
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/ReportService.java

@@ -43,6 +43,7 @@ public class ReportService {
 
     @Autowired
     KwsReportDataMapper reportDataMapper;
+
     @Autowired
     KwsProjectMapper projectMapper;
 

+ 10 - 0
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/ReportTemplateService.java

@@ -13,8 +13,10 @@ import com.sckw.core.model.page.PageRes;
 import com.sckw.core.utils.IdWorker;
 import com.sckw.core.web.response.HttpResult;
 import com.sckw.slope.detection.dao.mysql.KwsProjectMapper;
+import com.sckw.slope.detection.dao.mysql.KwsReportDataMapper;
 import com.sckw.slope.detection.dao.mysql.KwsReportTemplateMapper;
 import com.sckw.slope.detection.model.dos.mysql.KwsProject;
+import com.sckw.slope.detection.model.dos.mysql.KwsReportData;
 import com.sckw.slope.detection.model.dos.mysql.KwsReportTemplate;
 import com.sckw.slope.detection.model.dto.HeaderData;
 import com.sckw.slope.detection.model.dto.IsEnableDTO;
@@ -55,6 +57,9 @@ public class ReportTemplateService {
     @Autowired
     KwsReportTemplateMapper reportTemplateMapper;
 
+    @Autowired
+    KwsReportDataMapper reportDataMapper;
+
     @Transactional
     public HttpResult add(ReportTemplateAddDTO reportTemplateDTO, HttpServletRequest request) {
         HeaderData headerData = commonService.getHeaderData(request);
@@ -202,6 +207,7 @@ public class ReportTemplateService {
         return PageRes.build(info, list);
     }
 
+    @Transactional
     public HttpResult dels(String id, HttpServletRequest request) {
         HeaderData headerData = commonService.getHeaderData(request);
         KwsReportTemplate template = reportTemplateMapper.selectOne(new LambdaQueryWrapper<KwsReportTemplate>().eq(KwsReportTemplate::getDelFlag, 0)
@@ -215,6 +221,10 @@ public class ReportTemplateService {
                 .set(KwsReportTemplate::getUpdateBy, (headerData.getUpdateBy() == null ? null : Long.parseLong(headerData.getUpdateBy())))
                 .set(KwsReportTemplate::getStatus, NumberConstant.ONE)
         );
+       reportDataMapper.update(null, new LambdaUpdateWrapper<KwsReportData>()
+                .eq(KwsReportData::getTemplateId, Long.parseLong(id))
+               .set(KwsReportData::getDelFlag,NumberConstant.ONE)
+       );
         KwsProject project = projectMapper.selectOne(new LambdaQueryWrapper<KwsProject>()
                 .eq(KwsProject::getId, Long.parseLong(template.getProjectId())));
         Map<String, Object> logMap = new HashMap<>(NumberConstant.SIXTEEN);

+ 60 - 0
slope-modules/slope-detection/src/main/java/com/sckw/slope/detection/service/task/ReportTemplateTaskService.java

@@ -0,0 +1,60 @@
+package com.sckw.slope.detection.service.task;
+
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.sckw.core.model.enums.ReportTypeEnum;
+import com.sckw.slope.detection.dao.mysql.KwsReportTemplateMapper;
+import com.sckw.slope.detection.model.dos.mysql.KwsReportTemplate;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * @author lfdc
+ * @description 报表任务
+ * @date 2023-11-10 11:11:25
+ */
+
+@Slf4j
+@Component
+@EnableScheduling
+public class ReportTemplateTaskService {
+
+    @Resource
+    KwsReportTemplateMapper reportTemplateMapper;
+
+    /**
+     * 报表生成定时任务
+     */
+    //    @Scheduled(cron = "0 0 0 ? * *")
+    public void templateTask() {
+        List<KwsReportTemplate> kwsReportTemplates = reportTemplateMapper.selectList(new LambdaQueryWrapper<KwsReportTemplate>()
+                .eq(KwsReportTemplate::getStatus, 0)
+                .eq(KwsReportTemplate::getDelFlag, 0));
+        if (!CollectionUtils.isEmpty(kwsReportTemplates)) {
+            for (KwsReportTemplate kwsReportTemplate : kwsReportTemplates) {
+                Integer type = kwsReportTemplate.getType();
+                if (ReportTypeEnum.DAY.getCode() == type) {
+                    LocalDateTime localDateTime = LocalDateTime.now().minusDays(1);
+                    LocalDateTime dateEnd = com.sckw.excel.utils.DateUtil.localDateToLocalDateTimeEnd(localDateTime.toLocalDate());
+                    LocalDateTime dateStart = com.sckw.excel.utils.DateUtil.localDateToLocalDateTimeStart(localDateTime.toLocalDate());
+
+                }
+                if (ReportTypeEnum.WEEK.getCode() == type) {
+                    if (2 != DateUtil.thisDayOfWeekEnum().getValue()) {
+                        continue;
+                    }
+                }
+                if (ReportTypeEnum.MONTH.getCode() == type) {
+
+                }
+            }
+        }
+
+    }
+}

+ 8 - 1
slope-modules/slope-detection/src/main/resources/bootstrap-lfdc.yml

@@ -48,4 +48,11 @@ mqtt:
   receive:
     topic: slopePush/slopePull/test/out,test,slope,sharjeck/ai/test/out
 OkHttpClit:
-  url: "http://10.10.10.185:9501"
+  url: "http://10.10.10.185:9501"
+#oss上传
+aliyun:
+  oss:
+    endpoint: oss-cn-chengdu.aliyuncs.com
+    accessKeyId: LTAI5tPEbubCGq5Rdwygbz4Q
+    secret: 7mQLWMaBJeZPRV1SRGogctYGXwppjQ
+    bucket: kaiwu-saas

+ 209 - 0
slope-modules/slope-detection/src/main/resources/mapper/mysql/KwsAlarmDetailMapper.xml

@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.sckw.slope.detection.dao.mysql.KwsAlarmDetailMapper">
+  <resultMap id="BaseResultMap" type="com.sckw.slope.detection.model.dos.mysql.KwsAlarmDetail">
+    <!--@mbg.generated-->
+    <!--@Table kws_alarm_detail-->
+    <id column="id" jdbcType="BIGINT" property="id" />
+    <result column="mountain_id" jdbcType="VARCHAR" property="mountainId" />
+    <result column="company_id" jdbcType="VARCHAR" property="companyId" />
+    <result column="project_id" jdbcType="BIGINT" property="projectId" />
+    <result column="alarm_id" jdbcType="BIGINT" property="alarmId" />
+    <result column="pid" jdbcType="BIGINT" property="pid" />
+    <result column="val" jdbcType="VARCHAR" property="val" />
+<!--    <result column="item_name" jdbcType="VARCHAR" property="itemName" />-->
+    <result column="level" jdbcType="INTEGER" property="level" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="content" jdbcType="VARCHAR" property="content" />
+    <result column="type" jdbcType="INTEGER" property="type" />
+    <result column="lat" jdbcType="VARCHAR" property="lat" />
+    <result column="lng" jdbcType="VARCHAR" property="lng" />
+    <result column="alt" jdbcType="VARCHAR" property="alt" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
+    <result column="status" jdbcType="TINYINT" property="status" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--@mbg.generated-->
+    id, mountain_id, company_id, project_id, alarm_id, `level`, title, content, `type`, 
+    lat, lng, alt, create_time, update_time, `status`,val,pid
+  </sql>
+  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+    <!--@mbg.generated-->
+    select 
+    <include refid="Base_Column_List" />
+    from kws_alarm_detail
+    where id = #{id,jdbcType=BIGINT}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+    <!--@mbg.generated-->
+    delete from kws_alarm_detail
+    where id = #{id,jdbcType=BIGINT}
+  </delete>
+  <insert id="insertSelective" parameterType="com.sckw.slope.detection.model.dos.mysql.KwsAlarmDetail">
+    <!--@mbg.generated-->
+    insert into kws_alarm_detail
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="id != null">
+        id,
+      </if>
+      <if test="mountainId != null">
+        mountain_id,
+      </if>
+      <if test="companyId != null">
+        company_id,
+      </if>
+      <if test="projectId != null">
+        project_id,
+      </if>
+      <if test="alarmId != null">
+        alarm_id,
+      </if>
+      <if test="level != null">
+        `level`,
+      </if>
+      <if test="title != null">
+        title,
+      </if>
+      <if test="content != null">
+        content,
+      </if>
+      <if test="type != null">
+        `type`,
+      </if>
+      <if test="lat != null">
+        lat,
+      </if>
+      <if test="lng != null">
+        lng,
+      </if>
+      <if test="alt != null">
+        alt,
+      </if>
+      <if test="createTime != null">
+        create_time,
+      </if>
+      <if test="updateTime != null">
+        update_time,
+      </if>
+      <if test="status != null">
+        `status`,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="id != null">
+        #{id,jdbcType=BIGINT},
+      </if>
+      <if test="mountainId != null">
+        #{mountainId,jdbcType=VARCHAR},
+      </if>
+      <if test="companyId != null">
+        #{companyId,jdbcType=VARCHAR},
+      </if>
+      <if test="projectId != null">
+        #{projectId,jdbcType=BIGINT},
+      </if>
+      <if test="alarmId != null">
+        #{alarmId,jdbcType=BIGINT},
+      </if>
+      <if test="level != null">
+        #{level,jdbcType=INTEGER},
+      </if>
+      <if test="title != null">
+        #{title,jdbcType=VARCHAR},
+      </if>
+      <if test="content != null">
+        #{content,jdbcType=VARCHAR},
+      </if>
+      <if test="type != null">
+        #{type,jdbcType=INTEGER},
+      </if>
+      <if test="lat != null">
+        #{lat,jdbcType=VARCHAR},
+      </if>
+      <if test="lng != null">
+        #{lng,jdbcType=VARCHAR},
+      </if>
+      <if test="alt != null">
+        #{alt,jdbcType=VARCHAR},
+      </if>
+      <if test="createTime != null">
+        #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="updateTime != null">
+        #{updateTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="status != null">
+        #{status,jdbcType=TINYINT},
+      </if>
+    </trim>
+  </insert>
+  <update id="updateByPrimaryKeySelective" parameterType="com.sckw.slope.detection.model.dos.mysql.KwsAlarmDetail">
+    <!--@mbg.generated-->
+    update kws_alarm_detail
+    <set>
+      <if test="mountainId != null">
+        mountain_id = #{mountainId,jdbcType=VARCHAR},
+      </if>
+      <if test="companyId != null">
+        company_id = #{companyId,jdbcType=VARCHAR},
+      </if>
+      <if test="projectId != null">
+        project_id = #{projectId,jdbcType=BIGINT},
+      </if>
+      <if test="alarmId != null">
+        alarm_id = #{alarmId,jdbcType=BIGINT},
+      </if>
+      <if test="level != null">
+        `level` = #{level,jdbcType=INTEGER},
+      </if>
+      <if test="title != null">
+        title = #{title,jdbcType=VARCHAR},
+      </if>
+      <if test="content != null">
+        content = #{content,jdbcType=VARCHAR},
+      </if>
+      <if test="type != null">
+        `type` = #{type,jdbcType=INTEGER},
+      </if>
+      <if test="lat != null">
+        lat = #{lat,jdbcType=VARCHAR},
+      </if>
+      <if test="lng != null">
+        lng = #{lng,jdbcType=VARCHAR},
+      </if>
+      <if test="alt != null">
+        alt = #{alt,jdbcType=VARCHAR},
+      </if>
+      <if test="createTime != null">
+        create_time = #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="updateTime != null">
+        update_time = #{updateTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="status != null">
+        `status` = #{status,jdbcType=TINYINT},
+      </if>
+    </set>
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="com.sckw.slope.detection.model.dos.mysql.KwsAlarmDetail">
+    <!--@mbg.generated-->
+    update kws_alarm_detail
+    set mountain_id = #{mountainId,jdbcType=VARCHAR},
+      company_id = #{companyId,jdbcType=VARCHAR},
+      project_id = #{projectId,jdbcType=BIGINT},
+      alarm_id = #{alarmId,jdbcType=BIGINT},
+      `level` = #{level,jdbcType=INTEGER},
+      title = #{title,jdbcType=VARCHAR},
+      content = #{content,jdbcType=VARCHAR},
+      `type` = #{type,jdbcType=INTEGER},
+      lat = #{lat,jdbcType=VARCHAR},
+      lng = #{lng,jdbcType=VARCHAR},
+      alt = #{alt,jdbcType=VARCHAR},
+      create_time = #{createTime,jdbcType=TIMESTAMP},
+      update_time = #{updateTime,jdbcType=TIMESTAMP},
+      `status` = #{status,jdbcType=TINYINT}
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+</mapper>

+ 3 - 9
slope-modules/slope-detection/src/main/resources/mapper/mysql/KwsAlarmMapper.xml

@@ -5,27 +5,21 @@
     <!--@mbg.generated-->
     <!--@Table kws_alarm-->
     <id column="id" jdbcType="BIGINT" property="id" />
-    <result column="pid" jdbcType="BIGINT" property="pid" />
     <result column="title" jdbcType="VARCHAR" property="title" />
-    <result column="val" jdbcType="VARCHAR" property="val" />
-    <result column="content" jdbcType="VARCHAR" property="content" />
     <result column="company_id" jdbcType="VARCHAR" property="companyId" />
     <result column="mountain_id" jdbcType="VARCHAR" property="mountainId" />
     <result column="project_id" jdbcType="VARCHAR" property="projectId" />
+    <result column="device_id" jdbcType="VARCHAR" property="deviceId" />
     <result column="level" jdbcType="INTEGER" property="level" />
     <result column="type" jdbcType="INTEGER" property="type" />
-    <result column="lat" jdbcType="VARCHAR" property="lat" />
-    <result column="lng" jdbcType="VARCHAR" property="lng" />
-    <result column="alt" jdbcType="VARCHAR" property="alt" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
-    <result column="trigger_times" jdbcType="INTEGER" property="triggerTimes" />
     <result column="status" jdbcType="TINYINT" property="status" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--@mbg.generated-->
-    id, pid, title, val, content, `level`, `type`, lat, lng, alt, create_time, trigger_times, 
-    `status`,company_id,mountain_id,project_id,update_time
+    id,  title,`level`, `type`,  create_time,
+    `status`,company_id,mountain_id,project_id,update_time,device_id
   </sql>
   <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
     <!--@mbg.generated-->

+ 9 - 1
slope-modules/slope-detection/src/main/resources/mapper/tdengine/SlopeDataMapper.xml

@@ -97,7 +97,8 @@
         <include refid="Base_List">
         </include>
         FROM devices.slope_data
-        <if test="(page != null and page !='') and ( pageSize != null and pageSize != '')">
+<!--        <if test="(page != null and page !='') and ( pageSize != null and pageSize != '')">-->
+        <if test="page != null and pageSize != null ">
             limit #{page},#{pageSize}
         </if>
 
@@ -113,4 +114,11 @@
 <!--        FROM devices.slope_data AS t1-->
 <!--        LEFT JOIN devices.slope_raw AS t2 ON t1.guid  = t2.guid-->
     </select>
+
+    <select id="selectListByMasterCount" resultType="com.sckw.slope.detection.model.vo.SlopeDataVo">
+        SELECT
+        <include refid="Base_List">
+        </include>
+        FROM devices.slope_data
+    </select>
 </mapper>