- 后端: JPQL构造器投影排除LONGTEXT大字段(uploadedImages/videoReferenceImages) - 后端: DTO层过滤非分镜图类型的base64内联resultUrl - 前端: 列表缩略图从video改为img loading=lazy,消除172并发请求 - 前端: download函数增加resultUrl懒加载(详情接口兜底) - 文档: 新增性能优化报告 docs/performance-optimization-report.md
852 lines
40 KiB
Java
852 lines
40 KiB
Java
package com.example.demo.controller;
|
||
|
||
import java.util.HashMap;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
import java.util.Optional;
|
||
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.data.domain.Page;
|
||
import org.springframework.data.domain.PageRequest;
|
||
import org.springframework.data.domain.Pageable;
|
||
import org.springframework.data.domain.Sort;
|
||
import org.springframework.http.ResponseEntity;
|
||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||
import org.springframework.web.bind.annotation.GetMapping;
|
||
import org.springframework.web.bind.annotation.PathVariable;
|
||
import org.springframework.web.bind.annotation.PutMapping;
|
||
import org.springframework.web.bind.annotation.RequestBody;
|
||
import org.springframework.web.bind.annotation.RequestMapping;
|
||
import org.springframework.web.bind.annotation.RequestParam;
|
||
import org.springframework.web.bind.annotation.RestController;
|
||
|
||
import com.example.demo.model.MembershipLevel;
|
||
import com.example.demo.model.User;
|
||
import com.example.demo.model.UserMembership;
|
||
import com.example.demo.repository.MembershipLevelRepository;
|
||
import com.example.demo.repository.PaymentRepository;
|
||
import com.example.demo.repository.UserMembershipRepository;
|
||
import com.example.demo.repository.UserRepository;
|
||
import com.example.demo.service.UserService;
|
||
import com.example.demo.util.JwtUtils;
|
||
import org.springframework.web.bind.annotation.RequestHeader;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
import org.slf4j.Logger;
|
||
import org.slf4j.LoggerFactory;
|
||
|
||
@RestController
|
||
@RequestMapping("/api/members")
|
||
@CrossOrigin(origins = "*")
|
||
public class MemberApiController {
|
||
|
||
private static final Logger logger = LoggerFactory.getLogger(MemberApiController.class);
|
||
|
||
@Autowired
|
||
private UserRepository userRepository;
|
||
|
||
@Autowired
|
||
private UserMembershipRepository userMembershipRepository;
|
||
|
||
@Autowired
|
||
private MembershipLevelRepository membershipLevelRepository;
|
||
|
||
@Autowired
|
||
private PaymentRepository paymentRepository;
|
||
|
||
@Autowired
|
||
private JwtUtils jwtUtils;
|
||
|
||
@Autowired
|
||
private UserService userService;
|
||
|
||
// 获取会员列表
|
||
@GetMapping
|
||
public ResponseEntity<Map<String, Object>> getMembers(
|
||
@RequestParam(defaultValue = "1") int page,
|
||
@RequestParam(defaultValue = "10") int pageSize,
|
||
@RequestParam(required = false) String level,
|
||
@RequestParam(required = false) String status) {
|
||
|
||
try {
|
||
Pageable pageable = PageRequest.of(page - 1, pageSize, Sort.by("createdAt").descending());
|
||
|
||
// 第一步:根据会员等级筛选(如果指定了等级)
|
||
List<Long> filteredUserIds = null;
|
||
if (level != null && !level.isEmpty() && !"all".equals(level)) {
|
||
// 根据等级名称查找会员等级ID
|
||
Optional<MembershipLevel> levelOpt = membershipLevelRepository.findByName(level);
|
||
|
||
if (levelOpt.isPresent()) {
|
||
Long levelId = levelOpt.get().getId();
|
||
// 查找具有该等级的所有活跃会员记录
|
||
List<UserMembership> memberships = userMembershipRepository.findAll().stream()
|
||
.filter(m -> "ACTIVE".equals(m.getStatus()) && levelId.equals(m.getMembershipLevelId()))
|
||
.toList();
|
||
|
||
// 提取用户ID列表
|
||
filteredUserIds = memberships.stream()
|
||
.map(UserMembership::getUserId)
|
||
.distinct()
|
||
.toList();
|
||
|
||
logger.info("会员等级筛选: level={}, levelId={}, 找到 {} 个用户", level, levelId, filteredUserIds.size());
|
||
} else {
|
||
logger.warn("未找到会员等级: level={}", level);
|
||
// 如果找不到等级,返回空列表
|
||
filteredUserIds = List.of();
|
||
}
|
||
}
|
||
|
||
// 第二步:根据 status 参数和等级筛选结果查询用户
|
||
Page<User> userPage;
|
||
if (filteredUserIds != null) {
|
||
// 如果有等级筛选,需要同时满足等级和状态条件
|
||
if (filteredUserIds.isEmpty()) {
|
||
// 如果等级筛选结果为空,直接返回空列表
|
||
userPage = Page.empty(pageable);
|
||
} else {
|
||
// 根据用户ID列表和状态筛选
|
||
if ("all".equals(status)) {
|
||
userPage = userRepository.findByIdIn(filteredUserIds, pageable);
|
||
} else if ("banned".equals(status)) {
|
||
userPage = userRepository.findByIdInAndIsActive(filteredUserIds, false, pageable);
|
||
} else {
|
||
userPage = userRepository.findByIdInAndIsActive(filteredUserIds, true, pageable);
|
||
}
|
||
}
|
||
} else {
|
||
// 如果没有等级筛选,只根据状态筛选
|
||
if ("all".equals(status)) {
|
||
userPage = userRepository.findAll(pageable);
|
||
} else if ("banned".equals(status)) {
|
||
userPage = userRepository.findByIsActive(false, pageable);
|
||
} else {
|
||
userPage = userRepository.findByIsActive(true, pageable);
|
||
}
|
||
}
|
||
|
||
List<Map<String, Object>> members = userPage.getContent().stream()
|
||
.map(user -> {
|
||
Map<String, Object> member = new HashMap<>();
|
||
member.put("id", user.getId());
|
||
member.put("username", user.getUsername());
|
||
member.put("email", user.getEmail());
|
||
member.put("phone", user.getPhone());
|
||
member.put("nickname", user.getNickname());
|
||
member.put("points", user.getPoints());
|
||
member.put("role", user.getRole());
|
||
member.put("isActive", user.getIsActive());
|
||
member.put("createdAt", user.getCreatedAt());
|
||
member.put("lastLoginAt", user.getLastLoginAt());
|
||
|
||
// 获取会员信息(按到期时间降序,返回最新的)
|
||
Optional<UserMembership> membership = userMembershipRepository
|
||
.findFirstByUserIdAndStatusOrderByEndDateDesc(user.getId(), "ACTIVE");
|
||
|
||
if (membership.isPresent()) {
|
||
UserMembership userMembership = membership.get();
|
||
Optional<MembershipLevel> membershipLevel = membershipLevelRepository
|
||
.findById(userMembership.getMembershipLevelId());
|
||
|
||
if (membershipLevel.isPresent()) {
|
||
Map<String, Object> membershipInfo = new HashMap<>();
|
||
MembershipLevel memberLevel = membershipLevel.get();
|
||
String displayName = memberLevel.getDisplayName();
|
||
|
||
// 🔥 仅对 free 等级进行特殊判定:根据充值金额区分"免费会员"和"入门会员"
|
||
// 其他等级(standard/professional)直接使用数据库中的 displayName
|
||
if ("free".equalsIgnoreCase(memberLevel.getName())) {
|
||
// 计算用户的总充值金额(而非充值次数)
|
||
java.math.BigDecimal totalPaid = paymentRepository.sumAmountByUserIdAndStatus(
|
||
user.getId(),
|
||
com.example.demo.model.PaymentStatus.SUCCESS
|
||
);
|
||
|
||
// 获取入门版的价格阈值
|
||
double freePrice = memberLevel.getPrice() != null ? memberLevel.getPrice() : 0.0;
|
||
double totalAmount = totalPaid != null ? totalPaid.doubleValue() : 0.0;
|
||
|
||
// 充值金额 >= 入门版价格 → 入门会员,否则 → 免费会员
|
||
if (totalAmount >= freePrice && freePrice > 0) {
|
||
displayName = "入门会员"; // 充值金额达到入门版价格
|
||
} else {
|
||
displayName = "免费会员"; // 未充值或充值金额不足
|
||
}
|
||
}
|
||
// 注:如果出现标准会员被判定为入门会员,请检查数据库 user_memberships 表中
|
||
// 该用户的 membership_level_id 是否正确指向 standard 等级(通常 id=2)
|
||
|
||
membershipInfo.put("display_name", displayName);
|
||
membershipInfo.put("end_date", userMembership.getEndDate());
|
||
membershipInfo.put("status", userMembership.getStatus());
|
||
member.put("membership", membershipInfo);
|
||
}
|
||
}
|
||
|
||
return member;
|
||
})
|
||
.toList();
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("list", members);
|
||
response.put("total", userPage.getTotalElements());
|
||
response.put("page", page);
|
||
response.put("pageSize", pageSize);
|
||
response.put("totalPages", userPage.getTotalPages());
|
||
|
||
return ResponseEntity.ok(response);
|
||
|
||
} catch (Exception e) {
|
||
Map<String, Object> error = new HashMap<>();
|
||
error.put("error", "获取会员列表失败");
|
||
error.put("message", e.getMessage());
|
||
return ResponseEntity.status(500).body(error);
|
||
}
|
||
}
|
||
|
||
// 获取会员详情
|
||
@GetMapping("/{id}")
|
||
public ResponseEntity<Map<String, Object>> getMemberDetail(@PathVariable Long id) {
|
||
try {
|
||
Optional<User> userOpt = userRepository.findById(id);
|
||
if (userOpt.isEmpty()) {
|
||
return ResponseEntity.notFound().build();
|
||
}
|
||
|
||
User user = userOpt.get();
|
||
Map<String, Object> member = new HashMap<>();
|
||
member.put("id", user.getId());
|
||
member.put("username", user.getUsername());
|
||
member.put("email", user.getEmail());
|
||
member.put("phone", user.getPhone());
|
||
member.put("nickname", user.getNickname());
|
||
member.put("points", user.getPoints());
|
||
member.put("role", user.getRole());
|
||
member.put("isActive", user.getIsActive());
|
||
member.put("createdAt", user.getCreatedAt());
|
||
member.put("lastLoginAt", user.getLastLoginAt());
|
||
|
||
// 获取会员信息(按到期时间降序,返回最新的)
|
||
Optional<UserMembership> membership = userMembershipRepository
|
||
.findFirstByUserIdAndStatusOrderByEndDateDesc(user.getId(), "ACTIVE");
|
||
|
||
if (membership.isPresent()) {
|
||
UserMembership userMembership = membership.get();
|
||
Optional<MembershipLevel> membershipLevel = membershipLevelRepository
|
||
.findById(userMembership.getMembershipLevelId());
|
||
|
||
if (membershipLevel.isPresent()) {
|
||
Map<String, Object> membershipInfo = new HashMap<>();
|
||
MembershipLevel memberLevel = membershipLevel.get();
|
||
String displayName = memberLevel.getDisplayName();
|
||
|
||
// 🔥 仅对 free 等级进行特殊判定:根据充值金额区分"免费会员"和"入门会员"
|
||
// 其他等级(standard/professional)直接使用数据库中的 displayName
|
||
if ("free".equalsIgnoreCase(memberLevel.getName())) {
|
||
// 计算用户的总充值金额(而非充值次数)
|
||
java.math.BigDecimal totalPaid = paymentRepository.sumAmountByUserIdAndStatus(
|
||
user.getId(),
|
||
com.example.demo.model.PaymentStatus.SUCCESS
|
||
);
|
||
|
||
// 获取入门版的价格阈值
|
||
double freePrice = memberLevel.getPrice() != null ? memberLevel.getPrice() : 0.0;
|
||
double totalAmount = totalPaid != null ? totalPaid.doubleValue() : 0.0;
|
||
|
||
// 充值金额 >= 入门版价格 → 入门会员,否则 → 免费会员
|
||
if (totalAmount >= freePrice && freePrice > 0) {
|
||
displayName = "入门会员"; // 充值金额达到入门版价格
|
||
} else {
|
||
displayName = "免费会员"; // 未充值或充值金额不足
|
||
}
|
||
}
|
||
// 注:如果出现标准会员被判定为入门会员,请检查数据库 user_memberships 表中
|
||
// 该用户的 membership_level_id 是否正确指向 standard 等级(通常 id=2)
|
||
|
||
membershipInfo.put("display_name", displayName);
|
||
membershipInfo.put("end_date", userMembership.getEndDate());
|
||
membershipInfo.put("status", userMembership.getStatus());
|
||
member.put("membership", membershipInfo);
|
||
}
|
||
}
|
||
|
||
return ResponseEntity.ok(member);
|
||
|
||
} catch (Exception e) {
|
||
Map<String, Object> error = new HashMap<>();
|
||
error.put("error", "获取会员详情失败");
|
||
error.put("message", e.getMessage());
|
||
return ResponseEntity.status(500).body(error);
|
||
}
|
||
}
|
||
|
||
// 更新会员信息
|
||
@PutMapping("/{id}")
|
||
public ResponseEntity<Map<String, Object>> updateMember(
|
||
@PathVariable Long id,
|
||
@RequestBody Map<String, Object> updateData,
|
||
@RequestHeader("Authorization") String token) {
|
||
try {
|
||
// 验证管理员权限
|
||
String adminUsername = extractUsernameFromToken(token);
|
||
if (adminUsername == null) {
|
||
return ResponseEntity.status(401).body(Map.of("success", false, "message", "用户未登录"));
|
||
}
|
||
|
||
User admin = userRepository.findByUsername(adminUsername).orElse(null);
|
||
if (admin == null) {
|
||
return ResponseEntity.status(403).body(Map.of("success", false, "message", "需要管理员权限"));
|
||
}
|
||
|
||
boolean isSuperAdmin = "ROLE_SUPER_ADMIN".equals(admin.getRole());
|
||
boolean isAdmin = "ROLE_ADMIN".equals(admin.getRole());
|
||
|
||
if (!isSuperAdmin && !isAdmin) {
|
||
return ResponseEntity.status(403).body(Map.of("success", false, "message", "需要管理员权限"));
|
||
}
|
||
|
||
Optional<User> userOpt = userRepository.findById(id);
|
||
if (userOpt.isEmpty()) {
|
||
return ResponseEntity.notFound().build();
|
||
}
|
||
|
||
User user = userOpt.get();
|
||
|
||
// 普通管理员不能修改超级管理员的信息
|
||
if ("ROLE_SUPER_ADMIN".equals(user.getRole()) && !isSuperAdmin) {
|
||
return ResponseEntity.status(403).body(Map.of("success", false, "message", "只有超级管理员才能修改超级管理员的信息"));
|
||
}
|
||
|
||
// 更新用户基本信息
|
||
if (updateData.containsKey("username")) {
|
||
user.setUsername((String) updateData.get("username"));
|
||
}
|
||
if (updateData.containsKey("points")) {
|
||
Object pointsObj = updateData.get("points");
|
||
if (pointsObj instanceof Number) {
|
||
user.setPoints(((Number) pointsObj).intValue());
|
||
}
|
||
}
|
||
|
||
// 只有超级管理员可以修改角色,且不能修改超级管理员的角色
|
||
if (updateData.containsKey("role") && isSuperAdmin) {
|
||
String newRole = (String) updateData.get("role");
|
||
// 如果被编辑的用户是超级管理员,跳过角色修改
|
||
if ("ROLE_SUPER_ADMIN".equals(user.getRole())) {
|
||
// 不做任何操作,保持超级管理员角色
|
||
} else if ("ROLE_USER".equals(newRole) || "ROLE_ADMIN".equals(newRole)) {
|
||
// 只允许设置为普通用户或管理员
|
||
user.setRole(newRole);
|
||
}
|
||
// 如果 newRole 是 ROLE_SUPER_ADMIN,忽略(不允许通过此接口设置超级管理员)
|
||
}
|
||
|
||
userService.save(user);
|
||
|
||
// 更新会员等级和到期时间
|
||
String levelName = (String) updateData.get("level");
|
||
String expiryDateStr = (String) updateData.get("expiryDate");
|
||
|
||
logger.info("更新会员等级: userId={}, levelName={}, expiryDate={}", id, levelName, expiryDateStr);
|
||
|
||
// 只要有会员等级或到期时间参数,就需要更新会员信息
|
||
if (levelName != null || (expiryDateStr != null && !expiryDateStr.isEmpty())) {
|
||
// 查找或创建会员信息(按到期时间降序,返回最新的)
|
||
Optional<UserMembership> membershipOpt = userMembershipRepository
|
||
.findFirstByUserIdAndStatusOrderByEndDateDesc(user.getId(), "ACTIVE");
|
||
|
||
UserMembership membership;
|
||
MembershipLevel level = null;
|
||
|
||
// 如果传入了会员等级,查找对应的等级
|
||
if (levelName != null) {
|
||
// 先尝试精确匹配 displayName
|
||
Optional<MembershipLevel> levelOpt = membershipLevelRepository.findByDisplayName(levelName);
|
||
|
||
// 如果找不到,尝试模糊匹配
|
||
if (!levelOpt.isPresent()) {
|
||
List<MembershipLevel> allLevels = membershipLevelRepository.findAll();
|
||
for (MembershipLevel lvl : allLevels) {
|
||
String name = lvl.getName();
|
||
String displayName = lvl.getDisplayName();
|
||
|
||
// 匹配 "专业会员" -> "professional" 或 "专业版"
|
||
if (levelName.contains("专业") && "professional".equalsIgnoreCase(name)) {
|
||
levelOpt = Optional.of(lvl);
|
||
break;
|
||
}
|
||
// 匹配 "标准会员" -> "standard" 或 "标准会员"
|
||
if (levelName.contains("标准") && "standard".equalsIgnoreCase(name)) {
|
||
levelOpt = Optional.of(lvl);
|
||
break;
|
||
}
|
||
// 匹配 "入门"/"免费" -> "free"(后端标记仍为 free)
|
||
if ((levelName.contains("入门") || levelName.contains("免费")) && "free".equalsIgnoreCase(name)) {
|
||
levelOpt = Optional.of(lvl);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
logger.info("查找会员等级结果: levelName={}, found={}", levelName, levelOpt.isPresent());
|
||
if (levelOpt.isPresent()) {
|
||
level = levelOpt.get();
|
||
} else {
|
||
logger.warn("❌ 未找到会员等级: levelName={}", levelName);
|
||
}
|
||
}
|
||
|
||
if (membershipOpt.isPresent()) {
|
||
membership = membershipOpt.get();
|
||
logger.info("找到现有会员记录: membershipId={}, currentEndDate={}", membership.getId(), membership.getEndDate());
|
||
} else {
|
||
// 创建新的会员记录
|
||
membership = new UserMembership();
|
||
membership.setUserId(user.getId());
|
||
membership.setStatus("ACTIVE");
|
||
membership.setStartDate(java.time.LocalDateTime.now());
|
||
// 默认到期时间为1年后
|
||
membership.setEndDate(java.time.LocalDateTime.now().plusDays(365));
|
||
logger.info("创建新会员记录");
|
||
|
||
// 如果没有指定等级,默认使用标准会员
|
||
if (level == null) {
|
||
Optional<MembershipLevel> defaultLevel = membershipLevelRepository.findByName("standard");
|
||
if (defaultLevel.isPresent()) {
|
||
level = defaultLevel.get();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新会员等级
|
||
if (level != null) {
|
||
membership.setMembershipLevelId(level.getId());
|
||
}
|
||
|
||
// 更新到期时间
|
||
if (expiryDateStr != null && !expiryDateStr.isEmpty()) {
|
||
try {
|
||
// 尝试解析带时间的格式 (如 2025-12-11T17:03:16)
|
||
java.time.LocalDateTime expiryDateTime = java.time.LocalDateTime.parse(expiryDateStr);
|
||
membership.setEndDate(expiryDateTime);
|
||
logger.info("设置到期时间(带时间格式): {}", expiryDateTime);
|
||
} catch (Exception e1) {
|
||
try {
|
||
// 尝试解析仅日期格式 (如 2025-12-11)
|
||
java.time.LocalDate expiryDate = java.time.LocalDate.parse(expiryDateStr);
|
||
membership.setEndDate(expiryDate.atTime(23, 59, 59));
|
||
logger.info("设置到期时间(日期格式): {}", expiryDate.atTime(23, 59, 59));
|
||
} catch (Exception e2) {
|
||
logger.warn("日期格式错误: {}", expiryDateStr);
|
||
}
|
||
}
|
||
}
|
||
|
||
membership.setUpdatedAt(java.time.LocalDateTime.now());
|
||
UserMembership saved = userMembershipRepository.save(membership);
|
||
logger.info("✅ 会员信息已保存: userId={}, membershipId={}, levelId={}, endDate={}",
|
||
user.getId(), saved.getId(), saved.getMembershipLevelId(), saved.getEndDate());
|
||
} else {
|
||
logger.info("未传入会员等级和到期时间参数,跳过会员信息更新");
|
||
}
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("message", "会员信息更新成功");
|
||
|
||
return ResponseEntity.ok(response);
|
||
|
||
} catch (Exception e) {
|
||
Map<String, Object> error = new HashMap<>();
|
||
error.put("error", "更新会员信息失败");
|
||
error.put("message", e.getMessage());
|
||
return ResponseEntity.status(500).body(error);
|
||
}
|
||
}
|
||
|
||
// 删除会员
|
||
@DeleteMapping("/{id}")
|
||
@Transactional
|
||
public ResponseEntity<Map<String, Object>> deleteMember(
|
||
@PathVariable Long id,
|
||
@RequestHeader("Authorization") String token) {
|
||
try {
|
||
// 验证管理员权限
|
||
String adminUsername = extractUsernameFromToken(token);
|
||
if (adminUsername == null) {
|
||
return ResponseEntity.status(401).body(Map.of("success", false, "message", "用户未登录"));
|
||
}
|
||
|
||
User admin = userRepository.findByUsername(adminUsername).orElse(null);
|
||
if (admin == null) {
|
||
return ResponseEntity.status(403).body(Map.of("success", false, "message", "需要管理员权限"));
|
||
}
|
||
|
||
boolean isSuperAdmin = "ROLE_SUPER_ADMIN".equals(admin.getRole());
|
||
boolean isAdmin = "ROLE_ADMIN".equals(admin.getRole());
|
||
|
||
if (!isSuperAdmin && !isAdmin) {
|
||
return ResponseEntity.status(403).body(Map.of("success", false, "message", "需要管理员权限"));
|
||
}
|
||
|
||
Optional<User> userOpt = userRepository.findById(id);
|
||
if (userOpt.isEmpty()) {
|
||
return ResponseEntity.notFound().build();
|
||
}
|
||
|
||
User user = userOpt.get();
|
||
|
||
// 不能删除自己
|
||
if (user.getUsername().equals(adminUsername)) {
|
||
return ResponseEntity.badRequest().body(Map.of("success", false, "message", "不能删除自己的账号"));
|
||
}
|
||
|
||
// 不能删除超级管理员
|
||
if ("ROLE_SUPER_ADMIN".equals(user.getRole())) {
|
||
return ResponseEntity.badRequest().body(Map.of("success", false, "message", "不能删除超级管理员账号"));
|
||
}
|
||
|
||
// 普通管理员不能删除其他管理员,只有超级管理员可以
|
||
if ("ROLE_ADMIN".equals(user.getRole()) && !isSuperAdmin) {
|
||
return ResponseEntity.badRequest().body(Map.of("success", false, "message", "只有超级管理员才能删除管理员账号"));
|
||
}
|
||
|
||
// 先删除关联的会员信息
|
||
userMembershipRepository.deleteByUserId(user.getId());
|
||
|
||
// 清除用户缓存
|
||
userService.evictUserCache(user.getUsername());
|
||
|
||
// 物理删除用户
|
||
userRepository.delete(user);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("message", "会员删除成功");
|
||
|
||
return ResponseEntity.ok(response);
|
||
|
||
} catch (Exception e) {
|
||
Map<String, Object> error = new HashMap<>();
|
||
error.put("error", "删除会员失败");
|
||
error.put("message", e.getMessage());
|
||
return ResponseEntity.status(500).body(error);
|
||
}
|
||
}
|
||
|
||
// 批量删除会员
|
||
@DeleteMapping("/batch")
|
||
@Transactional
|
||
public ResponseEntity<Map<String, Object>> deleteMembers(
|
||
@RequestBody Map<String, List<Long>> request,
|
||
@RequestHeader("Authorization") String token) {
|
||
try {
|
||
// 验证管理员权限
|
||
String adminUsername = extractUsernameFromToken(token);
|
||
if (adminUsername == null) {
|
||
return ResponseEntity.status(401).body(Map.of("success", false, "message", "用户未登录"));
|
||
}
|
||
|
||
User admin = userRepository.findByUsername(adminUsername).orElse(null);
|
||
if (admin == null) {
|
||
return ResponseEntity.status(403).body(Map.of("success", false, "message", "需要管理员权限"));
|
||
}
|
||
|
||
boolean isSuperAdmin = "ROLE_SUPER_ADMIN".equals(admin.getRole());
|
||
boolean isAdmin = "ROLE_ADMIN".equals(admin.getRole());
|
||
|
||
if (!isSuperAdmin && !isAdmin) {
|
||
return ResponseEntity.status(403).body(Map.of("success", false, "message", "需要管理员权限"));
|
||
}
|
||
|
||
List<Long> ids = request.get("ids");
|
||
if (ids == null || ids.isEmpty()) {
|
||
return ResponseEntity.badRequest().body(Map.of("error", "请提供要删除的会员ID列表"));
|
||
}
|
||
|
||
List<User> users = userRepository.findAllById(ids);
|
||
|
||
// 过滤掉自己、超级管理员,普通管理员还需要过滤掉其他管理员
|
||
final boolean finalIsSuperAdmin = isSuperAdmin;
|
||
List<User> toDelete = users.stream()
|
||
.filter(user -> !user.getUsername().equals(adminUsername))
|
||
.filter(user -> !"ROLE_SUPER_ADMIN".equals(user.getRole()))
|
||
.filter(user -> finalIsSuperAdmin || !"ROLE_ADMIN".equals(user.getRole()))
|
||
.toList();
|
||
|
||
int skipped = users.size() - toDelete.size();
|
||
|
||
// 物理删除:先删除关联的会员信息,清除缓存,再删除用户
|
||
for (User user : toDelete) {
|
||
userMembershipRepository.deleteByUserId(user.getId());
|
||
userService.evictUserCache(user.getUsername()); // 清除缓存
|
||
}
|
||
userRepository.deleteAll(toDelete);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("message", skipped > 0
|
||
? "批量删除成功,已跳过 " + skipped + " 个管理员账号"
|
||
: "批量删除成功");
|
||
response.put("deletedCount", toDelete.size());
|
||
response.put("skippedCount", skipped);
|
||
|
||
return ResponseEntity.ok(response);
|
||
|
||
} catch (Exception e) {
|
||
Map<String, Object> error = new HashMap<>();
|
||
error.put("error", "批量删除失败");
|
||
error.put("message", e.getMessage());
|
||
return ResponseEntity.status(500).body(error);
|
||
}
|
||
}
|
||
|
||
// 封禁/解封会员
|
||
@PutMapping("/{id}/ban")
|
||
public ResponseEntity<Map<String, Object>> toggleBanMember(
|
||
@PathVariable Long id,
|
||
@RequestBody Map<String, Boolean> request,
|
||
@RequestHeader("Authorization") String token) {
|
||
try {
|
||
// 验证管理员权限
|
||
String adminUsername = extractUsernameFromToken(token);
|
||
if (adminUsername == null) {
|
||
return ResponseEntity.status(401).body(Map.of("success", false, "message", "用户未登录"));
|
||
}
|
||
|
||
User admin = userRepository.findByUsername(adminUsername).orElse(null);
|
||
if (admin == null) {
|
||
return ResponseEntity.status(403).body(Map.of("success", false, "message", "需要管理员权限"));
|
||
}
|
||
|
||
boolean isSuperAdmin = "ROLE_SUPER_ADMIN".equals(admin.getRole());
|
||
boolean isAdmin = "ROLE_ADMIN".equals(admin.getRole());
|
||
|
||
if (!isSuperAdmin && !isAdmin) {
|
||
return ResponseEntity.status(403).body(Map.of("success", false, "message", "需要管理员权限"));
|
||
}
|
||
|
||
Optional<User> userOpt = userRepository.findById(id);
|
||
if (userOpt.isEmpty()) {
|
||
return ResponseEntity.notFound().build();
|
||
}
|
||
|
||
User user = userOpt.get();
|
||
|
||
// 不能封禁自己
|
||
if (user.getUsername().equals(adminUsername)) {
|
||
return ResponseEntity.badRequest().body(Map.of("success", false, "message", "不能封禁自己的账号"));
|
||
}
|
||
|
||
// 不能封禁超级管理员
|
||
if ("ROLE_SUPER_ADMIN".equals(user.getRole())) {
|
||
return ResponseEntity.badRequest().body(Map.of("success", false, "message", "不能封禁超级管理员账号"));
|
||
}
|
||
|
||
// 普通管理员不能封禁其他管理员,只有超级管理员可以
|
||
if ("ROLE_ADMIN".equals(user.getRole()) && !isSuperAdmin) {
|
||
return ResponseEntity.badRequest().body(Map.of("success", false, "message", "只有超级管理员才能封禁管理员账号"));
|
||
}
|
||
|
||
// 获取要设置的状态(true=解封,false=封禁)
|
||
Boolean isActive = request.get("isActive");
|
||
if (isActive == null) {
|
||
isActive = !user.getIsActive(); // 如果没传,则切换状态
|
||
}
|
||
|
||
user.setIsActive(isActive);
|
||
userService.save(user);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("message", isActive ? "解封成功" : "封禁成功");
|
||
response.put("isActive", isActive);
|
||
|
||
return ResponseEntity.ok(response);
|
||
|
||
} catch (Exception e) {
|
||
Map<String, Object> error = new HashMap<>();
|
||
error.put("error", "操作失败");
|
||
error.put("message", e.getMessage());
|
||
return ResponseEntity.status(500).body(error);
|
||
}
|
||
}
|
||
|
||
// 设置用户角色(仅超级管理员可操作)
|
||
@PutMapping("/{id}/role")
|
||
public ResponseEntity<Map<String, Object>> setUserRole(
|
||
@PathVariable Long id,
|
||
@RequestBody Map<String, String> request,
|
||
@RequestHeader("Authorization") String token) {
|
||
try {
|
||
// 验证超级管理员权限
|
||
String adminUsername = extractUsernameFromToken(token);
|
||
if (adminUsername == null) {
|
||
return ResponseEntity.status(401).body(Map.of("success", false, "message", "用户未登录"));
|
||
}
|
||
|
||
User admin = userRepository.findByUsername(adminUsername).orElse(null);
|
||
if (admin == null || !"ROLE_SUPER_ADMIN".equals(admin.getRole())) {
|
||
return ResponseEntity.status(403).body(Map.of("success", false, "message", "需要超级管理员权限"));
|
||
}
|
||
|
||
Optional<User> userOpt = userRepository.findById(id);
|
||
if (userOpt.isEmpty()) {
|
||
return ResponseEntity.notFound().build();
|
||
}
|
||
|
||
User user = userOpt.get();
|
||
|
||
// 不能修改自己的角色
|
||
if (user.getUsername().equals(adminUsername)) {
|
||
return ResponseEntity.badRequest().body(Map.of("success", false, "message", "不能修改自己的角色"));
|
||
}
|
||
|
||
// 不能修改其他超级管理员的角色
|
||
if ("ROLE_SUPER_ADMIN".equals(user.getRole())) {
|
||
return ResponseEntity.badRequest().body(Map.of("success", false, "message", "不能修改超级管理员的角色"));
|
||
}
|
||
|
||
String newRole = request.get("role");
|
||
if (newRole == null || newRole.isEmpty()) {
|
||
return ResponseEntity.badRequest().body(Map.of("success", false, "message", "请指定角色"));
|
||
}
|
||
|
||
// 验证角色有效性
|
||
if (!"ROLE_USER".equals(newRole) && !"ROLE_ADMIN".equals(newRole)) {
|
||
return ResponseEntity.badRequest().body(Map.of("success", false, "message", "无效的角色"));
|
||
}
|
||
|
||
String oldRole = user.getRole();
|
||
user.setRole(newRole);
|
||
userService.save(user);
|
||
|
||
String action = "ROLE_ADMIN".equals(newRole) ? "设置为管理员" : "取消管理员权限";
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("message", "用户 " + user.getUsername() + " 已" + action);
|
||
response.put("oldRole", oldRole);
|
||
response.put("newRole", newRole);
|
||
|
||
return ResponseEntity.ok(response);
|
||
|
||
} catch (Exception e) {
|
||
Map<String, Object> error = new HashMap<>();
|
||
error.put("error", "操作失败");
|
||
error.put("message", e.getMessage());
|
||
return ResponseEntity.status(500).body(error);
|
||
}
|
||
}
|
||
|
||
// 从Token中提取用户名
|
||
private String extractUsernameFromToken(String token) {
|
||
try {
|
||
if (token == null || !token.startsWith("Bearer ")) {
|
||
return null;
|
||
}
|
||
String actualToken = token.substring(7);
|
||
if (jwtUtils.isTokenExpired(actualToken)) {
|
||
return null;
|
||
}
|
||
return jwtUtils.getUsernameFromToken(actualToken);
|
||
} catch (Exception e) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 获取所有会员等级配置(用于系统设置和订阅页面)
|
||
@GetMapping("/levels")
|
||
public ResponseEntity<Map<String, Object>> getMembershipLevels() {
|
||
try {
|
||
List<MembershipLevel> levels = membershipLevelRepository.findAll();
|
||
|
||
List<Map<String, Object>> levelList = levels.stream()
|
||
.map(level -> {
|
||
Map<String, Object> levelMap = new HashMap<>();
|
||
levelMap.put("id", level.getId());
|
||
levelMap.put("name", level.getName());
|
||
levelMap.put("displayName", level.getDisplayName());
|
||
levelMap.put("description", level.getDescription());
|
||
levelMap.put("price", level.getPrice());
|
||
levelMap.put("durationDays", level.getDurationDays());
|
||
levelMap.put("pointsBonus", level.getPointsBonus());
|
||
levelMap.put("features", level.getFeatures());
|
||
levelMap.put("isActive", level.getIsActive());
|
||
return levelMap;
|
||
})
|
||
.toList();
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("data", levelList);
|
||
|
||
return ResponseEntity.ok(response);
|
||
|
||
} catch (Exception e) {
|
||
Map<String, Object> error = new HashMap<>();
|
||
error.put("error", "获取会员等级配置失败");
|
||
error.put("message", e.getMessage());
|
||
return ResponseEntity.status(500).body(error);
|
||
}
|
||
}
|
||
|
||
// 更新会员等级价格和配置
|
||
@PutMapping("/levels/{id}")
|
||
public ResponseEntity<Map<String, Object>> updateMembershipLevel(
|
||
@PathVariable Long id,
|
||
@RequestBody Map<String, Object> updateData) {
|
||
try {
|
||
Optional<MembershipLevel> levelOpt = membershipLevelRepository.findById(id);
|
||
if (levelOpt.isEmpty()) {
|
||
return ResponseEntity.notFound().build();
|
||
}
|
||
|
||
MembershipLevel level = levelOpt.get();
|
||
|
||
// 更新价格
|
||
if (updateData.containsKey("price")) {
|
||
Object priceObj = updateData.get("price");
|
||
if (priceObj instanceof Number) {
|
||
level.setPrice(((Number) priceObj).doubleValue());
|
||
} else if (priceObj instanceof String) {
|
||
level.setPrice(Double.parseDouble((String) priceObj));
|
||
}
|
||
}
|
||
|
||
// 更新资源点数量
|
||
if (updateData.containsKey("pointsBonus") || updateData.containsKey("resourcePoints")) {
|
||
Object pointsObj = updateData.get("pointsBonus") != null
|
||
? updateData.get("pointsBonus")
|
||
: updateData.get("resourcePoints");
|
||
if (pointsObj instanceof Number) {
|
||
level.setPointsBonus(((Number) pointsObj).intValue());
|
||
} else if (pointsObj instanceof String) {
|
||
level.setPointsBonus(Integer.parseInt((String) pointsObj));
|
||
}
|
||
}
|
||
|
||
// 更新描述
|
||
if (updateData.containsKey("description")) {
|
||
level.setDescription((String) updateData.get("description"));
|
||
}
|
||
|
||
level.setUpdatedAt(java.time.LocalDateTime.now());
|
||
membershipLevelRepository.save(level);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("message", "会员等级配置更新成功");
|
||
|
||
return ResponseEntity.ok(response);
|
||
|
||
} catch (Exception e) {
|
||
Map<String, Object> error = new HashMap<>();
|
||
error.put("error", "更新会员等级配置失败");
|
||
error.put("message", e.getMessage());
|
||
return ResponseEntity.status(500).body(error);
|
||
}
|
||
}
|
||
}
|