查询设备

This commit is contained in:
2025-06-21 13:48:37 +08:00
parent a02819261d
commit f9a340c77c
10 changed files with 227 additions and 114 deletions

View File

@ -8,6 +8,8 @@ import lombok.Data;
import java.util.Date; import java.util.Date;
/** /**
* 设备分配记录表
*
* @TableName device_assignments * @TableName device_assignments
*/ */
@TableName(value = "device_assignments") @TableName(value = "device_assignments")
@ -35,6 +37,20 @@ public class DeviceAssignments {
*/ */
private Long toCustomerId; private Long toCustomerId;
/**
* 分配者
* assigner_name
*/
private Long assignerId;
private String assignerName;
/**
* 接收者
* assignee_name
*/
private Long assigneeId;
private String assigneeName;
/** /**
* 分配时间 * 分配时间
*/ */
@ -47,48 +63,23 @@ public class DeviceAssignments {
*/ */
private Integer deviceTypeGranted; private Integer deviceTypeGranted;
@Override /**
public boolean equals(Object that) { * 0 否
if (this == that) { * 1 是
return true; * 是否直接分配(用于父级显示)
} */
if (that == null) { private Integer direct;
return false;
}
if (getClass() != that.getClass()) {
return false;
}
DeviceAssignments other = (DeviceAssignments) that;
return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) && (this.getDeviceId() == null ? other.getDeviceId() == null : this.getDeviceId().equals(other.getDeviceId())) && (this.getFromCustomerId() == null ? other.getFromCustomerId() == null : this.getFromCustomerId().equals(other.getFromCustomerId())) && (this.getToCustomerId() == null ? other.getToCustomerId() == null : this.getToCustomerId().equals(other.getToCustomerId())) && (this.getAssignedAt() == null ? other.getAssignedAt() == null : this.getAssignedAt().equals(other.getAssignedAt())) && (this.getDeviceTypeGranted() == null ? other.getDeviceTypeGranted() == null : this.getDeviceTypeGranted().equals(other.getDeviceTypeGranted()));
}
@Override /**
public int hashCode() { * 0 否
final int prime = 31; * 1 是
int result = 1; * 设备是否有效
result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); */
result = prime * result + ((getDeviceId() == null) ? 0 : getDeviceId().hashCode()); private Integer active;
result = prime * result + ((getFromCustomerId() == null) ? 0 : getFromCustomerId().hashCode());
result = prime * result + ((getToCustomerId() == null) ? 0 : getToCustomerId().hashCode());
result = prime * result + ((getAssignedAt() == null) ? 0 : getAssignedAt().hashCode());
result = prime * result + ((getDeviceTypeGranted() == null) ? 0 : getDeviceTypeGranted().hashCode());
return result;
}
@Override /**
public String toString() { * 分配等级(用于失效)
StringBuilder sb = new StringBuilder(); */
sb.append(getClass().getSimpleName()); private String lever;
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", deviceId=").append(deviceId);
sb.append(", fromCustomerId=").append(fromCustomerId);
sb.append(", toCustomerId=").append(toCustomerId);
sb.append(", assignedAt=").append(assignedAt);
sb.append(", deviceTypeGranted=").append(deviceTypeGranted);
sb.append("]");
return sb.toString();
}
} }

View File

