Commit c495fa5bc6814d91b37a22a7ec8e0b90f1086310

Authored by 黄 x
1 parent 0657018b

fix: generate excel and save it. fix schedule bug

Showing 24 changed files with 591 additions and 209 deletions
1 package org.thingsboard.server.controller.yunteng; 1 package org.thingsboard.server.controller.yunteng;
2 2
3 import io.swagger.annotations.Api; 3 import io.swagger.annotations.Api;
  4 +import io.swagger.annotations.ApiOperation;
4 import lombok.RequiredArgsConstructor; 5 import lombok.RequiredArgsConstructor;
5 import org.quartz.SchedulerException; 6 import org.quartz.SchedulerException;
6 import org.springframework.security.access.prepost.PreAuthorize; 7 import org.springframework.security.access.prepost.PreAuthorize;
@@ -37,6 +38,7 @@ public class YtReportFormConfigController extends BaseController { @@ -37,6 +38,7 @@ public class YtReportFormConfigController extends BaseController {
37 private final YtReportFormConfigService reportFormConfigService; 38 private final YtReportFormConfigService reportFormConfigService;
38 39
39 @GetMapping(params = {PAGE_SIZE, PAGE}) 40 @GetMapping(params = {PAGE_SIZE, PAGE})
  41 + @ApiOperation("分页")
40 public YtPageData<ReportFormConfigDTO> page( 42 public YtPageData<ReportFormConfigDTO> page(
41 @RequestParam(PAGE_SIZE) int pageSize, 43 @RequestParam(PAGE_SIZE) int pageSize,
42 @RequestParam(PAGE) int page, 44 @RequestParam(PAGE) int page,
@@ -62,9 +64,10 @@ public class YtReportFormConfigController extends BaseController { @@ -62,9 +64,10 @@ public class YtReportFormConfigController extends BaseController {
62 } 64 }
63 65
64 @PostMapping 66 @PostMapping
  67 + @ApiOperation("新增")
65 public ResponseResult<ReportFormConfigDTO> saveReportFromConfig( 68 public ResponseResult<ReportFormConfigDTO> saveReportFromConfig(
66 @Validated({AddGroup.class}) @RequestBody ReportFormConfigDTO configDTO) 69 @Validated({AddGroup.class}) @RequestBody ReportFormConfigDTO configDTO)
67 - throws ThingsboardException, SchedulerException { 70 + throws ThingsboardException, SchedulerException {
68 if (StringUtils.isNotEmpty(configDTO.getId())) { 71 if (StringUtils.isNotEmpty(configDTO.getId())) {
69 throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); 72 throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
70 } 73 }
@@ -72,30 +75,43 @@ public class YtReportFormConfigController extends BaseController { @@ -72,30 +75,43 @@ public class YtReportFormConfigController extends BaseController {
72 } 75 }
73 76
74 @PutMapping 77 @PutMapping
  78 + @ApiOperation("编辑")
75 public ResponseResult<ReportFormConfigDTO> updateReportFromConfig( 79 public ResponseResult<ReportFormConfigDTO> updateReportFromConfig(
76 @Validated({UpdateGroup.class}) @RequestBody ReportFormConfigDTO configDTO) 80 @Validated({UpdateGroup.class}) @RequestBody ReportFormConfigDTO configDTO)
77 - throws ThingsboardException, SchedulerException { 81 + throws ThingsboardException, SchedulerException {
78 return saveOrUpdate(configDTO); 82 return saveOrUpdate(configDTO);
79 } 83 }
80 84
81 @PutMapping("/{id}/{status}") 85 @PutMapping("/{id}/{status}")
  86 + @ApiOperation("修改状态")
82 public ResponseResult<ReportFormConfigDTO> updateStatusById( 87 public ResponseResult<ReportFormConfigDTO> updateStatusById(
83 - @PathVariable String id, @PathVariable Integer status) throws ThingsboardException, SchedulerException { 88 + @PathVariable String id, @PathVariable Integer status)
  89 + throws ThingsboardException, SchedulerException {
84 return ResponseResult.success( 90 return ResponseResult.success(
85 reportFormConfigService.updateStatusById( 91 reportFormConfigService.updateStatusById(
86 getCurrentUser().getCurrentTenantId(), status, id)); 92 getCurrentUser().getCurrentTenantId(), status, id));
87 } 93 }
88 94
89 @DeleteMapping 95 @DeleteMapping
  96 + @ApiOperation("删除")
90 public ResponseResult<Boolean> deleteReportFormConfig( 97 public ResponseResult<Boolean> deleteReportFormConfig(
91 - @Validated({DeleteGroup.class}) @RequestBody DeleteDTO deleteDTO) { 98 + @Validated({DeleteGroup.class}) @RequestBody DeleteDTO deleteDTO) throws SchedulerException {
92 return reportFormConfigService.deleteReportFormConfig(deleteDTO) 99 return reportFormConfigService.deleteReportFormConfig(deleteDTO)
93 ? ResponseResult.success(FastIotConstants.StateValue.DELETE_SUCCESS) 100 ? ResponseResult.success(FastIotConstants.StateValue.DELETE_SUCCESS)
94 : ResponseResult.failed(FastIotConstants.StateValue.DELETE_FAILED); 101 : ResponseResult.failed(FastIotConstants.StateValue.DELETE_FAILED);
95 } 102 }
96 103
  104 + @GetMapping("/{id}")
  105 + @ApiOperation("获取报表配置信息")
  106 + public ResponseResult<ReportFormConfigDTO> getReportFormConfig(@PathVariable String id)
  107 + throws ThingsboardException, SchedulerException {
  108 + return ResponseResult.success(
  109 + reportFormConfigService.findReportFormConfigById(
  110 + id, getCurrentUser().getCurrentTenantId()));
  111 + }
  112 +
97 private ResponseResult<ReportFormConfigDTO> saveOrUpdate(ReportFormConfigDTO configDTO) 113 private ResponseResult<ReportFormConfigDTO> saveOrUpdate(ReportFormConfigDTO configDTO)
98 - throws ThingsboardException, SchedulerException { 114 + throws ThingsboardException, SchedulerException {
99 configDTO.setTenantId(getCurrentUser().getCurrentTenantId()); 115 configDTO.setTenantId(getCurrentUser().getCurrentTenantId());
100 ReportFormConfigDTO newDTO = reportFormConfigService.saveOrUpdateReportFormConfig(configDTO); 116 ReportFormConfigDTO newDTO = reportFormConfigService.saveOrUpdateReportFormConfig(configDTO);
101 return ResponseResult.success(newDTO); 117 return ResponseResult.success(newDTO);
1 package org.thingsboard.server.common.data.yunteng.core.utils; 1 package org.thingsboard.server.common.data.yunteng.core.utils;
2 2
3 -  
4 import org.springframework.http.ResponseEntity; 3 import org.springframework.http.ResponseEntity;
5 import org.springframework.web.multipart.MultipartFile; 4 import org.springframework.web.multipart.MultipartFile;
6 import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse; 5 import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse;
7 6
8 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletRequest;
9 import javax.servlet.http.HttpServletResponse; 8 import javax.servlet.http.HttpServletResponse;
  9 +import java.io.InputStream;
10 10
11 public interface FileStorageService { 11 public interface FileStorageService {
12 12
@@ -26,4 +26,6 @@ public interface FileStorageService { @@ -26,4 +26,6 @@ public interface FileStorageService {
26 */ 26 */
27 ResponseEntity<?> download( 27 ResponseEntity<?> download(
28 String fileName, HttpServletRequest request, HttpServletResponse response); 28 String fileName, HttpServletRequest request, HttpServletResponse response);
  29 +
  30 + String uploadFile(String fileName, String contentType, InputStream inputStream) throws Exception;
29 } 31 }
@@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse; @@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse;
22 import javax.servlet.http.HttpServletRequest; 22 import javax.servlet.http.HttpServletRequest;
23 import javax.servlet.http.HttpServletResponse; 23 import javax.servlet.http.HttpServletResponse;
24 import java.io.IOException; 24 import java.io.IOException;
  25 +import java.io.InputStream;
25 import java.net.MalformedURLException; 26 import java.net.MalformedURLException;
26 import java.nio.file.Files; 27 import java.nio.file.Files;
27 import java.nio.file.Path; 28 import java.nio.file.Path;
@@ -58,26 +59,7 @@ public class LocalFileStorageService implements FileStorageService { @@ -58,26 +59,7 @@ public class LocalFileStorageService implements FileStorageService {
58 String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename())); 59 String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename()));
59 60
60 try { 61 try {
61 - // random fileName if needed  
62 - if (fileStorageProperties.isRandomFileName()) {  
63 - if (fileName.contains(".")) {  
64 - fileName =  
65 - RandomStringUtils.randomAlphabetic(15)  
66 - + fileName.substring(fileName.lastIndexOf("."));  
67 - } else {  
68 - fileName = RandomStringUtils.randomAlphabetic(15);  
69 - }  
70 - }  
71 - // Check if the file's name contains invalid characters  
72 - if (fileName.contains("..")) {  
73 - throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED);  
74 - }  
75 -  
76 - // Copy file to the target location (Replacing existing file with the same name)  
77 - Path targetLocation = this.fileStorageLocation.resolve(fileName);  
78 - Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);  
79 -  
80 - return fileName; 62 + return storeFileByInputStream(fileName, file.getInputStream());
81 } catch (IOException ex) { 63 } catch (IOException ex) {
82 throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED); 64 throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED);
83 } 65 }
@@ -136,4 +118,37 @@ public class LocalFileStorageService implements FileStorageService { @@ -136,4 +118,37 @@ public class LocalFileStorageService implements FileStorageService {
136 "attachment; filename=\"" + resource.getFilename() + "\"") 118 "attachment; filename=\"" + resource.getFilename() + "\"")
137 .body(resource); 119 .body(resource);
138 } 120 }
  121 +
  122 + @Override
  123 + public String uploadFile(String fileName, String contentType, InputStream inputStream)
  124 + throws IOException {
  125 + String name = storeFileByInputStream(fileName, inputStream);
  126 + String ossStaticPath =
  127 + ServletUriComponentsBuilder.fromCurrentContextPath().toUriString() + ossFileUrl;
  128 + ossStaticPath = ossStaticPath.replace("**", name);
  129 + return ossStaticPath;
  130 + }
  131 +
  132 + private String storeFileByInputStream(String fileName, InputStream inputStream)
  133 + throws IOException {
  134 + // random fileName if needed
  135 + if (fileStorageProperties.isRandomFileName()) {
  136 + if (fileName.contains(".")) {
  137 + fileName =
  138 + RandomStringUtils.randomAlphabetic(15) + fileName.substring(fileName.lastIndexOf("."));
  139 + } else {
  140 + fileName = RandomStringUtils.randomAlphabetic(15);
  141 + }
  142 + }
  143 + // Check if the file's name contains invalid characters
  144 + if (fileName.contains("..")) {
  145 + throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED);
  146 + }
  147 +
  148 + // Copy file to the target location (Replacing existing file with the same name)
  149 + Path targetLocation = this.fileStorageLocation.resolve(fileName);
  150 + Files.copy(inputStream, targetLocation, StandardCopyOption.REPLACE_EXISTING);
  151 +
  152 + return fileName;
  153 + }
