袁强 6 months ago
parent
commit
4138eed0af
  1. 2
      dk-api/api-system/src/main/java/org/dromara/system/api/RemoteSubmailConfigService.java
  2. 3
      dk-common/common-cloudsdk/src/main/java/org/dromara/common/sdk/cloudapi/control/api/AbstractControlService.java
  3. 4
      dk-common/common-cloudsdk/src/main/java/org/dromara/common/sdk/cloudapi/device/DeviceVideoEnum.java
  4. 24
      dk-common/common-cloudsdk/src/main/java/org/dromara/common/sdk/cloudapi/wayline/GetWaylineListRequest.java
  5. 5
      dk-common/common-redis/src/main/java/org/dromara/common/redis/config/RedisConst.java
  6. 5
      dk-common/common-websocket/pom.xml
  7. 2
      dk-common/common-websocket/src/main/java/org/dromara/common/websocket/dto/BizCodeEnum.java
  8. 7
      dk-modules/business/src/main/java/org/dromara/business/service/impl/BusinessAlertServiceImpl.java
  9. 54
      dk-modules/business/src/main/resources/templates/alert.ftl
  10. 2
      dk-modules/business/src/main/resources/templates/pdfAlert.ftl
  11. 140
      dk-modules/sample/src/main/java/org/dromara/sample/configuration/LingxiuMqttMessageProcessorImpl.java
  12. 14
      dk-modules/sample/src/main/java/org/dromara/sample/configuration/LingxiuMqttStartupRunner.java
  13. 5
      dk-modules/sample/src/main/java/org/dromara/sample/configuration/MqttLingxiuSubscriber.java
  14. 18
      dk-modules/sample/src/main/java/org/dromara/sample/control/controller/DockController.java
  15. 10
      dk-modules/sample/src/main/java/org/dromara/sample/control/model/enums/PayloadCommandsEnum.java
  16. 14
      dk-modules/sample/src/main/java/org/dromara/sample/control/model/param/DronePayloadParam.java
  17. 6
      dk-modules/sample/src/main/java/org/dromara/sample/control/service/IControlService.java
  18. 54
      dk-modules/sample/src/main/java/org/dromara/sample/control/service/impl/ControlServiceImpl.java
  19. 22
      dk-modules/sample/src/main/java/org/dromara/sample/control/service/impl/IrMeteringAreaSetImpl.java
  20. 23
      dk-modules/sample/src/main/java/org/dromara/sample/control/service/impl/IrMeteringModeSetImpl.java
  21. 22
      dk-modules/sample/src/main/java/org/dromara/sample/control/service/impl/IrMeteringPointSetImpl.java
  22. 6
      dk-modules/sample/src/main/java/org/dromara/sample/feign/RemoteSystemFeign.java
  23. 77
      dk-modules/sample/src/main/java/org/dromara/sample/manage/controller/DeviceController.java
  24. 32
      dk-modules/sample/src/main/java/org/dromara/sample/manage/controller/DeviceProController.java
  25. 13
      dk-modules/sample/src/main/java/org/dromara/sample/manage/controller/DeviceRedisController.java
  26. 113
      dk-modules/sample/src/main/java/org/dromara/sample/manage/controller/ManageDevicePayloadCustomController.java
  27. 110
      dk-modules/sample/src/main/java/org/dromara/sample/manage/domain/ManageDevicePayloadCustom.java
  28. 99
      dk-modules/sample/src/main/java/org/dromara/sample/manage/domain/bo/ManageDevicePayloadCustomBo.java
  29. 100
      dk-modules/sample/src/main/java/org/dromara/sample/manage/domain/vo/ManageDevicePayloadCustomVo.java
  30. 15
      dk-modules/sample/src/main/java/org/dromara/sample/manage/mapper/ManageDevicePayloadCustomMapper.java
  31. 7
      dk-modules/sample/src/main/java/org/dromara/sample/manage/model/dto/DeviceDTO.java
  32. 10
      dk-modules/sample/src/main/java/org/dromara/sample/manage/model/enums/PropertySetFieldEnum.java
  33. 17
      dk-modules/sample/src/main/java/org/dromara/sample/manage/model/param/DeviceSubscribeParam.java
  34. 41
      dk-modules/sample/src/main/java/org/dromara/sample/manage/model/receiver/ThermalCurrentPaletteStyleReceiver.java
  35. 36
      dk-modules/sample/src/main/java/org/dromara/sample/manage/model/receiver/ThermalGaiModeReceiver.java
  36. 36
      dk-modules/sample/src/main/java/org/dromara/sample/manage/model/receiver/ThermalIsothermLowerLimitReceiver.java
  37. 36
      dk-modules/sample/src/main/java/org/dromara/sample/manage/model/receiver/ThermalIsothermStateReceiver.java
  38. 36
      dk-modules/sample/src/main/java/org/dromara/sample/manage/model/receiver/ThermalIsothermUpperLimitReceiver.java
  39. 20
      dk-modules/sample/src/main/java/org/dromara/sample/manage/service/IDeviceProService.java
  40. 12
      dk-modules/sample/src/main/java/org/dromara/sample/manage/service/IDeviceRedisService.java
  41. 2
      dk-modules/sample/src/main/java/org/dromara/sample/manage/service/IDeviceService.java
  42. 68
      dk-modules/sample/src/main/java/org/dromara/sample/manage/service/IManageDevicePayloadCustomService.java
  43. 182
      dk-modules/sample/src/main/java/org/dromara/sample/manage/service/impl/DeviceProServiceImpl.java
  44. 140
      dk-modules/sample/src/main/java/org/dromara/sample/manage/service/impl/DeviceRedisServiceImpl.java
  45. 57
      dk-modules/sample/src/main/java/org/dromara/sample/manage/service/impl/DeviceServiceImpl.java
  46. 139
      dk-modules/sample/src/main/java/org/dromara/sample/manage/service/impl/ManageDevicePayloadCustomServiceImpl.java
  47. 77
      dk-modules/sample/src/main/java/org/dromara/sample/media/controller/FileController.java
  48. 6
      dk-modules/sample/src/main/java/org/dromara/sample/media/service/IFileService.java
  49. 17
      dk-modules/sample/src/main/java/org/dromara/sample/media/service/impl/FileServiceImpl.java
  50. 42
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/controller/WaylineJobAtmosphereController.java
  51. 42
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/controller/WaylineJobController.java
  52. 18
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/domain/WaylineJobAtmosphere.java
  53. 16
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/domain/bo/WaylineJobAtmosphereBo.java
  54. 14
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/domain/vo/WaylineJobAtmosphereVo.java
  55. 6
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/mapper/WaylineJobAtmosphereMapper.java
  56. 3
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/model/dto/WaylineJobDTO.java
  57. 4
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/model/entity/WaylineJobEntity.java
  58. 7
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/IWaylineJobAtmosphereService.java
  59. 11
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/IWaylineJobService.java
  60. 5
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/impl/FlightTaskServiceImpl.java
  61. 12
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/impl/WaylineFileServiceImpl.java
  62. 29
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/impl/WaylineJobAtmosphereServiceImpl.java
  63. 146
      dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/impl/WaylineJobServiceImpl.java
  64. 5
      dk-modules/sample/src/main/java/org/dromara/sample/websocket/config/MyWebSocketFactory.java
  65. 81
      dk-modules/sample/src/main/java/org/dromara/sample/websocket/config/MyWebSocketHandler.java
  66. 104
      dk-modules/sample/src/main/java/org/dromara/sample/websocket/config/WebSocketSubscriptionManager.java
  67. 2
      dk-modules/sample/src/main/java/org/dromara/sample/websocket/service/IWebSocketMessageService.java
  68. 148
      dk-modules/sample/src/main/java/org/dromara/sample/websocket/service/impl/WebSocketMessageServiceImpl.java
  69. 7
      dk-modules/sample/src/main/resources/mapper/ManageDevicePayloadCustomMapper.xml
  70. 15
      dk-modules/sample/src/main/resources/mapper/WaylineJobAtmosphereMapper.xml
  71. 23
      dk-modules/sample/src/main/resources/mapper/WaylineJobMapper.xml
  72. 10
      dk-modules/system/src/main/java/org/dromara/system/controller/system/SysDepartBoundaryController.java
  73. 11
      dk-modules/system/src/main/java/org/dromara/system/controller/system/SysUserController.java
  74. 31
      dk-modules/system/src/main/java/org/dromara/system/domain/bo/SysDepartBoundaryBo.java
  75. 6
      dk-modules/system/src/main/java/org/dromara/system/dubbo/RemoteSubmailConfigServiceImpl.java
  76. 2
      dk-modules/system/src/main/java/org/dromara/system/mapper/SysDepartBoundaryMapper.java
  77. 4
      dk-modules/system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
  78. 2
      dk-modules/system/src/main/java/org/dromara/system/service/ISysDepartBoundaryService.java
  79. 8
      dk-modules/system/src/main/java/org/dromara/system/service/ISysDeptService.java
  80. 2
      dk-modules/system/src/main/java/org/dromara/system/service/ISysSubmailConfigService.java
  81. 8
      dk-modules/system/src/main/java/org/dromara/system/service/ISysUserService.java
  82. 30
      dk-modules/system/src/main/java/org/dromara/system/service/impl/SysDepartBoundaryServiceImpl.java
  83. 15
      dk-modules/system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
  84. 8
      dk-modules/system/src/main/java/org/dromara/system/service/impl/SysSubmailConfigServiceImpl.java
  85. 84
      dk-modules/system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
  86. 8
      dk-modules/system/src/main/resources/mapper/system/SysDepartBoundaryMapper.xml
  87. 5
      dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java
  88. 4
      dk-visual/nacos/src/main/resources/application.properties
  89. 39
      pom.xml

2
dk-api/api-system/src/main/java/org/dromara/system/api/RemoteSubmailConfigService.java

@ -35,6 +35,6 @@ public interface RemoteSubmailConfigService {
* @param userId
* @param noticeMap
*/
void remoteSendUser(String code,List<Long> userId,Map<String, Object> noticeMap);
void remoteSendUser(String code,List<Long> userId,Map<String, Object> noticeMap,String project);
}

3
dk-common/common-cloudsdk/src/main/java/org/dromara/common/sdk/cloudapi/control/api/AbstractControlService.java