@ -32,7 +32,8 @@ public class DeviceType extends BaseEntity implements Serializable {
private Long customerId; private Long customerId;
@ApiModelProperty(value = "创建该类型的客户") @ApiModelProperty(value = "创建该类型的客户")
private String ownerCustomerId; private Long ownerCustomerId;
/** /**
* 租户ID * 租户ID
*/ */

View File

@ -2,7 +2,9 @@ package com.fuyuanshen.modules.system.domain.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotNull;
import java.util.List; import java.util.List;
/** /**
@ -11,12 +13,15 @@ import java.util.List;
* @Date: 2025/5/28 * @Date: 2025/5/28
**/ **/
@Data @Data
@Validated
public class CustomerVo { public class CustomerVo {
@ApiModelProperty(value = "客户ID") @ApiModelProperty(value = "客户ID")
@NotNull(message = "客户ID不能为空")
private Long customerId; private Long customerId;
@ApiModelProperty(value = "设备ID") @ApiModelProperty(value = "设备ID")
@NotNull(message = "设备ID不能为空")
private List<Long> deviceIds; private List<Long> deviceIds;
} }

View File

@ -0,0 +1,44 @@
package com.fuyuanshen.modules.system.enums;
/**
* 设备有效性状态枚举
*
* @author: 默苍璃
* @date: 2025-06-2113:26
*/
public enum DeviceActiveStatusEnum {
INACTIVE(0, "无效"), ACTIVE(1, "有效");
private final Integer code;
private final String description;
DeviceActiveStatusEnum(Integer code, String description) {
this.code = code;
this.description = description;
}
public Integer getCode() {
return code;
}
public String getDescription() {
return description;
}
/**
* 根据 code 获取描述
*
* @param code 状态码
* @return 描述信息
*/
public static String getDescriptionByCode(Integer code) {
for (DeviceActiveStatusEnum status : values()) {
if (status.getCode().equals(code)) {
return status.getDescription();
}
}
return null;
}
}

View File

@ -216,28 +216,20 @@ public class DeviceController {
try { try {
User currentUser = userMapper.findByUsername(SecurityUtils.getCurrentUsername()); User currentUser = userMapper.findByUsername(SecurityUtils.getCurrentUsername());
DeviceImportParams params = DeviceImportParams.builder().ip(ip).deviceService(deviceService).tenantId(currentUser.getTenantId()).file(file).filePath(filePath).deviceMapper(deviceMapper).deviceTypeMapper(deviceTypeMapper).userId(currentUser.getId()).build(); DeviceImportParams params = DeviceImportParams.builder().ip(ip).deviceService(deviceService).tenantId(currentUser.getTenantId()).file(file).filePath(filePath).deviceMapper(deviceMapper).deviceTypeMapper(deviceTypeMapper).userId(currentUser.getId()).build();
// 创建监听器 // 创建监听器
UploadDeviceDataListener listener = new UploadDeviceDataListener(params); UploadDeviceDataListener listener = new UploadDeviceDataListener(params);
// 读取Excel // 读取Excel
EasyExcel.read(file.getInputStream(), DeviceExcelImportDTO.class, listener).sheet().doRead(); EasyExcel.read(file.getInputStream(), DeviceExcelImportDTO.class, listener).sheet().doRead();
// 获取导入结果 // 获取导入结果
result = listener.getImportResult(); result = listener.getImportResult();
// 设置响应消息 // 设置响应消息
String message = String.format("成功导入 %d 条数据,失败 %d 条", result.getSuccessCount(), result.getFailureCount()); String message = String.format("成功导入 %d 条数据,失败 %d 条", result.getSuccessCount(), result.getFailureCount());
// 返回带有正确泛型的响应 // 返回带有正确泛型的响应
return ResponseVO.<ImportResult>success(message, result); return ResponseVO.<ImportResult>success(message, result);
} catch (Exception e) { } catch (Exception e) {
log.error("导入设备数据出错: {}", e.getMessage(), e); log.error("导入设备数据出错: {}", e.getMessage(), e);
// 在异常情况下,设置默认结果 // 在异常情况下,设置默认结果
String errorMessage = String.format("导入失败: %s。成功 %d 条,失败 %d 条", e.getMessage(), result.getSuccessCount(), result.getFailureCount()); String errorMessage = String.format("导入失败: %s。成功 %d 条,失败 %d 条", e.getMessage(), result.getSuccessCount(), result.getFailureCount());
// 使用新方法确保类型正确 // 使用新方法确保类型正确
return ResponseVO.<ImportResult>fail(errorMessage, result); return ResponseVO.<ImportResult>fail(errorMessage, result);
} }

View File

@ -81,4 +81,5 @@ public class DeviceTypeController {
return ResponseVO.success(deviceTypeService.getById(id)); return ResponseVO.success(deviceTypeService.getById(id));
} }
} }

