From e7950bf6156c3f315c4f27db8b652cee9c83b3c7 Mon Sep 17 00:00:00 2001 From: bruce Date: Thu, 20 Feb 2025 17:32:22 +0800 Subject: [PATCH] =?UTF-8?q?v0.2.7=20=E5=AE=8C=E6=88=90=E6=B4=BB=E5=8A=A8?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E6=A8=A1=E5=9D=97=E6=90=AD=E5=BB=BA=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90=E7=B3=BB=E7=BB=9F=20?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E4=BB=B6=E8=8E=B7=E5=8F=96=E6=A8=A1?= =?UTF-8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sams/common/config/SecurityConfig.java | 39 +++- .../sams/common/config/WebMvcConfig.java | 16 ++ .../sams/common/filter/JwtAuthFilter.java | 58 ++++-- .../sams/common/utils/FileUploadUtil.java | 27 +++ .../bruce/sams/controller/AuthController.java | 4 + .../controller/ams/ActivityController.java | 40 ++++ .../controller/ams/ApprovalController.java | 41 ++++ .../sys/DocumentUploadController.java | 15 ++ .../sams/controller/sys/UserController.java | 33 +++ .../com/bruce/sams/domain/ams/Activity.java | 188 ++++++++++++++++++ .../com/bruce/sams/domain/ams/Approval.java | 114 +++++++++++ .../com/bruce/sams/domain/ams/Comment.java | 96 +++++++++ .../com/bruce/sams/domain/ams/Reaction.java | 88 ++++++++ .../bruce/sams/domain/ams/Registration.java | 104 ++++++++++ .../sams/domain/entity/ActivityStatus.java | 16 ++ .../sams/domain/entity/ActivityType.java | 11 + .../sams/domain/entity/ApprovalStatus.java | 10 + .../java/com/bruce/sams/domain/sys/User.java | 53 +++-- .../com/bruce/sams/mapper/ActivityMapper.java | 18 ++ .../com/bruce/sams/mapper/ApprovalMapper.java | 20 ++ .../com/bruce/sams/mapper/CommentMapper.java | 20 ++ .../com/bruce/sams/mapper/ReactionMapper.java | 20 ++ .../bruce/sams/mapper/RegistrationMapper.java | 20 ++ .../com/bruce/sams/mapper/UserMapper.java | 3 + .../bruce/sams/service/ActivityService.java | 36 ++++ .../bruce/sams/service/ApprovalService.java | 21 ++ .../bruce/sams/service/CommentService.java | 13 ++ .../bruce/sams/service/ReactionService.java | 13 ++ .../sams/service/RegistrationService.java | 13 ++ .../com/bruce/sams/service/UserService.java | 7 + .../service/impl/ActivityServiceImpl.java | 70 +++++++ .../service/impl/ApprovalServiceImpl.java | 102 ++++++++++ .../service/impl/ClubUserServiceImpl.java | 6 +- .../sams/service/impl/CommentServiceImpl.java | 22 ++ .../impl/CustomUserDetailsService.java | 2 +- .../service/impl/ReactionServiceImpl.java | 22 ++ .../service/impl/RegistrationServiceImpl.java | 22 ++ .../sams/service/impl/UserServiceImpl.java | 15 +- src/main/resources/application.yml | 11 +- src/main/resources/mapper/ActivityMapper.xml | 33 +++ src/main/resources/mapper/ApprovalMapper.xml | 22 ++ src/main/resources/mapper/CommentMapper.xml | 19 ++ src/main/resources/mapper/ReactionMapper.xml | 18 ++ .../resources/mapper/RegistrationMapper.xml | 21 ++ 44 files changed, 1485 insertions(+), 57 deletions(-) create mode 100644 src/main/java/com/bruce/sams/common/config/WebMvcConfig.java create mode 100644 src/main/java/com/bruce/sams/common/utils/FileUploadUtil.java create mode 100644 src/main/java/com/bruce/sams/controller/ams/ActivityController.java create mode 100644 src/main/java/com/bruce/sams/controller/ams/ApprovalController.java create mode 100644 src/main/java/com/bruce/sams/controller/sys/DocumentUploadController.java create mode 100644 src/main/java/com/bruce/sams/domain/ams/Activity.java create mode 100644 src/main/java/com/bruce/sams/domain/ams/Approval.java create mode 100644 src/main/java/com/bruce/sams/domain/ams/Comment.java create mode 100644 src/main/java/com/bruce/sams/domain/ams/Reaction.java create mode 100644 src/main/java/com/bruce/sams/domain/ams/Registration.java create mode 100644 src/main/java/com/bruce/sams/domain/entity/ActivityStatus.java create mode 100644 src/main/java/com/bruce/sams/domain/entity/ActivityType.java create mode 100644 src/main/java/com/bruce/sams/domain/entity/ApprovalStatus.java create mode 100644 src/main/java/com/bruce/sams/mapper/ActivityMapper.java create mode 100644 src/main/java/com/bruce/sams/mapper/ApprovalMapper.java create mode 100644 src/main/java/com/bruce/sams/mapper/CommentMapper.java create mode 100644 src/main/java/com/bruce/sams/mapper/ReactionMapper.java create mode 100644 src/main/java/com/bruce/sams/mapper/RegistrationMapper.java create mode 100644 src/main/java/com/bruce/sams/service/ActivityService.java create mode 100644 src/main/java/com/bruce/sams/service/ApprovalService.java create mode 100644 src/main/java/com/bruce/sams/service/CommentService.java create mode 100644 src/main/java/com/bruce/sams/service/ReactionService.java create mode 100644 src/main/java/com/bruce/sams/service/RegistrationService.java create mode 100644 src/main/java/com/bruce/sams/service/impl/ActivityServiceImpl.java create mode 100644 src/main/java/com/bruce/sams/service/impl/ApprovalServiceImpl.java create mode 100644 src/main/java/com/bruce/sams/service/impl/CommentServiceImpl.java create mode 100644 src/main/java/com/bruce/sams/service/impl/ReactionServiceImpl.java create mode 100644 src/main/java/com/bruce/sams/service/impl/RegistrationServiceImpl.java create mode 100644 src/main/resources/mapper/ActivityMapper.xml create mode 100644 src/main/resources/mapper/ApprovalMapper.xml create mode 100644 src/main/resources/mapper/CommentMapper.xml create mode 100644 src/main/resources/mapper/ReactionMapper.xml create mode 100644 src/main/resources/mapper/RegistrationMapper.xml diff --git a/src/main/java/com/bruce/sams/common/config/SecurityConfig.java b/src/main/java/com/bruce/sams/common/config/SecurityConfig.java index 29c8ffb1..5d915331 100644 --- a/src/main/java/com/bruce/sams/common/config/SecurityConfig.java +++ b/src/main/java/com/bruce/sams/common/config/SecurityConfig.java @@ -1,34 +1,57 @@ + package com.bruce.sams.common.config; import com.bruce.sams.common.filter.JwtAuthFilter; +import com.bruce.sams.service.impl.CustomUserDetailsService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -/** - * Spring Security 配置类 - */ +import java.util.Collections; + @Configuration -@EnableWebSecurity public class SecurityConfig { + private final JwtAuthFilter jwtAuthFilter; + + public SecurityConfig(JwtAuthFilter jwtAuthFilter) { + this.jwtAuthFilter = jwtAuthFilter; + } + @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - http + return http .csrf(csrf -> csrf.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth + .requestMatchers("/api/auth/**").permitAll() // 允许访问认证相关接口 .requestMatchers("/api/auth/login").permitAll() .requestMatchers("/api/admin/**").hasAuthority("ADMIN") .requestMatchers("/api/user/**").hasAuthority("participant") .anyRequest().authenticated() ) - .addFilterBefore(new JwtAuthFilter(), UsernamePasswordAuthenticationFilter.class); + .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) // JWT 过滤器 + .build(); + } - return http.build(); + @Bean + public AuthenticationManager authenticationManager(UserDetailsService userDetailsService) { + DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); + authProvider.setUserDetailsService(userDetailsService); + authProvider.setPasswordEncoder(new BCryptPasswordEncoder()); + return new ProviderManager(Collections.singletonList(authProvider)); + } + + @Bean + public UserDetailsService userDetailsService() { + return new CustomUserDetailsService(); } } diff --git a/src/main/java/com/bruce/sams/common/config/WebMvcConfig.java b/src/main/java/com/bruce/sams/common/config/WebMvcConfig.java new file mode 100644 index 00000000..721cb637 --- /dev/null +++ b/src/main/java/com/bruce/sams/common/config/WebMvcConfig.java @@ -0,0 +1,16 @@ +package com.bruce.sams.common.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/uploads/**") + .addResourceLocations("file:uploads/"); + } + +} diff --git a/src/main/java/com/bruce/sams/common/filter/JwtAuthFilter.java b/src/main/java/com/bruce/sams/common/filter/JwtAuthFilter.java index 724d9548..bab61820 100644 --- a/src/main/java/com/bruce/sams/common/filter/JwtAuthFilter.java +++ b/src/main/java/com/bruce/sams/common/filter/JwtAuthFilter.java @@ -1,44 +1,58 @@ package com.bruce.sams.common.filter; -import com.bruce.sams.service.impl.CustomUserDetailsService; import com.bruce.sams.common.utils.TokenUtil; +import com.bruce.sams.domain.sys.User; +import com.bruce.sams.service.impl.CustomUserDetailsService; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.JwtException; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.springframework.context.annotation.Bean; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; -/** - * JWT 认证过滤器,解析 Token 并设置用户身份 - */ @Component public class JwtAuthFilter extends OncePerRequestFilter { + private final UserDetailsService userDetailsService; + + public JwtAuthFilter(CustomUserDetailsService userDetailsService) { + this.userDetailsService = userDetailsService; + } + @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - String token = request.getHeader("Authorization"); + String token = getTokenFromRequest(request); - if (token != null && token.startsWith("Bearer ")) { - token = token.substring(7); + if (StringUtils.hasText(token)) { try { + // 解析 Token Long userId = TokenUtil.getUserIdFromToken(token); - String role = TokenUtil.getRoleFromToken(token); - // 将 userId 存入 request,供 Controller 直接使用 - request.setAttribute("userId", userId); + // **从数据库加载完整用户信息** + User userDetails = (User) userDetailsService.loadUserByUsername(String.valueOf(userId)); + + // **确保 Authentication 存入 User** + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + + // **存入 SecurityContext** + SecurityContextHolder.getContext().setAuthentication(authentication); - SecurityContextHolder.getContext().setAuthentication( - new UsernamePasswordAuthenticationToken(userId, null, null)); } catch (Exception e) { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid Token"); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token 无效"); return; } } @@ -46,9 +60,15 @@ public class JwtAuthFilter extends OncePerRequestFilter { filterChain.doFilter(request, response); } - @Bean - public UserDetailsService userDetailsService() { - return new CustomUserDetailsService(); // 认证逻辑 - } + /** + * 从请求头获取 Token + */ + private String getTokenFromRequest(HttpServletRequest request) { + String bearerToken = request.getHeader("Authorization"); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } } diff --git a/src/main/java/com/bruce/sams/common/utils/FileUploadUtil.java b/src/main/java/com/bruce/sams/common/utils/FileUploadUtil.java new file mode 100644 index 00000000..79bca1c5 --- /dev/null +++ b/src/main/java/com/bruce/sams/common/utils/FileUploadUtil.java @@ -0,0 +1,27 @@ +package com.bruce.sams.common.utils; + +import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; +import java.nio.file.*; + + +public class FileUploadUtil { + + private static final String UPLOAD_DIR = "uploads/"; + + public static String uploadFile(MultipartFile file, String subDir) { + if (file.isEmpty()) { + throw new RuntimeException("文件不能为空"); + } + try { + String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename(); + Path uploadPath = Paths.get(UPLOAD_DIR + subDir); + Files.createDirectories(uploadPath); + Path filePath = uploadPath.resolve(fileName); + Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING); + return "/uploads/" + subDir + fileName; + } catch (IOException e) { + throw new RuntimeException("文件上传失败", e); + } + } +} diff --git a/src/main/java/com/bruce/sams/controller/AuthController.java b/src/main/java/com/bruce/sams/controller/AuthController.java index 9db0b889..221a2a16 100644 --- a/src/main/java/com/bruce/sams/controller/AuthController.java +++ b/src/main/java/com/bruce/sams/controller/AuthController.java @@ -1,10 +1,12 @@ package com.bruce.sams.controller; +import com.bruce.sams.common.utils.FileUploadUtil; import com.bruce.sams.domain.entity.LoginRequest; import com.bruce.sams.service.AuthService; import com.bruce.sams.common.utils.AjaxResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; /** * 认证控制器,处理用户登录请求 @@ -28,4 +30,6 @@ public class AuthController { String token = authService.authenticate(loginRequest); return AjaxResult.success("登录成功", token); } + + } diff --git a/src/main/java/com/bruce/sams/controller/ams/ActivityController.java b/src/main/java/com/bruce/sams/controller/ams/ActivityController.java new file mode 100644 index 00000000..a35f03ad --- /dev/null +++ b/src/main/java/com/bruce/sams/controller/ams/ActivityController.java @@ -0,0 +1,40 @@ +package com.bruce.sams.controller.ams; + + +import com.bruce.sams.common.utils.AjaxResult; +import com.bruce.sams.domain.ams.Activity; +import com.bruce.sams.service.ActivityService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +/** + * 活动管理控制器(权限区分) + */ +@RestController +@RequestMapping("/api/admin/activity") +public class ActivityController { + + @Autowired + private ActivityService activityService; + + /** + * 创建活动 + */ + @PreAuthorize("hasRole('USER') or hasRole('CLUB_ADMIN')") + @PostMapping("/create") + public AjaxResult createActivity(@RequestBody Activity activity) { + activityService.createActivity(activity); + return AjaxResult.success("活动创建成功,等待审批"); + } + + /** + * 取消活动 + */ + @PreAuthorize("hasRole('CLUB_ADMIN')") + @PutMapping("/cancel") + public AjaxResult cancelActivity(@RequestParam Long actId) { + activityService.cancelActivity(actId); + return AjaxResult.success("活动已取消"); + } +} diff --git a/src/main/java/com/bruce/sams/controller/ams/ApprovalController.java b/src/main/java/com/bruce/sams/controller/ams/ApprovalController.java new file mode 100644 index 00000000..5bcd1969 --- /dev/null +++ b/src/main/java/com/bruce/sams/controller/ams/ApprovalController.java @@ -0,0 +1,41 @@ +package com.bruce.sams.controller.ams; + +import com.bruce.sams.common.utils.AjaxResult; +import com.bruce.sams.service.ApprovalService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * 活动审批控制器 + */ +@RestController +@RequestMapping("/api/admin/approval") +public class ApprovalController { + + @Autowired + private ApprovalService approvalService; + + /** + * 审批通过 + */ + @PreAuthorize("hasRole('CLUB_ADMIN') or hasRole('DEPARTMENT_ADMIN') or hasRole('COLLEGE_ADMIN')") + @PostMapping("/approve") + public AjaxResult approveActivity(@RequestParam Long apprId, @RequestParam Long approverId) { + approvalService.approveActivity(apprId, approverId); + return AjaxResult.success("审批已通过"); + } + + /** + * 审批拒绝 + */ + @PreAuthorize("hasRole('CLUB_ADMIN') or hasRole('DEPARTMENT_ADMIN') or hasRole('COLLEGE_ADMIN')") + @PostMapping("/reject") + public AjaxResult rejectActivity(@RequestParam Long apprId, @RequestParam String reason, @RequestParam Long approverId) { + approvalService.rejectActivity(apprId, reason, approverId); + return AjaxResult.success("审批已拒绝"); + } +} \ No newline at end of file diff --git a/src/main/java/com/bruce/sams/controller/sys/DocumentUploadController.java b/src/main/java/com/bruce/sams/controller/sys/DocumentUploadController.java new file mode 100644 index 00000000..1111d8e3 --- /dev/null +++ b/src/main/java/com/bruce/sams/controller/sys/DocumentUploadController.java @@ -0,0 +1,15 @@ +package com.bruce.sams.controller.sys; + +import com.bruce.sams.common.utils.FileUploadUtil; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +@RestController +@RequestMapping("/api/upload") +public class DocumentUploadController { + + @PostMapping("/document") + public String uploadDocument(@RequestParam("file") MultipartFile file) { + return FileUploadUtil.uploadFile(file, "documents/"); + } +} diff --git a/src/main/java/com/bruce/sams/controller/sys/UserController.java b/src/main/java/com/bruce/sams/controller/sys/UserController.java index d0e227fe..a13d29ba 100644 --- a/src/main/java/com/bruce/sams/controller/sys/UserController.java +++ b/src/main/java/com/bruce/sams/controller/sys/UserController.java @@ -1,10 +1,15 @@ package com.bruce.sams.controller.sys; +import com.bruce.sams.common.utils.FileUploadUtil; import com.bruce.sams.domain.sys.User; import com.bruce.sams.service.UserService; import com.bruce.sams.common.utils.AjaxResult; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.security.core.Authentication; + /** * 用户端 - 个人信息管理控制器 @@ -53,4 +58,32 @@ public class UserController { public AjaxResult getUserProfile(@PathVariable Long userId) { return AjaxResult.success(userService.getUserProfile(userId)); } + + /** + * 上传头像 + * @param file 头像信息 + * @return AjaxResult + */ + @PostMapping("/avatar") + public String uploadAvatar(@RequestParam("file") MultipartFile file) { + // 获取当前认证信息 + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication == null || !authentication.isAuthenticated()) { + throw new RuntimeException("未认证用户"); + } + + // 获取当前用户对象 + User userDetails = (User) authentication.getPrincipal(); + Long userId = userDetails.getUserId(); // 获取 userId + + // 上传文件 + String avatarUrl = FileUploadUtil.uploadFile(file, "avatars/"); + + // 更新用户头像 + userService.updateUserAvatar(userId, avatarUrl); + + return avatarUrl; + } + } diff --git a/src/main/java/com/bruce/sams/domain/ams/Activity.java b/src/main/java/com/bruce/sams/domain/ams/Activity.java new file mode 100644 index 00000000..8e8d2ae9 --- /dev/null +++ b/src/main/java/com/bruce/sams/domain/ams/Activity.java @@ -0,0 +1,188 @@ +package com.bruce.sams.domain.ams; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.math.BigDecimal; +import java.util.Date; + +import com.bruce.sams.domain.entity.ActivityStatus; +import com.bruce.sams.domain.entity.ActivityType; +import lombok.Data; + +/** + * 活动表 + * @TableName ams_activity + */ +@TableName(value ="ams_activity") +@Data +public class Activity { + /** + * 活动ID + */ + @TableId(type = IdType.AUTO) + private Long actId; + + /** + * 活动标题 + */ + private String title; + + /** + * 活动描述 + */ + private String description; + + /** + * 开始时间 + */ + private Date startTime; + + /** + * 结束时间 + */ + private Date endTime; + + /** + * 地点 + */ + private String location; + + /** + * 预算 + */ + private BigDecimal budget; + + /** + * 最大参与人数 + */ + private Integer maxParticipants; + + /** + * 创建者ID + */ + private Long creatorId; + + /** + * 所属院系ID + */ + private Long collegeId; + + /** + * 所属社团ID + */ + private Long clubId; + + /** + * 是否公开 + */ + private Object visibility; + + /** + * 活动状态 + */ + private ActivityStatus status; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 最后更新时间 + */ + private Date updatedAt; + + /** + * 活动类型(COLLEGE: 校级, DEPARTMENT: 院级, CLUB_INTERNAL: 社团内部, CLUB_EXTERNAL: 社团外部) + */ + private ActivityType activityType; + + /** + * 当前审批人ID + */ + private Long currentApproverId; + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (getClass() != that.getClass()) { + return false; + } + Activity other = (Activity) that; + return (this.getActId() == null ? other.getActId() == null : this.getActId().equals(other.getActId())) + && (this.getTitle() == null ? other.getTitle() == null : this.getTitle().equals(other.getTitle())) + && (this.getDescription() == null ? other.getDescription() == null : this.getDescription().equals(other.getDescription())) + && (this.getStartTime() == null ? other.getStartTime() == null : this.getStartTime().equals(other.getStartTime())) + && (this.getEndTime() == null ? other.getEndTime() == null : this.getEndTime().equals(other.getEndTime())) + && (this.getLocation() == null ? other.getLocation() == null : this.getLocation().equals(other.getLocation())) + && (this.getBudget() == null ? other.getBudget() == null : this.getBudget().equals(other.getBudget())) + && (this.getMaxParticipants() == null ? other.getMaxParticipants() == null : this.getMaxParticipants().equals(other.getMaxParticipants())) + && (this.getCreatorId() == null ? other.getCreatorId() == null : this.getCreatorId().equals(other.getCreatorId())) + && (this.getCollegeId() == null ? other.getCollegeId() == null : this.getCollegeId().equals(other.getCollegeId())) + && (this.getClubId() == null ? other.getClubId() == null : this.getClubId().equals(other.getClubId())) + && (this.getVisibility() == null ? other.getVisibility() == null : this.getVisibility().equals(other.getVisibility())) + && (this.getStatus() == null ? other.getStatus() == null : this.getStatus().equals(other.getStatus())) + && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt())) + && (this.getUpdatedAt() == null ? other.getUpdatedAt() == null : this.getUpdatedAt().equals(other.getUpdatedAt())) + && (this.getActivityType() == null ? other.getActivityType() == null : this.getActivityType().equals(other.getActivityType())) + && (this.getCurrentApproverId() == null ? other.getCurrentApproverId() == null : this.getCurrentApproverId().equals(other.getCurrentApproverId())); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getActId() == null) ? 0 : getActId().hashCode()); + result = prime * result + ((getTitle() == null) ? 0 : getTitle().hashCode()); + result = prime * result + ((getDescription() == null) ? 0 : getDescription().hashCode()); + result = prime * result + ((getStartTime() == null) ? 0 : getStartTime().hashCode()); + result = prime * result + ((getEndTime() == null) ? 0 : getEndTime().hashCode()); + result = prime * result + ((getLocation() == null) ? 0 : getLocation().hashCode()); + result = prime * result + ((getBudget() == null) ? 0 : getBudget().hashCode()); + result = prime * result + ((getMaxParticipants() == null) ? 0 : getMaxParticipants().hashCode()); + result = prime * result + ((getCreatorId() == null) ? 0 : getCreatorId().hashCode()); + result = prime * result + ((getCollegeId() == null) ? 0 : getCollegeId().hashCode()); + result = prime * result + ((getClubId() == null) ? 0 : getClubId().hashCode()); + result = prime * result + ((getVisibility() == null) ? 0 : getVisibility().hashCode()); + result = prime * result + ((getStatus() == null) ? 0 : getStatus().hashCode()); + result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode()); + result = prime * result + ((getUpdatedAt() == null) ? 0 : getUpdatedAt().hashCode()); + result = prime * result + ((getActivityType() == null) ? 0 : getActivityType().hashCode()); + result = prime * result + ((getCurrentApproverId() == null) ? 0 : getCurrentApproverId().hashCode()); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append(" ["); + sb.append("Hash = ").append(hashCode()); + sb.append(", actId=").append(actId); + sb.append(", title=").append(title); + sb.append(", description=").append(description); + sb.append(", startTime=").append(startTime); + sb.append(", endTime=").append(endTime); + sb.append(", location=").append(location); + sb.append(", budget=").append(budget); + sb.append(", maxParticipants=").append(maxParticipants); + sb.append(", creatorId=").append(creatorId); + sb.append(", collegeId=").append(collegeId); + sb.append(", clubId=").append(clubId); + sb.append(", visibility=").append(visibility); + sb.append(", status=").append(status); + sb.append(", createdAt=").append(createdAt); + sb.append(", updatedAt=").append(updatedAt); + sb.append(", activityType=").append(activityType); + sb.append(", currentApproverId=").append(currentApproverId); + sb.append("]"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/bruce/sams/domain/ams/Approval.java b/src/main/java/com/bruce/sams/domain/ams/Approval.java new file mode 100644 index 00000000..4565f7e8 --- /dev/null +++ b/src/main/java/com/bruce/sams/domain/ams/Approval.java @@ -0,0 +1,114 @@ +package com.bruce.sams.domain.ams; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.util.Date; + +import com.bruce.sams.domain.entity.ApprovalStatus; +import lombok.Data; + +/** + * 活动审批表 + * @TableName ams_approval + */ +@TableName(value ="ams_approval") +@Data +public class Approval { + /** + * 审批ID + */ + @TableId(type = IdType.AUTO) + private Long apprId; + + /** + * 活动ID + */ + private Long actId; + + /** + * 发起者ID + */ + private Long userId; + + /** + * 审批人ID + */ + private Long approverId; + + /** + * 审批状态 (0: 待审批, 1: 通过, 2: 拒绝) + */ + private Integer status; + + /** + * 拒绝原因(如果适用) + */ + private String reason; + + /** + * 审批状态 + */ + private ApprovalStatus approvedAt; + + /** + * 创建时间 + */ + private Date createdAt; + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (getClass() != that.getClass()) { + return false; + } + Approval other = (Approval) that; + return (this.getApprId() == null ? other.getApprId() == null : this.getApprId().equals(other.getApprId())) + && (this.getActId() == null ? other.getActId() == null : this.getActId().equals(other.getActId())) + && (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId())) + && (this.getApproverId() == null ? other.getApproverId() == null : this.getApproverId().equals(other.getApproverId())) + && (this.getStatus() == null ? other.getStatus() == null : this.getStatus().equals(other.getStatus())) + && (this.getReason() == null ? other.getReason() == null : this.getReason().equals(other.getReason())) + && (this.getApprovedAt() == null ? other.getApprovedAt() == null : this.getApprovedAt().equals(other.getApprovedAt())) + && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt())); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getApprId() == null) ? 0 : getApprId().hashCode()); + result = prime * result + ((getActId() == null) ? 0 : getActId().hashCode()); + result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode()); + result = prime * result + ((getApproverId() == null) ? 0 : getApproverId().hashCode()); + result = prime * result + ((getStatus() == null) ? 0 : getStatus().hashCode()); + result = prime * result + ((getReason() == null) ? 0 : getReason().hashCode()); + result = prime * result + ((getApprovedAt() == null) ? 0 : getApprovedAt().hashCode()); + result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode()); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append(" ["); + sb.append("Hash = ").append(hashCode()); + sb.append(", apprId=").append(apprId); + sb.append(", actId=").append(actId); + sb.append(", userId=").append(userId); + sb.append(", approverId=").append(approverId); + sb.append(", status=").append(status); + sb.append(", reason=").append(reason); + sb.append(", approvedAt=").append(approvedAt); + sb.append(", createdAt=").append(createdAt); + sb.append("]"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/bruce/sams/domain/ams/Comment.java b/src/main/java/com/bruce/sams/domain/ams/Comment.java new file mode 100644 index 00000000..4cf35f25 --- /dev/null +++ b/src/main/java/com/bruce/sams/domain/ams/Comment.java @@ -0,0 +1,96 @@ +package com.bruce.sams.domain.ams; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.util.Date; +import lombok.Data; + +/** + * 活动评论表 + * @TableName ams_comment + */ +@TableName(value ="ams_comment") +@Data +public class Comment { + /** + * 评论ID + */ + @TableId(type = IdType.AUTO) + private Long commentId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 活动ID + */ + private Long actId; + + /** + * 父评论ID(为空表示是顶级评论) + */ + private Long parentCommentId; + + /** + * 评论内容 + */ + private String content; + + /** + * 评论时间 + */ + private Date createdAt; + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (getClass() != that.getClass()) { + return false; + } + Comment other = (Comment) that; + return (this.getCommentId() == null ? other.getCommentId() == null : this.getCommentId().equals(other.getCommentId())) + && (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId())) + && (this.getActId() == null ? other.getActId() == null : this.getActId().equals(other.getActId())) + && (this.getParentCommentId() == null ? other.getParentCommentId() == null : this.getParentCommentId().equals(other.getParentCommentId())) + && (this.getContent() == null ? other.getContent() == null : this.getContent().equals(other.getContent())) + && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt())); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getCommentId() == null) ? 0 : getCommentId().hashCode()); + result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode()); + result = prime * result + ((getActId() == null) ? 0 : getActId().hashCode()); + result = prime * result + ((getParentCommentId() == null) ? 0 : getParentCommentId().hashCode()); + result = prime * result + ((getContent() == null) ? 0 : getContent().hashCode()); + result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode()); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append(" ["); + sb.append("Hash = ").append(hashCode()); + sb.append(", commentId=").append(commentId); + sb.append(", userId=").append(userId); + sb.append(", actId=").append(actId); + sb.append(", parentCommentId=").append(parentCommentId); + sb.append(", content=").append(content); + sb.append(", createdAt=").append(createdAt); + sb.append("]"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/bruce/sams/domain/ams/Reaction.java b/src/main/java/com/bruce/sams/domain/ams/Reaction.java new file mode 100644 index 00000000..d22a685c --- /dev/null +++ b/src/main/java/com/bruce/sams/domain/ams/Reaction.java @@ -0,0 +1,88 @@ +package com.bruce.sams.domain.ams; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.util.Date; +import lombok.Data; + +/** + * 活动点赞/点踩表 + * @TableName ams_reaction + */ +@TableName(value ="ams_reaction") +@Data +public class Reaction { + /** + * 点赞/点踩ID + */ + @TableId(type = IdType.AUTO) + private Long reactionId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 活动ID + */ + private Long actId; + + /** + * 反应类型(like: 点赞, dislike: 点踩) + */ + private Object reactionType; + + /** + * 反应时间 + */ + private Date createdAt; + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (getClass() != that.getClass()) { + return false; + } + Reaction other = (Reaction) that; + return (this.getReactionId() == null ? other.getReactionId() == null : this.getReactionId().equals(other.getReactionId())) + && (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId())) + && (this.getActId() == null ? other.getActId() == null : this.getActId().equals(other.getActId())) + && (this.getReactionType() == null ? other.getReactionType() == null : this.getReactionType().equals(other.getReactionType())) + && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt())); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getReactionId() == null) ? 0 : getReactionId().hashCode()); + result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode()); + result = prime * result + ((getActId() == null) ? 0 : getActId().hashCode()); + result = prime * result + ((getReactionType() == null) ? 0 : getReactionType().hashCode()); + result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode()); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append(" ["); + sb.append("Hash = ").append(hashCode()); + sb.append(", reactionId=").append(reactionId); + sb.append(", userId=").append(userId); + sb.append(", actId=").append(actId); + sb.append(", reactionType=").append(reactionType); + sb.append(", createdAt=").append(createdAt); + sb.append("]"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/bruce/sams/domain/ams/Registration.java b/src/main/java/com/bruce/sams/domain/ams/Registration.java new file mode 100644 index 00000000..e4adde1f --- /dev/null +++ b/src/main/java/com/bruce/sams/domain/ams/Registration.java @@ -0,0 +1,104 @@ +package com.bruce.sams.domain.ams; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.util.Date; +import lombok.Data; + +/** + * 活动报名表 + * @TableName ams_registration + */ +@TableName(value ="ams_registration") +@Data +public class Registration { + /** + * 报名ID + */ + @TableId(type = IdType.AUTO) + private Long regId; + + /** + * 活动ID + */ + private Long actId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 角色(organizer: 组织者, participant: 参与者) + */ + private Object role; + + /** + * 报名状态 + */ + private Object status; + + /** + * 报名时间 + */ + private Date registerTime; + + /** + * 参与时间 + */ + private Date attendTime; + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (getClass() != that.getClass()) { + return false; + } + Registration other = (Registration) that; + return (this.getRegId() == null ? other.getRegId() == null : this.getRegId().equals(other.getRegId())) + && (this.getActId() == null ? other.getActId() == null : this.getActId().equals(other.getActId())) + && (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId())) + && (this.getRole() == null ? other.getRole() == null : this.getRole().equals(other.getRole())) + && (this.getStatus() == null ? other.getStatus() == null : this.getStatus().equals(other.getStatus())) + && (this.getRegisterTime() == null ? other.getRegisterTime() == null : this.getRegisterTime().equals(other.getRegisterTime())) + && (this.getAttendTime() == null ? other.getAttendTime() == null : this.getAttendTime().equals(other.getAttendTime())); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getRegId() == null) ? 0 : getRegId().hashCode()); + result = prime * result + ((getActId() == null) ? 0 : getActId().hashCode()); + result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode()); + result = prime * result + ((getRole() == null) ? 0 : getRole().hashCode()); + result = prime * result + ((getStatus() == null) ? 0 : getStatus().hashCode()); + result = prime * result + ((getRegisterTime() == null) ? 0 : getRegisterTime().hashCode()); + result = prime * result + ((getAttendTime() == null) ? 0 : getAttendTime().hashCode()); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append(" ["); + sb.append("Hash = ").append(hashCode()); + sb.append(", regId=").append(regId); + sb.append(", actId=").append(actId); + sb.append(", userId=").append(userId); + sb.append(", role=").append(role); + sb.append(", status=").append(status); + sb.append(", registerTime=").append(registerTime); + sb.append(", attendTime=").append(attendTime); + sb.append("]"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/bruce/sams/domain/entity/ActivityStatus.java b/src/main/java/com/bruce/sams/domain/entity/ActivityStatus.java new file mode 100644 index 00000000..ce63dcf2 --- /dev/null +++ b/src/main/java/com/bruce/sams/domain/entity/ActivityStatus.java @@ -0,0 +1,16 @@ +package com.bruce.sams.domain.entity; + +/** + * 活动状态枚举 + * 该枚举用于表示活动的不同状态 + */ +public enum ActivityStatus { + DRAFT, // 草稿(未提交) + PENDING_CLUB, // 待社团管理员审批(适用于社团外部活动) + PENDING_DEPARTMENT,// 待院级管理员审批 + PENDING_COLLEGE, // 待校级管理员审批 + APPROVED, // 已批准 + ONGOING, // 活动进行中 + COMPLETED, // 活动已完成 + CANCELLED // 活动已取消 +} diff --git a/src/main/java/com/bruce/sams/domain/entity/ActivityType.java b/src/main/java/com/bruce/sams/domain/entity/ActivityType.java new file mode 100644 index 00000000..cdcace5b --- /dev/null +++ b/src/main/java/com/bruce/sams/domain/entity/ActivityType.java @@ -0,0 +1,11 @@ +package com.bruce.sams.domain.entity; + +/** + * 活动类型枚举 + */ +public enum ActivityType { + COLLEGE, // 校级活动 + DEPARTMENT, // 院级活动 + CLUB_INTERNAL, // 社团内部活动 + CLUB_EXTERNAL // 社团外部活动 +} diff --git a/src/main/java/com/bruce/sams/domain/entity/ApprovalStatus.java b/src/main/java/com/bruce/sams/domain/entity/ApprovalStatus.java new file mode 100644 index 00000000..285b8874 --- /dev/null +++ b/src/main/java/com/bruce/sams/domain/entity/ApprovalStatus.java @@ -0,0 +1,10 @@ +package com.bruce.sams.domain.entity; + +/** + * 活动审批状态枚举 + */ +public enum ApprovalStatus { + APPROVED, // 审批通过 + REJECTED, // 审批拒绝 + PENDING // 待审批 +} \ No newline at end of file diff --git a/src/main/java/com/bruce/sams/domain/sys/User.java b/src/main/java/com/bruce/sams/domain/sys/User.java index 21ebaf6f..416260cf 100644 --- a/src/main/java/com/bruce/sams/domain/sys/User.java +++ b/src/main/java/com/bruce/sams/domain/sys/User.java @@ -1,10 +1,13 @@ package com.bruce.sams.domain.sys; import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.List; /** * 系统用户表 @@ -12,7 +15,7 @@ import lombok.Data; */ @TableName(value ="sys_user") @Data -public class User { +public class User implements UserDetails { /** * 用户ID */ @@ -27,7 +30,8 @@ public class User { /** * 真实姓名 */ - private String userName; + + private String username; /** * 用户密码 @@ -59,6 +63,15 @@ public class User { */ private Object status; + // 不映射到数据库 + private List authorities; + + public User(String username, String password, List authorities) { + this.username = username; + this.password = password; + this.authorities = authorities; + } + @Override public boolean equals(Object that) { if (this == that) { @@ -73,7 +86,7 @@ public class User { User other = (User) that; return (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId())) && (this.getNickName() == null ? other.getNickName() == null : this.getNickName().equals(other.getNickName())) - && (this.getUserName() == null ? other.getUserName() == null : this.getUserName().equals(other.getUserName())) + && (this.getUsername() == null ? other.getUsername() == null : this.getUsername().equals(other.getUsername())) && (this.getPassword() == null ? other.getPassword() == null : this.getPassword().equals(other.getPassword())) && (this.getSchoolId() == null ? other.getSchoolId() == null : this.getSchoolId().equals(other.getSchoolId())) && (this.getCollegeId() == null ? other.getCollegeId() == null : this.getCollegeId().equals(other.getCollegeId())) @@ -88,7 +101,7 @@ public class User { int result = 1; result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode()); result = prime * result + ((getNickName() == null) ? 0 : getNickName().hashCode()); - result = prime * result + ((getUserName() == null) ? 0 : getUserName().hashCode()); + result = prime * result + ((getUsername() == null) ? 0 : getUsername().hashCode()); result = prime * result + ((getPassword() == null) ? 0 : getPassword().hashCode()); result = prime * result + ((getSchoolId() == null) ? 0 : getSchoolId().hashCode()); result = prime * result + ((getCollegeId() == null) ? 0 : getCollegeId().hashCode()); @@ -100,20 +113,20 @@ public class User { @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName()); - sb.append(" ["); - sb.append("Hash = ").append(hashCode()); - sb.append(", userId=").append(userId); - sb.append(", nickName=").append(nickName); - sb.append(", userName=").append(userName); - sb.append(", password=").append(password); - sb.append(", schoolId=").append(schoolId); - sb.append(", collegeId=").append(collegeId); - sb.append(", email=").append(email); - sb.append(", avatar=").append(avatar); - sb.append(", status=").append(status); - sb.append("]"); - return sb.toString(); + return getClass().getSimpleName() + + " [" + + "Hash = " + hashCode() + + ", userId=" + userId + + ", nickName=" + nickName + + ", userName=" + username + + ", password=" + password + + ", schoolId=" + schoolId + + ", collegeId=" + collegeId + + ", email=" + email + + ", avatar=" + avatar + + ", status=" + status + + "]"; } + + } \ No newline at end of file diff --git a/src/main/java/com/bruce/sams/mapper/ActivityMapper.java b/src/main/java/com/bruce/sams/mapper/ActivityMapper.java new file mode 100644 index 00000000..40856f60 --- /dev/null +++ b/src/main/java/com/bruce/sams/mapper/ActivityMapper.java @@ -0,0 +1,18 @@ +package com.bruce.sams.mapper; + +import com.bruce.sams.domain.ams.Activity; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** +* @author bruce +* @description 针对表【ams_activity(活动表)】的数据库操作Mapper +* @createDate 2025-02-20 16:01:31 +* @Entity com.bruce.sams.domain.ams.Activity +*/ +public interface ActivityMapper extends BaseMapper { + +} + + + + diff --git a/src/main/java/com/bruce/sams/mapper/ApprovalMapper.java b/src/main/java/com/bruce/sams/mapper/ApprovalMapper.java new file mode 100644 index 00000000..4145e390 --- /dev/null +++ b/src/main/java/com/bruce/sams/mapper/ApprovalMapper.java @@ -0,0 +1,20 @@ +package com.bruce.sams.mapper; + +import com.bruce.sams.domain.ams.Approval; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** +* @author bruce +* @description 针对表【ams_approval(活动审批表)】的数据库操作Mapper +* @createDate 2025-02-20 15:46:26 +* @Entity com.bruce.sams.domain.ams.Approval +*/ +@Mapper +public interface ApprovalMapper extends BaseMapper { + +} + + + + diff --git a/src/main/java/com/bruce/sams/mapper/CommentMapper.java b/src/main/java/com/bruce/sams/mapper/CommentMapper.java new file mode 100644 index 00000000..a9139ac7 --- /dev/null +++ b/src/main/java/com/bruce/sams/mapper/CommentMapper.java @@ -0,0 +1,20 @@ +package com.bruce.sams.mapper; + +import com.bruce.sams.domain.ams.Comment; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** +* @author bruce +* @description 针对表【ams_comment(活动评论表)】的数据库操作Mapper +* @createDate 2025-02-20 15:08:30 +* @Entity com.bruce.sams.domain.ams.Comment +*/ +@Mapper +public interface CommentMapper extends BaseMapper { + +} + + + + diff --git a/src/main/java/com/bruce/sams/mapper/ReactionMapper.java b/src/main/java/com/bruce/sams/mapper/ReactionMapper.java new file mode 100644 index 00000000..4122eaa0 --- /dev/null +++ b/src/main/java/com/bruce/sams/mapper/ReactionMapper.java @@ -0,0 +1,20 @@ +package com.bruce.sams.mapper; + +import com.bruce.sams.domain.ams.Reaction; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** +* @author bruce +* @description 针对表【ams_reaction(活动点赞/点踩表)】的数据库操作Mapper +* @createDate 2025-02-20 15:08:43 +* @Entity com.bruce.sams.domain.ams.Reaction +*/ +@Mapper +public interface ReactionMapper extends BaseMapper { + +} + + + + diff --git a/src/main/java/com/bruce/sams/mapper/RegistrationMapper.java b/src/main/java/com/bruce/sams/mapper/RegistrationMapper.java new file mode 100644 index 00000000..86f63b75 --- /dev/null +++ b/src/main/java/com/bruce/sams/mapper/RegistrationMapper.java @@ -0,0 +1,20 @@ +package com.bruce.sams.mapper; + +import com.bruce.sams.domain.ams.Registration; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** +* @author bruce +* @description 针对表【ams_registration(活动报名表)】的数据库操作Mapper +* @createDate 2025-02-20 15:08:53 +* @Entity com.bruce.sams.domain.ams.Registration +*/ +@Mapper +public interface RegistrationMapper extends BaseMapper { + +} + + + + diff --git a/src/main/java/com/bruce/sams/mapper/UserMapper.java b/src/main/java/com/bruce/sams/mapper/UserMapper.java index bfcdb8ef..d2f8a2c3 100644 --- a/src/main/java/com/bruce/sams/mapper/UserMapper.java +++ b/src/main/java/com/bruce/sams/mapper/UserMapper.java @@ -40,6 +40,9 @@ public interface UserMapper extends BaseMapper { @Select("SELECT * FROM sys_user WHERE user_id = #{userId}") User getUserById(@Param("userId") Long userId); + + @Update("UPDATE sys_user SET avatar = #{avatarUrl} WHERE user_id = #{userId}") + void updateAvatar(Long userId, String avatarUrl); } diff --git a/src/main/java/com/bruce/sams/service/ActivityService.java b/src/main/java/com/bruce/sams/service/ActivityService.java new file mode 100644 index 00000000..0cd7e1a4 --- /dev/null +++ b/src/main/java/com/bruce/sams/service/ActivityService.java @@ -0,0 +1,36 @@ +package com.bruce.sams.service; + +import com.bruce.sams.domain.ams.Activity; +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* @author bruce +* @description 针对表【ams_activity(活动表)】的数据库操作Service +* @createDate 2025-02-20 15:46:18 +*/ +public interface ActivityService extends IService { + + /** + * 创建活动 + */ + void createActivity(Activity activity); + + /** + * 更新活动信息 + * @param activity 活动对象 + */ + void updateActivity(Activity activity); + + /** + * 取消活动 + * @param actId 活动ID + */ + void cancelActivity(Long actId); + + /** + * 获取活动详情 + * @param actId 活动ID + * @return 活动对象 + */ + Activity getActivityById(Long actId); +} diff --git a/src/main/java/com/bruce/sams/service/ApprovalService.java b/src/main/java/com/bruce/sams/service/ApprovalService.java new file mode 100644 index 00000000..b52a7928 --- /dev/null +++ b/src/main/java/com/bruce/sams/service/ApprovalService.java @@ -0,0 +1,21 @@ +package com.bruce.sams.service; + +import com.bruce.sams.domain.ams.Approval; +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* @author bruce +* @description 针对表【ams_approval(活动审批表)】的数据库操作Service +* @createDate 2025-02-20 15:46:26 +*/ +public interface ApprovalService extends IService { + /** + * 审批活动(通过) + */ + void approveActivity(Long apprId, Long approverId); + + /** + * 拒绝活动 + */ + void rejectActivity(Long apprId, String reason, Long approverId); +} diff --git a/src/main/java/com/bruce/sams/service/CommentService.java b/src/main/java/com/bruce/sams/service/CommentService.java new file mode 100644 index 00000000..74600dfe --- /dev/null +++ b/src/main/java/com/bruce/sams/service/CommentService.java @@ -0,0 +1,13 @@ +package com.bruce.sams.service; + +import com.bruce.sams.domain.ams.Comment; +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* @author bruce +* @description 针对表【ams_comment(活动评论表)】的数据库操作Service +* @createDate 2025-02-20 15:08:30 +*/ +public interface CommentService extends IService { + +} diff --git a/src/main/java/com/bruce/sams/service/ReactionService.java b/src/main/java/com/bruce/sams/service/ReactionService.java new file mode 100644 index 00000000..2f583856 --- /dev/null +++ b/src/main/java/com/bruce/sams/service/ReactionService.java @@ -0,0 +1,13 @@ +package com.bruce.sams.service; + +import com.bruce.sams.domain.ams.Reaction; +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* @author bruce +* @description 针对表【ams_reaction(活动点赞/点踩表)】的数据库操作Service +* @createDate 2025-02-20 15:08:43 +*/ +public interface ReactionService extends IService { + +} diff --git a/src/main/java/com/bruce/sams/service/RegistrationService.java b/src/main/java/com/bruce/sams/service/RegistrationService.java new file mode 100644 index 00000000..d29c6288 --- /dev/null +++ b/src/main/java/com/bruce/sams/service/RegistrationService.java @@ -0,0 +1,13 @@ +package com.bruce.sams.service; + +import com.bruce.sams.domain.ams.Registration; +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* @author bruce +* @description 针对表【ams_registration(活动报名表)】的数据库操作Service +* @createDate 2025-02-20 15:08:53 +*/ +public interface RegistrationService extends IService { + +} diff --git a/src/main/java/com/bruce/sams/service/UserService.java b/src/main/java/com/bruce/sams/service/UserService.java index 5d2c390c..c982c702 100644 --- a/src/main/java/com/bruce/sams/service/UserService.java +++ b/src/main/java/com/bruce/sams/service/UserService.java @@ -82,4 +82,11 @@ public interface UserService { */ List getRolesByUserId(Long userId); + /** + * 更新用户头像 + * @param userId 用户ID + * @param avatarUrl 头像存储路径 + */ + public void updateUserAvatar(Long userId, String avatarUrl); + } diff --git a/src/main/java/com/bruce/sams/service/impl/ActivityServiceImpl.java b/src/main/java/com/bruce/sams/service/impl/ActivityServiceImpl.java new file mode 100644 index 00000000..f995bfd6 --- /dev/null +++ b/src/main/java/com/bruce/sams/service/impl/ActivityServiceImpl.java @@ -0,0 +1,70 @@ +package com.bruce.sams.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.bruce.sams.domain.ams.Activity; +import com.bruce.sams.domain.entity.ActivityStatus; +import com.bruce.sams.service.ActivityService; +import com.bruce.sams.mapper.ActivityMapper; +import org.springframework.stereotype.Service; + +/** + * 活动管理服务实现类 + * 负责活动的创建、修改、取消,以及初始化审批流程 + */ +@Service +public class ActivityServiceImpl extends ServiceImpl implements ActivityService { + + /** + * 创建活动 + * @param activity 活动对象 + */ + @Override + public void createActivity(Activity activity) { + // 初始化活动审批状态 + switch (activity.getActivityType()) { + case CLUB_INTERNAL, CLUB_EXTERNAL: + activity.setStatus(ActivityStatus.PENDING_CLUB); + break; + case DEPARTMENT: + activity.setStatus(ActivityStatus.PENDING_DEPARTMENT); + break; + case COLLEGE: + activity.setStatus(ActivityStatus.PENDING_COLLEGE); + break; + default: + activity.setStatus(ActivityStatus.DRAFT); + break; + } + this.save(activity); + } + + /** + * 更新活动信息 + * @param activity 活动对象 + */ + @Override + public void updateActivity(Activity activity) { + this.updateById(activity); + } + + /** + * 取消活动 + * @param actId 活动ID + */ + @Override + public void cancelActivity(Long actId) { + Activity activity = this.getById(actId); + activity.setStatus(ActivityStatus.CANCELLED); + this.updateById(activity); + } + + /** + * 获取活动详情 + * @param actId 活动ID + * @return 活动对象 + */ + @Override + public Activity getActivityById(Long actId) { + return this.getById(actId); + } +} diff --git a/src/main/java/com/bruce/sams/service/impl/ApprovalServiceImpl.java b/src/main/java/com/bruce/sams/service/impl/ApprovalServiceImpl.java new file mode 100644 index 00000000..f24b493a --- /dev/null +++ b/src/main/java/com/bruce/sams/service/impl/ApprovalServiceImpl.java @@ -0,0 +1,102 @@ +package com.bruce.sams.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.bruce.sams.domain.ams.Activity; +import com.bruce.sams.domain.ams.Approval; +import com.bruce.sams.domain.entity.ActivityStatus; +import com.bruce.sams.domain.entity.ActivityType; +import com.bruce.sams.domain.entity.ApprovalStatus; +import com.bruce.sams.service.ActivityService; +import com.bruce.sams.service.ApprovalService; +import com.bruce.sams.mapper.ApprovalMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 活动审批服务实现类 + * 负责活动的分级审批 + */ +@Service +public class ApprovalServiceImpl extends ServiceImpl implements ApprovalService { + + + @Autowired + private ActivityService activityService; + + /** + * 审批通过 + * @param apprId 审批ID + * @param approverId 审批人ID + */ + @Override + public void approveActivity(Long apprId, Long approverId) { + Approval approval = this.getById(apprId); + Activity activity = activityService.getActivityById(approval.getActId()); + + // 记录审批人 + approval.setApproverId(approverId); + this.updateById(approval); + + // 确定下一级审批流转 + switch (activity.getStatus()) { + case PENDING_CLUB: + if (activity.getActivityType() == ActivityType.CLUB_INTERNAL) { + activity.setStatus(ActivityStatus.APPROVED); + activity.setCurrentApproverId(null); + } else { + activity.setStatus(ActivityStatus.PENDING_DEPARTMENT); + activity.setCurrentApproverId(getNextApprover("DEPARTMENT_ADMIN")); + } + break; + case PENDING_DEPARTMENT: + activity.setStatus(ActivityStatus.PENDING_COLLEGE); + activity.setCurrentApproverId(getNextApprover("COLLEGE_ADMIN")); + break; + case PENDING_COLLEGE: + activity.setStatus(ActivityStatus.APPROVED); + activity.setCurrentApproverId(null); + break; + default: + throw new RuntimeException("无效审批状态"); + } + + activityService.updateActivity(activity); + } + + /** + * 拒绝审批 + * @param apprId 审批ID + * @param reason 拒绝理由 + * @param approverId 审批人ID + */ + @Override + public void rejectActivity(Long apprId, String reason, Long approverId) { + Approval approval = this.getById(apprId); + Activity activity = activityService.getActivityById(approval.getActId()); + + activity.setStatus(ActivityStatus.CANCELLED); + activity.setCurrentApproverId(null); + approval.setApprovedAt(ApprovalStatus.REJECTED); + approval.setReason(reason); + approval.setApproverId(approverId); + + this.updateById(approval); + activityService.updateActivity(activity); + } + + /** + * 获取下一级审批人 + * @param role 角色名称 + * @return 下一级审批人ID + */ + private Long getNextApprover(String role) { + // 这里可查询 `sys_user_role` 表以获取指定角色的审批人 + if ("DEPARTMENT_ADMIN".equals(role)) { + return 1L; + } else if ("COLLEGE_ADMIN".equals(role)) { + return 2L; + } + return null; + } +} + diff --git a/src/main/java/com/bruce/sams/service/impl/ClubUserServiceImpl.java b/src/main/java/com/bruce/sams/service/impl/ClubUserServiceImpl.java index 3cfaec13..33d40464 100644 --- a/src/main/java/com/bruce/sams/service/impl/ClubUserServiceImpl.java +++ b/src/main/java/com/bruce/sams/service/impl/ClubUserServiceImpl.java @@ -19,7 +19,7 @@ import java.util.List; public class ClubUserServiceImpl extends ServiceImpl implements ClubUserService { /** - * 添加社团成员(社团管理员审批) + * 添加社团成员 * * @param clubId 社团ID * @param userId 用户ID @@ -36,7 +36,7 @@ public class ClubUserServiceImpl extends ServiceImpl i } /** - * 移除社团成员(社团管理员 / 校级管理员) + * 移除社团成员 * * @param clubId 社团ID * @param userId 用户ID @@ -49,7 +49,7 @@ public class ClubUserServiceImpl extends ServiceImpl i } /** - * 获取社团成员列表(根据权限) + * 获取社团成员列表 * * @param clubId 社团ID * @return 成员列表 diff --git a/src/main/java/com/bruce/sams/service/impl/CommentServiceImpl.java b/src/main/java/com/bruce/sams/service/impl/CommentServiceImpl.java new file mode 100644 index 00000000..cdf30c97 --- /dev/null +++ b/src/main/java/com/bruce/sams/service/impl/CommentServiceImpl.java @@ -0,0 +1,22 @@ +package com.bruce.sams.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.bruce.sams.domain.ams.Comment; +import com.bruce.sams.service.CommentService; +import com.bruce.sams.mapper.CommentMapper; +import org.springframework.stereotype.Service; + +/** +* @author bruce +* @description 针对表【ams_comment(活动评论表)】的数据库操作Service实现 +* @createDate 2025-02-20 15:08:30 +*/ +@Service +public class CommentServiceImpl extends ServiceImpl + implements CommentService{ + +} + + + + diff --git a/src/main/java/com/bruce/sams/service/impl/CustomUserDetailsService.java b/src/main/java/com/bruce/sams/service/impl/CustomUserDetailsService.java index d6a5d5f1..128e3af3 100644 --- a/src/main/java/com/bruce/sams/service/impl/CustomUserDetailsService.java +++ b/src/main/java/com/bruce/sams/service/impl/CustomUserDetailsService.java @@ -37,6 +37,6 @@ public class CustomUserDetailsService implements UserDetailsService { .collect(Collectors.toList()); // 返回 LoginUser,符合 Spring Security 的 UserDetails - return new LoginUser(user.getUserId(), user.getUserName(), user.getPassword(), authorities); + return new LoginUser(user.getUserId(), user.getUsername(), user.getPassword(), authorities); } } \ No newline at end of file diff --git a/src/main/java/com/bruce/sams/service/impl/ReactionServiceImpl.java b/src/main/java/com/bruce/sams/service/impl/ReactionServiceImpl.java new file mode 100644 index 00000000..23173a1e --- /dev/null +++ b/src/main/java/com/bruce/sams/service/impl/ReactionServiceImpl.java @@ -0,0 +1,22 @@ +package com.bruce.sams.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.bruce.sams.domain.ams.Reaction; +import com.bruce.sams.service.ReactionService; +import com.bruce.sams.mapper.ReactionMapper; +import org.springframework.stereotype.Service; + +/** +* @author bruce +* @description 针对表【ams_reaction(活动点赞/点踩表)】的数据库操作Service实现 +* @createDate 2025-02-20 15:08:43 +*/ +@Service +public class ReactionServiceImpl extends ServiceImpl + implements ReactionService{ + +} + + + + diff --git a/src/main/java/com/bruce/sams/service/impl/RegistrationServiceImpl.java b/src/main/java/com/bruce/sams/service/impl/RegistrationServiceImpl.java new file mode 100644 index 00000000..b370c333 --- /dev/null +++ b/src/main/java/com/bruce/sams/service/impl/RegistrationServiceImpl.java @@ -0,0 +1,22 @@ +package com.bruce.sams.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.bruce.sams.domain.ams.Registration; +import com.bruce.sams.service.RegistrationService; +import com.bruce.sams.mapper.RegistrationMapper; +import org.springframework.stereotype.Service; + +/** +* @author bruce +* @description 针对表【ams_registration(活动报名表)】的数据库操作Service实现 +* @createDate 2025-02-20 15:08:53 +*/ +@Service +public class RegistrationServiceImpl extends ServiceImpl + implements RegistrationService{ + +} + + + + diff --git a/src/main/java/com/bruce/sams/service/impl/UserServiceImpl.java b/src/main/java/com/bruce/sams/service/impl/UserServiceImpl.java index 7d3cd5e4..8753aa6a 100644 --- a/src/main/java/com/bruce/sams/service/impl/UserServiceImpl.java +++ b/src/main/java/com/bruce/sams/service/impl/UserServiceImpl.java @@ -1,13 +1,11 @@ package com.bruce.sams.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bruce.sams.domain.sys.Role; import com.bruce.sams.domain.sys.User; import com.bruce.sams.common.exception.PasswordIncorrectException; import com.bruce.sams.common.exception.UserNotFoundException; -import com.bruce.sams.domain.sys.UserRole; import com.bruce.sams.mapper.RoleMapper; import com.bruce.sams.mapper.UserMapper; import com.bruce.sams.mapper.UserRoleMapper; @@ -17,7 +15,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; -import java.util.stream.Collectors; @Service public class UserServiceImpl extends ServiceImpl @@ -60,7 +57,7 @@ public class UserServiceImpl extends ServiceImpl public List listUsers(String keyword) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); if (keyword != null && !keyword.isEmpty()) { - queryWrapper.like(User::getUserName, keyword) + queryWrapper.like(User::getUsername, keyword) .or().like(User::getSchoolId, keyword) .or().like(User::getEmail, keyword); } @@ -197,4 +194,14 @@ public class UserServiceImpl extends ServiceImpl // 3. 根据 role_id 查询 sys_role 表 return roleMapper.selectRolesByIds(roleIds); } + + /** + * 更新用户头像 + * @param userId 用户ID + * @param avatarUrl 头像存储路径 + */ + public void updateUserAvatar(Long userId, String avatarUrl) { + userMapper.updateAvatar(userId, avatarUrl); + } + } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b687694f..ca838771 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,9 +1,16 @@ spring: application: name: SAMS - datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/SAMS username: root - password: admin123 \ No newline at end of file + password: admin123 + servlet: + multipart: + enabled: true + max-file-size: 5MB # 限制上传文件大小 + max-request-size: 10MB + +file: + upload-dir: uploads/ \ No newline at end of file diff --git a/src/main/resources/mapper/ActivityMapper.xml b/src/main/resources/mapper/ActivityMapper.xml new file mode 100644 index 00000000..30ec0538 --- /dev/null +++ b/src/main/resources/mapper/ActivityMapper.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + act_id,title,description,start_time,end_time,location, + budget,max_participants,creator_id,college_id,club_id, + visibility,status,created_at,updated_at,activity_type, + current_approver_id + + diff --git a/src/main/resources/mapper/ApprovalMapper.xml b/src/main/resources/mapper/ApprovalMapper.xml new file mode 100644 index 00000000..646aafed --- /dev/null +++ b/src/main/resources/mapper/ApprovalMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + appr_id,act_id,user_id,approver_id,status,reason, + approved_at,created_at + + diff --git a/src/main/resources/mapper/CommentMapper.xml b/src/main/resources/mapper/CommentMapper.xml new file mode 100644 index 00000000..f7094c72 --- /dev/null +++ b/src/main/resources/mapper/CommentMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + comment_id,user_id,act_id,parent_comment_id,content,created_at + + diff --git a/src/main/resources/mapper/ReactionMapper.xml b/src/main/resources/mapper/ReactionMapper.xml new file mode 100644 index 00000000..19c3e1a0 --- /dev/null +++ b/src/main/resources/mapper/ReactionMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + reaction_id,user_id,act_id,reaction_type,created_at + + diff --git a/src/main/resources/mapper/RegistrationMapper.xml b/src/main/resources/mapper/RegistrationMapper.xml new file mode 100644 index 00000000..16768d10 --- /dev/null +++ b/src/main/resources/mapper/RegistrationMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + reg_id,act_id,user_id,role,status,register_time, + attend_time + +