@ -436,7 +436,6 @@ public abstract class AbstractControlService {
* @param request data
* @return services_reply
*/
@CloudSDKVersion(since = CloudSDKVersionEnum.V1_0_2, include = GatewayTypeEnum.DOCK)
public TopicServicesResponse<ServicesReplyData> irMeteringModeSet(GatewayManager gateway, IrMeteringModeSetRequest request) {
return servicesPublish.publish(
gateway.getGatewaySn(),
@ -450,7 +449,6 @@ public abstract class AbstractControlService {
* @param request data
* @return services_reply
*/
@CloudSDKVersion(since = CloudSDKVersionEnum.V1_0_2, include = GatewayTypeEnum.DOCK)
public TopicServicesResponse<ServicesReplyData> irMeteringPointSet(GatewayManager gateway, IrMeteringPointSetRequest request) {
return servicesPublish.publish(
gateway.getGatewaySn(),
@ -464,7 +462,6 @@ public abstract class AbstractControlService {
* @param request data
* @return services_reply
*/
@CloudSDKVersion(since = CloudSDKVersionEnum.V1_0_2, include = GatewayTypeEnum.DOCK)
public TopicServicesResponse<ServicesReplyData> irMeteringAreaSet(GatewayManager gateway, IrMeteringAreaSetRequest request) {
return servicesPublish.publish(
gateway.getGatewaySn(),

4
dk-common/common-cloudsdk/src/main/java/org/dromara/common/sdk/cloudapi/device/DeviceVideoEnum.java

@ -76,5 +76,9 @@ public enum DeviceVideoEnum {
.findAny().orElseThrow(() -> new CloudSDKException(DeviceEnum.class, finalKey));
}
public static void main(String[] args) {
System.out.println(DeviceVideoEnum.find("Matrice 30T").getDevice());
}
}

24
dk-common/common-cloudsdk/src/main/java/org/dromara/common/sdk/cloudapi/wayline/GetWaylineListRequest.java

@ -92,6 +92,14 @@ public class GetWaylineListRequest {
@Schema(name = "key", description = "wayline 文件名", example = "waypoint")
private String key;
@JsonProperty("spirit_smell_flag")
@Schema(name = "spirit_smell_flag", description = "灵嗅负载")
private Boolean spiritSmellFlag;
private List<String> spiritSmellWaylineFileIds;
public GetWaylineListRequest() {
}
@ -200,4 +208,20 @@ public class GetWaylineListRequest {
this.deviceSn = deviceSn;
return this;
}
public Boolean getSpiritSmellFlag() {
return spiritSmellFlag;
}
public void setSpiritSmellFlag(Boolean spiritSmellFlag) {
this.spiritSmellFlag = spiritSmellFlag;
}
public List<String> getSpiritSmellWaylineFileIds() {
return spiritSmellWaylineFileIds;
}
public void setSpiritSmellWaylineFileIds(List<String> spiritSmellWaylineFileIds) {
this.spiritSmellWaylineFileIds = spiritSmellWaylineFileIds;
}
}

5
dk-common/common-redis/src/main/java/org/dromara/common/redis/config/RedisConst.java

@ -18,10 +18,15 @@ public final class RedisConst {
public static final Integer DEVICE_ALIVE_SECOND = 60;
public static final Integer WEBSOCKET_ALIVE_SECOND = 60 * 60 * 24;
public static final Integer ONLINE_REDIS_USER_ALIVE_SECOND = 60 * 5;
public static final Integer DEVICE_VIDEO_STATUE_SECOND = 60 * 50;
public static final String DEVICE_ONLINE_PREFIX = "online" + DELIMITER;
public static final String DEVICE_ONLINE_USER_PREFIX = "onlineuser" + DELIMITER;
public static final String DEVICE_SPIRITSMELL_PREFIX = "spiritsmell" + DELIMITER; //灵嗅设备状态
public static final String DEVICE_SPIRITSMELL_LIST_PREFIX = "spiritsmell_list" + DELIMITER; //灵嗅设备状态
public static final String WEBSOCKET_PREFIX = "webSocket" + DELIMITER;

5
dk-common/common-websocket/pom.xml

@ -48,6 +48,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!--<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>2.0.12</version>
</dependency>-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>common-cloudsdk</artifactId>

2
dk-common/common-websocket/src/main/java/org/dromara/common/websocket/dto/BizCodeEnum.java

@ -79,6 +79,8 @@ public enum BizCodeEnum {
FLIGHT_AREAS_UPDATE("flight_areas_update"),
SPIRIT_SMELL("spirit_smell"),
;
private String code;

7
dk-modules/business/src/main/java/org/dromara/business/service/impl/BusinessAlertServiceImpl.java

@ -689,7 +689,12 @@ public class BusinessAlertServiceImpl implements IBusinessAlertService {
}
if (ObjectUtil.isNotEmpty(bo.getDeptId())){
wrapper.eq("t.dept_id", bo.getDeptId());
//根据传过来的部门id查找是否存在下级部门
List<RemoteDeptVo> remoteDeptVos = remoteDeptService.selectListByParentId(bo.getDeptId());
List<Long> deptIdList = StreamUtils.toList(remoteDeptVos, RemoteDeptVo::getDeptId);
deptIdList.add(Long.valueOf(bo.getDeptId()));
wrapper.in("t.dept_id", deptIdList);
}
if (ObjectUtil.isNotEmpty(bo.getJobName())){

54
dk-modules/business/src/main/resources/templates/alert.ftl

@ -829,6 +829,33 @@
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1420" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p>
<w:pPr>
<w:listPr>
<w:ilvl w:val="0"/>
<w:ilfo w:val="0"/>
</w:listPr>
<w:rPr>
<w:rFonts w:hint="default"/>
<w:vertAlign w:val="baseline"/>
<w:lang w:val="EN-US" w:fareast="ZH-CN"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
<w:vertAlign w:val="baseline"/>
<w:lang w:val="EN-US" w:fareast="ZH-CN"/>
</w:rPr>
<w:t>标签</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1421" w:type="dxa"/>
@ -1012,6 +1039,33 @@
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1420" w:type="dxa"/>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p>
<w:pPr>
<w:listPr>
<w:ilvl w:val="0"/>
<w:ilfo w:val="0"/>
</w:listPr>
<w:rPr>
<w:rFonts w:hint="default"/>
<w:vertAlign w:val="baseline"/>
<w:lang w:val="EN-US" w:fareast="ZH-CN"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
<w:vertAlign w:val="baseline"/>
<w:lang w:val="EN-US" w:fareast="ZH-CN"/>
</w:rPr>
<w:t>${item.labelCn?if_exists}</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="1421" w:type="dxa"/>

2
dk-modules/business/src/main/resources/templates/pdfAlert.ftl

@ -50,6 +50,7 @@
<td>预警名称</td>
<td>所属部门</td>
<td>预警状态</td>
<td>标签</td>
<td>经纬度</td>
<td>预警时间</td>
</tr>
@ -60,6 +61,7 @@
<td>${item.jobName?if_exists}</td>
<td>${item.deptName?if_exists}</td>
<td>${item.handleType?if_exists}</td>
<td>${item.labelCn?if_exists}</td>
<td>${item.lng?if_exists} ${item.lat?if_exists}</td>
<td>${item.createTime?datetime?string('yyyy-MM-dd HH:mm:ss')}</td>
</tr>

140
dk-modules/sample/src/main/java/org/dromara/sample/configuration/LingxiuMqttMessageProcessorImpl.java

@ -1,26 +1,32 @@
package org.dromara.sample.configuration;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.redis.config.RedisConst;
import org.dromara.common.redis.utils.RedisOpsUtils;
import org.dromara.common.websocket.dto.BizCodeEnum;
import org.dromara.sample.manage.domain.ManageDevicePayloadCustom;
import org.dromara.sample.manage.mapper.IDevicePayloadMapper;
import org.dromara.sample.manage.model.dto.DevicePayloadDTO;
import org.dromara.sample.manage.mapper.ManageDevicePayloadCustomMapper;
import org.dromara.sample.manage.model.dto.TelemetryDTO;
import org.dromara.sample.manage.model.entity.DevicePayloadEntity;
import org.dromara.sample.manage.model.enums.UserTypeEnum;
import org.dromara.sample.manage.service.IDevicePayloadService;
import org.dromara.sample.wayline.domain.WaylineJobAtmosphere;
import org.dromara.sample.manage.service.IDeviceRedisService;
import org.dromara.sample.wayline.domain.bo.WaylineJobAtmosphereBo;
import org.dromara.sample.wayline.model.dto.WaylineJobDTO;
import org.dromara.sample.wayline.model.entity.WaylineJobEntity;
import org.dromara.sample.wayline.service.IWaylineJobAtmosphereService;
import org.dromara.sample.wayline.service.IWaylineJobService;
import org.dromara.sample.websocket.config.WebSocketSubscriptionManager;
import org.dromara.sample.websocket.service.IWebSocketMessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Slf4j
@ -31,49 +37,91 @@ public class LingxiuMqttMessageProcessorImpl implements LingxiuMqttMessageProces
private final IWaylineJobService waylineJobService;
private final IDevicePayloadService devicePayloadService;
@Autowired
private IDeviceRedisService deviceRedisService;
@Autowired
private final IDevicePayloadMapper devicePayloadMapper;
@Autowired
private final ManageDevicePayloadCustomMapper manageDevicePayloadCustomMapper;
@Autowired
private IWebSocketMessageService webSocketMessageService;
@Autowired
private WebSocketSubscriptionManager webSocketSubscriptionManager;
@Override
public void process(String topic, String payload) {
log.info("处理灵嗅MQTT数据 topic={}, payload={}", topic, payload);
// {"serial":"37c12953","sequence":12,"sateNum":0,"hdop":0,"utcTime":"2025-06-17-01-37-22","latitude":34.270486,"longitude":117.149302,"altitude":0.03,"temperature":29.61,"humidity":21.37,"pressure":100071.42,"airData":{"SO2(ppm)":0,"NO2(ppm)":0,"Ox(ppm)":0,"PM1.0(ug/m3)":14,"PM2.5(ug/m3)":35,"PM10(ug/m3)":46}}
// if(1==1){ //关闭数据
// return;
// }
// System.out.println("灵嗅"+topic);
log.info("处理灵嗅MQTT数据 topic={}, payload={}", topic, payload);
// {"serial":"37c12953","sequence":12,"sateNum":0,"hdop":0,"utcTime":"2025-06-17-01-37-22","latitude":34.270486,"longitude":117.149302,"altitude":0.03,"temperature":29.61,"humidity":21.37,"pressure":100071.42,"airData":{"SO2(ppm)":0,"NO2(ppm)":0,"Ox(ppm)":0,"PM1.0(ug/m3)":14,"PM2.5(ug/m3)":35,"PM10(ug/m3)":46}}
try {
JSONObject json = JSONUtil.parseObj(payload);
System.out.println("json打印"+json);
JSONObject airData = json.getJSONObject("airData");
JSONObject airData = json.getJSONObject("airData"); //"airData":{"SO2(ppm)":0,"NO2(ppm)":0,"Ox(ppm)":0,"PM1.0(ug/m3)":16,"PM2.5(ug/m3)":39,"PM10(ug/m3)":51}
/** 数据处理-简化对象内容 {"SO2":0,"NO2":0,"Ox":0.082399,"PM1_0":20,"PM2_5":39,"PM10":48} */
JSONObject simplified = new JSONObject();
for (String key : airData.keySet()) {
Object value = airData.get(key);
String newKey = key.replaceAll("\\(.*?\\)", ""); // 去掉括号及其内容:"SO2(ppm)" -> "SO2"
newKey = newKey.replace(".", "_"); // 替换 . 为 _,例如 "PM2.5" -> "PM2_5"
newKey = newKey.replaceAll("(?i)point", "_"); //point去除:PM1point0 or PM2POINT5 → PM1_0, PM2_5
newKey = newKey.trim(); // 去除空格
simplified.put(newKey, value);
}
String utcTimeStr = json.getStr("utcTime");
Boolean missionOpenStatus = json.getBool("missionOpenStatus");
Float relativeAltitude = json.getFloat("relativeAltitude");
Boolean dataRecoveryFlag = json.getBool("dataRecoveryFlag");
//"airData":{"SO2(ppm)":0,"NO2(ppm)":0,"Ox(ppm)":0,"PM1.0(ug/m3)":16,"PM2.5(ug/m3)":39,"PM10(ug/m3)":51}
//找默认数据
WaylineJobAtmosphereBo jobAtmosphere = JSONUtil.toBean(json, WaylineJobAtmosphereBo.class);
jobAtmosphere.setAirData(JSONUtil.toJsonStr(airData));
jobAtmosphere.setAirData(JSONUtil.toJsonStr(simplified));
jobAtmosphere.setUtcTimeStr(utcTimeStr);
jobAtmosphere.setMissionOpenStatus(missionOpenStatus);
jobAtmosphere.setRelativeAltitude(relativeAltitude);
jobAtmosphere.setDataRecoveryFlag(dataRecoveryFlag);
LambdaQueryWrapper<DevicePayloadEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DevicePayloadEntity::getPayloadSn,jobAtmosphere.getSerial());
DevicePayloadEntity devicePayloadEntity = devicePayloadMapper.selectOne(queryWrapper);
String deviceSn = devicePayloadEntity.getDeviceSn();
System.out.println(deviceSn);
// List<DevicePayloadDTO> devicePayloadEntitiesByDeviceSn = devicePayloadService.getDevicePayloadEntitiesByDeviceSn("");
//找第三方挂载
LambdaQueryWrapper<ManageDevicePayloadCustom> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ManageDevicePayloadCustom::getPayloadSn, jobAtmosphere.getSerial());
ManageDevicePayloadCustom paloadCustom = manageDevicePayloadCustomMapper.selectOne(queryWrapper);
if (paloadCustom == null) {
return;
}
String deviceSn = paloadCustom.getDockSn();//8UUXN2B00A00SK
String payloadType = paloadCustom.getPayloadType();
jobAtmosphere.setPayloadType(payloadType);
// List<DevicePayloadDTO> devicePayloadEntitiesByDeviceSn = devicePayloadService.getDevicePayloadEntitiesByDeviceSn("");
// String sn = json.getStr("8UUXN3100A01WS");//8UUXN3100A01WS 8UUXN2T00A01R8
/** 更新设备灵嗅状态上线 **/
// 查找无人机/wayline信息
WaylineJobDTO waylineJobDTO = waylineJobService.getJobByDockSn(deviceSn);
// waylineJobService.getid
// Optional<WaylineJobDTO> jobOpt = waylineJobService.getJobByJobInternalId(sn);
// if (jobOpt.isPresent()) {
// waylineJobAtmosphereService.handleAdd(jobOpt.get(), json);
// } else {
// log.warn("找不到对应无人机任务:sn={}", sn);
WaylineJobDTO waylineJobDTO = waylineJobService.getJobByDockSn(deviceSn); //飞行中+倒序》找第一个
// if(ObjectUtil.isEmpty(waylineJobDTO.getId())){
// //测试-找一个临时备用的
// Optional<WaylineJobDTO> jobByJobId = waylineJobService.getJobByJobId("e3dea0f5-37f2-4d79-ae58-490af3228070","8fc5e69e-2f8d-4a8f-9bdd-0c59eab39d74");
// if (jobByJobId.isPresent()) {
// waylineJobDTO = jobByJobId.get();
// }
// }
// "{\"SO2(ppm)\":0,\"NO2(ppm)\":0,\"Ox(ppm)\":0,\"PM1.0(ug/m3)\":16,\"PM2.5(ug/m3)\":38,\"PM10(ug/m3)\":48}"
if(ObjectUtil.isEmpty(waylineJobDTO.getId())){
return;
}
if(ObjectUtil.isNotEmpty(waylineJobDTO)){
jobAtmosphere.setWaylineJobId((long)waylineJobDTO.getId());
@ -83,8 +131,42 @@ public class LingxiuMqttMessageProcessorImpl implements LingxiuMqttMessageProces
jobAtmosphere.setFileId(waylineJobDTO.getFileId());
jobAtmosphere.setWorkspaceId(waylineJobDTO.getWorkspaceId());
jobAtmosphere.setDockSn(waylineJobDTO.getDockSn());
// BeanUtil.copyProperties();
waylineJobAtmosphereService.insertByBo(jobAtmosphere);
waylineJobAtmosphereService.insertByBo(jobAtmosphere);//存到库里
//拼接数据到redis ,负责push 对象到灵嗅记录列表-正常
// deviceRedisService.pushDeviceSpiritSmellList(deviceSn, jobAtmosphere);
// RedisOpsUtils.setWithExpire(RedisConst.DEVICE_SPIRITSMELL_PREFIX + deviceSn, data, 30);
//动态赋值给dockOsd的redis缓存。
jobAtmosphere.setAirDataJson(JSONUtil.parseObj(jobAtmosphere.getAirData()));
// 存到缓存-单独缓存
deviceRedisService.setDeviceSpiritSmellOnline(deviceSn,jobAtmosphere);
// 存到缓存-扩展OSD数据
// Object osdRedis = RedisOpsUtils.get(RedisConst.OSD_PREFIX + deviceSn);
// if(Optional.ofNullable(osdRedis).isPresent()){
//// OsdDockDrone
// JSONObject entries = JSONUtil.parseObj(osdRedis);
// entries.set("spiritsmell", jobAtmosphere);
// RedisOpsUtils.setWithExpire(RedisConst.OSD_PREFIX + deviceSn, entries, RedisConst.ONLINE_REDIS_USER_ALIVE_SECOND);
//
// }
// deviceRedisService.getDeviceSpiritSmellOnline(deviceSn);
//socket发送-正常
Optional<WaylineJobAtmosphereBo> deviceOpt = deviceRedisService.getDeviceSpiritSmellOnline(deviceSn);
if (deviceOpt.isEmpty()) {
return;
}
String bizCode = BizCodeEnum.SPIRIT_SMELL.getCode();
String dockSn = deviceSn; // 设备码
String workspaceId = deviceOpt.get().getWorkspaceId();
// Collection<MyConcurrentWebSocketSession> subs = webSocketSubscriptionManager.getSessionsForDock(dockSn);
webSocketMessageService.sendBatch(workspaceId, UserTypeEnum.WEB.getVal(),bizCode, TelemetryDTO.builder().sn(deviceSn).host(jobAtmosphere).build());
// Collection<MyConcurrentWebSocketSession> subs = webSocketSubscriptionManager.getSessionsForDock(dockSn);
// webSocketMessageService.sendBatchBySessions(subs, bizCode, TelemetryDTO.builder().sn(deviceSn).host(jobAtmosphere).build());
}
} catch (Exception e) {
log.error("处理灵嗅MQTT消息异常", e);

14
dk-modules/sample/src/main/java/org/dromara/sample/configuration/LingxiuMqttStartupRunner.java

@ -1,6 +1,8 @@
package org.dromara.sample.configuration;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
@ -11,10 +13,20 @@ import org.springframework.stereotype.Component;
public class LingxiuMqttStartupRunner implements ApplicationRunner {
private final MqttLingxiuSubscriber subscriber;
@Value("${lingxiu.mqtt.enable}")
private String enable;
@Value("${lingxiu.mqtt.topic}")
private String topic;
@Override
public void run(ApplicationArguments args) {
if(!StrUtil.equals(enable, "true")) {
return;
}
try {
subscriber.subscribe();
subscriber.subscribe(topic);
} catch (Exception e) {
System.err.println("启动灵嗅 MQTT 订阅失败"+ e);
}

5
dk-modules/sample/src/main/java/org/dromara/sample/configuration/MqttLingxiuSubscriber.java

@ -17,8 +17,9 @@ public class MqttLingxiuSubscriber {
this.processor = processor;
}
public void subscribe() throws MqttException {
String[] topics = new String[]{"/topic/#"};
public void subscribe(String topicParam) throws MqttException {
// String[] topics = new String[]{"/topic/#"};
String[] topics = new String[]{topicParam};
client.setCallback(new MqttCallback() {
@Override

18
dk-modules/sample/src/main/java/org/dromara/sample/control/controller/DockController.java

@ -71,5 +71,23 @@ public class DockController {
return controlService.payloadCommands(param);
}
@PostMapping("/{sn}/payload/irMeteringModeSet")
public HttpResultResponse irMeteringModeSet(@PathVariable String sn, @Valid @RequestBody PayloadCommandsParam param) throws Exception {
param.setSn(sn);
return controlService.irMeteringModeSet(param);
}
@PostMapping("/{sn}/payload/irMeteringPointSet")
public HttpResultResponse irMeteringPointSet(@PathVariable String sn, @Valid @RequestBody PayloadCommandsParam param) throws Exception {
param.setSn(sn);
return controlService.irMeteringPointSet(param);
}
@PostMapping("/{sn}/payload/irMeteringAreaSet")
public HttpResultResponse irMeteringAreaSet(@PathVariable String sn, @Valid @RequestBody PayloadCommandsParam param) throws Exception {
param.setSn(sn);
return controlService.irMeteringAreaSet(param);
}
}

10
dk-modules/sample/src/main/java/org/dromara/sample/control/model/enums/PayloadCommandsEnum.java

@ -2,6 +2,8 @@ package org.dromara.sample.control.model.enums;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import org.dromara.common.sdk.cloudapi.control.ControlMethodEnum;
import org.dromara.common.sdk.cloudapi.control.IrMeteringModeSetRequest;
import org.dromara.common.sdk.cloudapi.control.PayloadControlMethodEnum;
import java.util.Arrays;
@ -25,7 +27,13 @@ public enum PayloadCommandsEnum {
CAMERA_FOCAL_LENGTH_SET(PayloadControlMethodEnum.CAMERA_FOCAL_LENGTH_SET, org.dromara.sample.control.service.impl.CameraFocalLengthSetImpl.class),
GIMBAL_RESET(PayloadControlMethodEnum.GIMBAL_RESET, org.dromara.sample.control.service.impl.GimbalResetImpl.class);
GIMBAL_RESET(PayloadControlMethodEnum.GIMBAL_RESET, org.dromara.sample.control.service.impl.GimbalResetImpl.class),
IR_METERING_MODE_SET(PayloadControlMethodEnum.IR_METERING_MODE_SET, org.dromara.sample.control.service.impl.IrMeteringModeSetImpl.class),
IR_METERING_POINT_SET(PayloadControlMethodEnum.IR_METERING_POINT_SET, org.dromara.sample.control.service.impl.IrMeteringPointSetImpl.class),
IR_METERING_AREA_SET(PayloadControlMethodEnum.IR_METERING_AREA_SET, org.dromara.sample.control.service.impl.IrMeteringAreaSetImpl.class);
PayloadControlMethodEnum cmd;

14
dk-modules/sample/src/main/java/org/dromara/sample/control/model/param/DronePayloadParam.java

@ -1,6 +1,8 @@
package org.dromara.sample.control.model.param;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
@ -29,6 +31,18 @@ public class DronePayloadParam {
private CameraModeEnum cameraMode;
private Integer mode;
@Min(0)
@Max(1)
private Float width;
/**
* Temperature measurement area height
*/
@Min(0)
@Max(1)
private Float height;
/**
* true: Lock the gimbal, the gimbal and the drone rotate together.
* false: Only the gimbal rotates, but the drone does not.

6
dk-modules/sample/src/main/java/org/dromara/sample/control/service/IControlService.java

@ -70,4 +70,10 @@ public interface IControlService {
* @return
*/
HttpResultResponse payloadCommands(PayloadCommandsParam param) throws Exception;
HttpResultResponse irMeteringModeSet(PayloadCommandsParam param) throws Exception;
HttpResultResponse irMeteringPointSet(PayloadCommandsParam param) throws Exception;
HttpResultResponse irMeteringAreaSet(PayloadCommandsParam param) throws Exception;
}

54
dk-modules/sample/src/main/java/org/dromara/sample/control/service/impl/ControlServiceImpl.java

@ -301,4 +301,58 @@ public class ControlServiceImpl implements IControlService {
HttpResultResponse.success()
: HttpResultResponse.error(serviceReply.getResult());
}
@Override
public HttpResultResponse irMeteringModeSet(PayloadCommandsParam param) throws Exception {
param.getCmd().getClazz()
.getDeclaredConstructor(DronePayloadParam.class)
.newInstance(param.getData())
.checkCondition(param.getSn());
TopicServicesResponse<ServicesReplyData> response = abstractControlService.irMeteringModeSet(
SDKManager.getDeviceSDK(param.getSn()),
mapper.convertValue(param.getData(), IrMeteringModeSetRequest.class));
ServicesReplyData serviceReply = response.getData();
return serviceReply.getResult().isSuccess() ?
HttpResultResponse.success()
: HttpResultResponse.error(serviceReply.getResult());
}
@Override
public HttpResultResponse irMeteringPointSet(PayloadCommandsParam param) throws Exception {
param.getCmd().getClazz()
.getDeclaredConstructor(DronePayloadParam.class)
.newInstance(param.getData())
.checkCondition(param.getSn());
TopicServicesResponse<ServicesReplyData> response = abstractControlService.irMeteringPointSet(
SDKManager.getDeviceSDK(param.getSn()),
mapper.convertValue(param.getData(), IrMeteringPointSetRequest.class));
ServicesReplyData serviceReply = response.getData();
return serviceReply.getResult().isSuccess() ?
HttpResultResponse.success()
: HttpResultResponse.error(serviceReply.getResult());
}
@Override
public HttpResultResponse irMeteringAreaSet(PayloadCommandsParam param) throws Exception {
param.getCmd().getClazz()
.getDeclaredConstructor(DronePayloadParam.class)
.newInstance(param.getData())
.checkCondition(param.getSn());
TopicServicesResponse<ServicesReplyData> response = abstractControlService.irMeteringAreaSet(
SDKManager.getDeviceSDK(param.getSn()),
mapper.convertValue(param.getData(), IrMeteringAreaSetRequest.class));
ServicesReplyData serviceReply = response.getData();
return serviceReply.getResult().isSuccess() ?
HttpResultResponse.success()
: HttpResultResponse.error(serviceReply.getResult());
}
}

22
dk-modules/sample/src/main/java/org/dromara/sample/control/service/impl/IrMeteringAreaSetImpl.java

@ -0,0 +1,22 @@
package org.dromara.sample.control.service.impl;
import org.dromara.sample.control.model.param.DronePayloadParam;
/**
* @author sean
* @version 1.4
* @date 2023/4/23
*/
public class IrMeteringAreaSetImpl extends PayloadCommandsHandler {
public IrMeteringAreaSetImpl(DronePayloadParam param) {
super(param);
}
@Override
public boolean canPublish(String deviceSn) {
super.canPublish(deviceSn);
return true;
}
}

23
dk-modules/sample/src/main/java/org/dromara/sample/control/service/impl/IrMeteringModeSetImpl.java

@ -0,0 +1,23 @@
package org.dromara.sample.control.service.impl;
import org.dromara.common.sdk.cloudapi.device.CameraStateEnum;
import org.dromara.sample.control.model.param.DronePayloadParam;
/**
* @author sean
* @version 1.4
* @date 2023/4/23
*/
public class IrMeteringModeSetImpl extends PayloadCommandsHandler {
public IrMeteringModeSetImpl(DronePayloadParam param) {
super(param);
}
@Override
public boolean canPublish(String deviceSn) {
super.canPublish(deviceSn);
return true;
}
}

22
dk-modules/sample/src/main/java/org/dromara/sample/control/service/impl/IrMeteringPointSetImpl.java

@ -0,0 +1,22 @@
package org.dromara.sample.control.service.impl;
import org.dromara.sample.control.model.param.DronePayloadParam;
/**
* @author sean
* @version 1.4
* @date 2023/4/23
*/
public class IrMeteringPointSetImpl extends PayloadCommandsHandler {
public IrMeteringPointSetImpl(DronePayloadParam param) {
super(param);
}
@Override
public boolean canPublish(String deviceSn) {
super.canPublish(deviceSn);
return true;
}
}

6
dk-modules/sample/src/main/java/org/dromara/sample/feign/RemoteSystemFeign.java

@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
import java.util.Map;
@FeignClient(name = "gateway",path = "system")
public interface RemoteSystemFeign {
@ -17,4 +18,9 @@ public interface RemoteSystemFeign {
@GetMapping(value = "/config/configKeyFeign/{configKey}")
public String getConfigKeyFeign(@PathVariable String configKey);
//根据目标值类型查询用户信息
@GetMapping("/user/list/target")
public List<Map<String,Object>> listTargetTypeByUser(List<Map<String,Object>> params);
}

77
dk-modules/sample/src/main/java/org/dromara/sample/manage/controller/DeviceController.java

@ -1,24 +1,15 @@
package org.dromara.sample.manage.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.dromara.common.core.domain.R;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.config.RedisConst;
import org.dromara.common.redis.utils.RedisOpsUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.sdk.cloudapi.device.OsdDock;
import org.dromara.common.web.core.BaseController;
import org.dromara.sample.manage.model.dto.DeviceDTO;
import org.dromara.sample.manage.model.dto.DeviceFirmwareUpgradeDTO;
import org.dromara.sample.manage.model.entity.DeviceEntity;
import org.dromara.sample.manage.service.IDeviceProService;
import org.dromara.sample.manage.model.param.DeviceSubscribeParam;
import org.dromara.sample.manage.service.IDeviceRedisService;
import org.dromara.sample.manage.service.IDeviceService;
import com.fasterxml.jackson.databind.JsonNode;
@ -27,12 +18,10 @@ import org.dromara.common.sdk.common.HttpResultResponse;
import org.dromara.common.sdk.common.PaginationData;
import org.dromara.common.sdk.exception.CloudSDKErrorEnum;
import org.dromara.common.sdk.mqtt.property.PropertySetReplyResultEnum;
import org.dromara.system.api.model.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author sean.zhou
@ -65,6 +54,52 @@ public class DeviceController {
return HttpResultResponse.success(devicesList);
}
@GetMapping("/{workspace_id}/devices/osd")
@Operation(summary = "获取一个工作区中所有在线设备+OSD的列表", description = "获取一个工作区中所有在线设备+OSD的列表")
public HttpResultResponse<List<DeviceDTO>> getDevicesOsd(@PathVariable("workspace_id") String workspaceId,
@RequestParam(name = "nickname",required = false) String nickname,@RequestParam(name = "proIds",required = false) List<Integer> proIds) {
List<DeviceDTO> devicesList = deviceService.getDevicesTopoForWeb(workspaceId,nickname,proIds);
//拼接osd信息
JSONObject devicesOsdJson = deviceRedisService.getDevicesOsdList("");
for (DeviceDTO deviceDTO : devicesList) {
if(devicesOsdJson.containsKey(deviceDTO.getDeviceSn())){
deviceDTO.setOsdData(devicesOsdJson.getJSONObject(deviceDTO.getDeviceSn()));
}
}
return HttpResultResponse.success(devicesList);
}
//设备订阅-关闭保存到redis
@PostMapping("/{workspace_id}/subscribe")
@Operation(summary = "设备消息订阅", description = "设备消息订阅")
public HttpResultResponse subscribe(@PathVariable("workspace_id") String workspaceId,
@RequestBody DeviceSubscribeParam deviceSubscribeParam
// @RequestParam("action") String action,
// @RequestParam("token") String token,
// @RequestParam("dockSn") String dockSn
) {
String action = deviceSubscribeParam.getAction();
String token = deviceSubscribeParam.getToken();
String dockSn = deviceSubscribeParam.getDockSn();
if(action.equals("subscribe")) {
System.out.println("sub"+token);
String key = RedisConst.DEVICE_ONLINE_USER_PREFIX + token;
//基于机场sn找无人机sn
String value = "";
Optional<DeviceDTO> deviceBySn = deviceService.getDeviceBySn(dockSn);
if(deviceBySn.isPresent()) {
value = dockSn + "," + deviceBySn.get().getChildDeviceSn();
}
RedisOpsUtils.setWithExpire(key, value ,RedisConst.ONLINE_REDIS_USER_ALIVE_SECOND);
}else if(action.equals("unsubscribe")) {
RedisOpsUtils.del(RedisConst.DEVICE_ONLINE_USER_PREFIX+token);
}
return HttpResultResponse.success();
}
@GetMapping("/{workspace_id}/devices/redis")
@Operation(summary = "获取一个工作区中所有在线设备的列表。", description = "获取一个工作区中所有在线设备的列表")
public HttpResultResponse<JSONObject> getDeviceRedis(@PathVariable("workspace_id") String workspaceId,
@ -257,4 +292,18 @@ public class DeviceController {
return PropertySetReplyResultEnum.SUCCESS.getResult() == result ?
HttpResultResponse.success() : HttpResultResponse.error(result, String.valueOf(result));
}
@Operation(summary = "设置无人机的属性参数。", description = "设置无人机的属性参数。")
@PutMapping("/{workspace_id}/devices/{device_sn}/propertyData")
public HttpResultResponse devicePropertySetData(@PathVariable("workspace_id") String workspaceId,
@PathVariable("device_sn") String dockSn,
@RequestBody JsonNode param) {
if (param.size() != 1) {
return HttpResultResponse.error(CloudSDKErrorEnum.INVALID_PARAMETER);
}
int result = deviceService.devicePropertySetData(workspaceId, dockSn, param);
return PropertySetReplyResultEnum.SUCCESS.getResult() == result ?
HttpResultResponse.success() : HttpResultResponse.error(result, String.valueOf(result));
}
}

32
dk-modules/sample/src/main/java/org/dromara/sample/manage/controller/DeviceProController.java

@ -1,23 +1,20 @@
package org.dromara.sample.manage.controller;
import cn.hutool.core.lang.Dict;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.sdk.common.HttpResultResponse;
import org.dromara.common.sdk.common.PaginationData;
import org.dromara.sample.manage.model.dto.DeviceProDTO;
import org.dromara.sample.manage.model.entity.DeviceProEntity;
import org.dromara.sample.manage.model.entity.DeviceProUserEntity;
import org.dromara.sample.manage.service.IDeviceProService;
import org.dromara.system.api.model.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@Slf4j
@ -87,11 +84,27 @@ public class DeviceProController {
*/
@Operation(summary = "新增/更新项目人员。", description = "新增/更新项目人员。")
@PostMapping("/{proId}/update")
public HttpResultResponse<Boolean> updateDeviceProUser(@RequestBody List<DeviceProUserEntity> userEntity,@PathVariable Integer proId) {
public HttpResultResponse<Boolean> updateDeviceProUser(@RequestBody List<DeviceProUserEntity> userEntity, @PathVariable Integer proId) {
return HttpResultResponse.success(deviceProService.updateDeviceProUser(userEntity,proId));
}
/**
* 新增/更新项目人员
* @param userEntity
* @return
*/
@Operation(summary = "新增/更新项目人员新", description = "新增/更新项目人员新")
@PostMapping("/{proId}/update/new")
public HttpResultResponse<Boolean> updateDeviceProUserNew(@RequestBody List<Map<String, Object>> userEntity, @PathVariable Integer proId) {
//目标类型 targetType 1、用户 2、角色 3、部门 targetKey 目标值 List<Map<String,Object>> params
return HttpResultResponse.success(deviceProService.updateDeviceProUserNew(userEntity,proId));
}
@Operation(summary = "查询项目人员。", description = "查询项目人员")
@GetMapping("/{proId}/user/page")
public HttpResultResponse<PaginationData<DeviceProUserEntity>> pageProUser(@PathVariable Integer proId,
@ -102,6 +115,7 @@ public class DeviceProController {
return HttpResultResponse.success(deviceProService.pageProUser(searchValue,proId,pageQuery));
}
@Operation(summary = "删除项目人员", description = "删除项目人员")
@DeleteMapping("/{proId}/{proUserId}/user/delete")
public HttpResultResponse<Boolean> deleteProUser(@PathVariable Integer proId,
@ -149,4 +163,12 @@ public class DeviceProController {
List<DeviceProEntity> result = deviceProService.listUserGroup();
return HttpResultResponse.success(result);
}
/**
* 初始化将设备组数据存入redis
*/
@GetMapping("/redis/init")
public HttpResultResponse<Boolean> initProRedisCache(){
return HttpResultResponse.success(deviceProService.initProRedisCache());
}
}

13
dk-modules/sample/src/main/java/org/dromara/sample/manage/controller/DeviceRedisController.java

@ -1,6 +1,7 @@
package org.dromara.sample.manage.controller;
import cn.hutool.json.JSONObject;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
@ -9,10 +10,7 @@ import org.dromara.common.sdk.common.HttpResultResponse;
import org.dromara.sample.manage.model.dto.DeviceDTO;
import org.dromara.sample.manage.service.IDeviceRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@ -54,4 +52,11 @@ public class DeviceRedisController {
return HttpResultResponse.success(deviceRedisService.getDevicesOsdInfo(snList));
}
@GetMapping("/device/osd/list")
@Operation(summary = "获取设备osd实时列表", description = "获取设备osd实时列表")
public HttpResultResponse<JSONObject> getDevicesOsdList(@RequestParam(value = "type", required = false) String type) {
return HttpResultResponse.success(deviceRedisService.getDevicesOsdList(type));
}
}

113
dk-modules/sample/src/main/java/org/dromara/sample/manage/controller/ManageDevicePayloadCustomController.java

@ -0,0 +1,113 @@
package org.dromara.sample.manage.controller;
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.sample.manage.domain.vo.ManageDevicePayloadCustomVo;
import org.dromara.sample.manage.domain.bo.ManageDevicePayloadCustomBo;
import org.dromara.sample.manage.service.IManageDevicePayloadCustomService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* 设备自定义/第三方载荷信息
* 前端访问路由地址为:/sample/DevicePayloadCustom
*
* @author szs
* @date 2025-06-18
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/DevicePayloadCustom")
public class ManageDevicePayloadCustomController extends BaseController {
private final IManageDevicePayloadCustomService manageDevicePayloadCustomService;
/**
* 查询设备自定义/第三方载荷信息列表
*/
@SaCheckPermission("sample:DevicePayloadCustom:list")
@GetMapping("/list")
public TableDataInfo<ManageDevicePayloadCustomVo> list(ManageDevicePayloadCustomBo bo, PageQuery pageQuery) {
return manageDevicePayloadCustomService.queryPageList(bo, pageQuery);
}
@SaCheckPermission("sample:DevicePayloadCustom:list")
@GetMapping("/listAll")
public List<ManageDevicePayloadCustomVo> listAll(ManageDevicePayloadCustomBo bo) {
return manageDevicePayloadCustomService.queryList(bo);
}
/**
* 导出设备自定义/第三方载荷信息列表
*/
@SaCheckPermission("sample:DevicePayloadCustom:export")
@Log(title = "设备自定义/第三方载荷信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ManageDevicePayloadCustomBo bo, HttpServletResponse response) {
List<ManageDevicePayloadCustomVo> list = manageDevicePayloadCustomService.queryList(bo);
ExcelUtil.exportExcel(list, "设备自定义/第三方载荷信息", ManageDevicePayloadCustomVo.class, response);
}
/**
* 获取设备自定义/第三方载荷信息详细信息
*
* @param id 主键
*/
@SaCheckPermission("sample:DevicePayloadCustom:query")
@GetMapping("/{id}")
public R<ManageDevicePayloadCustomVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(manageDevicePayloadCustomService.queryById(id));
}
/**
* 新增设备自定义/第三方载荷信息
*/
@SaCheckPermission("sample:DevicePayloadCustom:add")
@Log(title = "设备自定义/第三方载荷信息", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ManageDevicePayloadCustomBo bo) {
return toAjax(manageDevicePayloadCustomService.insertByBo(bo));
}
/**
* 修改设备自定义/第三方载荷信息
*/
@SaCheckPermission("sample:DevicePayloadCustom:edit")
@Log(title = "设备自定义/第三方载荷信息", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ManageDevicePayloadCustomBo bo) {
return toAjax(manageDevicePayloadCustomService.updateByBo(bo));
}
/**
* 删除设备自定义/第三方载荷信息
*
* @param ids 主键串
*/
@SaCheckPermission("sample:DevicePayloadCustom:remove")
@Log(title = "设备自定义/第三方载荷信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(manageDevicePayloadCustomService.deleteWithValidByIds(List.of(ids), true));
}
}

110
dk-modules/sample/src/main/java/org/dromara/sample/manage/domain/ManageDevicePayloadCustom.java

@ -0,0 +1,110 @@
package org.dromara.sample.manage.domain;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.apache.ibatis.type.Alias;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 设备自定义/第三方载荷信息对象 manage_device_payload_custom
*
* @author szs
* @date 2025-06-18
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("manage_device_payload_custom")
public class ManageDevicePayloadCustom implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "id")
private Long id;
/**
* 载荷sn码
*/
@TableField("payload_sn")
private String payloadSn;
/**
* 载荷名称
*/
@TableField("payload_name")
private String payloadName;
/**
* 载荷类型
*/
@TableField("payload_type")
private String payloadType;
/**
* 父级Id
*/
@TableField("parent_id")
private Long parentId;
/**
* 设备版本
*/
@TableField("firmware_version")
private String firmwareVersion;
/**
* 所属机场
*/
@TableField("dock_sn")
private String dockSn;
/**
* 所属设备
*/
@TableField("device_sn")
private String deviceSn;
/**
* 所属无人机
*/
@TableField("drone_sn")
private String droneSn;
/**
* 设备中位置编号
*/
@TableField("payload_index")
private Long payloadIndex;
/**
* 是否启动(1启用0关闭)
*/
@TableField("enable_flag")
private Long enableFlag;
/**
* 设备描述
*/
@TableField("payload_desc")
private String payloadDesc;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}

99
dk-modules/sample/src/main/java/org/dromara/sample/manage/domain/bo/ManageDevicePayloadCustomBo.java

@ -0,0 +1,99 @@
package org.dromara.sample.manage.domain.bo;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonValue;
import org.dromara.sample.manage.domain.ManageDevicePayloadCustom;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 设备自定义/第三方载荷信息业务对象 manage_device_payload_custom
*
* @author szs
* @date 2025-06-18
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = ManageDevicePayloadCustom.class, reverseConvertGenerate = false)
public class ManageDevicePayloadCustomBo extends BaseEntity {
/**
* ID
*/
// @NotNull(message = "ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 载荷sn码
*/
// @NotBlank(message = "载荷sn码不能为空", groups = { AddGroup.class, EditGroup.class })
// @JsonValue("payloadSn")
@JsonAlias({"payload_sn"})
private String payloadSn;
/**
* 载荷名称
*/
// @NotBlank(message = "载荷名称不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonAlias({"payload_name"})
private String payloadName;
/**
* 载荷类型
*/
// @NotBlank(message = "载荷类型不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonAlias({"payload_type"})
private String payloadType;
/**
* 父级Id
*/
@JsonAlias({"parent_id"})
private Long parentId;
/**
* 设备版本
*/
@JsonAlias({"firmware_version"})
private String firmwareVersion;
/**
* 所属机场
*/
// @NotBlank(message = "所属机场不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonAlias({"dock_sn"})
private String dockSn;
/**
* 所属设备
*/
@JsonAlias({"device_sn"})
private String deviceSn;
/**
* 所属无人机
*/
private String droneSn;
/**
* 设备中位置编号
*/
private Long payloadIndex;
/**
* 是否启动(1启用0关闭)
*/
private Long enableFlag;
/**
* 设备描述
*/
private String payloadDesc;
}

100
dk-modules/sample/src/main/java/org/dromara/sample/manage/domain/vo/ManageDevicePayloadCustomVo.java

@ -0,0 +1,100 @@
package org.dromara.sample.manage.domain.vo;
import org.dromara.sample.manage.domain.ManageDevicePayloadCustom;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 设备自定义/第三方载荷信息视图对象 manage_device_payload_custom
*
* @author szs
* @date 2025-06-18
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = ManageDevicePayloadCustom.class)
public class ManageDevicePayloadCustomVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ExcelProperty(value = "ID")
private Long id;
/**
* 载荷sn码
*/
@ExcelProperty(value = "载荷sn码")
private String payloadSn;
/**
* 载荷名称
*/
@ExcelProperty(value = "载荷名称")
private String payloadName;
/**
* 载荷类型
*/
@ExcelProperty(value = "载荷类型")
private String payloadType;
/**
* 父级Id
*/
@ExcelProperty(value = "父级Id")
private Long parentId;
/**
* 设备版本
*/
@ExcelProperty(value = "设备版本")
private String firmwareVersion;
/**
* 所属机场
*/
@ExcelProperty(value = "所属机场")
private String dockSn;
/**
* 所属设备
*/
@ExcelProperty(value = "所属设备")
private String deviceSn;
/**
* 所属无人机
*/
@ExcelProperty(value = "所属无人机")
private String droneSn;
/**
* 设备中位置编号
*/
@ExcelProperty(value = "设备中位置编号")
private Long payloadIndex;
/**
* 是否启动(1启用0关闭)
*/
@ExcelProperty(value = "是否启动(1启用,0关闭)")
private Long enableFlag;
/**
* 设备描述
*/
@ExcelProperty(value = "设备描述")
private String payloadDesc;
}

15
dk-modules/sample/src/main/java/org/dromara/sample/manage/mapper/ManageDevicePayloadCustomMapper.java

@ -0,0 +1,15 @@
package org.dromara.sample.manage.mapper;
import org.dromara.sample.manage.domain.ManageDevicePayloadCustom;
import org.dromara.sample.manage.domain.vo.ManageDevicePayloadCustomVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 设备自定义/第三方载荷信息Mapper接口
*
* @author szs
* @date 2025-06-18
*/
public interface ManageDevicePayloadCustomMapper extends BaseMapperPlus<ManageDevicePayloadCustom, ManageDevicePayloadCustomVo> {
}

7
dk-modules/sample/src/main/java/org/dromara/sample/manage/model/dto/DeviceDTO.java

@ -1,11 +1,13 @@
package org.dromara.sample.manage.model.dto;
import cn.hutool.json.JSONObject;
import io.swagger.v3.oas.annotations.media.Schema;
import org.dromara.common.sdk.cloudapi.device.ControlSourceEnum;
import org.dromara.common.sdk.cloudapi.device.DeviceDomainEnum;
import org.dromara.common.sdk.cloudapi.device.DeviceSubTypeEnum;
import org.dromara.common.sdk.cloudapi.device.DeviceTypeEnum;
import org.dromara.common.sdk.cloudapi.tsa.DeviceIconUrl;
import org.dromara.sample.manage.domain.ManageDevicePayloadCustom;
import org.dromara.sample.manage.model.entity.DeviceProEntity;
import org.dromara.sample.manage.model.enums.DeviceFirmwareStatusEnum;
@ -117,4 +119,9 @@ public class DeviceDTO {
private Long pushDeptId;
private boolean spiritsmellFlag;//灵嗅设备状态:
private ManageDevicePayloadCustom payloadSpiritsmell;//灵嗅设备挂载:
private JSONObject osdData;//redis中的osd数据
}

10
dk-modules/sample/src/main/java/org/dromara/sample/manage/model/enums/PropertySetFieldEnum.java

@ -27,15 +27,15 @@ public enum PropertySetFieldEnum {
// EXIT_WAYLINE_WHEN_RC_LOST(PropertySetEnum.EXIT_WAYLINE_WHEN_RC_LOST, .class),
//
// THERMAL_CURRENT_PALETTE_STYLE(PropertySetEnum.THERMAL_CURRENT_PALETTE_STYLE, .class),
THERMAL_CURRENT_PALETTE_STYLE(PropertySetEnum.THERMAL_CURRENT_PALETTE_STYLE, ThermalCurrentPaletteStyleReceiver.class),
//
// THERMAL_GAIN_MODE(PropertySetEnum.THERMAL_GAIN_MODE, .class),
THERMAL_GAIN_MODE(PropertySetEnum.THERMAL_GAIN_MODE, ThermalGaiModeReceiver.class),
//
// THERMAL_ISOTHERM_STATE(PropertySetEnum.THERMAL_ISOTHERM_STATE, .class),
THERMAL_ISOTHERM_STATE(PropertySetEnum.THERMAL_ISOTHERM_STATE, ThermalIsothermStateReceiver.class),
//
// THERMAL_ISOTHERM_UPPER_LIMIT(PropertySetEnum.THERMAL_ISOTHERM_UPPER_LIMIT, .class),
THERMAL_ISOTHERM_UPPER_LIMIT(PropertySetEnum.THERMAL_ISOTHERM_UPPER_LIMIT, ThermalIsothermUpperLimitReceiver.class),
//
// THERMAL_ISOTHERM_LOWER_LIMIT(PropertySetEnum.THERMAL_ISOTHERM_LOWER_LIMIT, .class),
THERMAL_ISOTHERM_LOWER_LIMIT(PropertySetEnum.THERMAL_ISOTHERM_LOWER_LIMIT, ThermalIsothermLowerLimitReceiver.class),
;

17
dk-modules/sample/src/main/java/org/dromara/sample/manage/model/param/DeviceSubscribeParam.java

@ -0,0 +1,17 @@
package org.dromara.sample.manage.model.param;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.springframework.web.bind.annotation.RequestParam;
@Data
public class DeviceSubscribeParam {
@JsonProperty("action")
private String action;
@JsonProperty("token")
private String token;
@JsonProperty("dock_sn")
private String dockSn;
}

41
dk-modules/sample/src/main/java/org/dromara/sample/manage/model/receiver/ThermalCurrentPaletteStyleReceiver.java

@ -0,0 +1,41 @@
package org.dromara.sample.manage.model.receiver;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.dromara.common.sdk.cloudapi.device.OsdDockDrone;
import org.dromara.common.sdk.cloudapi.device.PayloadIndex;
import org.dromara.common.sdk.cloudapi.device.ThermalPaletteStyleEnum;
import org.dromara.common.sdk.cloudapi.property.ThermalCurrentPaletteStyleSet;
import java.util.Map;
import java.util.Objects;
/**
* @author sean.zhou
* @date 2021/11/18
* @version 0.1
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ThermalCurrentPaletteStyleReceiver extends BasicDeviceProperty {
private String payloadIndex;
private int thermalCurrentPaletteStyle;
@Override
public boolean valid() {
return Objects.nonNull(payloadIndex) && Objects.nonNull(thermalCurrentPaletteStyle);
}
@Override
public boolean canPublish(OsdDockDrone osd) {
return true;
}
}

36
dk-modules/sample/src/main/java/org/dromara/sample/manage/model/receiver/ThermalGaiModeReceiver.java

@ -0,0 +1,36 @@
package org.dromara.sample.manage.model.receiver;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.dromara.common.sdk.cloudapi.device.OsdDockDrone;
import java.util.Objects;
/**
* @author sean.zhou
* @date 2021/11/18
* @version 0.1
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ThermalGaiModeReceiver extends BasicDeviceProperty {
private String payloadIndex;
private int thermalGainMde;
@Override
public boolean valid() {
return Objects.nonNull(payloadIndex) && Objects.nonNull(thermalGainMde);
}
@Override
public boolean canPublish(OsdDockDrone osd) {
return true;
}
}

36
dk-modules/sample/src/main/java/org/dromara/sample/manage/model/receiver/ThermalIsothermLowerLimitReceiver.java

@ -0,0 +1,36 @@
package org.dromara.sample.manage.model.receiver;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.dromara.common.sdk.cloudapi.device.OsdDockDrone;
import java.util.Objects;
/**
* @author sean.zhou
* @date 2021/11/18
* @version 0.1
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ThermalIsothermLowerLimitReceiver extends BasicDeviceProperty {
private String payloadIndex;
private int thermalIsothermLowerLimit;
@Override
public boolean valid() {
return Objects.nonNull(payloadIndex) && Objects.nonNull(thermalIsothermLowerLimit);
}
@Override
public boolean canPublish(OsdDockDrone osd) {
return true;
}
}

36
dk-modules/sample/src/main/java/org/dromara/sample/manage/model/receiver/ThermalIsothermStateReceiver.java

@ -0,0 +1,36 @@
package org.dromara.sample.manage.model.receiver;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.dromara.common.sdk.cloudapi.device.OsdDockDrone;
import java.util.Objects;
/**
* @author sean.zhou
* @date 2021/11/18
* @version 0.1
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ThermalIsothermStateReceiver extends BasicDeviceProperty {
private String payloadIndex;
private int thermalIsothermState;
@Override
public boolean valid() {
return Objects.nonNull(payloadIndex) && Objects.nonNull(thermalIsothermState);
}
@Override
public boolean canPublish(OsdDockDrone osd) {
return true;
}
}

36
dk-modules/sample/src/main/java/org/dromara/sample/manage/model/receiver/ThermalIsothermUpperLimitReceiver.java

@ -0,0 +1,36 @@
package org.dromara.sample.manage.model.receiver;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.dromara.common.sdk.cloudapi.device.OsdDockDrone;
import java.util.Objects;
/**
* @author sean.zhou
* @date 2021/11/18
* @version 0.1
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ThermalIsothermUpperLimitReceiver extends BasicDeviceProperty {
private String payloadIndex;
private int thermalIsothermUpperLimit;
@Override
public boolean valid() {
return Objects.nonNull(payloadIndex) && Objects.nonNull(thermalIsothermUpperLimit);
}
@Override
public boolean canPublish(OsdDockDrone osd) {
return true;
}
}

20
dk-modules/sample/src/main/java/org/dromara/sample/manage/service/IDeviceProService.java

@ -2,24 +2,13 @@ package org.dromara.sample.manage.service;
import cn.hutool.core.lang.Dict;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.sdk.cloudapi.device.ControlSourceEnum;
import org.dromara.common.sdk.cloudapi.device.DeviceOsdHost;
import org.dromara.common.sdk.cloudapi.device.DockModeCodeEnum;
import org.dromara.common.sdk.cloudapi.device.DroneModeCodeEnum;
import org.dromara.common.sdk.common.HttpResultResponse;
import org.dromara.common.sdk.common.PaginationData;
import org.dromara.common.sdk.config.version.GatewayManager;
import org.dromara.common.websocket.dto.BizCodeEnum;
import org.dromara.sample.manage.model.dto.*;
import org.dromara.sample.manage.model.entity.DeviceProEntity;
import org.dromara.sample.manage.model.entity.DeviceProUserEntity;
import org.dromara.sample.manage.model.param.DeviceQueryParam;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Map;
/**
* @author sean.zhou
@ -36,7 +25,9 @@ public interface IDeviceProService {
Boolean updateDevicePro(DeviceProEntity deviceProEntity);
Boolean updateDeviceProUser(List<DeviceProUserEntity> userEntity,Integer proId);
Boolean updateDeviceProUser(List<DeviceProUserEntity> userEntity, Integer proId);
Boolean updateDeviceProUserNew(List<Map<String, Object>> userEntity, Integer proId);
Boolean updateDevice(Dict dict);
@ -56,4 +47,7 @@ public interface IDeviceProService {
List<DeviceProEntity> listUserGroup();
Boolean initProRedisCache();
}

12
dk-modules/sample/src/main/java/org/dromara/sample/manage/service/IDeviceRedisService.java

@ -1,10 +1,12 @@
package org.dromara.sample.manage.service;
import cn.hutool.json.JSONObject;
import org.dromara.common.sdk.cloudapi.device.OsdDockDrone;
import org.dromara.common.sdk.cloudapi.device.VideoId;
import org.dromara.common.sdk.cloudapi.firmware.OtaProgress;
import org.dromara.sample.component.mqtt.model.EventsReceiver;
import org.dromara.sample.manage.model.dto.DeviceDTO;
import org.dromara.sample.wayline.domain.bo.WaylineJobAtmosphereBo;
import java.util.List;
import java.util.Optional;
@ -135,4 +137,14 @@ public interface IDeviceRedisService {
Optional<VideoId> getDeviceVideo(String sn, Object data);
Boolean delDeviceVideo(String sn);
void setDeviceSpiritSmellOnline(String deviceSn, WaylineJobAtmosphereBo data);
boolean checkDeviceSpiritSmell(String deviceSn);
Optional<WaylineJobAtmosphereBo> getDeviceSpiritSmellOnline(String deviceSn);
void pushDeviceSpiritSmellList(String deviceSn, WaylineJobAtmosphereBo jobAtmosphere);
JSONObject getDevicesOsdList(String type);
}

2
dk-modules/sample/src/main/java/org/dromara/sample/manage/service/IDeviceService.java

@ -167,6 +167,8 @@ public interface IDeviceService {
*/
int devicePropertySet(String workspaceId, String dockSn, JsonNode param);
int devicePropertySetData(String workspaceId, String dockSn, JsonNode param);
/**
* Check the working status of the dock.
* @param dockSn

68
dk-modules/sample/src/main/java/org/dromara/sample/manage/service/IManageDevicePayloadCustomService.java

@ -0,0 +1,68 @@
package org.dromara.sample.manage.service;
import org.dromara.sample.manage.domain.vo.ManageDevicePayloadCustomVo;
import org.dromara.sample.manage.domain.bo.ManageDevicePayloadCustomBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 设备自定义/第三方载荷信息Service接口
*
* @author szs
* @date 2025-06-18
*/
public interface IManageDevicePayloadCustomService {
/**
* 查询设备自定义/第三方载荷信息
*
* @param id 主键
* @return 设备自定义/第三方载荷信息
*/
ManageDevicePayloadCustomVo queryById(Long id);
/**
* 分页查询设备自定义/第三方载荷信息列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 设备自定义/第三方载荷信息分页列表
*/
TableDataInfo<ManageDevicePayloadCustomVo> queryPageList(ManageDevicePayloadCustomBo bo, PageQuery pageQuery);
/**
* 查询符合条件的设备自定义/第三方载荷信息列表
*
* @param bo 查询条件
* @return 设备自定义/第三方载荷信息列表
*/
List<ManageDevicePayloadCustomVo> queryList(ManageDevicePayloadCustomBo bo);
/**
* 新增设备自定义/第三方载荷信息
*
* @param bo 设备自定义/第三方载荷信息
* @return 是否新增成功
*/
Boolean insertByBo(ManageDevicePayloadCustomBo bo);
/**
* 修改设备自定义/第三方载荷信息
*
* @param bo 设备自定义/第三方载荷信息
* @return 是否修改成功
*/
Boolean updateByBo(ManageDevicePayloadCustomBo bo);
/**
* 校验并批量删除设备自定义/第三方载荷信息信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

182
dk-modules/sample/src/main/java/org/dromara/sample/manage/service/impl/DeviceProServiceImpl.java

@ -1,73 +1,36 @@
package org.dromara.sample.manage.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.impl.BeanConverter;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.BatchResult;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.redis.utils.RedisOpsUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.sdk.cloudapi.device.*;
import org.dromara.common.sdk.cloudapi.firmware.*;
import org.dromara.common.sdk.cloudapi.firmware.api.AbstractFirmwareService;
import org.dromara.common.sdk.cloudapi.property.api.AbstractPropertyService;
import org.dromara.common.sdk.cloudapi.tsa.DeviceIconUrl;
import org.dromara.common.sdk.cloudapi.tsa.TopologyDeviceModel;
import org.dromara.common.sdk.common.*;
import org.dromara.common.sdk.config.version.GatewayManager;
import org.dromara.common.sdk.exception.CloudSDKException;
import org.dromara.common.sdk.mqtt.IMqttTopicService;
import org.dromara.common.sdk.mqtt.MqttGatewayPublish;
import org.dromara.common.sdk.mqtt.events.EventsSubscribe;
import org.dromara.common.sdk.mqtt.osd.OsdSubscribe;
import org.dromara.common.sdk.mqtt.property.PropertySetReplyResultEnum;
import org.dromara.common.sdk.mqtt.property.PropertySetSubscribe;
import org.dromara.common.sdk.mqtt.requests.RequestsSubscribe;
import org.dromara.common.sdk.mqtt.services.ServicesReplyData;
import org.dromara.common.sdk.mqtt.services.ServicesSubscribe;
import org.dromara.common.sdk.mqtt.services.TopicServicesResponse;
import org.dromara.common.sdk.mqtt.state.StateSubscribe;
import org.dromara.common.sdk.mqtt.status.StatusSubscribe;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.websocket.dto.BizCodeEnum;
import org.dromara.sample.common.error.CommonErrorEnum;
import org.dromara.sample.component.mqtt.model.EventsReceiver;
import org.dromara.sample.control.model.enums.DroneAuthorityEnum;
import org.dromara.sample.feign.RemoteSystemFeign;
import org.dromara.sample.manage.mapper.IDeviceMapper;
import org.dromara.sample.manage.mapper.IDeviceProMapper;
import org.dromara.sample.manage.mapper.IDeviceProUserMapper;
import org.dromara.sample.manage.mapper.IDeviceQrtzMapper;
import org.dromara.sample.manage.model.dto.*;
import org.dromara.sample.manage.model.entity.DeviceEntity;
import org.dromara.sample.manage.model.entity.DeviceProEntity;
import org.dromara.sample.manage.model.entity.DeviceProUserEntity;
import org.dromara.sample.manage.model.entity.DeviceQrtzDateEntity;
import org.dromara.sample.manage.model.enums.DeviceFirmwareStatusEnum;
import org.dromara.sample.manage.model.enums.PropertySetFieldEnum;
import org.dromara.sample.manage.model.enums.UserTypeEnum;
import org.dromara.sample.manage.model.param.DeviceQueryParam;
import org.dromara.sample.manage.model.receiver.BasicDeviceProperty;
import org.dromara.sample.manage.service.*;
import org.dromara.sample.websocket.service.IWebSocketMessageService;
import org.dromara.system.api.domain.vo.RemoteUserVo;
import org.dromara.system.api.model.LoginUser;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@ -90,6 +53,9 @@ public class DeviceProServiceImpl implements IDeviceProService {
@Autowired
private IDeviceProUserMapper deviceProUserMapper;
@Autowired
RemoteSystemFeign remoteSystemFeign;
@Override
public PaginationData<DeviceProEntity> listDeviceProEntityMap(Page page, DeviceProDTO deviceProDTO) {
@ -127,8 +93,7 @@ public class DeviceProServiceImpl implements IDeviceProService {
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateDeviceProUser(List<DeviceProUserEntity> userEntity,Integer proId) {
public Boolean updateDeviceProUser(List<DeviceProUserEntity> userEntity, Integer proId) {
try {
List<DeviceProUserEntity> proUserEntityList = deviceProUserMapper.selectList(new LambdaQueryWrapper<DeviceProUserEntity>().eq(DeviceProUserEntity::getDeviceProId, proId));
@ -142,6 +107,51 @@ public class DeviceProServiceImpl implements IDeviceProService {
deviceProUserMapper.insert(different);
}
//更新设备组redis缓存
Boolean flag = updateDeviceProCache("update",null);
return true;
} catch (ServiceException e) {
log.error(e.getMessage(),e);
return false;
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateDeviceProUserNew(List<Map<String, Object>> userEntity, Integer proId) {
try {
List<Map<String, Object>> resultList = remoteSystemFeign.listTargetTypeByUser(userEntity);
//构建DeviceProUserEntity集合
List<DeviceProUserEntity> userEntityList = new ArrayList<>();
resultList.forEach(resultMap -> {
DeviceProUserEntity deviceProUserEntity = new DeviceProUserEntity();
deviceProUserEntity.setDeviceProId(proId);
deviceProUserEntity.setUserId(Long.valueOf(resultMap.get("userId") + ""));
deviceProUserEntity.setUserName(resultMap.get("userName") + "");
deviceProUserEntity.setNickName(resultMap.get("nickName") + "");
userEntityList.add(deviceProUserEntity);
});
List<DeviceProUserEntity> proUserEntityList = deviceProUserMapper.selectList(new LambdaQueryWrapper<DeviceProUserEntity>().eq(DeviceProUserEntity::getDeviceProId, proId));
List<DeviceProUserEntity> different = userEntityList.stream()
.filter(user -> proUserEntityList.stream().noneMatch(u -> u.getUserId().equals(user.getUserId())))
.toList();
if (ObjectUtil.isNotEmpty(different)){
//添加新的项目组成员
deviceProUserMapper.insert(different);
}
//更新设备组redis缓存
Boolean flag = updateDeviceProCache("update",null);
return true;
} catch (ServiceException e) {
log.error(e.getMessage(),e);
@ -149,6 +159,67 @@ public class DeviceProServiceImpl implements IDeviceProService {
}
}
/**
* 更新设备组人员缓存
* @return
*/
private Boolean updateDeviceProCache(String operateType,Long proUserId) {
try {
// -------------------------------------- redis缓存 ---------------------------------------------------
//更新redis缓存
//1、如何存储redis 人员 项目组id device_pro:userId -> List<Long> proIdList
// device_pro:
//查询所有的用户-设备组信息
List<DeviceProUserEntity> proUserList = deviceProUserMapper.selectList(new LambdaQueryWrapper<>());
//分组
Map<Long, List<Integer>> proUserMap = proUserList.stream()
.collect(Collectors.groupingBy(
DeviceProUserEntity::getUserId, // 按 userId 分组
Collectors.mapping(DeviceProUserEntity::getDeviceProId, Collectors.toList()) // 收集每个 userId 对应的 DeviceProId 列表
));
//如果是删除操作
if (operateType.equalsIgnoreCase("delete")){
if (!proUserMap.containsKey(proUserId)){
if (RedisUtils.hasKey("device_pro:" + proUserId)){
RedisUtils.deleteObject("device_pro:" + proUserId);
}
}
}
//更新redis设备组信息
proUserMap.keySet().forEach(userId -> {
//获取最新的用户设备组信息
List<Integer> currentProId = proUserMap.get(userId);
List<Integer> cacheList = RedisUtils.getCacheList("device_pro:" + userId);
log.info("设备组缓存:{}",cacheList);
//删除这个用户的设备组信息
if (RedisUtils.hasKey("device_pro:" + userId)){
RedisUtils.deleteObject("device_pro:" + userId);
}
//更新设备组信息
RedisUtils.setCacheList("device_pro:" + userId, currentProId);
});
// -------------------------------------- redis缓存 ---------------------------------------------------
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 绑定设备的项目组
* @param dict
@ -183,6 +254,15 @@ public class DeviceProServiceImpl implements IDeviceProService {
*/
@Override
public List<Integer> listDeviceGroup(Long userId) {
try {
List<Integer> userIds = RedisUtils.getCacheList("device_pro:" + userId);
// List<Object> collect = RedisOpsUtils.listGetAll("device_pro:" + userId);
// List<Integer> userIds = collect.stream().map(item -> (Integer) item).collect(Collectors.toList());
if (CollUtil.isNotEmpty(userIds)) {return userIds;}//从缓存直接读取
} catch (Exception e) {
System.out.println("找不到pro用户" + "device_pro" + userId);
}
LambdaQueryWrapper<DeviceProUserEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DeviceProUserEntity::getUserId,userId);
List<DeviceProUserEntity> proUserEntityList = deviceProUserMapper.selectList(wrapper);
@ -265,7 +345,15 @@ public class DeviceProServiceImpl implements IDeviceProService {
LambdaQueryWrapper<DeviceProUserEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DeviceProUserEntity::getDeviceProId,proId);
wrapper.eq(DeviceProUserEntity::getId,proUserId);
return deviceProUserMapper.delete(wrapper) > 0;
DeviceProUserEntity deviceProUserEntity = deviceProUserMapper.selectById(proUserId);
int flag = deviceProUserMapper.delete(wrapper);
//更新缓存
updateDeviceProCache("delete",deviceProUserEntity.getUserId());
return flag > 0;
}
@Override
@ -286,6 +374,12 @@ public class DeviceProServiceImpl implements IDeviceProService {
return ListUtil.empty();
}
@Override
public Boolean initProRedisCache() {
return this.updateDeviceProCache("init",null);
}
@Override
public Boolean saveAndUpdate(DeviceProEntity entity) {
boolean flag = true;

140
dk-modules/sample/src/main/java/org/dromara/sample/manage/service/impl/DeviceRedisServiceImpl.java

@ -1,8 +1,14 @@
package org.dromara.sample.manage.service.impl;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import org.dromara.common.redis.config.RedisConst;
import org.dromara.common.redis.utils.RedisOpsUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.sdk.cloudapi.device.DockDronePayload;
import org.dromara.common.sdk.cloudapi.device.OsdDock;
import org.dromara.common.sdk.cloudapi.device.OsdDockDrone;
import org.dromara.common.sdk.cloudapi.device.VideoId;
import org.dromara.common.sdk.cloudapi.firmware.OtaProgress;
@ -10,6 +16,7 @@ import org.dromara.sample.component.mqtt.model.EventsReceiver;
import org.dromara.sample.manage.model.dto.DeviceDTO;
import org.dromara.sample.manage.service.ICapacityCameraService;
import org.dromara.sample.manage.service.IDeviceRedisService;
import org.dromara.sample.wayline.domain.bo.WaylineJobAtmosphereBo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -41,6 +48,125 @@ public class DeviceRedisServiceImpl implements IDeviceRedisService {
return Optional.ofNullable((DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + sn));
}
@Override
public JSONObject getDevicesOsdList(String type) {
JSONObject resJsonObject = new JSONObject(); //机场 droneInDock
Set<String> osdKeys = RedisOpsUtils.getAllKeys(RedisConst.OSD_PREFIX+"*");
for (String osdKey : osdKeys) {
Object osdObj = RedisOpsUtils.get(osdKey);
if(StrUtil.equals(type,"dock") && osdObj instanceof OsdDockDrone ){continue;}
if(StrUtil.equals(type,"drone") && osdObj instanceof OsdDock){continue;}
//处理机场数据
/**
* {
* "droneChargeState": {
* "state": false,
* "capacityPercent": 90
* },
* "latitude": 34.64393,
* "longitude": 116.82873,
* "height": 37.8021,
* "modeCode": 0
* }
*/
if(osdObj instanceof OsdDock ){ //org.plough.sdk.cloudapi.device.OsdDock
OsdDock dock = (OsdDock) osdObj;
// OsdDockVo osdDockVo = new OsdDockVo();
// BeanUtil.copyProperties(dock, osdDockVo);
JSONObject item = new JSONObject();
item.put("droneChargeState", dock.getDroneChargeState());
item.put("latitude", dock.getLatitude());
item.put("longitude", dock.getLongitude());
item.put("height", dock.getHeight());
item.put("modeCode", dock.getModeCode());
resJsonObject.put(osdKey.replaceFirst(RedisConst.OSD_PREFIX,""), item);
//处理无人机数据
/**
* {
* "attitudeHead": -177,
* "attitudePitch": 0.9,
* "attitudeRoll": -0.8,
* "battery": {
* "capacityPercent": 89,
* "landingPower": 8,
* "remainFlightTime": 0,
* "returnHomePower": 25
* },
* "height": 63.853302,
* "latitude": 34.19659,
* "longitude": 117.0838,
* "modeCode": 5,
* "trackId": "48f03cfa-4c61-4cff-8388-faac69605426",
* "payload": [
* {
* "payloadIndex": "81-0-0",
* "gimbalPitch": 0,
* "gimbalRoll": 0,
* "gimbalYaw": -177.15698
* }
* ]
* }
*/
// }else if(osdObj.getClass().getName().equals("org.plough.sdk.cloudapi.device.OsdDockDrone") ){ //org.plough.sdk.cloudapi.device.OsdDockDrone
}else if(osdObj instanceof OsdDockDrone){ //org.plough.sdk.cloudapi.device.OsdDockDrone
OsdDockDrone dockDrone = (OsdDockDrone) osdObj;
// OsdDockDroneVo dockDroneVo = new OsdDockDroneVo();
// BeanUtil.copyProperties(dockDrone, dockDroneVo);
JSONObject item = new JSONObject();
item.put("attitudeHead", dockDrone.getAttitudeHead());
item.put("attitudePitch", dockDrone.getAttitudePitch());
item.put("attitudeRoll", dockDrone.getAttitudeRoll());
if (dockDrone.getBattery() != null) {
JSONObject battery = new JSONObject();
battery.put("capacityPercent", dockDrone.getBattery().getCapacityPercent());
battery.put("landingPower", dockDrone.getBattery().getLandingPower());
battery.put("remainFlightTime", dockDrone.getBattery().getRemainFlightTime());
battery.put("returnHomePower", dockDrone.getBattery().getReturnHomePower());
item.put("battery", battery);
}
item.put("height", dockDrone.getHeight());
item.put("latitude", dockDrone.getLatitude());
item.put("longitude", dockDrone.getLongitude());
item.put("modeCode", dockDrone.getModeCode());
item.put("trackId", dockDrone.getTrackId());
// payload(只保留4个字段)
if (dockDrone.getPayloads() != null && !dockDrone.getPayloads().isEmpty()) {
JSONArray payloadArray = new JSONArray();
for (DockDronePayload payload : dockDrone.getPayloads()) {
JSONObject payloadObj = new JSONObject();
payloadObj.put("payloadIndex", payload.getPayloadIndex());
payloadObj.put("gimbalPitch", payload.getGimbalPitch());
payloadObj.put("gimbalRoll", payload.getGimbalRoll());
payloadObj.put("gimbalYaw", payload.getGimbalYaw());
payloadArray.add(payloadObj);
}
item.put("payload", payloadArray);
}
resJsonObject.put(osdKey.replaceFirst(RedisConst.OSD_PREFIX, ""), item);
}
}
return resJsonObject;
}
@Override
public Optional<WaylineJobAtmosphereBo> getDeviceSpiritSmellOnline(String deviceSn) {
return Optional.ofNullable((WaylineJobAtmosphereBo) RedisOpsUtils.get(RedisConst.DEVICE_SPIRITSMELL_PREFIX + deviceSn));
}
@Override
public void pushDeviceSpiritSmellList(String deviceSn, WaylineJobAtmosphereBo jobAtmosphere) {
RedisOpsUtils.listRPush(RedisConst.DEVICE_SPIRITSMELL_LIST_PREFIX + deviceSn,jobAtmosphere);
// RedisOpsUtils.setWithExpire(RedisConst.DEVICE_SPIRITSMELL_PREFIX + deviceSn, data, 30);
}
@Override
public void setDeviceOnline(DeviceDTO device) {
RedisOpsUtils.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn(), device, RedisConst.DEVICE_ALIVE_SECOND);
@ -51,6 +177,20 @@ public class DeviceRedisServiceImpl implements IDeviceRedisService {
return RedisOpsUtils.del(RedisConst.DEVICE_ONLINE_PREFIX + sn);
}
@Override
public void setDeviceSpiritSmellOnline(String deviceSn, WaylineJobAtmosphereBo data) {
RedisOpsUtils.setWithExpire(RedisConst.DEVICE_SPIRITSMELL_PREFIX + deviceSn, data, 30);
}
@Override
public boolean checkDeviceSpiritSmell(String deviceSn) {
return RedisOpsUtils.checkExist(RedisConst.DEVICE_SPIRITSMELL_PREFIX + deviceSn);
// &&
// RedisOpsUtils.getExpire(RedisConst.DEVICE_SPIRITSMELL_PREFIX + deviceSn) > 0 ;
// BooleanUtil.toBoolean(RedisOpsUtils.get(RedisConst.DEVICE_SPIRITSMELL_PREFIX + deviceSn).toString());
}
@Override
public void setDeviceOsd(String sn, Object data) {
RedisOpsUtils.setWithExpire(RedisConst.OSD_PREFIX + sn, data, RedisConst.DEVICE_ALIVE_SECOND);

57
dk-modules/sample/src/main/java/org/dromara/sample/manage/service/impl/DeviceServiceImpl.java

@ -1,5 +1,7 @@
package org.dromara.sample.manage.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -32,8 +34,10 @@ import org.dromara.common.websocket.dto.BizCodeEnum;
import org.dromara.sample.common.error.CommonErrorEnum;
import org.dromara.sample.component.mqtt.model.EventsReceiver;
import org.dromara.sample.control.model.enums.DroneAuthorityEnum;
import org.dromara.sample.manage.domain.ManageDevicePayloadCustom;
import org.dromara.sample.manage.mapper.IDeviceMapper;
import org.dromara.sample.manage.mapper.IDeviceProMapper;
import org.dromara.sample.manage.mapper.ManageDevicePayloadCustomMapper;
import org.dromara.sample.manage.model.dto.*;
import org.dromara.sample.manage.model.entity.DeviceEntity;
import org.dromara.sample.manage.model.entity.DeviceProEntity;
@ -61,6 +65,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.dromara.common.core.utils.StringUtils.DASH;
import static org.dromara.common.core.utils.StringUtils.SLASH;
@ -139,6 +144,9 @@ public class DeviceServiceImpl implements IDeviceService {
@Autowired
private IDeviceProMapper deviceProMapper;
@Autowired
private ManageDevicePayloadCustomMapper manageDevicePayloadCustomMapper;
@Autowired
private IDeviceProService deviceProService;
@ -264,6 +272,21 @@ public class DeviceServiceImpl implements IDeviceService {
deviceRedisService.checkDeviceOnline(gateway.getDeviceSn()))
.forEach(this::spliceDeviceTopo);
//验证第三方挂载状态(灵嗅)
List<String> deviceSnList = devicesList.stream().map(DeviceDTO::getDeviceSn).collect(Collectors.toList());
LambdaQueryWrapper<ManageDevicePayloadCustom> payloadCustomMapper = new LambdaQueryWrapper<>();
payloadCustomMapper.in(CollUtil.isNotEmpty(deviceSnList),ManageDevicePayloadCustom::getDockSn, deviceSnList);
List<ManageDevicePayloadCustom> payloadCustomList = manageDevicePayloadCustomMapper.selectList(payloadCustomMapper);
for (DeviceDTO deviceDTO : devicesList) {
ManageDevicePayloadCustom spiritsmellV2 = payloadCustomList.stream().filter(item ->
ObjectUtil.equals(item.getDockSn(), deviceDTO.getDeviceSn()) &&
ObjectUtil.equals(item.getPayloadName(), "spiritsmellV2")).findFirst().orElse(null);
// long spiritsmellV2Count = payloadCustomList.stream().filter(item ->
// ObjectUtil.equals(item.getDockSn(), deviceDTO.getDeviceSn()) &&
// ObjectUtil.equals(item.getPayloadName(), "spiritsmellV2")).count();
deviceDTO.setPayloadSpiritsmell(spiritsmellV2);
}
return devicesList;
}
@ -271,6 +294,7 @@ public class DeviceServiceImpl implements IDeviceService {
public void spliceDeviceTopo(DeviceDTO gateway) {
gateway.setStatus(deviceRedisService.checkDeviceOnline(gateway.getDeviceSn()));
gateway.setSpiritsmellFlag(deviceRedisService.checkDeviceSpiritSmell(gateway.getDeviceSn()));//验证是否有灵嗅在线
// sub device
if (!StringUtils.hasText(gateway.getChildDeviceSn())) {
@ -693,6 +717,39 @@ public class DeviceServiceImpl implements IDeviceService {
return result.getResult();
}
@Override
public int devicePropertySetData(String workspaceId, String dockSn, JsonNode param) {
String property = param.fieldNames().next();
PropertySetFieldEnum propertyEnum = PropertySetFieldEnum.find(property);
Optional<DeviceDTO> dockOpt = deviceRedisService.getDeviceOnline(dockSn);
if (dockOpt.isEmpty()) {
throw new RuntimeException("Dock处于脱机状态。");
}
String childSn = dockOpt.get().getChildDeviceSn();
Optional<OsdDockDrone> osdOpt = deviceRedisService.getDeviceOsd(childSn, OsdDockDrone.class);
if (osdOpt.isEmpty()) {
throw new RuntimeException("设备处于脱机状态。");
}
// Make sure the data is valid.
BasicDeviceProperty basicDeviceProperty = objectMapper.convertValue(param.get(property), propertyEnum.getClazz());
boolean valid = basicDeviceProperty.valid();
if (!valid) {
throw new IllegalArgumentException(CommonErrorEnum.ILLEGAL_ARGUMENT.getMessage());
}
boolean isPublish = basicDeviceProperty.canPublish(osdOpt.get());
if (!isPublish) {
return PropertySetReplyResultEnum.SUCCESS.getResult();
}
BaseModel baseModel = objectMapper.convertValue(param.get(property), propertyEnum.getProperty().getClazz());
PropertySetReplyResultEnum result = abstractPropertyService.propertySet(
SDKManager.getDeviceSDK(dockSn), propertyEnum.getProperty(), baseModel);
return result.getResult();
}
@Override
public DockModeCodeEnum getDockMode(String dockSn) {
return deviceRedisService.getDeviceOsd(dockSn, OsdDock.class)

139
dk-modules/sample/src/main/java/org/dromara/sample/manage/service/impl/ManageDevicePayloadCustomServiceImpl.java

@ -0,0 +1,139 @@
package org.dromara.sample.manage.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.sample.manage.domain.bo.ManageDevicePayloadCustomBo;
import org.dromara.sample.manage.domain.vo.ManageDevicePayloadCustomVo;
import org.dromara.sample.manage.domain.ManageDevicePayloadCustom;
import org.dromara.sample.manage.mapper.ManageDevicePayloadCustomMapper;
import org.dromara.sample.manage.service.IManageDevicePayloadCustomService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 设备自定义/第三方载荷信息Service业务层处理
*
* @author szs
* @date 2025-06-18
*/
@RequiredArgsConstructor
@Service
public class ManageDevicePayloadCustomServiceImpl implements IManageDevicePayloadCustomService {
private final ManageDevicePayloadCustomMapper baseMapper;
/**
* 查询设备自定义/第三方载荷信息
*
* @param id 主键
* @return 设备自定义/第三方载荷信息
*/
@Override
public ManageDevicePayloadCustomVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 分页查询设备自定义/第三方载荷信息列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 设备自定义/第三方载荷信息分页列表
*/
@Override
public TableDataInfo<ManageDevicePayloadCustomVo> queryPageList(ManageDevicePayloadCustomBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<ManageDevicePayloadCustom> lqw = buildQueryWrapper(bo);
Page<ManageDevicePayloadCustomVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的设备自定义/第三方载荷信息列表
*
* @param bo 查询条件
* @return 设备自定义/第三方载荷信息列表
*/
@Override
public List<ManageDevicePayloadCustomVo> queryList(ManageDevicePayloadCustomBo bo) {
LambdaQueryWrapper<ManageDevicePayloadCustom> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<ManageDevicePayloadCustom> buildQueryWrapper(ManageDevicePayloadCustomBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<ManageDevicePayloadCustom> lqw = Wrappers.lambdaQuery();
lqw.eq(StringUtils.isNotBlank(bo.getPayloadSn()), ManageDevicePayloadCustom::getPayloadSn, bo.getPayloadSn());
lqw.like(StringUtils.isNotBlank(bo.getPayloadName()), ManageDevicePayloadCustom::getPayloadName, bo.getPayloadName());
lqw.eq(StringUtils.isNotBlank(bo.getPayloadType()), ManageDevicePayloadCustom::getPayloadType, bo.getPayloadType());
lqw.eq(bo.getParentId() != null, ManageDevicePayloadCustom::getParentId, bo.getParentId());
lqw.eq(StringUtils.isNotBlank(bo.getFirmwareVersion()), ManageDevicePayloadCustom::getFirmwareVersion, bo.getFirmwareVersion());
lqw.eq(StringUtils.isNotBlank(bo.getDockSn()), ManageDevicePayloadCustom::getDockSn, bo.getDockSn());
lqw.eq(StringUtils.isNotBlank(bo.getDeviceSn()), ManageDevicePayloadCustom::getDeviceSn, bo.getDeviceSn());
lqw.eq(StringUtils.isNotBlank(bo.getDroneSn()), ManageDevicePayloadCustom::getDroneSn, bo.getDroneSn());
lqw.eq(bo.getPayloadIndex() != null, ManageDevicePayloadCustom::getPayloadIndex, bo.getPayloadIndex());
lqw.eq(bo.getEnableFlag() != null, ManageDevicePayloadCustom::getEnableFlag, bo.getEnableFlag());
lqw.eq(StringUtils.isNotBlank(bo.getPayloadDesc()), ManageDevicePayloadCustom::getPayloadDesc, bo.getPayloadDesc());
return lqw;
}
/**
* 新增设备自定义/第三方载荷信息
*
* @param bo 设备自定义/第三方载荷信息
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(ManageDevicePayloadCustomBo bo) {
ManageDevicePayloadCustom add = MapstructUtils.convert(bo, ManageDevicePayloadCustom.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改设备自定义/第三方载荷信息
*
* @param bo 设备自定义/第三方载荷信息
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(ManageDevicePayloadCustomBo bo) {
ManageDevicePayloadCustom update = MapstructUtils.convert(bo, ManageDevicePayloadCustom.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(ManageDevicePayloadCustom entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除设备自定义/第三方载荷信息信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

77
dk-modules/sample/src/main/java/org/dromara/sample/media/controller/FileController.java

@ -1,21 +1,34 @@
package org.dromara.sample.media.controller;
import cn.hutool.core.util.ObjectUtil;
import com.amazonaws.util.IOUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.sdk.common.HttpResultResponse;
import org.dromara.common.sdk.common.PaginationData;
import org.dromara.sample.manage.service.IDeviceProService;
import org.dromara.sample.media.model.MediaFileDTO;
import org.dromara.sample.media.model.MediaFileEntity;
import org.dromara.sample.media.service.IFileService;
import org.dromara.sample.wayline.service.IWaylineJobService;
import org.dromara.system.api.model.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.Optional;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @author sean
@ -30,6 +43,9 @@ public class FileController {
@Autowired
private IFileService fileService;
@Autowired
private IWaylineJobService waylineJobService;
/**
@ -81,11 +97,68 @@ public class FileController {
@RequestParam(name = "type", required = false) Integer type) {
PaginationData<MediaFileDTO> filesList = fileService.getMediaFilesPaginationByJobId(workspaceId, page, pageSize,jobId,type);
for (MediaFileDTO mediaFileDTO :filesList.getList()){
mediaFileDTO.setUrl(fileService.getObjectUrl(workspaceId, mediaFileDTO.getFileId()).toString());
mediaFileDTO.setUrl(fileService.getObjectUrl(mediaFileDTO.getObjectKey()).toString());
}
return HttpResultResponse.success(filesList);
}
@GetMapping("/{workspace_id}/file/downloadZip/{job_id}")
public void downloadZip( HttpServletResponse response, @PathVariable(name = "workspace_id") String workspaceId,
@PathVariable(name = "job_id") String jobId, @RequestParam(name = "jobName", required = false) String jobName) throws IOException {
List<String> mediaFileDTO = fileService.getFilesByWorkspaceAndJobId(workspaceId, jobId).stream().map(MediaFileDTO::getObjectKey).toList();
if(mediaFileDTO.size() == 0){
throw new ServiceException("文件不存在");
}
OssClient storage = OssFactory.instance("mediafile");
response.setContentType("application/zip");
if(ObjectUtil.isNull(jobName)){
jobName = waylineJobService.getJobByJobId(workspaceId,jobId).get().getJobName();
}
String encodedJobName = URLEncoder.encode(jobName, "UTF-8");
response.setHeader("Content-Disposition", "attachment; filename="+encodedJobName+".zip");
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
byte[] buffer = new byte[1024];
for (String objectKey : mediaFileDTO) {
try (InputStream inputStream = storage.getObjectContent(objectKey)) {
// 创建一个新的 ZIP 条目
zipOut.putNextEntry(new ZipEntry(objectKey));
int len;
// 读取文件内容并写入到 ZIP 输出流
while ((len = inputStream.read(buffer)) != -1) {
zipOut.write(buffer, 0, len);
}
// 完成当前条目的写入
zipOut.closeEntry();
} catch (IOException e) {
e.printStackTrace(); // 如果有某个文件出错,跳过该文件并继续处理其他文件
}
}
zipOut.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
@GetMapping("/{workspace_id}/file/download/{file_id}")
public void downloadZip( HttpServletResponse response, @PathVariable(name = "workspace_id") String workspaceId,
@PathVariable(name = "file_id") String fileId) throws IOException {
Optional<MediaFileEntity> mediaFileDTO = fileService.getObjectByFileId(workspaceId,fileId);
OssClient storage = OssFactory.instance("mediafile");
String jobName = waylineJobService.getJobByJobId(workspaceId,mediaFileDTO.get().getJobId()).get().getJobName();
String[] filePaths = mediaFileDTO.get().getObjectKey().split("\\.");
FileUtils.setAttachmentResponseHeader(response, jobName+"."+filePaths[filePaths.length-1]);
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
long contentLength = storage.download(mediaFileDTO.get().getObjectKey(), response.getOutputStream());
response.setContentLengthLong(contentLength);
}
/**
* 根据文件id查询图片的偏航角
* @param fileId

6
dk-modules/sample/src/main/java/org/dromara/sample/media/service/IFileService.java

@ -4,9 +4,11 @@ import org.dromara.common.sdk.cloudapi.media.FlightTask;
import org.dromara.common.sdk.cloudapi.media.MediaUploadCallbackRequest;
import org.dromara.common.sdk.common.PaginationData;
import org.dromara.sample.media.model.MediaFileDTO;
import org.dromara.sample.media.model.MediaFileEntity;
import java.net.URL;
import java.util.List;
import java.util.Optional;
/**
* @author sean
@ -55,6 +57,10 @@ public interface IFileService {
*/
URL getObjectUrl(String workspaceId, String fileId);
Optional<MediaFileEntity> getObjectByFileId(String workspaceId, String fileId);
URL getObjectUrl(String objectKey);
/**
* Query all media files of a job.
* @param workspaceId

17
dk-modules/sample/src/main/java/org/dromara/sample/media/service/impl/FileServiceImpl.java

@ -109,6 +109,7 @@ public class FileServiceImpl implements IFileService {
.collect(Collectors.toList());
}
@Override
public PaginationData<MediaFileDTO> getMediaFilesPaginationByWorkspaceId(String workspaceId, long page, long pageSize,List<Integer> proIds) {
LoginUser loginUser = LoginHelper.getLoginUser();
@ -139,6 +140,22 @@ public class FileServiceImpl implements IFileService {
return storage.getPrivateUrlURL(mediaFileOpt.get().getObjectKey(),3600);
}
@Override
public URL getObjectUrl(String objectKey) {
OssClient storage = OssFactory.instance("mediafile");
return storage.getPrivateUrlURL(objectKey,3600);
}
@Override
public Optional<MediaFileEntity> getObjectByFileId(String workspaceId, String fileId) {
Optional<MediaFileEntity> mediaFileOpt = getMediaByFileId(workspaceId, fileId);
if (mediaFileOpt.isEmpty()) {
throw new IllegalArgumentException("{} 不存在。");
}
return mediaFileOpt;
}
@Override
public List<MediaFileDTO> getFilesByWorkspaceAndJobId(String workspaceId, String jobId) {
return mapper.selectList(new LambdaQueryWrapper<MediaFileEntity>()

42
dk-modules/sample/src/main/java/org/dromara/sample/wayline/controller/WaylineJobAtmosphereController.java

@ -1,8 +1,13 @@
package org.dromara.sample.wayline.controller;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
@ -51,6 +56,43 @@ public class WaylineJobAtmosphereController extends BaseController {
return waylineJobAtmosphereService.queryPageList(bo, pageQuery);
}
/**
* 查询灵嗅记录 waylineJobId / dockSn
* @param bo
* @return
*/
@SaCheckPermission("sample:WaylineJobAtmosphere:list")
@GetMapping("/listQuery")
public List<WaylineJobAtmosphereVo> listQuery(WaylineJobAtmosphereBo bo) {
return waylineJobAtmosphereService.queryList(bo);
}
/**
* 根据时间查询记录 day / dayTime
* @param bo
* @return
*/
@SaCheckPermission("sample:WaylineJobAtmosphere:list")
@GetMapping("/listTime")
public List<WaylineJobAtmosphereVo> listTime(WaylineJobAtmosphereBo bo) {
List<WaylineJobAtmosphereVo> dayList = new ArrayList<>();
//没传开始-结束时间 默认查今天数据
if (ObjectUtil.isEmpty(bo.getDayStart()) || ObjectUtil.isEmpty(bo.getDayEnd())) {
Date currentDate = new Date();
DateTime dayStart = DateUtil.beginOfDay(currentDate);
DateTime dayEnd = DateUtil.endOfDay(currentDate);
dayList = waylineJobAtmosphereService.selectByDateRange(bo.getDockSn(), dayStart, dayEnd);
} else if (ObjectUtil.isNotEmpty(bo.getDayStart()) || ObjectUtil.isNotEmpty(bo.getDayEnd())) {
DateTime dayStart = DateUtil.date(bo.getDayStart());
DateTime dayEnd = DateUtil.date(bo.getDayEnd());
dayList = waylineJobAtmosphereService.selectByDateRange(bo.getDockSn(), dayStart, dayEnd);
}
return dayList;
}
/** 演示数据返回前台 **/
@GetMapping("/list/demo")
public List<WaylineJobAtmosphereVo> demoList(WaylineJobAtmosphereBo bo, PageQuery pageQuery) {
List<WaylineJobAtmosphereVo> demoList= waylineJobAtmosphereService.demoList(bo);

42
dk-modules/sample/src/main/java/org/dromara/sample/wayline/controller/WaylineJobController.java

@ -19,10 +19,7 @@ import org.dromara.sample.wayline.model.enums.WaylineTaskStatusEnum;
import org.dromara.sample.wayline.model.entity.WaylineFileEntity;
import org.dromara.sample.wayline.model.param.CreateJobParam;
import org.dromara.sample.wayline.model.param.UpdateJobParam;
import org.dromara.sample.wayline.service.IFlightTaskService;
import org.dromara.sample.wayline.service.IWaylineFileService;
import org.dromara.sample.wayline.service.IWaylineJobService;
import org.dromara.sample.wayline.service.IWaylineRedisService;
import org.dromara.sample.wayline.service.*;
import org.dromara.sample.wayline.service.IWaylineRedisService;
import org.dromara.sample.wayline.service.impl.WaylineFileServiceImpl;
import org.dromara.system.api.model.LoginUser;
@ -89,11 +86,44 @@ public class WaylineJobController {
@PathVariable(name = "workspace_id") String workspaceId,
@RequestParam(name = "proIds" , required = false) List<Integer> proIds,
@RequestParam(name = "fileId" , required = false) String fileId,
@RequestParam(name = "name" , required = false) String name) {
PaginationData<WaylineJobDTO> data = waylineJobService.getJobsByWorkspaceId(workspaceId, page, pageSize,fileId,proIds,name);
@RequestParam(name = "name" , required = false) String name,
@RequestParam(name = "mediaCount" , required = false) Integer mediaCount) {
PaginationData<WaylineJobDTO> data = waylineJobService.getJobsByWorkspaceId(workspaceId, page, pageSize,fileId,proIds,name,mediaCount);
return HttpResultResponse.success(data);
}
/** 灵嗅航线-分页查询 **/
@GetMapping("/{workspace_id}/jobsSpiritSmellPage")
@Operation(summary = "查询工作区中的所有作业。。", description = "查询工作区中的所有作业。")
public HttpResultResponse<PaginationData<WaylineJobDTO>> getJobsSpiritSmellPage(
@RequestParam(name = "pageNum", defaultValue = "1") Long page,
@RequestParam(name = "pageSize", defaultValue = "10") Long pageSize,
@PathVariable(name = "workspace_id") String workspaceId,
@RequestParam(name = "proIds" , required = false) List<Integer> proIds,
@RequestParam(name = "fileId" , required = false) String fileId,
@RequestParam(name = "name" , required = false) String name,
@RequestParam(name = "dockSn" , required = false) String dockSn
) {
PaginationData<WaylineJobDTO> data = waylineJobService.getJobsSpiritSmellPageByWorkspaceId(workspaceId,page, pageSize,fileId,proIds,name,dockSn);
return HttpResultResponse.success(data);
}
/** 灵嗅航线-全量查询-单个设备下查询 **/
@GetMapping("/{workspace_id}/jobsSpiritSmell")
@Operation(summary = "查询工作区中的所有作业。。", description = "查询工作区中的所有作业。")
public HttpResultResponse<List<WaylineJobDTO>> getJobsSpiritSmell(
@PathVariable(name = "workspace_id") String workspaceId,
@RequestParam(name = "proIds" , required = false) List<Integer> proIds,
@RequestParam(name = "fileId" , required = false) String fileId,
@RequestParam(name = "name" , required = false) String name,
@RequestParam(name = "dockSn" , required = false) String dockSn
) {
List<WaylineJobDTO> data = waylineJobService.getJobsSpiritSmellByWorkspaceId(workspaceId,fileId,proIds,name,dockSn);
return HttpResultResponse.success(data);
}
/**
* Send the command to cancel the jobs.
* @param jobIds

18
dk-modules/sample/src/main/java/org/dromara/sample/wayline/domain/WaylineJobAtmosphere.java

@ -122,6 +122,24 @@ public class WaylineJobAtmosphere implements Serializable {
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
//灵嗅扩展数据------
@TableField("mission_open_status")
private Boolean missionOpenStatus;//任务打开状态
@TableField("timestamp")
private Long timestamp;//时间戳
@TableField("relative_altitude")
private Float relativeAltitude;//相对高度
@TableField("data_recovery_flag")
private Boolean dataRecoveryFlag;//数据恢复标识
}

16
dk-modules/sample/src/main/java/org/dromara/sample/wayline/domain/bo/WaylineJobAtmosphereBo.java

@ -1,6 +1,7 @@
package org.dromara.sample.wayline.domain.bo;
import cn.hutool.json.JSONObject;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.sample.wayline.domain.WaylineJobAtmosphere;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
@ -10,6 +11,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
import java.util.List;
/**
* 无人机任务-空气质量业务对象 wayline_job_atmosphere
@ -32,6 +34,7 @@ public class WaylineJobAtmosphereBo extends BaseEntity {
*/
// @NotNull(message = "无人机任务ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long waylineJobId;
private List<Integer> waylineJobIds;
/**
* 任务UUID
@ -93,6 +96,7 @@ public class WaylineJobAtmosphereBo extends BaseEntity {
*/
// @NotBlank(message = "负载设备序列号不能为空", groups = { AddGroup.class, EditGroup.class })
private String serial;
private String payloadType;//负载类型 spiritsmellV2 / spiritsmellV2_1
/**
* 数据序列号
@ -148,6 +152,7 @@ public class WaylineJobAtmosphereBo extends BaseEntity {
* 空气质量数据
*/
private String airData;
private JSONObject airDataJson;
/**
* 错误码
@ -174,5 +179,16 @@ public class WaylineJobAtmosphereBo extends BaseEntity {
*/
private Long proId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date dayStart;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date dayEnd;
//灵嗅扩展数据------
private Boolean missionOpenStatus;
private Long timestamp;
private Float relativeAltitude;
private Boolean dataRecoveryFlag;
}

14
dk-modules/sample/src/main/java/org/dromara/sample/wayline/domain/vo/WaylineJobAtmosphereVo.java

@ -206,5 +206,19 @@ public class WaylineJobAtmosphereVo implements Serializable {
@ExcelProperty(value = "proID")
private Long proId;
//灵嗅扩展数据------
@ExcelProperty(value = "任务打开状态")
private Boolean missionOpenStatus;
@ExcelProperty(value = "时间戳")
private Long timestamp;
@ExcelProperty(value = "相对高度")
private Float relativeAltitude;
@ExcelProperty(value = "数据恢复标识")
private Boolean dataRecoveryFlag;
}

6
dk-modules/sample/src/main/java/org/dromara/sample/wayline/mapper/WaylineJobAtmosphereMapper.java

@ -1,9 +1,12 @@
package org.dromara.sample.wayline.mapper;
import org.apache.ibatis.annotations.Param;
import org.dromara.sample.wayline.domain.WaylineJobAtmosphere;
import org.dromara.sample.wayline.domain.vo.WaylineJobAtmosphereVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* 无人机任务-空气质量Mapper接口
*
@ -12,4 +15,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
*/
public interface WaylineJobAtmosphereMapper extends BaseMapperPlus<WaylineJobAtmosphere, WaylineJobAtmosphereVo> {
List<Long> selectSpiritSmellWayLineJobIds(@Param("dockSn") String dockSn);
List<String> selectDistinctWaylineFileId();
}

3
dk-modules/sample/src/main/java/org/dromara/sample/wayline/model/dto/WaylineJobDTO.java

@ -8,6 +8,7 @@ import org.dromara.common.sdk.cloudapi.wayline.OutOfControlActionEnum;
import org.dromara.common.sdk.cloudapi.wayline.ProgressExtBreakPoint;
import org.dromara.common.sdk.cloudapi.wayline.TaskTypeEnum;
import org.dromara.common.sdk.cloudapi.wayline.WaylineTypeEnum;
import org.dromara.sample.wayline.domain.vo.WaylineJobAtmosphereVo;
import java.time.LocalDateTime;
import java.util.List;
@ -79,4 +80,6 @@ public class WaylineJobDTO {
private ProgressExtBreakPoint breakPoint;
private List<Integer> proIds;
private List<WaylineJobAtmosphereVo> waylineJobAtmosphereVoList;
}

4
dk-modules/sample/src/main/java/org/dromara/sample/wayline/model/entity/WaylineJobEntity.java

@ -97,4 +97,8 @@ public class WaylineJobEntity implements Serializable {
@TableField("pro_id")
private Integer proId;
@TableField("dock_name")
private String dockName;
}

7
dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/IWaylineJobAtmosphereService.java

@ -1,5 +1,6 @@
package org.dromara.sample.wayline.service;
import cn.hutool.core.date.DateTime;
import cn.hutool.json.JSONObject;
import org.dromara.sample.wayline.domain.vo.WaylineJobAtmosphereVo;
import org.dromara.sample.wayline.domain.bo.WaylineJobAtmosphereBo;
@ -71,4 +72,10 @@ public interface IWaylineJobAtmosphereService {
void handleAdd(WaylineJobDTO waylineJobDTO, JSONObject json);
List<WaylineJobAtmosphereVo> demoList(WaylineJobAtmosphereBo bo);
List<Long> selectSpiritSmellWayLineJobIdsByDockSn(String dockSn);
List<WaylineJobAtmosphereVo> selectByDateRange(String dockSn, DateTime dayStart, DateTime dayEnd);
List<Long> selectSpiritSmellWayLineJobIds(String dockSn);
}

11
dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/IWaylineJobService.java

@ -28,7 +28,7 @@ public interface IWaylineJobService {
* @param endTime The time the job ended.
* @return
*/
Optional<WaylineJobDTO> createWaylineJob(CreateJobParam param, String workspaceId, String username, Date beginTime, Date endTime, Integer proId);
Optional<WaylineJobDTO> createWaylineJob(CreateJobParam param, String workspaceId, String username, Date beginTime, Date endTime, Integer proId,String dockName);
/**
* Create a sub-task based on the information of the parent task.
@ -71,7 +71,9 @@ public interface IWaylineJobService {
* @param pageSize
* @return
*/
PaginationData<WaylineJobDTO> getJobsByWorkspaceId(String workspaceId, long page, long pageSize,String fileId,List<Integer> proIds,String name);
PaginationData<WaylineJobDTO> getJobsByWorkspaceId(String workspaceId, long page, long pageSize,String fileId,List<Integer> proIds,String name,Integer mediaCount);
/**
* Query the wayline execution status of the dock.
@ -89,4 +91,9 @@ public interface IWaylineJobService {
List<MediaFileDTO> getMediaFileDTO(String jobId, String fileType);
WaylineJobDTO getJobByDockSn(String dockSn);
/**获取灵嗅数据**/
List<WaylineJobDTO> getJobsSpiritSmellByWorkspaceId(String workspaceId, String fileId, List<Integer> proIds, String name, String dockSn);
/**获取灵嗅数据-分页**/
PaginationData<WaylineJobDTO> getJobsSpiritSmellPageByWorkspaceId(String workspaceId, Long page, Long pageSize, String fileId, List<Integer> proIds, String name, String dockSn);
}

5
dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/impl/FlightTaskServiceImpl.java

@ -248,7 +248,7 @@ public class FlightTaskServiceImpl extends AbstractWaylineService implements IFl
if(deviceOnline.get().getProId() == null){
throw new SQLException("项目组不存在");
}
Optional<WaylineJobDTO> waylineJobOpt = waylineJobService.createWaylineJob(param, workspaceId, loginUser.getUsername(), new Date(beginTime), new Date(endTime),deviceOnline.get().getProId());
Optional<WaylineJobDTO> waylineJobOpt = waylineJobService.createWaylineJob(param, workspaceId, loginUser.getUsername(), new Date(beginTime), new Date(endTime),deviceOnline.get().getProId(),deviceOnline.get().getNickname());
if (waylineJobOpt.isEmpty()) {
throw new SQLException("无法创建路线作业。");
}
@ -286,7 +286,7 @@ public class FlightTaskServiceImpl extends AbstractWaylineService implements IFl
if(deviceOnline.get().getProId() == null){
throw new SQLException("项目组不存在");
}
Optional<WaylineJobDTO> waylineJobOpt = waylineJobService.createWaylineJob(param, workspaceId, username, new Date(beginTime), new Date(endTime),deviceOnline.get().getProId());
Optional<WaylineJobDTO> waylineJobOpt = waylineJobService.createWaylineJob(param, workspaceId, username, new Date(beginTime), new Date(endTime),deviceOnline.get().getProId(),deviceOnline.get().getNickname());
if (waylineJobOpt.isEmpty()) {
throw new SQLException("无法创建路线作业。");
}
@ -342,6 +342,7 @@ public class FlightTaskServiceImpl extends AbstractWaylineService implements IFl
if (waylineFile.isEmpty()) {
throw new SQLException("路线文件不存在。");
}
waylineJob.setWaylineName(waylineFile.get().getName());
// get file url
URL url = waylineFileService.getObjectUrl(waylineJob.getWorkspaceId(), waylineFile.get().getId());

12
dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/impl/WaylineFileServiceImpl.java

@ -1,5 +1,6 @@
package org.dromara.sample.wayline.service.impl;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.MD5;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -33,6 +34,7 @@ import org.dromara.sample.manage.service.IDeviceProService;
import org.dromara.sample.manage.service.IDeviceRedisService;
import org.dromara.sample.wayline.mapper.IAudioFileMapper;
import org.dromara.sample.wayline.mapper.IWaylineFileMapper;
import org.dromara.sample.wayline.mapper.WaylineJobAtmosphereMapper;
import org.dromara.sample.wayline.model.dto.KmzFileProperties;
import org.dromara.sample.wayline.model.dto.WaylineFileDTO;
import org.dromara.sample.wayline.model.entity.AudioFileEntity;
@ -87,6 +89,9 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
@Autowired
private IDeviceRedisService deviceRedisService;
@Autowired
private WaylineJobAtmosphereMapper waylineJobAtmosphereMapper;
@Override
public PaginationData<GetWaylineListResponse> getWaylinesByParam(String workspaceId, GetWaylineListRequest param,List<Integer> proIds) {
@ -94,6 +99,10 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
if(proIds == null){
proIds = deviceProService.listDeviceGroup(loginUser.getUserId());
}
if(BooleanUtil.isTrue(param.getSpiritSmellFlag())){ //灵嗅航线过滤wayLineFileIds
param.setSpiritSmellWaylineFileIds(waylineJobAtmosphereMapper.selectDistinctWaylineFileId());
}
// Paging Query
List<Integer> finalProIds = proIds;
Page<WaylineFileEntity> page = mapper.selectPage(
@ -122,6 +131,9 @@ public class WaylineFileServiceImpl implements IWaylineFileService {
.and(ObjectUtil.isAllNotEmpty(proIds), wrapper -> {
wrapper.in(WaylineFileEntity::getProId, finalProIds);
})
.and(BooleanUtil.isTrue(param.getSpiritSmellFlag()), wrapper -> {
wrapper.in(WaylineFileEntity::getWaylineId,param.getSpiritSmellWaylineFileIds());
})
.like(Objects.nonNull(param.getKey()), WaylineFileEntity::getName, param.getKey())
// There is a risk of SQL injection
.last(Objects.nonNull(param.getOrderBy()), " order by " + param.getOrderBy().toString()));

29
dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/impl/WaylineJobAtmosphereServiceImpl.java

@ -1,9 +1,12 @@
package org.dromara.sample.wayline.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
@ -22,6 +25,7 @@ import org.dromara.sample.wayline.service.IWaylineJobAtmosphereService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.stream.Collectors;
/**
* 无人机任务-空气质量Service业务层处理
@ -83,6 +87,7 @@ public class WaylineJobAtmosphereServiceImpl implements IWaylineJobAtmosphereSer
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<WaylineJobAtmosphere> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getWaylineJobId() != null, WaylineJobAtmosphere::getWaylineJobId, bo.getWaylineJobId());
lqw.in(CollUtil.isNotEmpty(bo.getWaylineJobIds()), WaylineJobAtmosphere::getWaylineJobId, bo.getWaylineJobIds());
lqw.eq(StringUtils.isNotBlank(bo.getJobId()), WaylineJobAtmosphere::getJobId, bo.getJobId());
lqw.like(StringUtils.isNotBlank(bo.getName()), WaylineJobAtmosphere::getName, bo.getName());
lqw.eq(StringUtils.isNotBlank(bo.getFileId()), WaylineJobAtmosphere::getFileId, bo.getFileId());
@ -185,4 +190,28 @@ public class WaylineJobAtmosphereServiceImpl implements IWaylineJobAtmosphereSer
}
return waylineJobAtmosphereVos;
}
@Override
public List<Long> selectSpiritSmellWayLineJobIdsByDockSn(String dockSn) {
LambdaQueryWrapper<WaylineJobAtmosphere> wrapper = new LambdaQueryWrapper<>();
wrapper.select(WaylineJobAtmosphere::getWaylineJobId);
wrapper.eq(WaylineJobAtmosphere::getDockSn,dockSn);
List<WaylineJobAtmosphereVo> waylineJobAtmosphereVoList = baseMapper.selectVoList(wrapper);
List<Long> waylineJobIds = waylineJobAtmosphereVoList.stream().map(WaylineJobAtmosphereVo::getWaylineJobId).distinct().collect(Collectors.toList());
return waylineJobIds;
}
@Override
public List<WaylineJobAtmosphereVo> selectByDateRange(String dockSn, DateTime dayStart, DateTime dayEnd) {
LambdaQueryWrapper<WaylineJobAtmosphere> wrapper = new LambdaQueryWrapper<>();
wrapper.between(WaylineJobAtmosphere::getCreateTime, dayStart, dayEnd);
wrapper.eq(ObjectUtil.isNotEmpty(dockSn),WaylineJobAtmosphere::getDockSn,dockSn); //传值了再查询
List<WaylineJobAtmosphereVo> waylineJobAtmosphereVoList = baseMapper.selectVoList(wrapper);
return waylineJobAtmosphereVoList;
}
@Override
public List<Long> selectSpiritSmellWayLineJobIds(String dockSn) {
return baseMapper.selectSpiritSmellWayLineJobIds(dockSn);
}
}

146
dk-modules/sample/src/main/java/org/dromara/sample/wayline/service/impl/WaylineJobServiceImpl.java

@ -1,6 +1,10 @@
package org.dromara.sample.wayline.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -25,12 +29,15 @@ import org.dromara.sample.manage.service.IDeviceService;
import org.dromara.sample.media.model.MediaFileCountDTO;
import org.dromara.sample.media.model.MediaFileDTO;
import org.dromara.sample.media.service.IFileService;
import org.dromara.sample.wayline.domain.bo.WaylineJobAtmosphereBo;
import org.dromara.sample.wayline.domain.vo.WaylineJobAtmosphereVo;
import org.dromara.sample.wayline.mapper.IWaylineJobMapper;
import org.dromara.sample.wayline.model.dto.WaylineJobDTO;
import org.dromara.sample.wayline.model.entity.WaylineJobEntity;
import org.dromara.sample.wayline.model.enums.WaylineJobStatusEnum;
import org.dromara.sample.wayline.model.param.CreateJobParam;
import org.dromara.sample.wayline.service.IWaylineFileService;
import org.dromara.sample.wayline.service.IWaylineJobAtmosphereService;
import org.dromara.sample.wayline.service.IWaylineJobService;
import org.dromara.sample.wayline.service.IWaylineRedisService;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -83,6 +90,9 @@ public class WaylineJobServiceImpl implements IWaylineJobService {
@Autowired
private IDeviceProService deviceProService;
@Autowired
private IWaylineJobAtmosphereService waylineJobAtmosphereService;
private Optional<WaylineJobDTO> insertWaylineJob(WaylineJobEntity jobEntity) {
int id = mapper.insert(jobEntity);
if (id <= 0) {
@ -92,7 +102,7 @@ public class WaylineJobServiceImpl implements IWaylineJobService {
}
@Override
public Optional<WaylineJobDTO> createWaylineJob(CreateJobParam param, String workspaceId, String username, Date beginTime, Date endTime,Integer proId) {
public Optional<WaylineJobDTO> createWaylineJob(CreateJobParam param, String workspaceId, String username, Date beginTime, Date endTime,Integer proId,String dockName) {
if (Objects.isNull(param)) {
return Optional.empty();
}
@ -116,6 +126,7 @@ public class WaylineJobServiceImpl implements IWaylineJobService {
.breakPoint(param.getBreakPoint())
.jobType(param.getJobType().getType())
.proId(proId)
.dockName(dockName)
.build();
return insertWaylineJob(jobEntity);
@ -175,7 +186,7 @@ public class WaylineJobServiceImpl implements IWaylineJobService {
}
@Override
public PaginationData<WaylineJobDTO> getJobsByWorkspaceId(String workspaceId, long page, long pageSize,String fileId,List<Integer> proIds,String name) {
public PaginationData<WaylineJobDTO> getJobsByWorkspaceId(String workspaceId, long page, long pageSize,String fileId,List<Integer> proIds,String name,Integer mediaCount) {
LoginUser loginUser = LoginHelper.getLoginUser();
if(ObjectUtil.isAllEmpty(proIds)){
proIds = deviceProService.listDeviceGroup(loginUser.getUserId());
@ -185,6 +196,9 @@ public class WaylineJobServiceImpl implements IWaylineJobService {
if(ObjectUtil.isNotEmpty(fileId)) {
waylineJobEntityLambdaQueryWrapper.eq(WaylineJobEntity::getFileId, fileId);
}
if(ObjectUtil.isNotEmpty(mediaCount)) {
waylineJobEntityLambdaQueryWrapper.ge(WaylineJobEntity::getMediaCount, mediaCount);
}
waylineJobEntityLambdaQueryWrapper.in(ObjectUtil.isAllNotEmpty(proIds),WaylineJobEntity::getProId,proIds);
if(ObjectUtil.isNotEmpty(name)){
waylineJobEntityLambdaQueryWrapper.and(wrapper ->{
@ -202,6 +216,103 @@ public class WaylineJobServiceImpl implements IWaylineJobService {
return new PaginationData<WaylineJobDTO>(records, new Pagination(pageData.getCurrent(), pageData.getSize(), pageData.getTotal()));
}
@Override
public List<WaylineJobDTO> getJobsSpiritSmellByWorkspaceId(String workspaceId, String fileId, List<Integer> proIds, String name, String dockSn) {
LoginUser loginUser = LoginHelper.getLoginUser();
if(ObjectUtil.isAllEmpty(proIds)){
proIds = deviceProService.listDeviceGroup(loginUser.getUserId());
}
LambdaQueryWrapper<WaylineJobEntity> waylineJobEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
waylineJobEntityLambdaQueryWrapper.eq(WaylineJobEntity::getWorkspaceId, workspaceId);
if(ObjectUtil.isNotEmpty(fileId)) {
waylineJobEntityLambdaQueryWrapper.eq(WaylineJobEntity::getFileId, fileId);
}
waylineJobEntityLambdaQueryWrapper.in(ObjectUtil.isAllNotEmpty(proIds),WaylineJobEntity::getProId,proIds);
// if(ObjectUtil.isNotEmpty(name)){
// waylineJobEntityLambdaQueryWrapper.and(wrapper ->{
// wrapper.like(WaylineJobEntity::getName, name).or().like(WaylineJobEntity::getWaylineName, name);
// });
// };
if(ObjectUtil.isNotEmpty(dockSn)){//找指定设备的航线 //灵嗅数据过滤
List<Long> waylineJobIds = waylineJobAtmosphereService.selectSpiritSmellWayLineJobIds(dockSn);
waylineJobEntityLambdaQueryWrapper.in(WaylineJobEntity::getId,waylineJobIds);
}else{//找全部有灵嗅数据的航线
List<Long> waylineJobIds = waylineJobAtmosphereService.selectSpiritSmellWayLineJobIds(null);
waylineJobEntityLambdaQueryWrapper.in(WaylineJobEntity::getId,waylineJobIds);
}
waylineJobEntityLambdaQueryWrapper.orderByDesc(WaylineJobEntity::getId);
List<WaylineJobEntity> waylineJobEntitieList = mapper.selectList(waylineJobEntityLambdaQueryWrapper);
List<WaylineJobDTO> records = waylineJobEntitieList
.stream()
.map(this::entity2Dto)
.collect(Collectors.toList());
//拼接灵嗅数据
/* List<Integer> waylineJobIds = records.stream().map(WaylineJobDTO::getId).collect(Collectors.toList());
if(CollUtil.isNotEmpty(waylineJobIds)){
WaylineJobAtmosphereBo bo = new WaylineJobAtmosphereBo();
bo.setWaylineJobIds(waylineJobIds);
List<WaylineJobAtmosphereVo> waylineJobAtmosphereVoList = waylineJobAtmosphereService.queryList(bo);
for (WaylineJobDTO record : records) {
List<WaylineJobAtmosphereVo> collect = waylineJobAtmosphereVoList.stream().filter(item -> item.getWaylineJobId().equals(record.getId().longValue())).collect(Collectors.toList());
// collect.stream().forEach(item -> {item.setAirDataJson( JSONUtil.parseObj(item.getAirData())); });
record.setWaylineJobAtmosphereVoList(collect);
}
}*/
return records;
}
@Override
public PaginationData<WaylineJobDTO> getJobsSpiritSmellPageByWorkspaceId(String workspaceId, Long page, Long pageSize, String fileId, List<Integer> proIds, String name, String dockSn) {
LoginUser loginUser = LoginHelper.getLoginUser();
if(ObjectUtil.isAllEmpty(proIds)){
proIds = deviceProService.listDeviceGroup(loginUser.getUserId());
}
LambdaQueryWrapper<WaylineJobEntity> waylineJobEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
waylineJobEntityLambdaQueryWrapper.eq(WaylineJobEntity::getWorkspaceId, workspaceId);
if(ObjectUtil.isNotEmpty(fileId)) {
waylineJobEntityLambdaQueryWrapper.eq(WaylineJobEntity::getFileId, fileId);
}
waylineJobEntityLambdaQueryWrapper.in(ObjectUtil.isAllNotEmpty(proIds),WaylineJobEntity::getProId,proIds);
// if(ObjectUtil.isNotEmpty(name)){
// waylineJobEntityLambdaQueryWrapper.and(wrapper ->{
// wrapper.like(WaylineJobEntity::getName, name).or().like(WaylineJobEntity::getWaylineName, name);
// });
// };
if(ObjectUtil.isNotEmpty(dockSn)){//找指定设备的航线 //灵嗅数据过滤
List<Long> waylineJobIds = waylineJobAtmosphereService.selectSpiritSmellWayLineJobIds(dockSn);
waylineJobEntityLambdaQueryWrapper.in(WaylineJobEntity::getId,waylineJobIds);
}else{//找全部有灵嗅数据的航线
List<Long> waylineJobIds = waylineJobAtmosphereService.selectSpiritSmellWayLineJobIds(null);
waylineJobEntityLambdaQueryWrapper.in(WaylineJobEntity::getId,waylineJobIds);
}
waylineJobEntityLambdaQueryWrapper.orderByDesc(WaylineJobEntity::getId);
Page<WaylineJobEntity> pageData = mapper.selectPage(new Page<WaylineJobEntity>(page, pageSize),waylineJobEntityLambdaQueryWrapper);
List<WaylineJobDTO> records = pageData.getRecords()
.stream().map(this::entity2Dto)
.collect(Collectors.toList());
//拼接灵嗅数据
/* List<Integer> waylineJobIds = records.stream().map(WaylineJobDTO::getId).collect(Collectors.toList());
if(CollUtil.isNotEmpty(waylineJobIds)){
WaylineJobAtmosphereBo bo = new WaylineJobAtmosphereBo();
bo.setWaylineJobIds(waylineJobIds);
List<WaylineJobAtmosphereVo> waylineJobAtmosphereVoList = waylineJobAtmosphereService.queryList(bo);
for (WaylineJobDTO record : records) {
List<WaylineJobAtmosphereVo> collect = waylineJobAtmosphereVoList.stream().filter(item -> item.getWaylineJobId().equals(record.getId().longValue())).collect(Collectors.toList());
// collect.stream().forEach(item -> {item.setAirDataJson( JSONUtil.parseObj(item.getAirData())); });
record.setWaylineJobAtmosphereVoList(collect);
}
}*/
return new PaginationData<WaylineJobDTO>(records, new Pagination(pageData.getCurrent(), pageData.getSize(), pageData.getTotal()));
}
private WaylineJobEntity dto2Entity(WaylineJobDTO dto) {
WaylineJobEntity.WaylineJobEntityBuilder builder = WaylineJobEntity.builder();
if (dto == null) {
@ -297,11 +408,12 @@ public class WaylineJobServiceImpl implements IWaylineJobService {
.jobId(entity.getJobId())
.jobName(entity.getName())
.fileId(entity.getFileId())
.fileName(waylineFileService.getWaylineByWaylineId(entity.getWorkspaceId(), entity.getFileId())
.orElse(new GetWaylineListResponse()).getName())
.fileName(entity.getWaylineName())
// .orElse(new GetWaylineListResponse()).getName())
.dockSn(entity.getDockSn())
.dockName(deviceService.getDeviceBySn(entity.getDockSn())
.orElse(DeviceDTO.builder().build()).getNickname())
.dockName(entity.getDockName())
// .dockName(deviceService.getDeviceBySn(entity.getDockSn())
// .orElse(DeviceDTO.builder().build()).getNickname())
.username(entity.getUsername())
.workspaceId(entity.getWorkspaceId())
.status(WaylineJobStatusEnum.IN_PROGRESS.getVal() == entity.getStatus() &&
@ -348,17 +460,17 @@ public class WaylineJobServiceImpl implements IWaylineJobService {
.uploading(RedisOpsUtils.checkExist(key) && entity.getJobId().equals(((MediaFileCountDTO)RedisOpsUtils.get(key)).getJobId()));
return builder.build();
}
int uploadedSize = fileService.getFilesByWorkspaceAndJobId(entity.getWorkspaceId(), entity.getJobId()).size();
// All media for this job have been uploaded.
if (uploadedSize >= entity.getMediaCount()) {
return builder.uploadedCount(uploadedSize).build();
}
RedisOpsUtils.hashSet(countKey, entity.getJobId(),
MediaFileCountDTO.builder()
.jobId(entity.getJobId())
.mediaCount(entity.getMediaCount())
.uploadedCount(uploadedSize).build());
//
// int uploadedSize = fileService.getFilesByWorkspaceAndJobId(entity.getWorkspaceId(), entity.getJobId()).size();
// //All media for this job have been uploaded.
// if (uploadedSize >= entity.getMediaCount()) {
// return builder.uploadedCount(uploadedSize).build();
// }
// RedisOpsUtils.hashSet(countKey, entity.getJobId(),
// MediaFileCountDTO.builder()
// .jobId(entity.getJobId())
// .mediaCount(entity.getMediaCount())
// .build());
return builder.build();
}
}

5
dk-modules/sample/src/main/java/org/dromara/sample/websocket/config/MyWebSocketFactory.java

@ -20,8 +20,11 @@ public class MyWebSocketFactory extends WebSocketDefaultFactory {
@Autowired
private IWebSocketManageService webSocketManageService;
@Autowired
private WebSocketSubscriptionManager websocketSubscriptionManager;
@Override
public WebSocketHandler decorate(WebSocketHandler handler) {
return new MyWebSocketHandler(handler, webSocketManageService);
return new MyWebSocketHandler(handler, webSocketManageService, websocketSubscriptionManager);
}
}

81
dk-modules/sample/src/main/java/org/dromara/sample/websocket/config/MyWebSocketHandler.java

@ -1,6 +1,8 @@
package org.dromara.sample.websocket.config;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.redis.utils.RedisUtils;
@ -28,16 +30,26 @@ import static org.dromara.common.satoken.utils.LoginHelper.LOGIN_USER_KEY;
@Slf4j
public class MyWebSocketHandler extends WebSocketDefaultHandler {
private IWebSocketManageService webSocketManageService;
private final IWebSocketManageService webSocketManageService;
MyWebSocketHandler(WebSocketHandler delegate, IWebSocketManageService webSocketManageService) {
private final WebSocketSubscriptionManager websocketSubscriptionManager;
public MyWebSocketHandler(WebSocketHandler delegate,
IWebSocketManageService webSocketManageService,
WebSocketSubscriptionManager websocketSubscriptionManager) {
super(delegate);
this.webSocketManageService = webSocketManageService;
this.websocketSubscriptionManager = websocketSubscriptionManager;
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
// 从 URL Query 中解析 token
String query = session.getUri().getQuery(); // e.g. "Authorization=Bearer abc...&clientid=xxx"
String token = parseTokenFromQuery(query);
session.getAttributes().put("token", token);
Object cacheObject = RedisUtils.getCacheObject("000000:online_tokens:" + session.getUri().toString().substring(session.getUri().toString().indexOf("%20") + 3, session.getUri().toString().indexOf("&")));
SysUserOnline sysUserOnline = BeanUtil.copyProperties(cacheObject, SysUserOnline.class);
if (StringUtils.hasText(sysUserOnline.getUserName())) {
@ -61,9 +73,70 @@ public class MyWebSocketHandler extends WebSocketDefaultHandler {
}
/**
* 前台触发连接
* // 建好 ws 连接之后
* ws.send(JSON.stringify({
* action: "subscribe",
* bizCode: "SPIRIT_SMELL"
* }));
*
* // 页面关闭或切换时
* ws.send(JSON.stringify({
* action: "unsubscribe",
* bizCode: "SPIRIT_SMELL"
* }));
*
* @throws Exception
*/
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
log.debug("received message: {}", message.getPayload());
public void handleMessage(WebSocketSession rawSession, WebSocketMessage<?> wsMsg) throws Exception {
// log.debug("received message: {}", message.getPayload());
String payload = wsMsg.getPayload().toString();
if(!JSONUtil.isTypeJSON(payload)){
System.out.println(payload);
return;
}
System.out.println(payload);
JSONObject json = JSONUtil.parseObj(payload);
String action = json.getStr("action"); // subscribe/unsubscribe
// String bizCode = json.getStr("bizCode");
String dockSn = json.getStr("dockSn");
String token = (String) rawSession.getAttributes().get("token");
// 还可以带 workspaceId/userType 等,按需扩展
/* MyConcurrentWebSocketSession session = new MyConcurrentWebSocketSession(rawSession);
if ("subscribe".equals(action)) {
// websocketSubscriptionManager.subscribe(bizCode, dockSn, token, session);
// websocketSubscriptionManager.subscribe( dockSn, token, session);
websocketSubscriptionManager.subscribe(token,dockSn,session);
}
else if ("unsubscribe".equals(action)) {
// websocketSubscriptionManager.unsubscribe(bizCode, dockSn, token, session.getId());
// websocketSubscriptionManager.unsubscribe( dockSn, token, session.getId());
websocketSubscriptionManager.unsubscribe( token,dockSn,session.getId());
}
else {
log.warn("Unknown WS action: {}", action);
}*/
}
private String parseTokenFromQuery(String query) {
// 简单解析:找到 Authorization=Bearer XXX
for (String part : query.split("&")) {
if (part.startsWith("Authorization=")) {
String v = part.substring("Authorization=".length());
if (v.startsWith("Bearer ")) {
return v.substring("Bearer ".length());
}
return v;
}
}
return null;
}
}

104
dk-modules/sample/src/main/java/org/dromara/sample/websocket/config/WebSocketSubscriptionManager.java

@ -0,0 +1,104 @@
package org.dromara.sample.websocket.config;
import org.dromara.common.redis.config.RedisConst;
import org.dromara.common.redis.utils.RedisOpsUtils;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class WebSocketSubscriptionManager {
/**
* 存储结构
* key = bizCode + ":" + dockSn
* 内部Map = token -> (sessionId -> session)
*/
// private final ConcurrentHashMap<String, ConcurrentHashMap<String, ConcurrentHashMap<String, MyConcurrentWebSocketSession>> > subs = new ConcurrentHashMap<>();
// token -> Set<dockSn>
private final ConcurrentHashMap<String, Set<String>> tokenToDockSet = new ConcurrentHashMap<>();
// token -> sessionId -> session
private final ConcurrentHashMap<String, ConcurrentHashMap<String, MyConcurrentWebSocketSession>> tokenSessions = new ConcurrentHashMap<>();
private String buildOuterKey(String bizCode, String dockSn) {
return bizCode + ":" + dockSn;
}
/** 订阅设备 */
public void subscribe(String token, String dockSn, MyConcurrentWebSocketSession session) {
// 保存用户到redis,案例数据: <onlineuser:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ, 7CTDM7H00BQ6W3> ,超时:30分钟
String key = RedisConst.DEVICE_ONLINE_USER_PREFIX + token;
RedisOpsUtils.setWithExpire(key, dockSn ,RedisConst.ONLINE_REDIS_USER_ALIVE_SECOND);
// tokenToDockSet.computeIfAbsent(token, k -> ConcurrentHashMap.newKeySet()).add(dockSn);
// tokenSessions.computeIfAbsent(key, k -> new ConcurrentHashMap<>()).put(session.getId(), session);
}
/** 取消订阅设备 */
public void unsubscribe(String token, String dockSn, String sessionId) {
RedisOpsUtils.del(RedisConst.DEVICE_ONLINE_USER_PREFIX+token);
// Set<String> docks = tokenToDockSet.get(token);
// if (docks != null) {
// docks.remove(dockSn);
// if (docks.isEmpty()) {
// tokenToDockSet.remove(token);
// }
// }
//
// var sessionMap = tokenSessions.get(token);
// if (sessionMap != null) {
// sessionMap.remove(sessionId);
// if (sessionMap.isEmpty()) {
// tokenSessions.remove(token);
// }
// }
}
/** 获取所有订阅了该 dockSn 的用户的 session */
public Collection<MyConcurrentWebSocketSession> getSessionsForDock(String dockSn) {
List<MyConcurrentWebSocketSession> result = new ArrayList<>();
for (Map.Entry<String, Set<String>> entry : tokenToDockSet.entrySet()) {
String token = entry.getKey();
Set<String> dockSnSet = entry.getValue();
if (dockSnSet.contains(dockSn)) {
var sessionMap = tokenSessions.get(token);
if (sessionMap != null) {
result.addAll(sessionMap.values());
}
}
}
return result;
}
// bizCode -> sessionId -> MyConcurrentWebSocketSession
// private final ConcurrentHashMap<String, ConcurrentHashMap<String, MyConcurrentWebSocketSession>> subs = new ConcurrentHashMap<>();
// /** 订阅 */
// public void subscribe(String bizCode, MyConcurrentWebSocketSession session) {
// subs.computeIfAbsent(bizCode, k -> new ConcurrentHashMap<>())
// .put(session.getId(), session);
// }
//
// /** 取消订阅 */
// public void unsubscribe(String bizCode, String sessionId) {
// var map = subs.get(bizCode);
// if (map != null) {
// map.remove(sessionId);
// if (map.isEmpty()) subs.remove(bizCode);
// }
// }
//
// /** 获取所有对该 bizCode 感兴趣的 sessions */
// public Collection<MyConcurrentWebSocketSession> getSubscribers(String bizCode) {
// var map = subs.get(bizCode);
// return map == null ? Collections.emptyList() : map.values();
// }
}

2
dk-modules/sample/src/main/java/org/dromara/sample/websocket/service/IWebSocketMessageService.java

@ -27,6 +27,8 @@ public interface IWebSocketMessageService {
*/
void sendBatch(Collection<MyConcurrentWebSocketSession> sessions, WebSocketMessageResponse message);
void sendBatchBySessions(Collection<MyConcurrentWebSocketSession> sessions, String bizCode, Object data);
void sendBatch(String workspaceId, Integer userType, String bizCode, Object data);
void sendBatch(String workspaceId, String bizCode, Object data);

148
dk-modules/sample/src/main/java/org/dromara/sample/websocket/service/impl/WebSocketMessageServiceImpl.java

@ -1,19 +1,33 @@
package org.dromara.sample.websocket.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.redis.config.RedisConst;
import org.dromara.common.redis.utils.RedisOpsUtils;
import org.dromara.common.websocket.dto.WebSocketMessageResponse;
import org.dromara.sample.websocket.config.MyConcurrentWebSocketSession;
import org.dromara.sample.websocket.config.WebSocketSubscriptionManager;
import org.dromara.sample.websocket.service.IWebSocketManageService;
import org.dromara.sample.websocket.service.IWebSocketMessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.handler.WebSocketSessionDecorator;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static cn.hutool.jwt.JWTUtil.parseToken;
/**
* @author sean.zhou
@ -29,12 +43,12 @@ public class WebSocketMessageServiceImpl implements IWebSocketMessageService {
@Autowired
private IWebSocketManageService webSocketManageService;
@Autowired
private WebSocketSubscriptionManager webSocketSubscriptionManager;
@Override
public void sendMessage(MyConcurrentWebSocketSession session, WebSocketMessageResponse message) {
if (session == null) {
return;
}
if (session == null) {return;}
try {
if (!session.isOpen()) {
@ -43,7 +57,6 @@ public class WebSocketMessageServiceImpl implements IWebSocketMessageService {
return;
}
session.sendMessage(new TextMessage(mapper.writeValueAsBytes(message)));
} catch (IOException e) {
log.info("Failed to publish the message. {}", message.toString());
@ -51,23 +64,68 @@ public class WebSocketMessageServiceImpl implements IWebSocketMessageService {
}
}
/** 核心调用 **/
@Override
public void sendBatch(Collection<MyConcurrentWebSocketSession> sessions, WebSocketMessageResponse message) {
if (sessions.isEmpty()) {
return;
}
if (sessions.isEmpty()) {return;}
try {
TextMessage data = new TextMessage(mapper.writeValueAsBytes(message));
// System.out.println(data.getPayload());
String targetDockSn = extractDockSn(message.getData());//获取sn码
// if (StrUtil.isBlank(targetDockSn)) { //消息体中不包含 dockSn 可拦截
// return;
// }
//查redis在线用户
String onlineUserPrefix = RedisConst.DEVICE_ONLINE_USER_PREFIX ;
// Set<String> allKeys = RedisOpsUtils.getAllKeys(keyPrefix);
// allKeys = allKeys.stream()
// .map(key -> StrUtil.subAfter(key, keyPrefix, false))
// .filter(StrUtil::isNotBlank) // 排除 null 或 空字符串
// .collect(Collectors.toSet());
for (MyConcurrentWebSocketSession session : sessions) {
if (!session.isOpen()) {
session.close();
log.debug("This session is closed.");
return;
// log.debug("This session is closed.");
// return;
continue;
}
// session.sendMessage(data);//数据发送 //关闭数据
String token = parseTokenFromQuery(session.getUri().getQuery());
// System.out.println("tok"+token);
// String newToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJzeXNfdXNlcjoxIiwicm5TdHIiOiJMVUoxUGUzczNMVGNndHkzTVI1SFRRV3NUcjdWamlsSSIsImNsaWVudGlkIjoiZTVjZDdlNDg5MWJmOTVkMWQxOTIwNmNlMjRhN2IzMmUiLCJ0ZW5hbnRJZCI6IjAwMDAwMCIsInVzZXJJZCI6MSwidXNlck5hbWUiOiJhZG1pbiIsImRlcHRJZCI6MiwiZGVwdE5hbWUiOiLmsZ_oi4_nnIEiLCJkZXB0Q2F0ZWdvcnkiOiIifQ.5SX070r1cmmQGbEmd9MMD88XnLDJ8wPJ5LvddJ3cn_Y";
// System.out.println(ObjectUtil.equals(token,newToken));
if (StrUtil.isBlank(token)) { continue;}
String key = onlineUserPrefix + token;
String snStr = (String)RedisOpsUtils.get(key);
if (StrUtil.isEmpty(snStr)) {continue;}
String[] snSplit = snStr.split(",");
// CollUtil.contains(Arrays.asList(snSplit),targetDockSn);
// if(ObjectUtil.isNotEmpty(snStr) && ObjectUtil.equals(sn, targetDockSn)){
if(ObjectUtil.isNotEmpty(snStr) && Arrays.asList(snSplit).contains(targetDockSn) ){
// if(ObjectUtil.isNotEmpty(sn)){
session.sendMessage(data);//数据发送
}
session.sendMessage(data);
// boolean keyExist = RedisOpsUtils.checkExist(keyPrefix + ":" + token);
// if (keyExist) {
// Object o = RedisOpsUtils.get(keyPrefix + ":" + token);
// }
//在线用户token里有当前用户,发送消息
// String query = session.getUri().getQuery(); // Authorization=Bearer abgffgx....
// String token = parseTokenFromQuery(query);
// if(CollUtil.contains(allKeys, token)){
// session.sendMessage(data);//数据发送
// }
}
} catch (IOException e) {
@ -77,11 +135,65 @@ public class WebSocketMessageServiceImpl implements IWebSocketMessageService {
}
}
@Override
public void sendBatchBySessions(Collection<MyConcurrentWebSocketSession> sessions, String bizCode, Object data) {
WebSocketMessageResponse<Object> response = new WebSocketMessageResponse<>()
.setBizCode(bizCode)
.setTimestamp(System.currentTimeMillis())
.setData(Objects.requireNonNullElse(data, ""));
sendBatch(sessions, response);
}
private String extractDockSn(Object data) {
try {
// 假设DTO 都有 getSn() 方法
Method method = data.getClass().getMethod("getSn");
Object sn = method.invoke(data);
return sn == null ? null : sn.toString();
} catch (Exception e) {
return null;
}
}
@Override
public void sendBatch(String workspaceId, Integer userType, String bizCode, Object data) {
if (!StringUtils.hasText(workspaceId)) {
throw new RuntimeException("工作区ID不存在。");
}
// // 1. 优先尝试基于订阅投递
// String dockSn = extractDockSn(data);
// if (dockSn != null) {
// Collection<MyConcurrentWebSocketSession> subs =
// webSocketSubscriptionManager.getSubscribers(bizCode, dockSn);
// if (!subs.isEmpty()) {
// // 精准投递给订阅者
// this.sendBatchBySessions(subs, bizCode, data);
// return;
// }
// }
//2. 全部发送
/* String dockSn = extractDockSn(data); //获取设备sn码
System.out.println("dockSn: "+ dockSn);
if (dockSn != null) {
Collection<MyConcurrentWebSocketSession> subs = webSocketSubscriptionManager.getSessionsForDock(dockSn);
// subs.stream().map()
String collect = subs.stream().map(WebSocketSessionDecorator::getId).collect(Collectors.joining(","));
if (!subs.isEmpty()) {
System.out.println("订阅数:" + subs.size() + " collect: "+ collect);
this.sendBatch(subs, new WebSocketMessageResponse<>()
.setData(Objects.requireNonNullElse(data, ""))
.setTimestamp(System.currentTimeMillis())
.setBizCode(bizCode));
return;
}
}*/
//旧群发
Collection<MyConcurrentWebSocketSession> sessions = Objects.isNull(userType) ?
webSocketManageService.getValueWithWorkspace(workspaceId) :
webSocketManageService.getValueWithWorkspaceAndUserType(workspaceId, userType);
@ -96,4 +208,18 @@ public class WebSocketMessageServiceImpl implements IWebSocketMessageService {
public void sendBatch(String workspaceId, String bizCode, Object data) {
this.sendBatch(workspaceId, null, bizCode, data);
}
private String parseTokenFromQuery(String query) {
// 简单解析:找到 Authorization=Bearer XXX
for (String part : query.split("&")) {
if (part.startsWith("Authorization=")) {
String v = part.substring("Authorization=".length());
if (v.startsWith("Bearer ")) {
return v.substring("Bearer ".length());
}
return v;
}
}
return null;
}
}

7
dk-modules/sample/src/main/resources/mapper/ManageDevicePayloadCustomMapper.xml

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.sample.manage.mapper.ManageDevicePayloadCustomMapper">
</mapper>

15
dk-modules/sample/src/main/resources/mapper/WaylineJobAtmosphereMapper.xml

@ -4,4 +4,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.sample.wayline.mapper.WaylineJobAtmosphereMapper">
<select id="selectSpiritSmellWayLineJobIds" resultType="java.lang.Long" parameterType="java.lang.String">
select distinct wayline_job_id from wayline_job_atmosphere
<where>
<if test="dockSn != null and dockSn != ''">
dock_sn = #{dockSn};
</if>
</where>
</select>
<select id="selectDistinctWaylineFileId" resultType="java.lang.String" >
select distinct file_id from wayline_job_atmosphere
</select>
</mapper>

23
dk-modules/sample/src/main/resources/mapper/WaylineJobMapper.xml

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.sample.wayline.mapper.IWaylineJobMapper">
<select id="getPage"
resultType="org.dromara.sample.wayline.model.entity.WaylineJobEntity">
SELECT
*
FROM
wayline_file wf
LEFT JOIN wayline_device wd ON wd.wayline_id = wf.wayline_id
LEFT JOIN manage_device md ON md.device_sn = wd.device_sn
where 1=1
<if test="param.deviceSn != null and param.deviceSn != ''">
AND wd.device_sn = #{param.deviceSn}
</if>
GROUP BY wf.wayline_id
</select>
</mapper>

10
dk-modules/system/src/main/java/org/dromara/system/controller/system/SysDepartBoundaryController.java

@ -1,12 +1,15 @@
package org.dromara.system.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
@ -38,8 +41,8 @@ public class SysDepartBoundaryController extends BaseController {
*/
@Operation(summary ="查询部门的地理位置",description = "查询部门的地理位置")
@GetMapping(value = "/listJson")
public R<List<SysDepartBoundaryBo>> listJson(SysDepartBoundary departBoundary) {
List<SysDepartBoundaryBo> listJson = departBoundaryService.listJson(departBoundary);
public R<String> listJson(SysDepartBoundary departBoundary) {
String listJson = departBoundaryService.listJson(departBoundary);
return R.ok("查询成功!",listJson);
}
/**
@ -71,6 +74,7 @@ public class SysDepartBoundaryController extends BaseController {
* @return
*/
@RepeatSubmit()
@Log(title = "导入部门区域", businessType = BusinessType.IMPORT)
@Operation(summary ="新增部门区域",description = "新增部门区域(areaType: 0:市级 1:区级(县) 2:镇级(街道) 3:村级)")
@RequestMapping(value = "/{areaType}/{parentId}/upload", method = RequestMethod.POST)
public R<Void> uploadShpFile(@RequestParam("file") MultipartFile file,
@ -100,6 +104,8 @@ public class SysDepartBoundaryController extends BaseController {
* @param id
* @return
*/
@SaCheckPermission("system:boundary:delete")
@Log(title = "删除部门区域", businessType = BusinessType.DELETE)
@Operation(summary ="删除部门区域",description = "删除部门区域")
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
public R<Void> deleteDepartBoundary(@RequestParam(name = "id") String id) {

11
dk-modules/system/src/main/java/org/dromara/system/controller/system/SysUserController.java

@ -37,6 +37,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 用户信息
@ -334,4 +335,14 @@ public class SysUserController extends BaseController {
return R.ok(userService.selectUserListByDept(deptId));
}
/**
* 用于设备组添加成员,根据目标值类型查询
* @param params
* @return
*/
@GetMapping("/list/target")
public List<Map<String,Object>> listTargetTypeByUser(List<Map<String,Object>> params){
return userService.listTargetTypeByUser(params);
}
}

31
dk-modules/system/src/main/java/org/dromara/system/domain/bo/SysDepartBoundaryBo.java

@ -7,27 +7,24 @@ import lombok.Getter;
@Data
public class SysDepartBoundaryBo {
private String departId;
/**
* 区域类别 1是市级 2是区级
* 部门id
*/
private AreaType areaType;
private String landCategoriesJson;
private String deptId;
@AllArgsConstructor
@Getter
public enum AreaType {
Municipal("1","市级"),
DistrictLevel("2","区级");
/**
* 部门名称
*/
private String deptName;
private String code;
/**
* 区域类别 areaType: 0市级 1区级() 2镇级(街道) 3村级
*/
private Integer areaType;
private String desc;
/**
* 区域矢量数据
*/
private String landCategoriesJson;
}
}

6
dk-modules/system/src/main/java/org/dromara/system/dubbo/RemoteSubmailConfigServiceImpl.java

@ -60,7 +60,7 @@ public class RemoteSubmailConfigServiceImpl implements RemoteSubmailConfigServic
Long deptId = Convert.toLong(map.get("deptId"));
List<SysUserVo> sysUserVos = userService.selectUserListByDept(Convert.toLong(deptId));
Set<String> phones = sysUserVos.stream().filter(u -> u.getNoticeType() == 1 && StrUtil.isNotEmpty(u.getPhonenumber())).map(SysUserVo::getPhonenumber).collect(Collectors.toSet());
sysSubmailConfigService.sendPhone(code,phones, JSON.toJSONString(map));
sysSubmailConfigService.sendPhone(code,phones, JSON.toJSONString(map),null);
}
}
@ -74,7 +74,7 @@ public class RemoteSubmailConfigServiceImpl implements RemoteSubmailConfigServic
* @param noticeMap
*/
@Override
public void remoteSendUser(String code, List<Long> userIds, Map<String, Object> noticeMap) {
public void remoteSendUser(String code, List<Long> userIds, Map<String, Object> noticeMap,String project) {
userIds.forEach(userId -> {
SysUserVo sysUserVo = userService.selectUserById(userId);
@ -83,7 +83,7 @@ public class RemoteSubmailConfigServiceImpl implements RemoteSubmailConfigServic
Set<String> phones = new HashSet<>();
phones.add(sysUserVo.getPhonenumber());
sysSubmailConfigService.sendPhone(code,phones, JSON.toJSONString(noticeMap));
sysSubmailConfigService.sendPhone(code,phones, JSON.toJSONString(noticeMap),project);
}
});

2
dk-modules/system/src/main/java/org/dromara/system/mapper/SysDepartBoundaryMapper.java

@ -24,7 +24,7 @@ public interface SysDepartBoundaryMapper extends BaseMapper<SysDepartBoundary> {
void saveBatchBoundary(@Param("list") List<SysDepartBoundary> boundaryList);
String listJson(@Param("deptId") String deptId);
String listJson(@Param("list") List<Long> deptIdList);
List<SysDepartBoundary> listDepartBoundaryByLngAndLat(@Param("lng") Double lng,@Param("lat") Double lat);
}

4
dk-modules/system/src/main/java/org/dromara/system/mapper/SysUserMapper.java

@ -92,9 +92,7 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
})
int updateById(@Param(Constants.ENTITY) SysUser user);
@DataPermission({
@DataColumn(key = "deptName", value = "dept_id")
})
List<SysUserVo> selectFlwByIds(@Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
List<SysUserVo> allList(@Param("param") SysUserBo user);

2
dk-modules/system/src/main/java/org/dromara/system/service/ISysDepartBoundaryService.java

@ -28,7 +28,7 @@ public interface ISysDepartBoundaryService extends IService<SysDepartBoundary>{
boolean addDepartBoundary(SysDepartBoundary departBoundary);
List<SysDepartBoundaryBo> listJson(SysDepartBoundary departBoundary);
String listJson(SysDepartBoundary departBoundary);
List<SysDepartBoundary> listDepartBoundaryByLngAndLat(Double lng, Double lat);

8
dk-modules/system/src/main/java/org/dromara/system/service/ISysDeptService.java

@ -162,4 +162,12 @@ public interface ISysDeptService {
SysDept addBoundaryDept(SysDeptBo sysDeptBo);
List<SysDeptVo> listTreeDeptByChild(Long deptId);
/**
* 根据当前部门查询下一级
* @param deptId
* @return
*/
List<SysDeptVo> selectSecondByParentId(Long deptId);
}

2
dk-modules/system/src/main/java/org/dromara/system/service/ISysSubmailConfigService.java

@ -72,7 +72,7 @@ public interface ISysSubmailConfigService {
R<String> cmdSend(String code, String multiParam);
R<String> sendPhone(String code,Set<String>phones, String multiParam);
R<String> sendPhone(String code,Set<String>phones, String multiParam,String project);
String submailSendUtil(SysSubmailConfigBo bo, List<SysSubmailConfigUserVo> configUserVoList);
String submailSendPhone(SysSubmailConfigBo bo, Set<String> phones);

8
dk-modules/system/src/main/java/org/dromara/system/service/ISysUserService.java

@ -7,6 +7,7 @@ import org.dromara.system.domain.vo.SysUserExportVo;
import org.dromara.system.domain.vo.SysUserVo;
import java.util.List;
import java.util.Map;
/**
* 用户 业务层
@ -280,4 +281,11 @@ public interface ISysUserService {
List<SysUserVo> selectFlwByIds(List<Long> userIds, Long deptId);
List<SysUserVo> allList(SysUserBo user);
/**
* 用于设备组添加成员,根据目标值类型查询
* @param params
* @return
*/
List<Map<String, Object>> listTargetTypeByUser(List<Map<String, Object>> params);
}

30
dk-modules/system/src/main/java/org/dromara/system/service/impl/SysDepartBoundaryServiceImpl.java

@ -1,12 +1,15 @@
package org.dromara.system.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.api.domain.vo.RemoteDeptVo;
import org.dromara.system.domain.SysDepartBoundary;
@ -215,23 +218,20 @@ public class SysDepartBoundaryServiceImpl extends ServiceImpl<SysDepartBoundaryM
}
@Override
public List<SysDepartBoundaryBo> listJson(SysDepartBoundary departBoundary) {
if(ObjectUtil.isEmpty(departBoundary.getDeptId())){
throw new ServiceException("部门【id】不存在");
}
public String listJson(SysDepartBoundary departBoundary) {
//获取当前人所属部门
Long deptId = LoginHelper.getDeptId();
//根据当前所属部门id查询下级部门,获取部门所属区域
List<SysDeptVo> deptVoList = deptService.selectSecondByParentId(deptId);
List<Long> secondDeptIdList = StreamUtils.toList(deptVoList, SysDeptVo::getDeptId);
SysDepartBoundaryBo child = new SysDepartBoundaryBo();
child.setDepartId(String.valueOf(departBoundary.getDeptId()));
child.setAreaType(SysDepartBoundaryBo.AreaType.DistrictLevel);
child.setLandCategoriesJson(this.baseMapper.listJson(String.valueOf(departBoundary.getDeptId())));
return this.baseMapper.listJson(secondDeptIdList.stream().distinct().toList());
SysDeptVo sysDeptVo = deptService.getByParentId(String.valueOf(departBoundary.getDeptId()));
SysDepartBoundaryBo parent = new SysDepartBoundaryBo();
parent.setDepartId(String.valueOf(sysDeptVo.getDeptId()));
parent.setAreaType(SysDepartBoundaryBo.AreaType.Municipal);
parent.setLandCategoriesJson(this.baseMapper.listJson(String.valueOf(sysDeptVo.getDeptId())));
return List.of(child,parent);
}
/**
@ -249,7 +249,7 @@ public class SysDepartBoundaryServiceImpl extends ServiceImpl<SysDepartBoundaryM
@Override
public String listUserJson() {
Long deptId = LoginHelper.getDeptId();
return this.baseMapper.listJson(String.valueOf(deptId));
return this.baseMapper.listJson(List.of(deptId));
}
@Override

15
dk-modules/system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java

@ -412,4 +412,19 @@ public class SysDeptServiceImpl implements ISysDeptService {
return baseMapper.listTreeDeptByChild(deptId); //.getTableCloud()
}
@Override
public List<SysDeptVo> selectSecondByParentId(Long deptId) {
LambdaQueryWrapper<SysDept> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysDept::getParentId, deptId);
wrapper.eq(SysDept::getStatus, UserConstants.DEPT_NORMAL);
List<SysDeptVo> deptVoList = this.baseMapper.selectVoList(wrapper);
if (ObjectUtil.isEmpty(deptVoList)) {
return List.of();
}
return deptVoList;
}
}

8
dk-modules/system/src/main/java/org/dromara/system/service/impl/SysSubmailConfigServiceImpl.java

@ -3,6 +3,7 @@ package org.dromara.system.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
@ -187,7 +188,7 @@ public class SysSubmailConfigServiceImpl implements ISysSubmailConfigService {
}
@Override
public R<String> sendPhone(String code, Set<String> phones, String multiParam) {
public R<String> sendPhone(String code, Set<String> phones, String multiParam,String project) {
//找到生效配置
SysSubmailConfigBo bo = new SysSubmailConfigBo();
bo.setCode(code);
@ -197,6 +198,11 @@ public class SysSubmailConfigServiceImpl implements ISysSubmailConfigService {
}
SysSubmailConfigVo firstConfigVo = sysSubmailConfigVoTempList.get(0);
//如果模版不为空则使用传过来的模版
if (ObjectUtil.isNotEmpty(project)){
firstConfigVo.setProject(project);
}
BeanUtil.copyProperties(firstConfigVo,bo);
bo.setMultiParam(multiParam);

84
dk-modules/system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java

@ -37,9 +37,8 @@ import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
* 用户 业务层处理
@ -613,6 +612,85 @@ public class SysUserServiceImpl implements ISysUserService {
return baseMapper.allList(user);
}
/**
* 用于设备组添加成员,根据目标值类型查询
* @param params
* @return
*/
@Override
public List<Map<String, Object>> listTargetTypeByUser(List<Map<String, Object>> params) {
//1、定义返回值
List<Map<String, Object>> result = new ArrayList<>();
//2、根据传过来的集合中的目标值类型分组
Map<Integer, List<Map<String, Object>>> targetMap = params.stream().collect(Collectors.groupingBy(p -> Integer.valueOf(p.get("targetType") + "")));
//3、根据目标值的遍历
targetMap.keySet().forEach(targetType -> {
List<SysUser> currentUserList = new ArrayList<>();
//4、获取相应目标类型的目标值集合
List<Map<String, Object>> targetMapList = targetMap.get(targetType);
//5、如果为空则结束当前循环
if (ObjectUtil.isEmpty(targetMapList)) {
return;
}
//不为空再根据集合中的目标值转换成long集合
List<Long> targetKeyList = targetMapList.stream().map(p -> Long.valueOf(p.get("targetKey") + "")).distinct().toList();
//根据目标值类型找到对应的解析方法
switch (targetType) {
case 1:
currentUserList= this.baseMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getUserId, targetKeyList));
break;
case 2:
//角色
List<Long> userRoleIds = Optional.ofNullable(userRoleMapper.selectList(
new LambdaQueryWrapper<SysUserRole>()
.in(SysUserRole::getRoleId, targetKeyList)))
.orElse(List.of())
.stream()
.map(SysUserRole::getUserId)
.filter(Objects::nonNull)
.distinct()
.toList();
currentUserList = this.baseMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getDeptId, userRoleIds));
break;
case 3:
//部门
currentUserList = this.baseMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getDeptId, targetKeyList));
break;
default:
break;
}
//拿到目标值获取的信息进行构建返回格式
currentUserList.forEach(sysUser -> {
Map<String,Object> userMap = new HashMap<>();
//用户
userMap.put("userId",sysUser.getUserId());
userMap.put("userName",sysUser.getUserName());
userMap.put("nickName",sysUser.getNickName());
//防止重复存入
if (result.stream().noneMatch(p-> Long.valueOf(p.get("userId") + "").equals(sysUser.getUserId()))) {
result.add(userMap);
}
});
});
return result;
}
/**
* 通过用户ID查询用户账户
*

8
dk-modules/system/src/main/resources/mapper/system/SysDepartBoundaryMapper.xml

@ -154,7 +154,8 @@
'deptId', l.dept_id,
'deptName', l.dept_name,
'name', l.name_path,
'community_name', l.name_path
'community_name', l.name_path,
'areaType',l.area_type
),
'geometry',
ST_AsGeoJSON(l.boundary)
@ -167,7 +168,10 @@
sys_depart_boundary l
LEFT JOIN sys_dept d ON l.dept_id = d.dept_id
WHERE
d.dept_id = #{deptId}
d.dept_id in
<foreach collection="list" item="item" open="(" close=")" separator=",">
#{item}
</foreach>
</select>
<select id="listDepartBoundaryByLngAndLat" resultType="org.dromara.system.domain.SysDepartBoundary">

5
dk-modules/workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java

@ -158,7 +158,8 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
dto.setProcessInstanceId(instance.getId());
dto.setTaskId(taskList.get(0).getId());
executeTask(taskList.get(0).getId(),true);
// executeTask(taskList.get(0).getId(),true);
executeTask(taskList.get(0).getId(),false);
return dto;
}
@ -242,7 +243,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
//发送短信是否属于指派
if(completeTaskBo.getAssign()){
remoteSubmailConfigService.remoteSendUser("smsMultixsend",List.of(Long.valueOf(completeTaskBo.getHandler())),noticeMap);
remoteSubmailConfigService.remoteSendUser("smsMultixsend",List.of(Long.valueOf(completeTaskBo.getHandler())),noticeMap,"kKv7s3");
}

4
dk-visual/nacos/src/main/resources/application.properties

@ -40,9 +40,9 @@ spring.sql.init.platform=mysql
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/dk_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
db.url.0=jdbc:mysql://114.235.183.147:3306/dk_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
db.user.0=root
db.password.0=123456
db.password.0=dkcy@yf
### the maximum retry times for push
nacos.config.push.maxRetryTime=50

39
pom.xml

@ -100,6 +100,45 @@
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>wuyuan</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>wuyuan</profiles.active>
<nacos.server>127.0.0.1:8848</nacos.server>
<nacos.discovery.group>DEFAULT_GROUP</nacos.discovery.group>
<nacos.config.group>DEFAULT_GROUP</nacos.config.group>
<nacos.username>nacos</nacos.username>
<nacos.password>nacos</nacos.password>
<logstash.address>127.0.0.1:4560</logstash.address>
</properties>
</profile>
<profile>
<id>w_nantong</id> <!-- 南通生产环境 -->
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>w_nantong</profiles.active>
<nacos.server>192.168.0.8:8848</nacos.server>
<nacos.discovery.group>DEFAULT_GROUP</nacos.discovery.group>
<nacos.config.group>DEFAULT_GROUP</nacos.config.group>
<nacos.username>nacos</nacos.username>
<nacos.password>nacos</nacos.password>
<logstash.address>192.168.0.8:4560</logstash.address>
</properties>
</profile>
<profile>
<id>nantong-dev</id> <!-- 南通测试环境 -->
<properties>
<profiles.active>nantong-dev</profiles.active>
<nacos.server>127.0.0.1:8848</nacos.server>
<nacos.discovery.group>DEFAULT_GROUP</nacos.discovery.group>
<nacos.config.group>DEFAULT_GROUP</nacos.config.group>
<nacos.username>nacos</nacos.username>
<nacos.password>nacos</nacos.password>
<logstash.address>127.0.0.1:4560</logstash.address>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>

Loading…
Cancel
Save