Sfoglia il codice sorgente

心理健康测评完成

李旭明 1 anno fa
parent
commit
461396c77f
26 ha cambiato i file con 4276 aggiunte e 16 eliminazioni
  1. 6 0
      backend/pom.xml
  2. 7 0
      backend/ruoyi-admin/pom.xml
  3. 1 0
      backend/ruoyi-modules/pom.xml
  4. 93 0
      backend/ruoyi-modules/ruoyi-stgl/pom.xml
  5. 176 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubController.java
  6. 145 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubRegisterController.java
  7. 205 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglMemberController.java
  8. 160 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/StglClub.java
  9. 75 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/StglMember.java
  10. 188 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/bo/StglClubBo.java
  11. 85 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/bo/StglMemberBo.java
  12. 111 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglClubRegisterVo.java
  13. 211 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglClubVo.java
  14. 133 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglMemberVo.java
  15. 15 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/mapper/StglClubMapper.java
  16. 15 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/mapper/StglMemberMapper.java
  17. 88 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglClubRegisterService.java
  18. 109 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglClubService.java
  19. 123 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglMemberService.java
  20. 306 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglClubRegisterServiceImpl.java
  21. 233 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglClubServiceImpl.java
  22. 272 0
      backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglMemberServiceImpl.java
  23. 6 9
      docs/开发文档/API/API文档总览.md
  24. 962 0
      docs/开发文档/API/社团管理API.md
  25. 550 0
      stgl-api-test.js
  26. 1 7
      web/src/router/index.ts

+ 6 - 0
backend/pom.xml

@@ -407,6 +407,12 @@
                 <version>${revision}</version>
             </dependency>
 
+            <!--  社团管理模块  -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-stgl</artifactId>
+                <version>${revision}</version>
+            </dependency>
 
         </dependencies>
     </dependencyManagement>

+ 7 - 0
backend/ruoyi-admin/pom.xml

@@ -135,6 +135,13 @@
             <version>${revision}</version>
         </dependency>
 
+        <!-- 社团管理模块 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-stgl</artifactId>
+            <version>${revision}</version>
+        </dependency>
+
         <dependency>
             <groupId>de.codecentric</groupId>
             <artifactId>spring-boot-admin-starter-client</artifactId>

+ 1 - 0
backend/ruoyi-modules/pom.xml

@@ -22,6 +22,7 @@
         <module>ruoyi-cw</module>
         <module>ruoyi-rs</module>
         <module>ruoyi-xljk</module>
+        <module>ruoyi-stgl</module>
     </modules>
 
     <artifactId>ruoyi-modules</artifactId>

+ 93 - 0
backend/ruoyi-modules/ruoyi-stgl/pom.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ruoyi-modules</artifactId>
+        <groupId>org.dromara</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-stgl</artifactId>
+
+    <description>
+        社团管理模块
+    </description>
+
+    <dependencies>
+        <!-- 通用工具-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <!-- 安全模块 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-security</artifactId>
+        </dependency>
+
+        <!-- web服务 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-web</artifactId>
+        </dependency>
+
+        <!-- excel -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-excel</artifactId>
+        </dependency>
+        <!-- Apache POI for Excel export -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>5.2.3</version>
+        </dependency>
+
+        <!-- 数据库 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mybatis</artifactId>
+        </dependency>
+
+        <!-- 多租户 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-tenant</artifactId>
+        </dependency>
+
+        <!-- 幂等性 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-idempotent</artifactId>
+        </dependency>
+
+        <!-- 日志记录 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-log</artifactId>
+        </dependency>
+
+        <!-- 数据翻译 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-translation</artifactId>
+        </dependency>
+
+        <!-- OSS云存储 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-oss</artifactId>
+        </dependency>
+
+        <!-- 接口文档 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-doc</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project> 

+ 176 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubController.java

@@ -0,0 +1,176 @@
+package org.dromara.stgl.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.stgl.domain.vo.StglClubVo;
+import org.dromara.stgl.domain.bo.StglClubBo;
+import org.dromara.stgl.service.IStglClubService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+/**
+ * 社团信息管理
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/stgl/club")
+@Tag(name = "社团信息管理", description = "社团信息管理")
+public class StglClubController extends BaseController {
+
+    private final IStglClubService stglClubService;
+
+    /**
+     * 查询社团信息列表
+     */
+    @Operation(summary = "查询社团信息列表")
+    @SaCheckPermission("stgl:club:list")
+    @GetMapping("/list")
+    public TableDataInfo<StglClubVo> list(StglClubBo bo, PageQuery pageQuery) {
+        return stglClubService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出社团信息列表
+     */
+    @Operation(summary = "导出社团信息列表")
+    @SaCheckPermission("stgl:club:export")
+    @Log(title = "社团信息", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(StglClubBo bo, HttpServletResponse response) {
+        List<StglClubVo> list = stglClubService.queryList(bo);
+        ExcelUtil.exportExcel(list, "社团信息", StglClubVo.class, response);
+    }
+
+    /**
+     * 获取社团信息详细信息
+     */
+    @Operation(summary = "获取社团信息详细信息")
+    @SaCheckPermission("stgl:club:query")
+    @GetMapping("/{id}")
+    public R<StglClubVo> getInfo(@NotNull(message = "主键不能为空")
+                                     @PathVariable Long id) {
+        return R.ok(stglClubService.queryById(id));
+    }
+
+    /**
+     * 新增社团信息
+     */
+    @Operation(summary = "新增社团信息")
+    @SaCheckPermission("stgl:club:add")
+    @Log(title = "社团信息", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody StglClubBo bo) {
+        return toAjax(stglClubService.insertByBo(bo));
+    }
+
+    /**
+     * 修改社团信息
+     */
+    @Operation(summary = "修改社团信息")
+    @SaCheckPermission("stgl:club:edit")
+    @Log(title = "社团信息", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglClubBo bo) {
+        return toAjax(stglClubService.updateByBo(bo));
+    }
+
+    /**
+     * 删除社团信息
+     */
+    @Operation(summary = "删除社团信息")
+    @SaCheckPermission("stgl:club:remove")
+    @Log(title = "社团信息", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable Long[] ids) {
+        return toAjax(stglClubService.deleteWithValidByIds(List.of(ids), true));
+    }
+
+    /**
+     * 查询可用的社团选项
+     */
+    @Operation(summary = "查询可用的社团选项")
+    @SaCheckPermission("stgl:club:list")
+    @GetMapping("/options")
+    public R<List<StglClubVo>> getOptions() {
+        return R.ok(stglClubService.queryAvailableOptions());
+    }
+
+    /**
+     * 根据社团类型查询社团列表
+     */
+    @Operation(summary = "根据社团类型查询社团列表")
+    @SaCheckPermission("stgl:club:list")
+    @GetMapping("/listByType/{clubType}")
+    @Parameters({
+        @Parameter(name = "clubType", description = "社团类型", required = true)
+    })
+    public R<List<StglClubVo>> listByType(@PathVariable String clubType) {
+        return R.ok(stglClubService.queryByClubType(clubType));
+    }
+
+    /**
+     * 查询我管理的社团列表
+     */
+    @Operation(summary = "查询我管理的社团列表")
+    @SaCheckPermission("stgl:club:list")
+    @GetMapping("/myClubs")
+    public R<List<StglClubVo>> getMyClubs() {
+        return R.ok(stglClubService.queryMyClubs());
+    }
+
+    /**
+     * 检查社团名称是否重复
+     */
+    @Operation(summary = "检查社团名称是否重复")
+    @SaCheckPermission("stgl:club:list")
+    @GetMapping("/checkClubNameUnique")
+    @Parameters({
+        @Parameter(name = "clubName", description = "社团名称", required = true),
+        @Parameter(name = "excludeId", description = "排除的ID", required = false)
+    })
+    public R<Boolean> checkClubNameUnique(@RequestParam String clubName, 
+                                         @RequestParam(required = false) Long excludeId) {
+        return R.ok(stglClubService.checkClubNameUnique(clubName, excludeId));
+    }
+
+    /**
+     * 启用/禁用社团
+     */
+    @Operation(summary = "启用/禁用社团")
+    @SaCheckPermission("stgl:club:edit")
+    @Log(title = "社团信息", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    @Parameters({
+        @Parameter(name = "id", description = "社团ID", required = true),
+        @Parameter(name = "status", description = "状态", required = true)
+    })
+    public R<Void> changeStatus(@RequestParam Long id, @RequestParam Integer status) {
+        return toAjax(stglClubService.changeStatus(id, status));
+    }
+
+} 

+ 145 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubRegisterController.java

@@ -0,0 +1,145 @@
+package org.dromara.stgl.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.stgl.domain.vo.StglClubRegisterVo;
+import org.dromara.stgl.service.IStglClubRegisterService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+/**
+ * 社团报名大厅
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/stgl/register")
+@Tag(name = "社团报名大厅", description = "社团报名大厅")
+public class StglClubRegisterController extends BaseController {
+
+    private final IStglClubRegisterService stglClubRegisterService;
+
+    /**
+     * 查询社团报名大厅列表
+     */
+    @Operation(summary = "查询社团报名大厅列表")
+    @GetMapping("/list")
+    public TableDataInfo<StglClubRegisterVo> list(@RequestParam(required = false) String clubType,
+                                                  @RequestParam(required = false) String clubName,
+                                                  PageQuery pageQuery) {
+        return stglClubRegisterService.queryPageList(clubType, clubName, pageQuery);
+    }
+
+    /**
+     * 查询社团报名大厅列表(不分页)
+     */
+    @Operation(summary = "查询社团报名大厅列表(不分页)")
+    @GetMapping("/listAll")
+    public R<List<StglClubRegisterVo>> listAll(@RequestParam(required = false) String clubType,
+                                               @RequestParam(required = false) String clubName) {
+        return R.ok(stglClubRegisterService.queryList(clubType, clubName));
+    }
+
+    /**
+     * 获取社团详细信息
+     */
+    @Operation(summary = "获取社团详细信息")
+    @GetMapping("/{clubId}")
+    @Parameters({
+        @Parameter(name = "clubId", description = "社团ID", required = true)
+    })
+    public R<StglClubRegisterVo> getClubDetail(@PathVariable Long clubId) {
+        return R.ok(stglClubRegisterService.queryClubDetail(clubId));
+    }
+
+    /**
+     * 报名加入社团
+     */
+    @Operation(summary = "报名加入社团")
+    @SaCheckPermission("stgl:register:join")
+    @Log(title = "社团报名", businessType = BusinessType.INSERT)
+    @PostMapping("/join/{clubId}")
+    @Parameters({
+        @Parameter(name = "clubId", description = "社团ID", required = true)
+    })
+    public R<Void> registerClub(@PathVariable Long clubId) {
+        Long userId = LoginHelper.getUserId();
+        return toAjax(stglClubRegisterService.registerClub(clubId, userId));
+    }
+
+    /**
+     * 退出社团
+     */
+    @Operation(summary = "退出社团")
+    @SaCheckPermission("stgl:register:quit")
+    @Log(title = "社团退出", businessType = BusinessType.UPDATE)
+    @PostMapping("/quit/{clubId}")
+    @Parameters({
+        @Parameter(name = "clubId", description = "社团ID", required = true)
+    })
+    public R<Void> quitClub(@PathVariable Long clubId) {
+        Long userId = LoginHelper.getUserId();
+        return toAjax(stglClubRegisterService.quitClub(clubId, userId));
+    }
+
+    /**
+     * 查询我参与的社团列表
+     */
+    @Operation(summary = "查询我参与的社团列表")
+    @SaCheckPermission("stgl:register:list")
+    @GetMapping("/myClubs")
+    public R<List<StglClubRegisterVo>> getMyClubs() {
+        Long userId = LoginHelper.getUserId();
+        return R.ok(stglClubRegisterService.queryMyClubs(userId));
+    }
+
+    /**
+     * 检查是否已报名某个社团
+     */
+    @Operation(summary = "检查是否已报名某个社团")
+    @GetMapping("/checkRegistered/{clubId}")
+    @Parameters({
+        @Parameter(name = "clubId", description = "社团ID", required = true)
+    })
+    public R<Boolean> checkRegistered(@PathVariable Long clubId) {
+        try {
+            Long userId = LoginHelper.getUserId();
+            return R.ok(stglClubRegisterService.checkRegistered(clubId, userId));
+        } catch (Exception e) {
+            // 未登录用户
+            return R.ok(false);
+        }
+    }
+
+    /**
+     * 查询推荐社团
+     */
+    @Operation(summary = "查询推荐社团")
+    @GetMapping("/recommend")
+    @Parameters({
+        @Parameter(name = "clubType", description = "社团类型", required = false),
+        @Parameter(name = "limit", description = "推荐数量", required = false)
+    })
+    public R<List<StglClubRegisterVo>> getRecommendClubs(@RequestParam(required = false) String clubType,
+                                                         @RequestParam(required = false, defaultValue = "6") Integer limit) {
+        return R.ok(stglClubRegisterService.queryRecommendClubs(clubType, limit));
+    }
+
+} 

+ 205 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglMemberController.java

@@ -0,0 +1,205 @@
+package org.dromara.stgl.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.stgl.domain.vo.StglMemberVo;
+import org.dromara.stgl.domain.bo.StglMemberBo;
+import org.dromara.stgl.service.IStglMemberService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+/**
+ * 社团成员管理
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/stgl/member")
+@Tag(name = "社团成员管理", description = "社团成员管理")
+public class StglMemberController extends BaseController {
+
+    private final IStglMemberService stglMemberService;
+
+    /**
+     * 查询社团成员列表
+     */
+    @Operation(summary = "查询社团成员列表")
+    @SaCheckPermission("stgl:member:list")
+    @GetMapping("/list")
+    public TableDataInfo<StglMemberVo> list(StglMemberBo bo, PageQuery pageQuery) {
+        return stglMemberService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出社团成员列表
+     */
+    @Operation(summary = "导出社团成员列表")
+    @SaCheckPermission("stgl:member:export")
+    @Log(title = "社团成员", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(StglMemberBo bo, HttpServletResponse response) {
+        List<StglMemberVo> list = stglMemberService.queryList(bo);
+        ExcelUtil.exportExcel(list, "社团成员", StglMemberVo.class, response);
+    }
+
+    /**
+     * 获取社团成员详细信息
+     */
+    @Operation(summary = "获取社团成员详细信息")
+    @SaCheckPermission("stgl:member:query")
+    @GetMapping("/{id}")
+    public R<StglMemberVo> getInfo(@NotNull(message = "主键不能为空")
+                                     @PathVariable Long id) {
+        return R.ok(stglMemberService.queryById(id));
+    }
+
+    /**
+     * 新增社团成员
+     */
+    @Operation(summary = "新增社团成员")
+    @SaCheckPermission("stgl:member:add")
+    @Log(title = "社团成员", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody StglMemberBo bo) {
+        return toAjax(stglMemberService.insertByBo(bo));
+    }
+
+    /**
+     * 修改社团成员
+     */
+    @Operation(summary = "修改社团成员")
+    @SaCheckPermission("stgl:member:edit")
+    @Log(title = "社团成员", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglMemberBo bo) {
+        return toAjax(stglMemberService.updateByBo(bo));
+    }
+
+    /**
+     * 删除社团成员
+     */
+    @Operation(summary = "删除社团成员")
+    @SaCheckPermission("stgl:member:remove")
+    @Log(title = "社团成员", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable Long[] ids) {
+        return toAjax(stglMemberService.deleteWithValidByIds(List.of(ids), true));
+    }
+
+    /**
+     * 根据社团ID查询成员列表
+     */
+    @Operation(summary = "根据社团ID查询成员列表")
+    @SaCheckPermission("stgl:member:list")
+    @GetMapping("/club/{clubId}")
+    @Parameters({
+        @Parameter(name = "clubId", description = "社团ID", required = true)
+    })
+    public R<List<StglMemberVo>> getByClubId(@PathVariable Long clubId) {
+        return R.ok(stglMemberService.queryByClubId(clubId));
+    }
+
+    /**
+     * 根据用户ID查询参与的社团列表
+     */
+    @Operation(summary = "根据用户ID查询参与的社团列表")
+    @SaCheckPermission("stgl:member:list")
+    @GetMapping("/user/{userId}")
+    @Parameters({
+        @Parameter(name = "userId", description = "用户ID", required = true)
+    })
+    public R<List<StglMemberVo>> getByUserId(@PathVariable Long userId) {
+        return R.ok(stglMemberService.queryByUserId(userId));
+    }
+
+    /**
+     * 检查用户是否已是某个社团/队伍的成员
+     */
+    @Operation(summary = "检查用户是否已是某个社团/队伍的成员")
+    @SaCheckPermission("stgl:member:list")
+    @GetMapping("/checkMemberExists")
+    @Parameters({
+        @Parameter(name = "memberType", description = "成员类型", required = true),
+        @Parameter(name = "relationId", description = "关联ID", required = true),
+        @Parameter(name = "userId", description = "用户ID", required = true)
+    })
+    public R<Boolean> checkMemberExists(@RequestParam Integer memberType,
+                                       @RequestParam Long relationId,
+                                       @RequestParam Long userId) {
+        return R.ok(stglMemberService.checkMemberExists(memberType, relationId, userId));
+    }
+
+    /**
+     * 批量添加成员
+     */
+    @Operation(summary = "批量添加成员")
+    @SaCheckPermission("stgl:member:add")
+    @Log(title = "社团成员", businessType = BusinessType.INSERT)
+    @PostMapping("/batchAdd")
+    @Parameters({
+        @Parameter(name = "memberType", description = "成员类型", required = true),
+        @Parameter(name = "relationId", description = "关联ID", required = true),
+        @Parameter(name = "userIds", description = "用户ID列表", required = true),
+        @Parameter(name = "roleType", description = "角色类型", required = false)
+    })
+    public R<Void> batchAddMembers(@RequestParam Integer memberType,
+                                  @RequestParam Long relationId,
+                                  @RequestParam List<Long> userIds,
+                                  @RequestParam(required = false) Integer roleType) {
+        return toAjax(stglMemberService.batchAddMembers(memberType, relationId, userIds, roleType));
+    }
+
+    /**
+     * 更新成员角色
+     */
+    @Operation(summary = "更新成员角色")
+    @SaCheckPermission("stgl:member:edit")
+    @Log(title = "社团成员", businessType = BusinessType.UPDATE)
+    @PutMapping("/updateRole")
+    @Parameters({
+        @Parameter(name = "id", description = "成员ID", required = true),
+        @Parameter(name = "roleType", description = "角色类型", required = true)
+    })
+    public R<Void> updateMemberRole(@RequestParam Long id, @RequestParam Integer roleType) {
+        return toAjax(stglMemberService.updateMemberRole(id, roleType));
+    }
+
+    /**
+     * 退出社团/队伍
+     */
+    @Operation(summary = "退出社团/队伍")
+    @SaCheckPermission("stgl:member:edit")
+    @Log(title = "社团成员", businessType = BusinessType.UPDATE)
+    @PutMapping("/quit/{id}")
+    @Parameters({
+        @Parameter(name = "id", description = "成员ID", required = true)
+    })
+    public R<Void> quitMember(@PathVariable Long id) {
+        return toAjax(stglMemberService.quitMember(id));
+    }
+
+} 

+ 160 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/StglClub.java

@@ -0,0 +1,160 @@
+package org.dromara.stgl.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * 社团信息对象 stgl_club
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("stgl_club")
+public class StglClub extends TenantEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 社团名称
+     */
+    private String clubName;
+
+    /**
+     * 社团类型
+     */
+    private String clubType;
+
+    /**
+     * 成立日期
+     */
+    private Date establishDate;
+
+    /**
+     * 社团简介(500字以内)
+     */
+    private String description;
+
+    /**
+     * 邮箱
+     */
+    private String email;
+
+    /**
+     * 电话
+     */
+    private String phone;
+
+    /**
+     * logo图片路径
+     */
+    private String logoUrl;
+
+    /**
+     * 社长姓名
+     */
+    private String presidentName;
+
+    /**
+     * 社长学号
+     */
+    private String presidentStudentNo;
+
+    /**
+     * 社长院系
+     */
+    private String presidentDept;
+
+    /**
+     * 社长专业
+     */
+    private String presidentMajor;
+
+    /**
+     * 社长班级
+     */
+    private String presidentClass;
+
+    /**
+     * 社长联系方式
+     */
+    private String presidentPhone;
+
+    /**
+     * 副社长姓名
+     */
+    private String vicePresidentName;
+
+    /**
+     * 副社长学号
+     */
+    private String vicePresidentStudentNo;
+
+    /**
+     * 指导老师姓名
+     */
+    private String advisorName;
+
+    /**
+     * 指导老师所属院系
+     */
+    private String advisorDept;
+
+    /**
+     * 成员规模上限
+     */
+    private Integer memberLimit;
+
+    /**
+     * 组织架构(部门设置及职责)
+     */
+    private String departments;
+
+    /**
+     * 招新周期
+     */
+    private String recruitCycle;
+
+    /**
+     * 招新时间
+     */
+    private String recruitTime;
+
+    /**
+     * 活动频率
+     */
+    private String activityFrequency;
+
+    /**
+     * 经费来源(多选)
+     */
+    private String fundingSources;
+
+    /**
+     * 章程文档路径
+     */
+    private String charterUrl;
+
+    /**
+     * 状态(1-正常 0-停用)
+     */
+    private Integer status;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+} 

+ 75 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/StglMember.java

@@ -0,0 +1,75 @@
+package org.dromara.stgl.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * 社团成员对象 stgl_member
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("stgl_member")
+public class StglMember extends TenantEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 成员类型(1-社团成员 2-志愿者)
+     */
+    private Integer memberType;
+
+    /**
+     * 关联ID(社团ID或志愿者队伍ID)
+     */
+    private Long relationId;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 学号
+     */
+    private String studentNo;
+
+    /**
+     * 学生姓名
+     */
+    private String studentName;
+
+    /**
+     * 角色类型(1-社长 2-副社长 3-成员)
+     */
+    private Integer roleType;
+
+    /**
+     * 加入时间
+     */
+    private Date joinTime;
+
+    /**
+     * 状态(1-正常 0-退出)
+     */
+    private Integer status;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+} 

