diff --git a/.gitignore b/.gitignore
index 03ef4a45..1ec16190 100644
--- a/.gitignore
+++ b/.gitignore
@@ -328,3 +328,6 @@ docs/部署文档/nginx配置/hzdyjsweb.camasort.com.conf
首页完善的提示词.md
scripts/
学生宿舍卫生检查、学生违纪记录统计.md
+学生调宿、退宿功能.md
+学生动向信息界面(宿管员).md
+prompt/
diff --git a/backend/ruoyi-modules/ruoyi-stgl/pom.xml b/backend/ruoyi-modules/ruoyi-stgl/pom.xml
index 8ae11d2d..7ea0ba55 100644
--- a/backend/ruoyi-modules/ruoyi-stgl/pom.xml
+++ b/backend/ruoyi-modules/ruoyi-stgl/pom.xml
@@ -93,6 +93,12 @@
ruoyi-xg
+
+
+ org.dromara
+ ruoyi-system
+
+
\ No newline at end of file
diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglAnnualReviewAuditController.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglAnnualReviewAuditController.java
new file mode 100644
index 00000000..b3f1c93c
--- /dev/null
+++ b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglAnnualReviewAuditController.java
@@ -0,0 +1,113 @@
+package org.dromara.stgl.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import lombok.RequiredArgsConstructor;
+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.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.stgl.domain.StglAnnualReviewAudit;
+import org.dromara.stgl.domain.bo.StglAnnualReviewApprovalBo;
+import org.dromara.stgl.service.IStglAnnualReviewAuditService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 社团年审审批
+ *
+ * @author ruoyi
+ * @date 2024-01-01
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/stgl/annualReviewAudit")
+public class StglAnnualReviewAuditController extends BaseController {
+
+ private final IStglAnnualReviewAuditService stglAnnualReviewAuditService;
+
+ /**
+ * 查询社团年审审批详细
+ */
+ @SaCheckPermission("stgl:annualReviewAudit:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "主键不能为空")
+ @PathVariable Long id) {
+ return R.ok(stglAnnualReviewAuditService.queryById(id));
+ }
+
+ /**
+ * 根据年审记录ID查询审批记录
+ */
+ @SaCheckPermission("stgl:annualReviewAudit:query")
+ @GetMapping("/byAnnualReview/{annualReviewId}")
+ public R> getByAnnualReviewId(@NotNull(message = "年审记录ID不能为空")
+ @PathVariable Long annualReviewId) {
+ return R.ok(stglAnnualReviewAuditService.queryByAnnualReviewId(annualReviewId));
+ }
+
+ /**
+ * 根据审批人ID查询待审批记录
+ */
+ @SaCheckPermission("stgl:annualReviewAudit:query")
+ @GetMapping("/pending/{approverId}")
+ public R> getPendingByApproverId(@NotNull(message = "审批人ID不能为空")
+ @PathVariable Long approverId) {
+ return R.ok(stglAnnualReviewAuditService.queryPendingByApproverId(approverId));
+ }
+
+ /**
+ * 新增社团年审审批
+ */
+ @SaCheckPermission("stgl:annualReviewAudit:add")
+ @Log(title = "社团年审审批", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R add(@Validated(AddGroup.class) @RequestBody StglAnnualReviewAudit stglAnnualReviewAudit) {
+ return toAjax(stglAnnualReviewAuditService.insertByBo(stglAnnualReviewAudit));
+ }
+
+ /**
+ * 修改社团年审审批
+ */
+ @SaCheckPermission("stgl:annualReviewAudit:edit")
+ @Log(title = "社团年审审批", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R edit(@Validated(EditGroup.class) @RequestBody StglAnnualReviewAudit stglAnnualReviewAudit) {
+ return toAjax(stglAnnualReviewAuditService.updateByBo(stglAnnualReviewAudit));
+ }
+
+ /**
+ * 删除社团年审审批
+ */
+ @SaCheckPermission("stgl:annualReviewAudit:remove")
+ @Log(title = "社团年审审批", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R remove(@NotEmpty(message = "主键不能为空")
+ @PathVariable Long[] ids) {
+ return toAjax(stglAnnualReviewAuditService.deleteWithValidByIds(List.of(ids), true));
+ }
+
+ /**
+ * 审批年审记录
+ */
+ @SaCheckPermission("stgl:annualReviewAudit:approve")
+ @Log(title = "社团年审审批", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PostMapping("/approve")
+ public R approve(@Validated @RequestBody StglAnnualReviewApprovalBo approvalBo) {
+ return toAjax(stglAnnualReviewAuditService.approveAnnualReview(approvalBo));
+ }
+}
\ No newline at end of file
diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglAuditorController.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglAuditorController.java
new file mode 100644
index 00000000..bd131134
--- /dev/null
+++ b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglAuditorController.java
@@ -0,0 +1,179 @@
+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.StglAuditorVo;
+import org.dromara.stgl.domain.bo.StglAuditorBo;
+import org.dromara.stgl.service.IStglAuditorService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.service.ISysUserService;
+import org.dromara.system.domain.vo.SysUserVo;
+
+/**
+ * 社团管理审核人配置
+ *
+ * @author ruoyi
+ * @date 2024-01-01
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/stgl/auditor")
+public class StglAuditorController extends BaseController {
+
+ private final IStglAuditorService stglAuditorService;
+ private final ISysUserService sysUserService;
+
+ /**
+ * 查询社团管理审核人配置列表
+ */
+ @SaCheckPermission("stgl:auditor:list")
+ @GetMapping("/list")
+ public TableDataInfo list(StglAuditorBo bo, PageQuery pageQuery) {
+ return stglAuditorService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 导出社团管理审核人配置列表
+ */
+ @SaCheckPermission("stgl:auditor:export")
+ @Log(title = "社团管理审核人配置", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(StglAuditorBo bo, HttpServletResponse response) {
+ List list = stglAuditorService.queryList(bo);
+ ExcelUtil.exportExcel(list, "社团管理审核人配置", StglAuditorVo.class, response);
+ }
+
+ /**
+ * 获取社团管理审核人配置详细信息
+ */
+ @SaCheckPermission("stgl:auditor:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "主键不能为空")
+ @PathVariable Long id) {
+ return R.ok(stglAuditorService.queryById(id));
+ }
+
+ /**
+ * 新增社团管理审核人配置
+ */
+ @SaCheckPermission("stgl:auditor:add")
+ @Log(title = "社团管理审核人配置", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R add(@Validated(AddGroup.class) @RequestBody StglAuditorBo bo) {
+ return toAjax(stglAuditorService.insertByBo(bo));
+ }
+
+ /**
+ * 修改社团管理审核人配置
+ */
+ @SaCheckPermission("stgl:auditor:edit")
+ @Log(title = "社团管理审核人配置", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R edit(@Validated(EditGroup.class) @RequestBody StglAuditorBo bo) {
+ return toAjax(stglAuditorService.updateByBo(bo));
+ }
+
+ /**
+ * 删除社团管理审核人配置
+ */
+ @SaCheckPermission("stgl:auditor:remove")
+ @Log(title = "社团管理审核人配置", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R remove(@NotEmpty(message = "主键不能为空")
+ @PathVariable Long[] ids) {
+ return toAjax(stglAuditorService.deleteWithValidByIds(List.of(ids)));
+ }
+
+ /**
+ * 批量添加审核人
+ */
+ @SaCheckPermission("stgl:auditor:add")
+ @Log(title = "批量添加审核人", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping("/batchAdd")
+ public R batchAdd(@RequestBody BatchAddRequest request) {
+ return toAjax(stglAuditorService.batchAddAuditors(request.getUserIds(), request.getRemark()));
+ }
+
+ /**
+ * 查询我配置的审核人列表
+ */
+ @SaCheckPermission("stgl:auditor:list")
+ @GetMapping("/myConfig")
+ public TableDataInfo myConfigList(StglAuditorBo bo, PageQuery pageQuery) {
+ return stglAuditorService.queryMyConfigList(bo, pageQuery);
+ }
+
+ /**
+ * 批量启用审核人
+ */
+ @SaCheckPermission("stgl:auditor:edit")
+ @Log(title = "启用审核人", businessType = BusinessType.UPDATE)
+ @PostMapping("/enable")
+ public R enable(@RequestBody List ids) {
+ return toAjax(stglAuditorService.enableAuditors(ids));
+ }
+
+ /**
+ * 批量停用审核人
+ */
+ @SaCheckPermission("stgl:auditor:edit")
+ @Log(title = "停用审核人", businessType = BusinessType.UPDATE)
+ @PostMapping("/disable")
+ public R disable(@RequestBody List ids) {
+ return toAjax(stglAuditorService.disableAuditors(ids));
+ }
+
+ /**
+ * 根据部门ID获取用户列表
+ */
+ @SaCheckPermission("stgl:auditor:list")
+ @GetMapping("/users/{deptId}")
+ public R> listUserByDeptId(@PathVariable String deptId) {
+ List users = sysUserService.selectUserListByDept(Long.valueOf(deptId));
+ return R.ok(users);
+ }
+
+ /**
+ * 批量添加请求对象
+ */
+ public static class BatchAddRequest {
+ private List userIds;
+ private String remark;
+
+ public List getUserIds() {
+ return userIds;
+ }
+
+ public void setUserIds(List userIds) {
+ this.userIds = userIds;
+ }
+
+ public String getRemark() {
+ return remark;
+ }
+
+ public void setRemark(String remark) {
+ this.remark = remark;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubAdvisorHistoryController.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubAdvisorHistoryController.java
new file mode 100644
index 00000000..42bb8e1d
--- /dev/null
+++ b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubAdvisorHistoryController.java
@@ -0,0 +1,147 @@
+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.StglClubAdvisorHistoryVo;
+import org.dromara.stgl.domain.bo.StglClubAdvisorHistoryBo;
+import org.dromara.stgl.service.IStglClubAdvisorHistoryService;
+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-03
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/stgl/club/advisor/history")
+@Tag(name = "社团指导老师任职历史管理", description = "社团指导老师任职历史管理")
+public class StglClubAdvisorHistoryController extends BaseController {
+
+ private final IStglClubAdvisorHistoryService stglClubAdvisorHistoryService;
+
+ /**
+ * 查询社团指导老师任职历史列表
+ */
+ @Operation(summary = "查询社团指导老师任职历史列表")
+ @SaCheckPermission("stgl:club:query")
+ @GetMapping("/list")
+ public TableDataInfo list(StglClubAdvisorHistoryBo bo, PageQuery pageQuery) {
+ return stglClubAdvisorHistoryService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 导出社团指导老师任职历史列表
+ */
+ @Operation(summary = "导出社团指导老师任职历史列表")
+ @SaCheckPermission("stgl:club:export")
+ @Log(title = "社团指导老师任职历史", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(StglClubAdvisorHistoryBo bo, HttpServletResponse response) {
+ List list = stglClubAdvisorHistoryService.queryList(bo);
+ ExcelUtil.exportExcel(list, "社团指导老师任职历史", StglClubAdvisorHistoryVo.class, response);
+ }
+
+ /**
+ * 获取社团指导老师任职历史详细信息
+ */
+ @Operation(summary = "获取社团指导老师任职历史详细信息")
+ @SaCheckPermission("stgl:club:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
+ return R.ok(stglClubAdvisorHistoryService.queryById(id));
+ }
+
+ /**
+ * 查询指定社团的当前在任指导老师
+ */
+ @Operation(summary = "查询指定社团的当前在任指导老师")
+ @SaCheckPermission("stgl:club:query")
+ @GetMapping("/current/{clubId}")
+ @Parameter(name = "clubId", description = "社团ID", required = true)
+ public R> getCurrentAdvisors(@PathVariable Long clubId) {
+ List list = stglClubAdvisorHistoryService.getCurrentAdvisorsByClubId(clubId);
+ return R.ok(list);
+ }
+
+ /**
+ * 查询指定社团的历史指导老师(已离任)
+ */
+ @Operation(summary = "查询指定社团的历史指导老师")
+ @SaCheckPermission("stgl:club:query")
+ @GetMapping("/history/{clubId}")
+ @Parameter(name = "clubId", description = "社团ID", required = true)
+ public R> getHistoryAdvisors(@PathVariable Long clubId) {
+ List list = stglClubAdvisorHistoryService.getHistoryAdvisorsByClubId(clubId);
+ return R.ok(list);
+ }
+
+ /**
+ * 查询指定社团的所有指导老师(包含当前和历史)
+ */
+ @Operation(summary = "查询指定社团的所有指导老师")
+ @SaCheckPermission("stgl:club:query")
+ @GetMapping("/all/{clubId}")
+ @Parameter(name = "clubId", description = "社团ID", required = true)
+ public R> getAllAdvisors(@PathVariable Long clubId) {
+ List list = stglClubAdvisorHistoryService.getAllAdvisorsByClubId(clubId);
+ return R.ok(list);
+ }
+
+ /**
+ * 新增社团指导老师任职历史
+ */
+ @Operation(summary = "新增社团指导老师任职历史")
+ @SaCheckPermission("stgl:club:add")
+ @Log(title = "社团指导老师任职历史", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R add(@Validated(AddGroup.class) @RequestBody StglClubAdvisorHistoryBo bo) {
+ return toAjax(stglClubAdvisorHistoryService.insertByBo(bo));
+ }
+
+ /**
+ * 修改社团指导老师任职历史
+ */
+ @Operation(summary = "修改社团指导老师任职历史")
+ @SaCheckPermission("stgl:club:edit")
+ @Log(title = "社团指导老师任职历史", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R edit(@Validated(EditGroup.class) @RequestBody StglClubAdvisorHistoryBo bo) {
+ return toAjax(stglClubAdvisorHistoryService.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(stglClubAdvisorHistoryService.deleteWithValidByIds(List.of(ids), true));
+ }
+
+}
\ No newline at end of file
diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubAnnualReviewController.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubAnnualReviewController.java
new file mode 100644
index 00000000..437086b7
--- /dev/null
+++ b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubAnnualReviewController.java
@@ -0,0 +1,213 @@
+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.StglClubAnnualReviewVo;
+import org.dromara.stgl.domain.bo.StglClubAnnualReviewBo;
+import org.dromara.stgl.service.IStglClubAnnualReviewService;
+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/annualReview")
+@Tag(name = "社团年审记录管理", description = "社团年审记录管理")
+public class StglClubAnnualReviewController extends BaseController {
+
+ private final IStglClubAnnualReviewService stglClubAnnualReviewService;
+
+ /**
+ * 查询社团年审记录列表
+ */
+ @Operation(summary = "查询社团年审记录列表")
+ @SaCheckPermission("stgl:clubAnnualReview:list")
+ @GetMapping("/list")
+ public TableDataInfo list(StglClubAnnualReviewBo bo, PageQuery pageQuery) {
+ return stglClubAnnualReviewService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 查询我的社团年审记录列表
+ */
+ @Operation(summary = "查询我的社团年审记录列表")
+ @SaCheckPermission("stgl:clubAnnualReview:myList")
+ @GetMapping("/myList")
+ public TableDataInfo myList(StglClubAnnualReviewBo bo, PageQuery pageQuery) {
+ return stglClubAnnualReviewService.queryMyPageList(bo, pageQuery);
+ }
+
+ /**
+ * 导出社团年审记录列表
+ */
+ @Operation(summary = "导出社团年审记录列表")
+ @SaCheckPermission("stgl:clubAnnualReview:export")
+ @Log(title = "社团年审记录", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(StglClubAnnualReviewBo bo, HttpServletResponse response) {
+ List list = stglClubAnnualReviewService.queryList(bo);
+ ExcelUtil.exportExcel(list, "社团年审记录", StglClubAnnualReviewVo.class, response);
+ }
+
+ /**
+ * 获取社团年审记录详细信息
+ */
+ @Operation(summary = "获取社团年审记录详细信息")
+ @SaCheckPermission("stgl:clubAnnualReview:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "主键不能为空")
+ @PathVariable Long id) {
+ return R.ok(stglClubAnnualReviewService.queryById(id));
+ }
+
+ /**
+ * 新增社团年审记录
+ */
+ @Operation(summary = "新增社团年审记录")
+ @SaCheckPermission("stgl:clubAnnualReview:add")
+ @Log(title = "社团年审记录", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R add(@Validated(AddGroup.class) @RequestBody StglClubAnnualReviewBo bo) {
+ return toAjax(stglClubAnnualReviewService.insertByBo(bo));
+ }
+
+ /**
+ * 修改社团年审记录
+ */
+ @Operation(summary = "修改社团年审记录")
+ @SaCheckPermission("stgl:clubAnnualReview:edit")
+ @Log(title = "社团年审记录", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R edit(@Validated(EditGroup.class) @RequestBody StglClubAnnualReviewBo bo) {
+ return toAjax(stglClubAnnualReviewService.updateByBo(bo));
+ }
+
+ /**
+ * 删除社团年审记录
+ */
+ @Operation(summary = "删除社团年审记录")
+ @SaCheckPermission("stgl:clubAnnualReview:remove")
+ @Log(title = "社团年审记录", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R remove(@NotEmpty(message = "主键不能为空")
+ @PathVariable Long[] ids) {
+ return toAjax(stglClubAnnualReviewService.deleteWithValidByIds(List.of(ids), true));
+ }
+
+ /**
+ * 提交年审记录
+ */
+ @Operation(summary = "提交年审记录")
+ @SaCheckPermission("stgl:clubAnnualReview:submit")
+ @Log(title = "社团年审记录", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PostMapping("/submit/{id}")
+ public R submit(@NotNull(message = "主键不能为空")
+ @PathVariable Long id) {
+ return toAjax(stglClubAnnualReviewService.submitReview(id));
+ }
+
+ /**
+ * 撤回年审记录
+ */
+ @Operation(summary = "撤回年审记录")
+ @SaCheckPermission("stgl:clubAnnualReview:withdraw")
+ @Log(title = "社团年审记录", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PostMapping("/withdraw/{id}")
+ public R withdraw(@NotNull(message = "主键不能为空")
+ @PathVariable Long id) {
+ return toAjax(stglClubAnnualReviewService.withdrawReview(id));
+ }
+
+ /**
+ * 审核年审记录
+ */
+ @Operation(summary = "审核年审记录")
+ @SaCheckPermission("stgl:clubAnnualReview:audit")
+ @Log(title = "社团年审记录", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PostMapping("/audit")
+ public R audit(@RequestParam @NotNull(message = "年审记录ID不能为空") Long id,
+ @RequestParam @NotBlank(message = "审核结果不能为空") String auditResult,
+ @RequestParam String auditOpinion,
+ @RequestParam @NotBlank(message = "审核类型不能为空") String auditType) {
+ return toAjax(stglClubAnnualReviewService.auditReview(id, auditResult, auditOpinion, auditType));
+ }
+
+ /**
+ * 检查是否可以创建年审记录
+ */
+ @Operation(summary = "检查是否可以创建年审记录")
+ @SaCheckPermission("stgl:clubAnnualReview:check")
+ @GetMapping("/check")
+ public R checkCanCreate(@RequestParam @NotNull(message = "社团ID不能为空") Long clubId,
+ @RequestParam @NotNull(message = "年审年度不能为空") Integer reviewYear) {
+ return R.ok(stglClubAnnualReviewService.checkCanCreateReview(clubId, reviewYear));
+ }
+
+ /**
+ * 获取年审状态选项
+ */
+ @Operation(summary = "获取年审状态选项")
+ @GetMapping("/statusOptions")
+ public R> getStatusOptions() {
+ List options = List.of("0", "1", "2", "3", "4");
+ return R.ok(options);
+ }
+
+ /**
+ * 根据社团ID和年审年度获取该年度的活动数据
+ */
+ @Operation(summary = "根据社团ID和年审年度获取该年度的活动数据")
+ @Parameters({
+ @Parameter(name = "clubId", description = "社团ID", required = true),
+ @Parameter(name = "reviewYear", description = "年审年度", required = true)
+ })
+ @SaCheckPermission("stgl:clubAnnualReview:query")
+ @GetMapping("/clubActivities")
+ public R> getClubActivities(
+ @RequestParam @NotNull(message = "社团ID不能为空") Long clubId,
+ @RequestParam @NotNull(message = "年审年度不能为空") Integer reviewYear) {
+ return R.ok(stglClubAnnualReviewService.getClubActivitiesByReviewYear(clubId, reviewYear));
+ }
+
+ /**
+ * 根据年审记录ID获取对应的活动数据
+ */
+ @Operation(summary = "根据年审记录ID获取对应的活动数据")
+ @Parameter(name = "id", description = "年审记录ID", required = true)
+ @SaCheckPermission("stgl:clubAnnualReview:query")
+ @GetMapping("/{id}/activities")
+ public R> getAnnualReviewActivities(
+ @NotNull(message = "年审记录ID不能为空") @PathVariable Long id) {
+ return R.ok(stglClubAnnualReviewService.getAnnualReviewActivities(id));
+ }
+
+}
\ No newline at end of file
diff --git a/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubPermissionController.java b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubPermissionController.java
new file mode 100644
index 00000000..4c2565c9
--- /dev/null
+++ b/backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/controller/StglClubPermissionController.java
@@ -0,0 +1,200 @@
+package org.dromara.stgl.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.stgl.domain.vo.ClubActivityPermissionResult;
+import org.dromara.stgl.service.IStglClubPermissionService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 社团权限管理Controller
+ *
+ * @author Cursor AI
+ * @date 2025-01-15
+ */
+@Slf4j
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/stgl/club/permission")
+public class StglClubPermissionController extends BaseController {
+
+ private final IStglClubPermissionService clubPermissionService;
+
+ /**
+ * 检查社团活动权限
+ * 前端每次进入活动管理页面都会调用这个接口
+ *
+ * @param clubId 社团ID
+ * @return 权限检查结果
+ */
+ @SaCheckPermission("stgl:club:list")
+ @GetMapping("/checkActivityPermission/{clubId}")
+ @Log(title = "检查社团活动权限", businessType = BusinessType.OTHER)
+ public R checkActivityPermission(@PathVariable Long clubId) {
+ log.info("检查社团活动权限请求,clubId: {}", clubId);
+
+ if (clubId == null || clubId <= 0) {
+ return R.fail("社团ID不能为空");
+ }
+
+ try {
+ ClubActivityPermissionResult result = clubPermissionService.checkClubActivityPermission(clubId);
+ log.info("社团ID: {} 权限检查结果: {}", clubId, result.getStatus());
+ return R.ok(result);
+ } catch (Exception e) {
+ log.error("检查社团活动权限失败,clubId: {}", clubId, e);
+ return R.fail("检查权限失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 批量检查多个社团的权限状态
+ * 用于列表页面显示多个社团的权限状态
+ *
+ * @param clubIds 社团ID列表
+ * @return 权限检查结果映射
+ */
+ @SaCheckPermission("stgl:club:list")
+ @PostMapping("/batchCheckPermission")
+ @Log(title = "批量检查社团权限", businessType = BusinessType.OTHER)
+ public R