增加用户优先级和所属平台 调整无人机控制逻辑增加优先级判断
| | |
| | | /** 角色ID */ |
| | | private Long roleId; |
| | | |
| | | /** 优先级 */ |
| | | private Integer priority; |
| | | /** 所属平台 */ |
| | | private String platform; |
| | | |
| | | public SysUser() |
| | | { |
| | | |
| | |
| | | this.roleId = roleId; |
| | | } |
| | | |
| | | public Integer getPriority() { |
| | | return priority; |
| | | } |
| | | |
| | | public void setPriority(Integer priority) { |
| | | this.priority = priority; |
| | | } |
| | | |
| | | public String getPlatform() { |
| | | return platform; |
| | | } |
| | | |
| | | public void setPlatform(String platform) { |
| | | this.platform = platform; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) |
| | |
| | | <result property="delFlag" column="del_flag" /> |
| | | <result property="loginIp" column="login_ip" /> |
| | | <result property="loginDate" column="login_date" /> |
| | | <result property="priority" column="priority" /> |
| | | <result property="platform" column="platform" /> |
| | | <result property="createBy" column="create_by" /> |
| | | <result property="createTime" column="create_time" /> |
| | | <result property="updateBy" column="update_by" /> |
| | |
| | | </resultMap> |
| | | |
| | | <sql id="selectUserVo"> |
| | | select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, |
| | | select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.priority,u.platform,u.login_date, u.create_by, u.create_time, u.remark, |
| | | d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status, |
| | | r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status |
| | | from sys_user u |
| | |
| | | </sql> |
| | | |
| | | <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult"> |
| | | select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u |
| | | select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.priority,u.platform, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u |
| | | left join sys_dept d on u.dept_id = d.dept_id |
| | | where u.del_flag = '0' |
| | | <if test="userId != null and userId != 0"> |
| | |
| | | <if test="password != null and password != ''">password,</if> |
| | | <if test="status != null and status != ''">status,</if> |
| | | <if test="createBy != null and createBy != ''">create_by,</if> |
| | | <if test="priority != null and priority != ''">priority,</if> |
| | | <if test="platform != null and platform != ''">platform,</if> |
| | | <if test="remark != null and remark != ''">remark,</if> |
| | | create_time |
| | | )values( |
| | |
| | | <if test="password != null and password != ''">#{password},</if> |
| | | <if test="status != null and status != ''">#{status},</if> |
| | | <if test="createBy != null and createBy != ''">#{createBy},</if> |
| | | <if test="priority != null and priority != ''">#{priority},</if> |
| | | <if test="platform != null and platform != ''">#{platform},</if> |
| | | <if test="remark != null and remark != ''">#{remark},</if> |
| | | sysdate() |
| | | ) |
| | |
| | | <if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if> |
| | | <if test="loginDate != null">login_date = #{loginDate},</if> |
| | | <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> |
| | | <if test="priority != null">priority = #{priority},</if> |
| | | <if test="platform != null">platform = #{platform},</if> |
| | | <if test="remark != null">remark = #{remark},</if> |
| | | update_time = sysdate() |
| | | </set> |
| | |
| | | import com.ard.common.constant.CacheConstants; |
| | | import com.ard.common.core.domain.entity.SysUser; |
| | | import com.ard.common.core.redis.RedisCache; |
| | | import com.ard.work.service.control.UavControlService; |
| | | import com.ard.work.domain.message.BaseMessage; |
| | | import com.ard.work.domain.message.UavControlMessage; |
| | | import com.ard.work.component.websocket.utils.WebSocketUtil; |
| | | import com.ard.work.domain.message.*; |
| | | import com.ard.work.service.control.UavControlService; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | |
| | | @Resource |
| | | private RedisCache redisCache; |
| | | |
| | | /** |
| | | * 发送控制请求 |
| | | */ |
| | | public void sendControlRequest(Long controllerId, String boxSn, String type, Long requester) { |
| | | UavControlMessage message = new UavControlMessage(boxSn, type, requester, null); |
| | | SysUser sysUser = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + requester); |
| | | message.setRequester(sysUser); |
| | | BaseMessage<UavControlMessage> baseMessage = new BaseMessage<>("control", message); |
| | | WebSocketUtil.sendMessage(controllerId, JSON.toJSONString(baseMessage)); |
| | | /* ===================== 1️⃣ 申请控制 ===================== */ |
| | | |
| | | public void sendControlRequest(Long controllerId, String boxSn, String type, Long requesterId) { |
| | | |
| | | SysUser requester = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + requesterId); |
| | | |
| | | UavControlMessage msg = new UavControlMessage(); |
| | | msg.setBoxSn(boxSn); |
| | | msg.setType(type); |
| | | msg.setAction("request"); |
| | | msg.setOperatorId(requesterId); |
| | | msg.setOperator(requester); |
| | | |
| | | BaseMessage<UavControlMessage> base = new BaseMessage<>("control", msg); |
| | | |
| | | WebSocketUtil.sendMessage(controllerId, JSON.toJSONString(base)); |
| | | } |
| | | |
| | | /** |
| | | * 发送控制同意通知 |
| | | */ |
| | | public void sendControlApproval(Long requesterId, String boxSn, String type) { |
| | | UavControlMessage message = new UavControlMessage(boxSn, type, null, true); |
| | | BaseMessage<UavControlMessage> baseMessage = new BaseMessage<>("control", message); |
| | | WebSocketUtil.sendMessage(requesterId, JSON.toJSONString(baseMessage)); |
| | | /* ===================== 2️⃣ 同意控制 ===================== */ |
| | | |
| | | public void sendControlApproval(Long requesterId, String boxSn, String type, Long controllerId) { |
| | | |
| | | SysUser controller = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + controllerId); |
| | | |
| | | UavControlMessage msg = new UavControlMessage(); |
| | | msg.setBoxSn(boxSn); |
| | | msg.setType(type); |
| | | msg.setAction("approve"); |
| | | msg.setApproved(true); |
| | | msg.setController(controller); |
| | | |
| | | BaseMessage<UavControlMessage> base = new BaseMessage<>("control", msg); |
| | | |
| | | WebSocketUtil.sendMessage(requesterId, JSON.toJSONString(base)); |
| | | } |
| | | |
| | | /** |
| | | * 发送控制拒绝通知 |
| | | */ |
| | | public void sendControlRejection(Long requesterId, String boxSn, String type) { |
| | | UavControlMessage message = new UavControlMessage(boxSn, type, null, false); |
| | | BaseMessage<UavControlMessage> baseMessage = new BaseMessage<>("control", message); |
| | | WebSocketUtil.sendMessage(requesterId, JSON.toJSONString(baseMessage)); |
| | | /* ===================== 3️⃣ 拒绝控制 ===================== */ |
| | | |
| | | public void sendControlRejection(Long requesterId, String boxSn, String type, Long controllerId) { |
| | | |
| | | SysUser controller = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + controllerId); |
| | | |
| | | UavControlMessage msg = new UavControlMessage(); |
| | | msg.setBoxSn(boxSn); |
| | | msg.setType(type); |
| | | msg.setAction("reject"); |
| | | msg.setApproved(false); |
| | | msg.setController(controller); |
| | | |
| | | BaseMessage<UavControlMessage> base = new BaseMessage<>("control", msg); |
| | | |
| | | WebSocketUtil.sendMessage(requesterId, JSON.toJSONString(base)); |
| | | } |
| | | |
| | | /** |
| | | * 发送控制释放通知 |
| | | */ |
| | | public void sendControlRelease(String boxSn, String type) { |
| | | UavControlMessage message = new UavControlMessage(boxSn, type, null, null); |
| | | public void sendControlRelease(String boxSn, String type, Long operatorId) { |
| | | SysUser operator = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + operatorId); |
| | | |
| | | UavControlMessage message = new UavControlMessage(); |
| | | message.setBoxSn(boxSn); |
| | | message.setType(type); |
| | | message.setAction("release"); |
| | | message.setOperatorId(operatorId); |
| | | message.setOperator(operator); |
| | | |
| | | BaseMessage<UavControlMessage> baseMessage = new BaseMessage<>("control", message); |
| | | WebSocketUtil.sendMessageAll(JSON.toJSONString(baseMessage)); |
| | | } |
| | | |
| | | /* ===================== 4️⃣ 控制权接管 ===================== */ |
| | | |
| | | public void sendControlTakeover(Long oldControllerId, Long newControllerId, String boxSn, String type) { |
| | | |
| | | SysUser newController = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + newControllerId); |
| | | SysUser oldController = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + oldControllerId); |
| | | |
| | | // 1️⃣ 通知原控制者:你被抢占了 |
| | | UavControlMessage msgOld = new UavControlMessage(); |
| | | msgOld.setBoxSn(boxSn); |
| | | msgOld.setType(type); |
| | | msgOld.setAction("takeover"); |
| | | msgOld.setOperatorId(newControllerId); |
| | | msgOld.setOperator(newController); |
| | | msgOld.setControllerId(oldControllerId); |
| | | msgOld.setController(oldController); |
| | | BaseMessage<UavControlMessage> baseMessage = new BaseMessage<>("control", msgOld); |
| | | WebSocketUtil.sendMessage(oldControllerId, JSON.toJSONString(baseMessage)); |
| | | |
| | | // 2️⃣ 通知新控制者:你已获得控制权 |
| | | UavControlMessage msgNew = new UavControlMessage(); |
| | | msgNew.setBoxSn(boxSn); |
| | | msgNew.setType(type); |
| | | msgNew.setAction("approve"); // 或 "takeover" 也可 |
| | | msgNew.setOperatorId(newControllerId); |
| | | msgNew.setOperator(newController); |
| | | baseMessage = new BaseMessage<>("control", msgNew); |
| | | WebSocketUtil.sendMessage(newControllerId, JSON.toJSONString(baseMessage)); |
| | | |
| | | // 3️⃣ 广播给观战用户(可选) |
| | | UavControlMessage msgBroadcast = new UavControlMessage(); |
| | | msgBroadcast.setBoxSn(boxSn); |
| | | msgBroadcast.setType(type); |
| | | msgBroadcast.setAction("takeover"); |
| | | msgBroadcast.setOperatorId(newControllerId); |
| | | msgBroadcast.setOperator(newController); |
| | | msgBroadcast.setControllerId(oldControllerId); |
| | | msgBroadcast.setController(oldController); |
| | | baseMessage = new BaseMessage<>("control", msgBroadcast); |
| | | WebSocketUtil.sendMessageAll(JSON.toJSONString(baseMessage)); |
| | | } |
| | | |
| | | /** |
| | | * 获取指定设备的当前操作者信息 |
| | | * 该方法重写自父类,用于获取无人机和载荷的当前控制者用户ID |
| | |
| | | |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 无人机控制消息 |
| | | * @author lsy |
| | | * @date 2026/1/19 |
| | | */ |
| | | |
| | | @Data |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | |
| | | |
| | | private String boxSn; // 无人机编号 |
| | | private String type; // 控制类型(fly 或 payload) |
| | | private Long requesterId; // 申请者ID(仅在请求控制时使用) |
| | | private SysUser requester; // 申请者实体 |
| | | private Boolean approved; // 控制是否被批准(仅在处理请求控制时使用) |
| | | /** |
| | | * 是否订阅 |
| | | */ |
| | | private Boolean subscribe; |
| | | private Map<String, Long> controller; |
| | | private String action; // request / approve / reject / release / takeover |
| | | |
| | | public UavControlMessage(String boxSn, String type, Long requesterId, Boolean approved) { |
| | | this.boxSn = boxSn; |
| | | this.type = type; |
| | | this.requesterId = requesterId; |
| | | this.approved = approved; |
| | | } |
| | | /** 本次动作的发起者(申请者 / 接管者) */ |
| | | private Long operatorId; |
| | | private SysUser operator; |
| | | |
| | | /** 当前控制者 */ |
| | | private Long controllerId; |
| | | private SysUser controller; |
| | | |
| | | private Boolean approved; // true / false |
| | | |
| | | private Boolean subscribe; // true 表示订阅,false 表示取消订阅 |
| | | } |
| | |
| | | |
| | | import com.ard.common.exception.ControlException; |
| | | import com.ard.common.utils.SecurityUtils; |
| | | import com.ard.work.domain.message.UavControlType; |
| | | import com.ard.system.service.ISysUserService; |
| | | import com.ard.work.component.websocket.handler.UavControlManager; |
| | | import com.ard.work.domain.message.UavControlType; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | /** |
| | | * UAV控制服务类,负责管理对飞行和载荷的控制请求、释放和权限管理。 |
| | | * UAV控制服务类,负责管理对飞行和载荷的控制请求、释放和权限管理 |
| | | * 支持优先级抢占 |
| | | */ |
| | | @Service |
| | | public class UavControlService { |
| | |
| | | @Resource |
| | | private UavControlManager uavControlManager; |
| | | |
| | | /** |
| | | * 记录当前获得飞行控制权限的用户 |
| | | */ |
| | | @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<>(); |
| | | /** |
| | | * 记录载荷控制请求 |
| | | */ |
| | | |
| | | /** 载荷控制请求 */ |
| | | private final ConcurrentHashMap<String, Long> payloadControlRequests = new ConcurrentHashMap<>(); |
| | | |
| | | /** |
| | | * 请求获取 UAV 控制权限 |
| | | * |
| | | * @param boxSn 设备序列号 |
| | | * @param type 控制类型("fly"、"payload") |
| | | * @return 是否立即获得控制权限 |
| | | */ |
| | | public boolean requestControl(String boxSn, String type) { |
| | | UavControlType controlType = UavControlType.fromString(type); |
| | |
| | | * 处理单个控制类型的请求 |
| | | */ |
| | | private boolean requestSingleControl(String boxSn, UavControlType controlType, Long requester) { |
| | | |
| | | ConcurrentHashMap<String, Long> controlMap = getControlMap(controlType); |
| | | ConcurrentHashMap<String, Long> requestMap = getRequestMap(controlType); |
| | | |
| | | Long controller = controlMap.get(boxSn); |
| | | |
| | | // 无人控制 → 直接获取 |
| | | if (controller == null) { |
| | | controlMap.put(boxSn, requester); |
| | | uavControlManager.sendControlApproval(requester, boxSn, controlType.getType(), requester); |
| | | return true; |
| | | } |
| | | if (!controller.equals(requester)) { |
| | | requestMap.put(boxSn, requester); |
| | | uavControlManager.sendControlRequest(controller, boxSn, controlType.getType(), requester); |
| | | } else { |
| | | |
| | | // 已是控制者 |
| | | if (controller.equals(requester)) { |
| | | throw new ControlException("当前已拥有控制权"); |
| | | } |
| | | |
| | | int requesterPriority = getUserPriority(requester); |
| | | int controllerPriority = getUserPriority(controller); |
| | | |
| | | // 优先级高 → 直接接管 |
| | | if (requesterPriority > controllerPriority) { |
| | | controlMap.put(boxSn, requester); |
| | | |
| | | // 通知原控制者被抢占 |
| | | uavControlManager.sendControlTakeover(controller, requester, boxSn, controlType.getType()); |
| | | |
| | | // 通知新控制者获得控制 |
| | | uavControlManager.sendControlApproval(requester, boxSn, controlType.getType(), requester); |
| | | return true; |
| | | } |
| | | |
| | | // 优先级相同或更低 → 申请流程 |
| | | requestMap.put(boxSn, requester); |
| | | uavControlManager.sendControlRequest(controller, boxSn, controlType.getType(), requester); |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 处理 UAV 控制请求的响应(同意或拒绝) |
| | | * |
| | | * @param boxSn 设备序列号 |
| | | * @param approve 是否同意 |
| | | * @param type 控制类型 |
| | | * @return 是否成功处理 |
| | | * 处理 UAV 控制请求的响应 |
| | | */ |
| | | public boolean handleControlResponse(String boxSn, boolean approve, String type) { |
| | | UavControlType controlType = UavControlType.fromString(type); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 处理单个控制类型的请求响应 |
| | | * 处理单个控制类型请求响应 |
| | | */ |
| | | private boolean handleSingleControlResponse(String boxSn, boolean approve, UavControlType controlType, |
| | | Long controller) { |
| | |
| | | |
| | | if (approve) { |
| | | getControlMap(controlType).put(boxSn, requester); |
| | | uavControlManager.sendControlApproval(requester, boxSn, controlType.getType()); |
| | | uavControlManager.sendControlApproval(requester, boxSn, controlType.getType(), controller); |
| | | } else { |
| | | uavControlManager.sendControlRejection(requester, boxSn, controlType.getType()); |
| | | uavControlManager.sendControlRejection(requester, boxSn, controlType.getType(), controller); |
| | | } |
| | | |
| | | requestMap.remove(boxSn); |
| | |
| | | |
| | | /** |
| | | * 释放 UAV 控制权限 |
| | | * |
| | | * @param boxSn 设备序列号 |
| | | * @param type 控制类型 |
| | | * @return 是否成功释放控制 |
| | | */ |
| | | public boolean releaseControl(String boxSn, String type) { |
| | | UavControlType controlType = UavControlType.fromString(type); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 释放单个控制类型的权限 |
| | | * 释放单个控制类型权限 |
| | | */ |
| | | private boolean releaseSingleControl(String boxSn, UavControlType controlType, Long controller) { |
| | | ConcurrentHashMap<String, Long> controlMap = getControlMap(controlType); |
| | |
| | | } |
| | | |
| | | controlMap.remove(boxSn); |
| | | uavControlManager.sendControlRelease(boxSn, controlType.getType()); |
| | | uavControlManager.sendControlRelease(boxSn, controlType.getType(), controller); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 释放用户所有 UAV 控制权 |
| | | * 释放用户所有控制权限 |
| | | */ |
| | | public void releaseAllControls(Long userId) { |
| | | // 释放飞行控制 |
| | | uavFlyControlMap.entrySet().removeIf(entry -> entry.getValue().equals(userId)); |
| | | |
| | | // 释放载荷控制 |
| | | uavPayloadControlMap.entrySet().removeIf(entry -> entry.getValue().equals(userId)); |
| | | } |
| | | |
| | | /** |
| | | * 获取当前某设备的控制用户 |
| | | * |
| | | * @param boxSn 设备序列号 |
| | | * @param type 控制类型 |
| | | * @return 当前控制该设备的用户 ID |
| | | */ |
| | | public Long getCurrentController(String boxSn, String type) { |
| | | UavControlType controlType = UavControlType.fromString(type); |
| | | return getControlMap(controlType).get(boxSn); |
| | | } |
| | | |
| | | public Map<String,Long> getCurrentController(String boxSn) { |
| | | Long flyController = uavFlyControlMap.get(boxSn); |
| | | Map<String,Long> map=new HashMap<>(); |
| | | map.put("flyController",flyController); |
| | | Long payloadController = uavPayloadControlMap.get(boxSn); |
| | | map.put("payloadController",payloadController); |
| | | map.put("flyController", uavFlyControlMap.get(boxSn)); |
| | | map.put("payloadController", uavPayloadControlMap.get(boxSn)); |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * 根据控制类型获取对应的控制 Map |
| | | * 根据控制类型获取对应控制 Map |
| | | */ |
| | | private ConcurrentHashMap<String, Long> getControlMap(UavControlType controlType) { |
| | | switch (controlType) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * 根据控制类型获取对应的请求 Map |
| | | * 根据控制类型获取对应请求 Map |
| | | */ |
| | | private ConcurrentHashMap<String, Long> getRequestMap(UavControlType controlType) { |
| | | switch (controlType) { |
| | |
| | | throw new IllegalArgumentException("不支持的控制类型"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取用户优先级 |
| | | */ |
| | | private int getUserPriority(Long userId) { |
| | | return sysUserService.selectUserById(userId).getPriority(); |
| | | } |
| | | } |