+ 188 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/bo/StglClubBo.java

@@ -0,0 +1,188 @@
+package org.dromara.stgl.domain.bo;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import org.dromara.stgl.domain.StglClub;
+
+import java.util.Date;
+
+/**
+ * 社团信息业务对象 stgl_club
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = StglClub.class, reverseConvertGenerate = false)
+public class StglClubBo extends BaseEntity {
+
+    /**
+     * 主键ID
+     */
+    @NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 社团名称
+     */
+    @NotBlank(message = "社团名称不能为空", groups = { AddGroup.class, EditGroup.class })
+    @Size(max = 100, message = "社团名称长度不能超过100个字符")
+    private String clubName;
+
+    /**
+     * 社团类型
+     */
+    @NotBlank(message = "社团类型不能为空", groups = { AddGroup.class, EditGroup.class })
+    @Size(max = 50, message = "社团类型长度不能超过50个字符")
+    private String clubType;
+
+    /**
+     * 成立日期
+     */
+    private Date establishDate;
+
+    /**
+     * 社团简介(500字以内)
+     */
+    @Size(max = 500, message = "社团简介长度不能超过500个字符")
+    private String description;
+
+    /**
+     * 邮箱
+     */
+    @Email(message = "邮箱格式不正确")
+    @Size(max = 100, message = "邮箱长度不能超过100个字符")
+    private String email;
+
+    /**
+     * 电话
+     */
+    @Pattern(regexp = "^[0-9-]+$", message = "电话格式不正确")
+    @Size(max = 20, message = "电话长度不能超过20个字符")
+    private String phone;
+
+    /**
+     * logo图片路径
+     */
+    @Size(max = 500, message = "logo图片路径长度不能超过500个字符")
+    private String logoUrl;
+
+    /**
+     * 社长姓名
+     */
+    @Size(max = 50, message = "社长姓名长度不能超过50个字符")
+    private String presidentName;
+
+    /**
+     * 社长学号
+     */
+    @Size(max = 20, message = "社长学号长度不能超过20个字符")
+    private String presidentStudentNo;
+
+    /**
+     * 社长院系
+     */
+    @Size(max = 100, message = "社长院系长度不能超过100个字符")
+    private String presidentDept;
+
+    /**
+     * 社长专业
+     */
+    @Size(max = 100, message = "社长专业长度不能超过100个字符")
+    private String presidentMajor;
+
+    /**
+     * 社长班级
+     */
+    @Size(max = 100, message = "社长班级长度不能超过100个字符")
+    private String presidentClass;
+
+    /**
+     * 社长联系方式
+     */
+    @Pattern(regexp = "^[0-9-]+$", message = "社长联系方式格式不正确")
+    @Size(max = 20, message = "社长联系方式长度不能超过20个字符")
+    private String presidentPhone;
+
+    /**
+     * 副社长姓名
+     */
+    @Size(max = 50, message = "副社长姓名长度不能超过50个字符")
+    private String vicePresidentName;
+
+    /**
+     * 副社长学号
+     */
+    @Size(max = 20, message = "副社长学号长度不能超过20个字符")
+    private String vicePresidentStudentNo;
+
+    /**
+     * 指导老师姓名
+     */
+    @Size(max = 50, message = "指导老师姓名长度不能超过50个字符")
+    private String advisorName;
+
+    /**
+     * 指导老师所属院系
+     */
+    @Size(max = 100, message = "指导老师所属院系长度不能超过100个字符")
+    private String advisorDept;
+
+    /**
+     * 成员规模上限
+     */
+    @Min(value = 0, message = "成员规模上限不能小于0")
+    private Integer memberLimit;
+
+    /**
+     * 组织架构(部门设置及职责)
+     */
+    private String departments;
+
+    /**
+     * 招新周期
+     */
+    @Size(max = 50, message = "招新周期长度不能超过50个字符")
+    private String recruitCycle;
+
+    /**
+     * 招新时间
+     */
+    @Size(max = 50, message = "招新时间长度不能超过50个字符")
+    private String recruitTime;
+
+    /**
+     * 活动频率
+     */
+    @Size(max = 50, message = "活动频率长度不能超过50个字符")
+    private String activityFrequency;
+
+    /**
+     * 经费来源(多选)
+     */
+    @Size(max = 200, message = "经费来源长度不能超过200个字符")
+    private String fundingSources;
+
+    /**
+     * 章程文档路径
+     */
+    @Size(max = 500, message = "章程文档路径长度不能超过500个字符")
+    private String charterUrl;
+
+    /**
+     * 状态(1-正常 0-停用)
+     */
+    private Integer status;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+} 

+ 85 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/bo/StglMemberBo.java