View File

@ -18,6 +18,7 @@ import com.fuyuanshen.modules.system.domain.dto.CustomerVo;
import com.fuyuanshen.modules.system.domain.dto.DeviceForm; import com.fuyuanshen.modules.system.domain.dto.DeviceForm;
import com.fuyuanshen.modules.system.domain.dto.DeviceQueryCriteria; import com.fuyuanshen.modules.system.domain.dto.DeviceQueryCriteria;
import com.fuyuanshen.modules.system.enums.BindingStatusEnum; import com.fuyuanshen.modules.system.enums.BindingStatusEnum;
import com.fuyuanshen.modules.system.enums.DeviceActiveStatusEnum;
import com.fuyuanshen.modules.system.enums.DeviceAuthorizationStatus; import com.fuyuanshen.modules.system.enums.DeviceAuthorizationStatus;
import com.fuyuanshen.modules.system.enums.DeviceStatusEnum; import com.fuyuanshen.modules.system.enums.DeviceStatusEnum;
import com.fuyuanshen.modules.system.mapper.DeviceMapper; import com.fuyuanshen.modules.system.mapper.DeviceMapper;
@ -29,6 +30,7 @@ import com.fuyuanshen.modules.system.service.DeviceAssignmentsService;
import com.fuyuanshen.modules.system.service.DeviceService; import com.fuyuanshen.modules.system.service.DeviceService;
import com.fuyuanshen.modules.system.service.DeviceTypeGrantsService; import com.fuyuanshen.modules.system.service.DeviceTypeGrantsService;
import com.fuyuanshen.modules.system.service.UserService; import com.fuyuanshen.modules.system.service.UserService;
import com.fuyuanshen.modules.utils.AdminCheckUtil;
import com.fuyuanshen.modules.utils.NanoId; import com.fuyuanshen.modules.utils.NanoId;
import com.fuyuanshen.utils.*; import com.fuyuanshen.utils.*;
import com.fuyuanshen.utils.enums.NanoIdLengthEnum; import com.fuyuanshen.utils.enums.NanoIdLengthEnum;
@ -56,6 +58,12 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService { public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {
/**
* 初级分配等级
*/
public static final int LEVEL_PRIMARY = 1;
@Value("${file.device.pic}") @Value("${file.device.pic}")
private String filePath; private String filePath;
@Value("${file.device.ip}") @Value("${file.device.ip}")
@ -99,7 +107,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
// 只能看到自己的创建的设备,以及被分配的设备。 // 只能看到自己的创建的设备,以及被分配的设备。
if (onlineuser.getTenantId() != null && !onlineuser.getTenantId().equals(UserConstants.SUPER_ADMIN_ID)) { if (onlineuser.getTenantId() != null && !onlineuser.getTenantId().equals(UserConstants.SUPER_ADMIN_ID)) {
criteria.setTenantId(onlineuser.getTenantId()); criteria.setTenantId(onlineuser.getTenantId());
// criteria.setCurrentOwnerId(onlineuser.getId()); criteria.setCurrentOwnerId(onlineuser.getId());
} }
IPage<Device> devices = deviceMapper.findAll(criteria, page); IPage<Device> devices = deviceMapper.findAll(criteria, page);
@ -183,11 +191,24 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
device.setDeviceStatus(DeviceStatusEnum.NORMAL.getCode()); device.setDeviceStatus(DeviceStatusEnum.NORMAL.getCode());
// SnowflakeGenerator snowflakeGenerator = new SnowflakeGenerator(); // SnowflakeGenerator snowflakeGenerator = new SnowflakeGenerator();
// device.setId(snowflakeGenerator.next()); // device.setId(snowflakeGenerator.next());
device.setCurrentOwnerId(currentUser.getId()); device.setCurrentOwnerId(currentUser.getId());
device.setOriginalOwnerId(currentUser.getId()); device.setOriginalOwnerId(currentUser.getId());
deviceMapper.insert(device); deviceMapper.insert(device);
// 新增设备类型记录
DeviceAssignments assignments = new DeviceAssignments();
assignments.setDeviceId(device.getId());
assignments.setAssignedAt(new Date());
// 分配者
assignments.setAssignerId(currentUser.getId());
// 接收者
assignments.setAssigneeId(currentUser.getId());
assignments.setActive(DeviceActiveStatusEnum.ACTIVE.getCode());
String lever = currentUser.getId() + ":";
assignments.setLever(lever);
deviceAssignmentsService.save(assignments);
} }
@ -315,88 +336,104 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void assignCustomer(CustomerVo customerVo) { public void assignCustomer(CustomerVo customerVo) {
// 防止管理员误操作 // 获取当前登录用户
User currentUser = userService.findById(SecurityUtils.getCurrentUserId()); User currentUser = userService.findById(SecurityUtils.getCurrentUserId());
if (currentUser.getTenantId().equals(UserConstants.SUPER_ADMIN_ID)) { // 防止管理员误操作
throw new BadRequestException(ExceptionMessages.ADMIN_OPERATION_NOT_ALLOWED); AdminCheckUtil.checkIfSuperAdmin(currentUser);
} // 获取分配用户信息
User user = userService.findById(customerVo.getCustomerId()); User user = userService.findById(customerVo.getCustomerId());
// 获取分配设备信息
List<Device> devices = deviceMapper.selectBatchIds(customerVo.getDeviceIds()); List<Device> devices = deviceMapper.selectBatchIds(customerVo.getDeviceIds());
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
// Timestamp timestamp = new Timestamp(System.currentTimeMillis());
for (Device device : devices) { for (Device device : devices) {
device.setCustomerId(user.getId()); device.setCustomerId(user.getId());
device.setCustomerName(user.getNickName()); device.setCustomerName(user.getNickName());
device.setUpdateTime(timestamp); // device.setUpdateTime(timestamp);
} }
this.updateBatchById(devices); this.updateBatchById(devices);
// 批量更新设备状态 // 批量更新设备状态
List<DeviceTypeGrants> deviceTypeGrants = new ArrayList<>(); List<DeviceTypeGrants> deviceTypeGrants = new ArrayList<>();
for (Device device : devices) { for (Device device : devices) {
// 获取当前用户的所有祖先用户
List<User> ancestorsById = userMapper.findAncestorsById(currentUser.getId());
Set<Long> excludedTenantIds = new HashSet<>();
if (CollectionUtil.isNotEmpty(ancestorsById)) {
// 提取所有需要排除的 tenant_id
excludedTenantIds = ancestorsById.stream().map(User::getTenantId).distinct().collect(Collectors.toSet());
}
excludedTenantIds.add(currentUser.getTenantId());
// 构建查询条件device_mac 相同,并且 tenant_id 不在 excludedTenantIds 列表中
Wrapper<Device> wrapper = new QueryWrapper<Device>().eq("device_mac", device.getDeviceMac()).notIn("tenant_id", excludedTenantIds);
// 构建要更新的数据 // 如果设备已分配给需要分配的客户,则跳过
Device updateDevice = new Device(); if (device.getCustomerId() != null && device.getCustomerId().equals(customerVo.getCustomerId())) {
updateDevice.setDeviceStatus(0); continue;
updateDevice.setUpdateTime(new Timestamp(System.currentTimeMillis())); }
// // 获取当前用户的所有祖先用户
// List<User> ancestorsById = userMapper.findAncestorsById(currentUser.getId());
// Set<Long> excludedTenantIds = new HashSet<>();
// if (CollectionUtil.isNotEmpty(ancestorsById)) {
// // 提取所有需要排除的 tenant_id
// excludedTenantIds = ancestorsById.stream().map(User::getTenantId).distinct().collect(Collectors.toSet());
// }
// excludedTenantIds.add(currentUser.getTenantId());
// // 构建查询条件device_mac 相同,并且 tenant_id 不在 excludedTenantIds 列表中
// Wrapper<Device> wrapper = new QueryWrapper<Device>().eq("device_mac", device.getDeviceMac()).notIn("tenant_id", excludedTenantIds);
//
// // 构建要更新的数据
// Device updateDevice = new Device();
// updateDevice.setDeviceStatus(0);
// updateDevice.setUpdateTime(new Timestamp(System.currentTimeMillis()));
// 根据条件批量更新 // 根据条件批量更新
deviceMapper.update(updateDevice, wrapper); // deviceMapper.update(updateDevice, wrapper);
// 自定义16位id // 创建并保存设备类型授权记录
Long generatedId = NanoId.generate(NanoIdLengthEnum.HIGH_CONCURRENCY.getLength()); createAndSaveDeviceTypeGrants(device, currentUser, customerVo, deviceTypeGrants);
// -- 授权设备类型给客户
// QueryWrapper<DeviceTypeGrants> deviceTypeGrantsQueryWrapper = new QueryWrapper<>();
// Long count = deviceTypeGrantsMapper.selectCount(deviceTypeGrantsQueryWrapper);
DeviceTypeGrants deviceTypeGrant = new DeviceTypeGrants();
deviceTypeGrant.setGrantedAt(new Date());
// 设备类型
deviceTypeGrant.setDeviceTypeId(device.getDeviceType());
deviceTypeGrant.setAssignmentId(generatedId);
// 被授权的客户
deviceTypeGrant.setCustomerId(customerVo.getCustomerId());
// 授权方客户
deviceTypeGrant.setGrantorCustomerId(currentUser.getId());
deviceTypeGrants.add(deviceTypeGrant);
} }
deviceTypeGrantsService.saveBatch(deviceTypeGrants); deviceTypeGrantsService.saveBatch(deviceTypeGrants);
// 批量分配 //
Set<DeviceType> deviceTypes = new HashSet<>(); // // 批量分配
for (Device device : devices) { // Set<DeviceType> deviceTypes = new HashSet<>();
device.setId(null); // for (Device device : devices) {
device.setCustomerName(null); // device.setId(null);
device.setCustomerId(null); // device.setCustomerName(null);
device.setTenantId(user.getTenantId()); // device.setCustomerId(null);
device.setCreateTime(timestamp); // device.setTenantId(user.getTenantId());
device.setCreateBy(currentUser.getUsername()); // device.setCreateTime(timestamp);
device.setUpdateTime(timestamp); // device.setCreateBy(currentUser.getUsername());
// device.setUpdateTime(timestamp);
//
// // 查询设备类型
// DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
// // SnowflakeGenerator snowflakeGenerator = new SnowflakeGenerator();
// Long id = NanoId.generate(NanoIdLengthEnum.HIGH_CONCURRENCY.getLength());
// deviceType.setId(id);
// deviceType.setCreateTime(timestamp);
// deviceType.setCreateBy(currentUser.getUsername());
// deviceType.setCustomerId(customerVo.getCustomerId());
// deviceTypes.add(deviceType);
//
// device.setDeviceType(deviceType.getId());
// }
// this.saveBatch(devices);
// deviceTypeService.saveBatch(deviceTypes);
// 查询设备类型
DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
// SnowflakeGenerator snowflakeGenerator = new SnowflakeGenerator();
Long id = NanoId.generate(NanoIdLengthEnum.HIGH_CONCURRENCY.getLength());
deviceType.setId(id);
deviceType.setCreateTime(timestamp);
deviceType.setCreateBy(currentUser.getUsername());
deviceType.setCustomerId(customerVo.getCustomerId());
deviceTypes.add(deviceType);
device.setDeviceType(deviceType.getId());
} }
this.saveBatch(devices);
deviceTypeService.saveBatch(deviceTypes);
/**
* 创建并保存设备类型授权记录
*
* @param device 当前设备对象
* @param currentUser 当前登录用户
* @param customerVo 客户信息
* @param deviceTypeGrants 授权记录集合
*/
private void createAndSaveDeviceTypeGrants(Device device, User currentUser, CustomerVo customerVo, List<DeviceTypeGrants> deviceTypeGrants) {
Long generatedId = NanoId.generate(NanoIdLengthEnum.HIGH_CONCURRENCY.getLength());
DeviceTypeGrants deviceTypeGrant = new DeviceTypeGrants();
deviceTypeGrant.setGrantedAt(new Date());
deviceTypeGrant.setDeviceTypeId(device.getDeviceType());
deviceTypeGrant.setAssignmentId(generatedId);
deviceTypeGrant.setCustomerId(customerVo.getCustomerId());
deviceTypeGrant.setGrantorCustomerId(currentUser.getId());
deviceTypeGrants.add(deviceTypeGrant);
} }

