阻止重复分配

This commit is contained in:
2025-06-19 19:26:59 +08:00
parent bc0419e2c3
commit 27aea7e20d
9 changed files with 314 additions and 7 deletions

View File

@ -87,4 +87,5 @@ public class AppController {
appService.delete(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@ -0,0 +1,94 @@
package com.fuyuanshen.modules.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* @TableName device_assignments
*/
@TableName(value = "device_assignments")
@Data
public class DeviceAssignments {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 设备id
*/
private Long deviceId;
/**
* 分配方
*/
private Long fromCustomerId;
/**
* 接收方
*/
private Long toCustomerId;
/**
* 分配时间
*/
private Date assignedAt;
/**
* 0 未授权
* 1 已授权
* 是否同步授权了设备类型
*/
private Integer deviceTypeGranted;
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
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() {
final int prime = 31;
int result = 1;
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
result = prime * result + ((getDeviceId() == null) ? 0 : getDeviceId().hashCode());
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());
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

@ -21,7 +21,7 @@ public class DeviceTypeGrants {
* id
*/
@TableId(type = IdType.AUTO)
private Integer id;
private Long id;
/**
* 设备类型
@ -46,7 +46,8 @@ public class DeviceTypeGrants {
/**
* 关联分配记录
*/
private Integer assignmentId;
private Long assignmentId;
@Override
public boolean equals(Object that) {

View File

@ -0,0 +1,45 @@
package com.fuyuanshen.modules.system.enums;
/**
* @author: 默苍璃
* @date: 2025-06-1918:50
*/
public enum DeviceAuthorizationStatus {
/**
* 未授权
*/
UNAUTHORIZED(0),
/**
* 已授权
*/
AUTHORIZED(1);
private final int value;
DeviceAuthorizationStatus(int value) {
this.value = value;
}
public int getValue() {
return value;
}
/**
* 根据整数值获取对应的枚举值
*
* @param value 整数值0 或 1
* @return 对应的 DeviceAuthorizationStatus 枚举
* @throws IllegalArgumentException 如果值不是 0 或 1
*/
public static DeviceAuthorizationStatus fromValue(int value) {
for (DeviceAuthorizationStatus status : values()) {
if (status.getValue() == value) {
return status;
}
}
throw new IllegalArgumentException("Invalid device authorization status value: " + value);
}
}

View File

@ -0,0 +1,17 @@
package com.fuyuanshen.modules.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fuyuanshen.modules.system.domain.DeviceAssignments;
import org.apache.ibatis.annotations.Mapper;
/**
* @author 97433
* @description 针对表【device_assignments】的数据库操作Mapper
* @createDate 2025-06-19 18:19:13
* @Entity system.domain.DeviceAssignments
*/
@Mapper
public interface DeviceAssignmentsMapper extends BaseMapper<DeviceAssignments> {
}

View File

@ -0,0 +1,13 @@
package com.fuyuanshen.modules.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fuyuanshen.modules.system.domain.DeviceAssignments;
/**
* @author 97433
* @description 针对表【device_assignments】的数据库操作Service
* @createDate 2025-06-19 18:19:13
*/
public interface DeviceAssignmentsService extends IService<DeviceAssignments> {
}

View File

@ -0,0 +1,18 @@
package com.fuyuanshen.modules.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyuanshen.modules.system.domain.DeviceAssignments;
import com.fuyuanshen.modules.system.mapper.DeviceAssignmentsMapper;
import com.fuyuanshen.modules.system.service.DeviceAssignmentsService;
import org.springframework.stereotype.Service;
/**
* @author 97433
* @description 针对表【device_assignments】的数据库操作Service实现
* @createDate 2025-06-19 18:19:13
*/
@Service
public class DeviceAssignmentsServiceImpl extends ServiceImpl<DeviceAssignmentsMapper, DeviceAssignments>
implements DeviceAssignmentsService {
}

View File

@ -12,21 +12,20 @@ import com.fuyuanshen.constants.ExceptionMessages;
import com.fuyuanshen.exception.BadRequestException;
import com.fuyuanshen.modules.security.service.UserCacheManager;
import com.fuyuanshen.modules.system.constant.UserConstants;
import com.fuyuanshen.modules.system.domain.Device;
import com.fuyuanshen.modules.system.domain.DeviceType;
import com.fuyuanshen.modules.system.domain.DeviceTypeGrants;
import com.fuyuanshen.modules.system.domain.User;
import com.fuyuanshen.modules.system.domain.*;
import com.fuyuanshen.modules.system.domain.app.APPDevice;
import com.fuyuanshen.modules.system.domain.dto.CustomerVo;
import com.fuyuanshen.modules.system.domain.dto.DeviceForm;
import com.fuyuanshen.modules.system.domain.dto.DeviceQueryCriteria;
import com.fuyuanshen.modules.system.enums.BindingStatusEnum;
import com.fuyuanshen.modules.system.enums.DeviceAuthorizationStatus;
import com.fuyuanshen.modules.system.enums.DeviceStatusEnum;
import com.fuyuanshen.modules.system.mapper.DeviceMapper;
import com.fuyuanshen.modules.system.mapper.DeviceTypeGrantsMapper;
import com.fuyuanshen.modules.system.mapper.DeviceTypeMapper;
import com.fuyuanshen.modules.system.mapper.UserMapper;
import com.fuyuanshen.modules.system.mapper.app.APPDeviceMapper;
import com.fuyuanshen.modules.system.service.DeviceAssignmentsService;
import com.fuyuanshen.modules.system.service.DeviceService;
import com.fuyuanshen.modules.system.service.UserService;
import com.fuyuanshen.modules.utils.NanoId;
@ -71,6 +70,8 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
private final APPDeviceMapper appDeviceMapper;
private final DeviceTypeGrantsMapper deviceTypeGrantsMapper;
private final DeviceAssignmentsService deviceAssignmentsService;
@Autowired
private UserService userService;
@ -149,7 +150,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
// JwtUserDto jwtUserDto = userCacheManager.getUserCache(username);
User currentUser = userMapper.findByUsername(SecurityUtils.getCurrentUsername());
if (StringUtils.isNotEmpty(deviceForm.getDeviceMac())){
if (StringUtils.isNotEmpty(deviceForm.getDeviceMac())) {
QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("device_mac", deviceForm.getDeviceMac());
// queryWrapper.eq("tenant_id", currentUser.getTenantId());
@ -255,6 +256,104 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
throw new BadRequestException(ExceptionMessages.ADMIN_OPERATION_NOT_ALLOWED);
}
List<DeviceAssignments> assignments = new ArrayList<>();
customerVo.getDeviceIds().forEach(deviceId -> {
// 阻止重复分配
Device device = deviceMapper.selectById(deviceId);
if (device.getCustomerId() != null && device.getCustomerId().equals(customerVo.getCustomerId())) {
throw new BadRequestException("设备 " + device.getDeviceName() + " 已被分配给客户 " + device.getCustomerName());
}
// -- 记录分配历史
DeviceAssignments deviceAssignments = new DeviceAssignments();
deviceAssignments.setDeviceId(deviceId);
deviceAssignments.setFromCustomerId(currentUser.getId());
deviceAssignments.setToCustomerId(customerVo.getCustomerId());
deviceAssignments.setAssignedAt(new Date());
deviceAssignments.setDeviceTypeGranted(DeviceAuthorizationStatus.AUTHORIZED.getValue());
assignments.add(deviceAssignments);
});
deviceAssignmentsService.saveBatch(assignments);
// -- 授权设备类型给客户
QueryWrapper<DeviceTypeGrants> deviceTypeGrantsQueryWrapper = new QueryWrapper<>();
deviceTypeGrantsMapper.selectCount(deviceTypeGrantsQueryWrapper);
User user = userService.findById(customerVo.getCustomerId());
List<Device> devices = deviceMapper.selectBatchIds(customerVo.getDeviceIds());
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
for (Device device : devices) {
device.setCustomerId(user.getId());
device.setCustomerName(user.getNickName());
device.setUpdateTime(timestamp);
}
this.updateBatchById(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();
updateDevice.setDeviceStatus(0);
updateDevice.setUpdateTime(new Timestamp(System.currentTimeMillis()));
// 根据条件批量更新
deviceMapper.update(updateDevice, wrapper);
}
// 批量分配
Set<DeviceType> deviceTypes = new HashSet<>();
for (Device device : devices) {
device.setId(null);
device.setCustomerName(null);
device.setCustomerId(null);
device.setTenantId(user.getTenantId());
device.setCreateTime(timestamp);
device.setCreateBy(currentUser.getUsername());
device.setUpdateTime(timestamp);
// 查询设备类型
DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
// SnowflakeGenerator snowflakeGenerator = new SnowflakeGenerator();
Long id = NanoId.generate(16);
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 customerVo
*/
public void assignCustomer1(CustomerVo customerVo) {
// 防止管理员误操作
User currentUser = userService.findById(SecurityUtils.getCurrentUserId());
if (currentUser.getTenantId().equals(UserConstants.SUPER_ADMIN_ID)) {
throw new BadRequestException(ExceptionMessages.ADMIN_OPERATION_NOT_ALLOWED);
}
User user = userService.findById(customerVo.getCustomerId());
List<Device> devices = deviceMapper.selectBatchIds(customerVo.getDeviceIds());
Timestamp timestamp = new Timestamp(System.currentTimeMillis());

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fuyuanshen.modules.system.mapper.DeviceAssignmentsMapper">
<resultMap id="BaseResultMap" type="com.fuyuanshen.modules.system.domain.DeviceAssignments">
<id property="id" column="id" />
<result property="deviceId" column="device_id" />
<result property="fromCustomerId" column="from_customer_id" />
<result property="toCustomerId" column="to_customer_id" />
<result property="assignedAt" column="assigned_at" />
<result property="deviceTypeGranted" column="device_type_granted" />
</resultMap>
<sql id="Base_Column_List">
id,device_id,from_customer_id,to_customer_id,assigned_at,device_type_granted
</sql>
</mapper>