@@ -0,0 +1,85 @@
+package org.dromara.stgl.domain.bo;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import org.dromara.stgl.domain.StglMember;
+
+import java.util.Date;
+
+/**
+ * 社团成员业务对象 stgl_member
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = StglMember.class, reverseConvertGenerate = false)
+public class StglMemberBo extends BaseEntity {
+
+    /**
+     * 主键ID
+     */
+    @NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 成员类型(1-社团成员 2-志愿者)
+     */
+    @NotNull(message = "成员类型不能为空", groups = { AddGroup.class, EditGroup.class })
+    @Min(value = 1, message = "成员类型值无效")
+    @Max(value = 2, message = "成员类型值无效")
+    private Integer memberType;
+
+    /**
+     * 关联ID(社团ID或志愿者队伍ID)
+     */
+    @NotNull(message = "关联ID不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long relationId;
+
+    /**
+     * 用户ID
+     */
+    @NotNull(message = "用户ID不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long userId;
+
+    /**
+     * 学号
+     */
+    @Size(max = 20, message = "学号长度不能超过20个字符")
+    private String studentNo;
+
+    /**
+     * 学生姓名
+     */
+    @Size(max = 50, message = "学生姓名长度不能超过50个字符")
+    private String studentName;
+
+    /**
+     * 角色类型(1-社长 2-副社长 3-成员)
+     */
+    @Min(value = 1, message = "角色类型值无效")
+    @Max(value = 3, message = "角色类型值无效")
+    private Integer roleType;
+
+    /**
+     * 加入时间
+     */
+    private Date joinTime;
+
+    /**
+     * 状态(1-正常 0-退出)
+     */
+    private Integer status;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+} 

+ 111 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglClubRegisterVo.java

@@ -0,0 +1,111 @@
+package org.dromara.stgl.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 社团报名大厅视图对象
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@Data
+public class StglClubRegisterVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 社团名称
+     */
+    private String clubName;
+
+    /**
+     * 社团类型
+     */
+    private String clubType;
+
+    /**
+     * 成立日期
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date establishDate;
+
+    /**
+     * 社团简介(500字以内)
+     */
+    private String description;
+
+    /**
+     * logo图片路径
+     */
+    private String logoUrl;
+
+    /**
+     * 社长姓名
+     */
+    private String presidentName;
+
+    /**
+     * 社长院系
+     */
+    private String presidentDept;
+
+    /**
+     * 指导老师姓名
+     */
+    private String advisorName;
+
+    /**
+     * 指导老师所属院系
+     */
+    private String advisorDept;
+
+    /**
+     * 成员规模上限
+     */
+    private Integer memberLimit;
+
+    /**
+     * 当前成员数量
+     */
+    private Integer currentMemberCount;
+
+    /**
+     * 招新周期
+     */
+    private String recruitCycle;
+
+    /**
+     * 招新时间
+     */
+    private String recruitTime;
+
+    /**
+     * 活动频率
+     */
+    private String activityFrequency;
+
+    /**
+     * 是否已报名
+     */
+    private Boolean hasRegistered;
+
+    /**
+     * 报名状态(1-已报名 0-未报名)
+     */
+    private Integer registrationStatus;
+
+    /**
+     * 是否可报名(基于成员上限等条件)
+     */
+    private Boolean canRegister;
+
+} 

+ 211 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglClubVo.java

@@ -0,0 +1,211 @@
+package org.dromara.stgl.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.stgl.domain.StglClub;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 社团信息视图对象 stgl_club
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = StglClub.class)
+public class StglClubVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @ExcelProperty(value = "主键ID")
+    private Long id;
+
+    /**
+     * 社团名称
+     */
+    @ExcelProperty(value = "社团名称")
+    private String clubName;
+
+    /**
+     * 社团类型
+     */
+    @ExcelProperty(value = "社团类型")
+    private String clubType;
+
+    /**
+     * 成立日期
+     */
+    @ExcelProperty(value = "成立日期")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date establishDate;
+
+    /**
+     * 社团简介(500字以内)
+     */
+    @ExcelProperty(value = "社团简介")
+    private String description;
+
+    /**
+     * 邮箱
+     */
+    @ExcelProperty(value = "邮箱")
+    private String email;
+
+    /**
+     * 电话
+     */
+    @ExcelProperty(value = "电话")
+    private String phone;
+
+    /**
+     * logo图片路径
+     */
+    @ExcelProperty(value = "社团Logo")
+    private String logoUrl;
+
+    /**
+     * 社长姓名
+     */
+    @ExcelProperty(value = "社长姓名")
+    private String presidentName;
+
+    /**
+     * 社长学号
+     */
+    @ExcelProperty(value = "社长学号")
+    private String presidentStudentNo;
+
+    /**
+     * 社长院系
+     */
+    @ExcelProperty(value = "社长院系")
+    private String presidentDept;
+
+    /**
+     * 社长专业
+     */
+    @ExcelProperty(value = "社长专业")
+    private String presidentMajor;
+
+    /**
+     * 社长班级
+     */
+    @ExcelProperty(value = "社长班级")
+    private String presidentClass;
+
+    /**
+     * 社长联系方式
+     */
+    @ExcelProperty(value = "社长联系方式")
+    private String presidentPhone;
+
+    /**
+     * 副社长姓名
+     */
+    @ExcelProperty(value = "副社长姓名")
+    private String vicePresidentName;
+
+    /**
+     * 副社长学号
+     */
+    @ExcelProperty(value = "副社长学号")
+    private String vicePresidentStudentNo;
+
+    /**
+     * 指导老师姓名
+     */
+    @ExcelProperty(value = "指导老师姓名")
+    private String advisorName;
+
+    /**
+     * 指导老师所属院系
+     */
+    @ExcelProperty(value = "指导老师所属院系")
+    private String advisorDept;
+
+    /**
+     * 成员规模上限
+     */
+    @ExcelProperty(value = "成员规模上限")
+    private Integer memberLimit;
+
+    /**
+     * 组织架构(部门设置及职责)
+     */
+    @ExcelProperty(value = "组织架构")
+    private String departments;
+
+    /**
+     * 招新周期
+     */
+    @ExcelProperty(value = "招新周期")
+    private String recruitCycle;
+
+    /**
+     * 招新时间
+     */
+    @ExcelProperty(value = "招新时间")
+    private String recruitTime;
+
+    /**
+     * 活动频率
+     */
+    @ExcelProperty(value = "活动频率")
+    private String activityFrequency;
+
+    /**
+     * 经费来源(多选)
+     */
+    @ExcelProperty(value = "经费来源")
+    private String fundingSources;
+
+    /**
+     * 章程文档路径
+     */
+    @ExcelProperty(value = "章程文档")
+    private String charterUrl;
+
+    /**
+     * 状态(1-正常 0-停用)
+     */
+    @ExcelProperty(value = "状态")
+    private Integer status;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+    /**
+     * 创建者
+     */
+    private Long createBy;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /**
+     * 更新者
+     */
+    private Long updateBy;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+} 

+ 133 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglMemberVo.java

@@ -0,0 +1,133 @@
+package org.dromara.stgl.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.stgl.domain.StglMember;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 社团成员视图对象 stgl_member
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = StglMember.class)
+public class StglMemberVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @ExcelProperty(value = "主键ID")
+    private Long id;
+
+    /**
+     * 成员类型(1-社团成员 2-志愿者)
+     */
+    @ExcelProperty(value = "成员类型")
+    private Integer memberType;
+
+    /**
+     * 成员类型名称
+     */
+    @ExcelProperty(value = "成员类型名称")
+    private String memberTypeName;
+
+    /**
+     * 关联ID(社团ID或志愿者队伍ID)
+     */
+    @ExcelProperty(value = "关联ID")
+    private Long relationId;
+
+    /**
+     * 关联名称(社团名称或志愿者队伍名称)
+     */
+    @ExcelProperty(value = "所属组织")
+    private String relationName;
+
+    /**
+     * 用户ID
+     */
+    @ExcelProperty(value = "用户ID")
+    private Long userId;
+
+    /**
+     * 学号
+     */
+    @ExcelProperty(value = "学号")
+    private String studentNo;
+
+    /**
+     * 学生姓名
+     */
+    @ExcelProperty(value = "学生姓名")
+    private String studentName;
+
+    /**
+     * 角色类型(1-社长 2-副社长 3-成员)
+     */
+    @ExcelProperty(value = "角色类型")
+    private Integer roleType;
+
+    /**
+     * 角色类型名称
+     */
+    @ExcelProperty(value = "角色名称")
+    private String roleTypeName;
+
+    /**
+     * 加入时间
+     */
+    @ExcelProperty(value = "加入时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date joinTime;
+
+    /**
+     * 状态(1-正常 0-退出)
+     */
+    @ExcelProperty(value = "状态")
+    private Integer status;
+
+    /**
+     * 状态名称
+     */
+    @ExcelProperty(value = "状态名称")
+    private String statusName;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+    /**
+     * 创建者
+     */
+    private Long createBy;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /**
+     * 更新者
+     */
+    private Long updateBy;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+} 

+ 15 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/mapper/StglClubMapper.java

@@ -0,0 +1,15 @@
+package org.dromara.stgl.mapper;
+
+import org.dromara.stgl.domain.StglClub;
+import org.dromara.stgl.domain.vo.StglClubVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 社团信息Mapper接口
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+public interface StglClubMapper extends BaseMapperPlus<StglClub, StglClubVo> {
+
+} 

+ 15 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/mapper/StglMemberMapper.java

@@ -0,0 +1,15 @@
+package org.dromara.stgl.mapper;
+
+import org.dromara.stgl.domain.StglMember;
+import org.dromara.stgl.domain.vo.StglMemberVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 社团成员Mapper接口
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+public interface StglMemberMapper extends BaseMapperPlus<StglMember, StglMemberVo> {
+
+} 

+ 88 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglClubRegisterService.java

@@ -0,0 +1,88 @@
+package org.dromara.stgl.service;
+
+import org.dromara.stgl.domain.vo.StglClubRegisterVo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.List;
+
+/**
+ * 社团报名大厅Service接口
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+public interface IStglClubRegisterService {
+
+    /**
+     * 分页查询社团报名大厅列表
+     *
+     * @param clubType  社团类型
+     * @param clubName  社团名称
+     * @param pageQuery 分页参数
+     * @return 社团报名大厅分页列表
+     */
+    TableDataInfo<StglClubRegisterVo> queryPageList(String clubType, String clubName, PageQuery pageQuery);
+
+    /**
+     * 查询社团报名大厅列表
+     *
+     * @param clubType 社团类型
+     * @param clubName 社团名称
+     * @return 社团报名大厅列表
+     */
+    List<StglClubRegisterVo> queryList(String clubType, String clubName);
+
+    /**
+     * 查询社团详细信息(用于报名)
+     *
+     * @param clubId 社团ID
+     * @return 社团详细信息
+     */
+    StglClubRegisterVo queryClubDetail(Long clubId);
+
+    /**
+     * 报名加入社团
+     *
+     * @param clubId 社团ID
+     * @param userId 用户ID
+     * @return 是否报名成功
+     */
+    Boolean registerClub(Long clubId, Long userId);
+
+    /**
+     * 退出社团
+     *
+     * @param clubId 社团ID
+     * @param userId 用户ID
+     * @return 是否退出成功
+     */
+    Boolean quitClub(Long clubId, Long userId);
+
+    /**
+     * 查询我参与的社团列表
+     *
+     * @param userId 用户ID
+     * @return 社团列表
+     */
+    List<StglClubRegisterVo> queryMyClubs(Long userId);
+
+    /**
+     * 检查是否已报名某个社团
+     *
+     * @param clubId 社团ID
+     * @param userId 用户ID
+     * @return 是否已报名
+     */
+    Boolean checkRegistered(Long clubId, Long userId);
+
+    /**
+     * 根据社团类型查询推荐社团
+     *
+     * @param clubType 社团类型
+     * @param limit    推荐数量
+     * @return 推荐社团列表
+     */
+    List<StglClubRegisterVo> queryRecommendClubs(String clubType, Integer limit);
+
+} 

+ 109 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglClubService.java

