完成数据库结构升级 - 移除模拟数据,实现真实数据库集成

- 扩展数据库表结构,添加会员等级、用户会员信息、视频任务、用户作品、系统配置等表
- 更新用户表,添加手机号、头像、昵称、性别、生日、地址等字段
- 创建完整的初始数据,包含10个用户、3个会员等级、15个订单、10个视频任务、10个用户作品
- 实现会员管理API控制器,支持CRUD操作和批量操作
- 创建会员等级和用户会员信息实体类及仓库接口
- 更新前端会员管理页面,集成真实API调用,保留模拟数据作为后备
- 实现编辑功能,支持修改用户名、会员等级、资源点、到期时间等信息
This commit is contained in:
AIGC Developer
2025-10-22 09:50:11 +08:00
parent c31019e013
commit 8449423cfb
26 changed files with 1196 additions and 40 deletions

View File

@@ -0,0 +1,263 @@
package com.example.demo.controller;
import com.example.demo.model.User;
import com.example.demo.model.UserMembership;
import com.example.demo.model.MembershipLevel;
import com.example.demo.repository.UserRepository;
import com.example.demo.repository.UserMembershipRepository;
import com.example.demo.repository.MembershipLevelRepository;
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.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@RestController
@RequestMapping("/api/members")
@CrossOrigin(origins = "*")
public class MemberApiController {
@Autowired
private UserRepository userRepository;
@Autowired
private UserMembershipRepository userMembershipRepository;
@Autowired
private MembershipLevelRepository membershipLevelRepository;
// 获取会员列表
@GetMapping
public ResponseEntity<Map<String, Object>> getMembers(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int pageSize,
@RequestParam(required = false) String level) {
try {
Pageable pageable = PageRequest.of(page - 1, pageSize, Sort.by("createdAt").descending());
Page<User> userPage = userRepository.findAll(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
.findByUserIdAndStatus(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<>();
membershipInfo.put("display_name", membershipLevel.get().getDisplayName());
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
.findByUserIdAndStatus(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<>();
membershipInfo.put("display_name", membershipLevel.get().getDisplayName());
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) {
try {
Optional<User> userOpt = userRepository.findById(id);
if (userOpt.isEmpty()) {
return ResponseEntity.notFound().build();
}
User user = userOpt.get();
// 更新用户基本信息
if (updateData.containsKey("username")) {
user.setUsername((String) updateData.get("username"));
}
if (updateData.containsKey("points")) {
user.setPoints((Integer) updateData.get("points"));
}
userRepository.save(user);
// 更新会员等级
if (updateData.containsKey("level")) {
String levelName = (String) updateData.get("level");
Optional<MembershipLevel> levelOpt = membershipLevelRepository
.findByDisplayName(levelName);
if (levelOpt.isPresent()) {
MembershipLevel level = levelOpt.get();
// 更新或创建会员信息
Optional<UserMembership> membershipOpt = userMembershipRepository
.findByUserIdAndStatus(user.getId(), "ACTIVE");
if (membershipOpt.isPresent()) {
UserMembership membership = membershipOpt.get();
membership.setMembershipLevelId(level.getId());
userMembershipRepository.save(membership);
}
}
}
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}")
public ResponseEntity<Map<String, Object>> deleteMember(@PathVariable Long id) {
try {
Optional<User> userOpt = userRepository.findById(id);
if (userOpt.isEmpty()) {
return ResponseEntity.notFound().build();
}
// 软删除:设置为非活跃状态
User user = userOpt.get();
user.setIsActive(false);
userRepository.save(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")
public ResponseEntity<Map<String, Object>> deleteMembers(@RequestBody Map<String, List<Long>> request) {
try {
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);
users.forEach(user -> user.setIsActive(false));
userRepository.saveAll(users);
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("message", "批量删除成功");
response.put("deletedCount", users.size());
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);
}
}
}

View File

@@ -0,0 +1,145 @@
package com.example.demo.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "membership_levels")
public class MembershipLevel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", nullable = false, unique = true)
private String name;
@Column(name = "display_name", nullable = false)
private String displayName;
@Column(name = "description")
private String description;
@Column(name = "price", nullable = false)
private Double price;
@Column(name = "duration_days", nullable = false)
private Integer durationDays;
@Column(name = "points_bonus", nullable = false)
private Integer pointsBonus;
@Column(name = "features", columnDefinition = "JSON")
private String features;
@Column(name = "is_active", nullable = false)
private Boolean isActive = true;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt = LocalDateTime.now();
@Column(name = "updated_at")
private LocalDateTime updatedAt;
// 构造函数
public MembershipLevel() {}
public MembershipLevel(String name, String displayName, String description, Double price,
Integer durationDays, Integer pointsBonus, String features) {
this.name = name;
this.displayName = displayName;
this.description = description;
this.price = price;
this.durationDays = durationDays;
this.pointsBonus = pointsBonus;
this.features = features;
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Integer getDurationDays() {
return durationDays;
}
public void setDurationDays(Integer durationDays) {
this.durationDays = durationDays;
}
public Integer getPointsBonus() {
return pointsBonus;
}
public void setPointsBonus(Integer pointsBonus) {
this.pointsBonus = pointsBonus;
}
public String getFeatures() {
return features;
}
public void setFeatures(String features) {
this.features = features;
}
public Boolean getIsActive() {
return isActive;
}
public void setIsActive(Boolean isActive) {
this.isActive = isActive;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}

View File

@@ -44,9 +44,36 @@ public class User {
@Column(nullable = false)
private Integer points = 50; // 默认50积分
@Column(name = "phone", length = 20)
private String phone;
@Column(name = "avatar", length = 500)
private String avatar;
@Column(name = "nickname", length = 100)
private String nickname;
@Column(name = "gender", length = 10)
private String gender;
@Column(name = "birthday")
private java.time.LocalDate birthday;
@Column(name = "address", columnDefinition = "TEXT")
private String address;
@Column(name = "is_active", nullable = false)
private Boolean isActive = true;
@Column(name = "last_login_at")
private LocalDateTime lastLoginAt;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
@@ -107,6 +134,78 @@ public class User {
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public java.time.LocalDate getBirthday() {
return birthday;
}
public void setBirthday(java.time.LocalDate birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Boolean getIsActive() {
return isActive;
}
public void setIsActive(Boolean isActive) {
this.isActive = isActive;
}
public LocalDateTime getLastLoginAt() {
return lastLoginAt;
}
public void setLastLoginAt(LocalDateTime lastLoginAt) {
this.lastLoginAt = lastLoginAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}

View File

@@ -0,0 +1,118 @@
package com.example.demo.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "user_memberships")
public class UserMembership {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id", nullable = false)
private Long userId;
@Column(name = "membership_level_id", nullable = false)
private Long membershipLevelId;
@Column(name = "start_date", nullable = false)
private LocalDateTime startDate = LocalDateTime.now();
@Column(name = "end_date", nullable = false)
private LocalDateTime endDate;
@Column(name = "status", nullable = false)
private String status = "ACTIVE";
@Column(name = "auto_renew", nullable = false)
private Boolean autoRenew = false;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt = LocalDateTime.now();
@Column(name = "updated_at")
private LocalDateTime updatedAt;
// 构造函数
public UserMembership() {}
public UserMembership(Long userId, Long membershipLevelId, LocalDateTime endDate) {
this.userId = userId;
this.membershipLevelId = membershipLevelId;
this.endDate = endDate;
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getMembershipLevelId() {
return membershipLevelId;
}
public void setMembershipLevelId(Long membershipLevelId) {
this.membershipLevelId = membershipLevelId;
}
public LocalDateTime getStartDate() {
return startDate;
}
public void setStartDate(LocalDateTime startDate) {
this.startDate = startDate;
}
public LocalDateTime getEndDate() {
return endDate;
}
public void setEndDate(LocalDateTime endDate) {
this.endDate = endDate;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Boolean getAutoRenew() {
return autoRenew;
}
public void setAutoRenew(Boolean autoRenew) {
this.autoRenew = autoRenew;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}

View File

@@ -0,0 +1,13 @@
package com.example.demo.repository;
import com.example.demo.model.MembershipLevel;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface MembershipLevelRepository extends JpaRepository<MembershipLevel, Long> {
Optional<MembershipLevel> findByDisplayName(String displayName);
Optional<MembershipLevel> findByName(String name);
}

View File

@@ -0,0 +1,12 @@
package com.example.demo.repository;
import com.example.demo.model.UserMembership;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserMembershipRepository extends JpaRepository<UserMembership, Long> {
Optional<UserMembership> findByUserIdAndStatus(Long userId, String status);
}

View File

@@ -25,3 +25,6 @@ public class PlainTextPasswordEncoder implements PasswordEncoder {