liusuyi
2026-01-19 3c8d6b8e60f02b9a40fc5acd4dc6c34a6b594eb6
增加用户优先级和所属平台 调整无人机控制逻辑增加优先级判断
5 files modified
304 ■■■■■ changed files
ard-common/src/main/java/com/ard/common/core/domain/entity/SysUser.java 21 ●●●●● patch | view | raw | blame | history
ard-system/src/main/resources/mapper/system/SysUserMapper.xml 12 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavControlManager.java 130 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/message/UavControlMessage.java 31 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/service/control/UavControlService.java 110 ●●●●● patch | view | raw | blame | history
ard-common/src/main/java/com/ard/common/core/domain/entity/SysUser.java
@@ -92,6 +92,11 @@
    /** 角色ID */
    private Long roleId;
    /** 优先级 */
    private Integer priority;
    /** 所属平台 */
    private String platform;
    public SysUser()
    {
@@ -300,6 +305,22 @@
        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)
ard-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -18,6 +18,8 @@
        <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"    />
@@ -47,7 +49,7 @@
    </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
@@ -57,7 +59,7 @@
    </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">
@@ -155,6 +157,8 @@
             <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(
@@ -169,6 +173,8 @@
             <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()
         )
@@ -189,6 +195,8 @@
             <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>
ard-work/src/main/java/com/ard/work/component/websocket/handler/UavControlManager.java
@@ -4,10 +4,9 @@
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;
@@ -22,44 +21,119 @@
    @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
ard-work/src/main/java/com/ard/work/domain/message/UavControlMessage.java
@@ -7,6 +7,12 @@
import java.util.Map;
/**
 * 无人机控制消息
 * @author lsy
 * @date 2026/1/19
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@@ -14,20 +20,17 @@
    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 表示取消订阅
}
ard-work/src/main/java/com/ard/work/service/control/UavControlService.java
@@ -2,8 +2,9 @@
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;
@@ -12,7 +13,8 @@
import java.util.concurrent.ConcurrentHashMap;
/**
 * UAV控制服务类,负责管理对飞行和载荷的控制请求、释放和权限管理。
 * UAV控制服务类,负责管理对飞行和载荷的控制请求、释放和权限管理
 * 支持优先级抢占
 */
@Service
public class UavControlService {
@@ -20,30 +22,23 @@
    @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);
@@ -55,31 +50,46 @@
     * 处理单个控制类型的请求
     */
    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);
@@ -88,7 +98,7 @@
    }
    /**
     * 处理单个控制类型的请求响应
     * 处理单个控制类型请求响应
     */
    private boolean handleSingleControlResponse(String boxSn, boolean approve, UavControlType controlType,
                                                Long controller) {
@@ -101,9 +111,9 @@
        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);
@@ -112,10 +122,6 @@
    /**
     * 释放 UAV 控制权限
     *
     * @param boxSn 设备序列号
     * @param type  控制类型
     * @return 是否成功释放控制
     */
    public boolean releaseControl(String boxSn, String type) {
        UavControlType controlType = UavControlType.fromString(type);
@@ -124,7 +130,7 @@
    }
    /**
     * 释放单个控制类型的权限
     * 释放单个控制类型权限
     */
    private boolean releaseSingleControl(String boxSn, UavControlType controlType, Long controller) {
        ConcurrentHashMap<String, Long> controlMap = getControlMap(controlType);
@@ -134,42 +140,35 @@
        }
        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) {
@@ -183,7 +182,7 @@
    }
    /**
     * 根据控制类型获取对应的请求 Map
     * 根据控制类型获取对应请求 Map
     */
    private ConcurrentHashMap<String, Long> getRequestMap(UavControlType controlType) {
        switch (controlType) {
@@ -195,4 +194,11 @@
                throw new IllegalArgumentException("不支持的控制类型");
        }
    }
    /**
     * 获取用户优先级
     */
    private int getUserPriority(Long userId) {
        return sysUserService.selectUserById(userId).getPriority();
    }
}