View File

@ -129,6 +129,7 @@ public class DeviceTypeServiceImpl extends ServiceImpl<DeviceTypeMapper, DeviceT
Long deviceTypeId = NanoId.generate(NanoIdLengthEnum.HIGH_CONCURRENCY.getLength()); Long deviceTypeId = NanoId.generate(NanoIdLengthEnum.HIGH_CONCURRENCY.getLength());
resources.setId(deviceTypeId); resources.setId(deviceTypeId);
resources.setCustomerId(SecurityUtils.getCurrentUserId()); resources.setCustomerId(SecurityUtils.getCurrentUserId());
resources.setOwnerCustomerId(SecurityUtils.getCurrentUserId());
deviceTypeMapper.insert(resources); deviceTypeMapper.insert(resources);
// 自动授权给自己 // 自动授权给自己

View File

@ -0,0 +1,40 @@
package com.fuyuanshen.modules.utils;
import com.fuyuanshen.constants.ExceptionMessages;
import com.fuyuanshen.exception.BadRequestException;
import com.fuyuanshen.modules.system.constant.UserConstants;
import com.fuyuanshen.modules.system.domain.User;
import com.fuyuanshen.modules.system.service.UserService;
import com.fuyuanshen.utils.SecurityUtils;
/**
* @author: 默苍璃
* @date: 2025-06-2110:35
*/
public class AdminCheckUtil {
/**
* 检查当前用户是否为超级管理员,如果是则抛出异常,防止误操作
*
* @param userService UserService 用于获取当前用户信息
*/
public static void preventAdminMisoperation(UserService userService) {
User currentUser = userService.findById(SecurityUtils.getCurrentUserId());
if (currentUser.getTenantId().equals(UserConstants.SUPER_ADMIN_ID)) {
throw new BadRequestException(ExceptionMessages.ADMIN_OPERATION_NOT_ALLOWED);
}
}
/**
* 检查用户是否是超级管理员,如果是则抛出异常
*
* @param user 当前用户对象
*/
public static void checkIfSuperAdmin(User user) {
if (user.getTenantId().equals(UserConstants.SUPER_ADMIN_ID)) {
throw new BadRequestException(ExceptionMessages.ADMIN_OPERATION_NOT_ALLOWED);
}
}
}

