Merge remote-tracking branch 'origin/dev' into dev
| | |
| | | package com.ard.web.controller.inspection; |
| | | |
| | | import com.ard.common.core.controller.BaseController; |
| | | import io.lettuce.core.dynamic.annotation.Value; |
| | | import io.swagger.annotations.Api; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | |
| | | @Api(tags = "大文件上传") |
| | | @RestController |
| | | @RequestMapping("/inspection/bigfile") |
| | | public class BigFileUploadController { |
| | | public class BigFileUploadController extends BaseController { |
| | | |
| | | /** 若依文件上传根目录(从配置文件读取) */ |
| | | //@Value("${ruoyi.profile}") |
| | |
| | | public AjaxResult handleControlRequest( |
| | | @RequestParam String boxSn, |
| | | @RequestParam String type, |
| | | @RequestParam boolean approve) { |
| | | return AjaxResult.success(uavControlService.handleControlResponse(boxSn, approve, type)); |
| | | @RequestParam boolean approve, |
| | | @RequestParam Long requesterId |
| | | ) { |
| | | return AjaxResult.success(uavControlService.handleControlResponse(boxSn, approve, type, requesterId)); |
| | | } |
| | | |
| | | /** |
| | |
| | | public AjaxResult getCurrentController(@RequestParam String boxSn, @RequestParam String type) { |
| | | return AjaxResult.success(uavControlService.getCurrentController(boxSn, type)); |
| | | } |
| | | |
| | | /** |
| | | * 获取全部类型当前控制者 |
| | | */ |
| | |
| | | * 航线类型 |
| | | * 1:逐点巡检 |
| | | * 2:沿线巡检 |
| | | * 3:任务航线 |
| | | * 4:巡检航线 |
| | | * 3:巡检航线 |
| | | * */ |
| | | private String type; |
| | | |
| | |
| | | /** 执行时间 */ |
| | | private Date executeTime; |
| | | |
| | | /** |
| | | * 任务类型 |
| | | * 1:报警任务 |
| | | * 2:巡检任务 |
| | | * */ |
| | | private String taskType; |
| | | |
| | | /** 航线任务航点列表 */ |
| | | private List<ArdRoutePoint> missionDetailList; |
| | | |
| | | /** 任务描述 */ |
| | | private String taskDescription; |
| | | |
| | | } |
| | |
| | | package com.ard.route.domain.route; |
| | | |
| | | import com.ard.common.core.domain.BaseEntity; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | |
| | | */ |
| | | @Data |
| | | public class ArdRoutePoint{ |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** 航线任务ID */ |
| | | private String missionId; |
| | |
| | | |
| | | import com.ard.common.exception.ControlException; |
| | | import com.ard.common.utils.DateUtils; |
| | | import com.ard.common.utils.SecurityUtils; |
| | | import com.ard.common.utils.file.FileUtils; |
| | | import com.ard.common.utils.uuid.IdUtils; |
| | | import com.ard.data.noflyzone.domain.ArdNoFlyZone; |
| | |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import javax.annotation.Resource; |
| | | |
| | | import static com.ard.common.utils.SecurityUtils.getUsername; |
| | | import static com.ard.route.enums.kml.DroneEnumValueEnums.M350_RTK; |
| | | import static com.ard.route.util.InitializationUtils.divided_23; |
| | | import static com.ard.route.util.ToolUtils.*; |
| | |
| | | */ |
| | | private void checkRouteMissionStatus(ArdRouteInfo ardRouteInfo,String type){ |
| | | ArdRouteMission mission = ardRouteMissionMapper.selectArdRouteMissionById(ardRouteInfo.getMissionId()); |
| | | if (mission != null){ |
| | | switch(type){ |
| | | case "1": |
| | | validateForCreate(mission); |
| | |
| | | bindRoute(mission, ardRouteInfo); |
| | | break; |
| | | case "3": |
| | | executeMission(mission); |
| | | executeMission(mission,ardRouteInfo); |
| | | break; |
| | | default: |
| | | throw new RuntimeException("不支持的操作类型!!!"); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | private void bindRoute(ArdRouteMission mission, ArdRouteInfo routeInfo) { |
| | | if (!"0".equals(mission.getRouteId())) { |
| | | if (mission.getRouteId() != null) { |
| | | throw new RuntimeException("航线任务下已绑定航线,不可创建新航线信息!!!"); |
| | | } |
| | | mission.setRouteId(routeInfo.getId()); |
| | | ardRouteMissionMapper.updateArdRouteMission(mission); |
| | | } |
| | | |
| | | private void executeMission(ArdRouteMission mission) { |
| | | private void executeMission(ArdRouteMission mission,ArdRouteInfo ardRouteInfo) { |
| | | if ("0".equals(mission.getExecuteStatus())) { |
| | | mission.setRouteId(ardRouteInfo.getId()); |
| | | mission.setExecuteStatus("1"); |
| | | mission.setExecuteBy(getUsername()); |
| | | mission.setExecuteBy(SecurityUtils.getUsername()); |
| | | mission.setExecuteTime(DateUtils.getNowDate()); |
| | | mission.setUpdateTime(DateUtils.getNowDate()); |
| | | ardRouteMissionMapper.updateArdRouteMission(mission); |
| | |
| | | @Override |
| | | public Boolean routeBegins(String id,String boxSn) { |
| | | ArdRouteInfo route = ardRouteInfoMapper.selectArdRouteInfoById(id); |
| | | if (null != route){ |
| | | // 判断是否循环航线 |
| | | if (null != route && "0".equals(route.getIsLoop())){ |
| | | if ("0".equals(route.getIsLoop())){ |
| | | deleteArdRouteInfoById(id); |
| | | } |
| | | checkRouteMissionStatus(route,"3"); |
| | | } |
| | | WayLineBeginDTO wayLineBeginDTO = new WayLineBeginDTO(boxSn); |
| | |
| | | |
| | | import java.util.List; |
| | | import com.ard.common.utils.DateUtils; |
| | | import com.ard.common.utils.SecurityUtils; |
| | | import com.ard.common.utils.uuid.IdUtils; |
| | | import com.ard.route.domain.route.ArdRouteMission; |
| | | import com.ard.route.domain.route.ArdRoutePoint; |
| | |
| | | ArdRouteMission ardRouteMission = new ArdRouteMission(); |
| | | ardRouteMission.setId(id); |
| | | ardRouteMission.setExecuteStatus(status); |
| | | ardRouteMission.setExecuteBy(getUsername()); |
| | | ardRouteMission.setExecuteBy(SecurityUtils.getUsername()); |
| | | ardRouteMission.setExecuteTime(DateUtils.getNowDate()); |
| | | ardRouteMission.setUpdateTime(DateUtils.getNowDate()); |
| | | return ardRouteMissionMapper.updateArdRouteMission(ardRouteMission); |
| | |
| | | <result property="updateTime" column="update_time" /> |
| | | <result property="executeBy" column="execute_by" /> |
| | | <result property="executeTime" column="execute_time" /> |
| | | <result property="taskType" column="task_type" /> |
| | | <result property="taskDescription" column="task_description" /> |
| | | </resultMap> |
| | | |
| | | <sql id="selectArdRouteMissionVo"> |
| | |
| | | update_by, |
| | | update_time, |
| | | execute_by, |
| | | execute_time |
| | | execute_time, |
| | | task_type, |
| | | task_description |
| | | from ard_route_mission |
| | | </sql> |
| | | |
| | |
| | | <if test="executeStatus != null and executeStatus != ''"> and execute_status = #{executeStatus}</if> |
| | | <if test="executeBy != null and executeBy != ''"> and execute_by = #{executeBy}</if> |
| | | <if test="executeTime != null "> and execute_time = #{executeTime}</if> |
| | | <if test="taskType != null and taskType != ''"> and task_type = #{taskType}</if> |
| | | </where> |
| | | order by create_time asc |
| | | order by create_time DESC |
| | | </select> |
| | | |
| | | <select id="selectArdRouteMissionById" parameterType="String" resultMap="ArdRouteMissionResult"> |
| | | <include refid="selectArdRouteMissionVo"/> |
| | | where id = #{id} |
| | | order by create_time asc |
| | | order by create_time DESC |
| | | </select> |
| | | |
| | | <insert id="insertArdRouteMission" parameterType="ArdRouteMission"> |
| | |
| | | <if test="updateTime != null">update_time,</if> |
| | | <if test="executeBy != null">execute_by,</if> |
| | | <if test="executeTime != null">execute_time,</if> |
| | | <if test="taskType != null">task_type,</if> |
| | | <if test="taskDescription != null">task_description,</if> |
| | | </trim> |
| | | <trim prefix="values (" suffix=")" suffixOverrides=","> |
| | | <if test="id != null">#{id},</if> |
| | |
| | | <if test="updateTime != null">#{updateTime},</if> |
| | | <if test="executeBy != null">#{executeBy},</if> |
| | | <if test="executeTime != null">#{executeTime},</if> |
| | | <if test="taskType != null">#{taskType},</if> |
| | | <if test="taskDescription != null">#{taskDescription},</if> |
| | | </trim> |
| | | </insert> |
| | | |
| | |
| | | <if test="updateTime != null">update_time = #{updateTime},</if> |
| | | <if test="executeBy != null">execute_by = #{executeBy},</if> |
| | | <if test="executeTime != null">execute_time = #{executeTime},</if> |
| | | <if test="taskType != null">task_type = #{taskType},</if> |
| | | <if test="taskDescription != null">task_description = #{taskDescription},</if> |
| | | </trim> |
| | | where id = #{id} |
| | | </update> |
| | |
| | | import javax.annotation.Resource; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | /** |
| | |
| | | @Resource |
| | | private ISysUserService sysUserService; |
| | | |
| | | /** 当前飞行控制权限用户 */ |
| | | /** |
| | | * 当前飞行控制权限用户 |
| | | */ |
| | | private final ConcurrentHashMap<String, Long> uavFlyControlMap = new ConcurrentHashMap<>(); |
| | | |
| | | /** 当前载荷控制权限用户 */ |
| | | /** |
| | | * 当前载荷控制权限用户 |
| | | */ |
| | | private final ConcurrentHashMap<String, Long> uavPayloadControlMap = new ConcurrentHashMap<>(); |
| | | |
| | | /** 飞行控制请求 */ |
| | | private final ConcurrentHashMap<String, Long> flyControlRequests = new ConcurrentHashMap<>(); |
| | | /** |
| | | * 飞行控制请求:boxSn -> 多个请求者 |
| | | */ |
| | | private final ConcurrentHashMap<String, Set<Long>> flyControlRequests = new ConcurrentHashMap<>(); |
| | | |
| | | /** 载荷控制请求 */ |
| | | private final ConcurrentHashMap<String, Long> payloadControlRequests = new ConcurrentHashMap<>(); |
| | | /** |
| | | * 载荷控制请求 |
| | | */ |
| | | private final ConcurrentHashMap<String, Set<Long>> payloadControlRequests = new ConcurrentHashMap<>(); |
| | | |
| | | |
| | | /** |
| | | * 请求获取 UAV 控制权限 |
| | |
| | | /** |
| | | * 处理单个控制类型的请求 |
| | | */ |
| | | /** |
| | | * 处理单个控制类型的请求(支持多请求者) |
| | | */ |
| | | private boolean requestSingleControl(String boxSn, UavControlType controlType, Long requester) { |
| | | |
| | | ConcurrentHashMap<String, Long> controlMap = getControlMap(controlType); |
| | | ConcurrentHashMap<String, Long> requestMap = getRequestMap(controlType); |
| | | ConcurrentHashMap<String, Set<Long>> requestMap = getRequestMap(controlType); |
| | | |
| | | Long controller = controlMap.get(boxSn); |
| | | |
| | |
| | | |
| | | // 通知原控制者被抢占 |
| | | uavControlManager.sendControlTakeover(controller, requester, boxSn, controlType.getType()); |
| | | |
| | | // 通知新控制者获得控制 |
| | | uavControlManager.sendControlApproval(requester, boxSn, controlType.getType(), requester); |
| | | return true; |
| | | } |
| | | |
| | | // 优先级相同或更低 → 申请流程 |
| | | requestMap.put(boxSn, requester); |
| | | // ===== 以下是关键改动点 ===== |
| | | |
| | | // 优先级相同或更低 → 加入请求集合(不覆盖) |
| | | Set<Long> requesters = requestMap.computeIfAbsent(boxSn, k -> ConcurrentHashMap.newKeySet()); |
| | | requesters.add(requester); |
| | | |
| | | // 通知当前控制者:有新的请求者 |
| | | uavControlManager.sendControlRequest(controller, boxSn, controlType.getType(), requester); |
| | | |
| | | return false; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 处理 UAV 控制请求的响应 |
| | | */ |
| | | public boolean handleControlResponse(String boxSn, boolean approve, String type) { |
| | | public boolean handleControlResponse(String boxSn, boolean approve, String type, Long requester) { |
| | | UavControlType controlType = UavControlType.fromString(type); |
| | | Long controller = SecurityUtils.getUserId(); |
| | | return handleSingleControlResponse(boxSn, approve, controlType, controller); |
| | | return handleSingleControlResponse(boxSn, approve, controlType, controller, requester); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 处理单个控制类型请求响应 |
| | | */ |
| | | private boolean handleSingleControlResponse(String boxSn, boolean approve, UavControlType controlType, |
| | | Long controller) { |
| | | ConcurrentHashMap<String, Long> requestMap = getRequestMap(controlType); |
| | | Long requester = requestMap.get(boxSn); |
| | | private boolean handleSingleControlResponse(String boxSn, |
| | | boolean approve, |
| | | UavControlType controlType, |
| | | Long controller, |
| | | Long requester) { |
| | | |
| | | if (requester == null || requester.equals(controller)) { |
| | | ConcurrentHashMap<String, Set<Long>> requestMap = getRequestMap(controlType); |
| | | Set<Long> requesters = requestMap.get(boxSn); |
| | | |
| | | if (requesters == null || !requesters.contains(requester)) { |
| | | throw new ControlException("无控制请求"); |
| | | } |
| | | |
| | | if (approve) { |
| | | getControlMap(controlType).put(boxSn, requester); |
| | | |
| | | // 通知被批准者 |
| | | uavControlManager.sendControlApproval(requester, boxSn, controlType.getType(), controller); |
| | | |
| | | // 🚨 其他请求者自动拒绝(强烈建议) |
| | | for (Long other : requesters) { |
| | | if (!other.equals(requester)) { |
| | | requesters.remove(requester); |
| | | uavControlManager.sendControlRejection(other, boxSn, controlType.getType(), controller); |
| | | } |
| | | } |
| | | } else { |
| | | uavControlManager.sendControlRejection(requester, boxSn, controlType.getType(), controller); |
| | | } |
| | | |
| | | requesters.remove(requester); |
| | | if (requesters.isEmpty()) { |
| | | requestMap.remove(boxSn); |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 释放 UAV 控制权限 |
| | |
| | | /** |
| | | * 根据控制类型获取对应请求 Map |
| | | */ |
| | | private ConcurrentHashMap<String, Long> getRequestMap(UavControlType controlType) { |
| | | private ConcurrentHashMap<String, Set<Long>> getRequestMap(UavControlType controlType) { |
| | | switch (controlType) { |
| | | case FLY: |
| | | return flyControlRequests; |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取用户优先级 |
| | | */ |