139 } 154 }
1 package org.thingsboard.server.common.data.yunteng.core.utils; 1 package org.thingsboard.server.common.data.yunteng.core.utils;
2 2
3 import io.minio.*; 3 import io.minio.*;
  4 +import io.minio.errors.*;
4 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
5 import okhttp3.OkHttpClient; 6 import okhttp3.OkHttpClient;
6 import org.apache.commons.lang3.RandomStringUtils; 7 import org.apache.commons.lang3.RandomStringUtils;
@@ -22,8 +23,10 @@ import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse; @@ -22,8 +23,10 @@ import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse;
22 import javax.net.ssl.*; 23 import javax.net.ssl.*;
23 import javax.servlet.http.HttpServletRequest; 24 import javax.servlet.http.HttpServletRequest;
24 import javax.servlet.http.HttpServletResponse; 25 import javax.servlet.http.HttpServletResponse;
  26 +import java.io.IOException;
25 import java.io.InputStream; 27 import java.io.InputStream;
26 import java.io.OutputStream; 28 import java.io.OutputStream;
  29 +import java.security.InvalidKeyException;
27 import java.security.KeyManagementException; 30 import java.security.KeyManagementException;
28 import java.security.NoSuchAlgorithmException; 31 import java.security.NoSuchAlgorithmException;
29 import java.security.SecureRandom; 32 import java.security.SecureRandom;
@@ -36,7 +39,7 @@ import java.util.Objects; @@ -36,7 +39,7 @@ import java.util.Objects;
36 public class MinioFileStorageService implements FileStorageService { 39 public class MinioFileStorageService implements FileStorageService {
37 40
38 private final MinioFileStorageProperties fileStorageProperties; 41 private final MinioFileStorageProperties fileStorageProperties;
39 - private MinioClient minioClient; 42 + private final MinioClient minioClient;
40 43
41 @Autowired 44 @Autowired
42 public MinioFileStorageService(MinioFileStorageProperties fileStorageProperties) 45 public MinioFileStorageService(MinioFileStorageProperties fileStorageProperties)
@@ -53,36 +56,47 @@ public class MinioFileStorageService implements FileStorageService { @@ -53,36 +56,47 @@ public class MinioFileStorageService implements FileStorageService {
53 checkBucket(); 56 checkBucket();
54 } 57 }
55 58
  59 + public static OkHttpClient getUnsafeOkHttpClient() throws KeyManagementException {
  60 + try {
  61 + final TrustManager[] trustAllCerts =
  62 + new TrustManager[] {
  63 + new X509TrustManager() {
  64 + @Override
  65 + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}
  66 +
  67 + @Override
  68 + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}
  69 +
  70 + @Override
  71 + public X509Certificate[] getAcceptedIssuers() {
  72 + return new X509Certificate[] {};
  73 + }
  74 + }
  75 + };
  76 +
  77 + final SSLContext sslContext = SSLContext.getInstance("SSL");
  78 + sslContext.init(null, trustAllCerts, new SecureRandom());
  79 + final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
  80 + OkHttpClient.Builder builder = new OkHttpClient.Builder();
  81 + builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
  82 +
  83 + builder.hostnameVerifier((s, sslSession) -> true);
  84 + return builder.build();
  85 +
  86 + } catch (NoSuchAlgorithmException e) {
  87 + e.printStackTrace();
  88 + }
  89 + return null;
  90 + }
  91 +
56 // 储存文件 92 // 储存文件
57 public String storeFile(MultipartFile file) { 93 public String storeFile(MultipartFile file) {
58 // Normalize file name 94 // Normalize file name
59 String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename())); 95 String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename()));
60 // random fileName if needed 96 // random fileName if needed
61 - if (fileStorageProperties.isRandomFileName()) {  
62 - if (fileName.contains(".")) {  
63 - fileName =  
64 - RandomStringUtils.randomAlphabetic(15) + fileName.substring(fileName.lastIndexOf("."));  
65 - } else {  
66 - fileName = RandomStringUtils.randomAlphabetic(15);  
67 - }  
68 - }  
69 - // Check if the file's name contains invalid characters  
70 - if (fileName.contains("..")) {  
71 - throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED);  
72 - }  
73 -  
74 // 储存 97 // 储存
75 try { 98 try {
76 - checkBucket();  
77 - PutObjectArgs build =  
78 - PutObjectArgs.builder()  
79 - .bucket(fileStorageProperties.getBucketName())  
80 - .object(fileName)  
81 - .contentType(file.getContentType())  
82 - .stream(file.getInputStream(), file.getInputStream().available(), -1)  
83 - .build();  
84 - minioClient.putObject(build);  
85 - return fileName; 99 + return storeFileByInputStream(fileName, file.getContentType(), file.getInputStream());
86 } catch (Exception ex) { 100 } catch (Exception ex) {
87 ex.printStackTrace(); 101 ex.printStackTrace();
88 throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED); 102 throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED);
@@ -122,7 +136,7 @@ public class MinioFileStorageService implements FileStorageService { @@ -122,7 +136,7 @@ public class MinioFileStorageService implements FileStorageService {
122 .object(fileName) 136 .object(fileName)
123 .build()); 137 .build());
124 // 获取输出流 138 // 获取输出流
125 - OutputStream outputStream = response.getOutputStream(); ) { 139 + OutputStream outputStream = response.getOutputStream()) {
126 // 清空 140 // 清空
127 response.reset(); 141 response.reset();
128 // 写入流 142 // 写入流
@@ -141,6 +155,16 @@ public class MinioFileStorageService implements FileStorageService { @@ -141,6 +155,16 @@ public class MinioFileStorageService implements FileStorageService {
141 } 155 }
142 } 156 }
143 157
  158 + @Override
  159 + public String uploadFile(String fileName, String contentType, InputStream inputStream)
  160 + throws IOException {
  161 + try {
  162 + return getPath(storeFileByInputStream(fileName, contentType, inputStream));
  163 + } catch (Exception e) {
  164 + throw new IOException(e.getMessage());
  165 + }
  166 + }
  167 +
