Commit 33b6d592c77c135e8fcbe835c45fd5de50b98243
1 parent
c495fa5b
fix: fix many to many device generate excel bug
Showing
6 changed files
with
246 additions
and
175 deletions
... | ... | @@ -34,7 +34,7 @@ public class YtReportGenerateRecordController extends BaseController { |
34 | 34 | @RequestParam(PAGE_SIZE) int pageSize, |
35 | 35 | @RequestParam(PAGE) int page, |
36 | 36 | @RequestParam(value = "reportConfigName", required = false) String reportConfigName, |
37 | - @RequestParam(value = "status", required = false) Integer status, | |
37 | + @RequestParam(value = "executeStatus", required = false) Integer executeStatus, | |
38 | 38 | @RequestParam(value = ORDER_FILED, required = false) String orderBy, |
39 | 39 | @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType) |
40 | 40 | throws ThingsboardException { |
... | ... | @@ -44,7 +44,7 @@ public class YtReportGenerateRecordController extends BaseController { |
44 | 44 | queryMap.put(PAGE, page); |
45 | 45 | queryMap.put(ORDER_FILED, orderBy); |
46 | 46 | queryMap.put("reportConfigName", reportConfigName); |
47 | - queryMap.put("status", status); | |
47 | + queryMap.put("executeStatus", executeStatus); | |
48 | 48 | queryMap.put("tenantId", getCurrentUser().getCurrentTenantId()); |
49 | 49 | if (orderType != null) { |
50 | 50 | queryMap.put(ORDER_TYPE, orderType.name()); | ... | ... |
1 | 1 | package org.thingsboard.server.common.data.yunteng.utils; |
2 | 2 | |
3 | 3 | import com.alibaba.excel.EasyExcel; |
4 | +import com.alibaba.excel.ExcelWriter; | |
5 | +import com.alibaba.excel.write.metadata.WriteSheet; | |
4 | 6 | import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; |
5 | 7 | import org.apache.commons.lang3.StringUtils; |
6 | 8 | import org.springframework.beans.BeanUtils; |
... | ... | @@ -17,6 +19,7 @@ import java.util.List; |
17 | 19 | |
18 | 20 | public class ExcelUtil { |
19 | 21 | private ExcelUtil() {} |
22 | + | |
20 | 23 | public static void exportExcel( |
21 | 24 | HttpServletResponse response, |
22 | 25 | String fileName, |
... | ... | @@ -54,14 +57,26 @@ public class ExcelUtil { |
54 | 57 | exportExcel(response, fileName, sheetName, targetList, targetClass); |
55 | 58 | } |
56 | 59 | |
57 | - public static ByteArrayOutputStream noModelWrite(String fileName, List<List<String>> heads, List<?> data) { | |
60 | + public static ByteArrayOutputStream noModelWrite( | |
61 | + String fileName, List<List<String>> heads, List<?> data) { | |
58 | 62 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); |
59 | 63 | EasyExcel.write(byteArrayOutputStream) |
60 | - .head(heads) | |
61 | - .sheet(fileName) | |
62 | - // 自适应列宽 | |
63 | - .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) | |
64 | - .doWrite(data); | |
64 | + .head(heads) | |
65 | + .sheet(fileName) | |
66 | + // 自适应列宽 | |
67 | + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) | |
68 | + .doWrite(data); | |
65 | 69 | return byteArrayOutputStream; |
66 | 70 | } |
71 | + | |
72 | + public static void noModelWrite( | |
73 | + ExcelWriter excelWriter, | |
74 | + List<List<String>> heads, | |
75 | + List<?> data, | |
76 | + int sheetNo, | |
77 | + String newSheetName) { | |
78 | + WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo, newSheetName).head(heads).build(); | |
79 | + excelWriter.write(data, writeSheet); | |
80 | + } | |
81 | + | |
67 | 82 | } | ... | ... |
1 | 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 | 3 | import lombok.RequiredArgsConstructor; |
7 | 4 | import lombok.extern.slf4j.Slf4j; |
8 | -import org.jetbrains.annotations.NotNull; | |
9 | -import org.springframework.http.HttpStatus; | |
10 | -import org.springframework.http.ResponseEntity; | |
11 | 5 | 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 | 6 | import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants; |
18 | -import org.thingsboard.server.common.data.yunteng.core.utils.FileStorageService; | |
19 | 7 | 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 | 8 | 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 | 9 | import org.thingsboard.server.dao.yunteng.service.YtReportFormConfigService; |
28 | 10 | 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 | 11 | import java.util.*; |
36 | -import java.util.stream.Collectors; | |
37 | 12 | |
38 | 13 | @Component("reportTask") |
39 | 14 | @RequiredArgsConstructor |
40 | 15 | @Slf4j |
41 | 16 | public class ReportTask { |
42 | - private static final String CONTENT_TYPE = | |
43 | - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; | |
44 | 17 | private final YtReportFormConfigService ytReportFormConfigService; |
45 | - private final TimeseriesService tsService; | |
46 | - private final FileStorageService fileStorageService; | |
18 | + | |
47 | 19 | private final YtReportGenerateRecordService ytReportGenerateRecordService; |
48 | 20 | |
49 | 21 | public void multipleParams(String s, Boolean b, Long l, Double d, Integer i) { |
... | ... | @@ -68,147 +40,22 @@ public class ReportTask { |
68 | 40 | if (dtoList.size() == FastIotConstants.MagicNumber.ONE) { |
69 | 41 | try { |
70 | 42 | ExecuteAttributesDTO attributesDTO = dtoList.get(0); |
71 | - getTsKv(formConfigDTO, attributesDTO, reportGenerateRecordId); | |
43 | + getTsKvForGenerateExcel(formConfigDTO, attributesDTO, reportGenerateRecordId); | |
72 | 44 | |
73 | 45 | } catch (Exception e) { |
74 | 46 | log.error(e.getMessage()); |
75 | 47 | } |
76 | 48 | } else { |
77 | 49 | for (ExecuteAttributesDTO dto : dtoList) { |
78 | - getTsKv(formConfigDTO, dto, reportGenerateRecordId); | |
50 | + getTsKvForGenerateExcel(formConfigDTO, dto, reportGenerateRecordId); | |
79 | 51 | } |
80 | 52 | } |
81 | 53 | } |
82 | 54 | } |
83 | 55 | |
84 | - private void getTsKv( | |
56 | + private void getTsKvForGenerateExcel( | |
85 | 57 | 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()); | |
103 | - | |
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); | |
148 | - } | |
149 | - return entry.getValue(); | |
150 | - } | |
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 | - } | |
58 | + ytReportGenerateRecordService.generateExcelUpdateReportRecord( | |
59 | + formConfigDTO, dto, reportGenerateRecordId); | |
213 | 60 | } |
214 | 61 | } | ... | ... |
... | ... | @@ -24,6 +24,7 @@ import org.thingsboard.server.dao.yunteng.mapper.OrganizationMapper; |
24 | 24 | import org.thingsboard.server.dao.yunteng.mapper.ReportFormConfigMapper; |
25 | 25 | import org.thingsboard.server.dao.yunteng.service.AbstractBaseService; |
26 | 26 | import org.thingsboard.server.dao.yunteng.service.YtReportFormConfigService; |
27 | +import org.thingsboard.server.dao.yunteng.service.YtReportGenerateRecordService; | |
27 | 28 | import org.thingsboard.server.dao.yunteng.service.YtSysJobService; |
28 | 29 | |
29 | 30 | import java.util.*; |
... | ... | @@ -37,6 +38,7 @@ public class YtReportFromConfigServiceImpl |
37 | 38 | implements YtReportFormConfigService { |
38 | 39 | private final OrganizationMapper organizationMapper; |
39 | 40 | private final YtSysJobService ytSysJobService; |
41 | + private final YtReportGenerateRecordService ytReportGenerateRecordService; | |
40 | 42 | |
41 | 43 | @Override |
42 | 44 | public YtPageData<ReportFormConfigDTO> page(Map<String, Object> queryMap) { |
... | ... | @@ -161,7 +163,7 @@ public class YtReportFromConfigServiceImpl |
161 | 163 | @Override |
162 | 164 | public ReportFormConfigDTO findReportFormConfigById(String id) { |
163 | 165 | return Optional.ofNullable(baseMapper.selectById(id)) |
164 | - .map(obj -> getReportFormConfigDTOByEntity(obj)) | |
166 | + .map(this::getReportFormConfigDTOByEntity) | |
165 | 167 | .orElseThrow( |
166 | 168 | () -> { |
167 | 169 | throw new YtDataValidationException(ErrorMessage.INTERNAL_ERROR.getMessage()); |
... | ... | @@ -174,6 +176,8 @@ public class YtReportFromConfigServiceImpl |
174 | 176 | if (isNowExecute) { |
175 | 177 | if (Objects.equals(reportFormConfig.getStatus(), StatusEnum.ENABLE.getIndex())) { |
176 | 178 | // 立即执行报表生成,并创建一条报表执行记录 |
179 | + // 生成Excel,并更新报表执行记录 | |
180 | + generateExcelUpdateReportRecord(reportFormConfig.getDTO(ReportFormConfigDTO.class)); | |
177 | 181 | } |
178 | 182 | } else { |
179 | 183 | createSysJob(reportFormConfig); |
... | ... | @@ -195,7 +199,8 @@ public class YtReportFromConfigServiceImpl |
195 | 199 | ytSysJobService.deleteJob(sysJobDTO); |
196 | 200 | if (enableStatus) { |
197 | 201 | // 立即执行报表生成,并创建一条报表执行记录 |
198 | - // TODO hxp | |
202 | + // 生成Excel,并更新报表执行记录 | |
203 | + generateExcelUpdateReportRecord(reportFormConfig.getDTO(ReportFormConfigDTO.class)); | |
199 | 204 | } |
200 | 205 | } else { |
201 | 206 | // 修改cron表达式 |
... | ... | @@ -207,7 +212,8 @@ public class YtReportFromConfigServiceImpl |
207 | 212 | if (isNowExecute) { |
208 | 213 | if (enableStatus) { |
209 | 214 | // 立即执行报表生成,并创建一条报表执行记录 |
210 | - // TODO hxp | |
215 | + // 生成Excel,并更新报表执行记录 | |
216 | + generateExcelUpdateReportRecord(reportFormConfig.getDTO(ReportFormConfigDTO.class)); | |
211 | 217 | } |
212 | 218 | } else { |
213 | 219 | createSysJob(reportFormConfig); |
... | ... | @@ -272,6 +278,7 @@ public class YtReportFromConfigServiceImpl |
272 | 278 | for (JsonNode key : attribute) { |
273 | 279 | attributes.add(JacksonUtil.convertValue(key, String.class)); |
274 | 280 | } |
281 | + assert attributesDTO != null; | |
275 | 282 | attributesDTO.setAttributes(attributes); |
276 | 283 | list.add(attributesDTO); |
277 | 284 | } |
... | ... | @@ -281,4 +288,19 @@ public class YtReportFromConfigServiceImpl |
281 | 288 | dto.setQueryCondition(queryCondition); |
282 | 289 | return dto; |
283 | 290 | } |
291 | + | |
292 | + private void generateExcelUpdateReportRecord(ReportFormConfigDTO reportFormConfigDTO) { | |
293 | + if (reportFormConfigDTO == null) { | |
294 | + throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); | |
295 | + } | |
296 | + // 立即执行报表生成,并创建一条报表执行记录 | |
297 | + ReportGenerateRecordDTO recordDTO = | |
298 | + ytReportGenerateRecordService.generateReportRecord( | |
299 | + reportFormConfigDTO.getId(), reportFormConfigDTO.getTenantId(), null); | |
300 | + // 生成Excel,并更新报表执行记录 | |
301 | + for (ExecuteAttributesDTO dto : reportFormConfigDTO.getExecuteAttributes()) { | |
302 | + ytReportGenerateRecordService.generateExcelUpdateReportRecord( | |
303 | + reportFormConfigDTO, dto, recordDTO.getId()); | |
304 | + } | |
305 | + } | |
284 | 306 | } | ... | ... |
... | ... | @@ -2,18 +2,36 @@ package org.thingsboard.server.dao.yunteng.impl; |
2 | 2 | |
3 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
4 | 4 | import com.baomidou.mybatisplus.core.metadata.IPage; |
5 | +import com.google.common.util.concurrent.FutureCallback; | |
6 | +import com.google.common.util.concurrent.Futures; | |
7 | +import com.google.common.util.concurrent.MoreExecutors; | |
5 | 8 | import lombok.RequiredArgsConstructor; |
9 | +import lombok.extern.slf4j.Slf4j; | |
6 | 10 | import org.apache.commons.lang3.StringUtils; |
11 | +import org.jetbrains.annotations.NotNull; | |
12 | +import org.springframework.http.HttpStatus; | |
13 | +import org.springframework.http.ResponseEntity; | |
7 | 14 | import org.springframework.stereotype.Service; |
15 | +import org.springframework.web.context.request.async.DeferredResult; | |
16 | +import org.thingsboard.common.util.JacksonUtil; | |
17 | +import org.thingsboard.server.common.data.id.DeviceId; | |
18 | +import org.thingsboard.server.common.data.id.TenantId; | |
19 | +import org.thingsboard.server.common.data.kv.*; | |
8 | 20 | import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants; |
9 | 21 | import org.thingsboard.server.common.data.yunteng.core.exception.YtDataValidationException; |
10 | 22 | import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage; |
23 | +import org.thingsboard.server.common.data.yunteng.core.utils.FileStorageService; | |
11 | 24 | import org.thingsboard.server.common.data.yunteng.dto.DeleteDTO; |
12 | 25 | import org.thingsboard.server.common.data.yunteng.dto.OrganizationDTO; |
13 | 26 | import org.thingsboard.server.common.data.yunteng.dto.ReportFormConfigDTO; |
14 | 27 | import org.thingsboard.server.common.data.yunteng.dto.ReportGenerateRecordDTO; |
28 | +import org.thingsboard.server.common.data.yunteng.dto.report.BasicData; | |
29 | +import org.thingsboard.server.common.data.yunteng.dto.request.ExecuteAttributesDTO; | |
30 | +import org.thingsboard.server.common.data.yunteng.dto.request.QueryConditionDTO; | |
15 | 31 | import org.thingsboard.server.common.data.yunteng.enums.StatusEnum; |
32 | +import org.thingsboard.server.common.data.yunteng.utils.ExcelUtil; | |
16 | 33 | import org.thingsboard.server.common.data.yunteng.utils.tools.YtPageData; |
34 | +import org.thingsboard.server.dao.timeseries.TimeseriesService; | |
17 | 35 | import org.thingsboard.server.dao.yunteng.entities.ReportGenerateRecord; |
18 | 36 | import org.thingsboard.server.dao.yunteng.mapper.ReportGenerateRecordMapper; |
19 | 37 | import org.thingsboard.server.dao.yunteng.service.AbstractBaseService; |
... | ... | @@ -21,18 +39,29 @@ import org.thingsboard.server.dao.yunteng.service.YtOrganizationService; |
21 | 39 | import org.thingsboard.server.dao.yunteng.service.YtReportFormConfigService; |
22 | 40 | import org.thingsboard.server.dao.yunteng.service.YtReportGenerateRecordService; |
23 | 41 | |
42 | +import java.io.ByteArrayInputStream; | |
43 | +import java.io.ByteArrayOutputStream; | |
44 | +import java.io.InputStream; | |
45 | +import java.sql.Timestamp; | |
24 | 46 | import java.time.LocalDateTime; |
25 | -import java.util.Map; | |
26 | -import java.util.Optional; | |
47 | +import java.time.ZoneOffset; | |
48 | +import java.time.format.DateTimeFormatter; | |
49 | +import java.util.*; | |
50 | +import java.util.stream.Collectors; | |
27 | 51 | |
28 | 52 | @Service |
29 | 53 | @RequiredArgsConstructor |
54 | +@Slf4j | |
30 | 55 | public class YtReportGenerateRecordServiceImpl |
31 | 56 | extends AbstractBaseService<ReportGenerateRecordMapper, ReportGenerateRecord> |
32 | 57 | implements YtReportGenerateRecordService { |
33 | 58 | |
59 | + private static final String CONTENT_TYPE = | |
60 | + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; | |
34 | 61 | private final YtReportFormConfigService ytReportFormConfigService; |
35 | 62 | private final YtOrganizationService ytOrganizationService; |
63 | + private final TimeseriesService tsService; | |
64 | + private final FileStorageService fileStorageService; | |
36 | 65 | |
37 | 66 | @Override |
38 | 67 | public YtPageData<ReportGenerateRecordDTO> page(Map<String, Object> queryMap) { |
... | ... | @@ -42,8 +71,8 @@ public class YtReportGenerateRecordServiceImpl |
42 | 71 | (LocalDateTime) Optional.ofNullable(queryMap.get("startTime")).orElse(null); |
43 | 72 | LocalDateTime endTime = |
44 | 73 | (LocalDateTime) Optional.ofNullable(queryMap.get("endTime")).orElse(null); |
45 | - Integer status = | |
46 | - Optional.ofNullable(queryMap.get("status")) | |
74 | + Integer executeStatus = | |
75 | + Optional.ofNullable(queryMap.get("executeStatus")) | |
47 | 76 | .map(obj -> Integer.valueOf(obj.toString())) |
48 | 77 | .orElse(null); |
49 | 78 | IPage<ReportGenerateRecord> iPage = |
... | ... | @@ -54,7 +83,7 @@ public class YtReportGenerateRecordServiceImpl |
54 | 83 | StringUtils.isNotEmpty(reportConfigName), |
55 | 84 | ReportGenerateRecord::getReportConfigName, |
56 | 85 | reportConfigName) |
57 | - .eq(null != status, ReportGenerateRecord::getExecuteStatus, status) | |
86 | + .eq(null != executeStatus, ReportGenerateRecord::getExecuteStatus, executeStatus) | |
58 | 87 | .eq(ReportGenerateRecord::getTenantId, queryMap.get("tenantId").toString()) |
59 | 88 | .between( |
60 | 89 | null != startTime && null != endTime, |
... | ... | @@ -126,4 +155,152 @@ public class YtReportGenerateRecordServiceImpl |
126 | 155 | dto.setExecuteWay(reportFormConfigDTO.getExecuteWay()); |
127 | 156 | return saveOrUpdateReportGenerateRecord(dto); |
128 | 157 | } |
158 | + | |
159 | + @Override | |
160 | + public void generateExcelUpdateReportRecord( | |
161 | + ReportFormConfigDTO formConfigDTO, ExecuteAttributesDTO dto, String recordId) { | |
162 | + Long startTs = formConfigDTO.getStartTs(); | |
163 | + Long endTs = formConfigDTO.getEndTs(); | |
164 | + QueryConditionDTO queryCondition = formConfigDTO.getQueryCondition(); | |
165 | + boolean useStrictDataTypes = queryCondition.isUseStrictDataTypes(); | |
166 | + Long interval = queryCondition.getInterval(); | |
167 | + int limit = queryCondition.getLimit(); | |
168 | + Aggregation agg = queryCondition.getAgg(); | |
169 | + String orderBy = queryCondition.getOrderBy(); | |
170 | + List<String> keys = dto.getAttributes(); | |
171 | + DeviceId entityId = DeviceId.fromString(dto.getDevice()); | |
172 | + String reportTenantId = formConfigDTO.getTenantId(); | |
173 | + TenantId tenantId = TenantId.fromUUID(UUID.fromString(reportTenantId)); | |
174 | + final DeferredResult<ResponseEntity> result = new DeferredResult<>(); | |
175 | + // 如果报表配置是定时执行,获取当前定时任务的执行时间,并计算新的开始时间、结束时间 | |
176 | + if (formConfigDTO.getExecuteWay() == FastIotConstants.MagicNumber.ONE) { | |
177 | + long differenceTs = endTs - startTs; | |
178 | + endTs = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli(); | |
179 | + startTs = endTs - differenceTs; | |
180 | + } | |
181 | + Long finalStartTs = startTs; | |
182 | + Long finalEndTs = endTs; | |
183 | + List<ReadTsKvQuery> queries = | |
184 | + keys.stream() | |
185 | + .map( | |
186 | + key -> | |
187 | + new BaseReadTsKvQuery( | |
188 | + key, finalStartTs, finalEndTs, interval, limit, agg, orderBy)) | |
189 | + .collect(Collectors.toList()); | |
190 | + | |
191 | + Futures.addCallback( | |
192 | + tsService.findAll(tenantId, entityId, queries), | |
193 | + getTsKvListCallback( | |
194 | + result, | |
195 | + useStrictDataTypes, | |
196 | + formConfigDTO.getName(), | |
197 | + dto.getName(), | |
198 | + recordId, | |
199 | + reportTenantId), | |
200 | + MoreExecutors.directExecutor()); | |
201 | + } | |
202 | + | |
203 | + private FutureCallback<List<TsKvEntry>> getTsKvListCallback( | |
204 | + final DeferredResult<ResponseEntity> response, | |
205 | + Boolean useStrictDataTypes, | |
206 | + String reportFormName, | |
207 | + String deviceName, | |
208 | + String reportGenerateRecordId, | |
209 | + String tenantId) { | |
210 | + return new FutureCallback<>() { | |
211 | + @Override | |
212 | + public void onSuccess(List<TsKvEntry> data) { | |
213 | + Map<String, List<BasicData>> result = new LinkedHashMap<>(); | |
214 | + for (TsKvEntry entry : data) { | |
215 | + Object value = useStrictDataTypes ? getKvValue(entry) : entry.getValueAsString(); | |
216 | + result | |
217 | + .computeIfAbsent(entry.getKey(), k -> new ArrayList<>()) | |
218 | + .add(new BasicData(entry.getTs(), value)); | |
219 | + } | |
220 | + response.setResult(new ResponseEntity<>(result, HttpStatus.OK)); | |
221 | + generateExcel(deviceName, reportFormName, result, reportGenerateRecordId, tenantId); | |
222 | + } | |
223 | + | |
224 | + @Override | |
225 | + public void onFailure(@NotNull Throwable e) { | |
226 | + log.error("Failed to fetch historical data", e); | |
227 | + } | |
228 | + }; | |
229 | + } | |
230 | + | |
231 | + private Object getKvValue(KvEntry entry) { | |
232 | + if (entry.getDataType() == DataType.JSON) { | |
233 | + Optional<String> json = entry.getJsonValue(); | |
234 | + return json.map(JacksonUtil::toJsonNode).orElse(null); | |
235 | + } | |
236 | + return entry.getValue(); | |
237 | + } | |
238 | + | |
239 | + private void generateExcel( | |
240 | + String deviceName, | |
241 | + String reportFormName, | |
242 | + Map<String, List<BasicData>> result, | |
243 | + String reportGenerateRecordId, | |
244 | + String tenantId) { | |
245 | + List<List<String>> heads = new ArrayList<>(); | |
246 | + List<List<Object>> values = new ArrayList<>(); | |
247 | + int firstKey = 0; | |
248 | + for (String key : result.keySet()) { | |
249 | + List<String> headValue = new ArrayList<>(); | |
250 | + headValue.add(deviceName); | |
251 | + headValue.add(key + "采集值"); | |
252 | + List<String> tsValue = new ArrayList<>(); | |
253 | + tsValue.add(deviceName); | |
254 | + tsValue.add(key + "采集时间"); | |
255 | + heads.add(headValue); | |
256 | + heads.add(tsValue); | |
257 | + List<BasicData> basicData = result.get(key); | |
258 | + for (int i = 0; i < basicData.size(); i++) { | |
259 | + BasicData item = basicData.get(i); | |
260 | + List<Object> listValue; | |
261 | + if (firstKey == 0) { | |
262 | + listValue = new ArrayList<>(); | |
263 | + } else { | |
264 | + listValue = values.get(i); | |
265 | + } | |
266 | + Object value = item.getValue(); | |
267 | + listValue.add(value); | |
268 | + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); | |
269 | + Timestamp t = new Timestamp(item.getTs()); | |
270 | + listValue.add(t.toLocalDateTime().format(dtf)); | |
271 | + if (firstKey == 0) { | |
272 | + values.add(listValue); | |
273 | + } | |
274 | + } | |
275 | + firstKey++; | |
276 | + } | |
277 | + ByteArrayOutputStream byteArrayOutputStream = | |
278 | + ExcelUtil.noModelWrite(reportFormName, heads, values); | |
279 | + String fileName = reportFormName + System.currentTimeMillis() + ".xlsx"; | |
280 | + int status = StatusEnum.SUCCESS.getIndex(); | |
281 | + InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); | |
282 | + String response = null; | |
283 | + try { | |
284 | + response = fileStorageService.uploadFile(fileName, CONTENT_TYPE, inputStream); | |
285 | + } catch (Exception e) { | |
286 | + log.error(e.getMessage()); | |
287 | + } | |
288 | + ReportGenerateRecordDTO recordDTO = | |
289 | + findReportGenerateRecordById(reportGenerateRecordId, tenantId); | |
290 | + if (null != recordDTO) { | |
291 | + if (response != null) { | |
292 | + String reportPath = recordDTO.getReportPath(); | |
293 | + if (null != reportPath) { | |
294 | + reportPath += "," + response; | |
295 | + } else { | |
296 | + reportPath = response; | |
297 | + } | |
298 | + recordDTO.setReportPath(reportPath); | |
299 | + } else { | |
300 | + status = StatusEnum.FAIL.getIndex(); | |
301 | + } | |
302 | + recordDTO.setExecuteStatus(status); | |
303 | + saveOrUpdateReportGenerateRecord(recordDTO); | |
304 | + } | |
305 | + } | |
129 | 306 | } | ... | ... |
1 | 1 | package org.thingsboard.server.dao.yunteng.service; |
2 | 2 | |
3 | 3 | import org.thingsboard.server.common.data.yunteng.dto.DeleteDTO; |
4 | +import org.thingsboard.server.common.data.yunteng.dto.ReportFormConfigDTO; | |
4 | 5 | import org.thingsboard.server.common.data.yunteng.dto.ReportGenerateRecordDTO; |
6 | +import org.thingsboard.server.common.data.yunteng.dto.request.ExecuteAttributesDTO; | |
5 | 7 | import org.thingsboard.server.common.data.yunteng.utils.tools.YtPageData; |
6 | 8 | |
7 | 9 | import java.util.Map; |
... | ... | @@ -25,4 +27,12 @@ public interface YtReportGenerateRecordService { |
25 | 27 | * @return 报表生成记录 |
26 | 28 | */ |
27 | 29 | ReportGenerateRecordDTO generateReportRecord(String sourceId, String tenantId, String jobId); |
30 | + | |
31 | + /** | |
32 | + * 生成报表记录 | |
33 | + * @param formConfigDTO 报表配置 | |
34 | + * @param dto 执行属性 | |
35 | + * @param recordId recordId 记录ID | |
36 | + */ | |
37 | + void generateExcelUpdateReportRecord(ReportFormConfigDTO formConfigDTO, ExecuteAttributesDTO dto, String recordId); | |
28 | 38 | } | ... | ... |