View File

@ -43,8 +43,8 @@
d.device_pic, d.device_mac, d.device_sn, d.create_by, d.update_by,d.device_imei, d.device_pic, d.device_mac, d.device_sn, d.create_by, d.update_by,d.device_imei,
d.create_time, d.update_time, d.device_type, d.remark, d.device_status, d.binding_status,t.type_name d.create_time, d.update_time, d.device_type, d.remark, d.device_status, d.binding_status,t.type_name
from device d from device d
left join device_type t LEFT JOIN device_type t ON d.device_type = t.id
on d.device_type = t.id LEFT JOIN device_assignments da ON da.device_id = d.id
<where> <where>
<!-- 时间范围等其他条件保持原样 --> <!-- 时间范围等其他条件保持原样 -->
<if test="criteria.deviceName != null and criteria.deviceName.trim() != ''"> <if test="criteria.deviceName != null and criteria.deviceName.trim() != ''">
@ -69,6 +69,7 @@
<if test="criteria.tenantId != null"> <if test="criteria.tenantId != null">
AND tenant_id = #{criteria.tenantId} AND tenant_id = #{criteria.tenantId}
</if> </if>
AND da.assignee_id = #{criteria.currentOwnerId}
<!-- 下面这两个条件只需满足一个 --> <!-- 下面这两个条件只需满足一个 -->