Commit 5276873e by 真的三个金的鑫

feat: 支持设备按团队与用户两级可见性分配

按当前组织过滤设备列表,超管可分配到多团队,团队管理员可再分配给用户;飞手/成员仅看分配给自己的设备。

Co-authored-by: Cursor <cursoragent@cursor.com>
parent 24356261
......@@ -3,6 +3,8 @@ package com.dji.sample.manage.controller;
import com.dji.sample.manage.model.dto.*;
import com.dji.sample.manage.model.enums.OperateRecordTypeEnum;
import com.dji.sample.manage.model.param.DeviceSearchParam;
import com.dji.sample.manage.model.param.DeviceVisibilityAssignParam;
import com.dji.sample.manage.model.param.DeviceVisibilityRemoveParam;
import com.dji.sample.manage.service.IDeviceDictionaryService;
import com.dji.sample.manage.service.IOperateRecordService;
import com.dji.sample.manage.service.IDeviceService;
......@@ -381,4 +383,93 @@ public class DeviceController {
: HttpResultResponse.success(osdOpt.get());
}
/**
* 可分配设备列表(机场+无人机)。超管:全量;团队管理员:本团队已分配。
*/
@GetMapping("/{workspace_id}/visibility/assignable")
public HttpResultResponse<List<DeviceDTO>> listAssignableDevices(
@PathVariable("workspace_id") String workspaceId) {
return HttpResultResponse.success(deviceService.listAssignableDevices(workspaceId));
}
/**
* 团队及已分配设备数量(仅超管)。
*/
@GetMapping("/{workspace_id}/visibility/orgs")
public HttpResultResponse<List<DeviceVisibilityOrgDTO>> listVisibilityOrgs(
@PathVariable("workspace_id") String workspaceId) {
return HttpResultResponse.success(deviceService.listVisibilityOrgs(workspaceId));
}
/**
* 某团队已分配设备。
*/
@GetMapping("/{workspace_id}/visibility/org/{org_id}")
public HttpResultResponse<List<DeviceDTO>> listOrgVisibleDevices(
@PathVariable("workspace_id") String workspaceId,
@PathVariable("org_id") String orgId) {
return HttpResultResponse.success(deviceService.listOrgVisibleDevices(workspaceId, orgId));
}
/**
* 超管覆盖设置团队可见设备。
*/
@PutMapping("/{workspace_id}/visibility/org/{org_id}")
public HttpResultResponse assignDevicesToOrg(
@PathVariable("workspace_id") String workspaceId,
@PathVariable("org_id") String orgId,
@RequestBody DeviceVisibilityAssignParam param) {
deviceService.assignDevicesToOrg(workspaceId, orgId,
param == null ? null : param.getDeviceSnList());
return HttpResultResponse.success();
}
/**
* 从团队移除设备可见性。
*/
@PostMapping("/{workspace_id}/visibility/org/{org_id}/remove")
public HttpResultResponse removeDevicesFromOrg(
@PathVariable("workspace_id") String workspaceId,
@PathVariable("org_id") String orgId,
@RequestBody DeviceVisibilityRemoveParam param) {
deviceService.removeDevicesFromOrg(workspaceId, orgId,
param == null ? null : param.getDeviceSnList());
return HttpResultResponse.success();
}
/**
* 团队内用户及已分配设备数。
*/
@GetMapping("/{workspace_id}/visibility/org/{org_id}/users")
public HttpResultResponse<List<DeviceVisibilityUserDTO>> listVisibilityUsers(
@PathVariable("workspace_id") String workspaceId,
@PathVariable("org_id") String orgId) {
return HttpResultResponse.success(deviceService.listVisibilityUsers(workspaceId, orgId));
}
/**
* 某用户在团队下已分配的设备。
*/
@GetMapping("/{workspace_id}/visibility/org/{org_id}/user/{user_id}")
public HttpResultResponse<List<DeviceDTO>> listUserVisibleDevices(
@PathVariable("workspace_id") String workspaceId,
@PathVariable("org_id") String orgId,
@PathVariable("user_id") String userId) {
return HttpResultResponse.success(deviceService.listUserVisibleDevices(workspaceId, orgId, userId));
}
/**
* 覆盖设置用户在本团队可见的设备。
*/
@PutMapping("/{workspace_id}/visibility/org/{org_id}/user/{user_id}")
public HttpResultResponse assignDevicesToUser(
@PathVariable("workspace_id") String workspaceId,
@PathVariable("org_id") String orgId,
@PathVariable("user_id") String userId,
@RequestBody DeviceVisibilityAssignParam param) {
deviceService.assignDevicesToUser(workspaceId, orgId, userId,
param == null ? null : param.getDeviceSnList());
return HttpResultResponse.success();
}
}
\ No newline at end of file
package com.dji.sample.manage.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dji.sample.manage.model.entity.UserDeviceEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface IUserDeviceMapper extends BaseMapper<UserDeviceEntity> {
}
package com.dji.sample.manage.model.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 团队设备可见性汇总
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeviceVisibilityOrgDTO implements Serializable {
@JsonProperty("org_id")
private String orgId;
@JsonProperty("org_name")
private String orgName;
@JsonProperty("device_count")
private Integer deviceCount;
}
package com.dji.sample.manage.model.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 团队内用户设备分配汇总
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeviceVisibilityUserDTO implements Serializable {
@JsonProperty("user_id")
private String userId;
private String username;
@JsonProperty("user_name")
private String userName;
@JsonProperty("role_type")
private Integer roleType;
@JsonProperty("device_count")
private Integer deviceCount;
}
package com.dji.sample.manage.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* 团队内用户可见设备
*/
@Data
@TableName("manage_user_device")
public class UserDeviceEntity implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;
private String userId;
private Integer deviceId;
private String deviceSn;
private String orgId;
private String workspaceId;
private Long createTime;
private Long updateTime;
private String creatorId;
private String creatorName;
private String updaterId;
private String updaterName;
}
package com.dji.sample.manage.model.param;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 覆盖分配团队可见设备
*/
@Data
public class DeviceVisibilityAssignParam {
@JsonProperty("device_sn_list")
private List<String> deviceSnList = new ArrayList<>();
}
package com.dji.sample.manage.model.param;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 从团队移除设备可见性
*/
@Data
public class DeviceVisibilityRemoveParam {
@JsonProperty("device_sn_list")
private List<String> deviceSnList = new ArrayList<>();
}
......@@ -2,10 +2,7 @@ package com.dji.sample.manage.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.dji.sample.component.websocket.model.BizCodeEnum;
import com.dji.sample.manage.model.dto.DeviceDTO;
import com.dji.sample.manage.model.dto.DeviceDetailCountDTO;
import com.dji.sample.manage.model.dto.DeviceFirmwareUpgradeDTO;
import com.dji.sample.manage.model.dto.TopologyDeviceDTO;
import com.dji.sample.manage.model.dto.*;
import com.dji.sample.manage.model.entity.DeviceEntity;
import com.dji.sample.manage.model.param.DeviceQueryParam;
import com.dji.sample.manage.model.param.DeviceSearchParam;
......@@ -13,9 +10,9 @@ import com.dji.sdk.cloudapi.device.ControlSourceEnum;
import com.dji.sdk.cloudapi.device.DeviceOsdHost;
import com.dji.sdk.cloudapi.device.DockModeCodeEnum;
import com.dji.sdk.cloudapi.device.DroneModeCodeEnum;
import com.dji.sdk.config.version.GatewayManager;
import com.dji.sdk.common.HttpResultResponse;
import com.dji.sdk.common.PaginationData;
import com.dji.sdk.config.version.GatewayManager;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.List;
......@@ -280,6 +277,46 @@ public interface IDeviceService extends IService<DeviceEntity> {
void cancelShareDevice(DeviceDTO device);
/**
* 可分配设备列表:超管看 workspace 全量机场/无人机;团队管理员仅看本团队已分配设备。
*/
List<DeviceDTO> listAssignableDevices(String workspaceId);
/**
* 团队列表及已分配设备数量(仅超管)。
*/
List<DeviceVisibilityOrgDTO> listVisibilityOrgs(String workspaceId);
/**
* 查询某团队已分配的设备。
*/
List<DeviceDTO> listOrgVisibleDevices(String workspaceId, String orgId);
/**
* 超管覆盖设置某团队可见设备集合。
*/
void assignDevicesToOrg(String workspaceId, String orgId, List<String> deviceSnList);
/**
* 从团队移除设备可见性(超管或本团队管理员)。
*/
void removeDevicesFromOrg(String workspaceId, String orgId, List<String> deviceSnList);
/**
* 团队内用户及已分配设备数(团队管理员+)。
*/
List<DeviceVisibilityUserDTO> listVisibilityUsers(String workspaceId, String orgId);
/**
* 某用户在某团队下已分配的设备。
*/
List<DeviceDTO> listUserVisibleDevices(String workspaceId, String orgId, String userId);
/**
* 团队管理员覆盖设置某用户在本团队可见的设备(须为本团队已有设备子集)。
*/
void assignDevicesToUser(String workspaceId, String orgId, String userId, List<String> deviceSnList);
/**
* Get the devices list in one workspace.
* @param workspaceId
* @param page
......
package com.dji.sample.manage.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.dji.sample.manage.model.entity.UserDeviceEntity;
public interface IUserDeviceService extends IService<UserDeviceEntity> {
}
......@@ -15,6 +15,9 @@ import com.dji.sample.manage.dao.IDeviceMapper;
import com.dji.sample.manage.model.dto.*;
import com.dji.sample.manage.model.entity.DeviceEntity;
import com.dji.sample.manage.model.entity.DeviceOrgEntity;
import com.dji.sample.manage.model.entity.OrgEntity;
import com.dji.sample.manage.model.entity.UserDeviceEntity;
import com.dji.sample.manage.model.entity.UserEntity;
import com.dji.sample.manage.model.entity.UserOrgEntity;
import com.dji.sample.manage.model.enums.DeviceFirmwareStatusEnum;
import com.dji.sample.manage.model.enums.PropertySetFieldEnum;
......@@ -57,6 +60,7 @@ import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
......@@ -142,10 +146,19 @@ public class DeviceServiceImpl extends ServiceImpl<IDeviceMapper, DeviceEntity>
private IDeviceOrgService deviceOrgService;
@Autowired
private IDeviceDetailService deviceDetailService;
@Autowired
private IOrgService orgService;
@Autowired
private IUserDeviceService userDeviceService;
@Autowired
private IUserOrgService userOrgService;
@Autowired
private IDeviceDetailService deviceDetailService;
private IUserService userService;
@Override
public void subDeviceOffline(String deviceSn) {
......@@ -295,6 +308,20 @@ public class DeviceServiceImpl extends ServiceImpl<IDeviceMapper, DeviceEntity>
.domains(List.of(DeviceDomainEnum.REMOTER_CONTROL.getDomain(), DeviceDomainEnum.DOCK.getDomain()))
.build());
if (!aboveSysAdminRole()) {
String orgId = getOrgId();
if (!StringUtils.hasText(orgId)) {
return new ArrayList<>();
}
Set<String> visibleSns = new HashSet<>(resolveVisibleDeviceSnsForCurrentUser(workspaceId, orgId));
// 机场/无人机按可见性;遥控器若自身或子设备在可见列表中则保留
devicesList = devicesList.stream()
.filter(device -> visibleSns.contains(device.getDeviceSn())
|| (StringUtils.hasText(device.getChildDeviceSn())
&& visibleSns.contains(device.getChildDeviceSn())))
.collect(Collectors.toList());
}
devicesList.stream()
.filter(gateway -> DeviceDomainEnum.DOCK == gateway.getDomain() ||
deviceRedisService.checkDeviceOnline(gateway.getDeviceSn()))
......@@ -526,6 +553,17 @@ public class DeviceServiceImpl extends ServiceImpl<IDeviceMapper, DeviceEntity>
return false;
}
// 优先:请求 orgId → DB 已有 orgId → 当前登录 orgId
String bindOrgId = StringUtils.hasText(device.getOrgId())
? device.getOrgId()
: dbDeviceBySn.map(DeviceDTO::getOrgId).filter(StringUtils::hasText).orElse(getOrgId());
String bindWorkspaceId = StringUtils.hasText(device.getWorkspaceId())
? device.getWorkspaceId()
: dbDeviceBySn.map(DeviceDTO::getWorkspaceId).filter(StringUtils::hasText).orElse(getWorkspaceId());
if (StringUtils.hasText(bindOrgId) && StringUtils.hasText(bindWorkspaceId)) {
ensureDeviceOrgRelation(device.getDeviceSn(), bindWorkspaceId, bindOrgId, 0);
}
Optional<DeviceDTO> deviceOpt = deviceRedisService.getDeviceOnline(device.getDeviceSn());
if (deviceOpt.isEmpty()) {
return false;
......@@ -567,6 +605,9 @@ public class DeviceServiceImpl extends ServiceImpl<IDeviceMapper, DeviceEntity>
if (StringUtils.hasText(deviceName)) {
wrapper.like(DeviceEntity::getDeviceName, deviceName);
}
if (!applyDeviceVisibilityFilter(wrapper, workspaceId, null)) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
Page<DeviceEntity> pagination = mapper.selectPage(new Page<>(page, pageSize), wrapper );
List<DeviceDTO> devicesList = pagination.getRecords().stream().map(this::deviceEntityConvertToDTO)
.peek(device -> {
......@@ -597,6 +638,9 @@ public class DeviceServiceImpl extends ServiceImpl<IDeviceMapper, DeviceEntity>
if (StringUtils.hasText(deviceName)) {
wrapper.like(DeviceEntity::getDeviceName, deviceName);
}
if (!applyDeviceVisibilityFilter(wrapper, workspaceId, null)) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
Page<DeviceEntity> pagination = mapper.selectPage(new Page<>(page, pageSize), wrapper );
List<DeviceDTO> devicesList = pagination.getRecords().stream().map(this::deviceEntityConvertToDTO)
.peek(device -> {
......@@ -640,55 +684,9 @@ public class DeviceServiceImpl extends ServiceImpl<IDeviceMapper, DeviceEntity>
wrapper.like(DeviceEntity::getBoundStatus, param.getBoundStatus());
}
if (StringUtils.hasText(param.getOrgId())) {
// 查询 指定团队的设备
LambdaQueryWrapper<DeviceOrgEntity> deviceOrgQueryWrapper = new LambdaQueryWrapper<>();
deviceOrgQueryWrapper.eq(DeviceOrgEntity::getWorkspaceId, workspaceId);
deviceOrgQueryWrapper.eq(DeviceOrgEntity::getOrgId, param.getOrgId());
List<DeviceOrgEntity> deviceOrgEntities = deviceOrgService.list(deviceOrgQueryWrapper);
if (CollectionUtils.isEmpty(deviceOrgEntities)) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
List<String> deviceSnList = deviceOrgEntities.stream().map(DeviceOrgEntity::getDeviceSn).distinct().collect(Collectors.toList());
if (CollectionUtils.isEmpty(deviceSnList)) {
if (!applyDeviceVisibilityFilter(wrapper, workspaceId, param.getOrgId())) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
wrapper.in(DeviceEntity::getDeviceSn, deviceSnList);
} else {
// 假如不是超级管理员 只能查询自己所属团队的设备
if (aboveSysAdminRole()) {
} else {
// 查询自己团队
LambdaQueryWrapper<UserOrgEntity> userOrgQueryWrapper = new LambdaQueryWrapper<>();
userOrgQueryWrapper.eq(UserOrgEntity::getUserId, getUserId());
userOrgQueryWrapper.eq(UserOrgEntity::getWorkspaceId, workspaceId);
List<UserOrgEntity> userOrgEntities = userOrgService.list(userOrgQueryWrapper);
if (CollectionUtils.isEmpty(userOrgEntities)) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
List<String> userOrgIdList = userOrgEntities.stream().map(UserOrgEntity::getOrgId).distinct().collect(Collectors.toList());
if (CollectionUtils.isEmpty(userOrgIdList)) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
// 查询 团队的设备
LambdaQueryWrapper<DeviceOrgEntity> deviceOrgQueryWrapper = new LambdaQueryWrapper<>();
deviceOrgQueryWrapper.eq(DeviceOrgEntity::getWorkspaceId, workspaceId);
deviceOrgQueryWrapper.in(DeviceOrgEntity::getOrgId, userOrgIdList);
List<DeviceOrgEntity> deviceOrgEntities = deviceOrgService.list(deviceOrgQueryWrapper);
if (CollectionUtils.isEmpty(deviceOrgEntities)) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
List<String> deviceSnList = deviceOrgEntities.stream().map(DeviceOrgEntity::getDeviceSn).distinct().collect(Collectors.toList());
if (CollectionUtils.isEmpty(deviceSnList)) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
wrapper.in(DeviceEntity::getDeviceSn, deviceSnList);
}
}
Page<DeviceEntity> pagination = mapper.selectPage(new Page<>(page, pageSize), wrapper );
List<DeviceDTO> devicesList = pagination.getRecords().stream().map(this::deviceEntityConvertToDTO)
......@@ -731,56 +729,10 @@ public class DeviceServiceImpl extends ServiceImpl<IDeviceMapper, DeviceEntity>
wrapper.like(DeviceEntity::getBoundStatus, param.getBoundStatus());
}
if (StringUtils.hasText(param.getOrgId())) {
// 查询 指定团队的设备
LambdaQueryWrapper<DeviceOrgEntity> deviceOrgQueryWrapper = new LambdaQueryWrapper<>();
deviceOrgQueryWrapper.eq(DeviceOrgEntity::getWorkspaceId, workspaceId);
deviceOrgQueryWrapper.eq(DeviceOrgEntity::getOrgId, param.getOrgId());
List<DeviceOrgEntity> deviceOrgEntities = deviceOrgService.list(deviceOrgQueryWrapper);
if (CollectionUtils.isEmpty(deviceOrgEntities)) {
return new ArrayList<>();
}
List<String> deviceSnList = deviceOrgEntities.stream().map(DeviceOrgEntity::getDeviceSn).distinct().collect(Collectors.toList());
if (CollectionUtils.isEmpty(deviceSnList)) {
return new ArrayList<>();
}
wrapper.in(DeviceEntity::getDeviceSn, deviceSnList);
} else {
// 假如不是超级管理员 只能查询自己所属团队的设备
if (aboveSysAdminRole()) {
} else {
// 查询自己团队
LambdaQueryWrapper<UserOrgEntity> userOrgQueryWrapper = new LambdaQueryWrapper<>();
userOrgQueryWrapper.eq(UserOrgEntity::getUserId, getUserId());
userOrgQueryWrapper.eq(UserOrgEntity::getWorkspaceId, workspaceId);
List<UserOrgEntity> userOrgEntities = userOrgService.list(userOrgQueryWrapper);
if (CollectionUtils.isEmpty(userOrgEntities)) {
return new ArrayList<>();
}
List<String> userOrgIdList = userOrgEntities.stream().map(UserOrgEntity::getOrgId).distinct().collect(Collectors.toList());
if (CollectionUtils.isEmpty(userOrgIdList)) {
if (!applyDeviceVisibilityFilter(wrapper, workspaceId, param.getOrgId())) {
return new ArrayList<>();
}
// 查询 团队的设备
LambdaQueryWrapper<DeviceOrgEntity> deviceOrgQueryWrapper = new LambdaQueryWrapper<>();
deviceOrgQueryWrapper.eq(DeviceOrgEntity::getWorkspaceId, workspaceId);
deviceOrgQueryWrapper.in(DeviceOrgEntity::getOrgId, userOrgIdList);
List<DeviceOrgEntity> deviceOrgEntities = deviceOrgService.list(deviceOrgQueryWrapper);
if (CollectionUtils.isEmpty(deviceOrgEntities)) {
return new ArrayList<>();
}
List<String> deviceSnList = deviceOrgEntities.stream().map(DeviceOrgEntity::getDeviceSn).distinct().collect(Collectors.toList());
if (CollectionUtils.isEmpty(deviceSnList)) {
return new ArrayList<>();
}
wrapper.in(DeviceEntity::getDeviceSn, deviceSnList);
}
}
List<DeviceEntity> deviceEntityList = this.list(wrapper);
List<DeviceDTO> devicesList = deviceEntityList.stream().map(this::deviceEntityConvertToDTO)
.peek(device -> {
......@@ -1672,51 +1624,12 @@ public class DeviceServiceImpl extends ServiceImpl<IDeviceMapper, DeviceEntity>
public PaginationData<DeviceDTO> getDockAndDrone(String workspaceId ,Long page, Long pageSize) {
LambdaQueryWrapper<DeviceEntity> wrapper = new LambdaQueryWrapper<DeviceEntity>();
// 假如是超级管理员 查询全部设备
if (aboveSysAdminRole()) {
} else {
wrapper.eq(DeviceEntity::getWorkspaceId, workspaceId);
}
// if (StringUtils.hasText(deviceName)) {
// wrapper.like(DeviceEntity::getDeviceName, deviceName);
// }
wrapper.in(DeviceEntity::getDomain, DeviceDomainEnum.DOCK.getDomain(), DeviceDomainEnum.DRONE.getDomain());
// 假如不是超级管理员 只能查询自己所属团队的设备
if (aboveSysAdminRole()) {
} else {
// 查询自己团队
LambdaQueryWrapper<UserOrgEntity> userOrgQueryWrapper = new LambdaQueryWrapper<>();
userOrgQueryWrapper.eq(UserOrgEntity::getUserId, getUserId());
userOrgQueryWrapper.eq(UserOrgEntity::getWorkspaceId, workspaceId);
List<UserOrgEntity> userOrgEntities = userOrgService.list(userOrgQueryWrapper);
if (CollectionUtils.isEmpty(userOrgEntities)) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
List<String> userOrgIdList = userOrgEntities.stream().map(UserOrgEntity::getOrgId).distinct().collect(Collectors.toList());
if (CollectionUtils.isEmpty(userOrgIdList)) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
// 查询 团队的设备
LambdaQueryWrapper<DeviceOrgEntity> deviceOrgQueryWrapper = new LambdaQueryWrapper<>();
deviceOrgQueryWrapper.eq(DeviceOrgEntity::getWorkspaceId, workspaceId);
deviceOrgQueryWrapper.in(DeviceOrgEntity::getOrgId, userOrgIdList);
List<DeviceOrgEntity> deviceOrgEntities = deviceOrgService.list(deviceOrgQueryWrapper);
if (CollectionUtils.isEmpty(deviceOrgEntities)) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
List<String> deviceSnList = deviceOrgEntities.stream().map(DeviceOrgEntity::getDeviceSn).distinct().collect(Collectors.toList());
if (CollectionUtils.isEmpty(deviceSnList)) {
if (!applyDeviceVisibilityFilter(wrapper, workspaceId, null)) {
return new PaginationData<>(new ArrayList<>(), new Pagination(page, pageSize, 0));
}
wrapper.in(DeviceEntity::getDeviceSn, deviceSnList);
}
Page<DeviceEntity> pagination = mapper.selectPage(new Page<>(page, pageSize), wrapper );
List<DeviceDTO> devicesList = pagination.getRecords().stream().map(this::deviceEntityConvertToDTO)
......@@ -1850,4 +1763,403 @@ public class DeviceServiceImpl extends ServiceImpl<IDeviceMapper, DeviceEntity>
return deviceDetailCountDTO;
}
@Override
public List<DeviceDTO> listAssignableDevices(String workspaceId) {
LambdaQueryWrapper<DeviceEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DeviceEntity::getWorkspaceId, workspaceId);
wrapper.in(DeviceEntity::getDomain, DeviceDomainEnum.DOCK.getDomain(), DeviceDomainEnum.DRONE.getDomain());
if (aboveSysAdminRole()) {
// 超管:workspace 全量
} else if (aboveAdminRole()) {
if (!applyDeviceVisibilityFilter(wrapper, workspaceId, getOrgId())) {
return new ArrayList<>();
}
} else {
throw new RuntimeException("The current role has no permissions");
}
return this.list(wrapper).stream()
.map(this::deviceEntityConvertToDTO)
.collect(Collectors.toList());
}
@Override
public List<DeviceVisibilityOrgDTO> listVisibilityOrgs(String workspaceId) {
aboveSysAdminRoleAndThrowError();
LambdaQueryWrapper<OrgEntity> orgQuery = new LambdaQueryWrapper<>();
orgQuery.eq(OrgEntity::getWorkspaceId, workspaceId);
List<OrgEntity> orgs = orgService.list(orgQuery);
List<DeviceVisibilityOrgDTO> result = new ArrayList<>();
for (OrgEntity org : orgs) {
List<String> sns = listVisibleDeviceSns(workspaceId, org.getOrgId());
result.add(DeviceVisibilityOrgDTO.builder()
.orgId(org.getOrgId())
.orgName(org.getOrgName())
.deviceCount(sns.size())
.build());
}
return result;
}
@Override
public List<DeviceDTO> listOrgVisibleDevices(String workspaceId, String orgId) {
assertCanViewOrgVisibility(orgId);
List<String> sns = listVisibleDeviceSns(workspaceId, orgId);
if (CollectionUtils.isEmpty(sns)) {
return new ArrayList<>();
}
LambdaQueryWrapper<DeviceEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DeviceEntity::getWorkspaceId, workspaceId);
wrapper.in(DeviceEntity::getDeviceSn, sns);
return this.list(wrapper).stream()
.map(this::deviceEntityConvertToDTO)
.collect(Collectors.toList());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void assignDevicesToOrg(String workspaceId, String orgId, List<String> deviceSnList) {
aboveSysAdminRoleAndThrowError();
if (!StringUtils.hasText(orgId)) {
throw new RuntimeException("org id is null");
}
Optional<OrgDTO> orgOpt = orgService.getOrgByOrgId(orgId);
if (orgOpt.isEmpty()) {
throw new RuntimeException("org does not exist");
}
if (StringUtils.hasText(workspaceId) && StringUtils.hasText(orgOpt.get().getWorkspaceId())
&& !workspaceId.equals(orgOpt.get().getWorkspaceId())) {
throw new RuntimeException("org does not belong to this workspace");
}
Set<String> targetSns = CollectionUtils.isEmpty(deviceSnList)
? new HashSet<>()
: deviceSnList.stream().filter(StringUtils::hasText).collect(Collectors.toSet());
if (!targetSns.isEmpty()) {
List<DeviceEntity> devices = this.list(new LambdaQueryWrapper<DeviceEntity>()
.eq(DeviceEntity::getWorkspaceId, workspaceId)
.in(DeviceEntity::getDeviceSn, targetSns));
Set<String> validSns = devices.stream().map(DeviceEntity::getDeviceSn).collect(Collectors.toSet());
targetSns.retainAll(validSns);
}
List<String> currentSns = listVisibleDeviceSns(workspaceId, orgId);
Set<String> currentSet = new HashSet<>(currentSns);
Set<String> toAdd = new HashSet<>(targetSns);
toAdd.removeAll(currentSet);
Set<String> toRemove = new HashSet<>(currentSet);
toRemove.removeAll(targetSns);
for (String sn : toAdd) {
ensureDeviceOrgRelation(sn, workspaceId, orgId, resolveIsSharedFlag(sn, orgId));
}
if (!toRemove.isEmpty()) {
LambdaQueryWrapper<DeviceOrgEntity> delWrapper = new LambdaQueryWrapper<>();
delWrapper.eq(DeviceOrgEntity::getWorkspaceId, workspaceId);
delWrapper.eq(DeviceOrgEntity::getOrgId, orgId);
delWrapper.in(DeviceOrgEntity::getDeviceSn, toRemove);
deviceOrgService.remove(delWrapper);
// 同步清理团队内用户分配
LambdaQueryWrapper<UserDeviceEntity> delUserDevice = new LambdaQueryWrapper<>();
delUserDevice.eq(UserDeviceEntity::getWorkspaceId, workspaceId);
delUserDevice.eq(UserDeviceEntity::getOrgId, orgId);
delUserDevice.in(UserDeviceEntity::getDeviceSn, toRemove);
userDeviceService.remove(delUserDevice);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void removeDevicesFromOrg(String workspaceId, String orgId, List<String> deviceSnList) {
assertCanManageOrgVisibility(orgId);
if (CollectionUtils.isEmpty(deviceSnList)) {
return;
}
LambdaQueryWrapper<DeviceOrgEntity> delWrapper = new LambdaQueryWrapper<>();
delWrapper.eq(DeviceOrgEntity::getWorkspaceId, workspaceId);
delWrapper.eq(DeviceOrgEntity::getOrgId, orgId);
delWrapper.in(DeviceOrgEntity::getDeviceSn, deviceSnList);
deviceOrgService.remove(delWrapper);
LambdaQueryWrapper<UserDeviceEntity> delUserDevice = new LambdaQueryWrapper<>();
delUserDevice.eq(UserDeviceEntity::getWorkspaceId, workspaceId);
delUserDevice.eq(UserDeviceEntity::getOrgId, orgId);
delUserDevice.in(UserDeviceEntity::getDeviceSn, deviceSnList);
userDeviceService.remove(delUserDevice);
}
@Override
public List<DeviceVisibilityUserDTO> listVisibilityUsers(String workspaceId, String orgId) {
assertCanManageOrgVisibility(orgId);
LambdaQueryWrapper<UserOrgEntity> userOrgQuery = new LambdaQueryWrapper<>();
userOrgQuery.eq(UserOrgEntity::getWorkspaceId, workspaceId);
userOrgQuery.eq(UserOrgEntity::getOrgId, orgId);
List<UserOrgEntity> userOrgs = userOrgService.list(userOrgQuery);
if (CollectionUtils.isEmpty(userOrgs)) {
return new ArrayList<>();
}
List<DeviceVisibilityUserDTO> result = new ArrayList<>();
for (UserOrgEntity uo : userOrgs) {
UserEntity user = userService.getOne(new LambdaQueryWrapper<UserEntity>()
.eq(UserEntity::getUserId, uo.getUserId()), false);
long count = userDeviceService.count(new LambdaQueryWrapper<UserDeviceEntity>()
.eq(UserDeviceEntity::getWorkspaceId, workspaceId)
.eq(UserDeviceEntity::getOrgId, orgId)
.eq(UserDeviceEntity::getUserId, uo.getUserId()));
result.add(DeviceVisibilityUserDTO.builder()
.userId(uo.getUserId())
.username(user != null ? user.getUsername() : uo.getUserId())
.userName(user != null ? user.getUsername() : uo.getUserId())
.roleType(uo.getRoleType())
.deviceCount((int) count)
.build());
}
return result;
}
@Override
public List<DeviceDTO> listUserVisibleDevices(String workspaceId, String orgId, String userId) {
assertCanManageOrgVisibility(orgId);
if (!StringUtils.hasText(userId)) {
return new ArrayList<>();
}
List<String> sns = listUserDeviceSns(workspaceId, orgId, userId);
if (CollectionUtils.isEmpty(sns)) {
return new ArrayList<>();
}
return this.list(new LambdaQueryWrapper<DeviceEntity>()
.eq(DeviceEntity::getWorkspaceId, workspaceId)
.in(DeviceEntity::getDeviceSn, sns))
.stream()
.map(this::deviceEntityConvertToDTO)
.collect(Collectors.toList());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void assignDevicesToUser(String workspaceId, String orgId, String userId, List<String> deviceSnList) {
assertCanManageOrgVisibility(orgId);
if (!StringUtils.hasText(userId)) {
throw new RuntimeException("user id is null");
}
// 用户须属于该团队
long userInOrg = userOrgService.count(new LambdaQueryWrapper<UserOrgEntity>()
.eq(UserOrgEntity::getWorkspaceId, workspaceId)
.eq(UserOrgEntity::getOrgId, orgId)
.eq(UserOrgEntity::getUserId, userId));
if (userInOrg == 0) {
throw new RuntimeException("user does not belong to this org");
}
Set<String> orgDeviceSns = new HashSet<>(listVisibleDeviceSns(workspaceId, orgId));
Set<String> targetSns = CollectionUtils.isEmpty(deviceSnList)
? new HashSet<>()
: deviceSnList.stream()
.filter(StringUtils::hasText)
.filter(orgDeviceSns::contains)
.collect(Collectors.toSet());
List<String> currentSns = listUserDeviceSns(workspaceId, orgId, userId);
Set<String> currentSet = new HashSet<>(currentSns);
Set<String> toAdd = new HashSet<>(targetSns);
toAdd.removeAll(currentSet);
Set<String> toRemove = new HashSet<>(currentSet);
toRemove.removeAll(targetSns);
for (String sn : toAdd) {
ensureUserDeviceRelation(userId, sn, workspaceId, orgId);
}
if (!toRemove.isEmpty()) {
LambdaQueryWrapper<UserDeviceEntity> del = new LambdaQueryWrapper<>();
del.eq(UserDeviceEntity::getWorkspaceId, workspaceId);
del.eq(UserDeviceEntity::getOrgId, orgId);
del.eq(UserDeviceEntity::getUserId, userId);
del.in(UserDeviceEntity::getDeviceSn, toRemove);
userDeviceService.remove(del);
}
}
/**
* 按组织(及飞手/成员的用户级)过滤设备可见性。超管不加组织限制(除非显式传 orgId)。
* @return false 表示无可见设备,调用方应返回空结果
*/
private boolean applyDeviceVisibilityFilter(LambdaQueryWrapper<DeviceEntity> wrapper,
String workspaceId,
String orgIdParam) {
String filterOrgId;
if (StringUtils.hasText(orgIdParam)) {
if (!aboveSysAdminRole() && !orgIdParam.equals(getOrgId())) {
return false;
}
filterOrgId = orgIdParam;
} else if (aboveSysAdminRole()) {
return true;
} else {
filterOrgId = getOrgId();
if (!StringUtils.hasText(filterOrgId)) {
return false;
}
}
List<String> deviceSnList = resolveVisibleDeviceSnsForCurrentUser(workspaceId, filterOrgId);
if (CollectionUtils.isEmpty(deviceSnList)) {
return false;
}
wrapper.in(DeviceEntity::getDeviceSn, deviceSnList);
return true;
}
/**
* 管理员看团队全量;飞手/成员仅看分配给自己的设备。
*/
private List<String> resolveVisibleDeviceSnsForCurrentUser(String workspaceId, String orgId) {
List<String> orgSns = listVisibleDeviceSns(workspaceId, orgId);
if (CollectionUtils.isEmpty(orgSns)) {
return new ArrayList<>();
}
// 团队管理员及以上看本团队全部设备
if (aboveAdminRole()) {
return orgSns;
}
// 飞手/成员:与用户分配取交集
List<String> userSns = listUserDeviceSns(workspaceId, orgId, getUserId());
if (CollectionUtils.isEmpty(userSns)) {
return new ArrayList<>();
}
Set<String> orgSet = new HashSet<>(orgSns);
return userSns.stream().filter(orgSet::contains).distinct().collect(Collectors.toList());
}
private List<String> listVisibleDeviceSns(String workspaceId, String orgId) {
if (!StringUtils.hasText(workspaceId) || !StringUtils.hasText(orgId)) {
return new ArrayList<>();
}
LambdaQueryWrapper<DeviceOrgEntity> deviceOrgQueryWrapper = new LambdaQueryWrapper<>();
deviceOrgQueryWrapper.eq(DeviceOrgEntity::getWorkspaceId, workspaceId);
deviceOrgQueryWrapper.eq(DeviceOrgEntity::getOrgId, orgId);
return deviceOrgService.list(deviceOrgQueryWrapper).stream()
.map(DeviceOrgEntity::getDeviceSn)
.filter(StringUtils::hasText)
.distinct()
.collect(Collectors.toList());
}
private List<String> listUserDeviceSns(String workspaceId, String orgId, String userId) {
if (!StringUtils.hasText(workspaceId) || !StringUtils.hasText(orgId) || !StringUtils.hasText(userId)) {
return new ArrayList<>();
}
return userDeviceService.list(new LambdaQueryWrapper<UserDeviceEntity>()
.eq(UserDeviceEntity::getWorkspaceId, workspaceId)
.eq(UserDeviceEntity::getOrgId, orgId)
.eq(UserDeviceEntity::getUserId, userId))
.stream()
.map(UserDeviceEntity::getDeviceSn)
.filter(StringUtils::hasText)
.distinct()
.collect(Collectors.toList());
}
private void ensureUserDeviceRelation(String userId, String deviceSn, String workspaceId, String orgId) {
LambdaQueryWrapper<UserDeviceEntity> exists = new LambdaQueryWrapper<>();
exists.eq(UserDeviceEntity::getUserId, userId);
exists.eq(UserDeviceEntity::getOrgId, orgId);
exists.eq(UserDeviceEntity::getDeviceSn, deviceSn);
if (userDeviceService.count(exists) > 0) {
return;
}
DeviceEntity dbDevice = this.getOne(new LambdaQueryWrapper<DeviceEntity>()
.eq(DeviceEntity::getDeviceSn, deviceSn));
if (dbDevice == null) {
throw new RuntimeException("device does not exist: " + deviceSn);
}
UserDeviceEntity entity = new UserDeviceEntity();
entity.setUserId(userId);
entity.setDeviceId(dbDevice.getId());
entity.setDeviceSn(deviceSn);
entity.setOrgId(orgId);
entity.setWorkspaceId(workspaceId);
entity.setCreatorId(getUserId());
entity.setCreatorName(getUsername());
entity.setCreateTime(System.currentTimeMillis());
entity.setUpdaterId(getUserId());
entity.setUpdaterName(getUsername());
entity.setUpdateTime(System.currentTimeMillis());
userDeviceService.save(entity);
}
private void ensureDeviceOrgRelation(String deviceSn, String workspaceId, String orgId, Integer isShared) {
if (!StringUtils.hasText(deviceSn) || !StringUtils.hasText(workspaceId) || !StringUtils.hasText(orgId)) {
return;
}
LambdaQueryWrapper<DeviceOrgEntity> existsQuery = new LambdaQueryWrapper<>();
existsQuery.eq(DeviceOrgEntity::getDeviceSn, deviceSn);
existsQuery.eq(DeviceOrgEntity::getOrgId, orgId);
existsQuery.eq(DeviceOrgEntity::getWorkspaceId, workspaceId);
if (deviceOrgService.count(existsQuery) > 0) {
return;
}
DeviceEntity dbDevice = this.getOne(new LambdaQueryWrapper<DeviceEntity>()
.eq(DeviceEntity::getDeviceSn, deviceSn));
if (dbDevice == null) {
throw new RuntimeException("device does not exist: " + deviceSn);
}
DeviceOrgEntity deviceOrgEntity = new DeviceOrgEntity();
deviceOrgEntity.setWorkspaceId(workspaceId);
deviceOrgEntity.setOrgId(orgId);
deviceOrgEntity.setDeviceSn(deviceSn);
deviceOrgEntity.setDeviceId(dbDevice.getId());
deviceOrgEntity.setIsShared(isShared == null ? 1 : isShared);
deviceOrgEntity.setCreatorId(getUserId());
deviceOrgEntity.setCreatorName(getUsername());
deviceOrgEntity.setCreateTime(System.currentTimeMillis());
deviceOrgEntity.setUpdaterId(getUserId());
deviceOrgEntity.setUpdaterName(getUsername());
deviceOrgEntity.setUpdateTime(System.currentTimeMillis());
deviceOrgService.save(deviceOrgEntity);
}
/**
* 设备归属组织用 isShared=0,分配到其他团队用 isShared=1。
*/
private Integer resolveIsSharedFlag(String deviceSn, String targetOrgId) {
Optional<DeviceDTO> deviceOpt = this.getDeviceBySn(deviceSn);
if (deviceOpt.isPresent() && StringUtils.hasText(deviceOpt.get().getOrgId())
&& targetOrgId.equals(deviceOpt.get().getOrgId())) {
return 0;
}
return 1;
}
private void assertCanViewOrgVisibility(String orgId) {
if (aboveSysAdminRole()) {
return;
}
if (aboveAdminRole() && StringUtils.hasText(orgId) && orgId.equals(getOrgId())) {
return;
}
throw new RuntimeException("The current role has no permissions");
}
private void assertCanManageOrgVisibility(String orgId) {
if (aboveSysAdminRole()) {
return;
}
if (aboveAdminRole() && StringUtils.hasText(orgId) && orgId.equals(getOrgId())) {
return;
}
throw new RuntimeException("The current role has no permissions");
}
}
\ No newline at end of file
package com.dji.sample.manage.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dji.sample.manage.dao.IUserDeviceMapper;
import com.dji.sample.manage.model.entity.UserDeviceEntity;
import com.dji.sample.manage.service.IUserDeviceService;
import org.springframework.stereotype.Service;
@Service
public class UserDeviceServiceImpl extends ServiceImpl<IUserDeviceMapper, UserDeviceEntity> implements IUserDeviceService {
}
-- 团队内用户-设备可见性(同一设备可分给多用户)
CREATE TABLE IF NOT EXISTS `manage_user_device` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` varchar(64) NOT NULL,
`device_id` int DEFAULT NULL,
`device_sn` varchar(64) NOT NULL,
`org_id` varchar(64) NOT NULL,
`workspace_id` varchar(64) NOT NULL,
`create_time` bigint DEFAULT NULL,
`update_time` bigint DEFAULT NULL,
`creator_id` varchar(64) DEFAULT NULL,
`creator_name` varchar(64) DEFAULT NULL,
`updater_id` varchar(64) DEFAULT NULL,
`updater_name` varchar(64) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_org_device` (`user_id`, `org_id`, `device_sn`),
KEY `idx_org_user` (`org_id`, `user_id`),
KEY `idx_device_sn` (`device_sn`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='团队内用户设备可见性';
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment