feat(client): 添加设备绑定/解绑与屏幕镜像功能

新增家属端设备绑定/解绑接口,支持设备上报手机号同步,并引入 WebSocket 依赖以支持 WebRTC 屏幕镜像信令端点。
This commit is contained in:
TongTongStudio
2026-08-26 06:16:55 +08:00
parent 2eb14103a1
commit 76e239212a
10 changed files with 617 additions and 0 deletions

View File

@@ -25,6 +25,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@@ -198,4 +199,91 @@ public class ClientController {
return Result.failed("获取设备列表失败: " + e.getMessage());
}
}
@Operation(summary = "绑定设备(家属端)", description = "将当前登录的 client 用户手机号写入设备 snMobile建立绑定关系")
@PreAuthorize("isAuthenticated()")
@PostMapping("/bind")
public Result<?> bindDevice(
@Parameter(description = "设备序列号") @RequestParam("sn") String sn
) {
try {
if (!StringUtils.hasText(sn)) {
return Result.failed("设备序列号不能为空");
}
Long userId = SecurityUtils.getUserId();
ClientUser clientUser = clientUserService.getById(userId);
if (clientUser == null || !StringUtils.hasText(clientUser.getMobile())) {
return Result.failed("当前用户未绑定手机号,无法绑定设备");
}
SnDeviceInfo deviceInfo = deviceService.getOne(
new LambdaQueryWrapper<SnDeviceInfo>().eq(SnDeviceInfo::getSerialno, sn)
);
if (deviceInfo == null) {
return Result.failed("设备不存在");
}
// 已绑定给其他用户则拒绝
if (StringUtils.hasText(deviceInfo.getSnMobile())
&& !deviceInfo.getSnMobile().equals(clientUser.getMobile())) {
return Result.failed("该设备已被其他用户绑定");
}
// 建立/更新绑定关系
SnDeviceInfo update = new SnDeviceInfo();
update.setId(deviceInfo.getId());
update.setSnMobile(clientUser.getMobile());
boolean result = deviceService.updateById(update);
return Result.judge(result);
} catch (BusinessException be) {
return Result.failed(be.getMessage());
} catch (Exception e) {
log.error("bindDevice error, sn: {}", sn, e);
return Result.failed("绑定设备失败: " + e.getMessage());
}
}
@Operation(summary = "解绑设备(家属端)", description = "解除当前登录的 client 用户与设备的绑定关系,仅允许本人解绑")
@PreAuthorize("isAuthenticated()")
@PostMapping("/unbind")
public Result<?> unbindDevice(
@Parameter(description = "设备序列号") @RequestParam("sn") String sn
) {
try {
if (!StringUtils.hasText(sn)) {
return Result.failed("设备序列号不能为空");
}
Long userId = SecurityUtils.getUserId();
ClientUser clientUser = clientUserService.getById(userId);
if (clientUser == null || !StringUtils.hasText(clientUser.getMobile())) {
return Result.failed("当前用户未绑定手机号,无法解绑设备");
}
SnDeviceInfo deviceInfo = deviceService.getOne(
new LambdaQueryWrapper<SnDeviceInfo>().eq(SnDeviceInfo::getSerialno, sn)
);
if (deviceInfo == null) {
return Result.failed("设备不存在");
}
// 仅允许本人解绑
if (!StringUtils.hasText(deviceInfo.getSnMobile())
|| !deviceInfo.getSnMobile().equals(clientUser.getMobile())) {
return Result.failed("当前用户未绑定该设备,无法解绑");
}
SnDeviceInfo update = new SnDeviceInfo();
update.setId(deviceInfo.getId());
update.setSnMobile(null);
boolean result = deviceService.updateById(update);
return Result.judge(result);
} catch (BusinessException be) {
return Result.failed(be.getMessage());
} catch (Exception e) {
log.error("unbindDevice error, sn: {}", sn, e);
return Result.failed("解绑设备失败: " + e.getMessage());
}
}
}