diff --git a/backend/pom.xml b/backend/pom.xml index a99a54ce..dbeb0c46 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -407,6 +407,12 @@ ${revision} + + + org.dromara + ruoyi-stgl + ${revision} + diff --git a/backend/ruoyi-admin/pom.xml b/backend/ruoyi-admin/pom.xml index 6e1fa000..eef9838f 100644 --- a/backend/ruoyi-admin/pom.xml +++ b/backend/ruoyi-admin/pom.xml @@ -135,6 +135,13 @@ ${revision} + + + org.dromara + ruoyi-stgl + ${revision} + + de.codecentric spring-boot-admin-starter-client diff --git a/backend/ruoyi-modules/pom.xml b/backend/ruoyi-modules/pom.xml index 6dfc9f47..2e93dacc 100644 --- a/backend/ruoyi-modules/pom.xml +++ b/backend/ruoyi-modules/pom.xml @@ -22,6 +22,7 @@ ruoyi-cw ruoyi-rs ruoyi-xljk + ruoyi-stgl ruoyi-modules diff --git a/backend/ruoyi-modules/ruoyi-stgl/pom.xml b/backend/ruoyi-modules/ruoyi-stgl/pom.xml new file mode 100644 index 00000000..f7e28e60 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-stgl/pom.xml @@ -0,0 +1,93 @@ + + + + ruoyi-modules + org.dromara + ${revision} + + 4.0.0 + + ruoyi-stgl + + + 社团管理模块 + + + + + + org.dromara + ruoyi-common-core + + + + + org.dromara + ruoyi-common-security + + + + + org.dromara + ruoyi-common-web + + + + + org.dromara + ruoyi-common-excel + + + + org.apache.poi + poi-ooxml + 5.2.3 + + + + + org.dromara + ruoyi-common-mybatis + + + + + org.dromara + ruoyi-common-tenant + + + + + org.dromara + ruoyi-common-idempotent + + + + + org.dromara + ruoyi-common-log + + + + + org.dromara + ruoyi-common-translation + + + + + org.dromara + ruoyi-common-oss + + + + + org.dromara + ruoyi-common-doc + + + + + \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubController.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubController.java new file mode 100644 index 00000000..a5604d00 --- /dev/null +++ b/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 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 list = stglClubService.queryList(bo); + ExcelUtil.exportExcel(list, "社团信息", StglClubVo.class, response); + } + + /** + * 获取社团信息详细信息 + */ + @Operation(summary = "获取社团信息详细信息") + @SaCheckPermission("stgl:club:query") + @GetMapping("/{id}") + public R 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 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 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 remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(stglClubService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 查询可用的社团选项 + */ + @Operation(summary = "查询可用的社团选项") + @SaCheckPermission("stgl:club:list") + @GetMapping("/options") + public R> getOptions() { + return R.ok(stglClubService.queryAvailableOptions()); + } + + /** + * 根据社团类型查询社团列表 + */ + @Operation(summary = "根据社团类型查询社团列表") + @SaCheckPermission("stgl:club:list") + @GetMapping("/listByType/{clubType}") + @Parameters({ + @Parameter(name = "clubType", description = "社团类型", required = true) + }) + public R> listByType(@PathVariable String clubType) { + return R.ok(stglClubService.queryByClubType(clubType)); + } + + /** + * 查询我管理的社团列表 + */ + @Operation(summary = "查询我管理的社团列表") + @SaCheckPermission("stgl:club:list") + @GetMapping("/myClubs") + public R> 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 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 changeStatus(@RequestParam Long id, @RequestParam Integer status) { + return toAjax(stglClubService.changeStatus(id, status)); + } + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubRegisterController.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubRegisterController.java new file mode 100644 index 00000000..b0c57795 --- /dev/null +++ b/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 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> 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 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 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 quitClub(@PathVariable Long clubId) { + Long userId = LoginHelper.getUserId(); + return toAjax(stglClubRegisterService.quitClub(clubId, userId)); + } + + /** + * 查询我参与的社团列表 + */ + @Operation(summary = "查询我参与的社团列表") + @SaCheckPermission("stgl:register:list") + @GetMapping("/myClubs") + public R> 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 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> getRecommendClubs(@RequestParam(required = false) String clubType, + @RequestParam(required = false, defaultValue = "6") Integer limit) { + return R.ok(stglClubRegisterService.queryRecommendClubs(clubType, limit)); + } + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglMemberController.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglMemberController.java new file mode 100644 index 00000000..e91085c7 --- /dev/null +++ b/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 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 list = stglMemberService.queryList(bo); + ExcelUtil.exportExcel(list, "社团成员", StglMemberVo.class, response); + } + + /** + * 获取社团成员详细信息 + */ + @Operation(summary = "获取社团成员详细信息") + @SaCheckPermission("stgl:member:query") + @GetMapping("/{id}") + public R 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 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 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 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> 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> 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 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 batchAddMembers(@RequestParam Integer memberType, + @RequestParam Long relationId, + @RequestParam List 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 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 quitMember(@PathVariable Long id) { + return toAjax(stglMemberService.quitMember(id)); + } + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/StglClub.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/StglClub.java new file mode 100644 index 00000000..28125ae5 --- /dev/null +++ b/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; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/StglMember.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/StglMember.java new file mode 100644 index 00000000..748e9006 --- /dev/null +++ b/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; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/bo/StglClubBo.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/bo/StglClubBo.java new file mode 100644 index 00000000..82ff495d --- /dev/null +++ b/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; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/bo/StglMemberBo.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/bo/StglMemberBo.java new file mode 100644 index 00000000..df0913b5 --- /dev/null +++ b/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; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglClubRegisterVo.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglClubRegisterVo.java new file mode 100644 index 00000000..cbd264bb --- /dev/null +++ b/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; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglClubVo.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglClubVo.java new file mode 100644 index 00000000..9dcc55ea --- /dev/null +++ b/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; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglMemberVo.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/vo/StglMemberVo.java new file mode 100644 index 00000000..54007c89 --- /dev/null +++ b/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; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/mapper/StglClubMapper.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/mapper/StglClubMapper.java new file mode 100644 index 00000000..0e244ffb --- /dev/null +++ b/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 { + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/mapper/StglMemberMapper.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/mapper/StglMemberMapper.java new file mode 100644 index 00000000..673b898b --- /dev/null +++ b/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 { + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglClubRegisterService.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglClubRegisterService.java new file mode 100644 index 00000000..f6b80259 --- /dev/null +++ b/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 queryPageList(String clubType, String clubName, PageQuery pageQuery); + + /** + * 查询社团报名大厅列表 + * + * @param clubType 社团类型 + * @param clubName 社团名称 + * @return 社团报名大厅列表 + */ + List 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 queryMyClubs(Long userId); + + /** + * 检查是否已报名某个社团 + * + * @param clubId 社团ID + * @param userId 用户ID + * @return 是否已报名 + */ + Boolean checkRegistered(Long clubId, Long userId); + + /** + * 根据社团类型查询推荐社团 + * + * @param clubType 社团类型 + * @param limit 推荐数量 + * @return 推荐社团列表 + */ + List queryRecommendClubs(String clubType, Integer limit); + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglClubService.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglClubService.java new file mode 100644 index 00000000..2bb93775 --- /dev/null +++ b/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 queryPageList(StglClubBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的社团信息列表 + * + * @param bo 查询条件 + * @return 社团信息列表 + */ + List 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 ids, Boolean isValid); + + /** + * 查询可用的社团选项 + * + * @return 社团选项列表 + */ + List queryAvailableOptions(); + + /** + * 根据社团类型查询社团列表 + * + * @param clubType 社团类型 + * @return 社团列表 + */ + List queryByClubType(String clubType); + + /** + * 查询我管理的社团列表 + * + * @return 社团列表 + */ + List 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); + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglMemberService.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/IStglMemberService.java new file mode 100644 index 00000000..50847b9a --- /dev/null +++ b/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 queryPageList(StglMemberBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的社团成员列表 + * + * @param bo 查询条件 + * @return 社团成员列表 + */ + List 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 ids, Boolean isValid); + + /** + * 根据社团ID查询成员列表 + * + * @param clubId 社团ID + * @return 成员列表 + */ + List queryByClubId(Long clubId); + + /** + * 根据用户ID查询参与的社团列表 + * + * @param userId 用户ID + * @return 社团成员关系列表 + */ + List 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 userIds, Integer roleType); + + /** + * 更新成员角色 + * + * @param id 成员ID + * @param roleType 角色类型 + * @return 是否更新成功 + */ + Boolean updateMemberRole(Long id, Integer roleType); + + /** + * 退出社团/队伍 + * + * @param id 成员ID + * @return 是否退出成功 + */ + Boolean quitMember(Long id); + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglClubRegisterServiceImpl.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglClubRegisterServiceImpl.java new file mode 100644 index 00000000..7fe1c67f --- /dev/null +++ b/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 queryPageList(String clubType, String clubName, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(clubType, clubName); + Page page = clubMapper.selectPage(pageQuery.build(), lqw); + + List voList = convertToRegisterVo(page.getRecords()); + + Page result = new Page<>(page.getCurrent(), page.getSize(), page.getTotal()); + result.setRecords(voList); + + return TableDataInfo.build(result); + } + + /** + * 查询社团报名大厅列表 + * + * @param clubType 社团类型 + * @param clubName 社团名称 + * @return 社团报名大厅列表 + */ + @Override + public List queryList(String clubType, String clubName) { + LambdaQueryWrapper lqw = buildQueryWrapper(clubType, clubName); + List clubs = clubMapper.selectList(lqw); + return convertToRegisterVo(clubs); + } + + private LambdaQueryWrapper buildQueryWrapper(String clubType, String clubName) { + LambdaQueryWrapper 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 convertToRegisterVo(List 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 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 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 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 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 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 queryMyClubs(Long userId) { + // 查询用户参与的社团ID + LambdaQueryWrapper memberLqw = Wrappers.lambdaQuery(); + memberLqw.eq(StglMember::getMemberType, 1); + memberLqw.eq(StglMember::getUserId, userId); + memberLqw.eq(StglMember::getStatus, 1); + List members = memberMapper.selectList(memberLqw); + + if (members.isEmpty()) { + return List.of(); + } + + List clubIds = members.stream().map(StglMember::getRelationId).collect(Collectors.toList()); + + // 查询社团信息 + LambdaQueryWrapper clubLqw = Wrappers.lambdaQuery(); + clubLqw.in(StglClub::getId, clubIds); + clubLqw.eq(StglClub::getStatus, 1); + clubLqw.orderByDesc(StglClub::getCreateTime); + List clubs = clubMapper.selectList(clubLqw); + + return convertToRegisterVo(clubs); + } + + /** + * 检查是否已报名某个社团 + * + * @param clubId 社团ID + * @param userId 用户ID + * @return 是否已报名 + */ + @Override + public Boolean checkRegistered(Long clubId, Long userId) { + LambdaQueryWrapper 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 queryRecommendClubs(String clubType, Integer limit) { + LambdaQueryWrapper 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 clubs = clubMapper.selectList(lqw); + return convertToRegisterVo(clubs); + } + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglClubServiceImpl.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglClubServiceImpl.java new file mode 100644 index 00000000..b7098b14 --- /dev/null +++ b/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 queryPageList(StglClubBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的社团信息列表 + * + * @param bo 查询条件 + * @return 社团信息列表 + */ + @Override + public List queryList(StglClubBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(StglClubBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper 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 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 ids, Boolean isValid) { + if(isValid){ + // 可以添加删除前的业务校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + /** + * 查询可用的社团选项 + * + * @return 社团选项列表 + */ + @Override + public List queryAvailableOptions() { + LambdaQueryWrapper 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 queryByClubType(String clubType) { + LambdaQueryWrapper 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 queryMyClubs() { + // 根据当前用户查询其管理的社团 + Long userId = LoginHelper.getUserId(); + LambdaQueryWrapper 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 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; + } + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglMemberServiceImpl.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/service/impl/StglMemberServiceImpl.java new file mode 100644 index 00000000..e6001ae7 --- /dev/null +++ b/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 queryPageList(StglMemberBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的社团成员列表 + * + * @param bo 查询条件 + * @return 社团成员列表 + */ + @Override + public List queryList(StglMemberBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(StglMemberBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper 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 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 ids, Boolean isValid) { + if(isValid){ + // 可以添加删除前的业务校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + /** + * 根据社团ID查询成员列表 + * + * @param clubId 社团ID + * @return 成员列表 + */ + @Override + public List queryByClubId(Long clubId) { + LambdaQueryWrapper 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 queryByUserId(Long userId) { + LambdaQueryWrapper 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 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 userIds, Integer roleType) { + Date now = new Date(); + List 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; + } + +} \ No newline at end of file diff --git a/docs/开发文档/API/API文档总览.md b/docs/开发文档/API/API文档总览.md index 04150e06..d2d63f81 100644 --- a/docs/开发文档/API/API文档总览.md +++ b/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 + diff --git a/docs/开发文档/API/社团管理API.md b/docs/开发文档/API/社团管理API.md new file mode 100644 index 00000000..1b56b8e6 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/stgl-api-test.js b/stgl-api-test.js new file mode 100644 index 00000000..11ce41d2 --- /dev/null +++ b/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); +} \ No newline at end of file diff --git a/web/src/router/index.ts b/web/src/router/index.ts index cecbf561..30b0e415 100644 --- a/web/src/router/index.ts +++ b/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 /** * 创建路由