144 // 检查储存桶情况 168 // 检查储存桶情况
145 private void checkBucket() { 169 private void checkBucket() {
146 try { 170 try {
@@ -181,37 +205,32 @@ public class MinioFileStorageService implements FileStorageService { @@ -181,37 +205,32 @@ public class MinioFileStorageService implements FileStorageService {
181 .concat(fileName); 205 .concat(fileName);
182 } 206 }
183 207
184 - public static OkHttpClient getUnsafeOkHttpClient() throws KeyManagementException {  
185 - try {  
186 - final TrustManager[] trustAllCerts =  
187 - new TrustManager[] {  
188 - new X509TrustManager() {  
189 - @Override  
190 - public void checkClientTrusted(X509Certificate[] x509Certificates, String s){}  
191 -  
192 - @Override  
193 - public void checkServerTrusted(X509Certificate[] x509Certificates, String s){}  
194 -  
195 - @Override  
196 - public X509Certificate[] getAcceptedIssuers() {  
197 - return new X509Certificate[] {};  
198 - }  
199 - }  
200 - };  
201 -  
202 - final SSLContext sslContext = SSLContext.getInstance("SSL");  
203 - sslContext.init(null, trustAllCerts, new SecureRandom());  
204 - final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();  
205 - OkHttpClient.Builder builder = new OkHttpClient.Builder();  
206 - builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);  
207 -  
208 - builder.hostnameVerifier(  
209 - (s, sslSession) -> true);  
210 - return builder.build();  
211 -  
212 - } catch (NoSuchAlgorithmException e) {  
213 - e.printStackTrace(); 208 + private String storeFileByInputStream(
  209 + String fileName, String contentType, InputStream inputStream)
  210 + throws ServerException, InsufficientDataException, ErrorResponseException, IOException,
  211 + NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException,
  212 + XmlParserException, InternalException {
  213 + if (fileStorageProperties.isRandomFileName()) {
  214 + if (!fileName.contains(".")) {
  215 + fileName = RandomStringUtils.randomAlphabetic(15);
  216 + } else {
  217 + fileName =
  218 + RandomStringUtils.randomAlphabetic(15) + fileName.substring(fileName.lastIndexOf("."));
  219 + }
214 } 220 }
215 - return null; 221 + // Check if the file's name contains invalid characters
  222 + if (fileName.contains("..")) {
  223 + throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED);
  224 + }
  225 + checkBucket();
  226 + PutObjectArgs build =
  227 + PutObjectArgs.builder()
  228 + .bucket(fileStorageProperties.getBucketName())
  229 + .object(fileName)
  230 + .contentType(contentType)
  231 + .stream(inputStream, inputStream.available(), -1)
  232 + .build();
  233 + minioClient.putObject(build);
  234 + return fileName;
216 } 235 }
217 } 236 }
@@ -26,6 +26,8 @@ public class ReportFormConfigDTO extends TenantDTO { @@ -26,6 +26,8 @@ public class ReportFormConfigDTO extends TenantDTO {
26 @NotEmpty(message = "组织不能为空或空字符串", groups = AddGroup.class) 26 @NotEmpty(message = "组织不能为空或空字符串", groups = AddGroup.class)
27 private String organizationId; 27 private String organizationId;
28 28
  29 + private OrganizationDTO organizationDTO;
  30 +
29 /** 执行方式:0立即执行 1定时执行 */ 31 /** 执行方式:0立即执行 1定时执行 */
30 @ApiModelProperty(value = "执行方式", required = true) 32 @ApiModelProperty(value = "执行方式", required = true)
31 @NotNull(message = "执行方式不能为空", groups = AddGroup.class) 33 @NotNull(message = "执行方式不能为空", groups = AddGroup.class)
@@ -39,15 +41,11 @@ public class ReportFormConfigDTO extends TenantDTO { @@ -39,15 +41,11 @@ public class ReportFormConfigDTO extends TenantDTO {
39 @Size(message = "至少需要一个执行设备及属性", min = 1,groups = AddGroup.class) 41 @Size(message = "至少需要一个执行设备及属性", min = 1,groups = AddGroup.class)
40 private List<ExecuteAttributesDTO> executeAttributes; 42 private List<ExecuteAttributesDTO> executeAttributes;
41 43
42 - /** 属性性质:0共有属性 1全部属性 */  
43 - @ApiModelProperty(value = "属性性质", required = true)  
44 - @NotNull(message = "属性性质不能为空", groups = AddGroup.class)  
45 - private Integer attributeNature;  
46 44
47 - /** 数据对比:0历史数据 1环比 2同比 */  
48 - @ApiModelProperty(value = "数据对比", required = true)  
49 - @NotNull(message = "数据对比不能为空", groups = AddGroup.class)  
50 - private Integer dataCompare; 45 + /** 数据类型:0历史数据 1聚合数据 */
  46 + @ApiModelProperty(value = "数据类型:0原始数据 1聚合数据", required = true)
  47 + @NotNull(message = "数据类型不能为空", groups = AddGroup.class)
  48 + private Integer dataType;
51 49
52 /** 数据周期:单位毫秒 */ 50 /** 数据周期:单位毫秒 */
53 @ApiModelProperty(value = "开始时间", required = true) 51 @ApiModelProperty(value = "开始时间", required = true)
  1 +package org.thingsboard.server.common.data.yunteng.dto.report;
  2 +
  3 +import lombok.Data;
  4 +import org.jetbrains.annotations.NotNull;
  5 +
  6 +@Data
  7 +public class BasicData implements Comparable<BasicData> {
  8 + private final Object value;
  9 +
  10 + private final long ts;
  11 +
  12 + public BasicData(long ts, Object value) {
  13 + super();
  14 + this.ts = ts;
  15 + this.value = value;
  16 + }
  17 +
  18 + @Override
  19 + public int compareTo(@NotNull BasicData o) {
  20 + return Long.compare(ts, o.ts);
  21 + }
  22 +}
  1 +package org.thingsboard.server.common.data.yunteng.dto.report;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.List;
  6 +
  7 +/** 报表导出:Echarts图表展示数据 */
  8 +@Data
  9 +public class ChartReportDTO {
  10 + /** 报表查询:开始时间 */
  11 + private Long startTs;
  12 +
  13 + /** 报表查询:结束时间 */
  14 + private Long endTs;
  15 +
  16 + /** 查询返回的数据 */
  17 + private List<ReportDataSourceDTO> data;
  18 +}
  1 +package org.thingsboard.server.common.data.yunteng.dto.report;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.List;
  6 +
  7 +/** 基础报表数据 */
  8 +@Data
  9 +public class ReportDataSourceDTO {
  10 +
  11 + /** 采集属性 */
  12 + private String attribute;
  13 +
  14 + /** 采集的数据 */
  15 + private List<BasicData> data;
  16 +}
1 -package org.thingsboard.server.common.data.yunteng.dto.report;  
2 -  
3 -/**+  
4 - * 导出报表:非聚合数据生成  
5 - */  
6 -public class UnAggregationReportDTO {  
7 -}  
@@ -4,12 +4,17 @@ import io.swagger.annotations.ApiModel; @@ -4,12 +4,17 @@ import io.swagger.annotations.ApiModel;
4 import io.swagger.annotations.ApiModelProperty; 4 import io.swagger.annotations.ApiModelProperty;
5 import lombok.Data; 5 import lombok.Data;
6 6
  7 +import java.util.List;
  8 +
7 @Data 9 @Data
8 @ApiModel(value = "执行设备及属性") 10 @ApiModel(value = "执行设备及属性")
9 public class ExecuteAttributesDTO { 11 public class ExecuteAttributesDTO {
10 @ApiModelProperty(value = "执行设备", required = true) 12 @ApiModelProperty(value = "执行设备", required = true)
11 private String device; 13 private String device;
12 14
  15 + @ApiModelProperty(value = "设备名称", required = true)
  16 + private String name;
  17 +
13 @ApiModelProperty(value = "执行属性", required = true) 18 @ApiModelProperty(value = "执行属性", required = true)
14 - private String attribute; 19 + private List<String> attributes;
15 } 20 }
@@ -3,21 +3,22 @@ package org.thingsboard.server.common.data.yunteng.dto.request; @@ -3,21 +3,22 @@ package org.thingsboard.server.common.data.yunteng.dto.request;
3 import io.swagger.annotations.ApiModel; 3 import io.swagger.annotations.ApiModel;
4 import io.swagger.annotations.ApiModelProperty; 4 import io.swagger.annotations.ApiModelProperty;
5 import lombok.Data; 5 import lombok.Data;
  6 +import org.thingsboard.server.common.data.kv.Aggregation;
6 7
7 @Data 8 @Data
8 @ApiModel(value = "查询条件") 9 @ApiModel(value = "查询条件")
9 public class QueryConditionDTO { 10 public class QueryConditionDTO {
10 - @ApiModelProperty("聚合间隔:单位毫秒")  
11 - private Long interval; 11 + @ApiModelProperty("聚合间隔:单位毫秒,默认0")
  12 + private Long interval = 0L;
12 13
13 - @ApiModelProperty("查询的最大数量:该参数仅在'agg'参数设置为'NONE'的情况下使用")  
14 - private Integer limit; 14 + @ApiModelProperty("查询的最大数量:该参数仅在'agg'参数设置为'NONE'的情况下使用,默认100")
  15 + private Integer limit = 100;
15 16
16 @ApiModelProperty("聚合条件:AVG, COUNT, MAX, MIN, NONE, SUM") 17 @ApiModelProperty("聚合条件:AVG, COUNT, MAX, MIN, NONE, SUM")
17 - private String agg; 18 + private Aggregation agg;
18 19
19 - @ApiModelProperty("排序:ASC, DESC")  
20 - private String orderBy; 20 + @ApiModelProperty("排序:ASC, DESC 默认DESC")
  21 + private String orderBy = "DESC";
21 22
22 @ApiModelProperty("启用/禁用遥测值到字符串的转换。默认情况下启用转换。设置参数为'true'以禁用转换") 23 @ApiModelProperty("启用/禁用遥测值到字符串的转换。默认情况下启用转换。设置参数为'true'以禁用转换")
23 private boolean useStrictDataTypes; 24 private boolean useStrictDataTypes;
@@ -8,8 +8,8 @@ public enum StatusEnum { @@ -8,8 +8,8 @@ public enum StatusEnum {
8 ONLINE("在线", 1), 8 ONLINE("在线", 1),
9 ENABLE("启用", 1), 9 ENABLE("启用", 1),
10 DISABLE("禁用", 0), 10 DISABLE("禁用", 0),
11 - NORMAL("正常", 0),  
12 - PAUSE("暂停", 1), 11 + NORMAL("正常", 1),
  12 + PAUSE("暂停", 0),
13 FAIL("失败", 0), 13 FAIL("失败", 0),
14 SUCCESS("成功", 1), 14 SUCCESS("成功", 1),
15 RUNNING("运行中",2), 15 RUNNING("运行中",2),
1 package org.thingsboard.server.common.data.yunteng.utils; 1 package org.thingsboard.server.common.data.yunteng.utils;
2 2
3 import com.alibaba.excel.EasyExcel; 3 import com.alibaba.excel.EasyExcel;
  4 +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
4 import org.apache.commons.lang3.StringUtils; 5 import org.apache.commons.lang3.StringUtils;
5 import org.springframework.beans.BeanUtils; 6 import org.springframework.beans.BeanUtils;
6 7
7 import javax.servlet.http.HttpServletResponse; 8 import javax.servlet.http.HttpServletResponse;
  9 +import java.io.ByteArrayOutputStream;
8 import java.io.IOException; 10 import java.io.IOException;
9 import java.net.URLEncoder; 11 import java.net.URLEncoder;
10 import java.nio.charset.StandardCharsets; 12 import java.nio.charset.StandardCharsets;
@@ -15,7 +17,6 @@ import java.util.List; @@ -15,7 +17,6 @@ import java.util.List;
15 17
16 public class ExcelUtil { 18 public class ExcelUtil {
17 private ExcelUtil() {} 19 private ExcelUtil() {}
18 -  
19 public static void exportExcel( 20 public static void exportExcel(
20 HttpServletResponse response, 21 HttpServletResponse response,
21 String fileName, 22 String fileName,
@@ -52,4 +53,15 @@ public class ExcelUtil { @@ -52,4 +53,15 @@ public class ExcelUtil {
52 53
53 exportExcel(response, fileName, sheetName, targetList, targetClass); 54 exportExcel(response, fileName, sheetName, targetList, targetClass);
54 } 55 }
  56 +
  57 + public static ByteArrayOutputStream noModelWrite(String fileName, List<List<String>> heads, List<?> data) {
  58 + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  59 + EasyExcel.write(byteArrayOutputStream)
  60 + .head(heads)
  61 + .sheet(fileName)
  62 + // 自适应列宽
  63 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
  64 + .doWrite(data);
  65 + return byteArrayOutputStream;
  66 + }
55 } 67 }
@@ -64,7 +64,7 @@ public abstract class AbstractQuartzJob implements Job { @@ -64,7 +64,7 @@ public abstract class AbstractQuartzJob implements Job {
64 long runMs = 64 long runMs =
65 sysJobLog.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli() 65 sysJobLog.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli()
66 - startTime.toInstant(ZoneOffset.of("+8")).toEpochMilli(); 66 - startTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
67 - sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒"); 67 + sysJobLog.setJobMessage(" 总共耗时:" + runMs + "毫秒");
68 if (e != null) { 68 if (e != null) {
69 sysJobLog.setStatus(StatusEnum.FAIL.getIndex()); 69 sysJobLog.setStatus(StatusEnum.FAIL.getIndex());
70 String errorMsg = StringUtils.substring(e.getMessage(), 0, 2000); 70 String errorMsg = StringUtils.substring(e.getMessage(), 0, 2000);
1 package org.thingsboard.server.dao.util.yunteng; 1 package org.thingsboard.server.dao.util.yunteng;
2 2
3 import org.apache.commons.lang3.StringUtils; 3 import org.apache.commons.lang3.StringUtils;
  4 +import org.thingsboard.server.common.data.yunteng.dto.ReportGenerateRecordDTO;
4 import org.thingsboard.server.common.data.yunteng.enums.JobGroupEnum; 5 import org.thingsboard.server.common.data.yunteng.enums.JobGroupEnum;
5 import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils; 6 import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils;
6 import org.thingsboard.server.dao.yunteng.entities.SysJob; 7 import org.thingsboard.server.dao.yunteng.entities.SysJob;
@@ -22,13 +23,16 @@ public class JobInvokeUtil { @@ -22,13 +23,16 @@ public class JobInvokeUtil {
22 String invokeTarget = sysJob.getInvokeTarget(); 23 String invokeTarget = sysJob.getInvokeTarget();
23 String beanName = getBeanName(invokeTarget); 24 String beanName = getBeanName(invokeTarget);
24 String methodName = getMethodName(invokeTarget); 25 String methodName = getMethodName(invokeTarget);
  26 + String reportGenerateRecordId = null;
25 if (StringUtils.isNotEmpty(sysJob.getSourceId()) 27 if (StringUtils.isNotEmpty(sysJob.getSourceId())
26 && sysJob.getJobGroup().equals(JobGroupEnum.REPORT.toString())) { 28 && sysJob.getJobGroup().equals(JobGroupEnum.REPORT.toString())) {
27 // 写入报表生成记录 29 // 写入报表生成记录
28 - SpringBeanUtils.getBean(YtReportGenerateRecordService.class)  
29 - .generateReportRecord(sysJob.getSourceId(), sysJob.getTenantId(), sysJob.getId()); 30 + ReportGenerateRecordDTO dto =
  31 + SpringBeanUtils.getBean(YtReportGenerateRecordService.class)
  32 + .generateReportRecord(sysJob.getSourceId(), sysJob.getTenantId(), sysJob.getId());
  33 + reportGenerateRecordId = dto.getId();
30 } 34 }
31 - List<Object[]> methodParams = getMethodParams(invokeTarget); 35 + List<Object[]> methodParams = getMethodParams(invokeTarget, reportGenerateRecordId);
32 Object bean; 36 Object bean;
33 if (!isValidClassName(beanName)) { 37 if (!isValidClassName(beanName)) {
34 bean = SpringBeanUtils.getBean(beanName); 38 bean = SpringBeanUtils.getBean(beanName);
@@ -96,11 +100,14 @@ public class JobInvokeUtil { @@ -96,11 +100,14 @@ public class JobInvokeUtil {
96 * @param invokeTarget 目标字符串 100 * @param invokeTarget 目标字符串
97 * @return method方法相关参数列表 101 * @return method方法相关参数列表
98 */ 102 */
99 - public static List<Object[]> getMethodParams(String invokeTarget) { 103 + public static List<Object[]> getMethodParams(String invokeTarget, String reportGenerateRecordId) {
100 String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")"); 104 String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
101 if (StringUtils.isEmpty(methodStr)) { 105 if (StringUtils.isEmpty(methodStr)) {
102 return null; 106 return null;
103 } 107 }
  108 + if (reportGenerateRecordId != null) {
  109 + methodStr += ",\"" + reportGenerateRecordId + "\"";
  110 + }
104 String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); 111 String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
105 List<Object[]> classs = new LinkedList<>(); 112 List<Object[]> classs = new LinkedList<>();
106 for (String methodParam : methodParams) { 113 for (String methodParam : methodParams) {
1 package org.thingsboard.server.dao.util.yunteng.task; 1 package org.thingsboard.server.dao.util.yunteng.task;
2 2
  3 +import com.google.common.util.concurrent.FutureCallback;
  4 +import com.google.common.util.concurrent.Futures;
  5 +import com.google.common.util.concurrent.MoreExecutors;
  6 +import lombok.RequiredArgsConstructor;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +import org.jetbrains.annotations.NotNull;
  9 +import org.springframework.http.HttpStatus;
  10 +import org.springframework.http.ResponseEntity;
3 import org.springframework.stereotype.Component; 11 import org.springframework.stereotype.Component;
  12 +import org.springframework.web.context.request.async.DeferredResult;
  13 +import org.thingsboard.common.util.JacksonUtil;
  14 +import org.thingsboard.server.common.data.id.DeviceId;
  15 +import org.thingsboard.server.common.data.id.TenantId;
  16 +import org.thingsboard.server.common.data.kv.*;
  17 +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
  18 +import org.thingsboard.server.common.data.yunteng.core.utils.FileStorageService;
  19 +import org.thingsboard.server.common.data.yunteng.dto.ReportFormConfigDTO;
  20 +import org.thingsboard.server.common.data.yunteng.dto.ReportGenerateRecordDTO;
  21 +import org.thingsboard.server.common.data.yunteng.dto.report.BasicData;
  22 +import org.thingsboard.server.common.data.yunteng.dto.request.ExecuteAttributesDTO;
  23 +import org.thingsboard.server.common.data.yunteng.dto.request.QueryConditionDTO;
  24 +import org.thingsboard.server.common.data.yunteng.enums.StatusEnum;
  25 +import org.thingsboard.server.common.data.yunteng.utils.ExcelUtil;
  26 +import org.thingsboard.server.dao.timeseries.TimeseriesService;
  27 +import org.thingsboard.server.dao.yunteng.service.YtReportFormConfigService;
  28 +import org.thingsboard.server.dao.yunteng.service.YtReportGenerateRecordService;
  29 +
  30 +import java.io.ByteArrayInputStream;
  31 +import java.io.ByteArrayOutputStream;
  32 +import java.io.InputStream;
  33 +import java.sql.Timestamp;
  34 +import java.time.format.DateTimeFormatter;
  35 +import java.util.*;
  36 +import java.util.stream.Collectors;
4 37
5 @Component("reportTask") 38 @Component("reportTask")
  39 +@RequiredArgsConstructor
  40 +@Slf4j
6 public class ReportTask { 41 public class ReportTask {
7 - public void multipleParams(String s, Boolean b, Long l, Double d, Integer i)  
8 - {  
9 - System.out.println("执行多参方法: s="+s+"b="+b+"l="+l+"d"+d+"i="+i);  
10 - } 42 + private static final String CONTENT_TYPE =
  43 + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
  44 + private final YtReportFormConfigService ytReportFormConfigService;
  45 + private final TimeseriesService tsService;
  46 + private final FileStorageService fileStorageService;
  47 + private final YtReportGenerateRecordService ytReportGenerateRecordService;
11 48
12 - public void params(String params) throws InterruptedException {  
13 - System.out.println("==========================执行有参方法:" + params+"=======================");  
14 - Thread.sleep(100);  
15 - } 49 + public void multipleParams(String s, Boolean b, Long l, Double d, Integer i) {
  50 + System.out.println("执行多参方法: s=" + s + "b=" + b + "l=" + l + "d" + d + "i=" + i);
  51 + }
  52 +
  53 + public void params(String params) throws InterruptedException {
  54 + System.out.println("==========================执行有参方法:" + params + "=======================");
  55 + Thread.sleep(100);
  56 + }
16 57
17 - public void noParams() throws InterruptedException {  
18 - System.out.println("=========================执行无参方法======================================"); 58 + public void noParams() throws InterruptedException {
  59 + System.out.println("=========================执行无参方法======================================");
  60 + }
  61 +
  62 + public void generateReport(String reportId, String reportGenerateRecordId) {
  63 + ReportFormConfigDTO formConfigDTO =
  64 + ytReportFormConfigService.findReportFormConfigById(reportId);
  65 + // 关联设备
  66 + List<ExecuteAttributesDTO> dtoList = formConfigDTO.getExecuteAttributes();
  67 + if (!dtoList.isEmpty()) {
  68 + if (dtoList.size() == FastIotConstants.MagicNumber.ONE) {
  69 + try {
  70 + ExecuteAttributesDTO attributesDTO = dtoList.get(0);
  71 + getTsKv(formConfigDTO, attributesDTO, reportGenerateRecordId);
  72 +
  73 + } catch (Exception e) {
  74 + log.error(e.getMessage());
  75 + }
  76 + } else {
  77 + for (ExecuteAttributesDTO dto : dtoList) {
  78 + getTsKv(formConfigDTO, dto, reportGenerateRecordId);
  79 + }
  80 + }
19 } 81 }
  82 + }
  83 +
  84 + private void getTsKv(
  85 + ReportFormConfigDTO formConfigDTO, ExecuteAttributesDTO dto, String reportGenerateRecordId) {
  86 + Long startTs = formConfigDTO.getStartTs();
  87 + Long endTs = formConfigDTO.getEndTs();
  88 + QueryConditionDTO queryCondition = formConfigDTO.getQueryCondition();
  89 + boolean useStrictDataTypes = queryCondition.isUseStrictDataTypes();
  90 + Long interval = queryCondition.getInterval();
  91 + int limit = queryCondition.getLimit();
  92 + Aggregation agg = queryCondition.getAgg();
  93 + String orderBy = queryCondition.getOrderBy();
  94 + List<String> keys = dto.getAttributes();
  95 + DeviceId entityId = DeviceId.fromString(dto.getDevice());
  96 + String reportTenantId = formConfigDTO.getTenantId();
  97 + TenantId tenantId = TenantId.fromUUID(UUID.fromString(reportTenantId));
  98 + final DeferredResult<ResponseEntity> result = new DeferredResult<>();
  99 + List<ReadTsKvQuery> queries =
  100 + keys.stream()
  101 + .map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy))
  102 + .collect(Collectors.toList());
20 103
21 - public void generateReport(String reportId){  
22 - System.out.println("===========================执行报表生成:"+ reportId +"===================================="); 104 + Futures.addCallback(
  105 + tsService.findAll(tenantId, entityId, queries),
  106 + getTsKvListCallback(
  107 + result,
  108 + useStrictDataTypes,
  109 + formConfigDTO.getName(),
  110 + dto.getName(),
  111 + reportGenerateRecordId,
  112 + reportTenantId),
  113 + MoreExecutors.directExecutor());
  114 + }
  115 +
  116 + private FutureCallback<List<TsKvEntry>> getTsKvListCallback(
  117 + final DeferredResult<ResponseEntity> response,
  118 + Boolean useStrictDataTypes,
  119 + String reportFormName,
  120 + String deviceName,
  121 + String reportGenerateRecordId,
  122 + String tenantId) {
  123 + return new FutureCallback<>() {
  124 + @Override
  125 + public void onSuccess(List<TsKvEntry> data) {
  126 + Map<String, List<BasicData>> result = new LinkedHashMap<>();
  127 + for (TsKvEntry entry : data) {
  128 + Object value = useStrictDataTypes ? getKvValue(entry) : entry.getValueAsString();
  129 + result
  130 + .computeIfAbsent(entry.getKey(), k -> new ArrayList<>())
  131 + .add(new BasicData(entry.getTs(), value));
  132 + }
  133 + response.setResult(new ResponseEntity<>(result, HttpStatus.OK));
  134 + generateExcel(deviceName, reportFormName, result, reportGenerateRecordId, tenantId);
  135 + }
  136 +
  137 + @Override
  138 + public void onFailure(@NotNull Throwable e) {
  139 + log.error("Failed to fetch historical data", e);
  140 + }
  141 + };
  142 + }
  143 +
  144 + private Object getKvValue(KvEntry entry) {
  145 + if (entry.getDataType() == DataType.JSON) {
  146 + Optional<String> json = entry.getJsonValue();
  147 + return json.map(JacksonUtil::toJsonNode).orElse(null);
23 } 148 }
  149 + return entry.getValue();
  150 + }
24 151
  152 + private void generateExcel(
  153 + String deviceName,
  154 + String reportFormName,
  155 + Map<String, List<BasicData>> result,
  156 + String reportGenerateRecordId,
  157 + String tenantId) {
  158 + List<List<String>> heads = new ArrayList<>();
  159 + List<List<Object>> values = new ArrayList<>();
  160 + int firstKey = 0;
  161 + for (String key : result.keySet()) {
  162 + List<String> headValue = new ArrayList<>();
  163 + headValue.add(deviceName);
  164 + headValue.add(key + "采集值");
  165 + List<String> tsValue = new ArrayList<>();
  166 + tsValue.add(deviceName);
  167 + tsValue.add(key + "采集时间");
  168 + heads.add(headValue);
  169 + heads.add(tsValue);
  170 + List<BasicData> basicData = result.get(key);
  171 + for (int i = 0; i < basicData.size(); i++) {
  172 + BasicData item = basicData.get(i);
  173 + List<Object> listValue;
  174 + if (firstKey == 0) {
  175 + listValue = new ArrayList<>();
  176 + } else {
  177 + listValue = values.get(i);
  178 + }
  179 + Object value = item.getValue();
  180 + listValue.add(value);
  181 + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  182 + Timestamp t = new Timestamp(item.getTs());
  183 + listValue.add(t.toLocalDateTime().format(dtf));
  184 + if (firstKey == 0) {
  185 + values.add(listValue);
  186 + }
  187 + }
  188 + firstKey++;
  189 + }
  190 + ByteArrayOutputStream byteArrayOutputStream =
  191 + ExcelUtil.noModelWrite(reportFormName, heads, values);
  192 + String fileName = reportFormName + System.currentTimeMillis() + ".xlsx";
  193 + int status = StatusEnum.SUCCESS.getIndex();
  194 + InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
  195 + String response = null;
  196 + try {
  197 + response = fileStorageService.uploadFile(fileName, CONTENT_TYPE, inputStream);
  198 + } catch (Exception e) {
  199 + log.error(e.getMessage());
  200 + }
  201 + ReportGenerateRecordDTO recordDTO =
  202 + ytReportGenerateRecordService.findReportGenerateRecordById(
  203 + reportGenerateRecordId, tenantId);
  204 + if (null != recordDTO) {
  205 + if (response != null) {
  206 + recordDTO.setReportPath(response);
  207 + } else {
  208 + status = StatusEnum.FAIL.getIndex();
  209 + }
  210 + recordDTO.setExecuteStatus(status);
  211 + ytReportGenerateRecordService.saveOrUpdateReportGenerateRecord(recordDTO);
  212 + }
  213 + }
25 } 214 }
@@ -33,11 +33,8 @@ public class ReportFormConfig extends TenantBaseEntity { @@ -33,11 +33,8 @@ public class ReportFormConfig extends TenantBaseEntity {
33 @TableField(typeHandler = JacksonTypeHandler.class) 33 @TableField(typeHandler = JacksonTypeHandler.class)
34 private JsonNode executeAttributes; 34 private JsonNode executeAttributes;
35 35
36 - /** 属性性质:0共有属性 1全部属性 */  
37 - private Integer attributeNature;  
38 -  
39 - /** 数据对比:0历史数据 1环比 2同比 */  
40 - private Integer dataCompare; 36 + /** 数据对比:0原始数据 1聚合数据 */
  37 + private Integer dataType;
41 38
42 /** 查询开始时间:单位毫秒 */ 39 /** 查询开始时间:单位毫秒 */
43 private Long startTs; 40 private Long startTs;
@@ -31,7 +31,7 @@ public class SysJob extends TenantBaseEntity { @@ -31,7 +31,7 @@ public class SysJob extends TenantBaseEntity {
31 /** 是否并发执行(0允许 1禁止) */ 31 /** 是否并发执行(0允许 1禁止) */
32 private Integer concurrent; 32 private Integer concurrent;
33 33
34 - /** 任务状态(0正常 1暂停) */ 34 + /** 任务状态(0暂停 1正常) */
35 private Integer status; 35 private Integer status;
36 36
37 /** 来源ID:即创建定时任务对应的业务ID */ 37 /** 来源ID:即创建定时任务对应的业务ID */
@@ -194,7 +194,6 @@ public class SysJobServiceImpl extends AbstractBaseService<SysJobMapper, SysJob> @@ -194,7 +194,6 @@ public class SysJobServiceImpl extends AbstractBaseService<SysJobMapper, SysJob>
194 @Transactional(rollbackFor = Exception.class) 194 @Transactional(rollbackFor = Exception.class)
195 public SysJobDTO saveOrUpdateJob(SysJobDTO jobDTO) throws SchedulerException { 195 public SysJobDTO saveOrUpdateJob(SysJobDTO jobDTO) throws SchedulerException {
196 if (StringUtils.isEmpty(jobDTO.getId())) { 196 if (StringUtils.isEmpty(jobDTO.getId())) {
197 - jobDTO.setStatus(StatusEnum.PAUSE.getIndex());  
198 SysJob job = jobDTO.getEntity(SysJob.class); 197 SysJob job = jobDTO.getEntity(SysJob.class);
199 baseMapper.insert(job); 198 baseMapper.insert(job);
200 ScheduleUtils.createScheduleJob(scheduler, job); 199 ScheduleUtils.createScheduleJob(scheduler, job);
@@ -13,28 +13,27 @@ import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants; @@ -13,28 +13,27 @@ import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
13 import org.thingsboard.server.common.data.yunteng.core.exception.YtDataValidationException; 13 import org.thingsboard.server.common.data.yunteng.core.exception.YtDataValidationException;
14 import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage; 14 import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
15 import org.thingsboard.server.common.data.yunteng.dto.*; 15 import org.thingsboard.server.common.data.yunteng.dto.*;
  16 +import org.thingsboard.server.common.data.yunteng.dto.request.ExecuteAttributesDTO;
  17 +import org.thingsboard.server.common.data.yunteng.dto.request.QueryConditionDTO;
16 import org.thingsboard.server.common.data.yunteng.enums.JobGroupEnum; 18 import org.thingsboard.server.common.data.yunteng.enums.JobGroupEnum;
17 import org.thingsboard.server.common.data.yunteng.enums.StatusEnum; 19 import org.thingsboard.server.common.data.yunteng.enums.StatusEnum;
18 import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil; 20 import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil;
19 import org.thingsboard.server.common.data.yunteng.utils.tools.YtPageData; 21 import org.thingsboard.server.common.data.yunteng.utils.tools.YtPageData;
20 import org.thingsboard.server.dao.yunteng.entities.ReportFormConfig; 22 import org.thingsboard.server.dao.yunteng.entities.ReportFormConfig;
21 import org.thingsboard.server.dao.yunteng.mapper.OrganizationMapper; 23 import org.thingsboard.server.dao.yunteng.mapper.OrganizationMapper;
22 -import org.thingsboard.server.dao.yunteng.mapper.ReportFromConfigMapper; 24 +import org.thingsboard.server.dao.yunteng.mapper.ReportFormConfigMapper;
23 import org.thingsboard.server.dao.yunteng.service.AbstractBaseService; 25 import org.thingsboard.server.dao.yunteng.service.AbstractBaseService;
24 import org.thingsboard.server.dao.yunteng.service.YtReportFormConfigService; 26 import org.thingsboard.server.dao.yunteng.service.YtReportFormConfigService;
25 import org.thingsboard.server.dao.yunteng.service.YtSysJobService; 27 import org.thingsboard.server.dao.yunteng.service.YtSysJobService;
26 28
27 -import java.util.List;  
28 -import java.util.Map;  
29 -import java.util.Objects;  
30 -import java.util.Optional; 29 +import java.util.*;
31 import java.util.stream.Collectors; 30 import java.util.stream.Collectors;
32 31
33 @Slf4j 32 @Slf4j
34 @Service 33 @Service
35 @RequiredArgsConstructor 34 @RequiredArgsConstructor
36 public class YtReportFromConfigServiceImpl 35 public class YtReportFromConfigServiceImpl
37 - extends AbstractBaseService<ReportFromConfigMapper, ReportFormConfig> 36 + extends AbstractBaseService<ReportFormConfigMapper, ReportFormConfig>
38 implements YtReportFormConfigService { 37 implements YtReportFormConfigService {
39 private final OrganizationMapper organizationMapper; 38 private final OrganizationMapper organizationMapper;
40 private final YtSysJobService ytSysJobService; 39 private final YtSysJobService ytSysJobService;
@@ -43,11 +42,6 @@ public class YtReportFromConfigServiceImpl @@ -43,11 +42,6 @@ public class YtReportFromConfigServiceImpl
43 public YtPageData<ReportFormConfigDTO> page(Map<String, Object> queryMap) { 42 public YtPageData<ReportFormConfigDTO> page(Map<String, Object> queryMap) {
44 String tenantId = 43 String tenantId =
45 Optional.ofNullable(queryMap.get("tenantId")).map(Object::toString).orElse(null); 44 Optional.ofNullable(queryMap.get("tenantId")).map(Object::toString).orElse(null);
46 - String name = Optional.ofNullable(queryMap.get("name")).map(Object::toString).orElse(null);  
47 - Integer status =  
48 - Optional.ofNullable(queryMap.get("status"))  
49 - .map(value -> Integer.valueOf(value.toString()))  
50 - .orElse(null);  
51 List<String> organizationIds = 45 List<String> organizationIds =
52 Optional.ofNullable(queryMap.get("organizationId")) 46 Optional.ofNullable(queryMap.get("organizationId"))
53 .map( 47 .map(
@@ -63,17 +57,10 @@ public class YtReportFromConfigServiceImpl @@ -63,17 +57,10 @@ public class YtReportFromConfigServiceImpl
63 return null; 57 return null;
64 }) 58 })
65 .orElse(null); 59 .orElse(null);
66 - IPage<ReportFormConfig> page =  
67 - baseMapper.selectPage(  
68 - getPage(queryMap, "create_time", false),  
69 - new LambdaQueryWrapper<ReportFormConfig>()  
70 - .eq(StringUtils.isNotEmpty(tenantId), ReportFormConfig::getTenantId, tenantId)  
71 - .eq(null != status, ReportFormConfig::getStatus, status)  
72 - .like(null != name, ReportFormConfig::getName, name)  
73 - .in(  
74 - null != organizationIds && organizationIds.size() > 0,  
75 - ReportFormConfig::getOrganizationId,  
76 - organizationIds)); 60 + queryMap.put("organizationIds", organizationIds);
  61 + IPage<ReportFormConfigDTO> page =
  62 + baseMapper.getReportFormConfigPage(
  63 + getPage(queryMap, FastIotConstants.DefaultOrder.CREATE_TIME, false), queryMap);
77 return getPageData(page, ReportFormConfigDTO.class); 64 return getPageData(page, ReportFormConfigDTO.class);
78 } 65 }
79 66
@@ -93,8 +80,7 @@ public class YtReportFromConfigServiceImpl @@ -93,8 +80,7 @@ public class YtReportFromConfigServiceImpl
93 .getExecuteAttributes() 80 .getExecuteAttributes()
94 .forEach( 81 .forEach(
95 item -> { 82 item -> {
96 - if (StringUtils.isEmpty(item.getDevice())  
97 - || StringUtils.isEmpty(item.getAttribute())) { 83 + if (StringUtils.isEmpty(item.getDevice()) || item.getAttributes().isEmpty()) {
98 throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); 84 throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
99 } 85 }
100 }); 86 });
@@ -123,7 +109,7 @@ public class YtReportFromConfigServiceImpl @@ -123,7 +109,7 @@ public class YtReportFromConfigServiceImpl
123 109
124 @Override 110 @Override
125 @Transactional 111 @Transactional
126 - public boolean deleteReportFormConfig(DeleteDTO deleteDTO) { 112 + public boolean deleteReportFormConfig(DeleteDTO deleteDTO) throws SchedulerException {
127 if (deleteDTO.getIds().isEmpty()) { 113 if (deleteDTO.getIds().isEmpty()) {
128 throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); 114 throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
129 } 115 }
@@ -146,11 +132,13 @@ public class YtReportFromConfigServiceImpl @@ -146,11 +132,13 @@ public class YtReportFromConfigServiceImpl
146 new LambdaQueryWrapper<ReportFormConfig>() 132 new LambdaQueryWrapper<ReportFormConfig>()
147 .eq(ReportFormConfig::getId, id) 133 .eq(ReportFormConfig::getId, id)
148 .eq(ReportFormConfig::getTenantId, tenantId)); 134 .eq(ReportFormConfig::getTenantId, tenantId));
149 - updateCheckSysJob(queryEntity); 135 + if (queryEntity != null) {
  136 + queryEntity.setStatus(status);
  137 + updateCheckSysJob(queryEntity);
  138 + }
150 return Optional.ofNullable(queryEntity) 139 return Optional.ofNullable(queryEntity)
151 .map( 140 .map(
152 entity -> { 141 entity -> {
153 - entity.setStatus(status);  
154 baseMapper.updateById(entity); 142 baseMapper.updateById(entity);
155 return entity.getDTO(ReportFormConfigDTO.class); 143 return entity.getDTO(ReportFormConfigDTO.class);
156 }) 144 })
@@ -167,14 +155,26 @@ public class YtReportFromConfigServiceImpl @@ -167,14 +155,26 @@ public class YtReportFromConfigServiceImpl
167 if (null == formConfig) { 155 if (null == formConfig) {
168 throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); 156 throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
169 } 157 }
170 - return formConfig.getDTO(ReportFormConfigDTO.class); 158 + return getReportFormConfigDTOByEntity(formConfig);
  159 + }
  160 +
  161 + @Override
  162 + public ReportFormConfigDTO findReportFormConfigById(String id) {
  163 + return Optional.ofNullable(baseMapper.selectById(id))
  164 + .map(obj -> getReportFormConfigDTOByEntity(obj))
  165 + .orElseThrow(
  166 + () -> {
  167 + throw new YtDataValidationException(ErrorMessage.INTERNAL_ERROR.getMessage());
  168 + });
171 } 169 }
172 170
173 private void addCheckSysJob(ReportFormConfig reportFormConfig) throws SchedulerException { 171 private void addCheckSysJob(ReportFormConfig reportFormConfig) throws SchedulerException {
174 boolean isNowExecute = 172 boolean isNowExecute =
175 Objects.equals(reportFormConfig.getExecuteWay(), FastIotConstants.MagicNumber.ZERO); 173 Objects.equals(reportFormConfig.getExecuteWay(), FastIotConstants.MagicNumber.ZERO);
176 if (isNowExecute) { 174 if (isNowExecute) {
177 - // 立即执行报表生成,并创建一条报表执行记录 175 + if (Objects.equals(reportFormConfig.getStatus(), StatusEnum.ENABLE.getIndex())) {
  176 + // 立即执行报表生成,并创建一条报表执行记录
  177 + }
178 } else { 178 } else {
179 createSysJob(reportFormConfig); 179 createSysJob(reportFormConfig);
180 } 180 }
@@ -186,30 +186,29 @@ public class YtReportFromConfigServiceImpl @@ -186,30 +186,29 @@ public class YtReportFromConfigServiceImpl
186 String cronExpression = reportFormConfig.getExecuteContent(); 186 String cronExpression = reportFormConfig.getExecuteContent();
187 // 查看之前是否创建了定时任务 187 // 查看之前是否创建了定时任务
188 SysJobDTO sysJobDTO = ytSysJobService.findSysJobBySourceId(reportFormConfig.getId()); 188 SysJobDTO sysJobDTO = ytSysJobService.findSysJobBySourceId(reportFormConfig.getId());
189 -  
190 - if (null != sysJobDTO  
191 - && Objects.equals(reportFormConfig.getStatus(), StatusEnum.ENABLE.getIndex())) { 189 + boolean enableStatus =
  190 + Objects.equals(reportFormConfig.getStatus(), StatusEnum.ENABLE.getIndex());
  191 + if (null != sysJobDTO) {
192 // 立即执行 192 // 立即执行
193 if (isNowExecute) { 193 if (isNowExecute) {
194 // 删除定时任务 194 // 删除定时任务
195 ytSysJobService.deleteJob(sysJobDTO); 195 ytSysJobService.deleteJob(sysJobDTO);
196 - // 立即执行报表生成,并创建一条报表执行记录  
197 - // TODO hxp 196 + if (enableStatus) {
  197 + // 立即执行报表生成,并创建一条报表执行记录
  198 + // TODO hxp
  199 + }
198 } else { 200 } else {
199 // 修改cron表达式 201 // 修改cron表达式
200 sysJobDTO.setCronExpression(cronExpression); 202 sysJobDTO.setCronExpression(cronExpression);
  203 + sysJobDTO.setStatus(reportFormConfig.getStatus());
201 ytSysJobService.saveOrUpdateJob(sysJobDTO); 204 ytSysJobService.saveOrUpdateJob(sysJobDTO);
202 } 205 }
203 - } else if (null != sysJobDTO  
204 - && Objects.equals(reportFormConfig.getStatus(), StatusEnum.DISABLE.getIndex())) {  
205 - // 修改定时任务状态  
206 - sysJobDTO.setStatus(StatusEnum.DISABLE.getIndex());  
207 - ytSysJobService.updateSysJobStatus(sysJobDTO);  
208 - } else if (null == sysJobDTO  
209 - && Objects.equals(reportFormConfig.getStatus(), StatusEnum.ENABLE.getIndex())) { 206 + } else {
210 if (isNowExecute) { 207 if (isNowExecute) {
211 - // 立即执行报表生成,并创建一条报表执行记录  
212 - // TODO hxp 208 + if (enableStatus) {
  209 + // 立即执行报表生成,并创建一条报表执行记录
  210 + // TODO hxp
  211 + }
213 } else { 212 } else {
214 createSysJob(reportFormConfig); 213 createSysJob(reportFormConfig);
215 } 214 }
@@ -240,7 +239,7 @@ public class YtReportFromConfigServiceImpl @@ -240,7 +239,7 @@ public class YtReportFromConfigServiceImpl
240 sysJobDTO.setTenantId(reportFormConfig.getTenantId()); 239 sysJobDTO.setTenantId(reportFormConfig.getTenantId());
241 sysJobDTO.setCronExpression(cronExpression); 240 sysJobDTO.setCronExpression(cronExpression);
242 sysJobDTO.setConcurrent(StatusEnum.ENABLE.getIndex()); 241 sysJobDTO.setConcurrent(StatusEnum.ENABLE.getIndex());
243 - sysJobDTO.setInvokeTarget("reportTask.generateReport(\""+reportId+"\")"); 242 + sysJobDTO.setInvokeTarget("reportTask.generateReport(\"" + reportId + "\")");
244 ytSysJobService.saveOrUpdateJob(sysJobDTO); 243 ytSysJobService.saveOrUpdateJob(sysJobDTO);
245 } 244 }
246 } 245 }
@@ -250,24 +249,36 @@ public class YtReportFromConfigServiceImpl @@ -250,24 +249,36 @@ public class YtReportFromConfigServiceImpl
250 * 249 *
251 * @param id 配置ID 250 * @param id 配置ID
252 */ 251 */
253 - private void checkAndDeleteJob(String id) { 252 + private void checkAndDeleteJob(String id) throws SchedulerException {
254 ReportFormConfig config = baseMapper.selectById(id); 253 ReportFormConfig config = baseMapper.selectById(id);
255 - Optional.ofNullable(config)  
256 - .map(  
257 - obj -> {  
258 - SysJobDTO sysJobDTO = ytSysJobService.findSysJobBySourceId(id);  
259 - if (null != sysJobDTO) {  
260 - try {  
261 - ytSysJobService.deleteJob(sysJobDTO);  
262 - } catch (SchedulerException e) {  
263 - log.error(e.getMessage());  
264 - }  
265 - }  
266 - return sysJobDTO;  
267 - })  
268 - .orElseThrow(  
269 - () -> {  
270 - throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());  
271 - }); 254 + if (null != config) {
  255 + SysJobDTO sysJobDTO = ytSysJobService.findSysJobBySourceId(id);
  256 + if (null != sysJobDTO) {
  257 + ytSysJobService.deleteJob(sysJobDTO);
  258 + }
  259 + }
  260 + }
  261 +
  262 + private ReportFormConfigDTO getReportFormConfigDTOByEntity(ReportFormConfig obj) {
  263 + ReportFormConfigDTO dto = new ReportFormConfigDTO();
  264 + obj.copyToDTO(dto, "executeAttributes");
  265 + JsonNode jsonNode = obj.getExecuteAttributes();
  266 + List<ExecuteAttributesDTO> list = new ArrayList<>();
  267 + for (JsonNode node : jsonNode) {
  268 + ExecuteAttributesDTO attributesDTO =
  269 + JacksonUtil.convertValue(node, ExecuteAttributesDTO.class);
  270 + List<String> attributes = new ArrayList<>();
  271 + JsonNode attribute = node.get("attributes");
  272 + for (JsonNode key : attribute) {
  273 + attributes.add(JacksonUtil.convertValue(key, String.class));
  274 + }
  275 + attributesDTO.setAttributes(attributes);
  276 + list.add(attributesDTO);
  277 + }
  278 + QueryConditionDTO queryCondition =
  279 + JacksonUtil.convertValue(obj.getQueryCondition(), QueryConditionDTO.class);
  280 + dto.setExecuteAttributes(list);
  281 + dto.setQueryCondition(queryCondition);
  282 + return dto;
272 } 283 }
273 } 284 }
@@ -48,7 +48,7 @@ public class YtReportGenerateRecordServiceImpl @@ -48,7 +48,7 @@ public class YtReportGenerateRecordServiceImpl
48 .orElse(null); 48 .orElse(null);
49 IPage<ReportGenerateRecord> iPage = 49 IPage<ReportGenerateRecord> iPage =
50 baseMapper.selectPage( 50 baseMapper.selectPage(
51 - getPage(queryMap, "", false), 51 + getPage(queryMap, "execute_time", false),
52 new LambdaQueryWrapper<ReportGenerateRecord>() 52 new LambdaQueryWrapper<ReportGenerateRecord>()
53 .like( 53 .like(
54 StringUtils.isNotEmpty(reportConfigName), 54 StringUtils.isNotEmpty(reportConfigName),
@@ -71,16 +71,15 @@ public class YtReportGenerateRecordServiceImpl @@ -71,16 +71,15 @@ public class YtReportGenerateRecordServiceImpl
71 if (StringUtils.isEmpty(recordDTO.getId())) { 71 if (StringUtils.isEmpty(recordDTO.getId())) {
72 baseMapper.insert(reportGenerateRecord); 72 baseMapper.insert(reportGenerateRecord);
73 } else { 73 } else {
74 - Optional.ofNullable(recordDTO.getId())  
75 - .map(id -> baseMapper.selectById(id))  
76 - .filter(obj -> !obj.getTenantId().equals(recordDTO.getTenantId()))  
77 - .map(record -> baseMapper.updateById(record)) 74 + ReportGenerateRecord record = baseMapper.selectById(recordDTO.getId());
  75 + Optional.ofNullable(record)
  76 + .map(obj -> baseMapper.updateById(reportGenerateRecord))
78 .orElseThrow( 77 .orElseThrow(
79 () -> { 78 () -> {
80 throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); 79 throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
81 }); 80 });
82 } 81 }
83 - return recordDTO; 82 + return reportGenerateRecord.getDTO(ReportGenerateRecordDTO.class);
84 } 83 }
85 84
86 @Override 85 @Override
@@ -111,17 +110,20 @@ public class YtReportGenerateRecordServiceImpl @@ -111,17 +110,20 @@ public class YtReportGenerateRecordServiceImpl
111 } 110 }
112 OrganizationDTO organizationDTO = 111 OrganizationDTO organizationDTO =
113 ytOrganizationService.findOrganizationById( 112 ytOrganizationService.findOrganizationById(
114 - reportFormConfigDTO.getId(), reportFormConfigDTO.getTenantId()); 113 + reportFormConfigDTO.getOrganizationId(), reportFormConfigDTO.getTenantId());
115 // 创建报表生成记录 114 // 创建报表生成记录
116 ReportGenerateRecordDTO dto = new ReportGenerateRecordDTO(); 115 ReportGenerateRecordDTO dto = new ReportGenerateRecordDTO();
  116 + LocalDateTime time = LocalDateTime.now();
117 dto.setJobId(jobId); 117 dto.setJobId(jobId);
118 dto.setReportConfigName(reportFormConfigDTO.getName()); 118 dto.setReportConfigName(reportFormConfigDTO.getName());
119 dto.setOrganizationName(null != organizationDTO ? organizationDTO.getName() : null); 119 dto.setOrganizationName(null != organizationDTO ? organizationDTO.getName() : null);
120 - dto.setDataCompare(reportFormConfigDTO.getDataCompare());  
121 - dto.setExecuteTime(LocalDateTime.now()); 120 + dto.setDataCompare(reportFormConfigDTO.getDataType());
  121 + dto.setExecuteTime(time);
  122 + dto.setCreateTime(time);
  123 + dto.setCreator(reportFormConfigDTO.getCreator());
  124 + dto.setTenantId(reportFormConfigDTO.getTenantId());
122 dto.setExecuteStatus(StatusEnum.RUNNING.getIndex()); 125 dto.setExecuteStatus(StatusEnum.RUNNING.getIndex());
123 dto.setExecuteWay(reportFormConfigDTO.getExecuteWay()); 126 dto.setExecuteWay(reportFormConfigDTO.getExecuteWay());
124 - saveOrUpdateReportGenerateRecord(dto);  
125 - return dto; 127 + return saveOrUpdateReportGenerateRecord(dto);
126 } 128 }
127 } 129 }
dao/src/main/java/org/thingsboard/server/dao/yunteng/mapper/ReportFormConfigMapper.java renamed from dao/src/main/java/org/thingsboard/server/dao/yunteng/mapper/ReportFromConfigMapper.java
1 package org.thingsboard.server.dao.yunteng.mapper; 1 package org.thingsboard.server.dao.yunteng.mapper;
2 2
3 import com.baomidou.mybatisplus.core.mapper.BaseMapper; 3 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import com.baomidou.mybatisplus.core.metadata.IPage;
4 import org.apache.ibatis.annotations.Mapper; 5 import org.apache.ibatis.annotations.Mapper;
5 -import org.thingsboard.server.dao.yunteng.entities.FrpInfo; 6 +import org.apache.ibatis.annotations.Param;
  7 +import org.thingsboard.server.common.data.yunteng.dto.ReportFormConfigDTO;
6 import org.thingsboard.server.dao.yunteng.entities.ReportFormConfig; 8 import org.thingsboard.server.dao.yunteng.entities.ReportFormConfig;
7 9
8 -@Mapper  
9 -public interface ReportFromConfigMapper extends BaseMapper<ReportFormConfig> { 10 +import java.util.Map;
10 11
  12 +@Mapper
  13 +public interface ReportFormConfigMapper extends BaseMapper<ReportFormConfig> {
  14 + IPage<ReportFormConfigDTO> getReportFormConfigPage(
  15 + IPage<?> page, @Param("queryMap") Map<String, Object> queryMap);
11 } 16 }
@@ -12,9 +12,11 @@ public interface YtReportFormConfigService { @@ -12,9 +12,11 @@ public interface YtReportFormConfigService {
12 12
13 ReportFormConfigDTO saveOrUpdateReportFormConfig(ReportFormConfigDTO report) throws SchedulerException; 13 ReportFormConfigDTO saveOrUpdateReportFormConfig(ReportFormConfigDTO report) throws SchedulerException;
14 14
15 - boolean deleteReportFormConfig(DeleteDTO deleteDTO); 15 + boolean deleteReportFormConfig(DeleteDTO deleteDTO) throws SchedulerException;
16 16
17 ReportFormConfigDTO updateStatusById(String tenantId,Integer status,String id) throws SchedulerException; 17 ReportFormConfigDTO updateStatusById(String tenantId,Integer status,String id) throws SchedulerException;
18 18
19 ReportFormConfigDTO findReportFormConfigById(String id,String tenantId); 19 ReportFormConfigDTO findReportFormConfigById(String id,String tenantId);
  20 +
  21 + ReportFormConfigDTO findReportFormConfigById(String id);
20 } 22 }
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +
  4 +<mapper namespace="org.thingsboard.server.dao.yunteng.mapper.ReportFormConfigMapper">
  5 + <resultMap id="formConfigDtoMap" type="org.thingsboard.server.common.data.yunteng.dto.ReportFormConfigDTO">
  6 + <result property="id" column="id"/>
  7 + <result property="name" column="name"/>
  8 + <result property="organizationId" column="organization_id"/>
  9 + <result property="executeWay" column="execute_way"/>
  10 + <result property="executeContent" column="execute_content"/>
  11 + <result property="dataType" column="data_type"/>
  12 + <result property="startTs" column="start_ts"/>
  13 + <result property="endTs" column="end_ts"/>
  14 + <result property="status" column="status"/>
  15 + <result property="remark" column="remark"/>
  16 + <result property="tenantId" column="tenant_id"/>
  17 + <result property="creator" column="creator"/>
  18 + <result property="createTime" column="create_time"/>
  19 + <result property="updater" column="updater"/>
  20 + <result property="updateTime" column="update_time"/>
  21 + <association property="organizationDTO"
  22 + javaType="org.thingsboard.server.common.data.yunteng.dto.OrganizationDTO">
  23 + <result property="name" column="organization_name"/>
  24 + </association>
  25 + </resultMap>
  26 +
  27 + <sql id="columns">
  28 + config.id,config.name,config.organization_id,config.execute_way,config.execute_content,
  29 + config.data_type,config.start_ts,config.end_ts,config.status,config.remark,config.create_time,config.creator,
  30 + config.updater,config.update_time,config.tenant_id
  31 + </sql>
  32 + <select id="getReportFormConfigPage" resultMap="formConfigDtoMap">
  33 + SELECT
  34 + <include refid="columns"/>,io.name as organization_name
  35 + FROM iotfs_report_form_config config
  36 + LEFT JOIN iotfs_organization io ON io.id = config.organization_id
  37 + <where>
  38 + config.tenant_id = #{queryMap.tenantId}
  39 + <if test="queryMap.name !=null and queryMap.name !=''">
  40 + AND config.name LIKE concat('%',#{queryMap.name}::TEXT,'%')
  41 + </if>
  42 + <if test="queryMap.status !=null">
  43 + AND config.status = #{queryMap.status}
  44 + </if>
  45 + <if test="queryMap.organizationIds !=null">
  46 + AND config.organization_id IN
  47 + <foreach collection="queryMap.organizationIds" item="organizationId" open="(" separator="," close=")">
  48 + #{organizationId}
  49 + </foreach>
  50 + </if>
  51 + </where>
  52 + </select>
  53 +</mapper>