diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/bo/StglBatchApprovalBo.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/bo/StglBatchApprovalBo.java new file mode 100644 index 00000000..86473f91 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/bo/StglBatchApprovalBo.java @@ -0,0 +1,40 @@ +package org.dromara.stgl.domain.bo; + +import lombok.Data; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Size; + +import java.util.List; + +/** + * 社团活动批量审核请求对象 + * + * @author ruoyi + * @date 2025-01-31 + */ +@Data +public class StglBatchApprovalBo { + + /** + * 报名ID数组 + */ + @NotEmpty(message = "审核ID列表不能为空") + private List ids; + + /** + * 审核状态 1-通过 2-驳回 + */ + @NotNull(message = "审核状态不能为空") + @Min(value = 1, message = "审核状态值无效") + @Max(value = 2, message = "审核状态值无效") + private Integer approvalStatus; + + /** + * 审核意见 + */ + @Size(max = 500, message = "审核意见不能超过500个字符") + private String approvalRemark; +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/utils/AdvisorRoleAssigner.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/utils/AdvisorRoleAssigner.java new file mode 100644 index 00000000..9191aa4b --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/utils/AdvisorRoleAssigner.java @@ -0,0 +1,189 @@ +package org.dromara.stgl.utils; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.mapper.SysUserRoleMapper; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +/** + * 指导老师角色分配工具类 + * 用于在社团、志愿者队伍、活动等模块中自动分配指导老师角色 + * + * @author Cursor AI + * @date 2025-01-03 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class AdvisorRoleAssigner { + + private final SysUserRoleMapper sysUserRoleMapper; + + /** + * 指导老师角色ID + */ + private static final Long ADVISOR_ROLE_ID = 1959880215953952769L; + + /** + * 为指导老师分配角色 + * + * @param advisorUserIds 指导老师用户ID列表 + */ + @Transactional(rollbackFor = Exception.class) + public void assignAdvisorRole(List advisorUserIds) { + if (advisorUserIds == null || advisorUserIds.isEmpty()) { + log.info("没有指导老师需要分配角色"); + return; + } + + List userRoles = new ArrayList<>(); + for (Long userId : advisorUserIds) { + if (userId != null) { + // 检查用户是否已有该角色 + if (!hasUserRole(userId, ADVISOR_ROLE_ID)) { + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(userId); + userRole.setRoleId(ADVISOR_ROLE_ID); + userRoles.add(userRole); + } else { + log.debug("用户 {} 已有指导老师角色,跳过分配", userId); + } + } + } + + if (!userRoles.isEmpty()) { + try { + // 批量插入用户角色关系 + boolean success = sysUserRoleMapper.insertBatch(userRoles); + if (success) { + log.info("成功为 {} 个指导老师分配角色,角色ID: {}", userRoles.size(), ADVISOR_ROLE_ID); + } else { + log.error("批量分配指导老师角色失败"); + } + } catch (Exception e) { + log.error("分配指导老师角色时发生异常", e); + throw new RuntimeException("分配指导老师角色失败", e); + } + } + } + + /** + * 为单个指导老师分配角色 + * + * @param advisorUserId 指导老师用户ID + */ + @Transactional(rollbackFor = Exception.class) + public void assignAdvisorRole(Long advisorUserId) { + if (advisorUserId == null) { + log.warn("指导老师用户ID为空,跳过角色分配"); + return; + } + + // 检查用户是否已有该角色 + if (!hasUserRole(advisorUserId, ADVISOR_ROLE_ID)) { + try { + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(advisorUserId); + userRole.setRoleId(ADVISOR_ROLE_ID); + + int result = sysUserRoleMapper.insert(userRole); + if (result > 0) { + log.info("成功为用户 {} 分配指导老师角色,角色ID: {}", advisorUserId, ADVISOR_ROLE_ID); + } else { + log.error("为用户 {} 分配指导老师角色失败", advisorUserId); + } + } catch (Exception e) { + log.error("为用户 {} 分配指导老师角色时发生异常", advisorUserId, e); + throw new RuntimeException("分配指导老师角色失败", e); + } + } else { + log.debug("用户 {} 已有指导老师角色,跳过分配", advisorUserId); + } + } + + /** + * 检查用户是否已有指定角色 + * + * @param userId 用户ID + * @param roleId 角色ID + * @return 是否已有该角色 + */ + private boolean hasUserRole(Long userId, Long roleId) { + try { + // 查询用户角色关系 + List roleIds = sysUserRoleMapper.selectUserIdsByRoleId(roleId); + return roleIds.contains(userId); + } catch (Exception e) { + log.error("检查用户角色关系时发生异常,用户ID: {}, 角色ID: {}", userId, roleId, e); + // 如果查询失败,假设用户没有该角色,继续分配 + return false; + } + } + + /** + * 移除指导老师角色 + * + * @param advisorUserId 指导老师用户ID + */ + @Transactional(rollbackFor = Exception.class) + public void removeAdvisorRole(Long advisorUserId) { + if (advisorUserId == null) { + log.warn("指导老师用户ID为空,跳过角色移除"); + return; + } + + try { + // 删除用户角色关系 + int result = sysUserRoleMapper.delete( + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(SysUserRole::getUserId, advisorUserId) + .eq(SysUserRole::getRoleId, ADVISOR_ROLE_ID) + ); + + if (result > 0) { + log.info("成功移除用户 {} 的指导老师角色", advisorUserId); + } else { + log.debug("用户 {} 没有指导老师角色,无需移除", advisorUserId); + } + } catch (Exception e) { + log.error("移除用户 {} 的指导老师角色时发生异常", advisorUserId, e); + throw new RuntimeException("移除指导老师角色失败", e); + } + } + + /** + * 批量移除指导老师角色 + * + * @param advisorUserIds 指导老师用户ID列表 + */ + @Transactional(rollbackFor = Exception.class) + public void removeAdvisorRoles(List advisorUserIds) { + if (advisorUserIds == null || advisorUserIds.isEmpty()) { + log.info("没有指导老师需要移除角色"); + return; + } + + try { + // 批量删除用户角色关系 + int result = sysUserRoleMapper.delete( + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .in(SysUserRole::getUserId, advisorUserIds) + .eq(SysUserRole::getRoleId, ADVISOR_ROLE_ID) + ); + + if (result > 0) { + log.info("成功移除 {} 个用户的指导老师角色", result); + } else { + log.debug("没有用户需要移除指导老师角色"); + } + } catch (Exception e) { + log.error("批量移除指导老师角色时发生异常", e); + throw new RuntimeException("批量移除指导老师角色失败", e); + } + } +} \ No newline at end of file diff --git a/web/src/views/stgl/activity/components/ActivityMembersDialog.vue b/web/src/views/stgl/activity/components/ActivityMembersDialog.vue new file mode 100644 index 00000000..3e7bc514 --- /dev/null +++ b/web/src/views/stgl/activity/components/ActivityMembersDialog.vue @@ -0,0 +1,108 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/stgl/activity/components/ActivityRegistrationView.vue b/web/src/views/stgl/activity/components/ActivityRegistrationView.vue new file mode 100644 index 00000000..a0e50722 --- /dev/null +++ b/web/src/views/stgl/activity/components/ActivityRegistrationView.vue @@ -0,0 +1,840 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/stgl/activity/components/PendingMembersTab.vue b/web/src/views/stgl/activity/components/PendingMembersTab.vue new file mode 100644 index 00000000..c5b2020d --- /dev/null +++ b/web/src/views/stgl/activity/components/PendingMembersTab.vue @@ -0,0 +1,469 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/stgl/activity/components/RegisteredMembersTab.vue b/web/src/views/stgl/activity/components/RegisteredMembersTab.vue new file mode 100644 index 00000000..270a3fbb --- /dev/null +++ b/web/src/views/stgl/activity/components/RegisteredMembersTab.vue @@ -0,0 +1,634 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/stgl/club/info/components/JoinedMembersTab.vue b/web/src/views/stgl/club/info/components/JoinedMembersTab.vue new file mode 100644 index 00000000..4fdf8d1f --- /dev/null +++ b/web/src/views/stgl/club/info/components/JoinedMembersTab.vue @@ -0,0 +1,835 @@ + + + + + diff --git a/web/src/views/stgl/club/info/components/MemberManagementDialog.vue b/web/src/views/stgl/club/info/components/MemberManagementDialog.vue new file mode 100644 index 00000000..ec33c69b --- /dev/null +++ b/web/src/views/stgl/club/info/components/MemberManagementDialog.vue @@ -0,0 +1,114 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/stgl/club/info/components/PendingMembersTab.vue b/web/src/views/stgl/club/info/components/PendingMembersTab.vue new file mode 100644 index 00000000..8b2c8c00 --- /dev/null +++ b/web/src/views/stgl/club/info/components/PendingMembersTab.vue @@ -0,0 +1,514 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/stgl/volunteer/team/components/JoinedMembersTab.vue b/web/src/views/stgl/volunteer/team/components/JoinedMembersTab.vue new file mode 100644 index 00000000..f51609eb --- /dev/null +++ b/web/src/views/stgl/volunteer/team/components/JoinedMembersTab.vue @@ -0,0 +1,735 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/stgl/volunteer/team/components/MemberManagementDialog.vue b/web/src/views/stgl/volunteer/team/components/MemberManagementDialog.vue new file mode 100644 index 00000000..1e7b6539 --- /dev/null +++ b/web/src/views/stgl/volunteer/team/components/MemberManagementDialog.vue @@ -0,0 +1,121 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/stgl/volunteer/team/components/PendingMembersTab.vue b/web/src/views/stgl/volunteer/team/components/PendingMembersTab.vue new file mode 100644 index 00000000..fd591e4d --- /dev/null +++ b/web/src/views/stgl/volunteer/team/components/PendingMembersTab.vue @@ -0,0 +1,555 @@ + + + + + \ No newline at end of file