@@ -0,0 +1,109 @@
+package org.dromara.stgl.service;
+
+import org.dromara.stgl.domain.vo.StglClubVo;
+import org.dromara.stgl.domain.bo.StglClubBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 社团信息Service接口
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+public interface IStglClubService {
+
+    /**
+     * 查询社团信息
+     *
+     * @param id 主键
+     * @return 社团信息
+     */
+    StglClubVo queryById(Long id);
+
+    /**
+     * 分页查询社团信息列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 社团信息分页列表
+     */
+    TableDataInfo<StglClubVo> queryPageList(StglClubBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的社团信息列表
+     *
+     * @param bo 查询条件
+     * @return 社团信息列表
+     */
+    List<StglClubVo> queryList(StglClubBo bo);
+
+    /**
+     * 新增社团信息
+     *
+     * @param bo 社团信息
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(StglClubBo bo);
+
+    /**
+     * 修改社团信息
+     *
+     * @param bo 社团信息
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(StglClubBo bo);
+
+    /**
+     * 校验并批量删除社团信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    /**
+     * 查询可用的社团选项
+     *
+     * @return 社团选项列表
+     */
+    List<StglClubVo> queryAvailableOptions();
+
+    /**
+     * 根据社团类型查询社团列表
+     *
+     * @param clubType 社团类型
+     * @return 社团列表
+     */
+    List<StglClubVo> queryByClubType(String clubType);
+
+    /**
+     * 查询我管理的社团列表
+     *
+     * @return 社团列表
+     */
+    List<StglClubVo> queryMyClubs();
+
+    /**
+     * 检查社团名称是否重复
+     *
+     * @param clubName 社团名称
+     * @param excludeId 排除的ID(修改时使用)
+     * @return 是否重复
+     */
+    Boolean checkClubNameUnique(String clubName, Long excludeId);
+
+    /**
+     * 启用/禁用社团
+     *
+     * @param id 社团ID
+     * @param status 状态
+     * @return 是否操作成功
+     */
+    Boolean changeStatus(Long id, Integer status);
+
+} 

+ 123 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglMemberService.java

@@ -0,0 +1,123 @@
+package org.dromara.stgl.service;
+
+import org.dromara.stgl.domain.vo.StglMemberVo;
+import org.dromara.stgl.domain.bo.StglMemberBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 社团成员Service接口
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+public interface IStglMemberService {
+
+    /**
+     * 查询社团成员
+     *
+     * @param id 主键
+     * @return 社团成员
+     */
+    StglMemberVo queryById(Long id);
+
+    /**
+     * 分页查询社团成员列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 社团成员分页列表
+     */
+    TableDataInfo<StglMemberVo> queryPageList(StglMemberBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的社团成员列表
+     *
+     * @param bo 查询条件
+     * @return 社团成员列表
+     */
+    List<StglMemberVo> queryList(StglMemberBo bo);
+
+    /**
+     * 新增社团成员
+     *
+     * @param bo 社团成员
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(StglMemberBo bo);
+
+    /**
+     * 修改社团成员
+     *
+     * @param bo 社团成员
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(StglMemberBo bo);
+
+    /**
+     * 校验并批量删除社团成员
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    /**
+     * 根据社团ID查询成员列表
+     *
+     * @param clubId 社团ID
+     * @return 成员列表
+     */
+    List<StglMemberVo> queryByClubId(Long clubId);
+
+    /**
+     * 根据用户ID查询参与的社团列表
+     *
+     * @param userId 用户ID
+     * @return 社团成员关系列表
+     */
+    List<StglMemberVo> queryByUserId(Long userId);
+
+    /**
+     * 检查用户是否已是某个社团/队伍的成员
+     *
+     * @param memberType 成员类型
+     * @param relationId 关联ID
+     * @param userId     用户ID
+     * @return 是否已是成员
+     */
+    Boolean checkMemberExists(Integer memberType, Long relationId, Long userId);
+
+    /**
+     * 批量添加成员
+     *
+     * @param memberType 成员类型
+     * @param relationId 关联ID
+     * @param userIds    用户ID列表
+     * @param roleType   角色类型
+     * @return 是否添加成功
+     */
+    Boolean batchAddMembers(Integer memberType, Long relationId, List<Long> userIds, Integer roleType);
+
+    /**
+     * 更新成员角色
+     *
+     * @param id       成员ID
+     * @param roleType 角色类型
+     * @return 是否更新成功
+     */
+    Boolean updateMemberRole(Long id, Integer roleType);
+
+    /**
+     * 退出社团/队伍
+     *
+     * @param id 成员ID
+     * @return 是否退出成功
+     */
+    Boolean quitMember(Long id);
+
+} 

+ 306 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglClubRegisterServiceImpl.java

@@ -0,0 +1,306 @@
+package org.dromara.stgl.service.impl;
+
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.dromara.stgl.domain.vo.StglClubRegisterVo;
+import org.dromara.stgl.domain.StglClub;
+import org.dromara.stgl.domain.StglMember;
+import org.dromara.stgl.mapper.StglClubMapper;
+import org.dromara.stgl.mapper.StglMemberMapper;
+import org.dromara.stgl.service.IStglClubRegisterService;
+import org.dromara.common.satoken.utils.LoginHelper;
+
+import java.util.List;
+import java.util.Date;
+import java.util.stream.Collectors;
+
+/**
+ * 社团报名大厅Service业务层处理
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@RequiredArgsConstructor
+@Service
+public class StglClubRegisterServiceImpl implements IStglClubRegisterService {
+
+    private final StglClubMapper clubMapper;
+    private final StglMemberMapper memberMapper;
+
+    /**
+     * 分页查询社团报名大厅列表
+     *
+     * @param clubType  社团类型
+     * @param clubName  社团名称
+     * @param pageQuery 分页参数
+     * @return 社团报名大厅分页列表
+     */
+    @Override
+    public TableDataInfo<StglClubRegisterVo> queryPageList(String clubType, String clubName, PageQuery pageQuery) {
+        LambdaQueryWrapper<StglClub> lqw = buildQueryWrapper(clubType, clubName);
+        Page<StglClub> page = clubMapper.selectPage(pageQuery.build(), lqw);
+        
+        List<StglClubRegisterVo> voList = convertToRegisterVo(page.getRecords());
+        
+        Page<StglClubRegisterVo> result = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
+        result.setRecords(voList);
+        
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询社团报名大厅列表
+     *
+     * @param clubType 社团类型
+     * @param clubName 社团名称
+     * @return 社团报名大厅列表
+     */
+    @Override
+    public List<StglClubRegisterVo> queryList(String clubType, String clubName) {
+        LambdaQueryWrapper<StglClub> lqw = buildQueryWrapper(clubType, clubName);
+        List<StglClub> clubs = clubMapper.selectList(lqw);
+        return convertToRegisterVo(clubs);
+    }
+
+    private LambdaQueryWrapper<StglClub> buildQueryWrapper(String clubType, String clubName) {
+        LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglClub::getStatus, 1); // 只查询正常状态的社团
+        lqw.eq(StringUtils.isNotBlank(clubType), StglClub::getClubType, clubType);
+        lqw.like(StringUtils.isNotBlank(clubName), StglClub::getClubName, clubName);
+        lqw.orderByDesc(StglClub::getCreateTime);
+        return lqw;
+    }
+
+    private List<StglClubRegisterVo> convertToRegisterVo(List<StglClub> clubs) {
+        Long currentUserId = null;
+        try {
+            currentUserId = LoginHelper.getUserId();
+        } catch (Exception e) {
+            // 未登录用户
+        }
+        
+        final Long userId = currentUserId;
+        
+        return clubs.stream().map(club -> {
+            StglClubRegisterVo vo = new StglClubRegisterVo();
+            vo.setId(club.getId());
+            vo.setClubName(club.getClubName());
+            vo.setClubType(club.getClubType());
+            vo.setEstablishDate(club.getEstablishDate());
+            vo.setDescription(club.getDescription());
+            vo.setLogoUrl(club.getLogoUrl());
+            vo.setPresidentName(club.getPresidentName());
+            vo.setPresidentDept(club.getPresidentDept());
+            vo.setAdvisorName(club.getAdvisorName());
+            vo.setAdvisorDept(club.getAdvisorDept());
+            vo.setMemberLimit(club.getMemberLimit());
+            vo.setRecruitCycle(club.getRecruitCycle());
+            vo.setRecruitTime(club.getRecruitTime());
+            vo.setActivityFrequency(club.getActivityFrequency());
+            
+                         // 查询当前成员数量
+             LambdaQueryWrapper<StglMember> memberCountLqw = Wrappers.lambdaQuery();
+             memberCountLqw.eq(StglMember::getMemberType, 1);
+             memberCountLqw.eq(StglMember::getRelationId, club.getId());
+             memberCountLqw.eq(StglMember::getStatus, 1);
+             long memberCount = memberMapper.selectCount(memberCountLqw);
+             vo.setCurrentMemberCount((int) memberCount);
+             
+             // 检查是否可报名
+             boolean canRegister = club.getMemberLimit() == null || club.getMemberLimit() == 0 || memberCount < club.getMemberLimit();
+             vo.setCanRegister(canRegister);
+             
+             // 检查当前用户是否已报名
+             if (userId != null) {
+                 LambdaQueryWrapper<StglMember> userMemberLqw = Wrappers.lambdaQuery();
+                 userMemberLqw.eq(StglMember::getMemberType, 1);
+                 userMemberLqw.eq(StglMember::getRelationId, club.getId());
+                 userMemberLqw.eq(StglMember::getUserId, userId);
+                 userMemberLqw.eq(StglMember::getStatus, 1);
+                 long registeredCount = memberMapper.selectCount(userMemberLqw);
+                 vo.setHasRegistered(registeredCount > 0);
+                 vo.setRegistrationStatus(registeredCount > 0 ? 1 : 0);
+             } else {
+                 vo.setHasRegistered(false);
+                 vo.setRegistrationStatus(0);
+             }
+            
+            return vo;
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * 查询社团详细信息(用于报名)
+     *
+     * @param clubId 社团ID
+     * @return 社团详细信息
+     */
+    @Override
+    public StglClubRegisterVo queryClubDetail(Long clubId) {
+        StglClub club = clubMapper.selectById(clubId);
+        if (club == null) {
+            return null;
+        }
+        return convertToRegisterVo(List.of(club)).get(0);
+    }
+
+    /**
+     * 报名加入社团
+     *
+     * @param clubId 社团ID
+     * @param userId 用户ID
+     * @return 是否报名成功
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean registerClub(Long clubId, Long userId) {
+        // 检查社团是否存在
+        StglClub club = clubMapper.selectById(clubId);
+        if (club == null || club.getStatus() != 1) {
+            throw new RuntimeException("社团不存在或已停用");
+        }
+        
+        // 检查是否已是成员
+        LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglMember::getMemberType, 1);
+        lqw.eq(StglMember::getRelationId, clubId);
+        lqw.eq(StglMember::getUserId, userId);
+        lqw.eq(StglMember::getStatus, 1);
+        long count = memberMapper.selectCount(lqw);
+        if (count > 0) {
+            throw new RuntimeException("您已是该社团的成员");
+        }
+        
+        // 检查成员上限
+        if (club.getMemberLimit() != null && club.getMemberLimit() > 0) {
+            LambdaQueryWrapper<StglMember> memberLqw = Wrappers.lambdaQuery();
+            memberLqw.eq(StglMember::getMemberType, 1);
+            memberLqw.eq(StglMember::getRelationId, clubId);
+            memberLqw.eq(StglMember::getStatus, 1);
+            long memberCount = memberMapper.selectCount(memberLqw);
+            if (memberCount >= club.getMemberLimit()) {
+                throw new RuntimeException("该社团成员已满,无法加入");
+            }
+        }
+        
+        // 创建成员记录
+        StglMember member = new StglMember();
+        member.setMemberType(1); // 社团成员
+        member.setRelationId(clubId);
+        member.setUserId(userId);
+        member.setRoleType(3); // 普通成员
+        member.setJoinTime(new Date());
+        member.setStatus(1);
+        
+        return memberMapper.insert(member) > 0;
+    }
+
+    /**
+     * 退出社团
+     *
+     * @param clubId 社团ID
+     * @param userId 用户ID
+     * @return 是否退出成功
+     */
+    @Override
+    public Boolean quitClub(Long clubId, Long userId) {
+        LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglMember::getMemberType, 1);
+        lqw.eq(StglMember::getRelationId, clubId);
+        lqw.eq(StglMember::getUserId, userId);
+        lqw.eq(StglMember::getStatus, 1);
+        
+        StglMember member = memberMapper.selectOne(lqw);
+        if (member == null) {
+            throw new RuntimeException("您不是该社团的成员");
+        }
+        
+        // 检查是否是社长或副社长
+        if (member.getRoleType() != null && member.getRoleType() <= 2) {
+            throw new RuntimeException("社长和副社长不能直接退出,请先转让职务");
+        }
+        
+        member.setStatus(0);
+        return memberMapper.updateById(member) > 0;
+    }
+
+    /**
+     * 查询我参与的社团列表
+     *
+     * @param userId 用户ID
+     * @return 社团列表
+     */
+    @Override
+    public List<StglClubRegisterVo> queryMyClubs(Long userId) {
+        // 查询用户参与的社团ID
+        LambdaQueryWrapper<StglMember> memberLqw = Wrappers.lambdaQuery();
+        memberLqw.eq(StglMember::getMemberType, 1);
+        memberLqw.eq(StglMember::getUserId, userId);
+        memberLqw.eq(StglMember::getStatus, 1);
+        List<StglMember> members = memberMapper.selectList(memberLqw);
+        
+        if (members.isEmpty()) {
+            return List.of();
+        }
+        
+        List<Long> clubIds = members.stream().map(StglMember::getRelationId).collect(Collectors.toList());
+        
+        // 查询社团信息
+        LambdaQueryWrapper<StglClub> clubLqw = Wrappers.lambdaQuery();
+        clubLqw.in(StglClub::getId, clubIds);
+        clubLqw.eq(StglClub::getStatus, 1);
+        clubLqw.orderByDesc(StglClub::getCreateTime);
+        List<StglClub> clubs = clubMapper.selectList(clubLqw);
+        
+        return convertToRegisterVo(clubs);
+    }
+
+    /**
+     * 检查是否已报名某个社团
+     *
+     * @param clubId 社团ID
+     * @param userId 用户ID
+     * @return 是否已报名
+     */
+    @Override
+    public Boolean checkRegistered(Long clubId, Long userId) {
+        LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglMember::getMemberType, 1);
+        lqw.eq(StglMember::getRelationId, clubId);
+        lqw.eq(StglMember::getUserId, userId);
+        lqw.eq(StglMember::getStatus, 1);
+        long count = memberMapper.selectCount(lqw);
+        return count > 0;
+    }
+
+    /**
+     * 根据社团类型查询推荐社团
+     *
+     * @param clubType 社团类型
+     * @param limit    推荐数量
+     * @return 推荐社团列表
+     */
+    @Override
+    public List<StglClubRegisterVo> queryRecommendClubs(String clubType, Integer limit) {
+        LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglClub::getStatus, 1);
+        if (StringUtils.isNotBlank(clubType)) {
+            lqw.eq(StglClub::getClubType, clubType);
+        }
+        lqw.orderByDesc(StglClub::getCreateTime);
+        if (limit != null && limit > 0) {
+            lqw.last("LIMIT " + limit);
+        }
+        
+        List<StglClub> clubs = clubMapper.selectList(lqw);
+        return convertToRegisterVo(clubs);
+    }
+
+} 

+ 233 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglClubServiceImpl.java

@@ -0,0 +1,233 @@
+package org.dromara.stgl.service.impl;
+
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.dromara.stgl.domain.bo.StglClubBo;
+import org.dromara.stgl.domain.vo.StglClubVo;
+import org.dromara.stgl.domain.StglClub;
+import org.dromara.stgl.mapper.StglClubMapper;
+import org.dromara.stgl.service.IStglClubService;
+import org.dromara.common.satoken.utils.LoginHelper;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 社团信息Service业务层处理
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@RequiredArgsConstructor
+@Service
+public class StglClubServiceImpl implements IStglClubService {
+
+    private final StglClubMapper baseMapper;
+
+    /**
+     * 查询社团信息
+     *
+     * @param id 主键
+     * @return 社团信息
+     */
+    @Override
+    public StglClubVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 分页查询社团信息列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 社团信息分页列表
+     */
+    @Override
+    public TableDataInfo<StglClubVo> queryPageList(StglClubBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<StglClub> lqw = buildQueryWrapper(bo);
+        Page<StglClubVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的社团信息列表
+     *
+     * @param bo 查询条件
+     * @return 社团信息列表
+     */
+    @Override
+    public List<StglClubVo> queryList(StglClubBo bo) {
+        LambdaQueryWrapper<StglClub> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<StglClub> buildQueryWrapper(StglClubBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getClubName()), StglClub::getClubName, bo.getClubName());
+        lqw.eq(StringUtils.isNotBlank(bo.getClubType()), StglClub::getClubType, bo.getClubType());
+        lqw.like(StringUtils.isNotBlank(bo.getPresidentName()), StglClub::getPresidentName, bo.getPresidentName());
+        lqw.like(StringUtils.isNotBlank(bo.getPresidentStudentNo()), StglClub::getPresidentStudentNo, bo.getPresidentStudentNo());
+        lqw.like(StringUtils.isNotBlank(bo.getAdvisorName()), StglClub::getAdvisorName, bo.getAdvisorName());
+        lqw.eq(bo.getStatus() != null, StglClub::getStatus, bo.getStatus());
+        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
+            StglClub::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
+        lqw.orderByDesc(StglClub::getCreateTime);
+        return lqw;
+    }
+
+    /**
+     * 新增社团信息
+     *
+     * @param bo 社团信息
+     * @return 是否新增成功
+     */
+    @Override
+    public Boolean insertByBo(StglClubBo bo) {
+        StglClub add = MapstructUtils.convert(bo, StglClub.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 修改社团信息
+     *
+     * @param bo 社团信息
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(StglClubBo bo) {
+        StglClub update = MapstructUtils.convert(bo, StglClub.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(StglClub entity){
+        // 检查社团名称是否重复
+        if (StringUtils.isNotBlank(entity.getClubName())) {
+            LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
+            lqw.eq(StglClub::getClubName, entity.getClubName());
+            if (entity.getId() != null) {
+                lqw.ne(StglClub::getId, entity.getId());
+            }
+            long count = baseMapper.selectCount(lqw);
+            if (count > 0) {
+                throw new RuntimeException("社团名称已存在,请重新输入");
+            }
+        }
+        
+        // 设置默认状态
+        if (entity.getStatus() == null) {
+            entity.setStatus(1);
+        }
+    }
+
+    /**
+     * 校验并批量删除社团信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            // 可以添加删除前的业务校验
+        }
+        return baseMapper.deleteBatchIds(ids) > 0;
+    }
+
+    /**
+     * 查询可用的社团选项
+     *
+     * @return 社团选项列表
+     */
+    @Override
+    public List<StglClubVo> queryAvailableOptions() {
+        LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglClub::getStatus, 1);
+        lqw.select(StglClub::getId, StglClub::getClubName, StglClub::getClubType);
+        lqw.orderByAsc(StglClub::getClubName);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    /**
+     * 根据社团类型查询社团列表
+     *
+     * @param clubType 社团类型
+     * @return 社团列表
+     */
+    @Override
+    public List<StglClubVo> queryByClubType(String clubType) {
+        LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglClub::getClubType, clubType);
+        lqw.eq(StglClub::getStatus, 1);
+        lqw.orderByAsc(StglClub::getClubName);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    /**
+     * 查询我管理的社团列表
+     *
+     * @return 社团列表
+     */
+    @Override
+    public List<StglClubVo> queryMyClubs() {
+        // 根据当前用户查询其管理的社团
+        Long userId = LoginHelper.getUserId();
+        LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglClub::getCreateBy, userId);
+        lqw.eq(StglClub::getStatus, 1);
+        lqw.orderByDesc(StglClub::getCreateTime);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    /**
+     * 检查社团名称是否重复
+     *
+     * @param clubName 社团名称
+     * @param excludeId 排除的ID(修改时使用)
+     * @return 是否重复
+     */
+    @Override
+    public Boolean checkClubNameUnique(String clubName, Long excludeId) {
+        LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglClub::getClubName, clubName);
+        if (excludeId != null) {
+            lqw.ne(StglClub::getId, excludeId);
+        }
+        long count = baseMapper.selectCount(lqw);
+        return count == 0;
+    }
+
+    /**
+     * 启用/禁用社团
+     *
+     * @param id 社团ID
+     * @param status 状态
+     * @return 是否操作成功
+     */
+    @Override
+    public Boolean changeStatus(Long id, Integer status) {
+        StglClub club = new StglClub();
+        club.setId(id);
+        club.setStatus(status);
+        return baseMapper.updateById(club) > 0;
+    }
+
+} 

+ 272 - 0
backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglMemberServiceImpl.java

@@ -0,0 +1,272 @@
+package org.dromara.stgl.service.impl;
+
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.dromara.stgl.domain.bo.StglMemberBo;
+import org.dromara.stgl.domain.vo.StglMemberVo;
+import org.dromara.stgl.domain.StglMember;
+import org.dromara.stgl.mapper.StglMemberMapper;
+import org.dromara.stgl.service.IStglMemberService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+import java.util.Date;
+import java.util.stream.Collectors;
+
+/**
+ * 社团成员Service业务层处理
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@RequiredArgsConstructor
+@Service
+public class StglMemberServiceImpl implements IStglMemberService {
+
+    private final StglMemberMapper baseMapper;
+
+    /**
+     * 查询社团成员
+     *
+     * @param id 主键
+     * @return 社团成员
+     */
+    @Override
+    public StglMemberVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 分页查询社团成员列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 社团成员分页列表
+     */
+    @Override
+    public TableDataInfo<StglMemberVo> queryPageList(StglMemberBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<StglMember> lqw = buildQueryWrapper(bo);
+        Page<StglMemberVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的社团成员列表
+     *
+     * @param bo 查询条件
+     * @return 社团成员列表
+     */
+    @Override
+    public List<StglMemberVo> queryList(StglMemberBo bo) {
+        LambdaQueryWrapper<StglMember> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<StglMember> buildQueryWrapper(StglMemberBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
+        lqw.eq(bo.getMemberType() != null, StglMember::getMemberType, bo.getMemberType());
+        lqw.eq(bo.getRelationId() != null, StglMember::getRelationId, bo.getRelationId());
+        lqw.eq(bo.getUserId() != null, StglMember::getUserId, bo.getUserId());
+        lqw.like(StringUtils.isNotBlank(bo.getStudentNo()), StglMember::getStudentNo, bo.getStudentNo());
+        lqw.like(StringUtils.isNotBlank(bo.getStudentName()), StglMember::getStudentName, bo.getStudentName());
+        lqw.eq(bo.getRoleType() != null, StglMember::getRoleType, bo.getRoleType());
+        lqw.eq(bo.getStatus() != null, StglMember::getStatus, bo.getStatus());
+        lqw.between(params.get("beginJoinTime") != null && params.get("endJoinTime") != null,
+            StglMember::getJoinTime, params.get("beginJoinTime"), params.get("endJoinTime"));
+        lqw.orderByDesc(StglMember::getJoinTime);
+        return lqw;
+    }
+
+    /**
+     * 新增社团成员
+     *
+     * @param bo 社团成员
+     * @return 是否新增成功
+     */
+    @Override
+    public Boolean insertByBo(StglMemberBo bo) {
+        StglMember add = MapstructUtils.convert(bo, StglMember.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 修改社团成员
+     *
+     * @param bo 社团成员
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(StglMemberBo bo) {
+        StglMember update = MapstructUtils.convert(bo, StglMember.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(StglMember entity){
+        // 检查用户是否已是成员
+        if (entity.getMemberType() != null && entity.getRelationId() != null && entity.getUserId() != null) {
+            LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
+            lqw.eq(StglMember::getMemberType, entity.getMemberType());
+            lqw.eq(StglMember::getRelationId, entity.getRelationId());
+            lqw.eq(StglMember::getUserId, entity.getUserId());
+            if (entity.getId() != null) {
+                lqw.ne(StglMember::getId, entity.getId());
+            }
+            long count = baseMapper.selectCount(lqw);
+            if (count > 0) {
+                throw new RuntimeException("用户已是该组织的成员,不能重复添加");
+            }
+        }
+        
+        // 设置默认值
+        if (entity.getJoinTime() == null) {
+            entity.setJoinTime(new Date());
+        }
+        if (entity.getStatus() == null) {
+            entity.setStatus(1);
+        }
+        if (entity.getRoleType() == null) {
+            entity.setRoleType(3); // 默认为普通成员
+        }
+    }
+
+    /**
+     * 校验并批量删除社团成员
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            // 可以添加删除前的业务校验
+        }
+        return baseMapper.deleteBatchIds(ids) > 0;
+    }
+
+    /**
+     * 根据社团ID查询成员列表
+     *
+     * @param clubId 社团ID
+     * @return 成员列表
+     */
+    @Override
+    public List<StglMemberVo> queryByClubId(Long clubId) {
+        LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglMember::getMemberType, 1); // 社团成员
+        lqw.eq(StglMember::getRelationId, clubId);
+        lqw.eq(StglMember::getStatus, 1);
+        lqw.orderByAsc(StglMember::getRoleType).orderByAsc(StglMember::getJoinTime);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    /**
+     * 根据用户ID查询参与的社团列表
+     *
+     * @param userId 用户ID
+     * @return 社团成员关系列表
+     */
+    @Override
+    public List<StglMemberVo> queryByUserId(Long userId) {
+        LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglMember::getUserId, userId);
+        lqw.eq(StglMember::getStatus, 1);
+        lqw.orderByDesc(StglMember::getJoinTime);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    /**
+     * 检查用户是否已是某个社团/队伍的成员
+     *
+     * @param memberType 成员类型
+     * @param relationId 关联ID
+     * @param userId     用户ID
+     * @return 是否已是成员
+     */
+    @Override
+    public Boolean checkMemberExists(Integer memberType, Long relationId, Long userId) {
+        LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StglMember::getMemberType, memberType);
+        lqw.eq(StglMember::getRelationId, relationId);
+        lqw.eq(StglMember::getUserId, userId);
+        lqw.eq(StglMember::getStatus, 1);
+        long count = baseMapper.selectCount(lqw);
+        return count > 0;
+    }
+
+    /**
+     * 批量添加成员
+     *
+     * @param memberType 成员类型
+     * @param relationId 关联ID
+     * @param userIds    用户ID列表
+     * @param roleType   角色类型
+     * @return 是否添加成功
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean batchAddMembers(Integer memberType, Long relationId, List<Long> userIds, Integer roleType) {
+        Date now = new Date();
+        List<StglMember> members = userIds.stream().map(userId -> {
+            StglMember member = new StglMember();
+            member.setMemberType(memberType);
+            member.setRelationId(relationId);
+            member.setUserId(userId);
+            member.setRoleType(roleType != null ? roleType : 3);
+            member.setJoinTime(now);
+            member.setStatus(1);
+            return member;
+        }).collect(Collectors.toList());
+        
+        return baseMapper.insertBatch(members);
+    }
+
+    /**
+     * 更新成员角色
+     *
+     * @param id       成员ID
+     * @param roleType 角色类型
+     * @return 是否更新成功
+     */
+    @Override
+    public Boolean updateMemberRole(Long id, Integer roleType) {
+        StglMember member = new StglMember();
+        member.setId(id);
+        member.setRoleType(roleType);
+        return baseMapper.updateById(member) > 0;
+    }
+
+    /**
+     * 退出社团/队伍
+     *
+     * @param id 成员ID
+     * @return 是否退出成功
+     */
+    @Override
+    public Boolean quitMember(Long id) {
+        StglMember member = new StglMember();
+        member.setId(id);
+        member.setStatus(0);
+        return baseMapper.updateById(member) > 0;
+    }
+
+} 

+ 6 - 9
docs/开发文档/API/API文档总览.md

@@ -6,9 +6,7 @@
 
 请参考 [API文档基础规范](./API文档基础规范.md) 了解通用的API调用规范、认证方式和响应格式。
 
-<<<<<<< HEAD
 ## API模块列表
-=======
 - [学生信息管理API](./学生信息管理API.md)
 - [学生信息收集批次管理API](./学生信息收集批次管理API.md)
 - [班级信息管理API](./班级信息管理API.md)
@@ -17,7 +15,6 @@
 - [宿舍管理员信息API](./宿舍管理员信息API.md)
 - [宿舍管理员授权API](./宿舍管理员授权API.md)
 - [学生管理员授权关系API](./学生管理员授权关系API.md)
->>>>>>> e450a8ffe73adab129a8f940bff3316c0361aa7a
 
 ### 1. 用户认证登录
 
@@ -41,9 +38,9 @@
 
 [心理健康测评API](./心理健康测评API.md) - 包含测评问卷管理、测评结果分析等接口。
 
-<<<<<<< HEAD
+
 ### 4. 统计报表
-=======
+
 ## 宿舍管理员信息API
 
 - [宿舍管理员信息API](./宿舍管理员信息API.md):包含宿舍管理员信息的增删改查接口
@@ -68,7 +65,7 @@
 **详细文档**: [宿舍管理员信息API.md](./宿舍管理员信息API.md)
 
 ## 企业信息管理API
->>>>>>> e450a8ffe73adab129a8f940bff3316c0361aa7a
+
 
 [统计报表API](./统计报表API.md) - 包含各类统计数据查询接口。
 
@@ -89,13 +86,13 @@
 
 ## 更新历史
 
-<<<<<<< HEAD
+
 | 日期 | 版本 | 更新内容 | 更新人 |
 |------|------|---------|-------|
 | 2025-07-01 | 1.0 | 初始版本 | 系统管理员 |
 | 2025-07-15 | 1.1 | 添加心理健康测评API | 张工 |
 | 2025-07-30 | 1.2 | 添加预约限制功能API | Cursor |
-=======
+
 **详细文档**: [企业信息管理API.md](./企业信息管理API.md)
 
 - [获取当前正在教学的班主任信息](/docs/开发文档/API/宿舍管理员信息API.md#获取当前正在教学的班主任信息)
@@ -144,4 +141,4 @@
 | [班级干部信息管理API](./班级干部信息管理API.md) | 班级干部信息管理(含用户角色关联) | ✅ 完成 | 2025-01-27 |
 | [班干部管理API](./班干部管理API.md) | 班级干部职务管理 | ✅ 完成 | 2025-01-27 |
 | [班级教师关联管理API](./班级教师关联管理API.md) | 班主任辅导员关联关系 | ✅ 完成 | 2025-01-27 |
->>>>>>> e450a8ffe73adab129a8f940bff3316c0361aa7a
+

+ 962 - 0
docs/开发文档/API/社团管理API.md

@@ -0,0 +1,962 @@
+# 社团管理API文档
+
+## 📋 文档信息
+
+- **模块名称**: 社团管理系统
+- **接口前缀**: `/stgl`
+- **版本**: v1.0
+- **创建时间**: 2025-01-15
+- **作者**: Cursor AI
+- **权限验证**: Sa-Token
+
+## 🎯 功能概述
+
+社团管理系统提供完整的校园社团管理功能,包括:
+
+1. **社团信息管理** - 社团基本信息的增删改查
+2. **社团成员管理** - 成员关系和角色管理
+3. **社团报名大厅** - 学生浏览和报名社团功能
+
+## 🔐 权限说明
+
+### 权限前缀
+- `stgl:club:*` - 社团信息管理权限
+- `stgl:member:*` - 社团成员管理权限
+- `stgl:register:*` - 社团报名大厅权限
+
+### 角色说明
+- **系统管理员**: 拥有所有社团管理权限
+- **社长**: 拥有所管理社团的完整权限
+- **副社长**: 拥有所管理社团的部分权限
+- **学生**: 拥有浏览和报名权限
+
+## 📊 数据模型
+
+### 社团信息表 (stgl_club)
+```sql
+CREATE TABLE `stgl_club` (
+  `id` bigint(20) NOT NULL COMMENT '主键ID',
+  `tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号',
+  `club_name` varchar(100) NOT NULL COMMENT '社团名称',
+  `club_type` varchar(50) NOT NULL COMMENT '社团类型',
+  `establish_date` date COMMENT '成立日期',
+  `description` text COMMENT '社团简介',
+  `president_name` varchar(50) COMMENT '社长姓名',
+  `member_limit` int DEFAULT 0 COMMENT '成员规模上限',
+  `status` tinyint DEFAULT 1 COMMENT '状态(1-正常 0-停用)',
+  -- 其他字段...
+);
+```
+
+### 成员关系表 (stgl_member)
+```sql
+CREATE TABLE `stgl_member` (
+  `id` bigint(20) NOT NULL COMMENT '主键ID',
+  `member_type` tinyint NOT NULL COMMENT '成员类型(1-社团成员 2-志愿者)',
+  `relation_id` bigint(20) NOT NULL COMMENT '关联ID(社团ID或志愿者队伍ID)',
+  `user_id` bigint(20) NOT NULL COMMENT '用户ID',
+  `student_no` varchar(20) COMMENT '学号',
+  `student_name` varchar(50) COMMENT '学生姓名',
+  `role_type` tinyint COMMENT '角色类型(1-社长 2-副社长 3-成员)',
+  `status` tinyint DEFAULT 1 COMMENT '状态(1-正常 0-退出)',
+  -- 其他字段...
+);
+```
+
+## 📋 API接口列表
+
+---
+
+## 1. 社团信息管理
+
+### 1.1 查询社团列表
+
+**接口地址**: `GET /stgl/club/list`
+
+**权限要求**: `stgl:club:list`
+
+**请求参数**:
+```json
+{
+  "pageNum": 1,
+  "pageSize": 10,
+  "clubName": "社团名称(模糊查询)",
+  "clubType": "社团类型",
+  "presidentName": "社长姓名(模糊查询)",
+  "status": 1,
+  "beginCreateTime": "2025-01-01",
+  "endCreateTime": "2025-12-31"
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": {
+    "total": 100,
+    "rows": [
+      {
+        "id": 1,
+        "clubName": "智能科技社团",
+        "clubType": "学术科技类",
+        "establishDate": "2025-01-15",
+        "description": "专注于人工智能、机器学习等前沿科技领域...",
+        "presidentName": "张三",
+        "presidentDept": "计算机学院",
+        "memberLimit": 50,
+        "status": 1,
+        "createTime": "2025-01-15 10:00:00"
+      }
+    ]
+  }
+}
+```
+
+### 1.2 新增社团
+
+**接口地址**: `POST /stgl/club`
+
+**权限要求**: `stgl:club:add`
+
+**请求参数**:
+```json
+{
+  "clubName": "智能科技社团",
+  "clubType": "学术科技类",
+  "establishDate": "2025-01-15",
+  "description": "专注于人工智能、机器学习等前沿科技领域的学术研究和实践交流社团",
+  "email": "aitech@example.com",
+  "phone": "028-12345678",
+  "presidentName": "张三",
+  "presidentStudentNo": "20250001",
+  "presidentDept": "计算机学院",
+  "presidentMajor": "软件工程",
+  "presidentClass": "软工2501班",
+  "presidentPhone": "13800138001",
+  "advisorName": "李教授",
+  "advisorDept": "计算机学院",
+  "memberLimit": 50,
+  "recruitCycle": "每学期",
+  "recruitTime": "9月、3月",
+  "activityFrequency": "每周1-2次",
+  "fundingSources": "学校拨款,社团自筹",
+  "status": 1
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功"
+}
+```
+
+### 1.3 查询社团详情
+
+**接口地址**: `GET /stgl/club/{id}`
+
+**权限要求**: `stgl:club:query`
+
+**路径参数**:
+- `id`: 社团ID
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": {
+    "id": 1,
+    "clubName": "智能科技社团",
+    "clubType": "学术科技类",
+    "establishDate": "2025-01-15",
+    "description": "专注于人工智能、机器学习等前沿科技领域...",
+    "email": "aitech@example.com",
+    "phone": "028-12345678",
+    "logoUrl": "/upload/club/logo/2025/01/15/xxx.jpg",
+    "presidentName": "张三",
+    "presidentStudentNo": "20250001",
+    "presidentDept": "计算机学院",
+    "presidentMajor": "软件工程",
+    "presidentClass": "软工2501班",
+    "presidentPhone": "13800138001",
+    "vicePresidentName": "李四",
+    "vicePresidentStudentNo": "20250002",
+    "advisorName": "李教授",
+    "advisorDept": "计算机学院",
+    "memberLimit": 50,
+    "departments": "技术部、宣传部、组织部",
+    "recruitCycle": "每学期",
+    "recruitTime": "9月、3月",
+    "activityFrequency": "每周1-2次",
+    "fundingSources": "学校拨款,社团自筹",
+    "charterUrl": "/upload/club/charter/2025/01/15/xxx.pdf",
+    "status": 1,
+    "createTime": "2025-01-15 10:00:00",
+    "updateTime": "2025-01-15 14:30:00"
+  }
+}
+```
+
+### 1.4 修改社团信息
+
+**接口地址**: `PUT /stgl/club`
+
+**权限要求**: `stgl:club:edit`
+
+**请求参数**: 同新增社团,需包含id字段
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功"
+}
+```
+
+### 1.5 删除社团
+
+**接口地址**: `DELETE /stgl/club/{ids}`
+
+**权限要求**: `stgl:club:remove`
+
+**路径参数**:
+- `ids`: 社团ID数组,用逗号分隔
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功"
+}
+```
+
+### 1.6 查询可用社团选项
+
+**接口地址**: `GET /stgl/club/options`
+
+**权限要求**: `stgl:club:list`
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": [
+    {
+      "id": 1,
+      "clubName": "智能科技社团",
+      "clubType": "学术科技类"
+    },
+    {
+      "id": 2,
+      "clubName": "文学社",
+      "clubType": "文化艺术类"
+    }
+  ]
+}
+```
+
+### 1.7 根据社团类型查询社团列表
+
+**接口地址**: `GET /stgl/club/listByType/{clubType}`
+
+**权限要求**: `stgl:club:list`
+
+**路径参数**:
+- `clubType`: 社团类型
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": [
+    {
+      "id": 1,
+      "clubName": "智能科技社团",
+      "clubType": "学术科技类",
+      "presidentName": "张三"
+    }
+  ]
+}
+```
+
+### 1.8 查询我管理的社团列表
+
+**接口地址**: `GET /stgl/club/myClubs`
+
+**权限要求**: `stgl:club:list`
+
+**返回数据**: 同上
+
+### 1.9 检查社团名称是否重复
+
+**接口地址**: `GET /stgl/club/checkClubNameUnique`
+
+**权限要求**: `stgl:club:list`
+
+**请求参数**:
+```json
+{
+  "clubName": "社团名称",
+  "excludeId": 1  // 可选,修改时排除的ID
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": true  // true=唯一,false=重复
+}
+```
+
+### 1.10 启用/禁用社团
+
+**接口地址**: `PUT /stgl/club/changeStatus`
+
+**权限要求**: `stgl:club:edit`
+
+**请求参数**:
+```json
+{
+  "id": 1,
+  "status": 0  // 1-启用,0-禁用
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功"
+}
+```
+
+### 1.11 导出社团信息
+
+**接口地址**: `POST /stgl/club/export`
+
+**权限要求**: `stgl:club:export`
+
+**请求参数**: 同查询列表的筛选条件
+
+**返回数据**: Excel文件流
+
+---
+
+## 2. 社团成员管理
+
+### 2.1 查询成员列表
+
+**接口地址**: `GET /stgl/member/list`
+
+**权限要求**: `stgl:member:list`
+
+**请求参数**:
+```json
+{
+  "pageNum": 1,
+  "pageSize": 10,
+  "memberType": 1,  // 1-社团成员,2-志愿者
+  "relationId": 1,  // 社团ID或志愿者队伍ID
+  "studentNo": "学号(模糊查询)",
+  "studentName": "学生姓名(模糊查询)",
+  "roleType": 3,    // 1-社长,2-副社长,3-成员
+  "status": 1       // 1-正常,0-退出
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": {
+    "total": 50,
+    "rows": [
+      {
+        "id": 1,
+        "memberType": 1,
+        "memberTypeName": "社团成员",
+        "relationId": 1,
+        "relationName": "智能科技社团",
+        "userId": 1001,
+        "studentNo": "20250002",
+        "studentName": "李四",
+        "roleType": 3,
+        "roleTypeName": "成员",
+        "joinTime": "2025-01-15 14:30:00",
+        "status": 1,
+        "statusName": "正常"
+      }
+    ]
+  }
+}
+```
+
+### 2.2 新增成员
+
+**接口地址**: `POST /stgl/member`
+
+**权限要求**: `stgl:member:add`
+
+**请求参数**:
+```json
+{
+  "memberType": 1,     // 1-社团成员,2-志愿者
+  "relationId": 1,     // 社团ID或志愿者队伍ID
+  "userId": 1001,      // 用户ID
+  "studentNo": "20250002",
+  "studentName": "李四",
+  "roleType": 3,       // 1-社长,2-副社长,3-成员
+  "status": 1
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功"
+}
+```
+
+### 2.3 查询成员详情
+
+**接口地址**: `GET /stgl/member/{id}`
+
+**权限要求**: `stgl:member:query`
+
+**路径参数**:
+- `id`: 成员ID
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": {
+    "id": 1,
+    "memberType": 1,
+    "relationId": 1,
+    "userId": 1001,
+    "studentNo": "20250002",
+    "studentName": "李四",
+    "roleType": 3,
+    "joinTime": "2025-01-15 14:30:00",
+    "status": 1,
+    "remark": "表现优秀"
+  }
+}
+```
+
+### 2.4 修改成员信息
+
+**接口地址**: `PUT /stgl/member`
+
+**权限要求**: `stgl:member:edit`
+
+**请求参数**: 同新增成员,需包含id字段
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功"
+}
+```
+
+### 2.5 删除成员
+
+**接口地址**: `DELETE /stgl/member/{ids}`
+
+**权限要求**: `stgl:member:remove`
+
+**路径参数**:
+- `ids`: 成员ID数组,用逗号分隔
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功"
+}
+```
+
+### 2.6 根据社团ID查询成员列表
+
+**接口地址**: `GET /stgl/member/club/{clubId}`
+
+**权限要求**: `stgl:member:list`
+
+**路径参数**:
+- `clubId`: 社团ID
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": [
+    {
+      "id": 1,
+      "studentName": "张三",
+      "studentNo": "20250001",
+      "roleType": 1,
+      "roleTypeName": "社长",
+      "joinTime": "2025-01-01 10:00:00"
+    },
+    {
+      "id": 2,
+      "studentName": "李四",
+      "studentNo": "20250002",
+      "roleType": 3,
+      "roleTypeName": "成员",
+      "joinTime": "2025-01-15 14:30:00"
+    }
+  ]
+}
+```
+
+### 2.7 根据用户ID查询参与的社团列表
+
+**接口地址**: `GET /stgl/member/user/{userId}`
+
+**权限要求**: `stgl:member:list`
+
+**路径参数**:
+- `userId`: 用户ID
+
+**返回数据**: 同上
+
+### 2.8 检查用户是否已是某个社团/队伍的成员
+
+**接口地址**: `GET /stgl/member/checkMemberExists`
+
+**权限要求**: `stgl:member:list`
+
+**请求参数**:
+```json
+{
+  "memberType": 1,   // 成员类型
+  "relationId": 1,   // 关联ID
+  "userId": 1001     // 用户ID
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": true  // true=已是成员,false=不是成员
+}
+```
+
+### 2.9 批量添加成员
+
+**接口地址**: `POST /stgl/member/batchAdd`
+
+**权限要求**: `stgl:member:add`
+
+**请求参数**:
+```json
+{
+  "memberType": 1,
+  "relationId": 1,
+  "userIds": [1002, 1003, 1004],
+  "roleType": 3
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功"
+}
+```
+
+### 2.10 更新成员角色
+
+**接口地址**: `PUT /stgl/member/updateRole`
+
+**权限要求**: `stgl:member:edit`
+
+**请求参数**:
+```json
+{
+  "id": 1,
+  "roleType": 2  // 新角色类型
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功"
+}
+```
+
+### 2.11 退出社团/队伍
+
+**接口地址**: `PUT /stgl/member/quit/{id}`
+
+**权限要求**: `stgl:member:edit`
+
+**路径参数**:
+- `id`: 成员ID
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功"
+}
+```
+
+### 2.12 导出成员信息
+
+**接口地址**: `POST /stgl/member/export`
+
+**权限要求**: `stgl:member:export`
+
+**请求参数**: 同查询列表的筛选条件
+
+**返回数据**: Excel文件流
+
+---
+
+## 3. 社团报名大厅
+
+### 3.1 查询社团报名大厅列表
+
+**接口地址**: `GET /stgl/register/list`
+
+**权限要求**: 无(公开接口)
+
+**请求参数**:
+```json
+{
+  "pageNum": 1,
+  "pageSize": 10,
+  "clubType": "学术科技类",
+  "clubName": "社团名称(模糊查询)"
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": {
+    "total": 20,
+    "rows": [
+      {
+        "id": 1,
+        "clubName": "智能科技社团",
+        "clubType": "学术科技类",
+        "establishDate": "2025-01-15",
+        "description": "专注于人工智能、机器学习等前沿科技领域...",
+        "logoUrl": "/upload/club/logo/2025/01/15/xxx.jpg",
+        "presidentName": "张三",
+        "presidentDept": "计算机学院",
+        "advisorName": "李教授",
+        "advisorDept": "计算机学院",
+        "memberLimit": 50,
+        "currentMemberCount": 25,
+        "recruitCycle": "每学期",
+        "recruitTime": "9月、3月",
+        "activityFrequency": "每周1-2次",
+        "hasRegistered": false,      // 当前用户是否已报名
+        "registrationStatus": 0,     // 报名状态
+        "canRegister": true          // 是否可报名
+      }
+    ]
+  }
+}
+```
+
+### 3.2 查询社团报名大厅列表(不分页)
+
+**接口地址**: `GET /stgl/register/listAll`
+
+**权限要求**: 无(公开接口)
+
+**请求参数**:
+```json
+{
+  "clubType": "学术科技类",
+  "clubName": "社团名称(模糊查询)"
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": [
+    // 社团列表数据,同上
+  ]
+}
+```
+
+### 3.3 查询社团详细信息
+
+**接口地址**: `GET /stgl/register/{clubId}`
+
+**权限要求**: 无(公开接口)
+
+**路径参数**:
+- `clubId`: 社团ID
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": {
+    "id": 1,
+    "clubName": "智能科技社团",
+    "clubType": "学术科技类",
+    "establishDate": "2025-01-15",
+    "description": "专注于人工智能、机器学习等前沿科技领域的学术研究和实践交流社团",
+    "logoUrl": "/upload/club/logo/2025/01/15/xxx.jpg",
+    "presidentName": "张三",
+    "presidentDept": "计算机学院",
+    "advisorName": "李教授",
+    "advisorDept": "计算机学院",
+    "memberLimit": 50,
+    "currentMemberCount": 25,
+    "recruitCycle": "每学期",
+    "recruitTime": "9月、3月",
+    "activityFrequency": "每周1-2次",
+    "hasRegistered": false,
+    "registrationStatus": 0,
+    "canRegister": true
+  }
+}
+```
+
+### 3.4 报名加入社团
+
+**接口地址**: `POST /stgl/register/join/{clubId}`
+
+**权限要求**: `stgl:register:join`
+
+**路径参数**:
+- `clubId`: 社团ID
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "报名成功,欢迎加入社团!"
+}
+```
+
+**异常情况**:
+```json
+{
+  "code": 500,
+  "msg": "您已是该社团的成员"
+}
+{
+  "code": 500,
+  "msg": "该社团成员已满,无法加入"
+}
+{
+  "code": 500,
+  "msg": "社团不存在或已停用"
+}
+```
+
+### 3.5 退出社团
+
+**接口地址**: `POST /stgl/register/quit/{clubId}`
+
+**权限要求**: `stgl:register:quit`
+
+**路径参数**:
+- `clubId`: 社团ID
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "退出社团成功"
+}
+```
+
+**异常情况**:
+```json
+{
+  "code": 500,
+  "msg": "您不是该社团的成员"
+}
+{
+  "code": 500,
+  "msg": "社长和副社长不能直接退出,请先转让职务"
+}
+```
+
+### 3.6 查询我参与的社团列表
+
+**接口地址**: `GET /stgl/register/myClubs`
+
+**权限要求**: `stgl:register:list`
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": [
+    {
+      "id": 1,
+      "clubName": "智能科技社团",
+      "clubType": "学术科技类",
+      "presidentName": "张三",
+      "currentMemberCount": 25,
+      "memberLimit": 50,
+      "hasRegistered": true,
+      "registrationStatus": 1
+    }
+  ]
+}
+```
+
+### 3.7 检查是否已报名某个社团
+
+**接口地址**: `GET /stgl/register/checkRegistered/{clubId}`
+
+**权限要求**: 无(公开接口)
+
+**路径参数**:
+- `clubId`: 社团ID
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": true  // true=已报名,false=未报名
+}
+```
+
+### 3.8 查询推荐社团
+
+**接口地址**: `GET /stgl/register/recommend`
+
+**权限要求**: 无(公开接口)
+
+**请求参数**:
+```json
+{
+  "clubType": "学术科技类",  // 可选
+  "limit": 6              // 推荐数量,默认6个
+}
+```
+
+**返回数据**:
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": [
+    {
+      "id": 1,
+      "clubName": "智能科技社团",
+      "clubType": "学术科技类",
+      "description": "专注于人工智能...",
+      "logoUrl": "/upload/club/logo/xxx.jpg",
+      "currentMemberCount": 25,
+      "memberLimit": 50,
+      "canRegister": true
+    }
+  ]
+}
+```
+
+---
+
+## 🔧 错误码说明
+
+| 错误码 | 说明 | 
+|-------|------|
+| 200 | 操作成功 |
+| 400 | 请求参数错误 |
+| 401 | 未授权,需要登录 |
+| 403 | 权限不足 |
+| 404 | 资源不存在 |
+| 500 | 服务器内部错误 |
+
+## 📝 常见异常信息
+
+### 社团管理相关
+- "社团名称已存在,请重新输入"
+- "社团不存在或已停用"
+- "该社团成员已满,无法加入"
+
+### 成员管理相关
+- "用户已是该组织的成员,不能重复添加"
+- "您不是该社团的成员"
+- "社长和副社长不能直接退出,请先转让职务"
+
+### 权限相关
+- "权限不足,无法访问该资源"
+- "Token已过期,请重新登录"
+
+## 🧪 测试说明
+
+### 测试环境
+- 服务器地址:http://localhost:8080
+- 测试账号:admin/admin123
+- 加密方式:AES+RSA双重加密
+
+### 测试脚本
+项目根目录提供了完整的Node.js测试脚本 `stgl-api-test.js`
+
+运行方法:
+```bash
+npm install axios crypto
+node stgl-api-test.js
+```
+
+测试覆盖:
+- 24个API接口完整测试
+- 权限验证测试
+- 异常情况测试
+- 数据完整性验证
+
+## 📊 使用统计
+
+### 接口统计
+- **社团信息管理**: 11个接口
+- **社团成员管理**: 12个接口  
+- **社团报名大厅**: 8个接口
+- **总计**: 31个API接口
+
+### 权限统计
+- **管理员权限**: 31个接口
+- **社长权限**: 23个接口
+- **学生权限**: 8个接口
+- **公开接口**: 5个接口
+
+---
+
+## 📞 技术支持
+
+如有问题请联系开发团队或查看项目文档。
+
+**文档版本**: v1.0  
+**最后更新**: 2025-01-15 

+ 550 - 0
stgl-api-test.js

@@ -0,0 +1,550 @@
+/**
+ * 社团管理系统API测试脚本
+ * 
+ * 功能说明:
+ * 1. 社团信息管理 - 增删改查、状态管理、权限验证
+ * 2. 社团成员管理 - 成员添加、角色管理、退出处理
+ * 3. 社团报名大厅 - 浏览社团、报名加入、我的社团
+ * 
+ * 测试环境配置:
+ * - 服务器地址:http://localhost:8080
+ * - 加密登录:AES+RSA双重加密
+ * - 权限验证:Sa-Token
+ * 
+ * 运行方法:
+ * npm install axios crypto
+ * node stgl-api-test.js
+ * 
+ * @author Cursor AI
+ * @date 2025-01-15
+ * @version 1.0
+ */
+
+const axios = require('axios');
+const crypto = require('crypto');
+
+// ============================== 配置信息 ==============================
+const CONFIG = {
+    BASE_URL: 'http://localhost:8080',
+    TIMEOUT: 30000,
+    
+    // 测试用户配置
+    TEST_USER: {
+        username: 'admin',
+        password: 'admin123',
+        clientid: 'e5cd7e4891bf95d1d19206ce24a7b32e',
+        referer: 'http://localhost'
+    },
+    
+    // AES加密密钥(16位)
+    AES_SECRET_KEY: '1234567890123456',
+    
+    // RSA公钥
+    RSA_PUBLIC_KEY: `-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7zL3w8s0LnG7yMrp9fGU+ZOwS
+Wd3g0CqX8nfF5qSZQ7GNcN8L3HS9N3jQKLdFy/9bTQJb8KcV3hxGJEGZ5cV3zqJf
+oX5x7N8sGZHtQzN5pG4qqGt8M2QlGbFQNQXxZ8HwJj8yGjQl7Z7gN3Z7yKd1J3M2
+5fX3Q2mFtGzP8KGc8QIDAQAB
+-----END PUBLIC KEY-----`
+};
+
+// ============================== 工具函数 ==============================
+
+// AES加密函数
+function aesEncrypt(text, key) {
+    const cipher = crypto.createCipher('aes-128-ecb', key);
+    let encrypted = cipher.update(text, 'utf8', 'hex');
+    encrypted += cipher.final('hex');
+    return encrypted;
+}
+
+// RSA加密函数
+function rsaEncrypt(text, publicKey) {
+    const buffer = Buffer.from(text, 'utf8');
+    const encrypted = crypto.publicEncrypt({
+        key: publicKey,
+        padding: crypto.constants.RSA_PKCS1_PADDING
+    }, buffer);
+    return encrypted.toString('base64');
+}
+
+// HTTP请求封装
+const request = axios.create({
+    baseURL: CONFIG.BASE_URL,
+    timeout: CONFIG.TIMEOUT,
+    headers: {
+        'Content-Type': 'application/json',
+        'clientid': CONFIG.TEST_USER.clientid,
+        'referer': CONFIG.TEST_USER.referer
+    }
+});
+
+// 全局变量
+let authToken = '';
+let testData = {
+    clubId: null,
+    memberId: null,
+    userIds: []
+};
+
+// ============================== 认证相关 ==============================
+
+/**
+ * 用户登录(AES+RSA双重加密)
+ */
+async function login() {
+    console.log('\n🔐 开始用户登录...');
+    
+    try {
+        // 第一步:AES加密用户名和密码
+        const aesUsername = aesEncrypt(CONFIG.TEST_USER.username, CONFIG.AES_SECRET_KEY);
+        const aesPassword = aesEncrypt(CONFIG.TEST_USER.password, CONFIG.AES_SECRET_KEY);
+        
+        // 第二步:RSA加密AES密钥
+        const rsaKey = rsaEncrypt(CONFIG.AES_SECRET_KEY, CONFIG.RSA_PUBLIC_KEY);
+        
+        // 第三步:发送登录请求
+        const response = await request.post('/auth/login', {
+            username: aesUsername,
+            password: aesPassword,
+            key: rsaKey,
+            captcha: '',
+            uuid: ''
+        });
+        
+        if (response.data.code === 200) {
+            authToken = response.data.data.access_token;
+            request.defaults.headers['Authorization'] = `Bearer ${authToken}`;
+            console.log('✅ 登录成功');
+            console.log(`🔑 Token: ${authToken.substring(0, 50)}...`);
+            return true;
+        } else {
+            console.error('❌ 登录失败:', response.data.msg);
+            return false;
+        }
+    } catch (error) {
+        console.error('❌ 登录请求失败:', error.message);
+        return false;
+    }
+}
+
+// ============================== 社团信息管理API测试 ==============================
+
+/**
+ * 测试社团信息管理功能
+ */
+async function testClubManagement() {
+    console.log('\n📋 ========== 社团信息管理API测试 ==========');
+    
+    // 1. 查询社团列表
+    await testAPI('GET', '/stgl/club/list', {
+        pageNum: 1,
+        pageSize: 10
+    }, '查询社团列表');
+    
+    // 2. 新增社团
+    const clubData = {
+        clubName: '智能科技社团',
+        clubType: '学术科技类',
+        establishDate: '2025-01-15',
+        description: '专注于人工智能、机器学习等前沿科技领域的学术研究和实践交流社团',
+        email: 'aitech@example.com',
+        phone: '028-12345678',
+        presidentName: '张三',
+        presidentStudentNo: '20250001',
+        presidentDept: '计算机学院',
+        presidentMajor: '软件工程',
+        presidentClass: '软工2501班',
+        presidentPhone: '13800138001',
+        advisorName: '李教授',
+        advisorDept: '计算机学院',
+        memberLimit: 50,
+        recruitCycle: '每学期',
+        recruitTime: '9月、3月',
+        activityFrequency: '每周1-2次',
+        fundingSources: '学校拨款,社团自筹',
+        status: 1
+    };
+    
+    const createResult = await testAPI('POST', '/stgl/club', clubData, '新增社团');
+    if (createResult) {
+        // 获取创建的社团ID
+        const listResult = await testAPI('GET', '/stgl/club/list', {
+            clubName: clubData.clubName
+        }, '查询新建社团ID');
+        
+        if (listResult && listResult.data.rows.length > 0) {
+            testData.clubId = listResult.data.rows[0].id;
+            console.log(`🆔 获取到社团ID: ${testData.clubId}`);
+        }
+    }
+    
+    // 3. 查询社团详情
+    if (testData.clubId) {
+        await testAPI('GET', `/stgl/club/${testData.clubId}`, {}, '查询社团详情');
+    }
+    
+    // 4. 修改社团信息
+    if (testData.clubId) {
+        await testAPI('PUT', '/stgl/club', {
+            id: testData.clubId,
+            clubName: '智能科技社团(更新版)',
+            memberLimit: 60
+        }, '修改社团信息');
+    }
+    
+    // 5. 查询可用社团选项
+    await testAPI('GET', '/stgl/club/options', {}, '查询可用社团选项');
+    
+    // 6. 检查社团名称唯一性
+    await testAPI('GET', '/stgl/club/checkClubNameUnique', {
+        clubName: '不存在的社团名称'
+    }, '检查社团名称唯一性');
+    
+    // 7. 查询我管理的社团
+    await testAPI('GET', '/stgl/club/myClubs', {}, '查询我管理的社团');
+    
+    // 8. 启用/禁用社团
+    if (testData.clubId) {
+        await testAPI('PUT', '/stgl/club/changeStatus', {}, '启用/禁用社团', {
+            id: testData.clubId,
+            status: 0
+        });
+        
+        await testAPI('PUT', '/stgl/club/changeStatus', {}, '重新启用社团', {
+            id: testData.clubId,
+            status: 1
+        });
+    }
+}
+
+// ============================== 社团成员管理API测试 ==============================
+
+/**
+ * 测试社团成员管理功能
+ */
+async function testMemberManagement() {
+    console.log('\n👥 ========== 社团成员管理API测试 ==========');
+    
+    // 1. 查询成员列表
+    await testAPI('GET', '/stgl/member/list', {
+        pageNum: 1,
+        pageSize: 10,
+        memberType: 1
+    }, '查询成员列表');
+    
+    // 2. 新增成员
+    if (testData.clubId) {
+        const memberData = {
+            memberType: 1,
+            relationId: testData.clubId,
+            userId: 1001,
+            studentNo: '20250002',
+            studentName: '李四',
+            roleType: 3,
+            status: 1
+        };
+        
+        const createResult = await testAPI('POST', '/stgl/member', memberData, '新增成员');
+        if (createResult) {
+            // 获取创建的成员ID
+            const listResult = await testAPI('GET', '/stgl/member/list', {
+                studentNo: memberData.studentNo
+            }, '查询新建成员ID');
+            
+            if (listResult && listResult.data.rows.length > 0) {
+                testData.memberId = listResult.data.rows[0].id;
+                console.log(`🆔 获取到成员ID: ${testData.memberId}`);
+            }
+        }
+    }
+    
+    // 3. 查询成员详情
+    if (testData.memberId) {
+        await testAPI('GET', `/stgl/member/${testData.memberId}`, {}, '查询成员详情');
+    }
+    
+    // 4. 修改成员信息
+    if (testData.memberId) {
+        await testAPI('PUT', '/stgl/member', {
+            id: testData.memberId,
+            studentName: '李四(更新)',
+            roleType: 2,
+            remark: '表现优秀,晋升为副社长'
+        }, '修改成员信息');
+    }
+    
+    // 5. 根据社团ID查询成员
+    if (testData.clubId) {
+        await testAPI('GET', `/stgl/member/club/${testData.clubId}`, {}, '根据社团ID查询成员');
+    }
+    
+    // 6. 批量添加成员
+    if (testData.clubId) {
+        await testAPI('POST', '/stgl/member/batchAdd', {}, '批量添加成员', {
+            memberType: 1,
+            relationId: testData.clubId,
+            userIds: [1002, 1003, 1004],
+            roleType: 3
+        });
+    }
+    
+    // 7. 更新成员角色
+    if (testData.memberId) {
+        await testAPI('PUT', '/stgl/member/updateRole', {}, '更新成员角色', {
+            id: testData.memberId,
+            roleType: 3
+        });
+    }
+    
+    // 8. 检查用户是否已是成员
+    if (testData.clubId) {
+        await testAPI('GET', '/stgl/member/checkMemberExists', {
+            memberType: 1,
+            relationId: testData.clubId,
+            userId: 1001
+        }, '检查用户是否已是成员');
+    }
+}
+
+// ============================== 社团报名大厅API测试 ==============================
+
+/**
+ * 测试社团报名大厅功能
+ */
+async function testClubRegister() {
+    console.log('\n🎯 ========== 社团报名大厅API测试 ==========');
+    
+    // 1. 查询社团报名大厅列表
+    await testAPI('GET', '/stgl/register/list', {
+        pageNum: 1,
+        pageSize: 10,
+        clubType: '学术科技类'
+    }, '查询社团报名大厅列表');
+    
+    // 2. 查询社团报名大厅列表(不分页)
+    await testAPI('GET', '/stgl/register/listAll', {
+        clubType: '学术科技类'
+    }, '查询社团报名大厅列表(不分页)');
+    
+    // 3. 查询社团详细信息
+    if (testData.clubId) {
+        await testAPI('GET', `/stgl/register/${testData.clubId}`, {}, '查询社团详细信息');
+    }
+    
+    // 4. 报名加入社团
+    if (testData.clubId) {
+        await testAPI('POST', `/stgl/register/join/${testData.clubId}`, {}, '报名加入社团');
+    }
+    
+    // 5. 检查报名状态
+    if (testData.clubId) {
+        await testAPI('GET', `/stgl/register/checkRegistered/${testData.clubId}`, {}, '检查报名状态');
+    }
+    
+    // 6. 查询我参与的社团
+    await testAPI('GET', '/stgl/register/myClubs', {}, '查询我参与的社团');
+    
+    // 7. 查询推荐社团
+    await testAPI('GET', '/stgl/register/recommend', {
+        clubType: '学术科技类',
+        limit: 5
+    }, '查询推荐社团');
+    
+    // 8. 退出社团
+    if (testData.clubId) {
+        await testAPI('POST', `/stgl/register/quit/${testData.clubId}`, {}, '退出社团');
+    }
+}
+
+// ============================== 通用API测试函数 ==============================
+
+/**
+ * 通用API测试函数
+ * @param {string} method HTTP方法
+ * @param {string} url 请求URL
+ * @param {object} data 请求数据
+ * @param {string} description 测试描述
+ * @param {object} params 查询参数
+ */
+async function testAPI(method, url, data = {}, description = '', params = {}) {
+    console.log(`\n${getMethodIcon(method)} 测试${description}...`);
+    
+    try {
+        let response;
+        const config = {
+            params: Object.keys(params).length > 0 ? params : (method === 'GET' ? data : {})
+        };
+        
+        switch (method.toUpperCase()) {
+            case 'GET':
+                response = await request.get(url, config);
+                break;
+            case 'POST':
+                response = await request.post(url, data, config);
+                break;
+            case 'PUT':
+                response = await request.put(url, data, config);
+                break;
+            case 'DELETE':
+                response = await request.delete(url, config);
+                break;
+            default:
+                throw new Error(`不支持的HTTP方法: ${method}`);
+        }
+        
+        if (response.data.code === 200) {
+            console.log(`✅ ${description}成功`);
+            
+            // 根据响应类型输出不同信息
+            if (response.data.data) {
+                if (Array.isArray(response.data.data)) {
+                    console.log(`📊 返回数据数量: ${response.data.data.length}`);
+                } else if (response.data.data.rows) {
+                    console.log(`📊 总记录数: ${response.data.data.total}`);
+                    console.log(`📄 当前页数据: ${response.data.data.rows.length} 条`);
+                } else if (typeof response.data.data === 'object') {
+                    console.log(`📝 返回数据类型: ${Object.keys(response.data.data).join(', ')}`);
+                } else {
+                    console.log(`📝 返回数据: ${response.data.data}`);
+                }
+            }
+            
+            return response.data;
+        } else {
+            console.error(`❌ ${description}失败:`, response.data.msg);
+            return null;
+        }
+    } catch (error) {
+        console.error(`❌ ${description}请求失败:`, error.response?.data?.msg || error.message);
+        return null;
+    }
+}
+
+/**
+ * 获取HTTP方法对应的图标
+ */
+function getMethodIcon(method) {
+    const icons = {
+        'GET': '🔍',
+        'POST': '➕',
+        'PUT': '✏️',
+        'DELETE': '🗑️'
+    };
+    return icons[method.toUpperCase()] || '📡';
+}
+
+// ============================== 清理测试数据 ==============================
+
+/**
+ * 清理测试数据
+ */
+async function cleanupTestData() {
+    console.log('\n🧹 ========== 清理测试数据 ==========');
+    
+    // 删除测试社团(会级联删除相关成员)
+    if (testData.clubId) {
+        await testAPI('DELETE', `/stgl/club/${testData.clubId}`, {}, '删除测试社团');
+    }
+    
+    console.log('🎯 测试数据清理完成');
+}
+
+// ============================== 主测试流程 ==============================
+
+/**
+ * 主测试函数
+ */
+async function runTests() {
+    console.log('🚀 ========== 社团管理系统API测试开始 ==========');
+    console.log(`📅 测试时间: ${new Date().toLocaleString()}`);
+    console.log(`🌐 服务器地址: ${CONFIG.BASE_URL}`);
+    console.log(`👤 测试用户: ${CONFIG.TEST_USER.username}`);
+    
+    const startTime = Date.now();
+    let successCount = 0;
+    let totalCount = 0;
+    
+    try {
+        // 1. 用户认证
+        console.log('\n🔐 ========== 用户认证测试 ==========');
+        const loginSuccess = await login();
+        if (!loginSuccess) {
+            console.log('❌ 登录失败,退出测试');
+            return;
+        }
+        
+        // 获取用户信息
+        const userInfo = await testAPI('GET', '/system/user/getInfo', {}, '获取用户信息');
+        if (userInfo && userInfo.data.user) {
+            console.log(`👤 当前用户: ${userInfo.data.user.userName} (${userInfo.data.user.nickName})`);
+        }
+        
+        // 2. 社团信息管理测试
+        await testClubManagement();
+        
+        // 3. 社团成员管理测试
+        await testMemberManagement();
+        
+        // 4. 社团报名大厅测试
+        await testClubRegister();
+        
+        // 5. 清理测试数据
+        await cleanupTestData();
+        
+    } catch (error) {
+        console.error('❌ 测试过程中发生错误:', error.message);
+    }
+    
+    const endTime = Date.now();
+    const duration = (endTime - startTime) / 1000;
+    
+    console.log('\n🎯 ========== 社团管理系统API测试完成 ==========');
+    console.log(`⏱️ 测试耗时: ${duration.toFixed(2)} 秒`);
+    console.log('📊 测试结果总结:');
+    console.log('  ✅ 社团信息管理: 8个API接口');
+    console.log('  ✅ 社团成员管理: 8个API接口');
+    console.log('  ✅ 社团报名大厅: 8个API接口');
+    console.log('  📝 总计: 24个API接口测试完成');
+    console.log('\n📋 API接口列表:');
+    console.log('【社团信息管理】');
+    console.log('  - GET  /stgl/club/list          查询社团列表');
+    console.log('  - POST /stgl/club               新增社团');
+    console.log('  - GET  /stgl/club/{id}          查询社团详情');
+    console.log('  - PUT  /stgl/club               修改社团信息');
+    console.log('  - GET  /stgl/club/options       查询可用社团选项');
+    console.log('  - GET  /stgl/club/checkClubNameUnique  检查社团名称唯一性');
+    console.log('  - GET  /stgl/club/myClubs       查询我管理的社团');
+    console.log('  - PUT  /stgl/club/changeStatus  启用/禁用社团');
+    console.log('\n【社团成员管理】');
+    console.log('  - GET  /stgl/member/list        查询成员列表');
+    console.log('  - POST /stgl/member             新增成员');
+    console.log('  - GET  /stgl/member/{id}        查询成员详情');
+    console.log('  - PUT  /stgl/member             修改成员信息');
+    console.log('  - GET  /stgl/member/club/{clubId}  根据社团ID查询成员');
+    console.log('  - POST /stgl/member/batchAdd    批量添加成员');
+    console.log('  - PUT  /stgl/member/updateRole  更新成员角色');
+    console.log('  - GET  /stgl/member/checkMemberExists  检查用户是否已是成员');
+    console.log('\n【社团报名大厅】');
+    console.log('  - GET  /stgl/register/list      查询社团报名大厅列表');
+    console.log('  - GET  /stgl/register/listAll   查询社团报名大厅列表(不分页)');
+    console.log('  - GET  /stgl/register/{clubId}  查询社团详细信息');
+    console.log('  - POST /stgl/register/join/{clubId}  报名加入社团');
+    console.log('  - GET  /stgl/register/checkRegistered/{clubId}  检查报名状态');
+    console.log('  - GET  /stgl/register/myClubs   查询我参与的社团');
+    console.log('  - GET  /stgl/register/recommend 查询推荐社团');
+    console.log('  - POST /stgl/register/quit/{clubId}  退出社团');
+}
+
+// 导出模块
+module.exports = {
+    runTests,
+    CONFIG,
+    testAPI,
+    login
+};
+
+// 如果直接运行此文件,则执行测试
+if (require.main === module) {
+    runTests().catch(console.error);
+} 

+ 1 - 7
web/src/router/index.ts

@@ -89,7 +89,7 @@ export const constantRoutes: RouteRecordRaw[] = [
       }
     ]
   },
-<<<<<<< HEAD
+
   {
     path: '/xljk',
     component: Layout,
@@ -140,12 +140,6 @@ export const dynamicRoutes: RouteRecordRaw[] = [
     ]
   }
 ];
-=======
-];
-
-// 动态路由,基于用户权限动态去加载
-export const dynamicRoutes: RouteRecordRaw[] = [];
->>>>>>> e450a8ffe73adab129a8f940bff3316c0361aa7a
 
 /**
  * 创建路由