mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-29 16:06:36 +08:00
feat: 简化用户隧道权限分配,支持多选隧道批量分配 (#8)
- 新增批量分配接口 POST /tunnel/user/batch-assign - 支持一次选择多个隧道进行分配 - 每个隧道可单独设置限速规则 - flow/num/flowResetTime/expTime 自动从用户设置继承 - 前端表单简化为隧道多选列表+限速选择 - 已分配的隧道显示'已分配'标记且不可重复选择
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
package com.admin.common.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class UserTunnelBatchAssignDto {
|
||||
|
||||
@NotNull(message = "用户ID不能为空")
|
||||
private Integer userId;
|
||||
|
||||
@NotEmpty(message = "隧道列表不能为空")
|
||||
private List<TunnelAssignItem> tunnels;
|
||||
|
||||
@Data
|
||||
public static class TunnelAssignItem {
|
||||
@NotNull(message = "隧道ID不能为空")
|
||||
private Integer tunnelId;
|
||||
|
||||
private Integer speedId;
|
||||
}
|
||||
}
|
||||
@@ -13,28 +13,15 @@ public class UserTunnelDto {
|
||||
@NotNull(message = "隧道ID不能为空")
|
||||
private Integer tunnelId;
|
||||
|
||||
@NotNull(message = "流量限制不能为空")
|
||||
@Min(value = 0, message = "流量限制不能小于0")
|
||||
private Long flow;
|
||||
|
||||
@NotNull(message = "转发数量不能为空")
|
||||
@Min(value = 0, message = "转发数量不能小于0")
|
||||
private Integer num;
|
||||
|
||||
/**
|
||||
* 流量重置时间(时间戳)
|
||||
*/
|
||||
@NotNull(message = "流量重置时间不能为空")
|
||||
private Long flowResetTime;
|
||||
|
||||
/**
|
||||
* 到期时间(时间戳)
|
||||
*/
|
||||
@NotNull(message = "到期时间不能为空")
|
||||
private Long expTime;
|
||||
|
||||
/**
|
||||
* 限速规则ID(可选,null表示不限速)
|
||||
*/
|
||||
private Integer speedId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.admin.common.annotation.RequireRole;
|
||||
import com.admin.common.dto.TunnelDto;
|
||||
import com.admin.common.dto.TunnelUpdateDto;
|
||||
|
||||
import com.admin.common.dto.UserTunnelBatchAssignDto;
|
||||
import com.admin.common.dto.UserTunnelDto;
|
||||
import com.admin.common.dto.UserTunnelQueryDto;
|
||||
import com.admin.common.dto.UserTunnelUpdateDto;
|
||||
@@ -78,6 +79,13 @@ public class TunnelController extends BaseController {
|
||||
public R assignUserTunnel(@Validated @RequestBody UserTunnelDto userTunnelDto) {
|
||||
return userTunnelService.assignUserTunnel(userTunnelDto);
|
||||
}
|
||||
|
||||
@LogAnnotation
|
||||
@RequireRole
|
||||
@PostMapping("/user/batch-assign")
|
||||
public R batchAssignUserTunnel(@Validated @RequestBody UserTunnelBatchAssignDto batchAssignDto) {
|
||||
return userTunnelService.batchAssignUserTunnel(batchAssignDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户隧道权限列表
|
||||
|
||||
@@ -1,49 +1,23 @@
|
||||
package com.admin.service;
|
||||
|
||||
import com.admin.common.dto.UserTunnelDto;
|
||||
import com.admin.common.dto.UserTunnelQueryDto;
|
||||
import com.admin.common.dto.UserTunnelUpdateDto;
|
||||
import com.admin.common.lang.R;
|
||||
import com.admin.entity.UserTunnel;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户隧道权限服务类
|
||||
* </p>
|
||||
*
|
||||
* @author QAQ
|
||||
* @since 2025-06-03
|
||||
*/
|
||||
public interface UserTunnelService extends IService<UserTunnel> {
|
||||
|
||||
/**
|
||||
* 分配用户隧道权限
|
||||
* @param userTunnelDto 用户隧道权限数据
|
||||
* @return 结果
|
||||
*/
|
||||
R assignUserTunnel(UserTunnelDto userTunnelDto);
|
||||
|
||||
/**
|
||||
* 查询用户隧道权限列表
|
||||
* @param queryDto 查询条件
|
||||
* @return 结果
|
||||
*/
|
||||
R getUserTunnelList(UserTunnelQueryDto queryDto);
|
||||
|
||||
/**
|
||||
* 删除用户隧道权限
|
||||
* @param id ID
|
||||
* @return 结果
|
||||
*/
|
||||
R removeUserTunnel(Integer id);
|
||||
|
||||
|
||||
/**
|
||||
* 更新用户隧道权限(包含流量、流量重置时间、到期时间)
|
||||
* @param updateDto 更新数据
|
||||
* @return 结果
|
||||
*/
|
||||
R updateUserTunnel(UserTunnelUpdateDto updateDto);
|
||||
|
||||
}
|
||||
package com.admin.service;
|
||||
|
||||
import com.admin.common.dto.UserTunnelBatchAssignDto;
|
||||
import com.admin.common.dto.UserTunnelDto;
|
||||
import com.admin.common.dto.UserTunnelQueryDto;
|
||||
import com.admin.common.dto.UserTunnelUpdateDto;
|
||||
import com.admin.common.lang.R;
|
||||
import com.admin.entity.UserTunnel;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
public interface UserTunnelService extends IService<UserTunnel> {
|
||||
|
||||
R assignUserTunnel(UserTunnelDto userTunnelDto);
|
||||
|
||||
R batchAssignUserTunnel(UserTunnelBatchAssignDto batchAssignDto);
|
||||
|
||||
R getUserTunnelList(UserTunnelQueryDto queryDto);
|
||||
|
||||
R removeUserTunnel(Integer id);
|
||||
|
||||
R updateUserTunnel(UserTunnelUpdateDto updateDto);
|
||||
|
||||
}
|
||||
|
||||
+178
-120
@@ -1,120 +1,178 @@
|
||||
package com.admin.service.impl;
|
||||
|
||||
import com.admin.common.dto.*;
|
||||
import com.admin.common.lang.R;
|
||||
import com.admin.entity.UserTunnel;
|
||||
import com.admin.mapper.TunnelMapper;
|
||||
import com.admin.mapper.UserTunnelMapper;
|
||||
import com.admin.service.TunnelService;
|
||||
import com.admin.service.UserTunnelService;
|
||||
import com.admin.service.ForwardService;
|
||||
import com.admin.service.NodeService;
|
||||
import com.admin.common.utils.GostUtil;
|
||||
import com.admin.entity.Forward;
|
||||
import com.admin.entity.Tunnel;
|
||||
import com.admin.entity.Node;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户隧道权限服务实现类
|
||||
* 提供用户隧道权限的分配、查询、更新和删除功能
|
||||
* 支持流量限制、数量限制、过期时间和限速规则的管理
|
||||
* </p>
|
||||
*
|
||||
* @author QAQ
|
||||
* @since 2025-06-03
|
||||
*/
|
||||
@Service
|
||||
public class UserTunnelServiceImpl extends ServiceImpl<UserTunnelMapper, UserTunnel> implements UserTunnelService {
|
||||
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private ForwardService forwardService;
|
||||
|
||||
@Override
|
||||
public R assignUserTunnel(UserTunnelDto userTunnelDto) {
|
||||
int count = this.count(new QueryWrapper<UserTunnel>().eq("user_id", userTunnelDto.getUserId()).eq("tunnel_id", userTunnelDto.getTunnelId()));
|
||||
if (count > 0) return R.err("该用户已拥有此隧道权限");
|
||||
UserTunnel userTunnel = new UserTunnel();
|
||||
BeanUtils.copyProperties(userTunnelDto, userTunnel);
|
||||
userTunnel.setStatus(1);
|
||||
this.save(userTunnel);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public R getUserTunnelList(UserTunnelQueryDto queryDto) {
|
||||
List<UserTunnelWithDetailDto> userTunnelWithDetails = this.baseMapper.getUserTunnelWithDetails(queryDto.getUserId());
|
||||
return R.ok(userTunnelWithDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R removeUserTunnel(Integer id) {
|
||||
UserTunnel userTunnel = this.getById(id);
|
||||
if (userTunnel == null) return R.err("未找到对应的用户隧道权限记录");
|
||||
|
||||
List<Forward> forwardList = forwardService.list(new QueryWrapper<Forward>().eq("user_id", userTunnel.getUserId()).eq("tunnel_id", userTunnel.getTunnelId()));
|
||||
for (Forward forward : forwardList) {
|
||||
forwardService.deleteForward(forward.getId());
|
||||
}
|
||||
this.removeById(id);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public R updateUserTunnel(UserTunnelUpdateDto updateDto) {
|
||||
UserTunnel userTunnel = this.getById(updateDto.getId());
|
||||
if (userTunnel == null) return R.err("隧道不存在");
|
||||
boolean speedChanged = hasSpeedChanged(userTunnel.getSpeedId(), updateDto.getSpeedId());
|
||||
userTunnel.setFlow(updateDto.getFlow());
|
||||
userTunnel.setNum(updateDto.getNum());
|
||||
updateOptionalProperty(userTunnel::setFlowResetTime, updateDto.getFlowResetTime());
|
||||
updateOptionalProperty(userTunnel::setExpTime, updateDto.getExpTime());
|
||||
updateOptionalProperty(userTunnel::setStatus, updateDto.getStatus());
|
||||
userTunnel.setSpeedId(updateDto.getSpeedId());
|
||||
this.updateById(userTunnel);
|
||||
if (speedChanged) {
|
||||
List<Forward> forwardList = forwardService.list(new QueryWrapper<Forward>().eq("user_id", userTunnel.getUserId()).eq("tunnel_id", userTunnel.getTunnelId()));
|
||||
for (Forward forward : forwardList) {
|
||||
ForwardUpdateDto forwardUpdateDto = new ForwardUpdateDto();
|
||||
forwardUpdateDto.setId(forward.getId());
|
||||
forwardUpdateDto.setUserId(forward.getUserId());
|
||||
forwardUpdateDto.setName(forward.getName());
|
||||
forwardUpdateDto.setRemoteAddr(forward.getRemoteAddr());
|
||||
forwardUpdateDto.setStrategy(forward.getStrategy());
|
||||
forwardService.updateForward(forwardUpdateDto);
|
||||
}
|
||||
}
|
||||
return R.err("用户隧道权限更新失败");
|
||||
}
|
||||
|
||||
private <T> void updateOptionalProperty(java.util.function.Consumer<T> setter, T value) {
|
||||
if (value != null) {
|
||||
setter.accept(value);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSpeedChanged(Integer oldSpeedId, Integer newSpeedId) {
|
||||
if (oldSpeedId == null && newSpeedId == null) {
|
||||
return false;
|
||||
}
|
||||
if (oldSpeedId == null || newSpeedId == null) {
|
||||
return true;
|
||||
}
|
||||
return !oldSpeedId.equals(newSpeedId);
|
||||
}
|
||||
|
||||
}
|
||||
package com.admin.service.impl;
|
||||
|
||||
import com.admin.common.dto.*;
|
||||
import com.admin.common.lang.R;
|
||||
import com.admin.entity.User;
|
||||
import com.admin.entity.UserTunnel;
|
||||
import com.admin.mapper.UserTunnelMapper;
|
||||
import com.admin.service.UserService;
|
||||
import com.admin.service.UserTunnelService;
|
||||
import com.admin.service.ForwardService;
|
||||
import com.admin.entity.Forward;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class UserTunnelServiceImpl extends ServiceImpl<UserTunnelMapper, UserTunnel> implements UserTunnelService {
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private ForwardService forwardService;
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public R assignUserTunnel(UserTunnelDto userTunnelDto) {
|
||||
int count = this.count(new QueryWrapper<UserTunnel>()
|
||||
.eq("user_id", userTunnelDto.getUserId())
|
||||
.eq("tunnel_id", userTunnelDto.getTunnelId()));
|
||||
if (count > 0) return R.err("该用户已拥有此隧道权限");
|
||||
|
||||
User user = userService.getById(userTunnelDto.getUserId());
|
||||
if (user == null) return R.err("用户不存在");
|
||||
|
||||
UserTunnel userTunnel = new UserTunnel();
|
||||
userTunnel.setUserId(userTunnelDto.getUserId());
|
||||
userTunnel.setTunnelId(userTunnelDto.getTunnelId());
|
||||
userTunnel.setSpeedId(userTunnelDto.getSpeedId());
|
||||
userTunnel.setStatus(1);
|
||||
userTunnel.setInFlow(0L);
|
||||
userTunnel.setOutFlow(0L);
|
||||
|
||||
userTunnel.setFlow(userTunnelDto.getFlow() != null ? userTunnelDto.getFlow() : user.getFlow());
|
||||
userTunnel.setNum(userTunnelDto.getNum() != null ? userTunnelDto.getNum() : user.getNum());
|
||||
userTunnel.setFlowResetTime(userTunnelDto.getFlowResetTime() != null ? userTunnelDto.getFlowResetTime() : user.getFlowResetTime());
|
||||
userTunnel.setExpTime(userTunnelDto.getExpTime() != null ? userTunnelDto.getExpTime() : user.getExpTime());
|
||||
|
||||
this.save(userTunnel);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public R batchAssignUserTunnel(UserTunnelBatchAssignDto batchAssignDto) {
|
||||
User user = userService.getById(batchAssignDto.getUserId());
|
||||
if (user == null) return R.err("用户不存在");
|
||||
|
||||
List<Integer> requestedTunnelIds = batchAssignDto.getTunnels().stream()
|
||||
.map(UserTunnelBatchAssignDto.TunnelAssignItem::getTunnelId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Set<Integer> existingTunnelIds = this.list(
|
||||
new QueryWrapper<UserTunnel>()
|
||||
.eq("user_id", batchAssignDto.getUserId())
|
||||
.in("tunnel_id", requestedTunnelIds)
|
||||
).stream().map(UserTunnel::getTunnelId).collect(Collectors.toSet());
|
||||
|
||||
List<UserTunnel> toSave = new ArrayList<>();
|
||||
List<Integer> skippedIds = new ArrayList<>();
|
||||
|
||||
for (UserTunnelBatchAssignDto.TunnelAssignItem item : batchAssignDto.getTunnels()) {
|
||||
if (existingTunnelIds.contains(item.getTunnelId())) {
|
||||
skippedIds.add(item.getTunnelId());
|
||||
continue;
|
||||
}
|
||||
|
||||
UserTunnel ut = new UserTunnel();
|
||||
ut.setUserId(batchAssignDto.getUserId());
|
||||
ut.setTunnelId(item.getTunnelId());
|
||||
ut.setSpeedId(item.getSpeedId());
|
||||
ut.setStatus(1);
|
||||
ut.setInFlow(0L);
|
||||
ut.setOutFlow(0L);
|
||||
ut.setFlow(user.getFlow());
|
||||
ut.setNum(user.getNum());
|
||||
ut.setFlowResetTime(user.getFlowResetTime());
|
||||
ut.setExpTime(user.getExpTime());
|
||||
toSave.add(ut);
|
||||
}
|
||||
|
||||
if (toSave.isEmpty()) {
|
||||
return R.err("所选隧道用户均已拥有权限");
|
||||
}
|
||||
|
||||
this.saveBatch(toSave);
|
||||
|
||||
if (!skippedIds.isEmpty()) {
|
||||
return R.ok("成功分配 " + toSave.size() + " 个隧道,跳过 " + skippedIds.size() + " 个已有权限的隧道");
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public R getUserTunnelList(UserTunnelQueryDto queryDto) {
|
||||
List<UserTunnelWithDetailDto> userTunnelWithDetails = this.baseMapper.getUserTunnelWithDetails(queryDto.getUserId());
|
||||
return R.ok(userTunnelWithDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R removeUserTunnel(Integer id) {
|
||||
UserTunnel userTunnel = this.getById(id);
|
||||
if (userTunnel == null) return R.err("未找到对应的用户隧道权限记录");
|
||||
|
||||
List<Forward> forwardList = forwardService.list(new QueryWrapper<Forward>()
|
||||
.eq("user_id", userTunnel.getUserId())
|
||||
.eq("tunnel_id", userTunnel.getTunnelId()));
|
||||
for (Forward forward : forwardList) {
|
||||
forwardService.deleteForward(forward.getId());
|
||||
}
|
||||
this.removeById(id);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public R updateUserTunnel(UserTunnelUpdateDto updateDto) {
|
||||
UserTunnel userTunnel = this.getById(updateDto.getId());
|
||||
if (userTunnel == null) return R.err("隧道不存在");
|
||||
boolean speedChanged = hasSpeedChanged(userTunnel.getSpeedId(), updateDto.getSpeedId());
|
||||
userTunnel.setFlow(updateDto.getFlow());
|
||||
userTunnel.setNum(updateDto.getNum());
|
||||
updateOptionalProperty(userTunnel::setFlowResetTime, updateDto.getFlowResetTime());
|
||||
updateOptionalProperty(userTunnel::setExpTime, updateDto.getExpTime());
|
||||
updateOptionalProperty(userTunnel::setStatus, updateDto.getStatus());
|
||||
userTunnel.setSpeedId(updateDto.getSpeedId());
|
||||
this.updateById(userTunnel);
|
||||
if (speedChanged) {
|
||||
List<Forward> forwardList = forwardService.list(new QueryWrapper<Forward>()
|
||||
.eq("user_id", userTunnel.getUserId())
|
||||
.eq("tunnel_id", userTunnel.getTunnelId()));
|
||||
for (Forward forward : forwardList) {
|
||||
ForwardUpdateDto forwardUpdateDto = new ForwardUpdateDto();
|
||||
forwardUpdateDto.setId(forward.getId());
|
||||
forwardUpdateDto.setUserId(forward.getUserId());
|
||||
forwardUpdateDto.setName(forward.getName());
|
||||
forwardUpdateDto.setRemoteAddr(forward.getRemoteAddr());
|
||||
forwardUpdateDto.setStrategy(forward.getStrategy());
|
||||
forwardService.updateForward(forwardUpdateDto);
|
||||
}
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
private <T> void updateOptionalProperty(java.util.function.Consumer<T> setter, T value) {
|
||||
if (value != null) {
|
||||
setter.accept(value);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSpeedChanged(Integer oldSpeedId, Integer newSpeedId) {
|
||||
if (oldSpeedId == null && newSpeedId == null) {
|
||||
return false;
|
||||
}
|
||||
if (oldSpeedId == null || newSpeedId == null) {
|
||||
return true;
|
||||
}
|
||||
return !oldSpeedId.equals(newSpeedId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user