Commit b69b04b43c968e866aa45c7082dbeac38335ee86
Merge branch 'master_dev' into 'master'
报表生成时,将多个设备用不同的sheet页来存储数据 See merge request yunteng/thingskit!243
Showing
22 changed files
with
295 additions
and
236 deletions
... | ... | @@ -306,11 +306,13 @@ public class TkDeviceController extends BaseController { |
306 | 306 | public void deleteDevices(@Validated({DeleteGroup.class}) @RequestBody DeleteDTO deleteDTO) |
307 | 307 | throws ThingsboardException { |
308 | 308 | String currentTenantId = getCurrentUser().getCurrentTenantId(); |
309 | - List<String> tdIds = tkdeviceService.findTbDeviceId(currentTenantId, deleteDTO.getIds()); | |
310 | - for (String id : tdIds) { | |
311 | - deleteTbDevice(id); | |
309 | + List<String> tdIds = tkdeviceService.findTbDeviceIdAndCheckForDelete(currentTenantId, deleteDTO.getIds()); | |
310 | + if(null !=tdIds){ | |
311 | + for (String id : tdIds) { | |
312 | + deleteTbDevice(id); | |
313 | + } | |
314 | + tkdeviceService.deleteDevices(currentTenantId, deleteDTO.getIds()); | |
312 | 315 | } |
313 | - tkdeviceService.deleteDevices(currentTenantId, deleteDTO.getIds()); | |
314 | 316 | } |
315 | 317 | |
316 | 318 | private void deleteTbDevice(String id) throws ThingsboardException { | ... | ... |
... | ... | @@ -176,9 +176,6 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev |
176 | 176 | save(deviceId, LAST_CONNECT_TIME, ts); |
177 | 177 | pushRuleEngineMessage(stateData, CONNECT_EVENT); |
178 | 178 | checkAndUpdateState(deviceId, stateData); |
179 | - //ThingsKit | |
180 | - saveDeviceStateLog(tenantId.toString(),deviceId.toString(), FastIotConstants.StateValue.ONLINE); | |
181 | - | |
182 | 179 | } |
183 | 180 | |
184 | 181 | @Override |
... | ... | @@ -204,8 +201,12 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev |
204 | 201 | save(deviceId, ACTIVITY_STATE, true); |
205 | 202 | pushRuleEngineMessage(stateData, ACTIVITY_EVENT); |
206 | 203 | //thingkit function |
207 | - tkDeviceService.updateDeviceStateByTbDeviceId(stateData.getTenantId().getId().toString(),deviceId.getId().toString(), | |
204 | + String tenantId = stateData.getTenantId().getId().toString(); | |
205 | + String tbDeviceId = deviceId.getId().toString(); | |
206 | + tkDeviceService.updateDeviceStateByTbDeviceId(tenantId,tbDeviceId, | |
208 | 207 | org.thingsboard.server.common.data.yunteng.enums.DeviceState.ONLINE); |
208 | + //ThingsKit | |
209 | + saveDeviceStateLog(tenantId,tbDeviceId, FastIotConstants.StateValue.ONLINE); | |
209 | 210 | } |
210 | 211 | } else { |
211 | 212 | log.debug("updateActivityState - fetched state IN NULL for device {}, lastReportedActivity {}", deviceId, lastReportedActivity); |
... | ... | @@ -223,8 +224,6 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev |
223 | 224 | stateData.getState().setLastDisconnectTime(ts); |
224 | 225 | save(deviceId, LAST_DISCONNECT_TIME, ts); |
225 | 226 | pushRuleEngineMessage(stateData, DISCONNECT_EVENT); |
226 | - //ThingsKit | |
227 | - saveDeviceStateLog(tenantId.toString(),deviceId.toString(), FastIotConstants.StateValue.OFFLINE); | |
228 | 227 | } |
229 | 228 | |
230 | 229 | @Override |
... | ... | @@ -422,8 +421,11 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService<Dev |
422 | 421 | pushRuleEngineMessage(stateData, INACTIVITY_EVENT); |
423 | 422 | //thingskit update tkDevice state |
424 | 423 | if(stateData.getState().getLastActivityTime()>0){ |
425 | - tkDeviceService.updateDeviceStateByTbDeviceId(stateData.getTenantId().getId().toString(), | |
426 | - deviceId.getId().toString(),org.thingsboard.server.common.data.yunteng.enums.DeviceState.OFFLINE); | |
424 | + String tenantId = stateData.getTenantId().getId().toString(); | |
425 | + String tbDeviceId = deviceId.getId().toString(); | |
426 | + tkDeviceService.updateDeviceStateByTbDeviceId(tenantId,tbDeviceId, | |
427 | + org.thingsboard.server.common.data.yunteng.enums.DeviceState.OFFLINE); | |
428 | + saveDeviceStateLog(tenantId,tbDeviceId, FastIotConstants.StateValue.OFFLINE); | |
427 | 429 | } |
428 | 430 | } else { |
429 | 431 | cleanupEntity(deviceId); | ... | ... |
... | ... | @@ -1191,14 +1191,8 @@ management: |
1191 | 1191 | include: '${METRICS_ENDPOINTS_EXPOSE:info}' |
1192 | 1192 | file: |
1193 | 1193 | storage: |
1194 | - type: ${FILE_STORAGE_TYPE:minio} #local, minio, or other to be implemented | |
1195 | - randomFileName: ${FILE_STORAGE_FILENAME:true} #是否重命名文件名字,防止冲突 | |
1196 | - local: | |
1197 | - uploadDir: ${FILE_LOCAL_UPLOAD_DIR:/var/thingskit/upload/} #文件上传地址 只有type = local需要 | |
1198 | - downloadPath: ${FILE_LOCAL_DOWN_PATH:/download_file/} #与controller里面下载文件GetMapping的path一致, 只有type = local需要 | |
1199 | - uploadPath: ${FILE_LOCAL_UPLOAD_PATH:/upload} #与controller里面下载文件GetMapping的path一致, 只有type = local需要 | |
1200 | - staticUrl: ${FILE_LOCAL_STATIC_URL:/static/files/**} #oss静态访问路径 只有type = local需要 | |
1201 | - randomFileName: ${file.storage.randomFileName} | |
1194 | + type: ${FILE_STORAGE_TYPE:minio} #minio, or other to be implemented | |
1195 | + randomFileName: ${FILE_STORAGE_FILENAME:true} #是否重命名文件名字,防止冲突 | |
1202 | 1196 | minio: |
1203 | 1197 | minioUrl: ${MINIO_URL:http://127.0.0.1:9000} #minio储存地址 |
1204 | 1198 | minioName: ${MINIO_NAME:xxxxxx} #minio账户 | ... | ... |
... | ... | @@ -3,5 +3,5 @@ package org.thingsboard.server.common.data.yunteng.config.sms; |
3 | 3 | import java.util.LinkedHashMap; |
4 | 4 | |
5 | 5 | public interface SmsSender { |
6 | - String sendSms(String phone, String templateCode, LinkedHashMap<String,String> param,String signName); | |
6 | + String sendSms(String phone, String templateCode, LinkedHashMap<String,Object> param,String signName); | |
7 | 7 | } | ... | ... |
... | ... | @@ -47,7 +47,7 @@ public class AliSmsSender extends AbstractSmsSender { |
47 | 47 | |
48 | 48 | @Override |
49 | 49 | public String sendSms( |
50 | - String phone, String templateCode, LinkedHashMap<String, String> param, String signName) { | |
50 | + String phone, String templateCode, LinkedHashMap<String, Object> param, String signName) { | |
51 | 51 | validatePhoneNumber(phone); |
52 | 52 | IAcsClient client = new DefaultAcsClient(profile); |
53 | 53 | SendSmsRequest request = new SendSmsRequest(); | ... | ... |
... | ... | @@ -13,7 +13,7 @@ public class TencentSmsSender extends AbstractSmsSender { |
13 | 13 | |
14 | 14 | @Override |
15 | 15 | public String sendSms( |
16 | - String phone, String templateCode, LinkedHashMap<String, String> param, String signName) { | |
16 | + String phone, String templateCode, LinkedHashMap<String, Object> param, String signName) { | |
17 | 17 | return ""; |
18 | 18 | } |
19 | 19 | } | ... | ... |
... | ... | @@ -112,8 +112,9 @@ public enum ErrorMessage { |
112 | 112 | MESSAGE_TEMPLATE_DELETED(400020,"消息模板不存在!"), |
113 | 113 | NEED_MAIN_PARAMETER(400021, "缺少必要参数【%s】"), |
114 | 114 | REGISTER_VALUE_IS_NONE(400022, "寄存器值不能为空"), |
115 | + GATE_WAY_DEVICE_HAS_SENSOR(400023, "网关设备【%s】有下挂网关子设备"), | |
115 | 116 | NOT_ALLOED_ISOLATED_IN_MONOLITH(500003,"【monolith】模式下,不能选择【isolated】类型的租户配置"), |
116 | - MESSAGE_TEMPLATE_USING_CONFIG(500004,"删除消息配置前,需要禁用使用消息配置的消息模板%s。"); | |
117 | + MESSAGE_TEMPLATE_USING_CONFIG(500004,"消息配置正在被消息模板【%s】使用"); | |
117 | 118 | private final int code; |
118 | 119 | private String message; |
119 | 120 | ... | ... |
1 | +package org.thingsboard.server.common.data.yunteng.dto.report; | |
2 | + | |
3 | +import lombok.Data; | |
4 | + | |
5 | +import java.util.List; | |
6 | + | |
7 | +@Data | |
8 | +public class CustomDataForExcelDTO { | |
9 | + /** sheet页名称 */ | |
10 | + String sheetName; | |
11 | + /** sheet页的头 */ | |
12 | + List<List<String>> sheetHeads; | |
13 | + /** sheet的数据 */ | |
14 | + List<?> sheetData; | |
15 | + | |
16 | + public CustomDataForExcelDTO(String sheetName, List<List<String>> sheetHeads, List<?> sheetData) { | |
17 | + this.sheetName = sheetName; | |
18 | + this.sheetHeads = sheetHeads; | |
19 | + this.sheetData = sheetData; | |
20 | + } | |
21 | +} | ... | ... |
... | ... | @@ -11,7 +11,7 @@ import java.util.LinkedHashMap; |
11 | 11 | public class SmsReqDTO { |
12 | 12 | |
13 | 13 | /** 模板参数 */ |
14 | - private LinkedHashMap<String, String> params; | |
14 | + private LinkedHashMap<String, Object> params; | |
15 | 15 | |
16 | 16 | /** 手机号码 */ |
17 | 17 | @Pattern(regexp = FastIotConstants.MOBILE, message = "请输入正确的手机号") | ... | ... |
... | ... | @@ -6,6 +6,7 @@ import com.alibaba.excel.write.metadata.WriteSheet; |
6 | 6 | import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; |
7 | 7 | import org.apache.commons.lang3.StringUtils; |
8 | 8 | import org.springframework.beans.BeanUtils; |
9 | +import org.thingsboard.server.common.data.yunteng.dto.report.CustomDataForExcelDTO; | |
9 | 10 | |
10 | 11 | import javax.servlet.http.HttpServletResponse; |
11 | 12 | import java.io.ByteArrayOutputStream; |
... | ... | @@ -79,4 +80,26 @@ public class ExcelUtil { |
79 | 80 | excelWriter.write(data, writeSheet); |
80 | 81 | } |
81 | 82 | |
83 | + /** | |
84 | + * 生成多sheet页的excel,一个设备用一个sheet页 | |
85 | + * @param list 自定义数据 | |
86 | + * @return 输出流 | |
87 | + */ | |
88 | + public static ByteArrayOutputStream manySheetWrite(List<CustomDataForExcelDTO> list) { | |
89 | + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); | |
90 | + if (null != list && !list.isEmpty()) { | |
91 | + try (ExcelWriter excelWriter = EasyExcel.write(byteArrayOutputStream).build()) { | |
92 | + int i = 0; | |
93 | + for (CustomDataForExcelDTO customDataForExcel : list) { | |
94 | + WriteSheet writeSheet = | |
95 | + EasyExcel.writerSheet(i, customDataForExcel.getSheetName()) | |
96 | + .head(customDataForExcel.getSheetHeads()) | |
97 | + .build(); | |
98 | + excelWriter.write(customDataForExcel.getSheetData(), writeSheet); | |
99 | + i++; | |
100 | + } | |
101 | + } | |
102 | + } | |
103 | + return byteArrayOutputStream; | |
104 | + } | |
82 | 105 | } | ... | ... |
... | ... | @@ -8,11 +8,8 @@ import lombok.RequiredArgsConstructor; |
8 | 8 | import lombok.extern.slf4j.Slf4j; |
9 | 9 | import org.checkerframework.checker.nullness.qual.Nullable; |
10 | 10 | import org.springframework.stereotype.Component; |
11 | -import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants; | |
12 | -import org.thingsboard.server.common.data.yunteng.dto.DeviceDTO; | |
13 | 11 | import org.thingsboard.server.common.data.yunteng.dto.ReportFormConfigDTO; |
14 | 12 | import org.thingsboard.server.common.data.yunteng.dto.request.ExecuteAttributesDTO; |
15 | -import org.thingsboard.server.dao.yunteng.service.TkDeviceService; | |
16 | 13 | import org.thingsboard.server.dao.yunteng.service.TkReportFormConfigService; |
17 | 14 | import org.thingsboard.server.dao.yunteng.service.TkReportGenerateRecordService; |
18 | 15 | import java.util.*; |
... | ... | @@ -25,8 +22,6 @@ public class ReportTask { |
25 | 22 | |
26 | 23 | private final TkReportGenerateRecordService tkReportGenerateRecordService; |
27 | 24 | |
28 | - private final TkDeviceService tkDeviceService; | |
29 | - | |
30 | 25 | public void multipleParams(String s, Boolean b, Long l, Double d, Integer i) { |
31 | 26 | System.out.println("执行多参方法: s=" + s + "b=" + b + "l=" + l + "d" + d + "i=" + i); |
32 | 27 | } |
... | ... | @@ -51,23 +46,8 @@ public class ReportTask { |
51 | 46 | // 关联设备 |
52 | 47 | List<ExecuteAttributesDTO> dtoList = reportFormConfigDTO.getExecuteAttributes(); |
53 | 48 | if (!dtoList.isEmpty()) { |
54 | - if (dtoList.size() == FastIotConstants.MagicNumber.ONE) { | |
55 | - try { | |
56 | - ExecuteAttributesDTO attributesDTO = dtoList.get(0); | |
57 | - getTsKvForGenerateExcel( | |
58 | - reportFormConfigDTO, attributesDTO, reportGenerateRecordId, dtoList.size()); | |
59 | - | |
60 | - } catch (Exception e) { | |
61 | - log.error(e.getMessage()); | |
62 | - } | |
63 | - } else { | |
64 | - int surplus = dtoList.size(); | |
65 | - for (ExecuteAttributesDTO dto : dtoList) { | |
66 | - getTsKvForGenerateExcel( | |
67 | - reportFormConfigDTO, dto, reportGenerateRecordId, surplus); | |
68 | - surplus--; | |
69 | - } | |
70 | - } | |
49 | + tkReportGenerateRecordService.generateExcelUpdateReportRecord( | |
50 | + reportFormConfigDTO, dtoList, reportGenerateRecordId); | |
71 | 51 | } |
72 | 52 | } |
73 | 53 | |
... | ... | @@ -76,17 +56,4 @@ public class ReportTask { |
76 | 56 | }, |
77 | 57 | MoreExecutors.directExecutor()); |
78 | 58 | } |
79 | - | |
80 | - private void getTsKvForGenerateExcel( | |
81 | - ReportFormConfigDTO formConfigDTO, | |
82 | - ExecuteAttributesDTO dto, | |
83 | - String reportGenerateRecordId, | |
84 | - int surplus) { | |
85 | - //检查设备是否存在 | |
86 | - DeviceDTO deviceDTO = tkDeviceService.findDeviceInfoByTbDeviceId(formConfigDTO.getTenantId(),dto.getDevice()); | |
87 | - if(null != deviceDTO){ | |
88 | - tkReportGenerateRecordService.generateExcelUpdateReportRecord( | |
89 | - formConfigDTO, dto, reportGenerateRecordId, surplus); | |
90 | - } | |
91 | - } | |
92 | 59 | } | ... | ... |
1 | 1 | package org.thingsboard.server.dao.yunteng.entities; |
2 | 2 | |
3 | +import com.baomidou.mybatisplus.annotation.FieldStrategy; | |
4 | +import com.baomidou.mybatisplus.annotation.TableField; | |
3 | 5 | import com.baomidou.mybatisplus.annotation.TableName; |
4 | 6 | import lombok.Data; |
5 | 7 | import lombok.EqualsAndHashCode; |
... | ... | @@ -23,6 +25,7 @@ public class SysTenantEntity extends AuditRelatedEntity { |
23 | 25 | |
24 | 26 | private String defaultConfig; |
25 | 27 | |
28 | + @TableField(updateStrategy = FieldStrategy.IGNORED) | |
26 | 29 | private LocalDateTime tenantExpireTime; |
27 | 30 | |
28 | 31 | /** TB的租户ID */ | ... | ... |
... | ... | @@ -249,13 +249,17 @@ public class SysRoleServiceImpl extends AbstractBaseService<RoleMapper, SysRoleE |
249 | 249 | .eq(SysRoleEntity::getRoleType, RoleEnum.CUSTOMER_USER.name())); |
250 | 250 | customerRoles.forEach(cr -> menuMapper.removeMenuFromRole(cr.getId(), removeMenus)); |
251 | 251 | } |
252 | - newMenus.forEach( | |
253 | - menu -> { | |
254 | - SysTenantMenuEntity tenantMenu = new SysTenantMenuEntity(); | |
255 | - tenantMenu.setMenuId(menu); | |
256 | - tenantMenu.setTenantId(updateTenantId); | |
257 | - tenantMenuMapper.insert(tenantMenu); | |
258 | - }); | |
252 | + if (!newMenus.isEmpty()) { | |
253 | + // 如果新增的菜单,在该租户下的另外一个角色已经存在了,就不需要再插入数据库 | |
254 | + List<String> chechResultList = checkNewMenus(updateTenantId, newMenus); | |
255 | + chechResultList.forEach( | |
256 | + menu -> { | |
257 | + SysTenantMenuEntity tenantMenu = new SysTenantMenuEntity(); | |
258 | + tenantMenu.setMenuId(menu); | |
259 | + tenantMenu.setTenantId(updateTenantId); | |
260 | + tenantMenuMapper.insert(tenantMenu); | |
261 | + }); | |
262 | + } | |
259 | 263 | }); |
260 | 264 | } |
261 | 265 | cacheUtils.invalidateCacheName(FastIotConstants.CacheConfigKey.CACHE_CONFIG_KEY); |
... | ... | @@ -283,4 +287,27 @@ public class SysRoleServiceImpl extends AbstractBaseService<RoleMapper, SysRoleE |
283 | 287 | } |
284 | 288 | return baseMapper.findRoleInfo(roleDTO); |
285 | 289 | } |
290 | + | |
291 | + private List<String> checkNewMenus(String tenantId, List<String> newMenus) { | |
292 | + List<SysTenantMenuEntity> existEntities = | |
293 | + tenantMenuMapper.selectList( | |
294 | + new LambdaQueryWrapper<SysTenantMenuEntity>() | |
295 | + .eq(SysTenantMenuEntity::getTenantId, tenantId) | |
296 | + .in(SysTenantMenuEntity::getMenuId, newMenus)); | |
297 | + if (!existEntities.isEmpty()) { | |
298 | + List<String> existMenuIds = | |
299 | + existEntities.stream().map(SysTenantMenuEntity::getMenuId).collect(Collectors.toList()); | |
300 | + List<String> tempList = existMenuIds; | |
301 | + for (String newMenu : newMenus) { | |
302 | + for (String menuId : existMenuIds) { | |
303 | + if (Objects.equals(menuId, newMenu)) { | |
304 | + tempList.remove(newMenu); | |
305 | + break; | |
306 | + } | |
307 | + } | |
308 | + } | |
309 | + return tempList; | |
310 | + } | |
311 | + return newMenus; | |
312 | + } | |
286 | 313 | } | ... | ... |
... | ... | @@ -563,7 +563,7 @@ public class SysUserServiceImpl extends AbstractBaseService<UserMapper, SysUserE |
563 | 563 | SmsReqDTO smsReqDTO = new SmsReqDTO(); |
564 | 564 | smsReqDTO.setPhoneNumbers(user.getPhoneNumber()); |
565 | 565 | smsReqDTO.setId(templateDTOList.get(0).getId()); |
566 | - LinkedHashMap<String, String> params = new LinkedHashMap<>(); | |
566 | + LinkedHashMap<String, Object> params = new LinkedHashMap<>(); | |
567 | 567 | params.put("code", accountProperties.getDefaultPassword()); |
568 | 568 | smsReqDTO.setParams(params); |
569 | 569 | smsReqDTO.setTemplatePurpose(messageTemplateDTO.getTemplatePurpose()); | ... | ... |
... | ... | @@ -9,7 +9,6 @@ import com.google.common.util.concurrent.ListenableFuture; |
9 | 9 | import lombok.RequiredArgsConstructor; |
10 | 10 | import lombok.extern.slf4j.Slf4j; |
11 | 11 | import org.apache.commons.lang3.StringUtils; |
12 | -import org.jetbrains.annotations.NotNull; | |
13 | 12 | import org.jetbrains.annotations.Nullable; |
14 | 13 | import org.springframework.cache.annotation.Cacheable; |
15 | 14 | import org.springframework.stereotype.Service; |
... | ... | @@ -94,7 +93,8 @@ public class TkDeviceServiceImpl extends AbstractBaseService<DeviceMapper, TkDev |
94 | 93 | } |
95 | 94 | |
96 | 95 | @Override |
97 | - public void validateFormData(String currentTenantId, DeviceDTO deviceDTO) throws RuntimeException{ | |
96 | + public void validateFormData(String currentTenantId, DeviceDTO deviceDTO) | |
97 | + throws RuntimeException { | |
98 | 98 | boolean insert = StringUtils.isBlank(deviceDTO.getId()); |
99 | 99 | String deviceTenantId; |
100 | 100 | if (StringUtils.isBlank(deviceDTO.getName())) { |
... | ... | @@ -132,25 +132,30 @@ public class TkDeviceServiceImpl extends AbstractBaseService<DeviceMapper, TkDev |
132 | 132 | DeviceProfile deviceProfile = |
133 | 133 | deviceProfileDao.findById(id, UUID.fromString(deviceDTO.getProfileId())); |
134 | 134 | OrganizationDTO organization = |
135 | - organizationService.findOrganizationById(deviceDTO.getOrganizationId(),deviceTenantId); | |
135 | + organizationService.findOrganizationById(deviceDTO.getOrganizationId(), deviceTenantId); | |
136 | 136 | if (null == deviceProfile || null == organization) { |
137 | 137 | throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); |
138 | 138 | } else if (!organization.getTenantId().equals(deviceTenantId)) { |
139 | 139 | throw new TkDataValidationException(ErrorMessage.TENANT_MISMATCHING.getMessage()); |
140 | 140 | } |
141 | - //如果是TCP的网关子设备,要验证其Code是否已在网关的其他子设备存在 | |
142 | - if(Objects.equals(deviceDTO.getDeviceType(),DeviceTypeEnum.SENSOR) && Objects.equals(deviceProfile.getTransportType(), | |
143 | - DeviceTransportType.TCP)){ | |
141 | + // 如果是TCP的网关子设备,要验证其Code是否已在网关的其他子设备存在 | |
142 | + if (Objects.equals(deviceDTO.getDeviceType(), DeviceTypeEnum.SENSOR) | |
143 | + && Objects.equals(deviceProfile.getTransportType(), DeviceTransportType.TCP)) { | |
144 | 144 | String gateWayId = deviceDTO.getGatewayId(); |
145 | - List<TkDeviceEntity> entities = baseMapper.selectList(new LambdaQueryWrapper<TkDeviceEntity>() | |
146 | - .eq(TkDeviceEntity::getTenantId,currentTenantId) | |
147 | - .eq(TkDeviceEntity::getGatewayId,gateWayId) | |
148 | - .ne(!insert,TkDeviceEntity::getId,deviceDTO.getId())); | |
149 | - if(null != entities && !entities.isEmpty()){ | |
150 | - for (TkDeviceEntity entity:entities) { | |
151 | - if(Objects.equals(deviceDTO.getCode(),entity.getCode())){ | |
152 | - throw new TkDataValidationException(String.format(ErrorMessage.DEVICE_IDENTIFIER_REPEATED.getMessage(), | |
153 | - deviceDTO.getCode(),StringUtils.isEmpty(entity.getAlias())?entity.getName():entity.getAlias())); | |
145 | + List<TkDeviceEntity> entities = | |
146 | + baseMapper.selectList( | |
147 | + new LambdaQueryWrapper<TkDeviceEntity>() | |
148 | + .eq(TkDeviceEntity::getTenantId, currentTenantId) | |
149 | + .eq(TkDeviceEntity::getGatewayId, gateWayId) | |
150 | + .ne(!insert, TkDeviceEntity::getId, deviceDTO.getId())); | |
151 | + if (null != entities && !entities.isEmpty()) { | |
152 | + for (TkDeviceEntity entity : entities) { | |
153 | + if (Objects.equals(deviceDTO.getCode(), entity.getCode())) { | |
154 | + throw new TkDataValidationException( | |
155 | + String.format( | |
156 | + ErrorMessage.DEVICE_IDENTIFIER_REPEATED.getMessage(), | |
157 | + deviceDTO.getCode(), | |
158 | + StringUtils.isEmpty(entity.getAlias()) ? entity.getName() : entity.getAlias())); | |
154 | 159 | } |
155 | 160 | } |
156 | 161 | } |
... | ... | @@ -248,21 +253,38 @@ public class TkDeviceServiceImpl extends AbstractBaseService<DeviceMapper, TkDev |
248 | 253 | } |
249 | 254 | |
250 | 255 | @Override |
251 | - public List<String> findTbDeviceId(String tenantId, Set<String> ids) { | |
256 | + public List<String> findTbDeviceIdAndCheckForDelete(String tenantId, Set<String> ids) { | |
252 | 257 | LambdaQueryWrapper<TkDeviceEntity> queryWrapper = |
253 | 258 | new QueryWrapper<TkDeviceEntity>() |
254 | 259 | .lambda() |
255 | 260 | .eq(TkDeviceEntity::getTenantId, tenantId) |
256 | 261 | .in(TkDeviceEntity::getId, ids); |
257 | 262 | |
258 | - List<String> tbDeviceIds = | |
259 | - baseMapper.selectList(queryWrapper).stream() | |
260 | - .map(TkDeviceEntity::getTbDeviceId) | |
261 | - .collect(Collectors.toList()); | |
262 | - for (String tbDeviceId : tbDeviceIds) { | |
263 | + List<TkDeviceEntity> list = baseMapper.selectList(queryWrapper); | |
264 | + if (null == list || list.isEmpty()) { | |
265 | + return null; | |
266 | + } | |
267 | + for (TkDeviceEntity entity : list) { | |
268 | + String tbDeviceId = entity.getTbDeviceId(); | |
263 | 269 | sceneNotUsed(tenantId, tbDeviceId, null); |
270 | + // 检查是否有网关子设备在使用该设备 | |
271 | + if (Objects.equals(entity.getDeviceType(), DeviceTypeEnum.GATEWAY)) { | |
272 | + int sensorSize = | |
273 | + baseMapper | |
274 | + .selectList( | |
275 | + new LambdaQueryWrapper<TkDeviceEntity>() | |
276 | + .eq(TkDeviceEntity::getTenantId, tenantId) | |
277 | + .eq(TkDeviceEntity::getGatewayId, tbDeviceId)) | |
278 | + .size(); | |
279 | + if (sensorSize > FastIotConstants.MagicNumber.ZERO) { | |
280 | + throw new TkDataValidationException( | |
281 | + String.format( | |
282 | + ErrorMessage.GATE_WAY_DEVICE_HAS_SENSOR.getMessage(), | |
283 | + StringUtils.isEmpty(entity.getAlias()) ? entity.getName() : entity.getAlias())); | |
284 | + } | |
285 | + } | |
264 | 286 | } |
265 | - return tbDeviceIds; | |
287 | + return list.stream().map(TkDeviceEntity::getTbDeviceId).collect(Collectors.toList()); | |
266 | 288 | } |
267 | 289 | |
268 | 290 | @Override |
... | ... | @@ -378,7 +400,8 @@ public class TkDeviceServiceImpl extends AbstractBaseService<DeviceMapper, TkDev |
378 | 400 | String convertConfigId = |
379 | 401 | Optional.ofNullable(queryMap.get("convertConfigId")).map(Object::toString).orElse(null); |
380 | 402 | if (!StringUtils.isEmpty(organizationId)) { |
381 | - List<String> queryOrganizationIds = organizationService.organizationAllIds(tenantId, organizationId); | |
403 | + List<String> queryOrganizationIds = | |
404 | + organizationService.organizationAllIds(tenantId, organizationId); | |
382 | 405 | queryMap.put("organizationIds", queryOrganizationIds); |
383 | 406 | } |
384 | 407 | // 用于数据流转已选,待选过滤============开始 |
... | ... | @@ -413,8 +436,6 @@ public class TkDeviceServiceImpl extends AbstractBaseService<DeviceMapper, TkDev |
413 | 436 | return new TkPageData<>(records, deviceIPage.getTotal()); |
414 | 437 | } |
415 | 438 | |
416 | - | |
417 | - | |
418 | 439 | @Override |
419 | 440 | public TkPageData<RelationDeviceDTO> pageRelation(Map<String, Object> queryMap) { |
420 | 441 | IPage<TkDeviceEntity> page = getPage(queryMap, "last_online_time", false); |
... | ... | @@ -636,8 +657,8 @@ public class TkDeviceServiceImpl extends AbstractBaseService<DeviceMapper, TkDev |
636 | 657 | attribute.put("name", dto.getFunctionName()); |
637 | 658 | attribute.put("identifier", dto.getIdentifier()); |
638 | 659 | attribute.put("detail", functionJson); |
639 | - attribute.put("accessMode",dto.getAccessMode()); | |
640 | - attribute.put("extensionDesc",dto.getExtensionDesc()); | |
660 | + attribute.put("accessMode", dto.getAccessMode()); | |
661 | + attribute.put("extensionDesc", dto.getExtensionDesc()); | |
641 | 662 | attributes.add(attribute); |
642 | 663 | } |
643 | 664 | } |
... | ... | @@ -662,7 +683,10 @@ public class TkDeviceServiceImpl extends AbstractBaseService<DeviceMapper, TkDev |
662 | 683 | } |
663 | 684 | return baseMapper.findDeviceInfo(tenantId, tbDeviceId); |
664 | 685 | } |
665 | - @Cacheable(cacheNames = FastIotConstants.CacheConfigKey.SCENE_REACT, key = "{#tenantId, #organizationId, #projectId}") | |
686 | + | |
687 | + @Cacheable( | |
688 | + cacheNames = FastIotConstants.CacheConfigKey.SCENE_REACT, | |
689 | + key = "{#tenantId, #organizationId, #projectId}") | |
666 | 690 | @Override |
667 | 691 | public List<String> rpcDevices(String tenantId, String organizationId, String projectId) { |
668 | 692 | List<String> orgIds = organizationService.organizationAllIds(tenantId, organizationId); | ... | ... |
... | ... | @@ -17,7 +17,6 @@ import org.thingsboard.server.common.data.yunteng.constant.ModelConstants; |
17 | 17 | import org.thingsboard.server.common.data.yunteng.core.exception.TkDataValidationException; |
18 | 18 | import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage; |
19 | 19 | import org.thingsboard.server.common.data.yunteng.dto.MessageConfigDTO; |
20 | -import org.thingsboard.server.common.data.yunteng.enums.StatusEnum; | |
21 | 20 | import org.thingsboard.server.common.data.yunteng.utils.ReflectUtils; |
22 | 21 | import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData; |
23 | 22 | import org.thingsboard.server.dao.yunteng.entities.TkMessageConfigEntity; |
... | ... | @@ -26,8 +25,6 @@ import org.thingsboard.server.dao.yunteng.mapper.MessageConfigMapper; |
26 | 25 | import org.thingsboard.server.dao.yunteng.mapper.MessageTemplateMapper; |
27 | 26 | import org.thingsboard.server.dao.yunteng.service.AbstractBaseService; |
28 | 27 | import org.thingsboard.server.dao.yunteng.service.TkMessageConfigService; |
29 | -import org.thingsboard.server.dao.yunteng.service.TkMessageTemplateService; | |
30 | -import org.thingsboard.server.dao.yunteng.service.TkUserService; | |
31 | 28 | |
32 | 29 | @Service |
33 | 30 | @Slf4j |
... | ... | @@ -36,6 +33,7 @@ public class TkMessageConfigServiceImpl |
36 | 33 | extends AbstractBaseService<MessageConfigMapper, TkMessageConfigEntity> |
37 | 34 | implements TkMessageConfigService { |
38 | 35 | private final MessageTemplateMapper templateMapper; |
36 | + | |
39 | 37 | @Override |
40 | 38 | public TkPageData<MessageConfigDTO> page(String tenantId, Map<String, Object> queryMap) { |
41 | 39 | IPage<TkMessageConfigEntity> configIPage = |
... | ... | @@ -76,16 +74,19 @@ public class TkMessageConfigServiceImpl |
76 | 74 | |
77 | 75 | @Override |
78 | 76 | @Transactional |
79 | - public boolean deleteMessageConfig(Set<String> ids,String tenantId) { | |
77 | + public boolean deleteMessageConfig(Set<String> ids, String tenantId) { | |
80 | 78 | LambdaQueryWrapper<TkMessageTemplateEntity> filter = new LambdaQueryWrapper<>(); |
81 | 79 | filter |
82 | 80 | .in(TkMessageTemplateEntity::getMessageConfigId, ids) |
83 | - .eq(TkMessageTemplateEntity::getTenantId, tenantId) | |
84 | - .eq(TkMessageTemplateEntity::getStatus, StatusEnum.ENABLE.getIndex()); | |
81 | + .eq(TkMessageTemplateEntity::getTenantId, tenantId); | |
85 | 82 | List<TkMessageTemplateEntity> templates = templateMapper.selectList(filter); |
86 | - if(templates.size()>0){ | |
87 | - List<String> templateNames =templates.stream().map(t->t.getTemplateName()).collect(Collectors.toList()); | |
88 | - String errMsg = String.format(ErrorMessage.MESSAGE_TEMPLATE_USING_CONFIG.getMessage(), templateNames); | |
83 | + if (templates.size() > 0) { | |
84 | + List<String> templateNames = | |
85 | + templates.stream() | |
86 | + .map(TkMessageTemplateEntity::getTemplateName) | |
87 | + .collect(Collectors.toList()); | |
88 | + String errMsg = | |
89 | + String.format(ErrorMessage.MESSAGE_TEMPLATE_USING_CONFIG.getMessage(), templateNames); | |
89 | 90 | throw new TkDataValidationException(errMsg); |
90 | 91 | } |
91 | 92 | return baseMapper.deleteBatchIds(ids) > 0; | ... | ... |
... | ... | @@ -139,7 +139,7 @@ public class TkNoticeServiceImpl implements TkNoticeService { |
139 | 139 | SmsReqDTO info = new SmsReqDTO(); |
140 | 140 | info.setId(templateId); |
141 | 141 | info.setTemplatePurpose(MsgTemplatePurposeEnum.FOR_ALARM_NOTICE.name()); |
142 | - LinkedHashMap<String, String> params = new LinkedHashMap<>(); | |
142 | + LinkedHashMap<String, Object> params = new LinkedHashMap<>(); | |
143 | 143 | //name-其他;device_name-其他;level-其他;location-其他;alarm_value-其他; |
144 | 144 | params.put("type", alarmInfo.getType()); |
145 | 145 | params.put("device_name", alarmInfo.getDeviceName()); |
... | ... | @@ -201,7 +201,7 @@ public class TkNoticeServiceImpl implements TkNoticeService { |
201 | 201 | // TODO 推送钉钉消息 |
202 | 202 | SmsReqDTO info = new SmsReqDTO(); |
203 | 203 | info.setId(templateId); |
204 | - LinkedHashMap<String, String> params = new LinkedHashMap<>(); | |
204 | + LinkedHashMap<String, Object> params = new LinkedHashMap<>(); | |
205 | 205 | //name-其他;device_name-其他;level-其他;location-其他;alarm_value-其他; |
206 | 206 | params.put("type", alarmInfo.getType()); |
207 | 207 | params.put("device_name", alarmInfo.getDeviceName()); |
... | ... | @@ -231,7 +231,7 @@ public class TkNoticeServiceImpl implements TkNoticeService { |
231 | 231 | // TODO 推送微信通知 |
232 | 232 | SmsReqDTO info = new SmsReqDTO(); |
233 | 233 | info.setId(templateId); |
234 | - LinkedHashMap<String, String> params = new LinkedHashMap<>(); | |
234 | + LinkedHashMap<String, Object> params = new LinkedHashMap<>(); | |
235 | 235 | //name-其他;device_name-其他;level-其他;location-其他;alarm_value-其他; |
236 | 236 | params.put("type", alarmInfo.getType()); |
237 | 237 | params.put("device_name", alarmInfo.getDeviceName()); | ... | ... |
... | ... | @@ -303,12 +303,8 @@ public class TkReportFromConfigServiceImpl |
303 | 303 | ReportGenerateRecordDTO recordDTO = |
304 | 304 | tkReportGenerateRecordService.generateReportRecord(reportFormConfigDTO, null); |
305 | 305 | // 生成Excel,并更新报表执行记录 |
306 | - int surplus = reportFormConfigDTO.getExecuteAttributes().size(); | |
307 | - for (ExecuteAttributesDTO dto : reportFormConfigDTO.getExecuteAttributes()) { | |
308 | - tkReportGenerateRecordService.generateExcelUpdateReportRecord( | |
309 | - reportFormConfigDTO, dto, recordDTO.getId(), surplus); | |
310 | - surplus--; | |
311 | - } | |
306 | + tkReportGenerateRecordService.generateExcelUpdateReportRecord( | |
307 | + reportFormConfigDTO, reportFormConfigDTO.getExecuteAttributes(), recordDTO.getId()); | |
312 | 308 | } |
313 | 309 | |
314 | 310 | @Override | ... | ... |
... | ... | @@ -11,8 +11,6 @@ import lombok.RequiredArgsConstructor; |
11 | 11 | import lombok.extern.slf4j.Slf4j; |
12 | 12 | import org.apache.commons.lang3.StringUtils; |
13 | 13 | import org.jetbrains.annotations.NotNull; |
14 | -import org.springframework.http.HttpStatus; | |
15 | -import org.springframework.http.ResponseEntity; | |
16 | 14 | import org.springframework.stereotype.Service; |
17 | 15 | import org.springframework.web.context.request.async.DeferredResult; |
18 | 16 | import org.thingsboard.common.util.JacksonUtil; |
... | ... | @@ -28,6 +26,7 @@ import org.thingsboard.server.common.data.yunteng.dto.OrganizationDTO; |
28 | 26 | import org.thingsboard.server.common.data.yunteng.dto.ReportFormConfigDTO; |
29 | 27 | import org.thingsboard.server.common.data.yunteng.dto.ReportGenerateRecordDTO; |
30 | 28 | import org.thingsboard.server.common.data.yunteng.dto.report.BasicData; |
29 | +import org.thingsboard.server.common.data.yunteng.dto.report.CustomDataForExcelDTO; | |
31 | 30 | import org.thingsboard.server.common.data.yunteng.dto.request.ExecuteAttributesDTO; |
32 | 31 | import org.thingsboard.server.common.data.yunteng.dto.request.QueryConditionDTO; |
33 | 32 | import org.thingsboard.server.common.data.yunteng.enums.StatusEnum; |
... | ... | @@ -49,6 +48,7 @@ import java.time.LocalDateTime; |
49 | 48 | import java.time.ZoneOffset; |
50 | 49 | import java.time.format.DateTimeFormatter; |
51 | 50 | import java.util.*; |
51 | +import java.util.concurrent.CompletableFuture; | |
52 | 52 | import java.util.stream.Collectors; |
53 | 53 | |
54 | 54 | @Service |
... | ... | @@ -92,7 +92,10 @@ public class TkReportGenerateRecordServiceImpl |
92 | 92 | StringUtils.isNotEmpty(reportConfigName), |
93 | 93 | TkReportGenerateRecordEntity::getReportConfigName, |
94 | 94 | reportConfigName) |
95 | - .eq(null != executeStatus, TkReportGenerateRecordEntity::getExecuteStatus, executeStatus) | |
95 | + .eq( | |
96 | + null != executeStatus, | |
97 | + TkReportGenerateRecordEntity::getExecuteStatus, | |
98 | + executeStatus) | |
96 | 99 | .eq(TkReportGenerateRecordEntity::getTenantId, queryMap.get("tenantId").toString()) |
97 | 100 | .between( |
98 | 101 | null != startTime && null != endTime, |
... | ... | @@ -109,13 +112,15 @@ public class TkReportGenerateRecordServiceImpl |
109 | 112 | @Override |
110 | 113 | public ReportGenerateRecordDTO saveOrUpdateReportGenerateRecord( |
111 | 114 | ReportGenerateRecordDTO recordDTO) { |
112 | - TkReportGenerateRecordEntity reportGenerateRecord = recordDTO.getEntity(TkReportGenerateRecordEntity.class); | |
115 | + TkReportGenerateRecordEntity reportGenerateRecord = | |
116 | + recordDTO.getEntity(TkReportGenerateRecordEntity.class); | |
113 | 117 | if (StringUtils.isEmpty(recordDTO.getId())) { |
114 | 118 | baseMapper.insert(reportGenerateRecord); |
115 | 119 | } else { |
116 | 120 | TkReportGenerateRecordEntity record = baseMapper.selectById(recordDTO.getId()); |
117 | 121 | Optional.ofNullable(record) |
118 | - .map(obj -> baseMapper.updateById(recordDTO.getEntity(TkReportGenerateRecordEntity.class))) | |
122 | + .map( | |
123 | + obj -> baseMapper.updateById(recordDTO.getEntity(TkReportGenerateRecordEntity.class))) | |
119 | 124 | .orElseThrow( |
120 | 125 | () -> { |
121 | 126 | throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); |
... | ... | @@ -169,29 +174,56 @@ public class TkReportGenerateRecordServiceImpl |
169 | 174 | } |
170 | 175 | |
171 | 176 | @Override |
172 | - public void generateExcelUpdateReportRecord( | |
173 | - ReportFormConfigDTO formConfigDTO, ExecuteAttributesDTO dto, String recordId, int surplus) { | |
174 | - Long startTs = formConfigDTO.getQueryCondition().getStartTs(); | |
175 | - Long endTs = formConfigDTO.getQueryCondition().getEndTs(); | |
176 | - // 如果报表配置是定时执行,获取当前定时任务的执行时间,并计算新的开始时间、结束时间 | |
177 | - if (formConfigDTO.getExecuteWay() == FastIotConstants.MagicNumber.ONE) { | |
178 | - ReportGenerateRecordDTO recordDTO = | |
179 | - findReportGenerateRecordById(recordId, formConfigDTO.getTenantId()); | |
180 | - long differenceTs = endTs - startTs; | |
181 | - endTs = recordDTO.getExecuteTime().toInstant(ZoneOffset.of("+8")).toEpochMilli(); | |
182 | - startTs = endTs - differenceTs; | |
183 | - formConfigDTO.getQueryCondition().setStartTs(startTs); | |
184 | - formConfigDTO.getQueryCondition().setEndTs(endTs); | |
177 | + public void generateExcelUpdateReportRecord(ReportFormConfigDTO formConfigDTO,List<ExecuteAttributesDTO> executeAttributes, | |
178 | + String recordId) { | |
179 | + List<DeferredResult<CustomDataForExcelDTO>> list = new ArrayList<>(); | |
180 | + for(ExecuteAttributesDTO dto:executeAttributes){ | |
181 | + DeferredResult<CustomDataForExcelDTO> result = new DeferredResult<>(); | |
182 | + Long startTs = formConfigDTO.getQueryCondition().getStartTs(); | |
183 | + Long endTs = formConfigDTO.getQueryCondition().getEndTs(); | |
184 | + // 如果报表配置是定时执行,获取当前定时任务的执行时间,并计算新的开始时间、结束时间 | |
185 | + if (formConfigDTO.getExecuteWay() == FastIotConstants.MagicNumber.ONE) { | |
186 | + ReportGenerateRecordDTO recordDTO = | |
187 | + findReportGenerateRecordById(recordId, formConfigDTO.getTenantId()); | |
188 | + long differenceTs = endTs - startTs; | |
189 | + endTs = recordDTO.getExecuteTime().toInstant(ZoneOffset.of("+8")).toEpochMilli(); | |
190 | + startTs = endTs - differenceTs; | |
191 | + formConfigDTO.getQueryCondition().setStartTs(startTs); | |
192 | + formConfigDTO.getQueryCondition().setEndTs(endTs); | |
193 | + } | |
194 | + getTsKvValuesOrGenerateExcel(result, formConfigDTO, dto); | |
195 | + list.add(result); | |
185 | 196 | } |
186 | - getTsKvValuesOrGenerateExcel(null, formConfigDTO, dto, recordId, surplus); | |
197 | + CompletableFuture<Void> future = CompletableFuture.allOf( | |
198 | + list.stream() | |
199 | + .map(deferredResult -> CompletableFuture.supplyAsync(deferredResult::getResult)) | |
200 | + .toArray(CompletableFuture<?>[]::new)); | |
201 | + // 在所有异步任务完成后进行下一步处理 | |
202 | + future.thenRun(() -> { | |
203 | + // 获取所有结果 | |
204 | + List<CustomDataForExcelDTO> results = new ArrayList<>(); | |
205 | + for (DeferredResult<CustomDataForExcelDTO> deferredResult : list) { | |
206 | + results.add((CustomDataForExcelDTO) deferredResult.getResult()); | |
207 | + } | |
208 | + ObjectNode executeCondition = JacksonUtil.newObjectNode(); | |
209 | + QueryConditionDTO queryCondition = formConfigDTO.getQueryCondition(); | |
210 | + executeCondition.replace( | |
211 | + FastIotConstants.CHART_EXECUTE_CONDITION, | |
212 | + JacksonUtil.convertValue(queryCondition, JsonNode.class)); | |
213 | + executeCondition.replace( | |
214 | + FastIotConstants.CHART_EXECUTE_ATTRIBUTES, | |
215 | + JacksonUtil.convertValue(formConfigDTO.getExecuteAttributes(), JsonNode.class)); | |
216 | + | |
217 | + // 汇总所有数据,生成Excel并上传 | |
218 | + generateExcelAndUpload(results,formConfigDTO.getName(),recordId,formConfigDTO.getTenantId(), | |
219 | + executeCondition); | |
220 | + }); | |
187 | 221 | } |
188 | 222 | |
189 | 223 | private void getTsKvValuesOrGenerateExcel( |
190 | - final DeferredResult<ResponseEntity> result, | |
224 | + DeferredResult<CustomDataForExcelDTO> result, | |
191 | 225 | ReportFormConfigDTO formConfigDTO, |
192 | - ExecuteAttributesDTO dto, | |
193 | - String recordId, | |
194 | - int surplus) { | |
226 | + ExecuteAttributesDTO dto) { | |
195 | 227 | QueryConditionDTO queryCondition = formConfigDTO.getQueryCondition(); |
196 | 228 | boolean useStrictDataTypes = queryCondition.isUseStrictDataTypes(); |
197 | 229 | Long interval = queryCondition.getInterval(); |
... | ... | @@ -213,25 +245,9 @@ public class TkReportGenerateRecordServiceImpl |
213 | 245 | .collect(Collectors.toList()); |
214 | 246 | queryCondition.setStartTs(finalStartTs); |
215 | 247 | queryCondition.setEndTs(finalEndTs); |
216 | - ObjectNode executeCondition = JacksonUtil.newObjectNode(); | |
217 | - executeCondition.replace( | |
218 | - FastIotConstants.CHART_EXECUTE_CONDITION, | |
219 | - JacksonUtil.convertValue(queryCondition, JsonNode.class)); | |
220 | - executeCondition.replace( | |
221 | - FastIotConstants.CHART_EXECUTE_ATTRIBUTES, | |
222 | - JacksonUtil.convertValue(formConfigDTO.getExecuteAttributes(), JsonNode.class)); | |
223 | 248 | Futures.addCallback( |
224 | 249 | tsService.findAll(tenantId, entityId, queries), |
225 | - getTsKvListCallback( | |
226 | - result, | |
227 | - useStrictDataTypes, | |
228 | - formConfigDTO.getName(), | |
229 | - dto.getName(), | |
230 | - recordId, | |
231 | - reportTenantId, | |
232 | - executeCondition, | |
233 | - surplus, | |
234 | - keys), | |
250 | + getTsKvListCallback(result, useStrictDataTypes, dto.getName(), keys), | |
235 | 251 | MoreExecutors.directExecutor()); |
236 | 252 | } |
237 | 253 | |
... | ... | @@ -249,14 +265,9 @@ public class TkReportGenerateRecordServiceImpl |
249 | 265 | } |
250 | 266 | |
251 | 267 | private FutureCallback<List<TsKvEntry>> getTsKvListCallback( |
252 | - final DeferredResult<ResponseEntity> response, | |
268 | + DeferredResult<CustomDataForExcelDTO> response, | |
253 | 269 | Boolean useStrictDataTypes, |
254 | - String reportFormName, | |
255 | 270 | String deviceName, |
256 | - String reportGenerateRecordId, | |
257 | - String tenantId, | |
258 | - JsonNode executeCondition, | |
259 | - int surplus, | |
260 | 271 | List<String> keys) { |
261 | 272 | return new FutureCallback<>() { |
262 | 273 | @Override |
... | ... | @@ -268,23 +279,21 @@ public class TkReportGenerateRecordServiceImpl |
268 | 279 | .computeIfAbsent(entry.getKey(), k -> new ArrayList<>()) |
269 | 280 | .add(new BasicData(entry.getTs(), value)); |
270 | 281 | } |
271 | - if (null == response) { | |
272 | - generateExcel( | |
273 | - deviceName, | |
274 | - reportFormName, | |
275 | - result, | |
276 | - reportGenerateRecordId, | |
277 | - tenantId, | |
278 | - executeCondition, | |
279 | - surplus, | |
280 | - keys); | |
281 | - } else { | |
282 | - response.setResult(new ResponseEntity<>(result, HttpStatus.OK)); | |
282 | + List<List<String>> heads = new ArrayList<>(); | |
283 | + List<List<Object>> values = new ArrayList<>(); | |
284 | + if (result.isEmpty()) { | |
285 | + for (String key : keys) { | |
286 | + List<BasicData> basicData = new ArrayList<>(); | |
287 | + result.put(key, basicData); | |
288 | + } | |
283 | 289 | } |
290 | + generateExcelHeadAndValues(result, deviceName, heads, values); | |
291 | + response.setResult(new CustomDataForExcelDTO(deviceName, heads, values)); | |
284 | 292 | } |
285 | 293 | |
286 | 294 | @Override |
287 | 295 | public void onFailure(@NotNull Throwable e) { |
296 | + response.setResult(null); | |
288 | 297 | log.error("Failed to fetch historical data", e); |
289 | 298 | } |
290 | 299 | }; |
... | ... | @@ -298,58 +307,6 @@ public class TkReportGenerateRecordServiceImpl |
298 | 307 | return entry.getValue(); |
299 | 308 | } |
300 | 309 | |
301 | - private void generateExcel( | |
302 | - String deviceName, | |
303 | - String reportFormName, | |
304 | - Map<String, List<BasicData>> result, | |
305 | - String reportGenerateRecordId, | |
306 | - String tenantId, | |
307 | - JsonNode executeCondition, | |
308 | - int surplus, | |
309 | - List<String> keys) { | |
310 | - List<List<String>> heads = new ArrayList<>(); | |
311 | - List<List<Object>> values = new ArrayList<>(); | |
312 | - if (result.isEmpty()) { | |
313 | - for (String key : keys) { | |
314 | - List<BasicData> data = new ArrayList<>(); | |
315 | - result.put(key, data); | |
316 | - } | |
317 | - } | |
318 | - generateExcelHeadAndValues(result, deviceName, heads, values); | |
319 | - ByteArrayOutputStream byteArrayOutputStream = | |
320 | - ExcelUtil.noModelWrite(reportFormName, heads, values); | |
321 | - String fileName = reportFormName + System.currentTimeMillis() + ".xlsx"; | |
322 | - int status = StatusEnum.SUCCESS.getIndex(); | |
323 | - InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); | |
324 | - String response = null; | |
325 | - try { | |
326 | - response = fileStorageService.uploadFile(fileName, CONTENT_TYPE, inputStream); | |
327 | - } catch (Exception e) { | |
328 | - log.error(e.getMessage()); | |
329 | - } | |
330 | - ReportGenerateRecordDTO recordDTO = | |
331 | - findReportGenerateRecordById(reportGenerateRecordId, tenantId); | |
332 | - if (null != recordDTO) { | |
333 | - if (response != null) { | |
334 | - String reportPath = recordDTO.getReportPath(); | |
335 | - if (null != reportPath) { | |
336 | - reportPath += "," + response; | |
337 | - } else { | |
338 | - reportPath = response; | |
339 | - } | |
340 | - recordDTO.setReportPath(reportPath); | |
341 | - } else { | |
342 | - status = StatusEnum.FAIL.getIndex(); | |
343 | - } | |
344 | - if (surplus == FastIotConstants.MagicNumber.ONE) { | |
345 | - recordDTO.setExecuteStatus(status); | |
346 | - } | |
347 | - recordDTO.setUpdateTime(LocalDateTime.now()); | |
348 | - recordDTO.setExecuteCondition(executeCondition); | |
349 | - saveOrUpdateReportGenerateRecord(recordDTO); | |
350 | - } | |
351 | - } | |
352 | - | |
353 | 310 | private void generateExcelHeadAndValues( |
354 | 311 | Map<String, List<BasicData>> result, |
355 | 312 | String deviceName, |
... | ... | @@ -386,4 +343,42 @@ public class TkReportGenerateRecordServiceImpl |
386 | 343 | firstKey++; |
387 | 344 | } |
388 | 345 | } |
346 | + | |
347 | + private void generateExcelAndUpload( | |
348 | + List<CustomDataForExcelDTO> list, | |
349 | + String reportFormName, | |
350 | + String reportGenerateRecordId, | |
351 | + String tenantId, | |
352 | + JsonNode executeCondition) { | |
353 | + ByteArrayOutputStream byteArrayOutputStream = ExcelUtil.manySheetWrite(list); | |
354 | + | |
355 | + String fileName = reportFormName + System.currentTimeMillis() + ".xlsx"; | |
356 | + int status = StatusEnum.SUCCESS.getIndex(); | |
357 | + InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); | |
358 | + String response = null; | |
359 | + try { | |
360 | + response = fileStorageService.uploadFile(fileName, CONTENT_TYPE, inputStream); | |
361 | + } catch (Exception e) { | |
362 | + log.error(e.getMessage()); | |
363 | + } | |
364 | + ReportGenerateRecordDTO recordDTO = | |
365 | + findReportGenerateRecordById(reportGenerateRecordId, tenantId); | |
366 | + if (null != recordDTO) { | |
367 | + if (response != null) { | |
368 | + String reportPath = recordDTO.getReportPath(); | |
369 | + if (null != reportPath) { | |
370 | + reportPath += "," + response; | |
371 | + } else { | |
372 | + reportPath = response; | |
373 | + } | |
374 | + recordDTO.setReportPath(reportPath); | |
375 | + } else { | |
376 | + status = StatusEnum.FAIL.getIndex(); | |
377 | + } | |
378 | + recordDTO.setExecuteStatus(status); | |
379 | + recordDTO.setUpdateTime(LocalDateTime.now()); | |
380 | + recordDTO.setExecuteCondition(executeCondition); | |
381 | + saveOrUpdateReportGenerateRecord(recordDTO); | |
382 | + } | |
383 | + } | |
389 | 384 | } | ... | ... |
... | ... | @@ -58,7 +58,7 @@ public class TkSmsServiceImpl implements TkSmsService { |
58 | 58 | @Transactional |
59 | 59 | public boolean sendSms(SmsReqDTO smsReqDTO) { |
60 | 60 | String phoneNumbers = smsReqDTO.getPhoneNumbers(); |
61 | - LinkedHashMap<String, String> templateParam = smsReqDTO.getParams(); | |
61 | + LinkedHashMap<String, Object> templateParam = smsReqDTO.getParams(); | |
62 | 62 | String templateId = smsReqDTO.getId(); |
63 | 63 | if (StringUtils.isEmpty(phoneNumbers) || StringUtils.isEmpty(templateId)) { |
64 | 64 | throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); |
... | ... | @@ -200,7 +200,7 @@ public class TkSmsServiceImpl implements TkSmsService { |
200 | 200 | } |
201 | 201 | |
202 | 202 | String code = RandomStringUtils.randomNumeric(6); |
203 | - LinkedHashMap<String, String> params = new LinkedHashMap<>(); | |
203 | + LinkedHashMap<String, Object> params = new LinkedHashMap<>(); | |
204 | 204 | params.put("code", code); |
205 | 205 | SmsReqDTO smsReqDTO = new SmsReqDTO(); |
206 | 206 | smsReqDTO.setParams(params); | ... | ... |
... | ... | @@ -38,7 +38,13 @@ public interface TkDeviceService extends BaseService<TkDeviceEntity> { |
38 | 38 | */ |
39 | 39 | boolean deviceNameUsed(String tenantId, String deviceName, String deviceId); |
40 | 40 | |
41 | - List<String> findTbDeviceId(String tenantId, Set<String> ids); | |
41 | + /** | |
42 | + * 设备删除前的检查 | |
43 | + * @param tenantId 租户ID | |
44 | + * @param ids 删除的设备ID集合 | |
45 | + * @return TB的设备ID集合 | |
46 | + */ | |
47 | + List<String> findTbDeviceIdAndCheckForDelete(String tenantId, Set<String> ids); | |
42 | 48 | |
43 | 49 | /** |
44 | 50 | * 通过设备类型和组织ID查询所有的设备 | ... | ... |
... | ... | @@ -7,6 +7,7 @@ import org.thingsboard.server.common.data.yunteng.dto.ReportGenerateRecordDTO; |
7 | 7 | import org.thingsboard.server.common.data.yunteng.dto.request.ExecuteAttributesDTO; |
8 | 8 | import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData; |
9 | 9 | |
10 | +import java.util.List; | |
10 | 11 | import java.util.Map; |
11 | 12 | |
12 | 13 | public interface TkReportGenerateRecordService { |
... | ... | @@ -30,18 +31,14 @@ public interface TkReportGenerateRecordService { |
30 | 31 | ReportFormConfigDTO reportFormConfigDTO, String jobId); |
31 | 32 | |
32 | 33 | /** |
33 | - * 生成报表记录 | |
34 | + * 生成Excel报表 | |
34 | 35 | * |
35 | - * @param formConfigDTO 报表配置 | |
36 | - * @param dto 执行属性 | |
37 | - * @param recordId recordId 记录ID | |
38 | - * @param surplus 剩余执行次数 | |
36 | + * @param executeAttributes 需要执行的设备和属性 | |
39 | 37 | */ |
40 | 38 | void generateExcelUpdateReportRecord( |
41 | - ReportFormConfigDTO formConfigDTO, | |
42 | - ExecuteAttributesDTO dto, | |
43 | - String recordId, | |
44 | - int surplus); | |
39 | + ReportFormConfigDTO reportFormConfigDTO, | |
40 | + List<ExecuteAttributesDTO> executeAttributes, | |
41 | + String recordId); | |
45 | 42 | |
46 | 43 | JsonNode getChartQueryCondition(String id, String tenantId); |
47 | 44 | } | ... | ... |