diff --git a/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/alert/AlertRecordBo.java b/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/alert/AlertRecordBo.java new file mode 100644 index 0000000..7592e66 --- /dev/null +++ b/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/alert/AlertRecordBo.java @@ -0,0 +1,83 @@ +/* + * + * * | Licensed 未经许可不能去掉「OPENIITA」相关版权 + * * +---------------------------------------------------------------------- + * * | Author: xw2sy@163.com + * * +---------------------------------------------------------------------- + * + * Copyright [2024] [OPENIITA] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * / + */ +package cc.iotkit.model.alert; + +import cc.iotkit.model.Owned; +import cc.iotkit.model.TenantModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +/** + * 告警配置 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AlertRecordBo extends TenantModel implements Owned { + + private Long id; + + /** + * 配置所属用户 + */ + private String uid; + + /** + * 告警名称 + */ + private String name; + + /** + * 告警严重度(1-5) + */ + private String level; + + /** + * 告警时间 + */ + /* @JsonFormat(timezone = "Asia/Shanghai",pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")*/ + private Long alertTime; + private String alertTimeStats; + /** + * 告警详情 + */ + private String details; + private Long tenantId; + private Long deptAreaId; + /** + * 是否已读 + */ + private Boolean readFlg; + private Boolean statusFlg = false; + /* @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + public Date getAlertTime() { + return new Date(this.alertTime); + }*/ + +} diff --git a/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceDetectorInfo.java b/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceDetectorInfo.java index a4d9553..2871a49 100644 --- a/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceDetectorInfo.java +++ b/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceDetectorInfo.java @@ -72,4 +72,5 @@ public class DeviceDetectorInfo extends TenantModel implements Owned,Ser private String node; private String gasTypeKey; private String dataDetectorValue; + private String nodeContext; } diff --git a/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceInfo.java b/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceInfo.java index 6beed16..dbd1385 100644 --- a/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceInfo.java +++ b/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceInfo.java @@ -45,7 +45,9 @@ public class DeviceInfo extends TenantModel implements Owned { private String deviceId; private String site; + private String longitude; + private String latitude; private String name; private String signalStrength; private String deviceVersion; @@ -95,7 +97,9 @@ public class DeviceInfo extends TenantModel implements Owned { private String nodeThreeDevice; private String nodeFourDevice; private String nodeFiveDevice; - + private String nodeStatus; + private String node; + private String nodeDevice; /** * 关联子用户ID列表 */ diff --git a/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceInstallInfo.java b/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceInstallInfo.java index f548dfd..caed632 100644 --- a/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceInstallInfo.java +++ b/iot-dao/iot-data-model/src/main/java/cc/iotkit/model/device/DeviceInstallInfo.java @@ -94,4 +94,11 @@ public class DeviceInstallInfo extends TenantModel implements Owned,Seri // @ApiModelProperty(value = "装电源线照片") private String fiexImage; private Integer state; + //@ExcelProperty(value = "厂家") + private String manufacturer; + //@ExcelProperty(value = "安装情况") + private String position; + private String site; + //绑定人电话 + private String bindUserIpone; } diff --git a/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IAlertConfigData.java b/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IAlertConfigData.java index 66e497d..e6aca73 100644 --- a/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IAlertConfigData.java +++ b/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IAlertConfigData.java @@ -33,6 +33,8 @@ import java.util.List; public interface IAlertConfigData extends ICommonData { List findByUidAndRuleInfoId(String uid, String ruleInfoId); + List findByRuleInfoId(String ruleInfoId); + List findByDeviceName(String deviceName); List findByUidAndRuleInfoIdAndDeviceName(String uid, String ruleInfoId,String deviceName); Paging selectAlertConfigPage(PageRequest request); diff --git a/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IAlertRecordData.java b/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IAlertRecordData.java index 0a1918b..6dd308b 100644 --- a/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IAlertRecordData.java +++ b/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IAlertRecordData.java @@ -26,6 +26,7 @@ import cc.iotkit.common.api.PageRequest; import cc.iotkit.common.api.Paging; import cc.iotkit.data.ICommonData; import cc.iotkit.model.alert.AlertRecord; +import cc.iotkit.model.alert.AlertRecordBo; import cc.iotkit.model.stats.AlertStatDTO; import java.util.List; @@ -36,6 +37,7 @@ public interface IAlertRecordData extends ICommonData { Paging selectAlertConfigPage(PageRequest request); + List selectAlertConfigPage(AlertRecordBo request); List getAlertRecord(); diff --git a/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IDeviceInfoData.java b/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IDeviceInfoData.java index 7acf455..5a5df1c 100644 --- a/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IDeviceInfoData.java +++ b/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IDeviceInfoData.java @@ -116,10 +116,17 @@ public interface IDeviceInfoData extends IOwnedData { */ Paging findByConditions(String name,String uid, String subUid, String productKey, String groupId, Boolean online, String keyword, - int page, int size,Long areaDepeId); + int page, int size,Long areaDepeId,String startTime,String endTime); + Paging findByConditionsExcel(String name,String uid, String subUid, String productKey, + String groupId, Boolean online, String keyword, + int page, int size,Long areaDepeId,String startTime,String endTime); + + + + Paging findByConditions1(String name,String uid, String subUid, String productKey, String groupId, Boolean online, String keyword, - int page, int size,Long areaDepeId); + int page, int size,Long areaDepeId,String startTime,String endTime); /** * 更新设备标签 * diff --git a/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IUserInfoData.java b/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IUserInfoData.java index bb1216e..d25b496 100644 --- a/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IUserInfoData.java +++ b/iot-dao/iot-data-service/src/main/java/cc/iotkit/data/manager/IUserInfoData.java @@ -34,6 +34,8 @@ public interface IUserInfoData extends ICommonData { UserInfo findByUid(String uid); UserInfo findByUidAndUserName(String uid,String userName); UserInfo findByUserName(String userName); + List findByUserNameLike(String userName); + List findByType(int type); Paging findAll(PageRequest pageRequest); } diff --git a/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/DeviceInfoDataCache.java b/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/DeviceInfoDataCache.java index 6829773..b00fbee 100644 --- a/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/DeviceInfoDataCache.java +++ b/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/DeviceInfoDataCache.java @@ -231,12 +231,19 @@ public class DeviceInfoDataCache implements IDeviceInfoData, SmartInitializingSi @Override public Paging findByConditions(String name,String uid, String subUid, String productKey, - String groupId, Boolean state, String keyword, int page, int size,Long deptAreaId) { - return deviceInfoData.findByConditions(name,uid, subUid, productKey, groupId, state, keyword, page, size,deptAreaId); + String groupId, Boolean state, String keyword, int page, int size,Long deptAreaId,String startTime,String endTime) { + return deviceInfoData.findByConditions(name,uid, subUid, productKey, groupId, state, keyword, page, size,deptAreaId,startTime,endTime); } + @Override + public Paging findByConditionsExcel(String name,String uid, String subUid, String productKey, + String groupId, Boolean state, String keyword, int page, int size,Long deptAreaId,String startTime,String endTime) { + return deviceInfoData.findByConditionsExcel(name,uid, subUid, productKey, groupId, state, keyword, page, size,deptAreaId,startTime,endTime); + } + + public Paging findByConditions1(String name,String uid, String subUid, String productKey, - String groupId, Boolean state, String keyword, int page, int size,Long deptAreaId) { - return deviceInfoData.findByConditions1(name,uid, subUid, productKey, groupId, state, keyword, page, size,deptAreaId); + String groupId, Boolean state, String keyword, int page, int size,Long deptAreaId,String startTime,String endTime) { + return deviceInfoData.findByConditions1(name,uid, subUid, productKey, groupId, state, keyword, page, size,deptAreaId,startTime,endTime); } @Override public void updateTag(String deviceId, DeviceInfo.Tag tag) { diff --git a/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/DeviceInfoPropertyDataCache.java b/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/DeviceInfoPropertyDataCache.java index 417269d..e12ee00 100644 --- a/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/DeviceInfoPropertyDataCache.java +++ b/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/DeviceInfoPropertyDataCache.java @@ -187,12 +187,17 @@ public class DeviceInfoPropertyDataCache implements IDeviceInfoData { } @Override - public Paging findByConditions(String name,String uid, String subUid, String productKey, String groupId, Boolean online, String keyword, int page, int size,Long deptAreaId) { - return deviceInfoData.findByConditions(name,uid, subUid, productKey, groupId, online, keyword, page, size,deptAreaId); + public Paging findByConditions(String name,String uid, String subUid, String productKey, String groupId, Boolean online, String keyword, int page, int size,Long deptAreaId,String startTime,String endTime) { + return deviceInfoData.findByConditions(name,uid, subUid, productKey, groupId, online, keyword, page, size,deptAreaId,startTime,endTime); } @Override - public Paging findByConditions1(String name,String uid, String subUid, String productKey, String groupId, Boolean online, String keyword, int page, int size,Long deptAreaId) { - return deviceInfoData.findByConditions(name,uid, subUid, productKey, groupId, online, keyword, page, size,deptAreaId); + public Paging findByConditionsExcel(String name,String uid, String subUid, String productKey, String groupId, Boolean online, String keyword, int page, int size,Long deptAreaId,String startTime,String endTime) { + return deviceInfoData.findByConditionsExcel(name,uid, subUid, productKey, groupId, online, keyword, page, size,deptAreaId,startTime,endTime); + } + + @Override + public Paging findByConditions1(String name,String uid, String subUid, String productKey, String groupId, Boolean online, String keyword, int page, int size,Long deptAreaId,String startTime,String endTime) { + return deviceInfoData.findByConditions(name,uid, subUid, productKey, groupId, online, keyword, page, size,deptAreaId,startTime, endTime); } @Override public void updateTag(String deviceId, DeviceInfo.Tag tag) { diff --git a/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/UserInfoDataCache.java b/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/UserInfoDataCache.java index d9f948e..0118f52 100644 --- a/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/UserInfoDataCache.java +++ b/iot-dao/iot-data-serviceImpl-cache/src/main/java/cc/iotkit/data/service/UserInfoDataCache.java @@ -74,6 +74,10 @@ public class UserInfoDataCache implements IUserInfoData { public UserInfo findByUserName(String userName) { return userInfoData.findByUserName(userName); } + @Override + public List findByUserNameLike(String userName) { + return userInfoData.findByUserNameLike(userName); + } @Override public List findByIds(Collection id) { diff --git a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/AlertConfigRepository.java b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/AlertConfigRepository.java index 53e3ad4..86e253d 100644 --- a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/AlertConfigRepository.java +++ b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/AlertConfigRepository.java @@ -38,5 +38,7 @@ import java.util.List; public interface AlertConfigRepository extends JpaRepository, QuerydslPredicateExecutor { List findByUidAndRuleInfoId(String uid, String ruleInfoId); - List findByUidAndRuleInfoIdAndDeviceName(String uid, String ruleInfoId,String deviceName); + List findByRuleInfoIdAndEnable(String ruleInfoId,Boolean enable); + List findByDeviceNameAndEnable(String deviceName,Boolean enable); + List findByUidAndRuleInfoIdAndDeviceNameAndEnable(String uid, String ruleInfoId,String deviceName,Boolean enable); } diff --git a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/DeviceGroupMappingRepository.java b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/DeviceGroupMappingRepository.java index 09abd0a..b93c8f8 100644 --- a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/DeviceGroupMappingRepository.java +++ b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/DeviceGroupMappingRepository.java @@ -33,7 +33,7 @@ public interface DeviceGroupMappingRepository extends JpaRepository findByDeviceId(String deviceId); TbDeviceGroupMapping findByDeviceIdAndGroupId(String deviceId, String groupId); - + TbDeviceGroupMapping findByDeviceIdAndGroupIdAndTenantId(String deviceId, String groupId,Long tenantId); long countByGroupId(String groupId); diff --git a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/UserInfoRepository.java b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/UserInfoRepository.java index 34a8bbe..b79a577 100644 --- a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/UserInfoRepository.java +++ b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/dao/UserInfoRepository.java @@ -34,7 +34,7 @@ public interface UserInfoRepository extends JpaRepository, Q TbUserInfo findByUid(String uid); TbUserInfo findByUidAndUserName(String uid,String userName); TbUserInfo findByUserName(String userName); - + List findByUserNameLike(String userName); List findByType(int type); } diff --git a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/model/TbDeviceDetectorInfo.java b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/model/TbDeviceDetectorInfo.java index 0edb2ca..9c8996d 100644 --- a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/model/TbDeviceDetectorInfo.java +++ b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/model/TbDeviceDetectorInfo.java @@ -74,4 +74,5 @@ public class TbDeviceDetectorInfo extends BaseEntity implements TenantAware { private String node; private String gasTypeKey; private String dataDetectorValue; + private String nodeContext; } diff --git a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/AlertConfigDataImpl.java b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/AlertConfigDataImpl.java index 1b30045..d0850f8 100644 --- a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/AlertConfigDataImpl.java +++ b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/AlertConfigDataImpl.java @@ -87,14 +87,28 @@ public class AlertConfigDataImpl implements IAlertConfigData, IJPACommData(alertConfigPage.getTotalElements(), MapstructUtils.convert(alertConfigPage.getContent(), AlertConfig.class)); } + @Override + public List findByRuleInfoId(String ruleInfoId) { + return MapstructUtils.convert(alertConfigRepository.findByRuleInfoIdAndEnable(ruleInfoId,true), AlertConfig.class); + // return new Paging<>(alertConfigPage.getTotalElements(), MapstructUtils.convert(alertConfigPage.getContent(), AlertConfig.class)); + } + @Override + public List findByDeviceName(String deviceName) { + return MapstructUtils.convert(alertConfigRepository.findByDeviceNameAndEnable(deviceName,true), AlertConfig.class); + // return new Paging<>(alertConfigPage.getTotalElements(), MapstructUtils.convert(alertConfigPage.getContent(), AlertConfig.class)); + } + + @Override public List findByUidAndRuleInfoIdAndDeviceName(String uid, String ruleInfoId, String deviceName) { - return MapstructUtils.convert(alertConfigRepository.findByUidAndRuleInfoIdAndDeviceName(uid, ruleInfoId,deviceName), AlertConfig.class); + return MapstructUtils.convert(alertConfigRepository.findByUidAndRuleInfoIdAndDeviceNameAndEnable(uid, ruleInfoId,deviceName,true), AlertConfig.class); // return new Paging<>(alertConfigPage.getTotalElements(), MapstructUtils.convert(alertConfigPage.getContent(), AlertConfig.class)); } private Predicate buildQueryCondition(AlertConfig dictData) { return PredicateBuilder.instance() + .and(ObjectUtil.isNotNull(dictData.getMessagePush()), () -> tbAlertConfig.messagePush.like("%" + dictData.getMessagePush() +"%")) + .and(ObjectUtil.isNotNull(dictData.getDeviceName()), () -> tbAlertConfig.deviceName.like("%" + dictData.getDeviceName() +"%")) .and(dictData.getUid() != null, () -> tbAlertConfig.uid.eq(AuthUtil.getUserId())).build(); } } diff --git a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/AlertRecordDataImpl.java b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/AlertRecordDataImpl.java index d1d69a6..2be16b6 100644 --- a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/AlertRecordDataImpl.java +++ b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/AlertRecordDataImpl.java @@ -37,9 +37,12 @@ import cc.iotkit.data.model.QTbAlertRecord; import cc.iotkit.data.model.TbAlertRecord; import cc.iotkit.data.util.PageBuilder; import cc.iotkit.data.util.PredicateBuilder; +import cc.iotkit.model.alert.AlertConfig; import cc.iotkit.model.alert.AlertRecord; +import cc.iotkit.model.alert.AlertRecordBo; import cc.iotkit.model.stats.AlertStatDTO; import cc.iotkit.model.system.SysLoginInfo; +import cn.hutool.core.date.DateTime; import cn.hutool.core.util.ObjectUtil; import com.querydsl.core.QueryResults; import com.querydsl.core.types.Predicate; @@ -63,6 +66,8 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import static cc.iotkit.data.model.QTbAlertRecord.tbAlertRecord; @@ -171,6 +176,43 @@ public class AlertRecordDataImpl implements IAlertRecordData, IJPACommData(results.getTotal(), results.getResults()).to(AlertRecord.class); } + + + private String extractByPattern(String text, String regex) { + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(text); + return matcher.find() ? matcher.group(1) : null; + } + @Override + public List selectAlertConfigPage(AlertRecordBo request) { + LocalDateTime endDateTime = LocalDateTime.now(); + LocalDateTime beginDateTime = endDateTime.minusMinutes(10); + // LocalDateTime beginDateTime = LocalDateTime.parse(beginTime, formatter); + // LocalDateTime endDateTime = LocalDateTime.parse(endTime, formatter); + // 提取设备ID + String deviceId = extractByPattern(request.getDetails(), "设备【(.*?)】"); + System.out.println("设备ID:" + deviceId); + // 提取事件类型 + String eventType = extractByPattern(request.getDetails(), "类型为:【(.*?)】"); + System.out.println("事件类型:" + eventType); + + long beginMillis = beginDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + long endMillis = endDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + + QueryResults results = jpaQueryFactory.selectFrom(tbAlertRecord) + .where(PredicateBuilder.instance() + .and(tbAlertRecord.alertTime.between(beginMillis, endMillis)) + .and(ObjectUtil.isNotEmpty(deviceId), + () -> tbAlertRecord.details.like( deviceId + "%") ) + .and(ObjectUtil.isNotEmpty(eventType), + () -> tbAlertRecord.details.like(eventType + "%") ).build()) + .orderBy(tbAlertRecord.id.desc()) + .fetchResults(); + + return MapstructUtils.convert(results.getResults(), AlertRecord.class); + // return new Paging<>(results.getTotal(), results.getResults()).to(AlertRecord.class); + + } private static Predicate genTimePredicate(Map params) { /* DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate beginDate = LocalDate.parse(params.get("beginTime").toString(), formatter); diff --git a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/DeviceInfoDataImpl.java b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/DeviceInfoDataImpl.java index 811630c..593c26d 100644 --- a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/DeviceInfoDataImpl.java +++ b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/DeviceInfoDataImpl.java @@ -69,6 +69,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; @@ -80,6 +81,7 @@ import java.util.stream.Collectors; import static cc.iotkit.data.model.QTbAlertRecord.tbAlertRecord; import static cc.iotkit.data.model.QTbDeviceGroupMapping.tbDeviceGroupMapping; import static cc.iotkit.data.model.QTbDeviceInfo.tbDeviceInfo; +import static cc.iotkit.data.model.QTbDeviceInstallInfo.tbDeviceInstallInfo; import static cc.iotkit.data.model.QTbDeviceSubUser.tbDeviceSubUser; import static cc.iotkit.data.model.QTbProduct.tbProduct; import static cc.iotkit.data.model.QTbSysTenant.tbSysTenant; @@ -344,6 +346,8 @@ public class DeviceInfoDataImpl implements IDeviceInfoData, IJPACommData findByConditions(String name, String uid, String subUid, + public Paging findByConditionsExcel(String name, String uid, String subUid, String productKey, String groupId, Boolean online, String keyword, - int page, int size, Long deptAreaId) { + int page, int size, Long deptAreaId,String startTime,String endTime) { JPAQuery query = jpaQueryFactory.selectFrom(tbDeviceInfo); // 根据groupId, 如果groupId存在,则关联查询TbDeviceGroupMapping, 根据groupId,查询对应的devices @@ -567,7 +571,125 @@ public class DeviceInfoDataImpl implements IDeviceInfoData, IJPACommData tbDeviceInfos = query.fetch(); + long total = query.fetchCount(); + List deviceInfos = new ArrayList<>(tbDeviceInfos.size()); + for (TbDeviceInfo tbDeviceInfo : tbDeviceInfos) { + DeviceInfo deviceInfo = MapstructUtils.convert(tbDeviceInfo, DeviceInfo.class); + // fillDeviceInfo(tbDeviceInfo.getDeviceId(), tbDeviceInfo, deviceInfo); + deviceInfos.add(deviceInfo); + } + return new Paging<>(total, deviceInfos); + } + @Override + public Paging findByConditions(String name, String uid, String subUid, + String productKey, String groupId, + Boolean online, String keyword, + int page, int size, Long deptAreaId,String startTime,String endTime) { + JPAQuery query = jpaQueryFactory.selectFrom(tbDeviceInfo); + + // 根据groupId, 如果groupId存在,则关联查询TbDeviceGroupMapping, 根据groupId,查询对应的devices + if (StringUtils.isNotBlank(groupId)) { + query.join(tbDeviceGroupMapping).on(tbDeviceGroupMapping.deviceId.eq(tbDeviceInfo.deviceId)); + query.where(tbDeviceGroupMapping.groupId.eq(groupId)); + } + + + if (StringUtils.isNotBlank(uid)) { + query.where(tbDeviceInfo.uid.eq(uid)); + } + if (StringUtils.isNotBlank(name)) { + query.where(tbDeviceInfo.name.like("%" + name + "%")); + } + System.out.println(TenantHelper.getTenantId()); + if (ObjectUtil.isNotNull(TenantHelper.getTenantId()) && (!LoginHelper.isSuperAdmin() || TenantHelper.getTenantId()!=0)) { + query.where(tbDeviceInfo.tenantId.eq(TenantHelper.getTenantId())); + } + if (ObjectUtil.isNotNull(deptAreaId)) { + List areaIds; + // if (Objects.nonNull(user) && Objects.nonNull(user.getDeptAreaId())) { + Long areaId = deptAreaId; + List depts = sysDeptData.findByDeptId(areaId); + areaIds = StreamUtils.toList(depts, SysDept::getId); + areaIds.add(areaId); + if (ObjectUtil.isNotEmpty(areaIds)) { + query.where(tbDeviceInfo.deptAreaId.in(areaIds)); + } + }else{ + if(!LoginHelper.isSuperAdmin()) { + if(ObjectUtil.isNotEmpty(LoginHelper.getUserId())) { + + SysUser user = isSysUserData.findById(LoginHelper.getUserId()); + if (ObjectUtil.isNotNull(user)) { + if (ObjectUtil.isNotNull(user.getDeptAreaId())) { + List areaIds; + // if (Objects.nonNull(user) && Objects.nonNull(user.getDeptAreaId())) { + Long areaId = user.getDeptAreaId(); + List depts = sysDeptData.findByDeptId(areaId); + areaIds = StreamUtils.toList(depts, SysDept::getId); + areaIds.add(areaId); + if (ObjectUtil.isNotEmpty(areaIds)) { + query.where(tbDeviceInfo.deptAreaId.in(areaIds)); + } + } else { + if(ObjectUtil.isNotEmpty(LoginHelper.getUserType()) && !LoginHelper.getUserType().equals(UserType.APP_USER)) { + //没有绑定区域查不到设备 + query.where(tbDeviceInfo.id.eq("0")); + } + } + } + } + }else{ + query.where(tbDeviceInfo.deptAreaId.isNull()); + } + } + if (StringUtils.isNotBlank(subUid)) { + query.join(tbDeviceSubUser).on(tbDeviceSubUser.deviceId.eq(tbDeviceInfo.deviceId)); + query.where(tbDeviceSubUser.uid.eq(subUid)); + } + + if (StringUtils.isNotBlank(productKey)) { + query.where(tbDeviceInfo.productKey.eq(productKey)); + } + + if (online != null) { + query.where(tbDeviceInfo.state.eq(online ? "online" : "offline")); + } + + if (StringUtils.isNotBlank(keyword)) { + query.where(tbDeviceInfo.deviceId.like("%" + keyword + "%") + .or(tbDeviceInfo.deviceName.like("%" + keyword + "%"))); + } + if (ObjectUtil.isNotNull(startTime)&& ObjectUtil.isNotNull(endTime)) { + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date startDateTime = sdf.parse(startTime); + Date dateTime = sdf.parse(endTime); + // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + // LocalDateTime startDateTime = LocalDateTime.parse(dictData.getStartTime() , formatter); + // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + // LocalDateTime dateTime = LocalDateTime.parse(dictData.getEndTime(), formatter); + query.where(tbDeviceInfo.createTime.between(startDateTime, dateTime)); + } catch (Exception e) { + } + } query.orderBy(tbDeviceInfo.createAt.desc()); query.offset((page - 1) * size).limit(size); @@ -585,7 +707,7 @@ public class DeviceInfoDataImpl implements IDeviceInfoData, IJPACommData findByConditions1(String name, String uid, String subUid, String productKey, String groupId, Boolean online, String keyword, - int page, int size, Long deptAreaId) { + int page, int size, Long deptAreaId,String startTime,String endTime) { JPAQuery query = jpaQueryFactory.selectFrom(tbDeviceInfo); // 根据groupId, 如果groupId存在,则关联查询TbDeviceGroupMapping, 根据groupId,查询对应的devices @@ -642,7 +764,20 @@ public class DeviceInfoDataImpl implements IDeviceInfoData, IJPACommData groupMap = data.getGroup(); groupMap.forEach((id, group) -> { - TbDeviceGroupMapping mapping = deviceGroupMappingRepository.findByDeviceIdAndGroupId(data.getDeviceId(), id); + TbDeviceGroupMapping mapping = deviceGroupMappingRepository.findByDeviceIdAndGroupIdAndTenantId(data.getDeviceId(), id,data.getTenantId()); if (mapping == null) { //保存设备分组与设备对应关系 deviceGroupMappingRepository.save(new TbDeviceGroupMapping( UUID.randomUUID().toString(), data.getDeviceId(), id, - TenantHelper.getTenantId() + data.getTenantId() )); } }); diff --git a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/UserInfoDataImpl.java b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/UserInfoDataImpl.java index 2184d47..ecee829 100644 --- a/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/UserInfoDataImpl.java +++ b/iot-dao/iot-data-serviceImpl-rdb/src/main/java/cc/iotkit/data/service/UserInfoDataImpl.java @@ -79,6 +79,10 @@ public class UserInfoDataImpl implements IUserInfoData, IJPACommData findByUserNameLike(String userName) { + return MapstructUtils.convert(userInfoRepository.findByUserNameLike(userName), UserInfo.class); + } @Override public List findByType(int type) { diff --git a/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/model/TbThingModelMessage.java b/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/model/TbThingModelMessage.java index 3638a72..42292da 100644 --- a/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/model/TbThingModelMessage.java +++ b/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/model/TbThingModelMessage.java @@ -45,6 +45,8 @@ public class TbThingModelMessage { private String type; + private Integer deviceStatus; + private String identifier; private int code; diff --git a/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/service/ThingModelMessageDataImpl.java b/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/service/ThingModelMessageDataImpl.java index a7485e4..82c3d26 100644 --- a/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/service/ThingModelMessageDataImpl.java +++ b/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/service/ThingModelMessageDataImpl.java @@ -80,7 +80,7 @@ public class ThingModelMessageDataImpl implements IThingModelMessageData { return new Paging<>(count, ruleLogs.stream().map(r -> new ThingModelMessage(r.getTime().toString(), r.getMid(), deviceId, r.getProductKey(), r.getDeviceName(), - r.getUid(), r.getType(), r.getIdentifier(), r.getCode(), + r.getUid(), r.getType(),r.getIdentifier(),r.getDeviceStatus(), r.getCode(), JsonUtils.parseObject(r.getData(), Map.class), r.getTime(), r.getReportTime())) .collect(Collectors.toList())); @@ -120,7 +120,7 @@ public class ThingModelMessageDataImpl implements IThingModelMessageData { return new Paging<>(count, ruleLogs.stream().map(r -> new ThingModelMessage(r.getTime().toString(), r.getMid(), r.getDeviceId(), r.getProductKey(), r.getDeviceName(), - r.getUid(), r.getType(), r.getIdentifier(), r.getCode(), + r.getUid(), r.getType(), r.getIdentifier(),r.getDeviceStatus(), r.getCode(), JsonUtils.parseObject(r.getData(), Map.class), r.getTime(), r.getReportTime())) .collect(Collectors.toList())); diff --git a/iot-module/iot-manager/src/main/java/cc/fonts/STSong-Light.ttf b/iot-module/iot-manager/src/main/java/cc/fonts/STSong-Light.ttf new file mode 100644 index 0000000..6f84fd6 Binary files /dev/null and b/iot-module/iot-manager/src/main/java/cc/fonts/STSong-Light.ttf differ diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/config/PDFGenerator.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/config/PDFGenerator.java index eca9495..e2ac505 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/config/PDFGenerator.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/config/PDFGenerator.java @@ -2,12 +2,10 @@ package cc.iotkit.manager.config; import cc.iotkit.model.device.DeviceInstallInfo; -import cn.hutool.core.util.ObjectUtil; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.common.PDRectangle; -import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType0Font; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; @@ -15,11 +13,11 @@ import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.*; import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.stream.Collectors; -import static cc.iotkit.manager.config.PDFUtils.drawAlignedText; - public class PDFGenerator { // 1. 表格参数配置 @@ -37,9 +35,9 @@ public class PDFGenerator { public static void generateInstallationPDF(DeviceInstallInfo entity, OutputStream outputStream) throws IOException { try (PDDocument document = new PDDocument()) { // 加载字体(需替换实际路径) - //PDType0Font font = PDType0Font.load(document, new File("D:\\simsun.ttf")); - PDType0Font font = PDType0Font.load(document, new File("/ttf/simsun.ttf")); - + // PDType0Font font = PDType0Font.load(document, new File("D:\\NotoSansCJK-Regular.ttf")); + //PDType0Font font = PDType0Font.load(document, new File("/ttf/simsun.ttf")); + PDType0Font font = PDType0Font.load(document, new File("/ttf/NotoSansCJK-Regular.ttf")); // 初始化第一页 PDPage currentPage = new PDPage(PDRectangle.A4); document.addPage(currentPage); @@ -55,7 +53,7 @@ public class PDFGenerator { // 2. 绘制基本信息表格 String[][] baseData = { - // {"公司名称", entity.getCorporateName()}, + // {"公司名称", entity.getCorporateName()}, {"申请时间", entity.getProposerTime().toString()}, {"申请人", entity.getProposer()}, {"申请人班组", entity.getProposerTeam()}, @@ -74,7 +72,7 @@ public class PDFGenerator { currentY -= (ROW_HEIGHT * baseData.length) + 20f; // @ApiModelProperty(value = "安装前图片") // 创建后续页面 - 图片部分 - // 图片处理(带自动分页) + // 图片处理(带自动分页) // 图片处理(带自动分页) List imageGroups = Arrays.asList( new String[]{entity.getBeforeInstallationImage(), "安装前图片"}, @@ -99,7 +97,7 @@ public class PDFGenerator { .collect(Collectors.toList()); if (!validUrls.isEmpty()) { - // float totalHeight = calculateTotalHeight(validUrls); + // float totalHeight = calculateTotalHeight(validUrls); List wrappedTitleLines = wrapText(title,LEFT_COL_WIDTH - 2 * CELL_PADDING); float titleHeight = wrappedTitleLines.size() * LINE_HEIGHT; // 计算图片组的自适应高度 @@ -127,12 +125,12 @@ public class PDFGenerator { } finally { cs.close(); } - // document.save("D:/output.pdf"); + // document.save("D:/output.pdf"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); document.save(baos); outputStream.flush(); baos.writeTo(outputStream); - // document.save(outputStream); + // document.save(outputStream); } } private static List wrapText(String text, float maxWidth) { @@ -213,7 +211,7 @@ public class PDFGenerator { return totalHeight; }*/ - private static float calculateAdjustedImagesHeight(PDDocument doc, List imageUrls, + /* private static float calculateAdjustedImagesHeight(PDDocument doc, List imageUrls, float maxWidth, float maxHeight) throws IOException { float totalHeight = 0; float remainingHeight = maxHeight; @@ -242,85 +240,162 @@ public class PDFGenerator { } } - return totalHeight; - } + return totalHeight*imageUrls.size(); + }*/ private static void drawImageGroup(PDPageContentStream cs, PDDocument doc, PDType0Font font, List titleLines, List imageUrls, float startY, float totalHeight) throws IOException { - // float currentImageY = startY - CELL_PADDING; - // 绘制单元格边框 cs.setLineWidth(0.5f); cs.addRect(TABLE_MARGIN, startY - totalHeight, LEFT_COL_WIDTH, totalHeight); cs.addRect(TABLE_MARGIN + LEFT_COL_WIDTH, startY - totalHeight, RIGHT_COL_WIDTH, totalHeight); cs.stroke(); - // 计算文本总高度 - float textHeight = titleLines.size() * LINE_HEIGHT; - float textStartY = startY - (totalHeight / 2) + (textHeight / 2); + // 计算每张图片的可用高度(根据图片数量动态调整) + float imageAvailableHeight = totalHeight - 2 * CELL_PADDING; + float imageAvailableWidth = RIGHT_COL_WIDTH - 2 * CELL_PADDING; + + if (imageUrls.size() == 1) { + // 单图片模式:一页两行,每行占半页高度 + float singleImageHeight = imageAvailableHeight; + // 绘制标题(垂直居中) + float titleY = startY - totalHeight/2 + (titleLines.size() * LINE_HEIGHT)/2; + // 绘制第一行标题(顶部) + // float titleY = startY - CELL_PADDING - FONT_SIZE; + cs.beginText(); + cs.setFont(font, FONT_SIZE); + cs.newLineAtOffset(TABLE_MARGIN + CELL_PADDING, titleY); + for (String line : titleLines) { + cs.showText(line); + titleY -= LINE_HEIGHT; + cs.newLineAtOffset(0, -LINE_HEIGHT); + } + cs.endText(); - // 在左侧单元格绘制标题(带自动换行) - cs.beginText(); - cs.setFont(font, FONT_SIZE); - for (String line : titleLines) { - // 检查文本是否超出单元格宽度 - /* float textWidth = font.getStringWidth(line) / 1000 * FONT_SIZE; - if (textWidth > LEFT_COL_WIDTH - 2*CELL_PADDING) { - line = TextUtils.truncateWithEllipsis(line, font,LEFT_COL_WIDTH - 2*CELL_PADDING); - }*/ - - cs.newLineAtOffset(TABLE_MARGIN + CELL_PADDING, textStartY); - cs.showText(line); - textStartY -= LINE_HEIGHT; - } - cs.endText(); - float availableWidth = RIGHT_COL_WIDTH - 2 * CELL_PADDING; - float remainingHeight = totalHeight - 2 * CELL_PADDING; - // 在右侧单元格绘制图片 - float currentImageY = startY - 10; - for (String url : imageUrls) { - PDImageXObject image = PDImageXObject.createFromByteArray(doc, - new URL(url).openStream().readAllBytes(), "embedded-image"); - // 计算图片的缩放比例 - float scale = Math.min( - availableWidth / image.getWidth(), - remainingHeight / image.getHeight() + // 绘制第一行图片(自动缩放) + PDImageXObject image1 = PDImageXObject.createFromByteArray(doc, + new URL(imageUrls.get(0)).openStream().readAllBytes(), "embedded-image"); + float scale1 = Math.min( + imageAvailableWidth / image1.getWidth(), + singleImageHeight / image1.getHeight() ); - // 确保图片高度不小于最小值 - float scaledHeight = Math.max( - image.getHeight() * scale, - MIN_IMAGE_HEIGHT + float scaledHeight1 = image1.getHeight() * scale1; + float scaledWidth1 = image1.getWidth() * scale1; + + cs.drawImage(image1, + TABLE_MARGIN + LEFT_COL_WIDTH + CELL_PADDING, + startY - CELL_PADDING - scaledHeight1, + scaledWidth1, scaledHeight1); + + } else if (imageUrls.size() == 2) { + // 双图片模式:改为上下布局 + float imageHeightPer = (imageAvailableHeight - CELL_PADDING) / 2; + + // 绘制标题(垂直居中) + float titleY = startY - totalHeight/2 + (titleLines.size() * LINE_HEIGHT)/2; + cs.beginText(); + cs.setFont(font, FONT_SIZE); + cs.newLineAtOffset(TABLE_MARGIN + CELL_PADDING, titleY); + for (String line : titleLines) { + cs.showText(line); + titleY -= LINE_HEIGHT; + cs.newLineAtOffset(0, -LINE_HEIGHT); + } + cs.endText(); + + // 绘制第一张图片(上) + PDImageXObject image1 = PDImageXObject.createFromByteArray(doc, + new URL(imageUrls.get(0)).openStream().readAllBytes(), "embedded-image"); + float scale1 = Math.min( + imageAvailableWidth / image1.getWidth(), + imageHeightPer / image1.getHeight() ); - float scaledWidth = image.getWidth() * scale; - cs.drawImage(image, + float scaledHeight1 = image1.getHeight() * scale1; + float scaledWidth1 = image1.getWidth() * scale1; + + cs.drawImage(image1, TABLE_MARGIN + LEFT_COL_WIDTH + CELL_PADDING, - currentImageY - scaledHeight, - scaledWidth, scaledHeight); + startY - CELL_PADDING - scaledHeight1, + scaledWidth1, scaledHeight1); + + // 绘制第二张图片(下) + PDImageXObject image2 = PDImageXObject.createFromByteArray(doc, + new URL(imageUrls.get(1)).openStream().readAllBytes(), "embedded-image"); + float scale2 = Math.min( + imageAvailableWidth / image2.getWidth(), + imageHeightPer / image2.getHeight() + ); + float scaledHeight2 = image2.getHeight() * scale2; + float scaledWidth2 = image2.getWidth() * scale2; - currentImageY -= scaledHeight + CELL_PADDING; - remainingHeight -= scaledHeight + CELL_PADDING; + cs.drawImage(image2, + TABLE_MARGIN + LEFT_COL_WIDTH + CELL_PADDING, + startY - CELL_PADDING - scaledHeight1 - CELL_PADDING - scaledHeight2, + scaledWidth2, scaledHeight2); + /* // 双图片模式:一行并列显示 + float imageWidthPer = (imageAvailableWidth - CELL_PADDING) / 2; - if (remainingHeight <= 0) { - break; // 超出可用高度则停止绘制 + // 绘制标题(垂直居中) + float titleY = startY - totalHeight/2 + (titleLines.size() * LINE_HEIGHT)/2; + cs.beginText(); + cs.setFont(font, FONT_SIZE); + cs.newLineAtOffset(TABLE_MARGIN + CELL_PADDING, titleY); + for (String line : titleLines) { + cs.showText(line); + titleY -= LINE_HEIGHT; + cs.newLineAtOffset(0, -LINE_HEIGHT); } + cs.endText(); - /* float imageWidth = RIGHT_COL_WIDTH - 10; - float height = imageWidth * image.getHeight() / image.getWidth(); + // 绘制第一张图片(左) + PDImageXObject image1 = PDImageXObject.createFromByteArray(doc, + new URL(imageUrls.get(0)).openStream().readAllBytes(), "embedded-image"); + float scale1 = Math.min( + imageWidthPer / image1.getWidth(), + imageAvailableHeight / image1.getHeight() + ); + float scaledHeight1 = image1.getHeight() * scale1; + float scaledWidth1 = image1.getWidth() * scale1; - cs.drawImage(image, - TABLE_MARGIN + LEFT_COL_WIDTH + 5, - currentImageY - height, - imageWidth, height); + cs.drawImage(image1, + TABLE_MARGIN + LEFT_COL_WIDTH + CELL_PADDING, + startY - CELL_PADDING - scaledHeight1, + scaledWidth1, scaledHeight1); + + // 绘制第二张图片(右) + PDImageXObject image2 = PDImageXObject.createFromByteArray(doc, + new URL(imageUrls.get(1)).openStream().readAllBytes(), "embedded-image"); + float scale2 = Math.min( + imageWidthPer / image2.getWidth(), + imageAvailableHeight / image2.getHeight() + ); + float scaledHeight2 = image2.getHeight() * scale2; + float scaledWidth2 = image2.getWidth() * scale2; - currentImageY -= height + 10;*/ + cs.drawImage(image2, + TABLE_MARGIN + LEFT_COL_WIDTH + CELL_PADDING + imageWidthPer + CELL_PADDING, + startY - CELL_PADDING - scaledHeight2, + scaledWidth2, scaledHeight2);*/ } } + private static float calculateAdjustedImagesHeight(PDDocument doc, List imageUrls, + float maxWidth, float maxHeight) throws IOException { + if (imageUrls.isEmpty()) return 0; + // return maxHeight; + if (imageUrls.size() == 1) { + // 单图片模式:占用半页高度 + return maxHeight / 2; + } else { + // 双图片模式:整页高度 + return maxHeight; + } + } // 截断超长文本 private static String truncateText(PDType0Font font,String text, float maxWidth) throws IOException { - // PDType0Font font = ...; // 获取字体对象 + // PDType0Font font = ...; // 获取字体对象 StringBuilder sb = new StringBuilder(); float currentWidth = 0; diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/config/PDFGenerator22.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/config/PDFGenerator22.java new file mode 100644 index 0000000..6bd1c74 --- /dev/null +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/config/PDFGenerator22.java @@ -0,0 +1,703 @@ +package cc.iotkit.manager.config; + + +import cc.iotkit.model.device.DeviceInstallInfo; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType0Font; +import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + + +public class PDFGenerator22 { + // 1. 表格参数配置 + + // 参数配置(优化后) + private static final float FONT_SIZE = 11f; + private static final float ROW_HEIGHT = 35f; + private static final float TABLE_MARGIN = 50f; + private static final float LEFT_COL_WIDTH = 130f; + private static final float RIGHT_COL_WIDTH = 350f; + private static final float LINE_HEIGHT = FONT_SIZE * 1.2f; + private static final float CELL_PADDING = 5; + private static final float[] COLUMN_WIDTHS = {LEFT_COL_WIDTH, RIGHT_COL_WIDTH}; + private static final float MIN_IMAGE_HEIGHT = 50; + public static void generateInstallationPDF(DeviceInstallInfo entity, OutputStream outputStream) throws IOException { + try (PDDocument document = new PDDocument()) { + // 加载字体(需替换实际路径) + PDType0Font font = PDType0Font.load(document, new File("D:\\simsun.ttf")); + // PDType0Font font = PDType0Font.load(document, new File("/ttf/simsun.ttf")); + + // 初始化第一页 + PDPage currentPage = new PDPage(PDRectangle.A4); + document.addPage(currentPage); + PDPageContentStream cs = new PDPageContentStream(document, currentPage); + float currentY = PDRectangle.A4.getHeight() - TABLE_MARGIN; + + try { + // 1. 绘制标题(居中) + drawCenteredText(cs, font, FONT_SIZE+10, + "安装信息录入表", + PDRectangle.A4.getWidth()/2, currentY); + currentY -= ROW_HEIGHT * 1.5f; + + // 2. 绘制基本信息表格 + String[][] baseData = { + // {"公司名称", entity.getCorporateName()}, + {"申请时间", entity.getProposerTime().toString()}, + {"申请人", entity.getProposer()}, + {"申请人班组", entity.getProposerTeam()}, + {"小区名字", entity.getCommunityName()}, + {"用户姓名", entity.getUserName()}, + {"电话", entity.getUserIpone()}, + {"楼栋单元号", entity.getBuildingUnit()}, + {"房间号", entity.getRoomNo()}, + {"报警器编号", entity.getDeviceName()}, + {"切断阀编号", entity.getShutValueNumber()}, + {"燃气表号", entity.getGasMeterNumber()}, + {"备注", entity.getBuildingUnit()} + + }; + drawTable(cs, font, TABLE_MARGIN, currentY, baseData, COLUMN_WIDTHS); + currentY -= (ROW_HEIGHT * baseData.length) + 20f; +// @ApiModelProperty(value = "安装前图片") + // 创建后续页面 - 图片部分 + // 图片处理(带自动分页) + // 图片处理(带自动分页) + List imageGroups = Arrays.asList( + new String[]{entity.getBeforeInstallationImage(), "安装前图片"}, + new String[]{entity.getWorkingOfTheDetectorImage(), "安装完成探测器工作图片"}, + new String[]{entity.getSideLeakageImage(), "测漏图片"}, + new String[]{entity.getIgnitionPictureImage(), "点火图片"}, + new String[]{entity.getInstallThePanoramicImage(), "安装完成全景图片"}, + new String[]{entity.getOfGasMeterImage(), "燃气表图片"}, + new String[]{entity.getWorkOrderImage(), "工单图片"}, + new String[]{entity.getPunchingImage(), "打孔图片"}, + new String[]{entity.getFiexImage(), "安装电源线图片"} + ); + + for (String[] group : imageGroups) { + String urls = group[0]; + String title = group[1]; + + if (urls != null && !urls.trim().isEmpty()) { + List validUrls = Arrays.stream(urls.split(",")) + .map(String::trim) + .filter(url -> !url.isEmpty() && url.startsWith("http")) + .collect(Collectors.toList()); + + if (!validUrls.isEmpty()) { + // float totalHeight = calculateTotalHeight(validUrls); + List wrappedTitleLines = wrapText(title,LEFT_COL_WIDTH - 2 * CELL_PADDING); + float titleHeight = wrappedTitleLines.size() * LINE_HEIGHT; + // 计算图片组的自适应高度 + float imagesHeight = calculateAdjustedImagesHeight(document, validUrls, + RIGHT_COL_WIDTH - 2 * CELL_PADDING, + PDRectangle.A4.getHeight() - 2 * TABLE_MARGIN - titleHeight); + + float totalHeight = Math.max(imagesHeight, titleHeight); + + if (currentY < TABLE_MARGIN + Math.max(totalHeight, titleHeight)) { + cs.close(); + currentPage = new PDPage(PDRectangle.A4); + document.addPage(currentPage); + cs = new PDPageContentStream(document, currentPage); + currentY = PDRectangle.A4.getHeight() - TABLE_MARGIN; + } + + drawImageGroup(cs, document, font, wrappedTitleLines, validUrls, currentY, + Math.max(totalHeight, titleHeight)); + currentY -= Math.max(totalHeight, titleHeight); + } + } + } + + } finally { + cs.close(); + } + // document.save("D:/output.pdf"); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + document.save(baos); + outputStream.flush(); + baos.writeTo(outputStream); + // document.save(outputStream); + } + } + private static List wrapText(String text, float maxWidth) { + List lines = new ArrayList<>(); + int maxCharsPerLine = (int)(maxWidth / (FONT_SIZE * 0.5f)); // 中文字符估算 + + StringBuilder currentLine = new StringBuilder(); + for (String word : text.split("")) { + if (currentLine.length() + word.length() <= maxCharsPerLine) { + currentLine.append(word); + } else { + lines.add(currentLine.toString()); + currentLine = new StringBuilder(word); + } + } + if (currentLine.length() > 0) { + lines.add(currentLine.toString()); + } + return lines; + } + + + private static float calculateTotalHeight(List imageUrls) throws IOException { + float totalHeight = 0; + for (String url : imageUrls) { + totalHeight += estimateImageHeight(url, RIGHT_COL_WIDTH - 10) + 10; + } + return totalHeight; + } + /* private static float calculateAdjustedImagesHeight(PDDocument doc, List imageUrls, + float maxWidth, float maxHeight) throws IOException { + if (imageUrls.isEmpty()) return 0; + + // 1. 预加载所有图片并收集尺寸信息 + List images = new ArrayList<>(); + for (String url : imageUrls) { + try { + PDImageXObject image = PDImageXObject.createFromByteArray(doc, + new URL(url).openStream().readAllBytes(), "embedded-image"); + images.add(image); + } catch (IOException e) { + // 跳过加载失败的图片 + continue; + } + } + + // 2. 计算统一缩放比例 + float uniformScale = Float.MAX_VALUE; + int validImageCount = images.size(); + float availableHeightPerImage = (maxHeight - (validImageCount-1)*10f) / validImageCount; // 10为图片间距 + + for (PDImageXObject image : images) { + // 计算当前图片的最大允许缩放比例 + float widthScale = maxWidth / image.getWidth(); + float heightScale = availableHeightPerImage / image.getHeight(); + float minScale = Math.min(widthScale, heightScale); + + // 取所有图片中最小的缩放比例作为统一比例 + uniformScale = Math.min(uniformScale, minScale); + } + + // 3. 应用最小高度限制 + uniformScale = Math.max(uniformScale, MIN_IMAGE_HEIGHT / + images.stream().map(img -> (float)img.getHeight()).max(Float::compare).orElse(1f)); + // images.stream().mapToFloat(PDImageXObject::getHeight).max().orElse(1f)); + + // 4. 计算总高度(所有图片统一缩放后的高度 + 间距) + float totalHeight = 0; + for (PDImageXObject image : images) { + float scaledHeight = image.getHeight() * uniformScale; + totalHeight += scaledHeight + 10; // 10为图片间距 + if (totalHeight > maxHeight) { + totalHeight -= scaledHeight + 10; // 移除超出的部分 + break; + } + } + + return totalHeight; + }*/ + + private static float calculateAdjustedImagesHeight(PDDocument doc, List imageUrls, + float maxWidth, float maxHeight) throws IOException { + float totalHeight = 0; + float remainingHeight = maxHeight; + + for (String url : imageUrls) { + PDImageXObject image = PDImageXObject.createFromByteArray(doc, + new URL(url).openStream().readAllBytes(), "embedded-image"); + + // 计算图片的缩放比例 + float scale = Math.min( + maxWidth / image.getWidth(), + remainingHeight / image.getHeight() + ); + + // 确保图片高度不小于最小值 + float scaledHeight = Math.max( + image.getHeight() * scale, + MIN_IMAGE_HEIGHT + ); + + totalHeight += scaledHeight + 10; // 10是图片间距 + remainingHeight -= scaledHeight + 10; + + if (remainingHeight <= 0) { + break; // 超出可用高度则停止添加图片 + } + } + + return totalHeight*imageUrls.size(); + } + + private static void drawImageGroup(PDPageContentStream cs, PDDocument doc, PDType0Font font, + List titleLines, List imageUrls, + float startY, float totalHeight) throws IOException { + // float currentImageY = startY - CELL_PADDING; + + // 绘制单元格边框 + cs.setLineWidth(0.5f); + cs.addRect(TABLE_MARGIN, startY - totalHeight, LEFT_COL_WIDTH, totalHeight); + cs.addRect(TABLE_MARGIN + LEFT_COL_WIDTH, startY - totalHeight, RIGHT_COL_WIDTH, totalHeight); + cs.stroke(); + + // 计算文本总高度 + float textHeight = titleLines.size() * LINE_HEIGHT; + float textStartY = 0f; + if(imageUrls.size() > 1){ + textStartY = startY + startY/imageUrls.size() - (totalHeight / 2) + (textHeight / 2); + }else{ + textStartY = startY - (totalHeight / 2) + (textHeight / 2); + } + + + // 在左侧单元格绘制标题(带自动换行) + cs.beginText(); + cs.setFont(font, FONT_SIZE); + for (String line : titleLines) { + // 检查文本是否超出单元格宽度 + /* float textWidth = font.getStringWidth(line) / 1000 * FONT_SIZE; + if (textWidth > LEFT_COL_WIDTH - 2*CELL_PADDING) { + line = TextUtils.truncateWithEllipsis(line, font,LEFT_COL_WIDTH - 2*CELL_PADDING); + }*/ + + cs.newLineAtOffset(TABLE_MARGIN + CELL_PADDING, textStartY); + cs.showText(line); + textStartY -= LINE_HEIGHT; + } + cs.endText(); + float availableWidth = RIGHT_COL_WIDTH - 2 * CELL_PADDING; + float remainingHeight = totalHeight - 2 * CELL_PADDING; + // 在右侧单元格绘制图片 + float currentImageY = startY - 10; + for (String url : imageUrls) { + PDImageXObject image = PDImageXObject.createFromByteArray(doc, + new URL(url).openStream().readAllBytes(), "embedded-image"); + // 计算图片的缩放比例 + float scale = Math.min( + availableWidth / image.getWidth()/imageUrls.size(), + remainingHeight / image.getHeight()/imageUrls.size() + ); + // 确保图片高度不小于最小值 + float scaledHeight = Math.max( + image.getHeight() * scale, + MIN_IMAGE_HEIGHT + ); + float scaledWidth = image.getWidth() * scale; + cs.drawImage(image, + TABLE_MARGIN + LEFT_COL_WIDTH + CELL_PADDING, + currentImageY - scaledHeight, + scaledWidth, scaledHeight); + + currentImageY -= scaledHeight + CELL_PADDING; + remainingHeight -= scaledHeight + CELL_PADDING; + + if (remainingHeight <= 0) { + break; // 超出可用高度则停止绘制 + } + + } + } + + + // 截断超长文本 + private static String truncateText(PDType0Font font,String text, float maxWidth) throws IOException { + // PDType0Font font = ...; // 获取字体对象 + StringBuilder sb = new StringBuilder(); + float currentWidth = 0; + + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + float charWidth = font.getStringWidth(String.valueOf(c)) / 1000 * FONT_SIZE; + + if (currentWidth + charWidth > maxWidth) { + break; + } + sb.append(c); + currentWidth += charWidth; + } + return sb.toString(); + } + + + // 新增方法:计算文本高度(考虑换行) + private static float getTextHeight(String text, float maxWidth, PDType0Font font, float fontSize) throws IOException { + if (text == null || text.isEmpty()) { + return 0; + } + + // 简单估算:假设每个中文字符宽度等于字体大小 + int charsPerLine = (int)(maxWidth / fontSize); + int lineCount = (int)Math.ceil((double)text.length() / charsPerLine); + + return lineCount * fontSize * 1.2f; // 行间距1.2倍 + } + + // 改进方法:绘制自动换行文本 + private static void drawWrappedText(PDPageContentStream cs, PDType0Font font, + float fontSize, String text, + float startX, float startY, float maxWidth) throws IOException { + cs.setFont(font, fontSize); + cs.setLeading(fontSize * 1.2f); // 行间距 + + // 简单换行实现 + int charsPerLine = (int)(maxWidth / (fontSize * 0.8)); // 中文字符估算 + int pos = 0; + float currentY = startY; + + while (pos < text.length()) { + int endPos = Math.min(pos + charsPerLine, text.length()); + String line = text.substring(pos, endPos); + + cs.beginText(); + cs.newLineAtOffset(startX, currentY); + cs.showText(line); + cs.endText(); + + pos = endPos; + currentY -= fontSize * 1.2f; + } + } + // 图片高度预估方法 + private static float estimateImageHeight(String imageUrl, float targetWidth) throws IOException { + try (InputStream is = new URL(imageUrl).openStream()) { + BufferedImage img = ImageIO.read(is); + return img.getHeight() * (targetWidth / img.getWidth()); + } + } + + /* public static void generateInstallationPDF(DeviceInstallInfo entity, OutputStream outputStream) throws IOException { + try (PDDocument document = new PDDocument()) { +// 加载中文字体(需确保D:/simsun.ttc存在) + PDType0Font font = PDType0Font.load(document, new File("D:\\simsun.ttf")); + + // 创建单页文档 + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + PDPageContentStream cs = new PDPageContentStream(document, page); + + float currentY = PDRectangle.A4.getHeight() - TABLE_MARGIN; + + // 3. 绘制标题(居中) + drawCenteredText(cs, font, FONT_SIZE + 6, + "贵阳户内安装信息录入表", + PDRectangle.A4.getWidth() / 2, currentY); + currentY -= ROW_HEIGHT * 1.5f; + + // 4. 基本信息表格 + String[][] baseData = { + {"安装班组", entity.getProposerTeam()}, + {"安装人", entity.getProposer()}, + {"安装时间", entity.getProposerTime().toString()}, + {"小区名称", entity.getCommunityName()}, + {"楼栋号", entity.getBuildingUnit()}, + {"单元号", entity.getBuildingUnit() != null ? + entity.getBuildingUnit().split("-")[0] : ""}, + {"房号", entity.getRoomNo()}, + {"用户姓名", entity.getUserName()}, + {"联系方式", entity.getUserIpone()}, + {"灶具类型", entity.getDeviceName() != null ? + (entity.getDeviceName().contains("台式") ? "台式灶" : "嵌入式灶") : ""} + }; + drawTable(cs, font, TABLE_MARGIN, currentY, baseData, + new float[]{COLUMN_LEFT_WIDTH, COLUMN_WIDTH}); + currentY -= (ROW_HEIGHT * baseData.length) + 20f; + + // 5. 图片处理(内嵌到表格) + if (entity.getBeforeInstallationImage() != null) { + if (currentY < TABLE_MARGIN + 150) { + cs.close(); + page = new PDPage(PDRectangle.A4); + document.addPage(page); + cs = new PDPageContentStream(document, page); + currentY = PDRectangle.A4.getHeight() - TABLE_MARGIN; + } + //page = new PDPage(PDRectangle.A4); + // document.addPage(page); + currentY = addImageRow(cs, document, font, "安装前图片", + entity.getBeforeInstallationImage(), TABLE_MARGIN, currentY); + // currentY -= ROW_HEIGHT * 3; // 图片行高是普通行的3倍 + } + // 其他图片处理同理... + + document.save("D:/output.pdf"); + document.save(outputStream); + } + + + }*/ + + /* private static void drawTable(PDPageContentStream cs, PDType0Font font, + float x, float y, String[][] data, float[] colWidths) throws IOException { + +// 计算表格总宽度 + float tableWidth = 0; + for (float width : colWidths) tableWidth += width; + +// 绘制外边框 + cs.setLineWidth(1.5f); + cs.addRect(x, y - ROW_HEIGHT * data.length, tableWidth, ROW_HEIGHT * data.length); + cs.stroke(); + +// 绘制列线 + float currentX = x; + for (int i = 0; i < colWidths.length - 1; i++) { + currentX += colWidths[i]; + cs.moveTo(currentX, y); + cs.lineTo(currentX, y - ROW_HEIGHT * data.length); + cs.stroke(); + } + +// 绘制行线 + for (int i = 1; i < data.length; i++) { + cs.moveTo(x, y - ROW_HEIGHT * i); + cs.lineTo(x + tableWidth, y - ROW_HEIGHT * i); + cs.stroke(); + } + // 改进的文本定位 + for (int row = 0; row < data.length; row++) { + for (int col = 0; col < data[row].length; col++) { + // 方案1:手动求和(推荐) + float sum = 0; + for (int i = 0; i < col; i++) { + sum += colWidths[i]; + } + + String text = data[row][col] != null ? data[row][col] : ""; + float textWidth = font.getStringWidth(text) / 1000 * FONT_SIZE; + float textX = x + sum + + (colWidths[col] - textWidth)/2; + float textY = y - (row * ROW_HEIGHT) - (ROW_HEIGHT/2 - FONT_SIZE/4); + + cs.beginText(); + cs.newLineAtOffset(textX, textY); + cs.showText(text); + cs.endText(); + } + }*/ +// 填写内容(严格居中) + /* for (int row = 0; row < data.length; row++) { + currentX = x; + for (int col = 0; col < data[row].length; col++) { + String text = data[row][col] != null ? data[row][col] : ""; + float textWidth = font.getStringWidth(text) / 1000 * FONT_SIZE; + + cs.beginText(); + cs.newLineAtOffset( + currentX + (colWidths[col] - textWidth) / 2, + y - (ROW_HEIGHT * row) - (ROW_HEIGHT / 2 + FONT_SIZE / 3) + ); + cs.showText(text); + cs.endText(); + + currentX += colWidths[col]; + } + }*/ + + + + + private static void drawTable(PDPageContentStream cs, PDType0Font font, + float x, float y, String[][] data, float[] colWidths) throws IOException { + +// 修改后的表格绘制代码 + if (data == null || data.length == 0 || colWidths == null) return; + + final float ROW_HEIGHT = 35f; // 增大行高以适应更大字体 + final float FONT_SIZE = 14f; // 增大字体大小 + final float PADDING = 5f; + +// 计算表格总宽度 + float tableWidth = 0; + for (float width : colWidths) { + tableWidth += width; + } + +// 绘制表格边框和分隔线(保持不变) + cs.setLineWidth(1f); + cs.addRect(x, y - ROW_HEIGHT * data.length, tableWidth, ROW_HEIGHT * data.length); + cs.stroke(); + +// 绘制列分隔线 + float currentX = x; + for (int i = 1; i < colWidths.length; i++) { + currentX += colWidths[i-1]; + cs.moveTo(currentX, y); + cs.lineTo(currentX, y - ROW_HEIGHT * data.length); + cs.stroke(); + } + +// 绘制行分隔线 + for (int i = 1; i <= data.length; i++) { + cs.moveTo(x, y - ROW_HEIGHT * i); + cs.lineTo(x + tableWidth, y - ROW_HEIGHT * i); + cs.stroke(); + } + +// 填写表格内容(关键修改部分) + cs.setFont(font, FONT_SIZE); + for (int row = 0; row < data.length; row++) { + currentX = x; + for (int col = 0; col < data[row].length; col++) { + String text = data[row][col] != null ? data[row][col] : ""; + // 计算文本宽度 + float textWidth = font.getStringWidth(text) / 1000 * FONT_SIZE; + float centerOffset = (colWidths[col] - textWidth) / 2; + // 修正垂直居中计算(关键修改) + float baselineOffset = (ROW_HEIGHT - FONT_SIZE) / 3; // 更精确的基线计算 + cs.beginText(); + cs.newLineAtOffset( + currentX + centerOffset, + y - (ROW_HEIGHT * row) - FONT_SIZE - baselineOffset // 修正垂直位置 + ); + cs.showText(text); + cs.endText(); + currentX += colWidths[col]; + } + } + } + + + + private static float addImageRow(PDPageContentStream cs, PDDocument doc, + PDType0Font font, String title, String imageUrl, + float startX, float startY) throws IOException { + // 加载图片 + PDImageXObject image = PDImageXObject.createFromByteArray(doc, + new URL(imageUrl).openStream().readAllBytes(), "embedded-image"); + // 动态计算尺寸 + float imageWidth = RIGHT_COL_WIDTH - 10; + float scale = imageWidth / image.getWidth(); + float imageHeight = image.getHeight() * scale; + float rowHeight = imageHeight + 20; + + // 绘制单元格边框 + cs.setLineWidth(0.5f); + cs.addRect(startX, startY - rowHeight, LEFT_COL_WIDTH, rowHeight); + cs.addRect(startX + LEFT_COL_WIDTH, startY - rowHeight, RIGHT_COL_WIDTH, rowHeight); + cs.stroke(); + + // 垂直居中文本(改进算法) + float textY = startY - rowHeight/2 + FONT_SIZE/2; + //String title = "安装完成探测器工作图片\n检测时间:2025-08-14"; + + /* if(title.contains("\n")){ + String[] lines = title.split("\n"); + textY = startY - rowHeight/2 + FONT_SIZE/2 + (lines.length-1)*FONT_SIZE/2; + }*/ + drawCenteredText(cs, font, FONT_SIZE, title, + startX + LEFT_COL_WIDTH/2, textY); + + // 绘制图片(带5pt边距) + cs.drawImage(image, + startX + LEFT_COL_WIDTH + 5, + startY - rowHeight + 10, + imageWidth, imageHeight); + + return startY - rowHeight - 10; + /*// 计算图片尺寸(保持比例) + float imageWidth = RIGHT_COL_WIDTH - 10; + float scale = imageWidth / image.getWidth(); + float imageHeight = image.getHeight() * scale; + + // 动态计算行高(图片高度+上下边距20) + float dynamicRowHeight = imageHeight + 20; + + // 绘制左侧标题单元格 + cs.setLineWidth(0.5f); + cs.addRect(TABLE_MARGIN, startY - dynamicRowHeight, LEFT_COL_WIDTH, dynamicRowHeight); + + // 绘制右侧图片单元格(高度与左侧同步) + cs.addRect(TABLE_MARGIN + LEFT_COL_WIDTH, startY - dynamicRowHeight, RIGHT_COL_WIDTH, dynamicRowHeight); + cs.stroke(); + + // 居中绘制标题文本 + float titleWidth = font.getStringWidth(title) / 1000 * FONT_SIZE; + float titleX = TABLE_MARGIN + (LEFT_COL_WIDTH - titleWidth) / 2; + float titleY = startY - (dynamicRowHeight / 2) - (FONT_SIZE / 3); + + cs.beginText(); + cs.setFont(font, FONT_SIZE); + cs.newLineAtOffset(titleX, titleY); + cs.showText(title); + cs.endText(); + + // 居中绘制图片 + float imageX = TABLE_MARGIN + LEFT_COL_WIDTH + 5; + float imageY = startY - dynamicRowHeight + 10; + cs.drawImage(image, imageX, imageY, imageWidth, imageHeight); + + // 返回新的Y坐标(当前位置减去行高和间距) + return startY - dynamicRowHeight - 10;*/ + } + + /* private static float addImageRow(PDPageContentStream cs, PDDocument doc, + PDType0Font font, String title, String imageUrl, float x, float y) throws IOException { +// 绘制标题行 + +// 加载并绘制图片(居中) + PDImageXObject image = PDImageXObject.createFromByteArray(doc, + new URL(imageUrl).openStream().readAllBytes(), "embedded-image"); + // 计算图片尺寸(保持比例) + +// 加载并绘制图片 + + // 计算图片缩放比例 + float imageWidth = RIGHT_COL_WIDTH - 10; + float scale = imageWidth / image.getWidth(); + float imageHeight = image.getHeight() * scale; + float rowHeight = Math.max(ROW_HEIGHT, imageHeight + 10); + + // 绘制图片行边框 + cs.setLineWidth(0.5f); + cs.addRect(TABLE_MARGIN, y - rowHeight, LEFT_COL_WIDTH, rowHeight); + cs.addRect(TABLE_MARGIN + LEFT_COL_WIDTH, y - rowHeight, RIGHT_COL_WIDTH, rowHeight); + cs.stroke(); + String[][] titleData = {{title, ""}}; + // drawTable(cs, font, x, y, titleData, new float[]{COLUMN_LEFT_WIDTH, COLUMN_WIDTH}); + // 写入标题文本 + // 新代码(居中显示) + float titleWidth = font.getStringWidth(title) / 1000 * 20; // 计算文本宽度 + float centerX = TABLE_MARGIN + (LEFT_COL_WIDTH - titleWidth) / 2; // 计算居中位置 + + cs.beginText(); + cs.setFont(font, 20); + cs.newLineAtOffset(centerX, y - 15); // 使用计算出的居中位置 + cs.showText(title); + cs.endText(); + // 绘制图片(居中显示) + float imageY = y - (rowHeight/2) - (imageHeight/2); + cs.drawImage(image, TABLE_MARGIN + LEFT_COL_WIDTH + 5, imageY, imageWidth, imageHeight); + + y -= rowHeight + 10; + return y - rowHeight - 10; // 返回新的Y坐标 + }*/ + + + private static void drawCenteredText(PDPageContentStream cs, PDType0Font font, + float fontSize, String text, float centerX, float baselineY) throws IOException { + + float textWidth = font.getStringWidth(text) / 1000 * fontSize; + cs.setFont(font, fontSize); + cs.beginText(); + // 原始调用改进为 + cs.newLineAtOffset(centerX - textWidth / 2, baselineY); + cs.showText(text); + cs.endText(); + } + + +} diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java index fe08be0..7babd18 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java @@ -26,6 +26,8 @@ import cc.iotkit.common.api.PageRequest; import cc.iotkit.common.api.Paging; import cc.iotkit.common.api.Request; import cc.iotkit.common.api.Response; +import cc.iotkit.common.excel.convert.ExcelBigNumberConvert; +import cc.iotkit.common.excel.core.CellMergeStrategy; import cc.iotkit.common.excel.utils.ExcelUtil; import cc.iotkit.common.log.annotation.Log; import cc.iotkit.common.log.enums.BusinessType; @@ -58,9 +60,11 @@ import cc.iotkit.model.device.message.DeviceProperty; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.ExcelWriter; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; +import org.apache.poi.sl.usermodel.Sheet; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -125,7 +129,7 @@ public class DeviceController { @ApiOperation(value = "创建设备") @SaCheckPermission("iot:device:add") @PostMapping("/add") - public boolean createDevice(@RequestBody @Validated Request bo) { + public boolean createDevice(@RequestBody @Validated Request bo) { return deviceServiceImpl.addDevice(bo.getData()); } @@ -204,20 +208,21 @@ public class DeviceController { @Log(title = "设备管理", businessType = BusinessType.EXPORT) // @SaCheckPermission("system:user:export")@RequestBody Request @PostMapping("/export") - public void export(DeviceQueryBo deviceQueryBo, + public void export(@Validated @RequestBody PageRequest deviceQueryBo, HttpServletResponse response) { if(ObjectUtil.isEmpty(deviceQueryBo)){ if(LoginHelper.isSuperAdmin() && TenantHelper.getTenantId() == 0){ - deviceQueryBo.setTenantId(null); + deviceQueryBo.getData().setTenantId(null); }else{ - deviceQueryBo.setTenantId(TenantHelper.getTenantId()); + deviceQueryBo.getData().setTenantId(TenantHelper.getTenantId()); } } - List list = deviceServiceImpl.getDevicess(deviceQueryBo); + List list = deviceServiceImpl.getDevicessExcel(deviceQueryBo); List listVo = MapstructUtils.convert(list, DeviceInfoExpordVo.class); ExcelUtil.exportExcel(listVo, "设备数据", DeviceInfoExpordVo.class, response); } + @ApiOperation("设备物模型日志") @SaCheckPermission("iot:deviceLog:query") @PostMapping("/deviceLogs/list") diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceInstallInfoController.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceInstallInfoController.java index 730ab9c..ec35a8f 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceInstallInfoController.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceInstallInfoController.java @@ -27,14 +27,23 @@ import cc.iotkit.common.api.Paging; import cc.iotkit.common.api.Request; import cc.iotkit.common.constant.Constants; import cc.iotkit.common.enums.ErrCode; +import cc.iotkit.common.excel.utils.ExcelUtil; import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.log.annotation.Log; +import cc.iotkit.common.log.enums.BusinessType; import cc.iotkit.common.satoken.utils.LoginHelper; import cc.iotkit.common.tenant.helper.TenantHelper; +import cc.iotkit.common.utils.MapstructUtils; import cc.iotkit.data.manager.IDeviceInstallInfoData; import cc.iotkit.manager.config.GasInstallationPDFGenerator; import cc.iotkit.manager.config.PDFGenerator; import cc.iotkit.manager.dto.bo.device.DeviceDetectorQueryBo; import cc.iotkit.manager.dto.bo.device.DeviceInstallInfoQueryBo; +import cc.iotkit.manager.dto.bo.device.DeviceQueryBo; +import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInfoExpordVo; +import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInfoVo; +import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInstallInfoExpordVo; +import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInstallInfoVo; import cc.iotkit.manager.service.IDeviceDetectorInfoService; import cc.iotkit.manager.service.IDeviceInstallInfoService; import cc.iotkit.model.UserInfo; @@ -192,6 +201,26 @@ public class DeviceInstallInfoController { PDFGenerator.generateInstallationPDF(data, response.getOutputStream()); } + @ApiOperation("导出设备列表") + @Log(title = "导出设备列表", businessType = BusinessType.EXPORT) + // @SaCheckPermission("system:user:export")@RequestBody Request + @PostMapping("/export") + public void export(@Validated @RequestBody PageRequest pageRequest, + HttpServletResponse response) { + if(ObjectUtil.isEmpty(pageRequest.getData())){ + if(LoginHelper.isSuperAdmin() && TenantHelper.getTenantId() == 0){ + pageRequest.getData().setTenantId(null); + }else{ + pageRequest.getData().setTenantId(TenantHelper.getTenantId()); + } + } + List list = deviceServiceImpl.getList(pageRequest); + // List list = deviceServiceImpl.getDevicess(deviceQueryBo); + List listVo = MapstructUtils.convert(list, DeviceInstallInfoExpordVo.class); + ExcelUtil.exportExcel(listVo, "每日安装明细", DeviceInstallInfoExpordVo.class, response); + } + + // @PostMapping("/getPdf") @SaCheckPermission("device:install:upload") public void getPdf1(@Validated @RequestBody Request request, HttpServletResponse response) throws Exception { diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceInfoAddBo.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceInfoAddBo.java new file mode 100644 index 0000000..7df788c --- /dev/null +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceInfoAddBo.java @@ -0,0 +1,129 @@ +/* + * + * * | Licensed 未经许可不能去掉「OPENIITA」相关版权 + * * +---------------------------------------------------------------------- + * * | Author: xw2sy@163.com + * * +---------------------------------------------------------------------- + * + * Copyright [2024] [OPENIITA] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * / + */ + +package cc.iotkit.manager.dto.bo.device; + +import cc.iotkit.common.api.BaseDto; +import cc.iotkit.model.device.DeviceInfo; +import cc.iotkit.model.device.DeviceInstallInfo; +import io.github.linpeilie.annotations.AutoMapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Size; +import java.util.HashMap; +import java.util.Map; + + +@ApiModel(value = "DeviceInfoAddBo") +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = DeviceInfo.class, reverseConvertGenerate = false) +public class DeviceInfoAddBo extends BaseDto { + + private static final long serialVersionUID = -1L; + + private String id; + + @ApiModelProperty(value = "创建时间") + private Long createAt; + + @ApiModelProperty(value = "设备id") + @Size(max = 255, message = "设备id长度不正确") + private String deviceId; + + @ApiModelProperty(value = "设备名称") + @Size(max = 255, message = "设备名称长度不正确") + private String deviceName; + + @ApiModelProperty(value = "设备类型") + @Size(max = 255, message = "设备类型长度不正确") + private String model; + + @ApiModelProperty(value = "设备离线时间") + private Long offlineTime; + + @ApiModelProperty(value = "设备在线时间") + private Long onlineTime; + + @ApiModelProperty(value = "父级id") + @Size(max = 255, message = "父级id长度不正确") + private String parentId; + + @ApiModelProperty(value = "产品key") + @Size(max = 255, message = "产品key长度不正确") + // @NotBlank(message = "产品Key不能为空") + private String productKey; + + @ApiModelProperty(value = "设备描述") + @Size(max = 255, message = "设备描述长度不正确") + private String secret; + + @ApiModelProperty(value = "经度") + private String longitude; + + @ApiModelProperty(value = "纬度") + private String latitude; + @ApiModelProperty(value = "详细地址") + private String site; + private String name; + @ApiModelProperty(value="部门表-区域id") + private Long deptAreaId; + @ApiModelProperty(value = "用户id") + @Size(max = 255, message = "用户id长度不正确") + private String uid; + private Long tenantId; + private String groupId; + + private DeviceInstallInfo deviceInstallInfo; + private String nodeOne; + private String nodeTwo; + private String nodeThree; + private String nodeFour; + private String nodeFive; + private String nodeOneStatus; + private String nodeTwoStatus; + private String nodeThreeStatus; + private String nodeFourStatus; + private String nodeFiveStatus; + private String nodeOneDevice; + private String nodeTwoDevice; + private String nodeThreeDevice; + private String nodeFourDevice; + private String nodeFiveDevice; + /** + * 设备所属分组 + */ + /* private Map group = new HashMap<>(); + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Group { + private String id; + private String name; + }*/ +} diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceInfoBo.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceInfoBo.java index 3af9444..6a58877 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceInfoBo.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceInfoBo.java @@ -26,11 +26,17 @@ package cc.iotkit.manager.dto.bo.device; import cc.iotkit.common.api.BaseDto; import cc.iotkit.model.device.DeviceInfo; import cc.iotkit.model.device.DeviceInstallInfo; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import io.github.linpeilie.annotations.AutoMapper; import io.github.linpeilie.annotations.AutoMapping; import io.github.linpeilie.annotations.ReverseAutoMapping; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.NotBlank; import javax.validation.constraints.Size; import lombok.Data; @@ -116,4 +122,37 @@ public class DeviceInfoBo extends BaseDto { private String nodeThreeDevice; private String nodeFourDevice; private String nodeFiveDevice; + /** + * 设备所属分组 + */ + private Map group = new HashMap<>(); + // private static final ObjectMapper mapper = new ObjectMapper(); + // 使用 @JsonAnySetter 处理动态键 + //@JsonSetter +/* public void setGroup(Object value) { + if (value instanceof Map) { + + this.group = (Map) value; + } + // 否则,不进行赋值,保持原来的空Map + }*/ + public void setGroup(Object value) { + if (value instanceof Map) { + ObjectMapper mapper = new ObjectMapper(); + this.group = mapper.convertValue( + value, + new TypeReference>(){} + ); + } + } + + + // private Object group; + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Group { + private String id; + private String name; + } } diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceInstallInfoQueryBo.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceInstallInfoQueryBo.java index e01da29..019359d 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceInstallInfoQueryBo.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceInstallInfoQueryBo.java @@ -102,4 +102,6 @@ public class DeviceInstallInfoQueryBo extends BaseDto { private String userName; // @ApiModelProperty(value = "用户电话") private String userIpone; + //绑定人电话 + private String bindUserIpone; } diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceQueryBo.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceQueryBo.java index 57074f1..4f0d6fa 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceQueryBo.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/device/DeviceQueryBo.java @@ -83,4 +83,8 @@ public class DeviceQueryBo extends BaseDto { @ApiModelProperty(value="设备名称") private String name; private Boolean flag = false; + @ApiModelProperty(value = "设备名称") + private String startTime; + @ApiModelProperty(value = "设备名称") + private String endTime; } diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/deviceinfo/DeviceInfoVo.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/deviceinfo/DeviceInfoVo.java index 529f7c0..b060ea1 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/deviceinfo/DeviceInfoVo.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/deviceinfo/DeviceInfoVo.java @@ -132,4 +132,6 @@ public class DeviceInfoVo implements Serializable { private String nodeThreeDevice; private String nodeFourDevice; private String nodeFiveDevice; + private String longitude; + private String latitude; } diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/deviceinfo/DeviceInstallInfoExpordVo.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/deviceinfo/DeviceInstallInfoExpordVo.java new file mode 100644 index 0000000..51aaa93 --- /dev/null +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/deviceinfo/DeviceInstallInfoExpordVo.java @@ -0,0 +1,82 @@ +/* + * + * * | Licensed 未经许可不能去掉「OPENIITA」相关版权 + * * +---------------------------------------------------------------------- + * * | Author: xw2sy@163.com + * * +---------------------------------------------------------------------- + * + * Copyright [2024] [OPENIITA] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * / + */ + +package cc.iotkit.manager.dto.vo.deviceinfo; + + +import cc.iotkit.model.device.DeviceInstallInfo; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.github.linpeilie.annotations.AutoMapper; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.util.Date; + + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = DeviceInstallInfoVo.class, convertGenerate = false) +public class DeviceInstallInfoExpordVo implements Serializable { + private static final long serialVersionUID = 1L; + + + /* // @ApiModelProperty(value = "申请人") + private String proposer; + // @ApiModelProperty(value = "申请班组") + private String proposerTeam; + // @ApiModelProperty(value = "小区名称") + private String communityName;*/ + // @ApiModelProperty(value = "用户名称") + @ExcelProperty(value = "序号") + private Integer xuhao; + @ExcelProperty(value = "姓名") + private String userName; + // @ApiModelProperty(value = "用户电话") + @ExcelProperty(value = "电话") + private String userIpone; + // @ApiModelProperty(value = "切断阀编号") + @ExcelProperty(value = "地址") + private String site; + // @ApiModelProperty(value = "燃气表号") + @ExcelProperty(value = "表号") + private String gasMeterNumber; + @ExcelProperty(value = "安装人") + private String proposer; + @ExcelProperty(value = "安装时间") + // @ApiModelProperty(value = "申请时间") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date proposerTime; + @ExcelProperty(value = "厂家") + private String manufacturer; + @ExcelProperty(value = "安装情况") + private String position; + /* // @ApiModelProperty(value = "备注") + private String remarks; + + private Integer state;*/ +} diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/deviceinfo/DeviceInstallInfoVo.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/deviceinfo/DeviceInstallInfoVo.java new file mode 100644 index 0000000..4120b1a --- /dev/null +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/vo/deviceinfo/DeviceInstallInfoVo.java @@ -0,0 +1,85 @@ +/* + * + * * | Licensed 未经许可不能去掉「OPENIITA」相关版权 + * * +---------------------------------------------------------------------- + * * | Author: xw2sy@163.com + * * +---------------------------------------------------------------------- + * + * Copyright [2024] [OPENIITA] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * / + */ + +package cc.iotkit.manager.dto.vo.deviceinfo; + + +import cc.iotkit.model.Owned; +import cc.iotkit.model.TenantModel; +import cc.iotkit.model.device.DeviceInfo; +import cc.iotkit.model.device.DeviceInstallInfo; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.github.linpeilie.annotations.AutoMapper; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.util.Date; + +@ApiModel(value = "DeviceInstallInfoVo") +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = DeviceInstallInfo.class, convertGenerate = false) +public class DeviceInstallInfoVo implements Serializable { + private static final long serialVersionUID = 1L; + + + /* // @ApiModelProperty(value = "申请人") + private String proposer; + // @ApiModelProperty(value = "申请班组") + private String proposerTeam; + // @ApiModelProperty(value = "小区名称") + private String communityName;*/ + // @ApiModelProperty(value = "用户名称") + @ExcelProperty(value = "序号") + private Integer xuhao; + @ExcelProperty(value = "姓名") + private String userName; + // @ApiModelProperty(value = "用户电话") + @ExcelProperty(value = "电话") + private String userIpone; + // @ApiModelProperty(value = "切断阀编号") + @ExcelProperty(value = "地址") + private String site; + // @ApiModelProperty(value = "燃气表号") + @ExcelProperty(value = "表号") + private String gasMeterNumber; + @ExcelProperty(value = "安装人") + private String proposer; + @ExcelProperty(value = "安装时间") + // @ApiModelProperty(value = "申请时间") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date proposerTime; + @ExcelProperty(value = "厂家") + private String manufacturer; + @ExcelProperty(value = "安装情况") + private String position; + /* // @ApiModelProperty(value = "备注") + private String remarks; + + private Integer state;*/ +} diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/listener/DeviceInfoImportListener.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/listener/DeviceInfoImportListener.java index 7dbb956..eced721 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/listener/DeviceInfoImportListener.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/listener/DeviceInfoImportListener.java @@ -29,6 +29,7 @@ import cc.iotkit.common.exception.BizException; import cc.iotkit.common.satoken.utils.LoginHelper; import cc.iotkit.common.utils.SpringUtils; import cc.iotkit.common.utils.StringUtils; +import cc.iotkit.manager.dto.bo.device.DeviceInfoAddBo; import cc.iotkit.manager.dto.bo.device.DeviceInfoBo; import cc.iotkit.manager.dto.bo.devicegroup.DeviceAddGroupBo; import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInfoImportVo; @@ -104,7 +105,7 @@ public class DeviceInfoImportListener extends AnalysisEventListener alerts = alertRecordData.selectAlertConfigPage(AlertRecordBo.builder().details(content).build()); + // if(alerts.isEmpty()) { + alertRecordData.save(AlertRecord.builder() + .level(config.getLevel()) + .name(config.getName()) + .tenantId(tenandId) + .uid(uid) + .deptAreaId(deptAreaId) + .readFlg(false) + .alertTime(System.currentTimeMillis()) + .details(content) + .build()); + // } } } diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/DeviceCtrlService.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/DeviceCtrlService.java index 4e6e9c2..753e5b9 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/DeviceCtrlService.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/DeviceCtrlService.java @@ -134,6 +134,9 @@ public class DeviceCtrlService { DeviceInfo device = getAndCheckDevice(deviceId, checkOwner); DeviceConfig config = deviceConfigData.findByDeviceId(deviceId); + if (config == null || ObjectUtil.isEmpty(config)) { + fail("设备未配置"); + } Map data = JsonUtils.parseObject(config.getConfig(), Map.class); return send(deviceId, device.getProductKey(), device.getDeviceName(), data, diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/DeviceStateCheckTask.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/DeviceStateCheckTask.java index 07421f3..24fa99e 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/DeviceStateCheckTask.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/DeviceStateCheckTask.java @@ -65,7 +65,7 @@ public class DeviceStateCheckTask { Paging all; while (true) { //取出数据库中所有在线设备 - all = deviceInfoData.findByConditions("","","","","",true,"",pn,1000,null); + all = deviceInfoData.findByConditions("","","","","",true,"",pn,1000,null,null,null); //判断属性更新时间是否大于产品定义保活时长 for (DeviceInfo device : all.getRows()) { if(ObjectUtil.isNull(device)){ diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/IDeviceInstallInfoService.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/IDeviceInstallInfoService.java index f9f3888..f65812d 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/IDeviceInstallInfoService.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/IDeviceInstallInfoService.java @@ -27,6 +27,7 @@ import cc.iotkit.common.api.PageRequest; import cc.iotkit.common.api.Paging; import cc.iotkit.manager.dto.bo.device.DeviceDetectorQueryBo; import cc.iotkit.manager.dto.bo.device.DeviceInstallInfoQueryBo; +import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInstallInfoVo; import cc.iotkit.model.device.DeviceDetectorInfo; import cc.iotkit.model.device.DeviceInstallInfo; @@ -40,5 +41,5 @@ import java.util.List; */ public interface IDeviceInstallInfoService { Paging getPage(PageRequest pageRequest); - // List getList(PageRequest pageRequest); + List getList(PageRequest pageRequest); } diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/IDeviceManagerService.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/IDeviceManagerService.java index a6a7589..12b0393 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/IDeviceManagerService.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/IDeviceManagerService.java @@ -26,10 +26,7 @@ package cc.iotkit.manager.service; import cc.iotkit.common.api.PageRequest; import cc.iotkit.common.api.Paging; import cc.iotkit.common.thing.ThingModelMessage; -import cc.iotkit.manager.dto.bo.device.DeviceInfoBo; -import cc.iotkit.manager.dto.bo.device.DeviceLogQueryBo; -import cc.iotkit.manager.dto.bo.device.DeviceQueryBo; -import cc.iotkit.manager.dto.bo.device.DeviceTagAddBo; +import cc.iotkit.manager.dto.bo.device.*; import cc.iotkit.manager.dto.bo.devicegroup.DeviceAddGroupBo; import cc.iotkit.manager.dto.bo.devicegroup.DeviceGroupBo; import cc.iotkit.manager.dto.vo.deviceconfig.DeviceConfigVo; @@ -56,7 +53,10 @@ public interface IDeviceManagerService { Paging getDevices1(PageRequest pageRequest); public List findByConditionsList(String productKey,boolean flag); List getDevicess(DeviceQueryBo pageRequest); - boolean addDevice(DeviceInfoBo data); + + List getDevicessExcel(PageRequest pageRequest); + + boolean addDevice(DeviceInfoAddBo data); List selectChildrenPageList(String deviceId); diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceInstallInfoServiceImpl.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceInstallInfoServiceImpl.java index 956d3b6..79d5c95 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceInstallInfoServiceImpl.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceInstallInfoServiceImpl.java @@ -10,13 +10,16 @@ import cc.iotkit.data.dao.DeviceIDetectornfoRepository; import cc.iotkit.data.dao.DeviceInstallInfoRepository; import cc.iotkit.data.manager.IDeviceDetectorInfoData; import cc.iotkit.data.manager.IDeviceInstallInfoData; +import cc.iotkit.data.manager.IUserInfoData; import cc.iotkit.data.model.TbDeviceDetectorInfo; import cc.iotkit.data.model.TbDeviceInstallInfo; import cc.iotkit.data.util.PredicateBuilder; import cc.iotkit.manager.dto.bo.device.DeviceDetectorQueryBo; import cc.iotkit.manager.dto.bo.device.DeviceInstallInfoQueryBo; +import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInstallInfoVo; import cc.iotkit.manager.service.IDeviceDetectorInfoService; import cc.iotkit.manager.service.IDeviceInstallInfoService; +import cc.iotkit.model.UserInfo; import cc.iotkit.model.device.DeviceDetectorInfo; import cc.iotkit.model.device.DeviceInstallInfo; import cn.hutool.core.util.ObjectUtil; @@ -54,6 +57,8 @@ public class DeviceInstallInfoServiceImpl implements IDeviceInstallInfoService { @Autowired private IDeviceInstallInfoData iDeviceInstallInfoData; @Autowired + private IUserInfoData iUserInfoData; + @Autowired private DeviceInstallInfoRepository deviceInstallInfoRepository; private final JPAQueryFactory jpaQueryFactory; @@ -84,6 +89,15 @@ public class DeviceInstallInfoServiceImpl implements IDeviceInstallInfoService { } } + if(ObjectUtil.isNotNull(pageReqVO.getData().getBindUserIpone())){ + List userInfoList = iUserInfoData.findByUserNameLike(pageReqVO.getData().getBindUserIpone()); + String[] uidArray = userInfoList.stream() + .map(UserInfo::getUid) + .toArray(String[]::new); + if(ObjectUtil.isNotEmpty(uidArray)) { + query.where(tbDeviceInstallInfo.uid.in(uidArray)); + } + } if(ObjectUtil.isNotNull(pageReqVO.getData().getDeviceName())) { query.where(tbDeviceInstallInfo.deviceName.like("%" + pageReqVO.getData().getDeviceName() +"%")); } @@ -125,6 +139,12 @@ public class DeviceInstallInfoServiceImpl implements IDeviceInstallInfoService { for (TbDeviceInstallInfo tbDeviceInfo : tbDeviceInfos) { DeviceInstallInfo deviceInfo = MapstructUtils.convert(tbDeviceInfo, DeviceInstallInfo.class); //fillDeviceInfo(tbDeviceInfo.getDeviceId(), tbDeviceInfo, deviceInfo); + if(ObjectUtil.isNotEmpty(tbDeviceInfo.getUid())) { + UserInfo userInfo = iUserInfoData.findByUid(tbDeviceInfo.getUid()); + if(ObjectUtil.isNotEmpty(userInfo)) { + deviceInfo.setBindUserIpone(userInfo.getUserName()); + } + } deviceInfos.add(deviceInfo); } return new Paging<>(total, deviceInfos); @@ -135,7 +155,89 @@ public class DeviceInstallInfoServiceImpl implements IDeviceInstallInfoService { } // 构建动态查询条件(含排序) + @Override + public List getList(PageRequest pageReqVO) { + //return idIccidRecordData.findAll(pageReqVO.to(DIccidRecordDO.class)).to(DIccidRecordRespVO.class); + // 构建分页时指定排序规则 + /* Pageable pageable = PageRequest.of( + pageReqVO..getPage(), + pageReqVO.getSize(), + Sort.by(Sort.Direction.DESC, "createTime") // 按创建时间降序 + );*/ + JPAQuery query = jpaQueryFactory.selectFrom(tbDeviceInstallInfo); + + if (ObjectUtil.isNotNull(pageReqVO.getData().getStartTime())&& ObjectUtil.isNotNull(pageReqVO.getData().getEndTime())) { + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date startDateTime = sdf.parse(pageReqVO.getData().getStartTime()); + Date dateTime = sdf.parse(pageReqVO.getData().getEndTime()); + // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + // LocalDateTime startDateTime = LocalDateTime.parse(dictData.getStartTime() , formatter); + // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + // LocalDateTime dateTime = LocalDateTime.parse(dictData.getEndTime(), formatter); + query.where(tbDeviceInstallInfo.proposerTime.between(startDateTime, dateTime)); + } catch (Exception e) { + + } + } + if(ObjectUtil.isNotNull(pageReqVO.getData().getDeviceName())) { + query.where(tbDeviceInstallInfo.deviceName.like("%" + pageReqVO.getData().getDeviceName() +"%")); + } + if(ObjectUtil.isNotNull(pageReqVO.getData().getUid())) { + query.where(tbDeviceInstallInfo.uid.eq(pageReqVO.getData().getUid())); + } + if(ObjectUtil.isNotNull(pageReqVO.getData().getCorporateName())) { + query.where(tbDeviceInstallInfo.corporateName.like("%" + pageReqVO.getData().getCorporateName() +"%")); + } + if(ObjectUtil.isNotNull(pageReqVO.getData().getProposer())) { + query.where(tbDeviceInstallInfo.proposer.like("%" + pageReqVO.getData().getProposer() +"%")); + } + if(ObjectUtil.isNotNull(pageReqVO.getData().getProposerTeam())) { + query.where(tbDeviceInstallInfo.proposerTeam.like("%" + pageReqVO.getData().getProposerTeam() +"%")); + } + if(ObjectUtil.isNotNull(pageReqVO.getData().getCommunityName())) { + query.where(tbDeviceInstallInfo.communityName.like("%" + pageReqVO.getData().getCommunityName() +"%")); + } + if(ObjectUtil.isNotNull(pageReqVO.getData().getUserName())) { + query.where(tbDeviceInstallInfo.userName.like("%" + pageReqVO.getData().getUserName() +"%")); + } + if(ObjectUtil.isNotNull(pageReqVO.getData().getUserIpone())) { + query.where(tbDeviceInstallInfo.userIpone.like("%" + pageReqVO.getData().getUserIpone() +"%")); + } + if(LoginHelper.isSuperAdmin() && TenantHelper.getTenantId() != 0){ + query.where(tbDeviceInstallInfo.tenantId.eq(TenantHelper.getTenantId())); + } + if(!LoginHelper.isSuperAdmin() && ObjectUtil.isNotNull(pageReqVO.getData().getTenantId())){ + query.where(tbDeviceInstallInfo.tenantId.eq(pageReqVO.getData().getTenantId())); + } + query.orderBy(tbDeviceInstallInfo.createTime.desc()); + // Integer page = ObjectUtil.isNotNull(pageReqVO.getPageNum()) ?pageReqVO.getPageNum():1; + //Integer size = ObjectUtil.isNotNull(pageReqVO.getPageSize()) ?pageReqVO.getPageSize():10; + //query.offset((page - 1) * size).limit(size); + List tbDeviceInfos = query.fetch(); + List deviceInfos = new ArrayList<>(tbDeviceInfos.size()); + // long total = query.fetchCount(); + int i = 1; + for (TbDeviceInstallInfo tbDeviceInfo : tbDeviceInfos) { + DeviceInstallInfo deviceInfo = MapstructUtils.convert(tbDeviceInfo, DeviceInstallInfo.class); + DeviceInstallInfoVo deviceInstallInfoVo = MapstructUtils.convert(deviceInfo, DeviceInstallInfoVo.class); + deviceInstallInfoVo.setXuhao(i); + deviceInstallInfoVo.setSite(tbDeviceInfo.getCommunityName() + tbDeviceInfo.getBuildingUnit() + tbDeviceInfo.getRoomNo()); + deviceInstallInfoVo.setManufacturer("天津费加罗"); + deviceInstallInfoVo.setPosition("成功"); + + //fillDeviceInfo(tbDeviceInfo.getDeviceId(), tbDeviceInfo, deviceInfo); + + deviceInfos.add(deviceInstallInfoVo); + i++; + } + return deviceInfos; + /* return PageBuilder.toPaging(deviceIDetectornfoRepository.findAll( + buildQueryCondition(pageReqVO.getData()), + PageBuilder.toPageable(pageReqVO) + )).to(DeviceDetectorInfo.class);*/ + } /* @Override public List getList(PageRequest pageReqVO) { //return idIccidRecordData.findAll(pageReqVO.to(DIccidRecordDO.class)).to(DIccidRecordRespVO.class); diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceManagerServiceImpl.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceManagerServiceImpl.java index 7e130b2..1d94517 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceManagerServiceImpl.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceManagerServiceImpl.java @@ -40,10 +40,7 @@ import cc.iotkit.data.dao.DeviceInfoRepository; import cc.iotkit.data.manager.*; import cc.iotkit.data.model.TbDeviceInfo; import cc.iotkit.data.system.ISysDeptData; -import cc.iotkit.manager.dto.bo.device.DeviceInfoBo; -import cc.iotkit.manager.dto.bo.device.DeviceLogQueryBo; -import cc.iotkit.manager.dto.bo.device.DeviceQueryBo; -import cc.iotkit.manager.dto.bo.device.DeviceTagAddBo; +import cc.iotkit.manager.dto.bo.device.*; import cc.iotkit.manager.dto.bo.devicegroup.DeviceAddGroupBo; import cc.iotkit.manager.dto.bo.devicegroup.DeviceGroupBo; import cc.iotkit.manager.dto.vo.deviceconfig.DeviceConfigVo; @@ -79,13 +76,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.context.request.async.DeferredResult; import org.springframework.web.multipart.MultipartFile; import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; import static cc.iotkit.common.web.core.BaseController.fail; @@ -151,7 +147,7 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { Boolean online = query.getOnline(); Long areaDepeId = query.getDeptAreaId(); Paging result = MapstructUtils.convert(deviceInfoData.findByConditions(name, uid, subUid, pk, group, - online, keyword, pageRequest.getPageNum(), pageRequest.getPageSize(), areaDepeId), DeviceInfoVo.class); + online, keyword, pageRequest.getPageNum(), pageRequest.getPageSize(), areaDepeId,query.getStartTime(), query.getEndTime()), DeviceInfoVo.class); for (DeviceInfoVo row : result.getRows()) { row.setProduct(productData.findByProductKey(row.getProductKey())); } @@ -171,7 +167,7 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { Boolean online = query.getOnline(); Long areaDepeId = query.getDeptAreaId(); Paging result = MapstructUtils.convert(deviceInfoData.findByConditions1(name, uid, subUid, pk, group, - online, keyword, pageRequest.getPageNum(), pageRequest.getPageSize(), areaDepeId), DeviceInfoVo.class); + online, keyword, pageRequest.getPageNum(), pageRequest.getPageSize(), areaDepeId,query.getStartTime(), query.getEndTime()), DeviceInfoVo.class); for (DeviceInfoVo row : result.getRows()) { row.setProduct(productData.findByProductKey(row.getProductKey())); } @@ -189,6 +185,30 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { return selectedDevices; } + public List getDevicessExcel(PageRequest pageRequest) { + /* DeviceInfo deviceInfo = pageRequest.to(DeviceInfo.class); + deviceInfo.setState(null); + List selectedDevices = MapstructUtils.convert(deviceInfoData.findAllByCondition(deviceInfo), DeviceInfoVo.class); +*/ + DeviceQueryBo query = pageRequest.getData(); + + String uid = query.getUid(); + String subUid = ""; + String name = query.getName(); + String pk = query.getProductKey(); + //关键字查询 + String keyword = query.getKeyword(); + String group = query.getGroup(); + Boolean online = query.getOnline(); + Long areaDepeId = query.getDeptAreaId(); + //pageRequest.setPageSize(99999); + Paging result = MapstructUtils.convert(deviceInfoData.findByConditionsExcel(name, uid, subUid, pk, group, + online, keyword, pageRequest.getPageNum(), pageRequest.getPageSize(), areaDepeId,query.getStartTime(), query.getEndTime()), DeviceInfoVo.class); + /* for (DeviceInfoVo row : result.getRows()) { + row.setProduct(productData.findByProductKey(row.getProductKey())); + }*/ + return result.getRows(); + } @Override public List findByConditionsList(String productKey, boolean flag) { return MapstructUtils.convert(iDeviceInfoData.findByConditionsList(productKey, flag), DeviceInfoVo.class); @@ -196,7 +216,7 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { } @Override - public boolean addDevice(DeviceInfoBo deviceInfo) { + public boolean addDevice(DeviceInfoAddBo deviceInfo) { String productKey = deviceInfo.getProductKey(); String deviceName = deviceInfo.getDeviceName(); @@ -227,11 +247,11 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { /* if(ObjectUtil.isNotNull(sysDept) && ObjectUtil.isNull(deviceInfo.getTenantId())) { device.setTenantId(sysDept.getTenantId()); }*/ - if (ObjectUtil.isNotNull(sysDept)) { + if (ObjectUtil.isNotNull(sysDept) && ObjectUtil.isNull(deviceInfo.getTenantId()) ) { device.setTenantId(sysDept.getTenantId()); } if (LoginHelper.isSuperAdmin() && TenantHelper.getTenantId() == 0) { - if (ObjectUtil.isNotNull(sysDept)) { + if (ObjectUtil.isNotNull(sysDept) && ObjectUtil.isNull(deviceInfo.getTenantId())) { device.setTenantId(sysDept.getTenantId()); } } @@ -550,10 +570,12 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { @Override public boolean saveDevice(DeviceInfoBo data) { DeviceInfo di = data.to(DeviceInfo.class); - if (ObjectUtil.isNotNull(data.getGroupId()) && !data.getGroupId().equals("{}")) { + if (ObjectUtil.isEmpty(di.getGroup()) && ObjectUtil.isNotNull(data.getGroupId()) && !data.getGroupId().equals("{}")) { di.getGroup().put(data.getGroupId(), new DeviceInfo.Group( data.getGroupId(), data.getDeviceId())); - } + }/*else if(process(data)){ + di.setGroup(convert(data.getGroup())); + }*/ di.setLocate(new DeviceInfo.Locate(data.getLongitude(), data.getLatitude())); if (StringUtils.isBlank(data.getSecret())) { data.setSecret(RandomStringUtils.random(16)); @@ -581,7 +603,7 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { if (deviceRepetition != null && !deviceRepetition.getDeviceId().equals(di.getDeviceId())) { throw new BizException(ErrCode.MODEL_DEVICE_ALREADY); } - if(ObjectUtil.isNotNull(deviceRepetition.getState())) { + if(ObjectUtil.isNotEmpty(deviceRepetition) && ObjectUtil.isNotNull(deviceRepetition.getState())) { di.setState(deviceRepetition.getState()); } /* if(ObjectUtil.isNotNull(data.getGroup())){ @@ -591,6 +613,36 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { TenantHelper.enableIgnore(); return deviceInfoData.save(di) != null; } + public static Map convert(Object obj) { + return obj instanceof Map ? ((Map) obj).entrySet().stream() + .filter(e -> e.getKey() instanceof String) + .filter(e -> e.getValue() instanceof DeviceInfo.Group) + .collect(Collectors.toMap( + e -> (String)e.getKey(), + e -> (DeviceInfo.Group)e.getValue() + )) : Collections.emptyMap(); + } + + public boolean process(DeviceInfoBo dto) { + Object input = dto.getGroup(); + if(input == null){ + return false; + } + if (input instanceof Map) { + // 处理Map逻辑 + return true; + }else if(isMapFormat(input.toString())){ + // 处理Map逻辑 + return true; + } else { + // 处理其他类型或默认值 + return false; + } + } + public boolean isMapFormat(String input) { + return input.matches("^\\{(\\w+:\\w+,?)*\\}$"); + } + @Override public boolean saveDevice1(DeviceInfoBo data) { diff --git a/iot-module/iot-plugin/iot-plugin-main/pom.xml b/iot-module/iot-plugin/iot-plugin-main/pom.xml index 6f0e4df..be9d034 100644 --- a/iot-module/iot-plugin/iot-plugin-main/pom.xml +++ b/iot-module/iot-plugin/iot-plugin-main/pom.xml @@ -17,7 +17,10 @@ cc.iotkit iot-plugin-core - + + cc.iotkit + iot-rule-engine + cc.iotkit iot-common-redis diff --git a/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java b/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java index e91472d..6f58450 100644 --- a/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java +++ b/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java @@ -35,6 +35,9 @@ import cc.iotkit.common.utils.JsonUtils; import cc.iotkit.common.utils.StringUtils; import cc.iotkit.common.utils.UniqueIdUtil; import cc.iotkit.data.manager.*; +import cc.iotkit.model.alert.AlertConfig; +import cc.iotkit.model.alert.AlertRecord; +import cc.iotkit.model.alert.AlertRecordBo; import cc.iotkit.model.device.DeviceDetectorInfo; import cc.iotkit.model.device.DeviceInfo; import cc.iotkit.model.iccid.DIccidRecordDO; @@ -46,6 +49,9 @@ import cc.iotkit.plugin.core.thing.actions.down.DeviceConfig; import cc.iotkit.plugin.core.thing.actions.up.*; import cc.iotkit.plugin.core.thing.model.ThingDevice; import cc.iotkit.plugin.core.thing.model.ThingProduct; +import cc.iotkit.ruleengine.rule.Rule; +import cc.iotkit.ruleengine.rule.RuleExecutor; +import cc.iotkit.ruleengine.rule.RuleMessageHandler; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; import lombok.extern.slf4j.Slf4j; @@ -60,9 +66,12 @@ import javax.annotation.security.PermitAll; import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static cc.iotkit.common.redis.utils.RedisUtils.setCacheMapValue; +import static cc.iotkit.common.redis.utils.RedisUtils.*; import static com.ibm.icu.impl.Assert.fail; /** @@ -92,29 +101,46 @@ public class ThingServiceImpl implements IThingService { private IDIccidRecordData idIccidRecordData; @Autowired private IDeviceDetectorInfoData iDeviceDetectorInfoData; + @Autowired + private IAlertRecordData idAlertRecordData; + @Autowired + private IAlertConfigData iAlertConfigData; + @Autowired + private RuleExecutor ruleExecutor; + @Autowired + private RuleMessageHandler ruleMessageHandler; @Override public ActionResult post(String pluginId, IDeviceAction action) { + try { log.info("receive plugin:{}, action:{}", pluginId, action); String deviceName = action.getDeviceName(); + if (!"NONE".equals(pluginId)) { //添加设备路由 deviceRouter.putRouter(deviceName, new PluginRouter(IPluginMain.MAIN_ID, pluginId)); } long lastTime = System.currentTimeMillis(); DeviceInfo device = getDeviceInfo(deviceName); - // DeviceStateChange deviceInfo = ((DeviceStateChange) action); - /* if(ObjectUtil.isNotNull(deviceInfo.getState())){ - if (deviceInfo.getState().equals(DeviceState.ONLINE)) { - device.getState().setOnline(true); - device.getState().setOnlineTime(System.currentTimeMillis()); - } else { - device.getState().setOnline(false); - device.getState().setOfflineTime(System.currentTimeMillis()); + if (ObjectUtil.isNotEmpty(action)) { + try { + DeviceStateChange deviceInfo = ((DeviceStateChange) action); + if (ObjectUtil.isNotEmpty(deviceInfo) && ObjectUtil.isNotNull(deviceInfo.getState())) { + // if (deviceInfo.getState().equals(DeviceState.ONLINE)) { + device.getState().setOnline(true); + device.getState().setOnlineTime(System.currentTimeMillis()); + /* } else { + device.getState().setOnline(false); + device.getState().setOfflineTime(System.currentTimeMillis()); + }*/ + } + } catch (Exception e) { + } - }*/ + + } if (Objects.isNull(device)) { log.warn("device:{} is not found.", deviceName); } else { @@ -127,7 +153,8 @@ public class ThingServiceImpl implements IThingService { System.out.println("type+++++++++++++++++++++" + type); System.out.println("action+++++++++++++++++++++" + action); System.out.println("device+++++++++++++++++++++" + device); - switch (type) { + + switch (type) { case REGISTER: //设备注册 String deviceId = registerDevice(device, (DeviceRegister) action, null); @@ -178,6 +205,10 @@ public class ThingServiceImpl implements IThingService { case PROPERTY_REPORT: //属性上报 PropertyReport propertyReport = (PropertyReport) action; + //根据事件变更设备状态,如果是浓度需要额外添加到指定表 + Map map = propertyReport.getParams(); + deviceStatusUpdate(device, map); + publishMsg( device, action, ThingModelMessage.builder() @@ -185,12 +216,11 @@ public class ThingServiceImpl implements IThingService { .identifier(ThingModelMessage.ID_PROPERTY_REPORT) .data(propertyReport.getParams()) .time(propertyReport.getTime()) + .deviceStatus(device.getDeviceStatus()) .occurred(propertyReport.getTime()) .build() ); - //根据事件变更设备状态,如果是浓度需要额外添加到指定表 - Map map = propertyReport.getParams(); - deviceStatusUpdate(device, map); + break; @@ -249,37 +279,44 @@ public class ThingServiceImpl implements IThingService { if (!status.equals(1) && !status.equals(2)) { device.setDeviceStatus(0); } + List deviceInfoArrayList = new ArrayList<>(); + boolean success = false; //设备在线发生了故障或者报警 - if (state.isOnline()) { + if (isMapValid(map, "eventTypeValue")) { if (map.get("eventTypeValue").toString().contains("寿命到期")) { device.setDeviceStatus(4); } - if (map.get("eventTypeValue").toString().contains("故障") && !map.get("eventTypeValue").toString().contains("故障恢复")) { + if (!status.equals(2) && map.get("eventTypeValue").toString().contains("故障") && !map.get("eventTypeValue").toString().contains("故障恢复")) { device.setDeviceStatus(1); - } else if (map.get("eventTypeValue").toString().contains("故障恢复")) { + success = true; + } else if ( !status.equals(2) && map.get("eventTypeValue").toString().contains("故障恢复")) { device.setDeviceStatus(0); } + // if(device.getDeviceName().equals("864029082017629") || device.getDeviceName().equals("864029082017017")){ if (map.get("eventTypeValue").toString().contains("警") && !map.get("eventTypeValue").toString().contains("正常") && !map.get("eventTypeValue").toString().contains("报警恢复")) { //如果该区域有控制箱,设备发生告警发送控制箱控制 try { - deviceLinkageControl(device); - }catch (Exception e){ - log.error("设备控制异常",e); + deviceInfoArrayList = deviceLinkageControl(device); + } catch (Exception e) { + log.error("设备控制异常", e); } - + success = true; device.setDeviceStatus(2); + } } else if (map.get("eventTypeValue").toString().contains("报警恢复")) { device.setDeviceStatus(0); + deviceLinkageControl1(device); } if (map.get("eventTypeValue").toString().contains("自检完成") || map.get("eventTypeValue").toString().contains("预热完成") || map.get("eventTypeValue").toString().contains("控制器复位") || map.get("eventTypeValue").toString().contains("控制器开机")) { device.setDeviceStatus(0); + deviceLinkageControl1(device); } - } - } else { + // } + if (!state.isOnline()) { if (!status.equals(1) && !status.equals(2)) { device.setDeviceStatus(3); } @@ -288,74 +325,221 @@ public class ThingServiceImpl implements IThingService { if (ObjectUtil.isNotNull(device.getDeviceStatus()) && !status.equals(device.getDeviceStatus())) { deviceInfoData.save(device); } + if (success) { + ThingModelMessage thingModelMessage = ThingModelMessage.builder() + .type(ThingModelMessage.TYPE_PROPERTY) + .identifier(ThingModelMessage.ID_PROPERTY_REPORT) + .data(map) + .deviceId(device.getDeviceId()) + .deviceName(device.getDeviceName()) + .productKey(device.getProductKey()) + .time(System.currentTimeMillis()) + .deviceStatus(device.getDeviceStatus()) + .occurred(System.currentTimeMillis()) + .build(); + List config = iAlertConfigData.findByDeviceName(device.getDeviceName()); + /* if(config.isEmpty()){ + List rules = ruleMessageHandler.processMessage1(thingModelMessage); + for (Rule rule : rules) { + config = iAlertConfigData.findByRuleInfoId(rule.getId()); + } + }*/ + // List alerts = idAlertRecordData.selectAlertConfigPage(AlertRecordBo.builder().details(device.getDeviceName()).build()); + System.out.println("设备告警 您的设备【" + device.getDeviceName() + "】触发事件 事件类型为:【" + map.get("eventTypeValue").toString() + "】。"); + if (ObjectUtil.isEmpty(config)) { + try { + ExecutorService executor = Executors.newSingleThreadExecutor(); + List deviceInfoArrayList1 = deviceInfoArrayList; + executor.execute(() -> { + List rules = ruleMessageHandler.processMessage1(thingModelMessage); + for (Rule rule : rules) { + List config1 = iAlertConfigData.findByRuleInfoId(rule.getId()); + for (int i = 0; i < config1.size(); i++) { + idAlertRecordData.save(AlertRecord.builder() + .level(config1.get(i).getLevel()) + .name(config1.get(i).getName()) + .tenantId(device.getTenantId()) + .uid(device.getUid()) + .deptAreaId(device.getDeptAreaId()) + .readFlg(false) + .alertTime(System.currentTimeMillis()) + .details("您的设备【" + device.getDeviceName() + "】触发事件 事件类型为:【" + map.get("eventTypeValue").toString() + "】。") + .build()); + if (ObjectUtil.isNotEmpty(deviceInfoArrayList1)) { + for (int j = 0; j < deviceInfoArrayList1.size(); j++) { + String deviceName = deviceInfoArrayList1.get(j).getNodeStatus().equals("1")?device.getDeviceName(): deviceInfoArrayList1.get(j).getNodeDevice(); + idAlertRecordData.save(AlertRecord.builder() + .level(config1.get(i).getLevel()) + .name(config1.get(i).getName()) + .tenantId(deviceInfoArrayList1.get(j).getTenantId()) + .uid(deviceInfoArrayList1.get(j).getUid()) + .deptAreaId(deviceInfoArrayList1.get(j).getDeptAreaId()) + .readFlg(false) + .alertTime(System.currentTimeMillis()) + .details("您的设备【" + deviceInfoArrayList1.get(j).getDeviceName() + "】,节点" + deviceInfoArrayList1.get(j).getNode() + "触发事件,事件类型:【联动箱输出】," + "告警设备:" + deviceName) + .build()); + } + } + ruleExecutor.execute1(thingModelMessage, config1); + } + } + // RuleExecutor ruleExecutor = new RuleExecutor(); + }); + executor.shutdown(); // 触发线程池关闭 + } catch (Exception e) { + } + } else { + ExecutorService executor = Executors.newSingleThreadExecutor(); + List deviceInfoArrayList1 = deviceInfoArrayList; + executor.execute(() -> { + for (int i = 0; i < config.size(); i++) { + idAlertRecordData.save(AlertRecord.builder() + .level(config.get(i).getLevel()) + .name(config.get(i).getName()) + .tenantId(device.getTenantId()) + .uid(device.getUid()) + .deptAreaId(device.getDeptAreaId()) + .readFlg(false) + .alertTime(System.currentTimeMillis()) + .details("您的设备【" + device.getDeviceName() + "】触发事件 事件类型为:【" + map.get("eventTypeValue").toString() + "】。") + .build()); + if (ObjectUtil.isNotEmpty(deviceInfoArrayList1)) { + for (int j = 0; j < deviceInfoArrayList1.size(); j++) { + String deviceName = deviceInfoArrayList1.get(j).getNodeStatus().equals("1")?device.getDeviceName(): deviceInfoArrayList1.get(j).getNodeDevice(); + idAlertRecordData.save(AlertRecord.builder() + .level(config.get(i).getLevel()) + .name(config.get(i).getName()) + .tenantId(deviceInfoArrayList1.get(j).getTenantId()) + .uid(deviceInfoArrayList1.get(j).getUid()) + .deptAreaId(deviceInfoArrayList1.get(j).getDeptAreaId()) + .readFlg(false) + .alertTime(System.currentTimeMillis()) + .details("您的设备【" + deviceInfoArrayList1.get(j).getDeviceName() + "】,节点" + deviceInfoArrayList1.get(j).getNode() + "触发事件,事件类型:【联动箱输出】," + "告警设备:" + deviceName) + .build()); + } + } + ruleExecutor.execute1(thingModelMessage, config); + } + // RuleExecutor ruleExecutor = new RuleExecutor(); + }); + } + } //存入浓度变化 extractDetectorData(device, map); } + /** * 设备告警,下发设备联动控制 - * */ - private void deviceLinkageControl(DeviceInfo device) { + */ + private List deviceLinkageControl(DeviceInfo device) { List deviceInfo1 = new ArrayList<>(); - deviceInfo1 = getDeviceInfo(device.getDeptAreaId(),"MQFejp7cyDMH3enG"); - if(deviceInfo1 != null && !deviceInfo1.isEmpty()) { + deviceInfo1 = getDeviceInfo(device.getDeptAreaId(), "MQFejp7cyDMH3enG"); + Boolean flag = false; + String nodeStatus = null; + List deviceInfo55 = new ArrayList<>(); + if (deviceInfo1 != null && !deviceInfo1.isEmpty()) { for (DeviceInfo deviceInfo2 : deviceInfo1) { - if(ObjectUtil.isNotNull(deviceInfo2.getNodeOne()) && ObjectUtil.isNotNull(deviceInfo2.getNodeOneStatus()) && ObjectUtil.isNotNull(deviceInfo2.getNodeOneDevice())) { - if (deviceInfo2.getNodeOneStatus().equals("1")) { - //选中的任意一个设备报警就发送联动控制指令 - deviceLinkageControlSend(deviceInfo2, deviceInfo2.getNodeOne()); - }else{ - //满足所有的设备告警才触发联动控制 - String [] nodeOneDevice = deviceInfo2.getNodeOneDevice().split(","); - handleDeviceAlert(deviceInfo2,deviceInfo2.getNodeOne(),nodeOneDevice); - } + if (ObjectUtil.isNotNull(deviceInfo2.getNodeOne()) && ObjectUtil.isNotNull(deviceInfo2.getNodeOneStatus()) && ObjectUtil.isNotNull(deviceInfo2.getNodeOneDevice())) { + flag = false; + if (deviceInfo2.getNodeOneStatus().equals("1")) { + //选中的任意一个设备报警就发送联动控制指令 + flag = deviceLinkageControlSend(deviceInfo2, deviceInfo2.getNodeOne()); + } else { + //满足所有的设备告警才触发联动控制 + String[] nodeOneDevice = deviceInfo2.getNodeOneDevice().split(","); + // + + flag = handleDeviceAlert(device,deviceInfo2, deviceInfo2.getNodeOne(), nodeOneDevice); + } + nodeStatus = "1"; + if (flag) { + deviceInfo2.setNode(nodeStatus); + deviceInfo2.setNodeStatus(deviceInfo2.getNodeOneStatus()); + deviceInfo2.setNodeDevice(deviceInfo2.getNodeOneDevice()); + deviceInfo55.add(deviceInfo2); + } + } - if(ObjectUtil.isNotNull(deviceInfo2.getNodeTwo()) && ObjectUtil.isNotNull(deviceInfo2.getNodeTwoStatus()) && ObjectUtil.isNotNull(deviceInfo2.getNodeTwoDevice())) { + if (ObjectUtil.isNotNull(deviceInfo2.getNodeTwo()) && ObjectUtil.isNotNull(deviceInfo2.getNodeTwoStatus()) && ObjectUtil.isNotNull(deviceInfo2.getNodeTwoDevice())) { //deviceLinkageControlSend(deviceInfo2,deviceInfo2.getNodeTwo()); + flag = false; if (deviceInfo2.getNodeTwoStatus().equals("1")) { //选中的任意一个设备报警就发送联动控制指令 - deviceLinkageControlSend(deviceInfo2, deviceInfo2.getNodeTwo()); - }else{ + flag = deviceLinkageControlSend(deviceInfo2, deviceInfo2.getNodeTwo()); + } else { //满足所有的设备告警才触发联动控制 - String [] nodeOneDevice = deviceInfo2.getNodeTwoDevice().split(","); - handleDeviceAlert(deviceInfo2,deviceInfo2.getNodeTwo(),nodeOneDevice); + String[] nodeOneDevice = deviceInfo2.getNodeTwoDevice().split(","); + flag = handleDeviceAlert(device,deviceInfo2, deviceInfo2.getNodeTwo(), nodeOneDevice); + } + nodeStatus = "2"; + if (flag) { + deviceInfo2.setNode(nodeStatus); + deviceInfo2.setNodeStatus(deviceInfo2.getNodeTwoStatus()); + deviceInfo2.setNodeDevice(deviceInfo2.getNodeTwoDevice()); + deviceInfo55.add(deviceInfo2); } } - if(ObjectUtil.isNotNull(deviceInfo2.getNodeThree()) && ObjectUtil.isNotNull(deviceInfo2.getNodeThreeStatus()) && ObjectUtil.isNotNull(deviceInfo2.getNodeThreeDevice())) { - // deviceLinkageControlSend(deviceInfo2,deviceInfo2.getNodeThree()); + if (ObjectUtil.isNotNull(deviceInfo2.getNodeThree()) && ObjectUtil.isNotNull(deviceInfo2.getNodeThreeStatus()) && ObjectUtil.isNotNull(deviceInfo2.getNodeThreeDevice())) { + // deviceLinkageControlSend(deviceInfo2,deviceInfo2.getNodeThree()); + flag = false; if (deviceInfo2.getNodeThreeStatus().equals("1")) { //选中的任意一个设备报警就发送联动控制指令 - deviceLinkageControlSend(deviceInfo2, deviceInfo2.getNodeThree()); - }else{ + flag = deviceLinkageControlSend(deviceInfo2, deviceInfo2.getNodeThree()); + } else { //满足所有的设备告警才触发联动控制 - String [] nodeOneDevice = deviceInfo2.getNodeThreeDevice().split(","); - handleDeviceAlert(deviceInfo2,deviceInfo2.getNodeThree(),nodeOneDevice); + String[] nodeOneDevice = deviceInfo2.getNodeThreeDevice().split(","); + flag = handleDeviceAlert(device,deviceInfo2, deviceInfo2.getNodeThree(), nodeOneDevice); + } + nodeStatus = "3"; + if (flag) { + deviceInfo2.setNode(nodeStatus); + deviceInfo2.setNodeStatus(deviceInfo2.getNodeThreeStatus()); + deviceInfo2.setNodeDevice(deviceInfo2.getNodeThreeDevice()); + deviceInfo55.add(deviceInfo2); } } - if(ObjectUtil.isNotNull(deviceInfo2.getNodeFour()) && ObjectUtil.isNotNull(deviceInfo2.getNodeFourStatus()) && ObjectUtil.isNotNull(deviceInfo2.getNodeFourDevice())) { - // deviceLinkageControlSend(deviceInfo2,deviceInfo2.getNodeFour()); + if (ObjectUtil.isNotNull(deviceInfo2.getNodeFour()) && ObjectUtil.isNotNull(deviceInfo2.getNodeFourStatus()) && ObjectUtil.isNotNull(deviceInfo2.getNodeFourDevice())) { + // deviceLinkageControlSend(deviceInfo2,deviceInfo2.getNodeFour()); + flag = false; if (deviceInfo2.getNodeFourStatus().equals("1")) { //选中的任意一个设备报警就发送联动控制指令 - deviceLinkageControlSend(deviceInfo2, deviceInfo2.getNodeFour()); - }else{ + flag = deviceLinkageControlSend(deviceInfo2, deviceInfo2.getNodeFour()); + } else { //满足所有的设备告警才触发联动控制 - String [] nodeOneDevice = deviceInfo2.getNodeFourDevice().split(","); - handleDeviceAlert(deviceInfo2,deviceInfo2.getNodeFour(),nodeOneDevice); + String[] nodeOneDevice = deviceInfo2.getNodeFourDevice().split(","); + flag = handleDeviceAlert(device,deviceInfo2, deviceInfo2.getNodeFour(), nodeOneDevice); + } + nodeStatus = "4"; + if (flag) { + deviceInfo2.setNode(nodeStatus); + deviceInfo2.setNodeStatus(deviceInfo2.getNodeFourStatus()); + deviceInfo2.setNodeDevice(deviceInfo2.getNodeFourDevice()); + deviceInfo55.add(deviceInfo2); } } - if(ObjectUtil.isNotNull(deviceInfo2.getNodeFive()) && ObjectUtil.isNotNull(deviceInfo2.getNodeFiveStatus()) && ObjectUtil.isNotNull(deviceInfo2.getNodeFiveDevice())) { - // deviceLinkageControlSend(deviceInfo2,deviceInfo2.getNodeFive()); + if (ObjectUtil.isNotNull(deviceInfo2.getNodeFive()) && ObjectUtil.isNotNull(deviceInfo2.getNodeFiveStatus()) && ObjectUtil.isNotNull(deviceInfo2.getNodeFiveDevice())) { + // deviceLinkageControlSend(deviceInfo2,deviceInfo2.getNodeFive()); + flag = false; if (deviceInfo2.getNodeFiveStatus().equals("1")) { //选中的任意一个设备报警就发送联动控制指令 - deviceLinkageControlSend(deviceInfo2, deviceInfo2.getNodeFive()); - }else{ + flag = deviceLinkageControlSend(deviceInfo2, deviceInfo2.getNodeFive()); + } else { //满足所有的设备告警才触发联动控制 - String [] nodeOneDevice = deviceInfo2.getNodeFiveDevice().split(","); - handleDeviceAlert(deviceInfo2,deviceInfo2.getNodeFive(),nodeOneDevice); + String[] nodeOneDevice = deviceInfo2.getNodeFiveDevice().split(","); + flag = handleDeviceAlert(device,deviceInfo2, deviceInfo2.getNodeFive(), nodeOneDevice); + } + nodeStatus = "5"; + if (flag) { + deviceInfo2.setNode(nodeStatus); + deviceInfo2.setNodeStatus(deviceInfo2.getNodeFiveStatus()); + deviceInfo2.setNodeDevice(deviceInfo2.getNodeFiveDevice()); + deviceInfo55.add(deviceInfo2); } } } } + return deviceInfo55; /* //下发联动控制箱控制输出 send(device.getDeviceId(), device.getProductKey(), device.getDeviceName(), Map.of( @@ -380,24 +564,52 @@ public class ThingServiceImpl implements IThingService { } + private void deviceLinkageControl1(DeviceInfo device) { + try { + List deviceInfo1 = getDeviceInfo(device.getDeptAreaId(), "MQFejp7cyDMH3enG"); + for (DeviceInfo deviceInfo2 : deviceInfo1) { + String ALERT_MAP_KEY1 = "device:alert:map" + ":" + "0001" + ":" + deviceInfo2.getDeviceName(); + String ALERT_MAP_KEY2 = "device:alert:map" + ":" + "0002" + ":" + deviceInfo2.getDeviceName(); + String ALERT_MAP_KEY3 = "device:alert:map" + ":" + "0003" + ":" + deviceInfo2.getDeviceName(); + String ALERT_MAP_KEY4 = "device:alert:map" + ":" + "0004" + ":" + deviceInfo2.getDeviceName(); + String ALERT_MAP_KEY5 = "device:alert:map" + ":" + "0005" + ":" + deviceInfo2.getDeviceName(); + delCacheMapValue(ALERT_MAP_KEY1, device.getDeviceName()); + delCacheMapValue(ALERT_MAP_KEY2, device.getDeviceName()); + delCacheMapValue(ALERT_MAP_KEY3, device.getDeviceName()); + delCacheMapValue(ALERT_MAP_KEY4, device.getDeviceName()); + delCacheMapValue(ALERT_MAP_KEY5, device.getDeviceName()); + } + }catch (Exception e ){ + log.error("设备联动异常删除缓存",e); + } - public void handleDeviceAlert(DeviceInfo deviceInfo,String node,String[] device) { - String ALERT_MAP_KEY = "device:alert:map" +":" +node; - // 记录设备告警状态 - setCacheMapValue(ALERT_MAP_KEY, deviceInfo.getDeviceName(), System.currentTimeMillis()); - // 获取当前告警设备数 - RMap alertMap = RedisUtils.getClient().getMap(ALERT_MAP_KEY); - if (alertMap.size() >= device.length) { - deviceLinkageControlSend(deviceInfo,node); - // triggerCommand(new ArrayList<>(alertMap.keySet())); - alertMap.clear(); - } + } + + public boolean handleDeviceAlert(DeviceInfo deviceInfo1,DeviceInfo deviceInfo, String node, String[] device) { + boolean isAlert = false; + boolean isContained = Arrays.asList(device).contains(deviceInfo1.getDeviceName()); + if(!isContained){ + return isAlert; + } + String ALERT_MAP_KEY = "device:alert:map" + ":" + node + ":" + deviceInfo.getDeviceName(); + // 记录设备告警状态 + setCacheMapValue(ALERT_MAP_KEY, deviceInfo1.getDeviceName(), deviceInfo1.getDeviceName()); + // expire(ALERT_MAP_KEY, 172800); + // 获取当前告警设备数 + RMap alertMap = RedisUtils.getClient().getMap(ALERT_MAP_KEY); + //删除某个key delCacheMapValue(ALERT_MAP_KEY, "862571079391303"); + if (alertMap.size() >= device.length || alertMap.size() >= 2) { + isAlert = deviceLinkageControlSend(deviceInfo, node); + // triggerCommand(new ArrayList<>(alertMap.keySet())); + alertMap.clear(); } + return isAlert; + } - private void deviceLinkageControlSend(DeviceInfo device,String node) { + private boolean deviceLinkageControlSend(DeviceInfo device, String node) { ThingService thingService = ThingService.builder() .mid(UniqueIdUtil.newRequestId()) .productKey(device.getProductKey()) @@ -410,11 +622,14 @@ public class ThingServiceImpl implements IThingService { .build(); //联动控制箱下发指令 deviceService.invoke(thingService); + return true; } + //浓度变化 public void extractDetectorData(DeviceInfo device, Map baseInfo) { for (Map.Entry entry : baseInfo.entrySet()) { if (entry.getKey().startsWith("dataDetectorValue")) { + String suffix = entry.getKey().substring(17); // 去掉前缀"dataDetectorValue" String value = entry.getValue().toString(); // 获取对应节点信息 @@ -433,6 +648,14 @@ public class ThingServiceImpl implements IThingService { } if (ObjectUtil.isNotNull(baseInfo.get(gasTypeKey))) { detectorInfo.setGasTypeKey(baseInfo.get(gasTypeKey).toString()); + + } + if (ObjectUtil.isNotNull(baseInfo.get("eventTypeValue"))) { + if (baseInfo.get("eventTypeValue").toString().contains("控制器复位") || baseInfo.get("eventTypeValue").toString().contains("控制器开机")) { + detectorInfo.setNodeContext("正常"); + } else { + detectorInfo.setNodeContext(baseInfo.get("eventTypeValue").toString()); + } } iDeviceDetectorInfoData.save(detectorInfo); /* @@ -480,20 +703,23 @@ public class ThingServiceImpl implements IThingService { public DeviceInfo getDeviceInfo(String dn) { try { + return deviceInfoData.findByDeviceName(dn); } catch (Throwable e) { log.error("get device error", e); return null; } } - public List getDeviceInfo(Long areaDeptId,String productKey) { + + public List getDeviceInfo(Long areaDeptId, String productKey) { try { - return deviceInfoData.findByDeptAreaIdAndProductKey(areaDeptId,productKey); + return deviceInfoData.findByDeptAreaIdAndProductKey(areaDeptId, productKey); } catch (Throwable e) { log.error("get device error", e); return null; } } + @Override public ThingDevice getDevice(String dn) { DeviceInfo deviceInfo = getDeviceInfo(dn); @@ -594,6 +820,7 @@ public class ThingServiceImpl implements IThingService { } if (device != null) { + device.setDeviceStatus(0); //随便写写 if (params != null && !params.isEmpty()) { if (ObjectUtil.isNotNull(params.get("signalStrength"))) { diff --git a/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/config/CallRateLimiter.java b/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/config/CallRateLimiter.java index 00b4c9a..30dd5ed 100644 --- a/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/config/CallRateLimiter.java +++ b/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/config/CallRateLimiter.java @@ -1,9 +1,15 @@ package cc.iotkit.ruleengine.config; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.springframework.context.annotation.Bean; import redis.clients.jedis.Jedis; import redis.clients.jedis.Pipeline; import redis.clients.jedis.Response; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + public class CallRateLimiter { private static final String REDIS_KEY_PREFIX = "call:limit:"; @@ -29,6 +35,7 @@ public class CallRateLimiter { dayCount.get() <= 20; } + public static void main(String[] args) { System.out.println(CallRateLimiter.checkRateLimit("19118345694"));; } diff --git a/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/handler/RuleDeviceConsumer.java b/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/handler/RuleDeviceConsumer.java index e76b53c..7c5676a 100644 --- a/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/handler/RuleDeviceConsumer.java +++ b/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/handler/RuleDeviceConsumer.java @@ -29,17 +29,23 @@ import cc.iotkit.common.utils.JsonUtils; import cc.iotkit.common.utils.ThreadUtil; import cc.iotkit.mq.ConsumerHandler; import cc.iotkit.mq.MqConsumer; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; @Slf4j public class RuleDeviceConsumer implements ConsumerHandler, ApplicationContextAware { @@ -47,11 +53,31 @@ public class RuleDeviceConsumer implements ConsumerHandler, A private final List handlers = new ArrayList<>(); private ScheduledThreadPoolExecutor messageHandlerPool; + //private ThreadPoolExecutor messageHandlerPool; @SneakyThrows public RuleDeviceConsumer(MqConsumer consumer) { consumer.consume(Constants.THING_MODEL_MESSAGE_TOPIC, this); } + /* @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + Map handlerMap = applicationContext.getBeansOfType(DeviceMessageHandler.class); + + // 动态计算核心线程数 + int corePoolSize = Math.max(4, Runtime.getRuntime().availableProcessors()); + // corePoolSize = corePoolSize > handlerMap.size()?corePoolSize:handlerMap.size(); + int maxPoolSize = corePoolSize * 2; + messageHandlerPool = new ThreadPoolExecutor( + corePoolSize, + maxPoolSize, + 60L, TimeUnit.SECONDS, + new LinkedBlockingQueue<>(10), // 限制队列大小 + new ThreadFactoryBuilder().setNameFormat("msg-handler-%d").build(), + new ThreadPoolExecutor.CallerRunsPolicy() // 饱和策略 + ); + + this.handlers.addAll(handlerMap.values()); + }*/ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map handlerMap = applicationContext.getBeansOfType(DeviceMessageHandler.class); diff --git a/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleExecutor.java b/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleExecutor.java index 463fde0..eadda79 100644 --- a/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleExecutor.java +++ b/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleExecutor.java @@ -100,8 +100,83 @@ public class RuleExecutor { @Resource private WxMaService wxMaService; + public void execute1(ThingModelMessage message,List listAlertConfigs) { + DeviceInfo deviceInfo = iDeviceInfoData.findByDeviceId(message.getDeviceId()); + // 注入 WxMaService 后直接调用 + String appId = wxMaService.getWxMaConfig().getAppid(); + System.out.println("当前小程序AppID: " + appId); + Map alertData = message.dataToMap(); + System.out.println("messagePushalertData+++++++++++++++++++++++++++++" + alertData); + // String alertData = processData(message); + // String deviceName = message.getDeviceName(); + try { + // DeviceInfo deviceInfo = iDeviceInfoData.findByDeviceId(message.getDeviceId()); + if (ObjectUtil.isNotNull(deviceInfo)) { + UserInfo userInfo = new UserInfo(); + if(ObjectUtil.isNotNull(deviceInfo.getUid()) && !deviceInfo.getUid().equals("")){ + userInfo = iUserInfoData.findById(Long.valueOf(deviceInfo.getUid())); + if (ObjectUtil.isNull(userInfo)) { + return; + } + } + // List listAlertConfigs = iAlertConfigData.findByUidAndRuleInfoIdAndDeviceName(deviceInfo.getUid(), ruleLog.getRuleId(), deviceInfo.getDeviceName()); + + for (AlertConfig alertConfig : listAlertConfigs) { + if (ObjectUtil.isNotNull(alertConfig.getMessagePushIpone())) { + String[] messagePushIpone = alertConfig.getMessagePushIpone().split(","); + // System.out.println("messagePushIpone+++++++++++++++++++++++++++++" + messagePushIpone); + // System.out.println("messagePushIpone.length+++++++++++++++++++++++++++++" + messagePushIpone.length); + for (int i = 0; i < messagePushIpone.length; i++) { + if (isValid(messagePushIpone[i])) { + String[] messagePush = alertConfig.getMessagePush().split(","); + UserInfo userInfo1 = new UserInfo(); + userInfo1.setUserName(messagePushIpone[i]); + if(ObjectUtil.isNotNull(userInfo) && ObjectUtil.isNotNull(userInfo.getUid())) { + userInfo1.setUid(userInfo.getUid()); + } + sendMessage(messagePush, message, deviceInfo, userInfo1, alertData, alertConfig, i); + } + } + + } else { + String[] messagePush = alertConfig.getMessagePush().split(","); + // System.out.println("messagePush+++++++++++++++++++++++++++++" + messagePush); + sendMessage(messagePush, message, deviceInfo, userInfo, alertData, alertConfig, 0); + } + } + + } + } catch (Exception e) { + + } + } + + public void execute(ThingModelMessage message, Rule rule) { + log.info("The listener did not match the appropriate content,deviceStatus:{},{}", rule.getId(), message.getDeviceStatus()); + if(ObjectUtil.isNull(message.getDeviceStatus()) + || message.getDeviceStatus().equals(2) || + message.getDeviceStatus().equals(1) + ){ + List config = iAlertConfigData.findByDeviceName(message.getDeviceName()); + log.info("The listener did not match the appropriate content,deviceStatus:{},{}", rule.getId(), message.getDeviceStatus()); + if(!config.isEmpty()){ + return; + }else{ + List config1 = iAlertConfigData.findByRuleInfoId(rule.getId()); + if(!config1.isEmpty()){ + return; + } + } + } if (!doListeners(message, rule)) { + /* if(ObjectUtil.isNotNull(message.getDeviceStatus()) + && (message.getDeviceStatus().equals(1) || message.getDeviceStatus().equals(2)) + ) { + log.info("继续处理规则"); + }else{*/ + // return; + // } log.info("The listener did not match the appropriate content,rule:{},{}", rule.getId(), rule.getName()); return; } @@ -145,9 +220,12 @@ public class RuleExecutor { try { // DeviceInfo deviceInfo = iDeviceInfoData.findByDeviceId(message.getDeviceId()); if (ObjectUtil.isNotNull(deviceInfo) && ObjectUtil.isNotNull(deviceInfo.getUid())) { - UserInfo userInfo = iUserInfoData.findById(Long.valueOf(deviceInfo.getUid())); - if (ObjectUtil.isNull(userInfo)) { - return; + UserInfo userInfo = new UserInfo(); + if(ObjectUtil.isNotNull(deviceInfo.getUid()) && !deviceInfo.getUid().equals("")){ + userInfo = iUserInfoData.findById(Long.valueOf(deviceInfo.getUid())); + if (ObjectUtil.isNull(userInfo)) { + return; + } } List listAlertConfigs = iAlertConfigData.findByUidAndRuleInfoIdAndDeviceName(deviceInfo.getUid(), ruleLog.getRuleId(), deviceInfo.getDeviceName()); @@ -161,7 +239,9 @@ public class RuleExecutor { String[] messagePush = alertConfig.getMessagePush().split(","); UserInfo userInfo1 = new UserInfo(); userInfo1.setUserName(messagePushIpone[i]); - userInfo1.setUid(userInfo.getUid()); + if(ObjectUtil.isNotNull(userInfo) && ObjectUtil.isNotNull(userInfo.getUid())) { + userInfo1.setUid(userInfo.getUid()); + } sendMessage(messagePush, message, deviceInfo, userInfo1, alertData, alertConfig, i); } } @@ -183,7 +263,6 @@ public class RuleExecutor { ruleLogData.add(ruleLog); } } - public boolean isValid(String phone) { return phone != null && phone.matches("^\\d{11}$"); } diff --git a/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleMessageHandler.java b/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleMessageHandler.java index 25c12b5..fc41644 100644 --- a/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleMessageHandler.java +++ b/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleMessageHandler.java @@ -28,9 +28,11 @@ import cc.iotkit.ruleengine.action.alert.AlertService; import cc.iotkit.ruleengine.handler.DeviceMessageHandler; import cc.iotkit.ruleengine.listener.DeviceCondition; import cc.iotkit.ruleengine.listener.Listener; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.apache.commons.lang3.ObjectUtils; import org.apache.tomcat.util.digester.Rules; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.*; @@ -44,6 +46,7 @@ import java.util.regex.Pattern; public class RuleMessageHandler implements DeviceMessageHandler { private final ConcurrentMap> deviceRuleMap = new ConcurrentHashMap<>(); + // 全局唯一线程池配置 @Autowired @@ -96,7 +99,7 @@ public class RuleMessageHandler implements DeviceMessageHandler { Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors() * 2, 60, TimeUnit.SECONDS, - new ArrayBlockingQueue<>(10000), + new ArrayBlockingQueue<>(1000), new ThreadPoolExecutor.CallerRunsPolicy()); } @@ -183,6 +186,43 @@ public class RuleMessageHandler implements DeviceMessageHandler { } + public List processMessage1(ThingModelMessage message) { + // Rule[] rules = getRulesForMessage(message); + + String pk = message.getProductKey(); + String dn = message.getDeviceName(); + List rules = new ArrayList<>(); + //仅用PK匹配 + List foundRules = deviceRuleMap.get(pk + "/#"); + if (foundRules != null) { + if (foundRules.get(0).getListeners().size() == 1) { + rules.add(foundRules.get(0)); + } else { + rules.addAll(foundRules); + } + } + //用PK和DN匹配 + foundRules = deviceRuleMap.get(pk + "/" + dn); + if (foundRules != null) { + if (foundRules.get(0).getListeners().size() == 1) { + rules.add(foundRules.get(0)); + } else { + rules.addAll(foundRules); + } + // rules.addAll(foundRules); + } + + /* for (Rule rule : rules) { + rule + clearUnmatchedScripts(rule, message, tempServices); + ruleExecutor.execute1(message, rule); + }*/ + return rules; + + + } + + private Rule[] getRulesForMessage(ThingModelMessage message) { String pk = message.getProductKey(); diff --git a/iot-module/iot-system/src/main/java/cc/iotkit/system/dto/bo/SysTenantBo.java b/iot-module/iot-system/src/main/java/cc/iotkit/system/dto/bo/SysTenantBo.java index f2f79d7..3c715d1 100644 --- a/iot-module/iot-system/src/main/java/cc/iotkit/system/dto/bo/SysTenantBo.java +++ b/iot-module/iot-system/src/main/java/cc/iotkit/system/dto/bo/SysTenantBo.java @@ -63,13 +63,13 @@ public class SysTenantBo extends BaseDto { /** * 联系人 */ - @NotBlank(message = "联系人不能为空", groups = { AddGroup.class, EditGroup.class }) + //@NotBlank(message = "联系人不能为空", groups = { AddGroup.class, EditGroup.class }) private String contactUserName; /** * 联系电话 */ - @NotBlank(message = "联系电话不能为空", groups = { AddGroup.class, EditGroup.class }) + // @NotBlank(message = "联系电话不能为空", groups = { AddGroup.class, EditGroup.class }) private String contactPhone; /** diff --git a/iot-starter/src/main/resources/fonts/STSong-Light.ttf b/iot-starter/src/main/resources/fonts/STSong-Light.ttf new file mode 100644 index 0000000..6f84fd6 Binary files /dev/null and b/iot-starter/src/main/resources/fonts/STSong-Light.ttf differ