Commit b69b04b43c968e866aa45c7082dbeac38335ee86

Authored by xp.Huang
2 parents df57da34 6ac8ae17

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 }
... ...