This commit is contained in:
李旭明 committed 2025-08-23 09:58:59 +08:00
1 parent e5029688e5
commit 0db0a99c85
288 files changed
+41335 -11400

No files matched your search

+145 -1
View File
@@ -161,4 +161,148 @@ coverage/
*.crt
*.p12
*.keystore/xgxt/
excel/
excel/
backend/script/sql/add-related-type-field.sql
backend/script/sql/execute-fix-stgl-member.sql
backend/script/sql/fix-stgl-activity-remark-field.sql
backend/script/sql/fix-stgl-member-remark-field.sql
backend/script/sql/stgl_dict_data.sql
backend/script/sql/stgl_menu_init.sql
backend/script/sql/stgl_volunteer_role_dict.sql
backend/script/sql/xljk-dict-data.sql
backend/sql/stgl_volunteer_team_menu.sql
backend/sql/stgl_volunteer_team.sql
backend/sql/volunteer_apply_permission.sql
docs/sql/stgl_material_task_add_remark_field.sql
docs/变更管理/材料收集管理模块开发完成-2025-01-03-lixuming.md
docs/变更管理/材料收集任务查询SQL错误修复-2025-01-03-system.md
docs/变更管理/材料提交记录SQL错误修复-2025-08-22-system.md
docs/变更管理/活动报名成绩录入优化-2025-08-21-lixuming.md
docs/变更管理/活动报名大厅团队报名优化-2025-01-03-lixuming.md
docs/变更管理/活动报名管理审核功能优化-2025-01-15-lixuming.md
docs/变更管理/活动报名状态动态计算优化-2025-01-21-system.md
docs/变更管理/社团管理字段名称一致性检查报告.md
docs/变更管理/code-adjust-record-2025-01-03-lixuming.md
docs/变更管理/code-adjust-record-2025-01-03-system.md
docs/变更管理/code-adjust-record-2025-01-05-system.md
docs/变更管理/code-adjust-record-2025-01-07-cursor.md
docs/变更管理/code-adjust-record-2025-01-07-lixuming.md
docs/变更管理/code-adjust-record-2025-01-08-assistant.md
docs/变更管理/code-adjust-record-2025-01-08-cursor.md
docs/变更管理/code-adjust-record-2025-01-08-lixuming.md
docs/变更管理/code-adjust-record-2025-01-10-CursorAI.md
docs/变更管理/code-adjust-record-2025-01-14-cursor.md
docs/变更管理/code-adjust-record-2025-01-15-compilation-fix.md
docs/变更管理/code-adjust-record-2025-01-15-cursor.md
docs/变更管理/code-adjust-record-2025-01-15-lixuming.md
docs/变更管理/code-adjust-record-2025-01-15-volunteer-consistency-fix.md
docs/变更管理/code-adjust-record-2025-01-15-volunteer-member-404-fix.md
docs/变更管理/code-adjust-record-2025-01-15-volunteer-member-api-import-fix.md
docs/变更管理/code-adjust-record-2025-01-15-volunteer-member-resetform-fix.md
docs/变更管理/code-adjust-record-2025-01-15-volunteer-member-search-optimization.md
docs/变更管理/code-adjust-record-2025-01-15-volunteer-member-ui-enhancement.md
docs/变更管理/code-adjust-record-2025-01-15-volunteer-team-selector.md
docs/变更管理/code-adjust-record-2025-01-16-lixuming.md
docs/变更管理/code-adjust-record-2025-01-17-CursorAI.md
docs/变更管理/code-adjust-record-2025-01-18-lixuming.md
docs/变更管理/code-adjust-record-2025-01-19-cursor.md
docs/变更管理/code-adjust-record-2025-01-20-lixuming.md
docs/变更管理/code-adjust-record-2025-01-21-AI.md
docs/变更管理/code-adjust-record-2025-01-21-cursor.md
docs/变更管理/code-adjust-record-2025-01-21-lixuming-club-optimization.md
docs/变更管理/code-adjust-record-2025-01-21-lixuming.md
docs/变更管理/code-adjust-record-2025-01-22-cursor-fix-copy-activity.md
docs/变更管理/code-adjust-record-2025-01-26-cursor.md
docs/变更管理/code-adjust-record-2025-01-26-lixuming.md
docs/变更管理/code-adjust-record-2025-01-27-lixuming.md
docs/变更管理/code-adjust-record-2025-01-27-volunteer-permission-fix.md
docs/变更管理/code-adjust-record-2025-01-28-lixuming.md
docs/变更管理/code-adjust-record-2025-01-31-cursor.md
docs/变更管理/code-adjust-record-2025-01-31-lixuming-stgl-activity-export.md
docs/变更管理/code-adjust-record-2025-01-31-lixuming.md
docs/变更管理/code-adjust-record-2025-07-01-assistant.md
docs/变更管理/code-adjust-record-2025-07-01-lixuming.md
docs/变更管理/code-adjust-record-2025-08-08-lixuming.md
docs/变更管理/code-adjust-record-2025-08-12-cursor.md
docs/变更管理/code-adjust-record-2025-08-13-cursor.md
docs/变更管理/code-adjust-record-2025-08-13-lixuming.md
docs/变更管理/code-adjust-record-2025-08-15-dict-loading-fix.md
docs/变更管理/code-adjust-record-2025-08-18-lixuming.md
docs/变更管理/code-adjust-record-2025-08-19-志愿者报名状态字段修复.md
docs/变更管理/code-adjust-record-2025-08-19-lixuming.md
docs/变更管理/code-adjust-record-2025-08-19-stgl-member-clubName-search-fix.md
docs/变更管理/code-adjust-record-2025-08-20-lixuming.md
docs/变更管理/code-adjust-record-2025-08-21-lixuming.md
docs/变更管理/code-adjust-record-2025-08-22-lixuming.md
docs/变更管理/database-alter-stgl-club-add-remark-2025-07-01.sql
docs/变更管理/fix-stgl-member-remark-field-2025-01-07.sql
docs/开发文档/权限分离方案实施说明.md
docs/开发文档/社团管理表单验证修复说明.md
docs/开发文档/学生数据加载性能优化说明.md
docs/开发文档/学生选择弹窗关闭问题修复说明.md
docs/开发文档/指导老师选择弹窗数据获取问题修复说明.md
docs/开发文档/API权限字符-活动考勤签到管理.md
docs/开发文档/stgl_backend_development_summary.md
docs/开发文档/API/社团管理API.md
docs/开发文档/API/志愿者报名管理API.md
docs/变更管理/code-adjust-record-2025-01-08-cursor.md
docs/变更管理/code-adjust-record-2025-01-14-cursor.md
docs/变更管理/code-adjust-record-2025-01-15-cursor.md
docs/变更管理/code-adjust-record-2025-01-21-cursor.md
docs/开发文档/API/社团管理API.md
我的报名模块开发方案.md
docs/变更管理/code-adjust-record-2025-01-08-cursor.md
docs/变更管理/code-adjust-record-2025-01-14-cursor.md
docs/变更管理/code-adjust-record-2025-01-15-cursor.md
docs/变更管理/code-adjust-record-2025-01-21-cursor.md
docs/开发文档/API/社团管理API.md
docs/设计文档/database/教师数据初始化脚本.sql
docs/设计文档/database/社团管理/活动考勤签到管理-字段长度更新.sql
docs/设计文档/database/社团管理/活动考勤签到管理数据库设计.sql
docs/设计文档/database/社团管理/社团成员数量修复总结.md
docs/设计文档/database/社团管理/社团管理菜单权限配置修正版.sql
docs/设计文档/database/社团管理/社团管理菜单权限配置增量版.sql
docs/设计文档/database/社团管理/社团管理菜单权限配置正确版.sql
docs/设计文档/database/社团管理/社团管理菜单权限配置最终版.sql
docs/设计文档/database/社团管理/社团管理建表脚本.sql
docs/设计文档/database/社团管理/修复活动报名表字段.sql
docs/设计文档/database/社团管理/学生社团管理菜单结构对比分析.md
docs/设计文档/database/社团管理/学生社团管理菜单配置优化版.sql
docs/需求文档/社团管理需求/社团管理系统需求说明.md
script/fix-activity-display-fields.sql
script/material_management_config.sql
script/stgl-activity-register-menu.sql
script/test-volunteer-member-permission.md
docs/变更管理/code-adjust-record-2025-01-08-cursor.md
docs/变更管理/code-adjust-record-2025-01-14-cursor.md
docs/变更管理/code-adjust-record-2025-01-15-cursor.md
docs/变更管理/code-adjust-record-2025-01-21-cursor.md
docs/开发文档/API/社团管理API.md
docs/设计文档/database/社团管理/社团管理建表脚本.sql
docs/需求文档/社团管理需求/社团管理系统需求说明.md
script/update-volunteer-role-dict.sql
script/sql/add-activity-attachment-fields.sql
script/sql/fix-activity-related-type.sql
test/stgl_api_test.py
test/stgl-api-test.js
docs/变更管理/code-adjust-record-2025-01-08-cursor.md
docs/变更管理/code-adjust-record-2025-01-14-cursor.md
docs/变更管理/code-adjust-record-2025-01-15-cursor.md
docs/变更管理/code-adjust-record-2025-01-21-cursor.md
docs/开发文档/API/社团管理API.md
docs/设计文档/database/社团管理/社团管理建表脚本.sql
docs/需求文档/社团管理需求/社团管理系统需求说明.md
docs/变更管理/code-adjust-record-2025-01-08-cursor.md
docs/变更管理/code-adjust-record-2025-01-14-cursor.md
docs/变更管理/code-adjust-record-2025-01-15-cursor.md
docs/变更管理/code-adjust-record-2025-01-21-cursor.md
docs/开发文档/API/社团管理API.md
docs/设计文档/database/社团管理/社团管理建表脚本.sql
docs/需求文档/社团管理需求/社团管理系统需求说明.md
docs/变更管理/code-adjust-record-2025-01-08-cursor.md
docs/变更管理/code-adjust-record-2025-01-08-cursor.md
docs/变更管理/code-adjust-record-2025-01-08-cursor.md
docs/变更管理/code-adjust-record-2025-01-08-cursor.md
docs/变更管理/code-adjust-record-2025-01-08-cursor.md
docs/变更管理/code-adjust-record-2025-01-14-cursor.md
docs/设计文档/database/社团管理/社团管理建表脚本.sql
@@ -1,2 +0,0 @@
-- 添加批次ID字段
ALTER TABLE xljk_consultation_schedule ADD COLUMN batch_id VARCHAR(50) DEFAULT NULL COMMENT '批次ID,用于标识同一批次创建的预约时段';
+6
View File
@@ -88,6 +88,12 @@
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<!-- 学工模块 - 用于访问学生信息 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-xg</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,148 @@
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.StglActivityAttendanceVo;
import org.dromara.stgl.domain.bo.StglActivityAttendanceBo;
import org.dromara.stgl.service.IStglActivityAttendanceService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
/**
* 活动考勤签到
*
* @author ruoyi
* @date 2025-01-15
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/stgl/activityAttendance")
public class StglActivityAttendanceController extends BaseController {
private final IStglActivityAttendanceService stglActivityAttendanceService;
/**
* 查询活动考勤签到列表
*/
@SaCheckPermission("stgl:activityAttendance:list")
@GetMapping("/list")
public TableDataInfo<StglActivityAttendanceVo> list(StglActivityAttendanceBo bo, PageQuery pageQuery) {
return stglActivityAttendanceService.queryPageList(bo, pageQuery);
}
/**
* 导出活动考勤签到列表
*/
@SaCheckPermission("stgl:activityAttendance:export")
@Log(title = "活动考勤签到", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(StglActivityAttendanceBo bo, HttpServletResponse response) {
List<StglActivityAttendanceVo> list = stglActivityAttendanceService.queryList(bo);
ExcelUtil.exportExcel(list, "活动考勤签到", StglActivityAttendanceVo.class, response);
}
/**
* 获取活动考勤签到详细信息
*/
@SaCheckPermission("stgl:activityAttendance:query")
@GetMapping("/{id}")
public R<StglActivityAttendanceVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(stglActivityAttendanceService.queryById(id));
}
/**
* 新增活动考勤签到
*/
@SaCheckPermission("stgl:activityAttendance:add")
@Log(title = "活动考勤签到", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglActivityAttendanceBo bo) {
return toAjax(stglActivityAttendanceService.insertByBo(bo));
}
/**
* 修改活动考勤签到
*/
@SaCheckPermission("stgl:activityAttendance:edit")
@Log(title = "活动考勤签到", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglActivityAttendanceBo bo) {
return toAjax(stglActivityAttendanceService.updateByBo(bo));
}
/**
* 删除活动考勤签到
*/
@SaCheckPermission("stgl:activityAttendance:remove")
@Log(title = "活动考勤签到", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(stglActivityAttendanceService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 查询用户已报名成功且进行中的活动列表
*/
@SaCheckPermission("stgl:activityAttendance:list")
@GetMapping("/userAvailableActivities")
public R<List<StglActivityAttendanceVo>> getUserAvailableActivities() {
Long userId = LoginHelper.getUserId();
return R.ok(stglActivityAttendanceService.queryUserAvailableActivities(userId));
}
/**
* 根据活动ID和用户ID查询签到记录
*/
@SaCheckPermission("stgl:activityAttendance:query")
@GetMapping("/getByActivityAndUser")
public R<StglActivityAttendanceVo> getByActivityAndUser(@RequestParam Long activityId) {
Long userId = LoginHelper.getUserId();
return R.ok(stglActivityAttendanceService.queryByActivityAndUser(activityId, userId));
}
/**
* 用户签到
*/
@SaCheckPermission("stgl:activityAttendance:signIn")
@Log(title = "活动签到", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/signIn")
public R<Void> signIn(@Validated @RequestBody StglActivityAttendanceBo bo) {
// 设置当前登录用户ID
bo.setUserId(LoginHelper.getUserId());
return toAjax(stglActivityAttendanceService.signIn(bo));
}
/**
* 用户签退
*/
@SaCheckPermission("stgl:activityAttendance:signOut")
@Log(title = "活动签退", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/signOut")
public R<Void> signOut(@Validated @RequestBody StglActivityAttendanceBo bo) {
// 设置当前登录用户ID
bo.setUserId(LoginHelper.getUserId());
return toAjax(stglActivityAttendanceService.signOut(bo));
}
}
@@ -0,0 +1,146 @@
package org.dromara.stgl.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.MapstructUtils;
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.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.dromara.stgl.domain.bo.StglActivityBo;
import org.dromara.stgl.domain.vo.StglActivityVo;
import org.dromara.stgl.service.IStglActivityService;
import java.util.List;
/**
* 活动信息
*
* @author ruoyi
* @date 2025-01-07
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/stgl/activity")
public class StglActivityController extends BaseController {
private final IStglActivityService stglActivityService;
/**
* 查询活动信息列表
*/
@SaCheckPermission("stgl:activity:list")
@GetMapping("/list")
public TableDataInfo<StglActivityVo> list(StglActivityBo bo, PageQuery pageQuery) {
return stglActivityService.queryPageList(bo, pageQuery);
}
/**
* 导出活动信息列表
*/
@SaCheckPermission("stgl:activity:export")
@Log(title = "活动信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(StglActivityBo bo, HttpServletResponse response) {
List<StglActivityVo> list = stglActivityService.queryList(bo);
ExcelUtil.exportExcel(list, "活动信息", StglActivityVo.class, response);
}
/**
* 获取活动信息详细信息
*/
@SaCheckPermission("stgl:activity:query")
@GetMapping("/{id}")
public R<StglActivityVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(stglActivityService.queryById(id));
}
/**
* 新增活动信息
*/
@SaCheckPermission("stgl:activity:add")
@Log(title = "活动信息", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglActivityBo bo) {
return toAjax(stglActivityService.insertByBo(bo));
}
/**
* 修改活动信息
*/
@SaCheckPermission("stgl:activity:edit")
@Log(title = "活动信息", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglActivityBo bo) {
return toAjax(stglActivityService.updateByBo(bo));
}
/**
* 删除活动信息
*/
@SaCheckPermission("stgl:activity:remove")
@Log(title = "活动信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(stglActivityService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 复制活动信息
*/
@SaCheckPermission("stgl:activity:add")
@Log(title = "复制活动信息", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/copy")
public R<Void> copy(@RequestParam("sourceId") Long sourceId, @RequestParam("newActivityName") String newActivityName) {
return toAjax(stglActivityService.copyActivity(sourceId, newActivityName));
}
/**
* 活动总结
*/
@SaCheckPermission("stgl:activity:edit")
@Log(title = "活动总结", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/summarize")
public R<Void> summarize(@RequestParam("id") Long id,
@RequestParam(value = "summary", required = false) String summary,
@RequestParam(value = "achievements", required = false) String achievements,
@RequestParam(value = "summaryAttachments", required = false) String summaryAttachments,
@RequestParam(value = "achievementsAttachments", required = false) String achievementsAttachments) {
return toAjax(stglActivityService.summarizeActivity(id, summary, achievements, summaryAttachments, achievementsAttachments));
}
/**
* 查询社团选择器选项
*/
@SaCheckPermission("stgl:activity:query")
@GetMapping("/club/options")
public R<List<StglActivityVo>> getClubOptions() {
return R.ok(stglActivityService.queryClubOptions());
}
/**
* 查询志愿者队伍选择器选项
*/
@SaCheckPermission("stgl:activity:query")
@GetMapping("/volunteer/options")
public R<List<StglActivityVo>> getVolunteerTeamOptions() {
return R.ok(stglActivityService.queryVolunteerTeamOptions());
}
}
@@ -0,0 +1,137 @@
package org.dromara.stgl.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
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.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.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.stgl.domain.bo.BatchApprovalBo;
import org.dromara.stgl.domain.bo.StglActivityRegistrationBo;
import org.dromara.stgl.domain.vo.StglActivityRegistrationVo;
import org.dromara.stgl.service.IStglActivityRegistrationService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 活动报名管理Controller
*
* @author ruoyi
* @date 2025-01-31
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/stgl/activity/register")
public class StglActivityRegisterController extends BaseController {
private final IStglActivityRegistrationService stglActivityRegistrationService;
/**
* 查询活动报名管理列表
*/
@SaCheckPermission("stgl:activityRegister:list")
@GetMapping("/list")
public TableDataInfo<StglActivityRegistrationVo> list(StglActivityRegistrationBo bo, PageQuery pageQuery) {
return stglActivityRegistrationService.queryPageList(bo, pageQuery);
}
/**
* 导出活动报名管理列表
*/
@SaCheckPermission("stgl:activityRegister:export")
@Log(title = "活动报名管理", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(StglActivityRegistrationBo bo, HttpServletResponse response) {
List<StglActivityRegistrationVo> list = stglActivityRegistrationService.queryList(bo);
ExcelUtil.exportExcel(list, "活动报名管理", StglActivityRegistrationVo.class, response);
}
/**
* 获取活动报名管理详细信息
*/
@SaCheckPermission("stgl:activityRegister:query")
@GetMapping("/{id}")
public R<StglActivityRegistrationVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(stglActivityRegistrationService.queryById(id));
}
/**
* 新增活动报名管理
*/
@SaCheckPermission("stgl:activityRegister:add")
@Log(title = "活动报名管理", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglActivityRegistrationBo bo) {
return toAjax(stglActivityRegistrationService.insertByBo(bo));
}
/**
* 修改活动报名管理
*/
@SaCheckPermission("stgl:activityRegister:edit")
@Log(title = "活动报名管理", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglActivityRegistrationBo bo) {
return toAjax(stglActivityRegistrationService.updateByBo(bo));
}
/**
* 删除活动报名管理
*/
@SaCheckPermission("stgl:activityRegister:remove")
@Log(title = "活动报名管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(stglActivityRegistrationService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 审核活动报名
*/
@SaCheckPermission("stgl:activityRegister:approve")
@Log(title = "活动报名审核", businessType = BusinessType.UPDATE)
@PostMapping("/approve/{id}")
public R<Void> approve(@NotNull(message = "主键不能为空") @PathVariable Long id,
@RequestParam Integer approvalStatus,
@RequestParam(required = false) String approvalRemark) {
StglActivityRegistrationBo bo = new StglActivityRegistrationBo();
bo.setId(id);
bo.setApprovalStatus(approvalStatus.toString());
bo.setApprovalRemark(approvalRemark);
bo.setApprovalBy(LoginHelper.getUserId());
return toAjax(stglActivityRegistrationService.updateByBo(bo));
}
/**
* 批量审核活动报名
*/
@SaCheckPermission("stgl:activityRegister:approve")
@Log(title = "活动报名批量审核", businessType = BusinessType.UPDATE)
@PostMapping("/batchApprove")
public R<Void> batchApprove(@Validated @RequestBody BatchApprovalBo batchApprovalBo) {
return toAjax(stglActivityRegistrationService.batchApprove(batchApprovalBo.getIds(), batchApprovalBo.getApprovalStatus(), batchApprovalBo.getApprovalRemark(), LoginHelper.getUserId()));
}
/**
* 录入成绩
*/
@SaCheckPermission("stgl:activityRegister:recordScore")
@Log(title = "录入成绩", businessType = BusinessType.UPDATE)
@PostMapping("/score/{id}")
public R<Void> recordScore(@NotNull(message = "主键不能为空") @PathVariable Long id,
@RequestParam String score) {
return toAjax(stglActivityRegistrationService.inputScore(id, score));
}
}
@@ -0,0 +1,83 @@
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.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.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.stgl.domain.bo.StglActivityBo;
import org.dromara.stgl.domain.bo.StglActivityRegistrationBo;
import org.dromara.stgl.domain.vo.StglActivityVo;
import org.dromara.stgl.domain.vo.StglActivityRegistrationVo;
import org.dromara.stgl.service.IStglActivityService;
import org.dromara.stgl.service.IStglActivityRegistrationService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 活动报名大厅Controller
*
* @author ruoyi
* @date 2025-01-31
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/stgl/activity/registerhall")
public class StglActivityRegisterHallController extends BaseController {
private final IStglActivityService stglActivityService;
private final IStglActivityRegistrationService stglActivityRegistrationService;
/**
* 查询可报名活动列表(仅显示报名状态为0和1的活动)
*/
@GetMapping("/list")
public TableDataInfo<StglActivityVo> list(StglActivityBo bo, PageQuery pageQuery) {
// 设置查询条件:只查询报名状态为0(未开始)和1(报名中)的活动
return stglActivityService.queryRegistrableActivityList(bo, pageQuery);
}
/**
* 获取活动详细信息
*/
@GetMapping("/{id}")
public R<StglActivityVo> getInfo(@PathVariable Long id) {
return R.ok(stglActivityService.queryById(id));
}
/**
* 学生报名活动
*/
@Log(title = "活动报名", businessType = BusinessType.INSERT)
@PostMapping("/register")
public R<Void> register(@Validated(AddGroup.class) @RequestBody StglActivityRegistrationBo bo) {
// 设置当前用户ID
bo.setUserId(LoginHelper.getUserId());
return toAjax(stglActivityRegistrationService.register(bo));
}
/**
* 检查用户是否已报名某活动
*/
@GetMapping("/checkRegistration/{activityId}")
public R<Boolean> checkRegistration(@PathVariable Long activityId) {
Long userId = LoginHelper.getUserId();
boolean isRegistered = stglActivityRegistrationService.checkUserRegistration(activityId, userId);
return R.ok(isRegistered);
}
/**
* 获取用户的报名记录
*/
@GetMapping("/myRegistrations")
public TableDataInfo<StglActivityRegistrationVo> getMyRegistrations(PageQuery pageQuery) {
Long userId = LoginHelper.getUserId();
return stglActivityRegistrationService.queryUserRegistrations(userId, pageQuery);
}
}
@@ -0,0 +1,159 @@
package org.dromara.stgl.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
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.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.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.stgl.domain.bo.StglActivityRegistrationBo;
import org.dromara.stgl.domain.vo.StglActivityRegistrationVo;
import org.dromara.stgl.service.IStglActivityRegistrationService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 活动报名管理
*
* @author ruoyi
* @date 2024-12-19
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/stgl/activityregistration")
public class StglActivityRegistrationController extends BaseController {
private final IStglActivityRegistrationService stglActivityRegistrationService;
/**
* 查询活动报名列表
*/
@SaCheckPermission("stgl:activityregistration:list")
@GetMapping("/list")
public TableDataInfo<StglActivityRegistrationVo> list(StglActivityRegistrationBo bo, PageQuery pageQuery) {
return stglActivityRegistrationService.queryPageList(bo, pageQuery);
}
/**
* 导出活动报名列表
*/
@SaCheckPermission("stgl:activityregistration:export")
@Log(title = "活动报名", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(StglActivityRegistrationBo bo, HttpServletResponse response) {
List<StglActivityRegistrationVo> list = stglActivityRegistrationService.queryList(bo);
ExcelUtil.exportExcel(list, "活动报名", StglActivityRegistrationVo.class, response);
}
/**
* 获取活动报名详细信息
*/
@SaCheckPermission("stgl:activityregistration:query")
@GetMapping("/{id}")
public R<StglActivityRegistrationVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(stglActivityRegistrationService.queryById(id));
}
/**
* 新增活动报名
*/
@SaCheckPermission("stgl:activityregistration:add")
@Log(title = "活动报名", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglActivityRegistrationBo bo) {
return toAjax(stglActivityRegistrationService.insertByBo(bo));
}
/**
* 修改活动报名
*/
@SaCheckPermission("stgl:activityregistration:edit")
@Log(title = "活动报名", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglActivityRegistrationBo bo) {
return toAjax(stglActivityRegistrationService.updateByBo(bo));
}
/**
* 删除活动报名
*/
@SaCheckPermission("stgl:activityregistration:remove")
@Log(title = "活动报名", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(stglActivityRegistrationService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 审核活动报名
*/
@SaCheckPermission("stgl:activityregistration:approval")
@Log(title = "活动报名审核", businessType = BusinessType.UPDATE)
@PostMapping("/approval")
public R<Void> approval(@RequestParam Long id,
@RequestParam String approvalStatus,
@RequestParam(required = false) String approvalRemark) {
return toAjax(stglActivityRegistrationService.approvalRegistration(id, approvalStatus, approvalRemark));
}
/**
* 录入成绩
*/
@SaCheckPermission("stgl:activityregistration:score")
@Log(title = "录入成绩", businessType = BusinessType.UPDATE)
@PostMapping("/inputScore")
public R<Void> inputScore(@RequestParam Long id, @RequestParam String score) {
return toAjax(stglActivityRegistrationService.inputScore(id, score));
}
/**
* 检查用户是否已报名该活动
*/
@GetMapping("/checkRegistered")
public R<Boolean> checkRegistered(@RequestParam Long activityId, @RequestParam(required = false) Long userId) {
Long currentUserId = userId != null ? userId : LoginHelper.getUserId();
return R.ok(stglActivityRegistrationService.checkUserRegistered(activityId, currentUserId));
}
/**
* 获取用户在指定活动的报名信息
*/
@GetMapping("/getUserRegistration")
public R<StglActivityRegistrationVo> getUserRegistration(@RequestParam Long activityId, @RequestParam(required = false) Long userId) {
Long currentUserId = userId != null ? userId : LoginHelper.getUserId();
return R.ok(stglActivityRegistrationService.getUserRegistration(activityId, currentUserId));
}
/**
* 活动报名
*/
@Log(title = "活动报名", businessType = BusinessType.INSERT)
@PostMapping("/register")
public R<Void> register(@Validated(AddGroup.class) @RequestBody StglActivityRegistrationBo bo) {
// 设置当前用户ID
bo.setUserId(LoginHelper.getUserId());
return toAjax(stglActivityRegistrationService.register(bo));
}
/**
* 我的报名列表
*/
@GetMapping("/myRegistrations")
public TableDataInfo<StglActivityRegistrationVo> myRegistrations(StglActivityRegistrationBo bo, PageQuery pageQuery) {
// 只查询当前用户的报名记录
bo.setUserId(LoginHelper.getUserId());
return stglActivityRegistrationService.queryPageList(bo, pageQuery);
}
}
@@ -0,0 +1,105 @@
package org.dromara.stgl.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
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.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.bo.StglActivityTeamInfoBo;
import org.dromara.stgl.domain.vo.StglActivityTeamInfoVo;
import org.dromara.stgl.service.IStglActivityTeamInfoService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 活动团队信息管理
*
* @author ruoyi
* @date 2024-12-19
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/stgl/activityteaminfo")
public class StglActivityTeamInfoController extends BaseController {
private final IStglActivityTeamInfoService stglActivityTeamInfoService;
/**
* 查询活动团队信息列表
*/
@SaCheckPermission("stgl:activityteaminfo:list")
@GetMapping("/list")
public TableDataInfo<StglActivityTeamInfoVo> list(StglActivityTeamInfoBo bo, PageQuery pageQuery) {
return stglActivityTeamInfoService.queryPageList(bo, pageQuery);
}
/**
* 导出活动团队信息列表
*/
@SaCheckPermission("stgl:activityteaminfo:export")
@Log(title = "活动团队信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(StglActivityTeamInfoBo bo, HttpServletResponse response) {
List<StglActivityTeamInfoVo> list = stglActivityTeamInfoService.queryList(bo);
ExcelUtil.exportExcel(list, "活动团队信息", StglActivityTeamInfoVo.class, response);
}
/**
* 获取活动团队信息详细信息
*/
@SaCheckPermission("stgl:activityteaminfo:query")
@GetMapping("/{id}")
public R<StglActivityTeamInfoVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(stglActivityTeamInfoService.queryById(id));
}
/**
* 新增活动团队信息
*/
@SaCheckPermission("stgl:activityteaminfo:add")
@Log(title = "活动团队信息", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglActivityTeamInfoBo bo) {
return toAjax(stglActivityTeamInfoService.insertByBo(bo));
}
/**
* 修改活动团队信息
*/
@SaCheckPermission("stgl:activityteaminfo:edit")
@Log(title = "活动团队信息", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglActivityTeamInfoBo bo) {
return toAjax(stglActivityTeamInfoService.updateByBo(bo));
}
/**
* 删除活动团队信息
*/
@SaCheckPermission("stgl:activityteaminfo:remove")
@Log(title = "活动团队信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(stglActivityTeamInfoService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 根据活动ID查询团队列表
*/
@GetMapping("/activity/{activityId}")
public R<List<StglActivityTeamInfoVo>> getTeamsByActivityId(@PathVariable Long activityId) {
return R.ok(stglActivityTeamInfoService.queryByActivityId(activityId));
}
}
@@ -25,6 +25,7 @@ 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;
import org.dromara.common.satoken.utils.LoginHelper;
/**
* 社团信息管理
@@ -147,15 +148,69 @@ public class StglClubController extends BaseController {
* 检查社团名称是否重复
*/
@Operation(summary = "检查社团名称是否重复")
@SaCheckPermission("stgl:club:list")
@GetMapping("/checkClubNameUnique")
@SaCheckPermission("stgl:club:add")
@GetMapping("/checkClubName")
@Parameters({
@Parameter(name = "clubName", description = "社团名称", required = true),
@Parameter(name = "excludeId", description = "排除的ID", required = false)
@Parameter(name = "id", description = "社团ID,编辑时排除自己", required = false)
})
public R<Boolean> checkClubNameUnique(@RequestParam String clubName,
@RequestParam(required = false) Long excludeId) {
return R.ok(stglClubService.checkClubNameUnique(clubName, excludeId));
public R<Boolean> checkClubName(@RequestParam String clubName, @RequestParam(required = false) Long id) {
return R.ok(stglClubService.checkClubNameExists(clubName, id));
}
/**
* 验证当前用户是否为社团社长
*/
@Operation(summary = "验证当前用户是否为社团社长")
@SaCheckPermission("stgl:club:query")
@GetMapping("/checkPresident/{id}")
@Parameters({
@Parameter(name = "id", description = "社团ID", required = true)
})
public R<Boolean> checkPresidentRole(@PathVariable Long id) {
Long currentUserId = LoginHelper.getUserId();
if (currentUserId == null) {
return R.ok(false);
}
boolean isPresident = stglClubService.isClubPresident(id, currentUserId);
return R.ok(isPresident);
}
/**
* 社团转让
*/
@Operation(summary = "社团转让")
@SaCheckPermission("stgl:club:edit")
@Log(title = "社团转让", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/transfer/{id}")
@Parameters({
@Parameter(name = "id", description = "社团ID", required = true),
@Parameter(name = "newPresidentUserId", description = "新社长用户ID", required = true)
})
public R<Void> transferClub(@PathVariable Long id, @RequestParam Long newPresidentUserId) {
return toAjax(stglClubService.transferClub(id, newPresidentUserId));
}
/**
* 临时测试接口:验证副社长数据映射
*/
@Operation(summary = "测试副社长数据映射")
@SaCheckPermission("stgl:club:query")
@GetMapping("/testVicePresidentData/{id}")
public R<StglClubVo> testVicePresidentData(@PathVariable Long id) {
StglClubVo club = stglClubService.queryById(id);
if (club != null) {
// 输出调试信息到日志
System.out.println("=== 副社长数据测试 ===");
System.out.println("副社长姓名: " + club.getVicePresidentName());
System.out.println("副社长院系: " + club.getVicePresidentDept());
System.out.println("副社长专业: " + club.getVicePresidentMajor());
System.out.println("副社长班级: " + club.getVicePresidentClass());
System.out.println("副社长电话: " + club.getVicePresidentPhone());
System.out.println("=====================");
}
return R.ok(club);
}
/**
@@ -173,4 +228,17 @@ public class StglClubController extends BaseController {
return toAjax(stglClubService.changeStatus(id, status));
}
/**
* 修复已存在社团的成员记录
* 为缺失社长、副社长成员记录的社团补充相应记录
*/
@Operation(summary = "修复已存在社团的成员记录")
@SaCheckPermission("stgl:club:edit")
@Log(title = "社团信息", businessType = BusinessType.UPDATE)
@PostMapping("/fixMemberRecords")
public R<String> fixMemberRecords() {
Integer fixedCount = stglClubService.fixExistingClubMemberRecords();
return R.ok("成功修复 " + fixedCount + " 条社长/副社长成员记录");
}
}
@@ -20,6 +20,7 @@ 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;
import org.dromara.stgl.domain.bo.StglClubApplyBo;
/**
* 社团报名大厅
@@ -30,7 +31,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/stgl/register")
@RequestMapping("/stgl/clubRegister")
@Tag(name = "社团报名大厅", description = "社团报名大厅")
public class StglClubRegisterController extends BaseController {
@@ -40,6 +41,7 @@ public class StglClubRegisterController extends BaseController {
* 查询社团报名大厅列表
*/
@Operation(summary = "查询社团报名大厅列表")
@SaCheckPermission("stgl:club:list")
@GetMapping("/list")
public TableDataInfo<StglClubRegisterVo> list(@RequestParam(required = false) String clubType,
@RequestParam(required = false) String clubName,
@@ -70,18 +72,16 @@ public class StglClubRegisterController extends BaseController {
}
/**
* 报名加入社团
* 申请加入社团
*/
@Operation(summary = "报名加入社团")
@SaCheckPermission("stgl:register:join")
@Log(title = "社团报名", businessType = BusinessType.INSERT)
@PostMapping("/join/{clubId}")
@Parameters({
@Parameter(name = "clubId", description = "社团ID", required = true)
})
public R<Void> registerClub(@PathVariable Long clubId) {
@Operation(summary = "申请加入社团")
@SaCheckPermission("stgl:register:apply")
@Log(title = "社团申请", businessType = BusinessType.INSERT)
@PostMapping("/apply")
public R<Void> applyClub(@RequestParam Long clubId, @RequestBody StglClubApplyBo applyBo) {
Long userId = LoginHelper.getUserId();
return toAjax(stglClubRegisterService.registerClub(clubId, userId));
String reason = applyBo != null ? applyBo.getReason() : null;
return toAjax(stglClubRegisterService.registerClub(clubId, userId, reason));
}
/**
@@ -132,6 +132,7 @@ public class StglClubRegisterController extends BaseController {
* 查询推荐社团
*/
@Operation(summary = "查询推荐社团")
@SaCheckPermission("stgl:club:list")
@GetMapping("/recommend")
@Parameters({
@Parameter(name = "clubType", description = "社团类型", required = false),
@@ -0,0 +1,190 @@
package org.dromara.stgl.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.MapstructUtils;
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.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.dromara.stgl.domain.bo.StglMaterialSubmissionBo;
import org.dromara.stgl.domain.vo.StglMaterialSubmissionVo;
import org.dromara.stgl.service.IStglMaterialSubmissionService;
import java.util.List;
import java.util.Map;
/**
* 材料提交记录管理
*
* @author ruoyi
* @date 2025-01-03
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/stgl/activitymaterial/submission")
public class StglMaterialSubmissionController extends BaseController {
private final IStglMaterialSubmissionService materialSubmissionService;
/**
* 查询材料提交记录列表
*/
@SaCheckPermission("stgl:activitymaterial:query")
@GetMapping("/list")
public TableDataInfo<StglMaterialSubmissionVo> list(StglMaterialSubmissionBo bo, PageQuery pageQuery) {
return materialSubmissionService.queryPageList(bo, pageQuery);
}
/**
* 导出材料提交记录列表
*/
@SaCheckPermission("stgl:activitymaterial:export")
@Log(title = "材料提交记录", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(StglMaterialSubmissionBo bo, HttpServletResponse response) {
List<StglMaterialSubmissionVo> list = materialSubmissionService.queryList(bo);
ExcelUtil.exportExcel(list, "材料提交记录", StglMaterialSubmissionVo.class, response);
}
/**
* 获取材料提交记录详细信息
*/
@SaCheckPermission("stgl:activitymaterial:query")
@GetMapping("/{id}")
public R<StglMaterialSubmissionVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(materialSubmissionService.queryById(id));
}
/**
* 新增材料提交记录
*/
@SaCheckPermission("stgl:activitymaterial:upload")
@Log(title = "材料提交记录", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglMaterialSubmissionBo bo) {
return toAjax(materialSubmissionService.insertByBo(bo));
}
/**
* 修改材料提交记录
*/
@SaCheckPermission("stgl:activitymaterial:upload")
@Log(title = "材料提交记录", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglMaterialSubmissionBo bo) {
return toAjax(materialSubmissionService.updateByBo(bo));
}
/**
* 删除材料提交记录
*/
@SaCheckPermission("stgl:activitymaterial:remove")
@Log(title = "材料提交记录", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(materialSubmissionService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 材料上传
*/
@SaCheckPermission("stgl:activitymaterial:upload")
@Log(title = "材料上传", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/upload")
public R<Void> uploadMaterial(@Validated(AddGroup.class) @RequestBody StglMaterialSubmissionBo bo) {
return toAjax(materialSubmissionService.uploadMaterial(bo));
}
/**
* 根据任务ID查询提交记录
*/
@SaCheckPermission("stgl:activitymaterial:query")
@GetMapping("/task/{taskId}")
public R<List<StglMaterialSubmissionVo>> getByTaskId(@PathVariable Long taskId) {
List<StglMaterialSubmissionVo> submissions = materialSubmissionService.queryByTaskId(taskId);
return R.ok(submissions);
}
/**
* 查询用户在指定任务的提交记录
*/
@SaCheckPermission("stgl:activitymaterial:query")
@GetMapping("/task/{taskId}/user/{userId}")
public R<StglMaterialSubmissionVo> getByTaskIdAndUserId(@PathVariable Long taskId, @PathVariable Long userId) {
StglMaterialSubmissionVo submission = materialSubmissionService.queryByTaskIdAndUserId(taskId, userId);
return R.ok(submission);
}
/**
* 查询团队在指定任务的提交记录
*/
@SaCheckPermission("stgl:activitymaterial:query")
@GetMapping("/task/{taskId}/team/{teamId}")
public R<StglMaterialSubmissionVo> getByTaskIdAndTeamId(@PathVariable Long taskId, @PathVariable Long teamId) {
StglMaterialSubmissionVo submission = materialSubmissionService.queryByTaskIdAndTeamId(taskId, teamId);
return R.ok(submission);
}
/**
* 获取任务的提交统计信息
*/
@SaCheckPermission("stgl:activitymaterial:query")
@GetMapping("/statistics/{taskId}")
public R<Map<String, Object>> getSubmissionStatistics(@PathVariable Long taskId) {
Map<String, Object> statistics = materialSubmissionService.getSubmissionStatistics(taskId);
return R.ok(statistics);
}
/**
* 审核材料
*/
@SaCheckPermission("stgl:activitymaterial:review")
@Log(title = "材料审核", businessType = BusinessType.UPDATE)
@PutMapping("/review/{id}")
public R<Void> reviewSubmission(@PathVariable Long id,
@RequestParam Integer reviewStatus,
@RequestParam(required = false) String reviewRemark) {
if (reviewStatus != 1 && reviewStatus != 2) {
return R.fail("审核状态参数错误,只能为1(通过)或2(驳回)");
}
return toAjax(materialSubmissionService.reviewSubmission(id, reviewStatus, reviewRemark));
}
/**
* 批量审核材料
*/
@SaCheckPermission("stgl:activitymaterial:review")
@Log(title = "批量材料审核", businessType = BusinessType.UPDATE)
@PutMapping("/review/batch")
public R<Void> batchReviewSubmissions(@RequestParam String ids,
@RequestParam Integer reviewStatus,
@RequestParam(required = false) String reviewRemark) {
if (reviewStatus != 1 && reviewStatus != 2) {
return R.fail("审核状态参数错误,只能为1(通过)或2(驳回)");
}
String[] idArray = ids.split(",");
List<Long> idList = List.of(idArray).stream()
.map(Long::valueOf)
.toList();
return toAjax(materialSubmissionService.batchReviewSubmissions(idList, reviewStatus, reviewRemark));
}
}
@@ -0,0 +1,167 @@
package org.dromara.stgl.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.MapstructUtils;
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.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.dromara.stgl.domain.bo.StglMaterialTaskBo;
import org.dromara.stgl.domain.bo.StglMaterialTaskQueryBo;
import org.dromara.stgl.domain.vo.StglMaterialTaskVo;
import org.dromara.stgl.service.IStglMaterialTaskService;
import java.util.List;
/**
* 材料收集任务管理
*
* @author ruoyi
* @date 2025-01-03
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/stgl/activitymaterial")
public class StglMaterialTaskController extends BaseController {
private final IStglMaterialTaskService materialTaskService;
/**
* 查询材料收集任务列表
*/
@SaCheckPermission("stgl:activitymaterial:list")
@GetMapping("/list")
public TableDataInfo<StglMaterialTaskVo> list(StglMaterialTaskQueryBo queryBo, PageQuery pageQuery) {
return materialTaskService.queryPageList(queryBo, pageQuery);
}
/**
* 导出材料收集任务列表
*/
@SaCheckPermission("stgl:activitymaterial:export")
@Log(title = "材料收集任务", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(StglMaterialTaskQueryBo queryBo, HttpServletResponse response) {
List<StglMaterialTaskVo> list = materialTaskService.queryList(queryBo);
ExcelUtil.exportExcel(list, "材料收集任务", StglMaterialTaskVo.class, response);
}
/**
* 获取材料收集任务详细信息
*/
@SaCheckPermission("stgl:activitymaterial:query")
@GetMapping("/{id}")
public R<StglMaterialTaskVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(materialTaskService.queryById(id));
}
/**
* 新增材料收集任务
*/
@SaCheckPermission("stgl:activitymaterial:add")
@Log(title = "材料收集任务", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglMaterialTaskBo bo) {
return toAjax(materialTaskService.insertByBo(bo));
}
/**
* 修改材料收集任务
*/
@SaCheckPermission("stgl:activitymaterial:edit")
@Log(title = "材料收集任务", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglMaterialTaskBo bo) {
return toAjax(materialTaskService.updateByBo(bo));
}
/**
* 删除材料收集任务
*/
@SaCheckPermission("stgl:activitymaterial:remove")
@Log(title = "材料收集任务", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(materialTaskService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 更新任务状态(开启/关闭)
*/
@SaCheckPermission("stgl:activitymaterial:status")
@Log(title = "材料收集任务状态", businessType = BusinessType.UPDATE)
@PutMapping("/status")
public R<Void> updateStatus(@RequestParam Long id, @RequestParam Integer taskStatus) {
if (taskStatus != 0 && taskStatus != 1) {
return R.fail("任务状态参数错误");
}
return toAjax(materialTaskService.updateTaskStatus(id, taskStatus));
}
/**
* 查询用户可上传的材料收集任务
*/
@SaCheckPermission("stgl:activitymaterial:upload")
@GetMapping("/uploadable")
public R<List<StglMaterialTaskVo>> getUploadableTasks(@RequestParam Long userId,
@RequestParam(required = false) Long activityId) {
List<StglMaterialTaskVo> tasks = materialTaskService.queryUploadableTasksByUser(userId, activityId);
return R.ok(tasks);
}
/**
* 验证用户上传权限
*/
@SaCheckPermission("stgl:activitymaterial:upload")
@GetMapping("/validate")
public R<Boolean> validateUploadPermission(@RequestParam Long taskId, @RequestParam Long userId) {
Boolean hasPermission = materialTaskService.validateUploadPermission(taskId, userId);
return R.ok(hasPermission);
}
/**
* 查询活动的材料收集任务
*/
@SaCheckPermission("stgl:activitymaterial:query")
@GetMapping("/activity/{activityId}")
public R<List<StglMaterialTaskVo>> getTasksByActivityId(@PathVariable Long activityId) {
List<StglMaterialTaskVo> tasks = materialTaskService.queryTasksByActivityId(activityId);
return R.ok(tasks);
}
/**
* 更新任务统计信息
*/
@SaCheckPermission("stgl:activitymaterial:edit")
@Log(title = "材料收集任务统计", businessType = BusinessType.UPDATE)
@PutMapping("/statistics/{taskId}")
public R<Void> updateStatistics(@PathVariable Long taskId) {
return toAjax(materialTaskService.updateTaskStatistics(taskId));
}
/**
* 根据活动名称查询活动选项(用于选择器)
*/
@SaCheckPermission("stgl:activitymaterial:query")
@GetMapping("/activity/options")
public R<List<StglMaterialTaskVo>> getActivityOptions(@RequestParam(required = false) String activityName) {
List<StglMaterialTaskVo> options = materialTaskService.queryActivityOptions(activityName);
return R.ok(options);
}
}
@@ -1,13 +1,20 @@
package org.dromara.stgl.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.text.SimpleDateFormat;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.springframework.web.multipart.MultipartFile;
import org.springframework.http.MediaType;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
@@ -17,9 +24,12 @@ 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.common.excel.core.ExcelResult;
import org.dromara.stgl.domain.vo.StglMemberVo;
import org.dromara.stgl.domain.vo.StglMemberImportVo;
import org.dromara.stgl.domain.bo.StglMemberBo;
import org.dromara.stgl.service.IStglMemberService;
import org.dromara.stgl.listener.StglMemberImportListener;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@@ -32,6 +42,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
* @author Cursor AI
* @date 2025-01-15
*/
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@@ -45,7 +56,7 @@ public class StglMemberController extends BaseController {
* 查询社团成员列表
*/
@Operation(summary = "查询社团成员列表")
@SaCheckPermission("stgl:member:list")
@SaCheckPermission("stgl:clubmember:list")
@GetMapping("/list")
public TableDataInfo<StglMemberVo> list(StglMemberBo bo, PageQuery pageQuery) {
return stglMemberService.queryPageList(bo, pageQuery);
@@ -55,7 +66,7 @@ public class StglMemberController extends BaseController {
* 导出社团成员列表
*/
@Operation(summary = "导出社团成员列表")
@SaCheckPermission("stgl:member:export")
@SaCheckPermission("stgl:clubmember:export")
@Log(title = "社团成员", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(StglMemberBo bo, HttpServletResponse response) {
@@ -67,10 +78,13 @@ public class StglMemberController extends BaseController {
* 获取社团成员详细信息
*/
@Operation(summary = "获取社团成员详细信息")
@SaCheckPermission("stgl:member:query")
@SaCheckPermission("stgl:clubmember:query")
@GetMapping("/{id}")
@Parameters({
@Parameter(name = "id", description = "成员ID", required = true)
})
public R<StglMemberVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
@PathVariable Long id) {
return R.ok(stglMemberService.queryById(id));
}
@@ -78,7 +92,7 @@ public class StglMemberController extends BaseController {
* 新增社团成员
*/
@Operation(summary = "新增社团成员")
@SaCheckPermission("stgl:member:add")
@SaCheckPermission("stgl:clubmember:add")
@Log(title = "社团成员", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
@@ -90,7 +104,7 @@ public class StglMemberController extends BaseController {
* 修改社团成员
*/
@Operation(summary = "修改社团成员")
@SaCheckPermission("stgl:member:edit")
@SaCheckPermission("stgl:clubmember:edit")
@Log(title = "社团成员", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
@@ -102,7 +116,7 @@ public class StglMemberController extends BaseController {
* 删除社团成员
*/
@Operation(summary = "删除社团成员")
@SaCheckPermission("stgl:member:remove")
@SaCheckPermission("stgl:clubmember:remove")
@Log(title = "社团成员", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@@ -110,59 +124,16 @@ public class StglMemberController extends BaseController {
return toAjax(stglMemberService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 根据社团ID查询成员列表
*/
@Operation(summary = "根据社团ID查询成员列表")
@SaCheckPermission("stgl:member:list")
@GetMapping("/club/{clubId}")
@Parameters({
@Parameter(name = "clubId", description = "社团ID", required = true)
})
public R<List<StglMemberVo>> getByClubId(@PathVariable Long clubId) {
return R.ok(stglMemberService.queryByClubId(clubId));
}
/**
* 根据用户ID查询参与的社团列表
*/
@Operation(summary = "根据用户ID查询参与的社团列表")
@SaCheckPermission("stgl:member:list")
@GetMapping("/user/{userId}")
@Parameters({
@Parameter(name = "userId", description = "用户ID", required = true)
})
public R<List<StglMemberVo>> getByUserId(@PathVariable Long userId) {
return R.ok(stglMemberService.queryByUserId(userId));
}
/**
* 检查用户是否已是某个社团/队伍的成员
*/
@Operation(summary = "检查用户是否已是某个社团/队伍的成员")
@SaCheckPermission("stgl:member:list")
@GetMapping("/checkMemberExists")
@Parameters({
@Parameter(name = "memberType", description = "成员类型", required = true),
@Parameter(name = "relationId", description = "关联ID", required = true),
@Parameter(name = "userId", description = "用户ID", required = true)
})
public R<Boolean> checkMemberExists(@RequestParam Integer memberType,
@RequestParam Long relationId,
@RequestParam Long userId) {
return R.ok(stglMemberService.checkMemberExists(memberType, relationId, userId));
}
/**
* 批量添加成员
*/
@Operation(summary = "批量添加成员")
@SaCheckPermission("stgl:member:add")
@SaCheckPermission("stgl:clubmember:add")
@Log(title = "社团成员", businessType = BusinessType.INSERT)
@PostMapping("/batchAdd")
@Parameters({
@Parameter(name = "memberType", description = "成员类型", required = true),
@Parameter(name = "relationId", description = "关联ID", required = true),
@Parameter(name = "memberType", description = "成员类型(1-社团成员,2-志愿队成员)", required = true),
@Parameter(name = "relationId", description = "关联ID(社团ID或志愿队ID)", required = true),
@Parameter(name = "userIds", description = "用户ID列表", required = true),
@Parameter(name = "roleType", description = "角色类型", required = false)
})
@@ -177,7 +148,7 @@ public class StglMemberController extends BaseController {
* 更新成员角色
*/
@Operation(summary = "更新成员角色")
@SaCheckPermission("stgl:member:edit")
@SaCheckPermission("stgl:clubmember:edit")
@Log(title = "社团成员", businessType = BusinessType.UPDATE)
@PutMapping("/updateRole")
@Parameters({
@@ -188,11 +159,26 @@ public class StglMemberController extends BaseController {
return toAjax(stglMemberService.updateMemberRole(id, roleType));
}
/**
* 审核成员申请
*/
@Operation(summary = "审核成员申请")
@SaCheckPermission("stgl:clubmember:approve")
@Log(title = "社团成员审核", businessType = BusinessType.UPDATE)
@PutMapping("/approve/{id}")
@Parameters({
@Parameter(name = "id", description = "成员ID", required = true),
@Parameter(name = "approved", description = "是否通过(true-通过,false-拒绝)", required = true)
})
public R<Void> approveMember(@PathVariable Long id, @RequestParam Boolean approved) {
return toAjax(stglMemberService.approveMember(id, approved));
}
/**
* 退出社团/队伍
*/
@Operation(summary = "退出社团/队伍")
@SaCheckPermission("stgl:member:edit")
@SaCheckPermission("stgl:clubmember:edit")
@Log(title = "社团成员", businessType = BusinessType.UPDATE)
@PutMapping("/quit/{id}")
@Parameters({
@@ -202,4 +188,48 @@ public class StglMemberController extends BaseController {
return toAjax(stglMemberService.quitMember(id));
}
/**
* 导入社团成员数据
*
* @param file 导入文件
* @param updateSupport 是否更新已存在数据
*/
@Operation(summary = "导入社团成员数据")
@Log(title = "社团成员", businessType = BusinessType.IMPORT)
@SaCheckPermission("stgl:clubmember:import")
@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<Void> importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception {
ExcelResult<StglMemberImportVo> result = ExcelUtil.importExcel(file.getInputStream(),
StglMemberImportVo.class,
new StglMemberImportListener(updateSupport));
return R.ok(result.getAnalysis());
}
/**
* 获取社团成员导入模板
*/
@Operation(summary = "获取社团成员导入模板")
@SaCheckPermission("stgl:member:import")
@PostMapping("/importTemplate")
public void importTemplate(HttpServletResponse response) {
// 创建示例数据
List<StglMemberImportVo> templateData = new ArrayList<>();
StglMemberImportVo example = new StglMemberImportVo();
example.setClubName("足球社");
example.setStudentNo("2025ZY24102");
example.setStudentName("张三");
// 设置加入时间为今天(只保留年月日)
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
example.setJoinTime(sdf.parse(sdf.format(new Date())));
} catch (Exception e) {
example.setJoinTime(new Date());
}
templateData.add(example);
ExcelUtil.exportExcel(templateData, "社团成员导入模板", StglMemberImportVo.class, response);
}
}
@@ -0,0 +1,108 @@
package org.dromara.stgl.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
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.bo.ActivityRatingBo;
import org.dromara.stgl.domain.vo.MyActivityVo;
import org.dromara.stgl.domain.vo.MyClubVo;
import org.dromara.stgl.domain.vo.MyRegistrationVo;
import org.dromara.stgl.domain.vo.MyVolunteerTeamVo;
import org.dromara.stgl.service.IStglMyService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 我的报名控制器
*
* @author ruoyi
* @date 2025-01-01
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/stgl/my")
@Tag(name = "我的报名", description = "我的报名模块")
public class StglMyController extends BaseController {
private final IStglMyService stglMyService;
/**
* 查询我参与的社团列表
*/
@Operation(summary = "查询我参与的社团列表")
@SaCheckPermission("stgl:my:list")
@GetMapping("/clubs")
public R<List<MyClubVo>> getMyClubs() {
List<MyClubVo> list = stglMyService.queryMyClubs();
return R.ok(list);
}
/**
* 查询我参与的志愿团队列表
*/
@Operation(summary = "查询我参与的志愿团队列表")
@SaCheckPermission("stgl:my:list")
@GetMapping("/volunteerTeams")
public R<List<MyVolunteerTeamVo>> getMyVolunteerTeams() {
List<MyVolunteerTeamVo> list = stglMyService.queryMyVolunteerTeams();
return R.ok(list);
}
/**
* 查询我报名的活动列表
*/
@Operation(summary = "查询我报名的活动列表")
@SaCheckPermission("stgl:my:list")
@GetMapping("/activities")
public R<List<MyActivityVo>> getMyActivities() {
List<MyActivityVo> list = stglMyService.queryMyActivities();
return R.ok(list);
}
/**
* 分页查询我的报名记录
*/
@Operation(summary = "分页查询我的报名记录")
@SaCheckPermission("stgl:my:list")
@GetMapping("/registrations")
public TableDataInfo<MyRegistrationVo> getMyRegistrations(
@Parameter(description = "分页参数") PageQuery pageQuery,
@Parameter(description = "报名类型(1-社团 2-志愿团队 3-活动)") @RequestParam(required = false) String registrationType) {
return stglMyService.queryMyRegistrations(pageQuery, registrationType);
}
/**
* 对活动进行评分
*/
@Operation(summary = "对活动进行评分")
@SaCheckPermission("stgl:my:rate")
@PostMapping("/activities/{id}/rate")
public R<Void> rateActivity(
@Parameter(description = "活动ID") @PathVariable("id") Long activityId,
@Validated(AddGroup.class) @RequestBody ActivityRatingBo ratingBo) {
Boolean result = stglMyService.rateActivity(activityId, ratingBo);
return result ? R.ok() : R.fail("评分失败");
}
/**
* 检查是否可以对活动评分
*/
@Operation(summary = "检查是否可以对活动评分")
@SaCheckPermission("stgl:my:rate")
@GetMapping("/activities/{id}/canRate")
public R<Boolean> canRateActivity(@Parameter(description = "活动ID") @PathVariable("id") Long activityId) {
Boolean canRate = stglMyService.canRateActivity(activityId);
return R.ok(canRate);
}
}
@@ -0,0 +1,235 @@
package org.dromara.stgl.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
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.core.ExcelResult;
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.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.stgl.domain.bo.StglMemberBo;
import org.dromara.stgl.domain.vo.StglMemberVo;
import org.dromara.stgl.domain.vo.StglVolunteerMemberImportVo;
import org.dromara.stgl.domain.vo.StglVolunteerImportVo;
import org.dromara.stgl.listener.StglVolunteerImportListener;
import org.dromara.stgl.service.IStglMemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* 志愿者成员管理Controller
*
* @author Cursor AI
* @date 2025-01-15
*/
@Validated
@RestController
@RequestMapping("/stgl/volunteer/member")
public class StglVolunteerMemberController extends BaseController {
@Autowired
private IStglMemberService stglMemberService;
/**
* 查询志愿者成员列表
*/
@SaCheckPermission("stgl:volunteerMember:list")
@GetMapping("/list")
public TableDataInfo<StglMemberVo> list(StglMemberBo bo, PageQuery pageQuery) {
bo.setMemberType(2); // 志愿者成员
return stglMemberService.queryPageList(bo, pageQuery);
}
/**
* 导出志愿者成员列表
*/
@SaCheckPermission("stgl:volunteerMember:export")
@Log(title = "志愿者成员", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(StglMemberBo bo, HttpServletResponse response) {
bo.setMemberType(2); // 志愿者成员
List<StglMemberVo> list = stglMemberService.queryList(bo);
ExcelUtil.exportExcel(list, "志愿者成员", StglMemberVo.class, response);
}
/**
* 获取志愿者成员详细信息
*/
@SaCheckPermission("stgl:volunteerMember:query")
@GetMapping("/{id}")
public R<StglMemberVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(stglMemberService.queryById(id));
}
/**
* 新增志愿者成员
*/
@SaCheckPermission("stgl:volunteerMember:add")
@Log(title = "志愿者成员", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglMemberBo bo) {
bo.setMemberType(2); // 志愿者成员
// 如果前端没有传递roleType,设置默认值为1(队员)
if (bo.getRoleType() == null) {
bo.setRoleType(1);
}
return toAjax(stglMemberService.insertByBo(bo));
}
/**
* 修改志愿者成员
*/
@SaCheckPermission("stgl:volunteerMember:edit")
@Log(title = "志愿者成员", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglMemberBo bo) {
bo.setMemberType(2); // 志愿者成员
return toAjax(stglMemberService.updateByBo(bo));
}
/**
* 删除志愿者成员
*/
@SaCheckPermission("stgl:volunteerMember:remove")
@Log(title = "志愿者成员", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(stglMemberService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 我的志愿队伍成员
*/
@SaCheckPermission("stgl:volunteerRegistration:my")
@GetMapping("/my")
public R<List<StglMemberVo>> getMyTeamMembers() {
Long userId = LoginHelper.getUserId();
// 查询当前用户所属的志愿者队伍
StglMemberBo userBo = new StglMemberBo();
userBo.setMemberType(2); // 志愿者成员
userBo.setUserId(userId);
List<StglMemberVo> userMembers = stglMemberService.queryList(userBo);
if (userMembers.isEmpty()) {
return R.ok(List.of());
}
// 获取第一个队伍的所有成员
Long teamId = userMembers.get(0).getRelationId();
StglMemberBo bo = new StglMemberBo();
bo.setMemberType(2); // 志愿者成员
bo.setRelationId(teamId);
List<StglMemberVo> list = stglMemberService.queryList(bo);
return R.ok(list);
}
/**
* 根据队伍ID查询成员
*/
@SaCheckPermission("stgl:volunteerMember:list")
@GetMapping("/team/{teamId}")
public R<List<StglMemberVo>> getTeamMembers(@NotNull(message = "队伍ID不能为空")
@PathVariable Long teamId) {
StglMemberBo bo = new StglMemberBo();
bo.setMemberType(2); // 志愿者成员
bo.setRelationId(teamId);
List<StglMemberVo> list = stglMemberService.queryList(bo);
return R.ok(list);
}
/**
* 批量分配队伍
*/
@SaCheckPermission("stgl:volunteerMember:edit")
@Log(title = "志愿者成员", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/assignTeam")
public R<Void> assignTeam(@RequestBody StglMemberBo bo) {
return toAjax(stglMemberService.batchAssignTeam(bo.getIds(), bo.getRelationId(), 2));
}
/**
* 获取志愿者成员统计信息
*/
@SaCheckPermission("stgl:volunteerMember:query")
@GetMapping("/stats")
public R<Object> getStats() {
return R.ok(stglMemberService.getVolunteerMemberStats());
}
/**
* 下载志愿者成员导入模板
*/
@PostMapping("/importTemplate")
@SaCheckPermission("stgl:volunteerMember:import")
public void importTemplate(HttpServletResponse response) {
// 创建示例数据
List<StglVolunteerImportVo> templateData = new ArrayList<>();
StglVolunteerImportVo example = new StglVolunteerImportVo();
example.setTeamName("环保志愿队");
example.setStudentNo("2025ZY24103");
example.setStudentName("李四");
// 设置加入时间为今天(只保留年月日)
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
example.setJoinTime(sdf.parse(sdf.format(new Date())));
} catch (Exception e) {
example.setJoinTime(new Date());
}
templateData.add(example);
// 导出Excel模版(包含示例数据)
ExcelUtil.exportExcel(templateData, "志愿者队伍成员导入模板", StglVolunteerImportVo.class, response);
}
/**
* 导入志愿者成员数据
*/
@SaCheckPermission("stgl:volunteerMember:import")
@Log(title = "志愿者成员", businessType = BusinessType.IMPORT)
@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<Void> importData(@RequestPart("file") MultipartFile file,
boolean updateSupport) throws Exception {
ExcelResult<StglVolunteerImportVo> result = ExcelUtil.importExcel(file.getInputStream(),
StglVolunteerImportVo.class,
new StglVolunteerImportListener(updateSupport));
return R.ok(result.getAnalysis());
}
/**
* 审核志愿者成员申请
*/
@Log(title = "志愿者成员审核", businessType = BusinessType.UPDATE)
@PutMapping("/approve/{id}")
public R<Void> approveMember(@NotNull(message = "成员ID不能为空")
@PathVariable Long id,
@RequestParam Boolean approved) {
return toAjax(stglMemberService.approveMember(id, approved));
}
}
@@ -0,0 +1,305 @@
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.utils.MapstructUtils;
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.excel.core.ExcelResult;
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.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.stgl.domain.bo.StglVolunteerTeamBo;
import org.dromara.stgl.domain.bo.StglVolunteerTeamApplicationBo;
import org.dromara.stgl.domain.vo.StglVolunteerTeamVo;
import org.dromara.stgl.service.IStglVolunteerTeamService;
import org.dromara.xg.domain.vo.XgStudentMsgVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
import cn.dev33.satoken.stp.StpUtil;
/**
* 志愿者队伍Controller
*
* @author Cursor AI
* @date 2025-01-07
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/stgl/volunteerTeam")
public class StglVolunteerTeamController extends BaseController {
private final IStglVolunteerTeamService stglVolunteerTeamService;
/**
* 查询志愿者队伍列表
*/
@SaCheckPermission("stgl:volunteerTeam:list")
@GetMapping("/list")
public TableDataInfo<StglVolunteerTeamVo> list(StglVolunteerTeamBo bo, PageQuery pageQuery) {
return stglVolunteerTeamService.queryPageList(bo, pageQuery);
}
/**
* 导出志愿者队伍列表
*/
@SaCheckPermission("stgl:volunteerTeam:export")
@Log(title = "志愿者队伍", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(StglVolunteerTeamBo bo, HttpServletResponse response) {
List<StglVolunteerTeamVo> list = stglVolunteerTeamService.queryList(bo);
ExcelUtil.exportExcel(list, "志愿者队伍", StglVolunteerTeamVo.class, response);
}
/**
* 获取志愿者队伍详细信息
*/
@SaCheckPermission("stgl:volunteerTeam:query")
@GetMapping("/{id}")
public R<StglVolunteerTeamVo> getInfo(@PathVariable Long id) {
return R.ok(stglVolunteerTeamService.queryById(id));
}
/**
* 新增志愿者队伍
*/
@SaCheckPermission("stgl:volunteerTeam:add")
@Log(title = "志愿者队伍", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglVolunteerTeamBo bo) {
return toAjax(stglVolunteerTeamService.insertByBo(bo));
}
/**
* 修改志愿者队伍
*/
@SaCheckPermission("stgl:volunteerTeam:edit")
@Log(title = "志愿者队伍", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglVolunteerTeamBo bo) {
return toAjax(stglVolunteerTeamService.updateByBo(bo));
}
/**
* 删除志愿者队伍
*/
@SaCheckPermission("stgl:volunteerTeam:remove")
@Log(title = "志愿者队伍", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@PathVariable Long[] ids) {
return toAjax(stglVolunteerTeamService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 获取志愿者队伍可用选项列表
*/
@SaCheckPermission("stgl:volunteerTeam:list")
@GetMapping("/options")
public R<List<StglVolunteerTeamVo>> getAvailableOptions() {
List<StglVolunteerTeamVo> list = stglVolunteerTeamService.queryAvailableOptions();
return R.ok(list);
}
/**
* 根据队长用户ID查询队伍
*/
@SaCheckPermission("stgl:volunteerTeam:list")
@GetMapping("/byLeader/{leaderUserId}")
public R<List<StglVolunteerTeamVo>> getByLeaderUserId(@PathVariable Long leaderUserId) {
List<StglVolunteerTeamVo> list = stglVolunteerTeamService.queryByLeaderUserId(leaderUserId);
return R.ok(list);
}
/**
* 根据队伍类型查询队伍列表
*/
@SaCheckPermission("stgl:volunteerTeam:list")
@GetMapping("/byType/{teamType}")
public R<List<StglVolunteerTeamVo>> getByTeamType(@PathVariable String teamType) {
List<StglVolunteerTeamVo> list = stglVolunteerTeamService.queryByTeamType(teamType);
return R.ok(list);
}
/**
* 启用/禁用志愿者队伍
*/
@SaCheckPermission("stgl:volunteerTeam:edit")
@Log(title = "志愿者队伍状态变更", businessType = BusinessType.UPDATE)
@PutMapping("/status")
public R<Void> updateStatus(@RequestParam Long id, @RequestParam Integer status) {
return toAjax(stglVolunteerTeamService.updateStatus(id, status));
}
/**
* 导入志愿者队伍数据
*/
@SaCheckPermission("stgl:volunteerTeam:import")
@Log(title = "志愿者队伍", businessType = BusinessType.IMPORT)
@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<Void> importData(@RequestPart("file") MultipartFile file) throws Exception {
ExcelResult<StglVolunteerTeamVo> result = ExcelUtil.importExcel(file.getInputStream(), StglVolunteerTeamVo.class, false);
List<StglVolunteerTeamVo> voList = result.getList();
List<StglVolunteerTeamBo> boList = MapstructUtils.convert(voList, StglVolunteerTeamBo.class);
for (StglVolunteerTeamBo bo : boList) {
stglVolunteerTeamService.insertByBo(bo);
}
return R.ok();
}
/**
* 获取导入模板
*/
@SaCheckPermission("stgl:volunteerTeam:import")
@PostMapping("/importTemplate")
public void importTemplate(HttpServletResponse response) {
ExcelUtil.exportExcel(List.of(), "志愿者队伍", StglVolunteerTeamVo.class, response);
}
/**
* 申请加入志愿者队伍
*/
@SaCheckPermission("stgl:volunteerRegistration:apply")
@PostMapping("/apply")
@RepeatSubmit()
public R<Void> applyJoinVolunteerTeam(@Validated @RequestBody StglVolunteerTeamApplicationBo applicationBo) {
return toAjax(stglVolunteerTeamService.applyJoinVolunteerTeam(applicationBo));
}
/**
* 根据姓名搜索学生信息(用于队长选择)
*/
@SaCheckPermission("stgl:volunteerTeam:list")
@GetMapping("/searchStudentByName")
public R<List<XgStudentMsgVo>> searchStudentByName(@RequestParam("name") String name) {
List<XgStudentMsgVo> students = stglVolunteerTeamService.searchStudentByName(name);
return R.ok(students);
}
/**
* 查询志愿者队伍报名大厅列表(无数据权限限制)
*/
@SaCheckPermission("stgl:volunteerTeam:list")
@GetMapping("/registration/list")
public TableDataInfo<StglVolunteerTeamVo> registrationList(StglVolunteerTeamBo bo, PageQuery pageQuery) {
return stglVolunteerTeamService.queryRegistrationPageList(bo, pageQuery);
}
/**
* 查询志愿者队伍报名大厅列表(学生专用)
*/
@SaCheckPermission("stgl:volunteerRegistration:list")
@GetMapping("/registration/student/list")
public TableDataInfo<StglVolunteerTeamVo> registrationStudentList(StglVolunteerTeamBo bo, PageQuery pageQuery) {
return stglVolunteerTeamService.queryRegistrationPageList(bo, pageQuery);
}
/**
* 获取志愿者队伍详细信息(学生报名大厅专用)
*/
@SaCheckPermission("stgl:volunteerRegistration:query")
@GetMapping("/registration/{id}")
public R<StglVolunteerTeamVo> getRegistrationInfo(@PathVariable Long id) {
StglVolunteerTeamVo vo = stglVolunteerTeamService.queryRegistrationById(id);
return R.ok(vo);
}
/**
* 根据学号获取学生详细信息(用于自动填充)
*/
@SaCheckPermission("stgl:volunteerTeam:list")
@GetMapping("/getStudentByNo")
public R<XgStudentMsgVo> getStudentByNo(@RequestParam("studentNo") String studentNo) {
XgStudentMsgVo student = stglVolunteerTeamService.getStudentByNo(studentNo);
return R.ok(student);
}
/**
* 根据姓名搜索指导老师信息
*/
@SaCheckPermission("stgl:volunteerTeam:list")
@GetMapping("/searchTeacherByName")
public R<List<SysUserVo>> searchTeacherByName(@RequestParam("name") String name) {
List<SysUserVo> teachers = stglVolunteerTeamService.searchTeacherByName(name);
return R.ok(teachers);
}
/**
* 根据用户ID获取教师详细信息(用于自动填充)
*/
@SaCheckPermission("stgl:volunteerTeam:list")
@GetMapping("/getTeacherById")
public R<SysUserVo> getTeacherById(@RequestParam("userId") Long userId) {
SysUserVo teacher = stglVolunteerTeamService.getTeacherById(userId);
return R.ok(teacher);
}
/**
* 修复所有已存在志愿者队伍的队长成员记录
* 为那些没有对应成员记录的队长补充成员记录
*/
@SaCheckPermission("stgl:volunteerTeam:edit")
@Log(title = "修复志愿者队伍队长成员记录", businessType = BusinessType.UPDATE)
@PostMapping("/fixLeaderRecords")
public R<String> fixExistingTeamLeaderRecords() {
try {
Integer fixedCount = stglVolunteerTeamService.fixExistingTeamLeaderRecords();
return R.ok("修复完成,共补充了 " + fixedCount + " 条队长成员记录");
} catch (Exception e) {
return R.fail("修复失败:" + e.getMessage());
}
}
/**
* 验证当前用户是否为志愿者队伍队长
*/
@SaCheckPermission("stgl:volunteerTeam:query")
@GetMapping("/checkLeader/{id}")
public R<Boolean> checkTeamLeader(@PathVariable Long id) {
Long currentUserId = LoginHelper.getUserId();
if (currentUserId == null) {
return R.ok(false);
}
boolean isLeader = stglVolunteerTeamService.isTeamLeader(id, currentUserId);
return R.ok(isLeader);
}
/**
* 志愿者队伍转让
*/
@SaCheckPermission("stgl:volunteerTeam:transfer")
@Log(title = "志愿者队伍转让", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/transfer/{id}")
public R<Void> transferVolunteerTeam(@PathVariable Long id, @RequestParam Long newLeaderUserId) {
// 验证当前用户是否为队长或管理员
Long currentUserId = LoginHelper.getUserId();
if (currentUserId == null) {
return R.fail("用户未登录");
}
// 如果是队长角色,需要验证是否为该队伍的队长
if (StpUtil.hasRole("stgl_volunteer_captain")) {
boolean isLeader = stglVolunteerTeamService.isTeamLeader(id, currentUserId);
if (!isLeader) {
return R.fail("只有队长才能转让自己的队伍");
}
}
return toAjax(stglVolunteerTeamService.transferVolunteerTeam(id, newLeaderUserId));
}
}
@@ -0,0 +1,237 @@
package org.dromara.stgl.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
import java.io.Serial;
import java.util.Date;
/**
* 活动信息对象 stgl_activity
*
* @author ruoyi
* @date 2025-01-07
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("stgl_activity")
public class StglActivity extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 活动名称
*/
@TableField("activity_name")
private String activityName;
/**
* 活动类型
*/
@TableField("activity_type")
private String activityType;
/**
* 活动主题
*/
@TableField("activity_theme")
private String activityTheme;
/**
* 开始时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("start_time")
private Date startTime;
/**
* 结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("end_time")
private Date endTime;
/**
* 活动地点
*/
@TableField("location")
private String location;
/**
* 活动简介
*/
@TableField("description")
private String description;
/**
* 活动海报路径
*/
@TableField("poster_url")
private String posterUrl;
/**
* 关联社团ID
*/
@TableField("related_club_id")
private Long relatedClubId;
/**
* 关联类型(1-社团 2-志愿者队伍)
*/
@TableField("related_type")
private Integer relatedType;
/**
* 主办方名称
*/
@TableField("organizer_name")
private String organizerName;
/**
* 主办方类型
*/
@TableField("organizer_type")
private String organizerType;
/**
* 主办方联系人
*/
@TableField("organizer_contact")
private String organizerContact;
/**
* 主办方电话
*/
@TableField("organizer_phone")
private String organizerPhone;
/**
* 承办方信息(JSON格式存储多个承办方)
*/
@TableField("co_organizers")
private String coOrganizers;
/**
* 指导老师列表(JSON格式)
*/
@TableField("instructors")
private String instructors;
/**
* 报名方式(1-个人 2-团队 3-两者均可)
*/
@TableField("registration_type")
private Integer registrationType;
/**
* 报名开始时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("registration_start")
private Date registrationStart;
/**
* 报名结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("registration_end")
private Date registrationEnd;
/**
* 报名状态(0-未开始 1-报名中 2-已截止 3-已关闭)
*/
@TableField("registration_status")
private Integer registrationStatus;
/**
* 总人数上限
*/
@TableField("max_participants")
private Integer maxParticipants;
/**
* 团队数量上限
*/
@TableField("max_teams")
private Integer maxTeams;
/**
* 每队最小人数
*/
@TableField("team_size_min")
private Integer teamSizeMin;
/**
* 每队最大人数
*/
@TableField("team_size_max")
private Integer teamSizeMax;
/**
* 是否需要审核(0-无需 1-需要)
*/
@TableField("need_approval")
private Integer needApproval;
/**
* 活动状态
*/
@TableField("activity_status")
private String activityStatus;
/**
* 是否为已办活动
*/
@TableField("is_finished")
private Integer isFinished;
/**
* 活动总结报告
*/
@TableField("summary")
private String summary;
/**
* 活动总结报告附件
*/
@TableField("summary_attachments")
private String summaryAttachments;
/**
* 活动成果
*/
@TableField("achievements")
private String achievements;
/**
* 活动成果附件
*/
@TableField("achievements_attachments")
private String achievementsAttachments;
/**
* 导入来源信息
*/
@TableField("import_source")
private String importSource;
/**
* 备注
*/
@TableField("remark")
private String remark;
}
@@ -0,0 +1,129 @@
package org.dromara.stgl.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import java.io.Serial;
/**
* 活动考勤签到对象 stgl_activity_sign
*
* @author ruoyi
* @date 2025-01-15
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("stgl_activity_sign")
public class StglActivityAttendance extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 活动ID(关联stgl_activity表)
*/
private Long activityId;
/**
* 用户ID(关联sys_user表)
*/
private Long userId;
/**
* 学生姓名
*/
private String studentName;
/**
* 学号
*/
private String studentNo;
/**
* 院系
*/
private String department;
/**
* 专业
*/
private String major;
/**
* 班级
*/
private String className;
/**
* 联系电话
*/
private String phone;
/**
* 邮箱
*/
private String email;
/**
* 签到时间
*/
private Date signInTime;
/**
* 签到状态(0-未签到 1-已签到)
*/
private Integer signInStatus;
/**
* 签到地点
*/
private String signInLocation;
/**
* 签到设备信息
*/
private String signInDevice;
/**
* 签到备注
*/
private String signInRemark;
/**
* 签退时间
*/
private Date signOutTime;
/**
* 签退状态(0-未签退 1-已签退)
*/
private Integer signOutStatus;
/**
* 签退地点
*/
private String signOutLocation;
/**
* 签退设备信息
*/
private String signOutDevice;
/**
* 签退备注
*/
private String signOutRemark;
/**
* 签到状态(0-未签到 1-已签到 2-已签退)
*/
private Integer overallStatus;
}
@@ -0,0 +1,80 @@
package org.dromara.stgl.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
import java.time.LocalDateTime;
/**
* 活动评分对象 stgl_activity_rating
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("stgl_activity_rating")
public class StglActivityRating extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 活动ID
*/
private Long activityId;
/**
* 用户ID
*/
private Long userId;
/**
* 学号
*/
private String studentNo;
/**
* 学生姓名
*/
private String studentName;
/**
* 综合评分(1-5分)
*/
private Integer ratingScore;
/**
* 评价意见
*/
private String ratingComment;
/**
* 评分时间
*/
private LocalDateTime ratingTime;
/**
* 内容评分(1-5分)
*/
private Integer contentScore;
/**
* 组织评分(1-5分)
*/
private Integer organizationScore;
/**
* 体验评分(1-5分)
*/
private Integer experienceScore;
}
@@ -0,0 +1,172 @@
package org.dromara.stgl.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
import java.io.Serial;
import java.util.Date;
/**
* 活动报名对象 stgl_activity_registration
*
* @author ruoyi
* @date 2024-12-19
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("stgl_activity_registration")
public class StglActivityRegistration extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 活动ID
*/
private Long activityId;
/**
* 用户ID
*/
private Long userId;
/**
* 学号
*/
private String studentNo;
/**
* 学生姓名
*/
private String studentName;
/**
* 报名类型(1-个人 2-团队)
*/
private String registrationType;
/**
* 团队ID(团队报名时)
*/
private Long teamId;
/**
* 团队名称
*/
private String teamName;
/**
* 报名时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date registrationTime;
/**
* 申请理由(非必填)
*/
private String remark;
/**
* 审核状态(0-待审核 1-通过 2-驳回)
*/
private String approvalStatus;
/**
* 审核时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date approvalTime;
/**
* 审核人
*/
private Long approvalBy;
/**
* 审核意见
*/
private String approvalRemark;
/**
* 获得成绩
*/
private String score;
/**
* 成绩录入时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date scoreTime;
/**
* 成绩录入人
*/
private Long scoreBy;
/**
* 性别
*/
private String gender;
/**
* 联系电话
*/
private String phone;
/**
* 邮箱
*/
private String email;
/**
* 院系
*/
private String department;
/**
* 专业
*/
private String major;
/**
* 班级
*/
private String className;
/**
* 删除标志(0代表存在 1代表删除)
*/
@TableLogic
private Integer deleted;
// 扩展字段(不存储到数据库,用于显示)
/**
* 活动名称
*/
@TableField(exist = false)
private String activityName;
/**
* 审核人姓名
*/
@TableField(exist = false)
private String approvalByName;
/**
* 成绩录入人姓名
*/
@TableField(exist = false)
private String scoreByName;
}
@@ -0,0 +1,76 @@
package org.dromara.stgl.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
import java.io.Serial;
/**
* 活动团队信息对象 stgl_activity_team_info
*
* @author ruoyi
* @date 2024-12-19
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("stgl_activity_team_info")
public class StglActivityTeamInfo extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 团队名称
*/
private String teamName;
/**
* 关联活动ID
*/
private Long activityId;
/**
* 队长用户ID
*/
private Long leaderUserId;
/**
* 队长姓名
*/
private String leaderName;
/**
* 队长学号
*/
private String leaderStudentNo;
/**
* 团队成员信息(JSON格式)
*/
private String teamMembers;
/**
* 团队人数
*/
private Integer teamSize;
/**
* 团队简介
*/
private String description;
// 扩展字段(不存储到数据库,用于显示)
/**
* 活动名称
*/
private String activityName;
}
@@ -102,6 +102,26 @@ public class StglClub extends TenantEntity {
*/
private String vicePresidentStudentNo;
/**
* 副社长院系
*/
private String vicePresidentDept;
/**
* 副社长专业
*/
private String vicePresidentMajor;
/**
* 副社长班级
*/
private String vicePresidentClass;
/**
* 副社长联系方式
*/
private String vicePresidentPhone;
/**
* 指导老师姓名
*/
@@ -112,6 +132,26 @@ public class StglClub extends TenantEntity {
*/
private String advisorDept;
/**
* 指导老师联系电话
*/
private String advisorPhone;
/**
* 指导老师邮箱
*/
private String advisorEmail;
/**
* 副社长列表JSON格式存储
*/
private String vicePresidentsJson;
/**
* 指导老师列表JSON格式存储
*/
private String advisorsJson;
/**
* 成员规模上限
*/
@@ -0,0 +1,133 @@
package org.dromara.stgl.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
import java.io.Serial;
import java.util.Date;
/**
* 材料提交记录对象 stgl_material_submission
*
* @author ruoyi
* @date 2025-01-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("stgl_material_submission")
public class StglMaterialSubmission extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 收集任务ID
*/
@TableField("task_id")
private Long taskId;
/**
* 活动ID
*/
@TableField("activity_id")
private Long activityId;
/**
* 用户ID
*/
@TableField("user_id")
private Long userId;
/**
* 学号
*/
@TableField("student_no")
private String studentNo;
/**
* 学生姓名
*/
@TableField("student_name")
private String studentName;
/**
* 提交类型(1-个人 2-团队)
*/
@TableField("submission_type")
private Integer submissionType;
/**
* 团队ID
*/
@TableField("team_id")
private Long teamId;
/**
* 文本内容
*/
@TableField("content_text")
private String contentText;
/**
* 附件路径(JSON格式)
*/
@TableField("file_urls")
private String fileUrls;
/**
* 图片路径(JSON格式)
*/
@TableField("image_urls")
private String imageUrls;
/**
* 提交时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("submission_time")
private Date submissionTime;
/**
* 提交轮次
*/
@TableField("round_number")
private Integer roundNumber;
/**
* 审核状态(0-待审核 1-通过 2-驳回)
*/
@TableField("review_status")
private Integer reviewStatus;
/**
* 审核时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("review_time")
private Date reviewTime;
/**
* 审核人
*/
@TableField("review_by")
private Long reviewBy;
/**
* 审核意见
*/
@TableField("review_remark")
private String reviewRemark;
}
@@ -0,0 +1,120 @@
package org.dromara.stgl.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
import java.io.Serial;
import java.util.Date;
/**
* 材料收集任务对象 stgl_material_task
*
* @author ruoyi
* @date 2025-01-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("stgl_material_task")
public class StglMaterialTask extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 关联活动ID
*/
@TableField("activity_id")
private Long activityId;
/**
* 任务名称
*/
@TableField("task_name")
private String taskName;
/**
* 收集类型(多选,逗号分隔)
*/
@TableField("collection_types")
private String collectionTypes;
/**
* 任务描述
*/
@TableField("task_description")
private String taskDescription;
/**
* 任务状态(1-开启 0-关闭)
*/
@TableField("task_status")
private Integer taskStatus;
/**
* 截止时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("deadline")
private Date deadline;
/**
* 收集轮次
*/
@TableField("round_number")
private Integer roundNumber;
/**
* 文件大小限制(MB)
*/
@TableField("file_size_limit")
private Integer fileSizeLimit;
/**
* 文件数量限制
*/
@TableField("file_count_limit")
private Integer fileCountLimit;
/**
* 允许的文件类型
*/
@TableField("allowed_file_types")
private String allowedFileTypes;
/**
* 总参与人数
*/
@TableField("total_participants")
private Integer totalParticipants;
/**
* 已提交人数
*/
@TableField("submitted_count")
private Integer submittedCount;
/**
* 待提交人数
*/
@TableField("pending_count")
private Integer pendingCount;
/**
* 备注
*/
@TableField("remark")
private String remark;
}
@@ -53,7 +53,7 @@ public class StglMember extends TenantEntity {
private String studentName;
/**
* 角色类型(1-社长 2-副社长 3-成员)
* 角色类型(1-社长 2-副社长 3-部长 4-普通成员)
*/
private Integer roleType;
@@ -63,7 +63,7 @@ public class StglMember extends TenantEntity {
private Date joinTime;
/**
* 状态(1-正常 0-退出)
* 状态(0-待审核 1-审核中 2-已加入 3-已驳回 4-已退出)
*/
private Integer status;
@@ -0,0 +1,130 @@
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_volunteer_team
*
* @author Cursor AI
* @date 2025-01-07
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("stgl_volunteer_team")
public class StglVolunteerTeam extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 队伍名称
*/
private String teamName;
/**
* 队伍类型
*/
private String teamType;
/**
* 队伍描述
*/
private String description;
/**
* 成立日期
*/
private Date establishDate;
/**
* 联系电话
*/
private String phone;
/**
* 联系邮箱
*/
private String email;
/**
* 备注信息
*/
private String remark;
/**
* 队长姓名
*/
private String leaderName;
/**
* 队长学号
*/
private String leaderStudentNo;
/**
* 队长用户ID
*/
private Long leaderUserId;
/**
* 队长联系方式
*/
private String leaderPhone;
/**
* 队长院系
*/
private String leaderDept;
/**
* 队长专业
*/
private String leaderMajor;
/**
* 队长班级
*/
private String leaderClass;
/**
* 指导老师姓名
*/
private String advisorName;
/**
* 指导老师联系电话
*/
private String advisorPhone;
/**
* 指导老师所在部门
*/
private String advisorDept;
/**
* 指导老师邮箱
*/
private String advisorEmail;
/**
* 人员上限
*/
private Integer memberLimit;
/**
* 状态(1-正常 0-停用)
*/
private Integer status;
}
@@ -0,0 +1,81 @@
package org.dromara.stgl.domain.bo;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.stgl.domain.StglActivityRating;
/**
* 活动评分业务对象 ActivityRatingBo
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = StglActivityRating.class, reverseConvertGenerate = false)
public class ActivityRatingBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 活动ID
*/
@NotNull(message = "活动ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long activityId;
/**
* 用户ID
*/
private Long userId;
/**
* 学号
*/
private String studentNo;
/**
* 学生姓名
*/
private String studentName;
/**
* 内容评分(1-5分)
*/
@NotNull(message = "内容评分不能为空", groups = { AddGroup.class })
@Min(value = 1, message = "内容评分最小为1分", groups = { AddGroup.class, EditGroup.class })
@Max(value = 5, message = "内容评分最大为5分", groups = { AddGroup.class, EditGroup.class })
private Integer contentScore;
/**
* 组织评分(1-5分)
*/
@NotNull(message = "组织评分不能为空", groups = { AddGroup.class })
@Min(value = 1, message = "组织评分最小为1分", groups = { AddGroup.class, EditGroup.class })
@Max(value = 5, message = "组织评分最大为5分", groups = { AddGroup.class, EditGroup.class })
private Integer organizationScore;
/**
* 体验评分(1-5分)
*/
@NotNull(message = "体验评分不能为空", groups = { AddGroup.class })
@Min(value = 1, message = "体验评分最小为1分", groups = { AddGroup.class, EditGroup.class })
@Max(value = 5, message = "体验评分最大为5分", groups = { AddGroup.class, EditGroup.class })
private Integer experienceScore;
/**
* 评价意见
*/
private String ratingComment;
}
@@ -0,0 +1,40 @@
package org.dromara.stgl.domain.bo;
import lombok.Data;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Size;
import java.util.List;
/**
* 批量审核请求对象
*
* @author ruoyi
* @date 2025-01-31
*/
@Data
public class BatchApprovalBo {
/**
* 报名ID数组
*/
@NotEmpty(message = "审核ID列表不能为空")
private List<Long> ids;
/**
* 审核状态 1-通过 2-驳回
*/
@NotNull(message = "审核状态不能为空")
@Min(value = 1, message = "审核状态值无效")
@Max(value = 2, message = "审核状态值无效")
private Integer approvalStatus;
/**
* 审核意见
*/
@Size(max = 500, message = "审核意见不能超过500个字符")
private String approvalRemark;
}
@@ -0,0 +1,132 @@
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 java.util.Date;
/**
* 活动考勤签到业务对象 stgl_activity_attendance
*
* @author ruoyi
* @date 2025-01-15
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = org.dromara.stgl.domain.StglActivityAttendance.class, reverseConvertGenerate = false)
public class StglActivityAttendanceBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 活动ID(关联stgl_activity表)
*/
@NotNull(message = "活动ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long activityId;
/**
* 用户ID(关联sys_user表)
*/
@NotNull(message = "用户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long userId;
/**
* 学生姓名
*/
@NotBlank(message = "学生姓名不能为空", groups = { AddGroup.class, EditGroup.class })
private String studentName;
/**
* 学号
*/
@NotBlank(message = "学号不能为空", groups = { AddGroup.class, EditGroup.class })
private String studentNo;
/**
* 院系
*/
private String department;
/**
* 专业
*/
private String major;
/**
* 班级
*/
private String className;
/**
* 联系电话
*/
private String phone;
/**
* 邮箱
*/
private String email;
/**
* 签到时间
*/
private Date signInTime;
/**
* 签到状态(0-未签到 1-已签到)
*/
private Integer signInStatus;
/**
* 签到地点
*/
private String signInLocation;
/**
* 签到设备信息
*/
private String signInDevice;
/**
* 签到备注
*/
private String signInRemark;
/**
* 签退时间
*/
private Date signOutTime;
/**
* 签退状态(0-未签退 1-已签退)
*/
private Integer signOutStatus;
/**
* 签退地点
*/
private String signOutLocation;
/**
* 签退设备信息
*/
private String signOutDevice;
/**
* 签退备注
*/
private String signOutRemark;
/**
* 签到状态(0-未签到 1-已签到 2-已签退)
*/
private Integer overallStatus;
}
@@ -0,0 +1,208 @@
package org.dromara.stgl.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.stgl.domain.StglActivity;
import java.util.Date;
/**
* 活动信息业务对象 stgl_activity
*
* @author ruoyi
* @date 2025-01-07
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = StglActivity.class, reverseConvertGenerate = false)
public class StglActivityBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 活动名称
*/
@NotBlank(message = "活动名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String activityName;
/**
* 活动类型
*/
@NotBlank(message = "活动类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String activityType;
/**
* 活动主题
*/
private String activityTheme;
/**
* 开始时间
*/
@NotNull(message = "开始时间不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/**
* 结束时间
*/
@NotNull(message = "结束时间不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
/**
* 活动地点
*/
private String location;
/**
* 活动简介
*/
private String description;
/**
* 活动海报路径
*/
private String posterUrl;
/**
* 关联社团ID
*/
private Long relatedClubId;
/**
* 关联类型 (1: 社团, 2: 志愿者队伍)
*/
private Integer relatedType;
/**
* 主办方名称
*/
@NotBlank(message = "主办方名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String organizerName;
/**
* 主办方类型
*/
private String organizerType;
/**
* 主办方联系人
*/
private String organizerContact;
/**
* 主办方电话
*/
private String organizerPhone;
/**
* 承办方信息(JSON格式存储多个承办方)
*/
private String coOrganizers;
/**
* 指导老师列表(JSON格式)
*/
private String instructors;
/**
* 报名方式(1-个人 2-团队 3-两者均可)
*/
private Integer registrationType;
/**
* 报名开始时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date registrationStart;
/**
* 报名结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date registrationEnd;
/**
* 报名状态(0-未开始 1-进行中 2-已结束)
*/
private String registrationStatus;
/**
* 总人数上限
*/
private Integer maxParticipants;
/**
* 团队数量上限
*/
private Integer maxTeams;
/**
* 每队最小人数
*/
private Integer teamSizeMin;
/**
* 每队最大人数
*/
private Integer teamSizeMax;
/**
* 是否需要审核(0-无需 1-需要)
*/
private Integer needApproval;
/**
* 活动状态
*/
@NotBlank(message = "活动状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String activityStatus;
/**
* 是否为已办活动
*/
private Integer isFinished;
/**
* 活动总结报告
*/
private String summary;
/**
* 活动总结报告附件
*/
private String summaryAttachments;
/**
* 活动成果
*/
private String achievements;
/**
* 活动成果附件
*/
private String achievementsAttachments;
/**
* 导入来源信息
*/
private String importSource;
/**
* 备注
*/
private String remark;
}
@@ -0,0 +1,148 @@
package org.dromara.stgl.domain.bo;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.stgl.domain.StglActivityRegistration;
/**
* 活动报名业务对象 stgl_activity_registration
*
* @author ruoyi
* @date 2024-12-19
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = StglActivityRegistration.class, reverseConvertGenerate = false)
public class StglActivityRegistrationBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 活动ID
*/
@NotNull(message = "活动ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long activityId;
/**
* 活动名称(用于查询条件)
*/
private String activityName;
/**
* 用户ID
*/
private Long userId;
/**
* 学号
*/
@NotBlank(message = "学号不能为空", groups = { AddGroup.class, EditGroup.class })
private String studentNo;
/**
* 学生姓名
*/
@NotBlank(message = "学生姓名不能为空", groups = { AddGroup.class, EditGroup.class })
private String studentName;
/**
* 报名类型(1-个人 2-团队)
*/
@NotBlank(message = "报名类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String registrationType;
/**
* 团队ID(团队报名时)
*/
private Long teamId;
/**
* 团队名称
*/
private String teamName;
/**
* 团队成员信息(JSON格式)
*/
private String teamMembers;
/**
* 团队描述
*/
private String teamDescription;
/**
* 申请理由
*/
private String remark;
/**
* 审核状态(0-待审核 1-通过 2-驳回)
*/
private String approvalStatus;
/**
* 审核意见
*/
private String approvalRemark;
/**
* 审核人
*/
private Long approvalBy;
/**
* 审核时间
*/
private java.util.Date approvalTime;
/**
* 获得成绩
*/
private String score;
/**
* 性别
*/
private String gender;
/**
* 联系电话
*/
private String phone;
/**
* 邮箱
*/
private String email;
/**
* 院系
*/
private String department;
/**
* 专业
*/
private String major;
/**
* 班级
*/
private String className;
/**
* 报名时间
*/
private java.util.Date registrationTime;
}
@@ -0,0 +1,74 @@
package org.dromara.stgl.domain.bo;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.stgl.domain.StglActivityTeamInfo;
/**
* 活动团队信息业务对象 stgl_activity_team_info
*
* @author ruoyi
* @date 2024-12-19
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = StglActivityTeamInfo.class, reverseConvertGenerate = false)
public class StglActivityTeamInfoBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 团队名称
*/
@NotBlank(message = "团队名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String teamName;
/**
* 关联活动ID
*/
@NotNull(message = "关联活动ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long activityId;
/**
* 队长用户ID
*/
@NotNull(message = "队长用户ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long leaderUserId;
/**
* 队长姓名
*/
@NotBlank(message = "队长姓名不能为空", groups = { AddGroup.class, EditGroup.class })
private String leaderName;
/**
* 队长学号
*/
@NotBlank(message = "队长学号不能为空", groups = { AddGroup.class, EditGroup.class })
private String leaderStudentNo;
/**
* 团队成员信息(JSON格式)
*/
private String teamMembers;
/**
* 团队人数
*/
private Integer teamSize;
/**
* 团队简介
*/
private String description;
}
@@ -0,0 +1,20 @@
package org.dromara.stgl.domain.bo;
import lombok.Data;
import jakarta.validation.constraints.Size;
/**
* 社团申请请求对象
*
* @author Cursor AI
* @date 2025-01-26
*/
@Data
public class StglClubApplyBo {
/**
* 申请理由
*/
@Size(max = 500, message = "申请理由不能超过500个字符")
private String reason;
}
@@ -10,6 +10,7 @@ import jakarta.validation.constraints.*;
import org.dromara.stgl.domain.StglClub;
import java.util.Date;
import java.util.List;
/**
* 社团信息业务对象 stgl_club
@@ -122,6 +123,31 @@ public class StglClubBo extends BaseEntity {
@Size(max = 20, message = "副社长学号长度不能超过20个字符")
private String vicePresidentStudentNo;
/**
* 副社长院系
*/
@Size(max = 100, message = "副社长院系长度不能超过100个字符")
private String vicePresidentDept;
/**
* 副社长专业
*/
@Size(max = 100, message = "副社长专业长度不能超过100个字符")
private String vicePresidentMajor;
/**
* 副社长班级
*/
@Size(max = 100, message = "副社长班级长度不能超过100个字符")
private String vicePresidentClass;
/**
* 副社长联系方式
*/
@Pattern(regexp = "^[0-9-]+$", message = "副社长联系方式格式不正确")
@Size(max = 20, message = "副社长联系方式长度不能超过20个字符")
private String vicePresidentPhone;
/**
* 指导老师姓名
*/
@@ -134,6 +160,30 @@ public class StglClubBo extends BaseEntity {
@Size(max = 100, message = "指导老师所属院系长度不能超过100个字符")
private String advisorDept;
/**
* 指导老师联系电话
*/
@Pattern(regexp = "^[0-9-]+$", message = "指导老师联系电话格式不正确")
@Size(max = 20, message = "指导老师联系电话长度不能超过20个字符")
private String advisorPhone;
/**
* 指导老师邮箱
*/
@Email(message = "指导老师邮箱格式不正确")
@Size(max = 100, message = "指导老师邮箱长度不能超过100个字符")
private String advisorEmail;
/**
* 副社长列表JSON格式存储
*/
private String vicePresidentsJson;
/**
* 指导老师列表JSON格式存储
*/
private String advisorsJson;
/**
* 成员规模上限
*/
@@ -185,4 +235,9 @@ public class StglClubBo extends BaseEntity {
*/
private String remark;
/**
* 社团ID列表(用于数据权限控制)
*/
private List<Long> clubIds;
}
@@ -0,0 +1,60 @@
package org.dromara.stgl.domain.bo;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.stgl.domain.StglClub;
import jakarta.validation.constraints.*;
import java.util.Date;
/**
* 社团报名大厅业务对象 stgl_club_register
*
* @author Cursor AI
* @date 2025-01-15
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = StglClub.class, reverseConvertGenerate = false)
public class StglClubRegisterBo extends BaseEntity {
/**
* 社团类型
*/
private String clubType;
/**
* 社团名称(模糊查询)
*/
private String clubName;
/**
* 状态(1-正常 0-停用)
*/
private Integer status;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新者
*/
private Long updateBy;
/**
* 更新时间
*/
private Date updateTime;
}
@@ -0,0 +1,117 @@
package org.dromara.stgl.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.stgl.domain.StglMaterialSubmission;
import java.util.Date;
/**
* 材料提交记录业务对象 stgl_material_submission
*
* @author ruoyi
* @date 2025-01-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = StglMaterialSubmission.class, reverseConvertGenerate = false)
public class StglMaterialSubmissionBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 收集任务ID
*/
@NotNull(message = "收集任务ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long taskId;
/**
* 活动ID
*/
@NotNull(message = "活动ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long activityId;
/**
* 用户ID
*/
private Long userId;
/**
* 学号
*/
private String studentNo;
/**
* 学生姓名
*/
private String studentName;
/**
* 提交类型(1-个人 2-团队)
*/
@NotNull(message = "提交类型不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer submissionType;
/**
* 团队ID
*/
private Long teamId;
/**
* 文本内容
*/
private String contentText;
/**
* 附件路径(JSON格式)
*/
private String fileUrls;
/**
* 图片路径(JSON格式)
*/
private String imageUrls;
/**
* 提交时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date submissionTime;
/**
* 提交轮次
*/
private Integer roundNumber;
/**
* 审核状态(0-待审核 1-通过 2-驳回)
*/
private Integer reviewStatus;
/**
* 审核时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date reviewTime;
/**
* 审核人
*/
private Long reviewBy;
/**
* 审核意见
*/
private String reviewRemark;
}
@@ -0,0 +1,111 @@
package org.dromara.stgl.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.stgl.domain.StglMaterialTask;
import java.util.Date;
/**
* 材料收集任务业务对象 stgl_material_task
*
* @author ruoyi
* @date 2025-01-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = StglMaterialTask.class, reverseConvertGenerate = false)
public class StglMaterialTaskBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 关联活动ID
*/
@NotNull(message = "关联活动不能为空", groups = { AddGroup.class, EditGroup.class })
private Long activityId;
/**
* 任务名称
*/
@NotBlank(message = "任务名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String taskName;
/**
* 收集类型(多选,逗号分隔)
*/
@NotBlank(message = "收集类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String collectionTypes;
/**
* 任务描述
*/
@NotBlank(message = "收集说明不能为空", groups = { AddGroup.class, EditGroup.class })
private String taskDescription;
/**
* 任务状态(1-开启 0-关闭)
*/
private Integer taskStatus;
/**
* 截止时间
*/
@NotNull(message = "截止时间不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date deadline;
/**
* 收集轮次
*/
private Integer roundNumber;
/**
* 文件大小限制(MB)
*/
@NotNull(message = "文件大小限制不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer fileSizeLimit;
/**
* 文件数量限制
*/
@NotNull(message = "文件数量限制不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer fileCountLimit;
/**
* 允许的文件类型
*/
private String allowedFileTypes;
/**
* 总参与人数
*/
private Integer totalParticipants;
/**
* 已提交人数
*/
private Integer submittedCount;
/**
* 待提交人数
*/
private Integer pendingCount;
/**
* 备注
*/
private String remark;
}
@@ -0,0 +1,62 @@
package org.dromara.stgl.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.util.Date;
/**
* 材料收集任务查询业务对象 stgl_material_task
*
* @author ruoyi
* @date 2025-01-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class StglMaterialTaskQueryBo extends BaseEntity {
/**
* 关联活动ID
*/
private Long activityId;
/**
* 活动名称
*/
private String activityName;
/**
* 任务名称
*/
private String taskName;
/**
* 收集类型(多选,逗号分隔)
*/
private String collectionTypes;
/**
* 任务状态(1-开启 0-关闭)
*/
private Integer taskStatus;
/**
* 截止时间开始
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date deadlineStart;
/**
* 截止时间结束
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date deadlineEnd;
/**
* 创建者姓名(用于查询)
*/
private String creatorName;
}
@@ -10,6 +10,7 @@ import jakarta.validation.constraints.*;
import org.dromara.stgl.domain.StglMember;
import java.util.Date;
import java.util.List;
/**
* 社团成员业务对象 stgl_member
@@ -61,10 +62,10 @@ public class StglMemberBo extends BaseEntity {
private String studentName;
/**
* 角色类型(1-社长 2-副社长 3-成员)
* 角色类型(社团:1-社长 2-副社长 3-部长 4-普通成员;志愿者:0-队长 1-队员)
*/
@Min(value = 1, message = "角色类型值无效")
@Max(value = 3, message = "角色类型值无效")
@Min(value = 0, message = "角色类型值无效")
@Max(value = 4, message = "角色类型值无效")
private Integer roleType;
/**
@@ -73,7 +74,7 @@ public class StglMemberBo extends BaseEntity {
private Date joinTime;
/**
* 状态(1-正常 0-退出)
* 状态(0-正常 1-停用)
*/
private Integer status;
@@ -82,4 +83,21 @@ public class StglMemberBo extends BaseEntity {
*/
private String remark;
/**
* 队伍名称(用于模糊查询)
*/
@Size(max = 100, message = "队伍名称长度不能超过100个字符")
private String teamName;
/**
* 社团名称(用于模糊查询)
*/
@Size(max = 100, message = "社团名称长度不能超过100个字符")
private String clubName;
/**
* 批量操作的ID列表
*/
private List<Long> ids;
}
@@ -0,0 +1,86 @@
package org.dromara.stgl.domain.bo;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.stgl.domain.StglMember;
/**
* 志愿者队伍申请业务对象 stgl_volunteer_team_application
*
* @author Cursor AI
* @date 2025-01-15
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = StglMember.class, reverseConvertGenerate = false)
public class StglVolunteerTeamApplicationBo extends BaseEntity {
/**
* 志愿者队伍ID
*/
@NotNull(message = "志愿者队伍ID不能为空", groups = { AddGroup.class })
private Long teamId;
/**
* 学生姓名
*/
@NotBlank(message = "学生姓名不能为空", groups = { AddGroup.class })
private String studentName;
/**
* 学号
*/
@NotBlank(message = "学号不能为空", groups = { AddGroup.class })
private String studentNo;
/**
* 性别(1-男 2-女)
*/
@NotBlank(message = "性别不能为空", groups = { AddGroup.class })
private String gender;
/**
* 联系方式
*/
@NotBlank(message = "联系方式不能为空", groups = { AddGroup.class })
@Pattern(regexp = "^1[3|4|5|6|7|8|9][0-9]\\d{8}$", message = "手机号码格式错误", groups = { AddGroup.class })
private String phone;
/**
* 邮箱
*/
@Email(message = "邮箱格式错误", groups = { AddGroup.class })
private String email;
/**
* 院系
*/
@NotBlank(message = "院系不能为空", groups = { AddGroup.class })
private String department;
/**
* 专业
*/
@NotBlank(message = "专业不能为空", groups = { AddGroup.class })
private String major;
/**
* 班级
*/
@NotBlank(message = "班级不能为空", groups = { AddGroup.class })
private String className;
/**
* 申请理由
*/
@NotBlank(message = "申请理由不能为空", groups = { AddGroup.class })
private String applyReason;
}
@@ -0,0 +1,153 @@
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.StglVolunteerTeam;
import java.util.Date;
/**
* 志愿者队伍业务对象 stgl_volunteer_team
*
* @author Cursor AI
* @date 2025-01-07
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = StglVolunteerTeam.class, reverseConvertGenerate = false)
public class StglVolunteerTeamBo 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 teamName;
/**
* 队伍类型
*/
@Size(max = 50, message = "队伍类型长度不能超过50个字符")
private String teamType;
/**
* 队伍描述
*/
@Size(max = 2000, message = "队伍描述长度不能超过2000个字符")
private String description;
/**
* 成立日期
*/
private Date establishDate;
/**
* 联系电话
*/
@Pattern(regexp = "^[0-9-]{7,20}$", message = "联系电话格式不正确")
private String phone;
/**
* 联系邮箱
*/
@Email(message = "联系邮箱格式不正确")
@Size(max = 100, message = "联系邮箱长度不能超过100个字符")
private String email;
/**
* 备注信息
*/
@Size(max = 500, message = "备注信息长度不能超过500个字符")
private String remark;
/**
* 队长姓名
*/
@NotBlank(message = "队长姓名不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 50, message = "队长姓名长度不能超过50个字符")
private String leaderName;
/**
* 队长学号
*/
@Size(max = 20, message = "队长学号长度不能超过20个字符")
private String leaderStudentNo;
/**
* 队长用户ID
*/
private Long leaderUserId;
/**
* 队长联系方式
*/
@Pattern(regexp = "^[0-9-]{7,20}$", message = "队长联系方式格式不正确")
private String leaderPhone;
/**
* 队长院系
*/
@Size(max = 100, message = "队长院系长度不能超过100个字符")
private String leaderDept;
/**
* 队长专业
*/
@Size(max = 100, message = "队长专业长度不能超过100个字符")
private String leaderMajor;
/**
* 队长班级
*/
@Size(max = 100, message = "队长班级长度不能超过100个字符")
private String leaderClass;
/**
* 指导老师姓名
*/
@Size(max = 50, message = "指导老师姓名长度不能超过50个字符")
private String advisorName;
/**
* 指导老师联系电话
*/
@Pattern(regexp = "^[0-9-]{7,20}$", message = "指导老师联系电话格式不正确")
private String advisorPhone;
/**
* 指导老师所在部门
*/
@Size(max = 100, message = "指导老师所在部门长度不能超过100个字符")
private String advisorDept;
/**
* 指导老师邮箱
*/
@Email(message = "指导老师邮箱格式不正确")
@Size(max = 100, message = "指导老师邮箱长度不能超过100个字符")
private String advisorEmail;
/**
* 人员上限
*/
@Min(value = 1, message = "人员上限不能小于1")
@Max(value = 999, message = "人员上限不能大于999")
private Integer memberLimit;
/**
* 状态(1-正常 0-停用)
*/
private Integer status;
}
@@ -0,0 +1,147 @@
package org.dromara.stgl.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.stgl.domain.StglActivity;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 我的活动视图对象 MyActivityVo
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@AutoMapper(target = StglActivity.class)
public class MyActivityVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 活动ID
*/
private Long id;
/**
* 活动名称
*/
private String activityName;
/**
* 活动类型
*/
private String activityType;
/**
* 活动主题
*/
private String activityTheme;
/**
* 开始时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime startTime;
/**
* 结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime endTime;
/**
* 活动地点
*/
private String location;
/**
* 主办方名称
*/
private String organizerName;
/**
* 关联类型(1-社团 2-志愿者队伍)
*/
private Integer relatedType;
/**
* 关联组织名称(社团名称或志愿者团队名称)
*/
private String organizationName;
/**
* 指导老师
*/
private String instructors;
/**
* 活动状态
*/
private String activityStatus;
/**
* 报名状态
*/
private String registrationStatus;
/**
* 海报地址
*/
private String posterUrl;
/**
* 活动简介
*/
private String description;
/**
* 我的报名时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime myRegistrationTime;
/**
* 我的报名状态
*/
private String myRegistrationStatus;
/**
* 我的评分状态(0-未评分 1-已评分)
*/
private Integer myRatingStatus;
/**
* 我的综合评分
*/
private Integer myRatingScore;
/**
* 我的评分时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime myRatingTime;
/**
* 活动平均评分
*/
private Double averageRating;
/**
* 是否可以评分
*/
private Boolean canRate;
// 继承的基础字段
private Long createBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
private Long updateBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}
@@ -0,0 +1,115 @@
package org.dromara.stgl.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.stgl.domain.StglClub;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 我的社团视图对象 MyClubVo
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@AutoMapper(target = StglClub.class)
public class MyClubVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 社团ID
*/
private Long id;
/**
* 社团名称
*/
private String clubName;
/**
* 社团类型
*/
private String clubType;
/**
* LOGO地址
*/
private String logoUrl;
/**
* 社长姓名
*/
private String presidentName;
/**
* 社长院系
*/
private String presidentDept;
/**
* 指导老师姓名
*/
private String advisorName;
/**
* 指导老师部门
*/
private String advisorDept;
/**
* 成员数量
*/
private Integer memberCount;
/**
* 成员限制
*/
private Integer memberLimit;
/**
* 社团状态
*/
private String status;
/**
* 我的角色
*/
private String myRole;
/**
* 加入时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime joinTime;
/**
* 成员状态
*/
private String memberStatus;
/**
* 社团简介
*/
private String description;
/**
* 成立日期
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDateTime establishDate;
// 继承的基础字段
private Long createBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
private Long updateBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}
@@ -0,0 +1,108 @@
package org.dromara.stgl.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 我的报名记录视图对象 MyRegistrationVo
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
public class MyRegistrationVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 记录ID
*/
private Long id;
/**
* 报名类型(1-社团 2-志愿团队 3-活动)
*/
private String registrationType;
/**
* 目标ID(社团ID/志愿团队ID/活动ID)
*/
private Long targetId;
/**
* 名称(社团名称/队伍名称/活动名称)
*/
private String targetName;
/**
* 类型(社团类型/活动类型等)
*/
private String targetType;
/**
* 报名时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime registrationTime;
/**
* 审核状态
*/
private String approvalStatus;
/**
* 审核时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime approvalTime;
/**
* 审核人
*/
private String approvalBy;
/**
* 备注信息
*/
private String remark;
/**
* 当前状态
*/
private String currentStatus;
/**
* 角色(如:普通成员、副社长等)
*/
private String role;
/**
* 组织者/负责人
*/
private String organizer;
/**
* 时间信息(活动时间/成立时间等)
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime timeInfo;
/**
* 地点信息(活动地点等)
*/
private String location;
// 继承的基础字段
private Long createBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
private Long updateBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}
@@ -0,0 +1,115 @@
package org.dromara.stgl.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.stgl.domain.StglVolunteerTeam;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 我的志愿团队视图对象 MyVolunteerTeamVo
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@AutoMapper(target = StglVolunteerTeam.class)
public class MyVolunteerTeamVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 团队ID
*/
private Long id;
/**
* 队伍名称
*/
private String teamName;
/**
* 队长姓名
*/
private String leaderName;
/**
* 队长院系
*/
private String leaderDept;
/**
* 指导老师姓名
*/
private String advisorName;
/**
* 指导老师部门
*/
private String advisorDept;
/**
* 当前成员数量
*/
private Integer currentMemberCount;
/**
* 成员限制
*/
private Integer memberLimit;
/**
* 团队状态
*/
private String status;
/**
* 我的角色
*/
private String myRole;
/**
* 加入时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime joinTime;
/**
* 成员状态
*/
private String memberStatus;
/**
* 队伍简介
*/
private String description;
/**
* 成立日期
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDateTime establishDate;
/**
* 联系电话
*/
private String contactPhone;
/**
* 邮箱
*/
private String email;
// 继承的基础字段
private Long createBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
private Long updateBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}
@@ -0,0 +1,230 @@
package org.dromara.stgl.domain.vo;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.util.Date;
import java.io.Serial;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 活动考勤签到视图对象 stgl_activity_attendance
*
* @author ruoyi
* @date 2025-01-15
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = org.dromara.stgl.domain.StglActivityAttendance.class)
public class StglActivityAttendanceVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 活动ID(关联stgl_activity表)
*/
@ExcelProperty(value = "活动ID")
private Long activityId;
/**
* 用户ID(关联sys_user表)
*/
@ExcelProperty(value = "用户ID")
private Long userId;
/**
* 学生姓名
*/
@ExcelProperty(value = "学生姓名")
private String studentName;
/**
* 学号
*/
@ExcelProperty(value = "学号")
private String studentNo;
/**
* 院系
*/
@ExcelProperty(value = "院系")
private String department;
/**
* 专业
*/
@ExcelProperty(value = "专业")
private String major;
/**
* 班级
*/
@ExcelProperty(value = "班级")
private String className;
/**
* 联系电话
*/
@ExcelProperty(value = "联系电话")
private String phone;
/**
* 邮箱
*/
@ExcelProperty(value = "邮箱")
private String email;
/**
* 签到时间
*/
@ExcelProperty(value = "签到时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date signInTime;
/**
* 签到状态(0-未签到 1-已签到)
*/
@ExcelProperty(value = "签到状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "stgl_activity_sign_status")
private Integer signInStatus;
/**
* 签到地点
*/
@ExcelProperty(value = "签到地点")
private String signInLocation;
/**
* 签到设备信息
*/
@ExcelProperty(value = "签到设备信息")
private String signInDevice;
/**
* 签到备注
*/
@ExcelProperty(value = "签到备注")
private String signInRemark;
/**
* 签退时间
*/
@ExcelProperty(value = "签退时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date signOutTime;
/**
* 签退状态(0-未签退 1-已签退)
*/
@ExcelProperty(value = "签退状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "stgl_activity_sign_status")
private Integer signOutStatus;
/**
* 签退地点
*/
@ExcelProperty(value = "签退地点")
private String signOutLocation;
/**
* 签退设备信息
*/
@ExcelProperty(value = "签退设备信息")
private String signOutDevice;
/**
* 签退备注
*/
@ExcelProperty(value = "签退备注")
private String signOutRemark;
/**
* 签到状态(0-未签到 1-已签到 2-已签退)
*/
@ExcelProperty(value = "签到状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "stgl_activity_sign_status")
private Integer overallStatus;
/**
* 创建者
*/
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;
// ===== 关联查询字段 =====
/**
* 活动名称
*/
@ExcelProperty(value = "活动名称")
private String activityName;
/**
* 活动类型
*/
@ExcelProperty(value = "活动类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "stgl_activity_type")
private String activityType;
/**
* 活动主题
*/
@ExcelProperty(value = "活动主题")
private String activityTheme;
/**
* 活动地点
*/
@ExcelProperty(value = "活动地点")
private String location;
/**
* 开始时间
*/
@ExcelProperty(value = "开始时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/**
* 结束时间
*/
@ExcelProperty(value = "结束时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
/**
* 记录时间(根据签到状态取sign_in_time或sign_out_time)
*/
@ExcelProperty(value = "记录时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date recordTime;
}
@@ -0,0 +1,224 @@
package org.dromara.stgl.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.stgl.domain.StglActivityRegistration;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 活动报名视图对象 stgl_activity_registration
*
* @author ruoyi
* @date 2024-12-19
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = StglActivityRegistration.class)
public class StglActivityRegistrationVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 活动ID
*/
@ExcelProperty(value = "活动ID")
private Long activityId;
/**
* 用户ID
*/
@ExcelProperty(value = "用户ID")
private Long userId;
/**
* 学号
*/
@ExcelProperty(value = "学号")
private String studentNo;
/**
* 学生姓名
*/
@ExcelProperty(value = "学生姓名")
private String studentName;
/**
* 报名类型(1-个人 2-团队)
*/
@ExcelProperty(value = "报名类型")
private String registrationType;
/**
* 团队ID(团队报名时)
*/
@ExcelProperty(value = "团队ID")
private Long teamId;
/**
* 团队名称
*/
@ExcelProperty(value = "团队名称")
private String teamName;
/**
* 报名时间
*/
@ExcelProperty(value = "报名时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date registrationTime;
/**
* 申请理由
*/
@ExcelProperty(value = "申请理由")
private String remark;
/**
* 审核状态(0-待审核 1-通过 2-驳回)
*/
@ExcelProperty(value = "审核状态")
private String approvalStatus;
/**
* 审核时间
*/
@ExcelProperty(value = "审核时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date approvalTime;
/**
* 审核人
*/
@ExcelProperty(value = "审核人")
private Long approvalBy;
/**
* 审核意见
*/
@ExcelProperty(value = "审核意见")
private String approvalRemark;
/**
* 获得成绩
*/
@ExcelProperty(value = "获得成绩")
private String score;
/**
* 成绩录入时间
*/
@ExcelProperty(value = "成绩录入时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date scoreTime;
/**
* 成绩录入人
*/
@ExcelProperty(value = "成绩录入人")
private Long scoreBy;
/**
* 性别
*/
@ExcelProperty(value = "性别")
private String gender;
/**
* 联系电话
*/
@ExcelProperty(value = "联系电话")
private String phone;
/**
* 邮箱
*/
@ExcelProperty(value = "邮箱")
private String email;
/**
* 院系
*/
@ExcelProperty(value = "院系")
private String department;
/**
* 专业
*/
@ExcelProperty(value = "专业")
private String major;
/**
* 班级
*/
@ExcelProperty(value = "班级")
private String className;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
@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;
/**
* 删除标志(0代表存在 1代表删除)
*/
private Integer deleted;
/**
* 租户编号
*/
private String tenantId;
/**
* 创建部门
*/
private Long createDept;
/**
* 活动名称
*/
@ExcelProperty(value = "活动名称")
private String activityName;
/**
* 审核人姓名
*/
@ExcelProperty(value = "审核人姓名")
private String approvalByName;
/**
* 成绩录入人姓名
*/
@ExcelProperty(value = "成绩录入人姓名")
private String scoreByName;
}
@@ -0,0 +1,110 @@
package org.dromara.stgl.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.stgl.domain.StglActivityTeamInfo;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 活动团队信息视图对象 stgl_activity_team_info
*
* @author ruoyi
* @date 2024-12-19
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = StglActivityTeamInfo.class)
public class StglActivityTeamInfoVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 团队名称
*/
@ExcelProperty(value = "团队名称")
private String teamName;
/**
* 关联活动ID
*/
@ExcelProperty(value = "关联活动ID")
private Long activityId;
/**
* 队长用户ID
*/
@ExcelProperty(value = "队长用户ID")
private Long leaderUserId;
/**
* 队长姓名
*/
@ExcelProperty(value = "队长姓名")
private String leaderName;
/**
* 队长学号
*/
@ExcelProperty(value = "队长学号")
private String leaderStudentNo;
/**
* 团队成员信息(JSON格式)
*/
@ExcelProperty(value = "团队成员信息")
private String teamMembers;
/**
* 团队人数
*/
@ExcelProperty(value = "团队人数")
private Integer teamSize;
/**
* 团队简介
*/
@ExcelProperty(value = "团队简介")
private String description;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
@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;
/**
* 活动名称
*/
@ExcelProperty(value = "活动名称")
private String activityName;
}
@@ -0,0 +1,299 @@
package org.dromara.stgl.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.stgl.domain.StglActivity;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 活动信息视图对象 stgl_activity
*
* @author ruoyi
* @date 2025-01-07
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = StglActivity.class)
public class StglActivityVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 序号(用于Excel导出)
*/
@ExcelProperty(value = "序号", index = 0)
private Integer sequenceNumber;
/**
* 主键ID
*/
private Long id;
/**
* 活动名称
*/
@ExcelProperty(value = "活动名称", index = 1)
private String activityName;
/**
* 活动类型
*/
@ExcelProperty(value = "活动类型", converter = ExcelDictConvert.class, index = 2)
@ExcelDictFormat(dictType = "stgl_activity_type")
private String activityType;
/**
* 活动主题
*/
@ExcelProperty(value = "活动主题", index = 3)
private String activityTheme;
/**
* 开始时间
*/
@ExcelProperty(value = "开始时间", index = 4)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/**
* 结束时间
*/
@ExcelProperty(value = "结束时间", index = 5)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
/**
* 活动地点
*/
@ExcelProperty(value = "活动地点", index = 6)
private String location;
/**
* 活动简介
*/
@ExcelProperty(value = "活动简介", index = 7)
private String description;
/**
* 活动海报路径
*/
private String posterUrl;
/**
* 关联社团ID
*/
private Long relatedClubId;
/**
* 关联类型(1-社团 2-志愿者队伍)
*/
private Integer relatedType;
/**
* 关联社团名称(查询时关联获取)
*/
@ExcelProperty(value = "关联社团名称", index = 8)
private String relatedClubName;
/**
* 主办方名称
*/
@ExcelProperty(value = "主办方名称", index = 9)
private String organizerName;
/**
* 主办方类型
*/
private String organizerType;
/**
* 主办方联系人
*/
@ExcelProperty(value = "主办方联系人", index = 10)
private String organizerContact;
/**
* 主办方电话
*/
@ExcelProperty(value = "主办方电话", index = 11)
private String organizerPhone;
/**
* 承办方信息(JSON格式存储多个承办方)
*/
private String coOrganizers;
/**
* 承办方信息(格式化显示用于Excel导出)
*/
@ExcelProperty(value = "承办方信息", index = 12)
private String coOrganizersDisplay;
/**
* 指导老师列表(JSON格式)
*/
private String instructors;
/**
* 指导老师(格式化显示用于Excel导出)
*/
@ExcelProperty(value = "指导老师", index = 13)
private String instructorsDisplay;
/**
* 报名方式(1-个人 2-团队 3-两者均可)
*/
@ExcelProperty(value = "报名方式", converter = ExcelDictConvert.class, index = 14)
@ExcelDictFormat(dictType = "stgl_registration_type")
private Integer registrationType;
/**
* 报名开始时间
*/
@ExcelProperty(value = "报名开始时间", index = 15)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date registrationStart;
/**
* 报名结束时间
*/
@ExcelProperty(value = "报名结束时间", index = 16)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date registrationEnd;
/**
* 报名状态(0-未开始 1-报名中 2-已截止 3-已关闭)
*/
@ExcelProperty(value = "报名状态", converter = ExcelDictConvert.class, index = 17)
@ExcelDictFormat(dictType = "stgl_registration_status")
private Integer registrationStatus;
/**
* 总人数上限
*/
@ExcelProperty(value = "总人数上限", index = 18)
private Integer maxParticipants;
/**
* 团队数量上限
*/
@ExcelProperty(value = "团队数量上限", index = 19)
private Integer maxTeams;
/**
* 每队最小人数
*/
@ExcelProperty(value = "每队最小人数", index = 20)
private Integer teamSizeMin;
/**
* 每队最大人数
*/
@ExcelProperty(value = "每队最大人数", index = 21)
private Integer teamSizeMax;
/**
* 是否需要审核(0-无需 1-需要)
*/
@ExcelProperty(value = "是否需要审核", converter = ExcelDictConvert.class, index = 22)
@ExcelDictFormat(dictType = "sys_yes_no")
private Integer needApproval;
/**
* 活动状态
*/
@ExcelProperty(value = "活动状态", converter = ExcelDictConvert.class, index = 23)
@ExcelDictFormat(dictType = "stgl_activity_status")
private String activityStatus;
/**
* 是否为已办活动
*/
@ExcelProperty(value = "是否为已办活动", converter = ExcelDictConvert.class, index = 29)
@ExcelDictFormat(dictType = "sys_yes_no")
private Integer isFinished;
/**
* 活动总结报告
*/
@ExcelProperty(value = "活动总结报告", index = 27)
private String summary;
/**
* 活动总结报告附件
*/
private String summaryAttachments;
/**
* 活动成果
*/
@ExcelProperty(value = "活动成果", index = 28)
private String achievements;
/**
* 活动成果附件
*/
private String achievementsAttachments;
/**
* 创建者姓名(关联查询)
*/
@ExcelProperty(value = "创建者", index = 24)
private String createByName;
/**
* 导入来源信息
*/
@ExcelProperty(value = "导入来源信息", index = 30)
private String importSource;
/**
* 备注
*/
@ExcelProperty(value = "备注", index = 31)
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;
/**
* 报名人数统计(关联查询)
*/
@ExcelProperty(value = "报名人数", index = 25)
private Integer registrationCount;
/**
* 平均评分(关联查询)
*/
@ExcelProperty(value = "平均评分", index = 26)
private Double averageRating;
}
@@ -78,6 +78,11 @@ public class StglClubRegisterVo implements Serializable {
*/
private Integer currentMemberCount;
/**
* 成员数量(前端兼容字段)
*/
private Integer memberCount;
/**
* 招新周期
*/
@@ -108,4 +113,129 @@ public class StglClubRegisterVo implements Serializable {
*/
private Boolean canRegister;
/**
* 我在该社团的角色类型(用户相关查询时使用)
*/
private Integer myRoleType;
/**
* 我加入该社团的时间(用户相关查询时使用)
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date myJoinTime;
/**
* 我在该社团的角色名称(用户相关查询时使用)
*/
private String myRoleName;
/**
* 是否已报名/加入(用于兼容性)
*/
private Boolean isRegistered;
// ========== 副社长信息 ==========
/**
* 副社长姓名
*/
private String vicePresidentName;
/**
* 副社长学号
*/
private String vicePresidentStudentNo;
/**
* 副社长院系
*/
private String vicePresidentDept;
/**
* 副社长专业
*/
private String vicePresidentMajor;
/**
* 副社长班级
*/
private String vicePresidentClass;
/**
* 副社长联系方式
*/
private String vicePresidentPhone;
/**
* 副社长列表JSON格式(支持多个副社长)
*/
private String vicePresidentsJson;
// ========== 其他完善字段 ==========
/**
* 电话
*/
private String phone;
/**
* 邮箱
*/
private String email;
/**
* 社长学号
*/
private String presidentStudentNo;
/**
* 社长专业
*/
private String presidentMajor;
/**
* 社长班级
*/
private String presidentClass;
/**
* 社长联系方式
*/
private String presidentPhone;
/**
* 指导老师联系电话
*/
private String advisorPhone;
/**
* 指导老师邮箱
*/
private String advisorEmail;
/**
* 指导老师列表JSON格式(支持多个指导老师)
*/
private String advisorsJson;
/**
* 经费来源
*/
private String fundingSources;
/**
* 组织架构
*/
private String departments;
/**
* 章程文档路径
*/
private String charterUrl;
/**
* 备注信息
*/
private String remark;
}
@@ -1,7 +1,7 @@
package org.dromara.stgl.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
@@ -120,6 +120,30 @@ public class StglClubVo implements Serializable {
@ExcelProperty(value = "副社长学号")
private String vicePresidentStudentNo;
/**
* 副社长院系
*/
@ExcelProperty(value = "副社长院系")
private String vicePresidentDept;
/**
* 副社长专业
*/
@ExcelProperty(value = "副社长专业")
private String vicePresidentMajor;
/**
* 副社长班级
*/
@ExcelProperty(value = "副社长班级")
private String vicePresidentClass;
/**
* 副社长联系方式
*/
@ExcelProperty(value = "副社长联系方式")
private String vicePresidentPhone;
/**
* 指导老师姓名
*/
@@ -132,6 +156,28 @@ public class StglClubVo implements Serializable {
@ExcelProperty(value = "指导老师所属院系")
private String advisorDept;
/**
* 指导老师联系电话
*/
@ExcelProperty(value = "指导老师联系电话")
private String advisorPhone;
/**
* 指导老师邮箱
*/
@ExcelProperty(value = "指导老师邮箱")
private String advisorEmail;
/**
* 副社长列表JSON格式存储
*/
private String vicePresidentsJson;
/**
* 指导老师列表JSON格式存储
*/
private String advisorsJson;
/**
* 成员规模上限
*/
@@ -208,4 +254,25 @@ public class StglClubVo implements Serializable {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/**
* 当前成员数量(查询时动态计算)
*/
private Integer memberCount;
/**
* 我在该社团的角色类型(用户相关查询时使用)
*/
private Integer myRoleType;
/**
* 我加入该社团的时间(用户相关查询时使用)
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date myJoinTime;
/**
* 我在该社团的角色名称(用户相关查询时使用)
*/
private String myRoleName;
}
@@ -0,0 +1,190 @@
package org.dromara.stgl.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.stgl.domain.StglMaterialSubmission;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 材料提交记录视图对象 stgl_material_submission
*
* @author ruoyi
* @date 2025-01-03
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = StglMaterialSubmission.class)
public class StglMaterialSubmissionVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 序号(用于Excel导出)
*/
@ExcelProperty(value = "序号", index = 0)
private Integer sequenceNumber;
/**
* 主键ID
*/
private Long id;
/**
* 收集任务ID
*/
private Long taskId;
/**
* 任务名称
*/
@ExcelProperty(value = "任务名称", index = 1)
private String taskName;
/**
* 活动ID
*/
private Long activityId;
/**
* 活动名称
*/
@ExcelProperty(value = "活动名称", index = 2)
private String activityName;
/**
* 用户ID
*/
private Long userId;
/**
* 学号
*/
@ExcelProperty(value = "学号", index = 3)
private String studentNo;
/**
* 学生姓名
*/
@ExcelProperty(value = "学生姓名", index = 4)
private String studentName;
/**
* 提交类型(1-个人 2-团队)
*/
private Integer submissionType;
/**
* 提交类型显示名称
*/
@ExcelProperty(value = "提交类型", converter = ExcelDictConvert.class, index = 5)
@ExcelDictFormat(dictType = "stgl_submission_type")
private String submissionTypeDisplay;
/**
* 团队ID
*/
private Long teamId;
/**
* 团队名称
*/
@ExcelProperty(value = "团队名称", index = 6)
private String teamName;
/**
* 文本内容
*/
@ExcelProperty(value = "文本内容", index = 7)
private String contentText;
/**
* 附件路径(JSON格式)
*/
private String fileUrls;
/**
* 图片路径(JSON格式)
*/
private String imageUrls;
/**
* 提交时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ExcelProperty(value = "提交时间", index = 8)
private Date submissionTime;
/**
* 提交轮次
*/
@ExcelProperty(value = "提交轮次", index = 9)
private Integer roundNumber;
/**
* 审核状态(0-待审核 1-通过 2-驳回)
*/
private Integer reviewStatus;
/**
* 审核状态显示名称
*/
@ExcelProperty(value = "审核状态", converter = ExcelDictConvert.class, index = 10)
@ExcelDictFormat(dictType = "stgl_review_status")
private String reviewStatusDisplay;
/**
* 审核时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ExcelProperty(value = "审核时间", index = 11)
private Date reviewTime;
/**
* 审核人
*/
private Long reviewBy;
/**
* 审核人姓名
*/
@ExcelProperty(value = "审核人", index = 12)
private String reviewByName;
/**
* 审核意见
*/
@ExcelProperty(value = "审核意见", index = 13)
private String reviewRemark;
/**
* 创建者
*/
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;
}
@@ -0,0 +1,169 @@
package org.dromara.stgl.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.stgl.domain.StglMaterialTask;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 材料收集任务视图对象 stgl_material_task
*
* @author ruoyi
* @date 2025-01-03
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = StglMaterialTask.class)
public class StglMaterialTaskVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 序号(用于Excel导出)
*/
@ExcelProperty(value = "序号", index = 0)
private Integer sequenceNumber;
/**
* 主键ID
*/
private Long id;
/**
* 关联活动ID
*/
private Long activityId;
/**
* 活动名称
*/
@ExcelProperty(value = "活动名称", index = 1)
private String activityName;
/**
* 任务名称
*/
@ExcelProperty(value = "任务名称", index = 2)
private String taskName;
/**
* 收集类型(多选,逗号分隔)
*/
private String collectionTypes;
/**
* 收集类型显示名称
*/
@ExcelProperty(value = "材料收集类型", index = 3)
private String collectionTypesDisplay;
/**
* 任务描述
*/
@ExcelProperty(value = "收集说明", index = 4)
private String taskDescription;
/**
* 任务状态(1-开启 0-关闭)
*/
private Integer taskStatus;
/**
* 任务状态显示名称
*/
@ExcelProperty(value = "任务状态", converter = ExcelDictConvert.class, index = 5)
@ExcelDictFormat(dictType = "stgl_task_status")
private String taskStatusDisplay;
/**
* 截止时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ExcelProperty(value = "截止时间", index = 6)
private Date deadline;
/**
* 收集轮次
*/
@ExcelProperty(value = "收集轮次", index = 7)
private Integer roundNumber;
/**
* 文件大小限制(MB)
*/
@ExcelProperty(value = "文件大小限制(MB)", index = 8)
private Integer fileSizeLimit;
/**
* 文件数量限制
*/
@ExcelProperty(value = "文件数量限制", index = 9)
private Integer fileCountLimit;
/**
* 允许的文件类型
*/
private String allowedFileTypes;
/**
* 总参与人数
*/
@ExcelProperty(value = "总参与人数", index = 10)
private Integer totalParticipants;
/**
* 已提交人数
*/
@ExcelProperty(value = "已提交人数", index = 11)
private Integer submittedCount;
/**
* 待提交人数
*/
@ExcelProperty(value = "待提交人数", index = 12)
private Integer pendingCount;
/**
* 备注
*/
@ExcelProperty(value = "备注", index = 13)
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;
/**
* 创建者姓名
*/
@ExcelProperty(value = "创建者", index = 14)
private String createByName;
}
@@ -0,0 +1,126 @@
package org.dromara.stgl.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.dromara.stgl.domain.StglMember;
import io.github.linpeilie.annotations.AutoMapper;
import java.io.Serial;
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 StglMemberImportVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 社团名称
*/
@ExcelProperty(value = "社团名称")
private String clubName;
/**
* 学号
*/
@ExcelProperty(value = "学号")
private String studentNo;
/**
* 姓名
*/
@ExcelProperty(value = "姓名")
private String studentName;
/**
* 加入时间
*/
@ExcelProperty(value = "加入时间", format = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date joinTime;
// ========== 以下字段不在Excel中,用于内部处理 ==========
/**
* 成员类型(默认:1-社团成员)
*/
private Integer memberType = 1;
/**
* 社团ID(从社团名称查询获得)
*/
private Long relationId;
/**
* 用户ID(从学号查询获得)
*/
private Long userId;
/**
* 性别(从学生信息表获得)
*/
private String gender;
/**
* 联系方式(从学生信息表获得)
*/
private String phone;
/**
* 院系(从学生信息表获得)
*/
private String department;
/**
* 专业(从学生信息表获得)
*/
private String major;
/**
* 班级(从学生信息表获得)
*/
private String className;
/**
* 角色类型(默认:4-普通成员)
*/
private Integer roleType = 4;
/**
* 状态(默认:2-已加入)
*/
private Integer status = 2;
/**
* 创建者
*/
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;
}
@@ -1,7 +1,7 @@
package org.dromara.stgl.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
@@ -26,86 +26,122 @@ public class StglMemberVo implements Serializable {
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 成员类型(1-社团成员 2-志愿者)
*/
@ExcelProperty(value = "成员类型")
private Integer memberType;
/**
* 成员类型名称
*/
@ExcelProperty(value = "成员类型名称")
@ExcelProperty(value = "成员类型", index = 0)
private String memberTypeName;
/**
* 关联ID(社团ID或志愿者队伍ID)
*/
@ExcelProperty(value = "关联ID")
private Long relationId;
/**
* 关联名称(社团名称或志愿者队伍名称)
*/
@ExcelProperty(value = "所属组织")
@ExcelProperty(value = "所属组织", index = 1)
private String relationName;
/**
* 用户ID
*/
@ExcelProperty(value = "用户ID")
private Long userId;
/**
* 学号
*/
@ExcelProperty(value = "学号")
@ExcelProperty(value = "学号", index = 2)
private String studentNo;
/**
* 学生姓名
*/
@ExcelProperty(value = "学生姓名")
@ExcelProperty(value = "姓名", index = 3)
private String studentName;
/**
* 性别
*/
@ExcelProperty(value = "性别", index = 4)
private String gender;
/**
* 院系
*/
@ExcelProperty(value = "院系", index = 5)
private String department;
/**
* 专业
*/
@ExcelProperty(value = "专业", index = 6)
private String major;
/**
* 班级
*/
@ExcelProperty(value = "班级", index = 7)
private String className;
/**
* 联系方式
*/
@ExcelProperty(value = "联系方式", index = 8)
private String phone;
/**
* 邮箱
*/
@ExcelProperty(value = "邮箱", index = 9)
private String email;
/**
* 社团名称
*/
@ExcelProperty(value = "社团名称", index = 10)
private String clubName;
/**
* 角色类型(1-社长 2-副社长 3-成员)
*/
@ExcelProperty(value = "角色类型")
private Integer roleType;
/**
* 角色类型名称
*/
@ExcelProperty(value = "角色名称")
@ExcelProperty(value = "角色", index = 11)
private String roleTypeName;
/**
* 加入时间
*/
@ExcelProperty(value = "加入时间")
@ExcelProperty(value = "加入时间", index = 12)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date joinTime;
/**
* 状态(1-正常 0-退出)
* 状态(0-正常 1-停用)
*/
@ExcelProperty(value = "状态")
private Integer status;
/**
* 状态名称
*/
@ExcelProperty(value = "状态名称")
@ExcelProperty(value = "状态", index = 13)
private String statusName;
/**
* 备注
*/
@ExcelProperty(value = "备注")
@ExcelProperty(value = "备注", index = 14)
private String remark;
/**
@@ -0,0 +1,55 @@
package org.dromara.stgl.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 志愿者成员导入模板视图对象
*
* @author Cursor AI
* @date 2025-01-18
*/
@Data
@ExcelIgnoreUnannotated
public class StglVolunteerImportVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 队伍名称
*/
@ExcelProperty(value = "队伍名称", index = 0)
private String teamName;
/**
* 学号
*/
@ExcelProperty(value = "学号", index = 1)
private String studentNo;
/**
* 姓名
*/
@ExcelProperty(value = "姓名", index = 2)
private String studentName;
/**
* 加入时间
*/
@ExcelProperty(value = "加入时间", index = 3, format = "yyyy-MM-dd")
private Date joinTime;
/**
* 队伍ID(内部使用,不在Excel中显示)
*/
private Long relationId;
/**
* 用户ID(内部使用,不在Excel中显示)
*/
private Long userId;
}
@@ -0,0 +1,47 @@
package org.dromara.stgl.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
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
@ExcelIgnoreUnannotated
public class StglVolunteerMemberImportVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 所属队伍
*/
@ExcelProperty(value = "所属队伍", index = 0)
private String relationName;
/**
* 学号
*/
@ExcelProperty(value = "学号", index = 1)
private String studentNo;
/**
* 姓名
*/
@ExcelProperty(value = "姓名", index = 2)
private String studentName;
/**
* 加入时间
*/
@ExcelProperty(value = "加入时间", index = 3, format = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date joinTime;
}
@@ -0,0 +1,216 @@
package org.dromara.stgl.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.stgl.domain.StglVolunteerTeam;
import java.io.Serializable;
import java.util.Date;
/**
* 志愿者队伍视图对象 stgl_volunteer_team
*
* @author Cursor AI
* @date 2025-01-07
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = StglVolunteerTeam.class)
public class StglVolunteerTeamVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 队伍名称
*/
@ExcelProperty(value = "队伍名称")
private String teamName;
/**
* 队伍类型
*/
@ExcelProperty(value = "队伍类型")
private String teamType;
/**
* 队伍描述
*/
@ExcelProperty(value = "队伍描述")
private String description;
/**
* 成立日期
*/
@ExcelProperty(value = "成立日期")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date establishDate;
/**
* 联系电话
*/
@ExcelProperty(value = "联系电话")
private String phone;
/**
* 联系邮箱
*/
@ExcelProperty(value = "联系邮箱")
private String email;
/**
* 备注信息
*/
@ExcelProperty(value = "备注信息")
private String remark;
/**
* 队长姓名
*/
@ExcelProperty(value = "队长姓名")
private String leaderName;
/**
* 队长学号
*/
@ExcelProperty(value = "队长学号")
private String leaderStudentNo;
/**
* 队长用户ID
*/
private Long leaderUserId;
/**
* 队长联系方式
*/
@ExcelProperty(value = "队长联系方式")
private String leaderPhone;
/**
* 队长院系
*/
@ExcelProperty(value = "队长院系")
private String leaderDept;
/**
* 队长专业
*/
@ExcelProperty(value = "队长专业")
private String leaderMajor;
/**
* 队长班级
*/
@ExcelProperty(value = "队长班级")
private String leaderClass;
/**
* 指导老师姓名
*/
@ExcelProperty(value = "指导老师姓名")
private String advisorName;
/**
* 指导老师联系电话
*/
@ExcelProperty(value = "指导老师联系电话")
private String advisorPhone;
/**
* 指导老师所在部门
*/
@ExcelProperty(value = "指导老师所在部门")
private String advisorDept;
/**
* 指导老师邮箱
*/
@ExcelProperty(value = "指导老师邮箱")
private String advisorEmail;
/**
* 人员上限
*/
@ExcelProperty(value = "人员上限")
private Integer memberLimit;
/**
* 状态(1-正常 0-停用)
*/
@ExcelProperty(value = "状态")
private Integer status;
/**
* 创建者
*/
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;
/**
* 租户编号
*/
private String tenantId;
/**
* 版本号
*/
private Long version;
/**
* 逻辑删除
*/
private Long deleted;
/**
* 当前志愿者人数(动态计算)
*/
private Integer currentMemberCount;
/**
* 当前用户在此队伍的申请状态(0-待审核 1-审核中 2-已加入 3-已驳回 4-已退出)
*/
private Integer userApplicationStatus;
/**
* 当前用户是否已申请此队伍(状态为0或1时为true)
*/
private Boolean hasApplied;
/**
* 当前用户是否已加入此队伍(状态为2时为true)
*/
private Boolean hasJoined;
/**
* 队伍简介(用于前端显示description字段)
*/
public String getTeamDescription() {
return this.description;
}
}
@@ -0,0 +1,314 @@
package org.dromara.stgl.listener;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HtmlUtil;
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.event.AnalysisEventListener;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.excel.core.ExcelListener;
import org.dromara.common.excel.core.ExcelResult;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.stgl.domain.bo.StglClubBo;
import org.dromara.stgl.domain.bo.StglMemberBo;
import org.dromara.stgl.domain.vo.StglClubVo;
import org.dromara.stgl.domain.vo.StglMemberImportVo;
import org.dromara.stgl.domain.vo.StglMemberVo;
import org.dromara.stgl.service.IStglClubService;
import org.dromara.stgl.service.IStglMemberService;
import org.dromara.system.service.ISysUserService;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.xg.domain.bo.XgStudentMsgBo;
import org.dromara.xg.domain.vo.XgStudentMsgVo;
import org.dromara.xg.service.IXgStudentMsgService;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
/**
* 社团成员导入监听器
*
* @author Cursor AI
* @date 2025-01-15
*/
@Slf4j
public class StglMemberImportListener extends AnalysisEventListener<StglMemberImportVo>
implements ExcelListener<StglMemberImportVo> {
private final IStglMemberService memberService;
private final IStglClubService clubService;
private final IXgStudentMsgService studentMsgService;
private final ISysUserService userService;
private final Boolean isUpdateSupport;
private final Long operUserId;
private int successNum = 0;
private int failureNum = 0;
private final StringBuilder successMsg = new StringBuilder();
private final StringBuilder failureMsg = new StringBuilder();
// 存储所有Excel数据,用于批量验证
private final List<StglMemberImportVo> allDataList = new ArrayList<>();
public StglMemberImportListener(Boolean isUpdateSupport) {
this.memberService = SpringUtils.getBean(IStglMemberService.class);
this.clubService = SpringUtils.getBean(IStglClubService.class);
this.studentMsgService = SpringUtils.getBean(IXgStudentMsgService.class);
this.userService = SpringUtils.getBean(ISysUserService.class);
this.isUpdateSupport = isUpdateSupport;
this.operUserId = LoginHelper.getUserId();
}
@Override
public void invoke(StglMemberImportVo memberVo, AnalysisContext context) {
try {
log.info("收集Excel行数据,行号: {}", context.readRowHolder().getRowIndex());
// 验证必填字段
if (ObjectUtil.hasEmpty(memberVo.getClubName(), memberVo.getStudentNo(), memberVo.getStudentName())) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、第 ")
.append(context.readRowHolder().getRowIndex() + 1)
.append(" 行数据不完整,社团名称、学号、姓名为必填项");
return;
}
// 先收集数据,不进行处理
allDataList.add(memberVo);
} catch (Exception e) {
failureNum++;
String msg = "<br/>" + failureNum + "、学号 " + HtmlUtil.cleanHtmlTag(memberVo.getStudentNo()) + " 数据收集失败:";
failureMsg.append(msg).append(e.getMessage());
log.error(msg, e);
}
}
/**
* 从学生信息填充成员信息
* 注:只填充BO类中存在的核心字段,学生详细信息通过关联查询在VO层获取
*/
private void fillStudentInfo(StglMemberBo member, XgStudentMsgVo student) {
member.setStudentName(student.getName());
// 移除BO类中不存在的字段设置
// 学生的性别、电话、院系、专业、班级等信息通过关联查询在显示层获取
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
log.info("Excel数据解析完成,开始批量验证和处理,共 {} 条数据", allDataList.size());
// 如果之前已有失败记录,直接返回
if (failureNum > 0) {
return;
}
try {
// 第一阶段:批量验证所有学号是否存在对应用户
log.info("第一阶段:验证所有学号是否存在对应用户");
for (int i = 0; i < allDataList.size(); i++) {
StglMemberImportVo memberVo = allDataList.get(i);
// 验证学号对应的用户是否存在
SysUserVo user = userService.selectUserByUserName(memberVo.getStudentNo());
if (user == null) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、系统中不存在学号为")
.append(memberVo.getStudentNo()).append("姓名为").append(memberVo.getStudentName())
.append("的学生");
// 一旦发现学号不存在,立即停止验证
log.error("学号 {} 不存在对应用户,停止验证", memberVo.getStudentNo());
return;
}
// 设置用户ID
memberVo.setUserId(user.getUserId());
log.info("学号 {} 对应用户ID: {}", memberVo.getStudentNo(), user.getUserId());
}
log.info("所有学号验证通过,开始第二阶段处理");
// 第二阶段:所有学号验证通过后,进行具体的业务验证和数据导入
for (int i = 0; i < allDataList.size(); i++) {
StglMemberImportVo memberVo = allDataList.get(i);
processOneMember(memberVo, i + 1);
}
} catch (Exception e) {
log.error("批量处理过程中发生异常", e);
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、批量处理失败:").append(e.getMessage());
}
log.info("批量处理完成,成功: {}, 失败: {}", successNum, failureNum);
}
/**
* 处理单个成员记录
*/
private void processOneMember(StglMemberImportVo memberVo, int rowNum) {
try {
log.info("处理第 {} 行成员数据: {}", rowNum, memberVo.getStudentNo());
// 1. 验证社团名称,获取社团ID
StglClubBo clubQueryBo = new StglClubBo();
clubQueryBo.setClubName(memberVo.getClubName());
List<StglClubVo> clubList = clubService.queryList(clubQueryBo);
if (clubList.isEmpty()) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、社团名称 \"")
.append(memberVo.getClubName()).append("\" 不存在");
return;
}
StglClubVo club = clubList.get(0);
memberVo.setRelationId(club.getId());
// 2. 验证学号,获取学生信息
XgStudentMsgBo studentQueryBo = new XgStudentMsgBo();
studentQueryBo.setStudentNo(memberVo.getStudentNo());
List<XgStudentMsgVo> studentList = studentMsgService.queryList(studentQueryBo);
if (studentList.isEmpty()) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、学号 \"")
.append(memberVo.getStudentNo()).append("\" 不存在");
return;
}
XgStudentMsgVo student = studentList.get(0);
// 3. 验证学号与姓名是否匹配
if (!memberVo.getStudentName().equals(student.getName())) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、学号 \"")
.append(memberVo.getStudentNo()).append("\" 对应的姓名应为 \"")
.append(student.getName()).append("\",不匹配 \"")
.append(memberVo.getStudentName()).append("\"");
return;
}
// 4. 检查是否已经是该社团成员
StglMemberBo memberQueryBo = new StglMemberBo();
memberQueryBo.setRelationId(club.getId());
memberQueryBo.setStudentNo(memberVo.getStudentNo());
List<StglMemberVo> existingMembers = memberService.queryList(memberQueryBo);
if (!existingMembers.isEmpty()) {
if (isUpdateSupport) {
// 支持更新,更新现有成员信息
StglMemberBo updateMember = BeanUtil.toBean(memberVo, StglMemberBo.class);
updateMember.setId(existingMembers.get(0).getId());
updateMember.setUpdateBy(operUserId);
updateMember.setUpdateTime(new Date());
// 从学生信息自动填充字段
fillStudentInfo(updateMember, student);
// 确保必要字段有正确的默认值
ensureDefaultValues(updateMember);
ValidatorUtils.validate(updateMember);
memberService.updateByBo(updateMember);
successNum++;
successMsg.append("<br/>").append(successNum).append("、学号 ")
.append(memberVo.getStudentNo()).append(" 姓名 ")
.append(memberVo.getStudentName()).append(" 更新成功");
return;
} else {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、学号 \"")
.append(memberVo.getStudentNo()).append("\" 已是社团 \"")
.append(memberVo.getClubName()).append("\" 的成员");
return;
}
}
// 5. 创建新成员
StglMemberBo newMember = BeanUtil.toBean(memberVo, StglMemberBo.class);
newMember.setCreateBy(operUserId);
newMember.setCreateTime(new Date());
newMember.setUpdateBy(operUserId);
newMember.setUpdateTime(new Date());
// 从学生信息自动填充字段
fillStudentInfo(newMember, student);
// 设置默认值
if (newMember.getJoinTime() == null) {
newMember.setJoinTime(new Date());
}
// 确保必要字段有正确的默认值
ensureDefaultValues(newMember);
ValidatorUtils.validate(newMember);
memberService.insertByBo(newMember);
successNum++;
successMsg.append("<br/>").append(successNum).append("、学号 ")
.append(memberVo.getStudentNo()).append(" 姓名 ")
.append(memberVo.getStudentName()).append(" 导入成功");
} catch (Exception e) {
failureNum++;
String msg = "<br/>" + failureNum + "、学号 " + HtmlUtil.cleanHtmlTag(memberVo.getStudentNo()) + " 导入失败:";
String message = e.getMessage();
if (e instanceof ConstraintViolationException cvException) {
message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", ");
}
failureMsg.append(msg).append(message);
log.error(msg, e);
}
}
/**
* 确保必要字段有正确的默认值
*/
private void ensureDefaultValues(StglMemberBo member) {
if (member.getMemberType() == null) {
member.setMemberType(1); // 社团成员
}
if (member.getRoleType() == null) {
member.setRoleType(4); // 普通成员
}
if (member.getStatus() == null) {
member.setStatus(2); // 已加入
}
// 🔑 关键验证:确保userId不为空
if (member.getUserId() == null) {
log.error("成员{}的用户ID为空,这是数据处理逻辑问题", member.getStudentNo());
throw new ServiceException("用户ID不能为空,请检查学生数据");
}
}
@Override
public ExcelResult<StglMemberImportVo> getExcelResult() {
return new ExcelResult<>() {
@Override
public String getAnalysis() {
if (failureNum > 0) {
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
throw new ServiceException(failureMsg.toString());
} else {
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
}
return successMsg.toString();
}
@Override
public List<StglMemberImportVo> getList() {
return null;
}
@Override
public List<String> getErrorList() {
return null;
}
};
}
}
@@ -0,0 +1,299 @@
package org.dromara.stgl.listener;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HtmlUtil;
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.event.AnalysisEventListener;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.excel.core.ExcelListener;
import org.dromara.common.excel.core.ExcelResult;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.stgl.domain.bo.StglMemberBo;
import org.dromara.stgl.domain.bo.StglVolunteerTeamBo;
import org.dromara.stgl.domain.vo.StglMemberVo;
import org.dromara.stgl.domain.vo.StglVolunteerImportVo;
import org.dromara.stgl.domain.vo.StglVolunteerTeamVo;
import org.dromara.stgl.service.IStglMemberService;
import org.dromara.stgl.service.IStglVolunteerTeamService;
import org.dromara.system.service.ISysUserService;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.xg.domain.bo.XgStudentMsgBo;
import org.dromara.xg.domain.vo.XgStudentMsgVo;
import org.dromara.xg.service.IXgStudentMsgService;
import java.util.*;
import java.util.stream.Collectors;
/**
* 志愿者成员导入监听器
*
* @author Cursor AI
* @date 2025-01-18
*/
@Slf4j
public class StglVolunteerImportListener extends AnalysisEventListener<StglVolunteerImportVo>
implements ExcelListener<StglVolunteerImportVo> {
private final IStglMemberService memberService;
private final IStglVolunteerTeamService volunteerTeamService;
private final IXgStudentMsgService studentMsgService;
private final ISysUserService userService;
private final Boolean isUpdateSupport;
private final Long operUserId;
private int successNum = 0;
private int failureNum = 0;
private final StringBuilder successMsg = new StringBuilder();
private final StringBuilder failureMsg = new StringBuilder();
// 存储所有Excel数据,用于批量验证
private final List<StglVolunteerImportVo> allDataList = new ArrayList<>();
public StglVolunteerImportListener(Boolean isUpdateSupport) {
this.memberService = SpringUtils.getBean(IStglMemberService.class);
this.volunteerTeamService = SpringUtils.getBean(IStglVolunteerTeamService.class);
this.studentMsgService = SpringUtils.getBean(IXgStudentMsgService.class);
this.userService = SpringUtils.getBean(ISysUserService.class);
this.isUpdateSupport = isUpdateSupport;
this.operUserId = LoginHelper.getUserId();
}
@Override
public void invoke(StglVolunteerImportVo volunteerVo, AnalysisContext context) {
try {
log.info("收集Excel行数据,行号: {}", context.readRowHolder().getRowIndex());
// 验证必填字段
if (ObjectUtil.hasEmpty(volunteerVo.getTeamName(), volunteerVo.getStudentNo(), volunteerVo.getStudentName())) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、第 ")
.append(context.readRowHolder().getRowIndex() + 1)
.append(" 行数据不完整,队伍名称、学号、姓名为必填项");
return;
}
// 先收集数据,不进行处理
allDataList.add(volunteerVo);
} catch (Exception e) {
failureNum++;
String msg = "<br/>" + failureNum + "、学号 " + HtmlUtil.cleanHtmlTag(volunteerVo.getStudentNo()) + " 数据收集失败:";
failureMsg.append(msg).append(e.getMessage());
log.error(msg, e);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
log.info("Excel数据解析完成,开始批量验证和处理,共 {} 条数据", allDataList.size());
// 如果之前已有失败记录,直接返回
if (failureNum > 0) {
return;
}
try {
// 第一阶段:验证所有队伍名称是否存在,并设置relationId
log.info("第一阶段:验证队伍名称并设置relationId");
for (int i = 0; i < allDataList.size(); i++) {
StglVolunteerImportVo volunteerVo = allDataList.get(i);
// 验证队伍名称,获取队伍ID
StglVolunteerTeamBo teamQueryBo = new StglVolunteerTeamBo();
teamQueryBo.setTeamName(volunteerVo.getTeamName());
List<StglVolunteerTeamVo> teamList = volunteerTeamService.queryList(teamQueryBo);
if (teamList.isEmpty()) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、志愿者队伍名称 \"")
.append(volunteerVo.getTeamName()).append("\" 不存在");
return;
}
StglVolunteerTeamVo team = teamList.get(0);
volunteerVo.setRelationId(team.getId());
}
// 第二阶段:检查模板内数据重复(同一队伍下的学号不能重复)
log.info("第二阶段:检查模板内数据重复");
Map<String, Set<String>> teamStudentMap = new HashMap<>();
for (int i = 0; i < allDataList.size(); i++) {
StglVolunteerImportVo volunteerVo = allDataList.get(i);
String teamKey = volunteerVo.getTeamName();
teamStudentMap.computeIfAbsent(teamKey, k -> new HashSet<>());
if (!teamStudentMap.get(teamKey).add(volunteerVo.getStudentNo())) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、模板中存在重复学号:")
.append(volunteerVo.getStudentNo()).append("(队伍:").append(teamKey).append(")");
log.error("模板中存在重复学号:{}(队伍:{})", volunteerVo.getStudentNo(), teamKey);
return;
}
}
// 第二阶段:批量验证所有学号是否存在对应用户和学生信息
log.info("第二阶段:批量验证学号对应的用户和学生信息");
for (int i = 0; i < allDataList.size(); i++) {
StglVolunteerImportVo volunteerVo = allDataList.get(i);
// 验证学号对应的用户是否存在
SysUserVo user = userService.selectUserByUserName(volunteerVo.getStudentNo());
if (user == null) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、系统中不存在学号为")
.append(volunteerVo.getStudentNo()).append("的用户");
log.error("学号 {} 不存在对应用户,停止验证", volunteerVo.getStudentNo());
return;
}
// 验证学号对应的学生信息是否存在
XgStudentMsgBo studentQueryBo = new XgStudentMsgBo();
studentQueryBo.setStudentNo(volunteerVo.getStudentNo());
List<XgStudentMsgVo> studentList = studentMsgService.queryList(studentQueryBo);
if (studentList.isEmpty()) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、学生信息表中不存在学号为")
.append(volunteerVo.getStudentNo()).append("的学生");
log.error("学号 {} 不存在对应学生信息,停止验证", volunteerVo.getStudentNo());
return;
}
XgStudentMsgVo student = studentList.get(0);
// 验证学号与姓名是否匹配
if (!volunteerVo.getStudentName().equals(student.getName())) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、学号 \"")
.append(volunteerVo.getStudentNo()).append("\" 对应的姓名应为 \"")
.append(student.getName()).append("\",不匹配 \"")
.append(volunteerVo.getStudentName()).append("\"");
log.error("学号 {} 姓名不匹配,停止验证", volunteerVo.getStudentNo());
return;
}
// 设置用户ID
volunteerVo.setUserId(user.getUserId());
log.info("学号 {} 对应用户ID: {}", volunteerVo.getStudentNo(), user.getUserId());
}
// 第四阶段:批量检查是否存在已有数据重复(按队伍分组检查)
log.info("第四阶段:检查与已有数据重复");
for (StglVolunteerImportVo volunteerVo : allDataList) {
StglMemberBo queryBo = new StglMemberBo();
queryBo.setRelationId(volunteerVo.getRelationId());
queryBo.setStudentNo(volunteerVo.getStudentNo());
queryBo.setMemberType(2); // 志愿者成员类型
List<StglMemberVo> existingMembers = memberService.queryList(queryBo);
if (!existingMembers.isEmpty()) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、学号 \"")
.append(volunteerVo.getStudentNo()).append("\" 已是志愿者队伍 \"")
.append(volunteerVo.getTeamName()).append("\" 的成员");
log.error("学号 {} 已是志愿者队伍 {} 的成员", volunteerVo.getStudentNo(), volunteerVo.getTeamName());
return;
}
}
log.info("所有验证通过,开始第五阶段处理");
// 第五阶段:所有验证通过后,进行数据导入
for (int i = 0; i < allDataList.size(); i++) {
StglVolunteerImportVo volunteerVo = allDataList.get(i);
processOneVolunteer(volunteerVo, i + 1);
}
} catch (Exception e) {
log.error("批量处理过程中发生异常", e);
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、批量处理失败:").append(e.getMessage());
}
log.info("批量处理完成,成功: {}, 失败: {}", successNum, failureNum);
}
/**
* 处理单个志愿者成员记录
*/
private void processOneVolunteer(StglVolunteerImportVo volunteerVo, int rowNum) {
try {
log.info("处理第 {} 行志愿者成员数据: {}", rowNum, volunteerVo.getStudentNo());
// 获取学生信息用于填充详细信息
XgStudentMsgBo studentQueryBo = new XgStudentMsgBo();
studentQueryBo.setStudentNo(volunteerVo.getStudentNo());
List<XgStudentMsgVo> studentList = studentMsgService.queryList(studentQueryBo);
XgStudentMsgVo student = studentList.get(0); // 前面已验证过存在
// 创建新志愿者成员
StglMemberBo newMember = new StglMemberBo();
newMember.setMemberType(2); // 志愿者成员类型
newMember.setRelationId(volunteerVo.getRelationId()); // 使用导入时设置的relationId
newMember.setStudentNo(volunteerVo.getStudentNo());
newMember.setStudentName(volunteerVo.getStudentName());
// 🔑 关键修复:设置用户ID(学生ID就是用户ID)
newMember.setUserId(student.getId());
newMember.setRoleType(1); // 志愿者角色 stgl_volunteer_role=1 队员
newMember.setStatus(2); // 成员状态 stgl_member_status=2 已加入
newMember.setJoinTime(volunteerVo.getJoinTime() != null ? volunteerVo.getJoinTime() : new Date());
newMember.setCreateBy(operUserId);
newMember.setCreateTime(new Date());
newMember.setUpdateBy(operUserId);
newMember.setUpdateTime(new Date());
log.info("为志愿者{}设置用户ID: {}", student.getName(), student.getId());
ValidatorUtils.validate(newMember);
memberService.insertByBo(newMember);
successNum++;
successMsg.append("<br/>").append(successNum).append("、学号 ")
.append(volunteerVo.getStudentNo()).append(" 姓名 ")
.append(volunteerVo.getStudentName()).append(" 所属队伍 ")
.append(volunteerVo.getTeamName()).append(" 导入成功");
} catch (Exception e) {
failureNum++;
String msg = "<br/>" + failureNum + "、学号 " + HtmlUtil.cleanHtmlTag(volunteerVo.getStudentNo()) + " 导入失败:";
String message = e.getMessage();
if (e instanceof ConstraintViolationException cvException) {
message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", ");
}
failureMsg.append(msg).append(message);
log.error(msg, e);
}
}
@Override
public ExcelResult<StglVolunteerImportVo> getExcelResult() {
return new ExcelResult<>() {
@Override
public String getAnalysis() {
if (failureNum > 0) {
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
throw new ServiceException(failureMsg.toString());
} else {
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
}
return successMsg.toString();
}
@Override
public List<StglVolunteerImportVo> getList() {
return null;
}
@Override
public List<String> getErrorList() {
return null;
}
};
}
}
@@ -0,0 +1,49 @@
package org.dromara.stgl.mapper;
import org.dromara.stgl.domain.StglActivityAttendance;
import org.dromara.stgl.domain.vo.StglActivityAttendanceVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 活动考勤签到Mapper接口
*
* @author ruoyi
* @date 2025-01-15
*/
public interface StglActivityAttendanceMapper extends BaseMapperPlus<StglActivityAttendance, StglActivityAttendanceVo> {
/**
* 查询活动考勤签到列表(关联查询活动信息)
*
* @param queryWrapper 查询条件
* @return 活动考勤签到列表
*/
List<StglActivityAttendanceVo> selectAttendanceList(@Param("ew") com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StglActivityAttendance> queryWrapper);
/**
* 查询用户已报名成功且进行中的活动列表
*
* @param userId 用户ID
* @return 活动列表
*/
List<StglActivityAttendanceVo> selectUserAvailableActivities(@Param("userId") Long userId);
/**
* 根据活动ID和用户ID查询签到记录
*
* @param activityId 活动ID
* @param userId 用户ID
* @return 签到记录
*/
StglActivityAttendanceVo selectByActivityAndUser(@Param("activityId") Long activityId, @Param("userId") Long userId);
/**
* 根据ID查询活动考勤签到详情(关联查询活动信息)
*
* @param id 主键ID
* @return 活动考勤签到详情
*/
StglActivityAttendanceVo selectVoByIdWithActivity(@Param("id") Long id);
}
@@ -0,0 +1,75 @@
package org.dromara.stgl.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.stgl.domain.StglActivity;
import org.dromara.stgl.domain.vo.StglActivityVo;
import java.util.List;
/**
* 活动信息Mapper接口
*
* @author ruoyi
* @date 2025-01-07
*/
public interface StglActivityMapper extends BaseMapperPlus<StglActivity, StglActivityVo> {
/**
* 查询活动信息列表(包含关联信息)
*
* @param activity 活动信息
* @return 活动信息集合
*/
List<StglActivityVo> selectVoList(StglActivity activity);
/**
* 分页查询活动信息列表(包含关联信息)
*
* @param page 分页参数
* @param activity 活动信息
* @return 活动信息集合
*/
Page<StglActivityVo> selectVoPage(Page<StglActivityVo> page, @Param("activity") StglActivity activity);
/**
* 查询活动信息详情(包含关联信息)
*
* @param id 活动ID
* @return 活动信息
*/
StglActivityVo selectVoById(Long id);
/**
* 根据创建者查询活动数量
*
* @param createBy 创建者ID
* @return 活动数量
*/
Long countByCreateBy(@Param("createBy") Long createBy);
/**
* 查询社团简单信息(用于选择器)
*
* @return 社团信息列表
*/
List<StglActivityVo> selectClubOptions();
/**
* 查询志愿者队伍简单信息(用于选择器)
*
* @return 志愿者队伍信息列表
*/
List<StglActivityVo> selectVolunteerTeamOptions();
/**
* 复制活动信息
*
* @param sourceId 源活动ID
* @param newActivity 新活动信息
* @return 影响行数
*/
int copyActivity(@Param("sourceId") Long sourceId, @Param("newActivity") StglActivity newActivity);
}
@@ -0,0 +1,43 @@
package org.dromara.stgl.mapper;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.stgl.domain.StglActivityRating;
/**
* 活动评分数据访问层
*
* @author ruoyi
* @date 2025-01-01
*/
public interface StglActivityRatingMapper extends BaseMapperPlus<StglActivityRating, StglActivityRating> {
/**
* 查询用户对指定活动的评分记录
*
* @param activityId 活动ID
* @param userId 用户ID
* @return 评分记录
*/
StglActivityRating selectByActivityIdAndUserId(@Param("activityId") Long activityId,
@Param("userId") Long userId);
/**
* 检查用户是否已对活动评分
*
* @param activityId 活动ID
* @param userId 用户ID
* @return 评分记录数量
*/
Long countByActivityIdAndUserId(@Param("activityId") Long activityId,
@Param("userId") Long userId);
/**
* 查询活动平均评分
*
* @param activityId 活动ID
* @return 平均评分
*/
Double selectAverageRatingByActivityId(@Param("activityId") Long activityId);
}
@@ -0,0 +1,39 @@
package org.dromara.stgl.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.dromara.stgl.domain.StglActivityRegistration;
import org.dromara.stgl.domain.vo.StglActivityRegistrationVo;
import org.dromara.stgl.domain.bo.StglActivityRegistrationBo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 活动报名Mapper接口
*
* @author ruoyi
* @date 2024-12-19
*/
public interface StglActivityRegistrationMapper extends BaseMapperPlus<StglActivityRegistration, StglActivityRegistrationVo> {
/**
* 查询活动报名列表(包含JOIN查询)
*
* @param bo 查询条件
* @return 活动报名列表
*/
List<StglActivityRegistrationVo> selectList(StglActivityRegistrationBo bo);
/**
* 分页查询活动报名列表(包含JOIN查询)
*
* @param page 分页参数
* @param bo 查询条件
* @return 分页结果
*/
IPage<StglActivityRegistrationVo> selectPageList(IPage<StglActivityRegistrationVo> page, @Param("bo") StglActivityRegistrationBo bo);
}
@@ -0,0 +1,16 @@
package org.dromara.stgl.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.dromara.stgl.domain.StglActivityTeamInfo;
import org.dromara.stgl.domain.vo.StglActivityTeamInfoVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 活动团队信息Mapper接口
*
* @author ruoyi
* @date 2024-12-19
*/
public interface StglActivityTeamInfoMapper extends BaseMapperPlus<StglActivityTeamInfo, StglActivityTeamInfoVo> {
}
@@ -3,6 +3,12 @@ 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;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.List;
import java.util.Date;
/**
* 社团信息Mapper接口
@@ -12,4 +18,43 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
*/
public interface StglClubMapper extends BaseMapperPlus<StglClub, StglClubVo> {
/**
* 查询社团详情(包含成员统计)
*
* @param id 社团ID
* @return 社团详情信息
*/
StglClubVo selectClubWithMemberCount(@Param("id") Long id);
/**
* 查询热门社团(按成员数量排序)
*
* @param clubType 社团类型
* @param limit 限制数量
* @return 社团列表
*/
List<StglClubVo> selectPopularClubs(@Param("clubType") String clubType, @Param("limit") Integer limit);
/**
* 分页查询社团列表(包含成员统计)
*
* @param page 分页参数
* @param clubName 社团名称
* @param clubType 社团类型
* @param status 状态
* @param establishDate 成立日期
* @param presidentName 社长姓名
* @param advisorName 指导老师姓名
* @param clubIds 社团ID列表(用于数据权限控制)
* @return 社团分页列表
*/
IPage<StglClubVo> selectClubPageWithMemberCount(IPage<StglClubVo> page,
@Param("clubName") String clubName,
@Param("clubType") String clubType,
@Param("status") Integer status,
@Param("establishDate") Date establishDate,
@Param("presidentName") String presidentName,
@Param("advisorName") String advisorName,
@Param("clubIds") List<Long> clubIds);
}
@@ -0,0 +1,78 @@
package org.dromara.stgl.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.stgl.domain.StglMaterialSubmission;
import org.dromara.stgl.domain.vo.StglMaterialSubmissionVo;
import java.util.List;
/**
* 材料提交记录Mapper接口
*
* @author ruoyi
* @date 2025-01-03
*/
public interface StglMaterialSubmissionMapper extends BaseMapperPlus<StglMaterialSubmission, StglMaterialSubmissionVo> {
/**
* 查询材料提交记录列表(包含关联信息)
*
* @param submission 查询条件
* @return 材料提交记录集合
*/
List<StglMaterialSubmissionVo> selectVoList(@Param("submission") StglMaterialSubmission submission);
/**
* 分页查询材料提交记录列表(包含关联信息)
*
* @param page 分页参数
* @param submission 查询条件
* @return 材料提交记录集合
*/
Page<StglMaterialSubmissionVo> selectVoPage(Page<StglMaterialSubmissionVo> page, @Param("submission") StglMaterialSubmission submission);
/**
* 查询材料提交记录详情(包含关联信息)
*
* @param id 提交记录ID
* @return 材料提交记录信息
*/
StglMaterialSubmissionVo selectVoById(@Param("id") Long id);
/**
* 根据任务ID查询提交记录
*
* @param taskId 任务ID
* @return 提交记录列表
*/
List<StglMaterialSubmissionVo> selectByTaskId(@Param("taskId") Long taskId);
/**
* 查询用户在指定任务的提交记录
*
* @param taskId 任务ID
* @param userId 用户ID
* @return 提交记录
*/
StglMaterialSubmissionVo selectByTaskIdAndUserId(@Param("taskId") Long taskId, @Param("userId") Long userId);
/**
* 查询团队在指定任务的提交记录
*
* @param taskId 任务ID
* @param teamId 团队ID
* @return 提交记录
*/
StglMaterialSubmissionVo selectByTaskIdAndTeamId(@Param("taskId") Long taskId, @Param("teamId") Long teamId);
/**
* 获取任务的提交统计信息
*
* @param taskId 任务ID
* @return 统计信息 Map
*/
java.util.Map<String, Object> getSubmissionStatistics(@Param("taskId") Long taskId);
}
@@ -0,0 +1,79 @@
package org.dromara.stgl.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.stgl.domain.StglMaterialTask;
import org.dromara.stgl.domain.bo.StglMaterialTaskQueryBo;
import org.dromara.stgl.domain.vo.StglMaterialTaskVo;
import java.util.List;
/**
* 材料收集任务Mapper接口
*
* @author ruoyi
* @date 2025-01-03
*/
public interface StglMaterialTaskMapper extends BaseMapperPlus<StglMaterialTask, StglMaterialTaskVo> {
/**
* 查询材料收集任务列表(包含关联信息)
*
* @param queryBo 查询条件
* @return 材料收集任务集合
*/
List<StglMaterialTaskVo> selectVoList(@Param("queryBo") StglMaterialTaskQueryBo queryBo);
/**
* 分页查询材料收集任务列表(包含关联信息)
*
* @param page 分页参数
* @param queryBo 查询条件
* @return 材料收集任务集合
*/
Page<StglMaterialTaskVo> selectVoPage(Page<StglMaterialTaskVo> page, @Param("queryBo") StglMaterialTaskQueryBo queryBo);
/**
* 查询材料收集任务详情(包含关联信息)
*
* @param id 任务ID
* @return 材料收集任务信息
*/
StglMaterialTaskVo selectVoById(@Param("id") Long id);
/**
* 查询用户可上传的材料收集任务
*
* @param userId 用户ID
* @param activityId 活动ID(可选)
* @return 可上传的任务列表
*/
List<StglMaterialTaskVo> selectUploadableTasksByUser(@Param("userId") Long userId, @Param("activityId") Long activityId);
/**
* 更新任务状态
*
* @param id 任务ID
* @param taskStatus 任务状态
* @return 影响行数
*/
int updateTaskStatus(@Param("id") Long id, @Param("taskStatus") Integer taskStatus);
/**
* 更新任务统计信息
*
* @param taskId 任务ID
* @return 影响行数
*/
int updateTaskStatistics(@Param("taskId") Long taskId);
/**
* 查询活动的材料收集任务
*
* @param activityId 活动ID
* @return 任务列表
*/
List<StglMaterialTaskVo> selectTasksByActivityId(@Param("activityId") Long activityId);
}
@@ -2,7 +2,11 @@ package org.dromara.stgl.mapper;
import org.dromara.stgl.domain.StglMember;
import org.dromara.stgl.domain.vo.StglMemberVo;
import org.dromara.stgl.domain.vo.StglClubVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 社团成员Mapper接口
@@ -12,4 +16,72 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
*/
public interface StglMemberMapper extends BaseMapperPlus<StglMember, StglMemberVo> {
/**
* 查询社团成员详情(包含用户信息)
*
* @param id 主键ID
* @return 成员详情
*/
StglMemberVo selectMemberWithUserInfoById(@Param("id") Long id);
/**
* 查询社团成员列表(包含用户信息)
*
* @param memberType 成员类型
* @param relationId 关联ID
* @param studentNo 学号
* @param studentName 学生姓名
* @param roleType 角色类型
* @param status 状态
* @param clubName 社团名称(用于社团成员查询)
* @param teamName 队伍名称(用于志愿者查询)
* @param userId 用户ID(用于权限过滤)
* @return 成员列表
*/
List<StglMemberVo> selectMemberWithUserInfo(@Param("memberType") Integer memberType,
@Param("relationId") Long relationId,
@Param("studentNo") String studentNo,
@Param("studentName") String studentName,
@Param("roleType") Integer roleType,
@Param("status") Integer status,
@Param("clubName") String clubName,
@Param("teamName") String teamName,
@Param("userId") Long userId);
/**
* 检查用户是否已加入某个社团/志愿者队伍
*
* @param memberType 成员类型
* @param relationId 关联ID
* @param userId 用户ID
* @return 是否已加入
*/
Boolean checkMemberExists(@Param("memberType") Integer memberType,
@Param("relationId") Long relationId,
@Param("userId") Long userId);
/**
* 查询用户参与的社团列表
*
* @param userId 用户ID
* @return 社团列表
*/
List<StglClubVo> selectUserClubs(@Param("userId") Long userId);
/**
* 统计社团成员数量
*
* @param clubId 社团ID
* @return 成员数量
*/
Integer countClubMembers(@Param("clubId") Long clubId);
/**
* 查询社团管理员(社长和副社长)
*
* @param clubId 社团ID
* @return 管理员列表
*/
List<StglMemberVo> selectClubAdmins(@Param("clubId") Long clubId);
}
@@ -0,0 +1,79 @@
package org.dromara.stgl.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.stgl.domain.vo.MyActivityVo;
import org.dromara.stgl.domain.vo.MyClubVo;
import org.dromara.stgl.domain.vo.MyRegistrationVo;
import org.dromara.stgl.domain.vo.MyVolunteerTeamVo;
import java.util.List;
/**
* 我的报名数据访问层
*
* @author ruoyi
* @date 2025-01-01
*/
public interface StglMyMapper {
/**
* 查询我参与的社团列表
*
* @param userId 用户ID
* @return 社团列表
*/
List<MyClubVo> selectMyClubs(@Param("userId") Long userId);
/**
* 查询我参与的志愿团队列表
*
* @param userId 用户ID
* @param tenantId 租户ID
* @return 志愿团队列表
*/
List<MyVolunteerTeamVo> selectMyVolunteerTeams(@Param("userId") Long userId, @Param("tenantId") String tenantId);
/**
* 查询我报名的活动列表(带评分状态)
*
* @param userId 用户ID
* @param tenantId 租户ID
* @return 活动列表
*/
List<MyActivityVo> selectMyActivities(@Param("userId") Long userId, @Param("tenantId") String tenantId);
/**
* 分页查询我的报名记录(社团+志愿团队+活动)
*
* @param userId 用户ID
* @param registrationType 报名类型(可选)
* @return 报名记录列表
*/
List<MyRegistrationVo> selectMyRegistrations(@Param("userId") Long userId,
@Param("registrationType") String registrationType);
/**
* 分页查询我的报名记录(社团+志愿团队+活动)
*
* @param page 分页对象
* @param userId 用户ID
* @param registrationType 报名类型(可选)
* @return 分页结果
*/
Page<MyRegistrationVo> selectMyRegistrationsPage(@Param("page") Page<MyRegistrationVo> page,
@Param("userId") Long userId,
@Param("registrationType") String registrationType);
/**
* 查询我的报名记录总数
*
* @param userId 用户ID
* @param registrationType 报名类型(可选)
* @return 记录总数
*/
Long countMyRegistrations(@Param("userId") Long userId,
@Param("registrationType") String registrationType);
}
@@ -0,0 +1,15 @@
package org.dromara.stgl.mapper;
import org.dromara.stgl.domain.StglVolunteerTeam;
import org.dromara.stgl.domain.vo.StglVolunteerTeamVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 志愿者队伍Mapper接口
*
* @author Cursor AI
* @date 2025-01-07
*/
public interface StglVolunteerTeamMapper extends BaseMapperPlus<StglVolunteerTeam, StglVolunteerTeamVo> {
}
@@ -0,0 +1,68 @@
package org.dromara.stgl.service;
import org.dromara.stgl.domain.vo.StglActivityAttendanceVo;
import org.dromara.stgl.domain.bo.StglActivityAttendanceBo;
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 ruoyi
* @date 2025-01-15
*/
public interface IStglActivityAttendanceService {
/**
* 查询活动考勤签到
*/
StglActivityAttendanceVo queryById(Long id);
/**
* 查询活动考勤签到列表
*/
TableDataInfo<StglActivityAttendanceVo> queryPageList(StglActivityAttendanceBo bo, PageQuery pageQuery);
/**
* 查询活动考勤签到列表
*/
List<StglActivityAttendanceVo> queryList(StglActivityAttendanceBo bo);
/**
* 新增活动考勤签到
*/
Boolean insertByBo(StglActivityAttendanceBo bo);
/**
* 修改活动考勤签到
*/
Boolean updateByBo(StglActivityAttendanceBo bo);
/**
* 校验并批量删除活动考勤签到信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 查询用户已报名成功且进行中的活动列表
*/
List<StglActivityAttendanceVo> queryUserAvailableActivities(Long userId);
/**
* 根据活动ID和用户ID查询签到记录
*/
StglActivityAttendanceVo queryByActivityAndUser(Long activityId, Long userId);
/**
* 用户签到
*/
Boolean signIn(StglActivityAttendanceBo bo);
/**
* 用户签退
*/
Boolean signOut(StglActivityAttendanceBo bo);
}
@@ -0,0 +1,90 @@
package org.dromara.stgl.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.stgl.domain.StglActivityRegistration;
import org.dromara.stgl.domain.bo.StglActivityRegistrationBo;
import org.dromara.stgl.domain.vo.StglActivityRegistrationVo;
import java.util.Collection;
import java.util.List;
/**
* 活动报名Service接口
*
* @author ruoyi
* @date 2024-12-19
*/
public interface IStglActivityRegistrationService extends IService<StglActivityRegistration> {
/**
* 查询活动报名
*/
StglActivityRegistrationVo queryById(Long id);
/**
* 查询活动报名列表
*/
TableDataInfo<StglActivityRegistrationVo> queryPageList(StglActivityRegistrationBo bo, PageQuery pageQuery);
/**
* 查询活动报名列表
*/
List<StglActivityRegistrationVo> queryList(StglActivityRegistrationBo bo);
/**
* 新增活动报名
*/
Boolean insertByBo(StglActivityRegistrationBo bo);
/**
* 修改活动报名
*/
Boolean updateByBo(StglActivityRegistrationBo bo);
/**
* 校验并批量删除活动报名信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 审核活动报名
*/
Boolean approvalRegistration(Long id, String approvalStatus, String approvalRemark);
/**
* 录入成绩
*/
Boolean inputScore(Long id, String score);
/**
* 检查用户是否已报名该活动
*/
Boolean checkUserRegistered(Long activityId, Long userId);
/**
* 获取用户在指定活动的报名信息
*/
StglActivityRegistrationVo getUserRegistration(Long activityId, Long userId);
/**
* 活动报名
*/
Boolean register(StglActivityRegistrationBo bo);
/**
* 检查用户是否已报名某活动
*/
Boolean checkUserRegistration(Long activityId, Long userId);
/**
* 获取用户的报名记录
*/
TableDataInfo<StglActivityRegistrationVo> queryUserRegistrations(Long userId, PageQuery pageQuery);
/**
* 批量审核活动报名
*/
Boolean batchApprove(List<Long> ids, Integer approvalStatus, String approvalRemark, Long approvalBy);
}
@@ -0,0 +1,115 @@
package org.dromara.stgl.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.stgl.domain.StglActivity;
import org.dromara.stgl.domain.bo.StglActivityBo;
import org.dromara.stgl.domain.vo.StglActivityVo;
import java.util.Collection;
import java.util.List;
/**
* 活动信息Service接口
*
* @author ruoyi
* @date 2025-01-07
*/
public interface IStglActivityService extends IService<StglActivity> {
/**
* 查询活动信息
*
* @param id 主键
* @return 活动信息
*/
StglActivityVo queryById(Long id);
/**
* 查询活动信息列表
*
* @param bo 活动信息
* @param pageQuery 分页查询条件
* @return 活动信息集合
*/
TableDataInfo<StglActivityVo> queryPageList(StglActivityBo bo, PageQuery pageQuery);
/**
* 查询活动信息列表
*
* @param bo 活动信息
* @return 活动信息集合
*/
List<StglActivityVo> queryList(StglActivityBo bo);
/**
* 查询可报名活动列表(仅显示报名状态为0和1的活动)
*
* @param bo 活动信息
* @param pageQuery 分页查询条件
* @return 活动信息集合
*/
TableDataInfo<StglActivityVo> queryRegistrableActivityList(StglActivityBo bo, PageQuery pageQuery);
/**
* 新增活动信息
*
* @param bo 活动信息
* @return 是否成功
*/
Boolean insertByBo(StglActivityBo bo);
/**
* 修改活动信息
*
* @param bo 活动信息
* @return 是否成功
*/
Boolean updateByBo(StglActivityBo bo);
/**
* 校验并批量删除活动信息
*
* @param ids 主键集合
* @param isValid 是否校验
* @return 是否成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 复制活动信息
*
* @param sourceId 源活动ID
* @param newActivityName 新活动名称
* @return 是否成功
*/
Boolean copyActivity(Long sourceId, String newActivityName);
/**
* 查询社团选择器选项
*
* @return 社团选项列表
*/
List<StglActivityVo> queryClubOptions();
/**
* 查询志愿者队伍选择器选项
*
* @return 志愿者队伍选项列表
*/
List<StglActivityVo> queryVolunteerTeamOptions();
/**
* 活动总结(更新总结报告和成果)
*
* @param id 活动ID
* @param summary 总结报告
* @param achievements 活动成果
* @param summaryAttachments 总结报告附件
* @param achievementsAttachments 活动成果附件
* @return 是否成功
*/
Boolean summarizeActivity(Long id, String summary, String achievements, String summaryAttachments, String achievementsAttachments);
}
@@ -0,0 +1,60 @@
package org.dromara.stgl.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.stgl.domain.StglActivityTeamInfo;
import org.dromara.stgl.domain.bo.StglActivityTeamInfoBo;
import org.dromara.stgl.domain.vo.StglActivityTeamInfoVo;
import java.util.Collection;
import java.util.List;
/**
* 活动团队信息Service接口
*
* @author ruoyi
* @date 2024-12-19
*/
public interface IStglActivityTeamInfoService extends IService<StglActivityTeamInfo> {
/**
* 查询活动团队信息
*/
StglActivityTeamInfoVo queryById(Long id);
/**
* 查询活动团队信息列表
*/
TableDataInfo<StglActivityTeamInfoVo> queryPageList(StglActivityTeamInfoBo bo, PageQuery pageQuery);
/**
* 查询活动团队信息列表
*/
List<StglActivityTeamInfoVo> queryList(StglActivityTeamInfoBo bo);
/**
* 新增活动团队信息
*/
Boolean insertByBo(StglActivityTeamInfoBo bo);
/**
* 修改活动团队信息
*/
Boolean updateByBo(StglActivityTeamInfoBo bo);
/**
* 校验并批量删除活动团队信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据活动ID查询团队列表
*/
List<StglActivityTeamInfoVo> queryByActivityId(Long activityId);
/**
* 创建团队并返回团队ID
*/
Long createTeam(StglActivityTeamInfoBo bo);
}
@@ -46,9 +46,10 @@ public interface IStglClubRegisterService {
*
* @param clubId 社团ID
* @param userId 用户ID
* @param reason 申请理由
* @return 是否报名成功
*/
Boolean registerClub(Long clubId, Long userId);
Boolean registerClub(Long clubId, Long userId, String reason);
/**
* 退出社团
@@ -106,4 +106,39 @@ public interface IStglClubService {
*/
Boolean changeStatus(Long id, Integer status);
/**
* 修复所有已存在社团的成员记录
* 为那些没有对应成员记录的社长和副社长补充成员记录
*
* @return 修复的记录数量
*/
Integer fixExistingClubMemberRecords();
/**
* 检查社团名称是否存在
*
* @param clubName 社团名称
* @param id 社团ID(排除自己)
* @return 是否存在
*/
Boolean checkClubNameExists(String clubName, Long id);
/**
* 验证用户是否为社团社长
*
* @param clubId 社团ID
* @param userId 用户ID
* @return 是否为社长
*/
Boolean isClubPresident(Long clubId, Long userId);
/**
* 社团转让
*
* @param clubId 社团ID
* @param newPresidentUserId 新社长用户ID
* @return 是否转让成功
*/
Boolean transferClub(Long clubId, Long newPresidentUserId);
}
@@ -0,0 +1,134 @@
package org.dromara.stgl.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.stgl.domain.StglMaterialSubmission;
import org.dromara.stgl.domain.bo.StglMaterialSubmissionBo;
import org.dromara.stgl.domain.vo.StglMaterialSubmissionVo;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 材料提交记录Service接口
*
* @author ruoyi
* @date 2025-01-03
*/
public interface IStglMaterialSubmissionService extends IService<StglMaterialSubmission> {
/**
* 查询材料提交记录
*
* @param id 主键
* @return 材料提交记录
*/
StglMaterialSubmissionVo queryById(Long id);
/**
* 查询材料提交记录列表
*
* @param bo 材料提交记录
* @param pageQuery 分页查询条件
* @return 材料提交记录集合
*/
TableDataInfo<StglMaterialSubmissionVo> queryPageList(StglMaterialSubmissionBo bo, PageQuery pageQuery);
/**
* 查询材料提交记录列表
*
* @param bo 材料提交记录
* @return 材料提交记录集合
*/
List<StglMaterialSubmissionVo> queryList(StglMaterialSubmissionBo bo);
/**
* 新增材料提交记录
*
* @param bo 材料提交记录
* @return 结果
*/
Boolean insertByBo(StglMaterialSubmissionBo bo);
/**
* 修改材料提交记录
*
* @param bo 材料提交记录
* @return 结果
*/
Boolean updateByBo(StglMaterialSubmissionBo bo);
/**
* 校验并批量删除材料提交记录信息
*
* @param ids 主键集合
* @param isValid 是否校验,true-删除前校验,false-不校验
* @return 结果
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据任务ID查询提交记录
*
* @param taskId 任务ID
* @return 提交记录列表
*/
List<StglMaterialSubmissionVo> queryByTaskId(Long taskId);
/**
* 查询用户在指定任务的提交记录
*
* @param taskId 任务ID
* @param userId 用户ID
* @return 提交记录
*/
StglMaterialSubmissionVo queryByTaskIdAndUserId(Long taskId, Long userId);
/**
* 查询团队在指定任务的提交记录
*
* @param taskId 任务ID
* @param teamId 团队ID
* @return 提交记录
*/
StglMaterialSubmissionVo queryByTaskIdAndTeamId(Long taskId, Long teamId);
/**
* 获取任务的提交统计信息
*
* @param taskId 任务ID
* @return 统计信息
*/
Map<String, Object> getSubmissionStatistics(Long taskId);
/**
* 材料上传
*
* @param bo 材料提交信息
* @return 结果
*/
Boolean uploadMaterial(StglMaterialSubmissionBo bo);
/**
* 审核材料
*
* @param id 提交记录ID
* @param reviewStatus 审核状态(1-通过 2-驳回)
* @param reviewRemark 审核意见
* @return 结果
*/
Boolean reviewSubmission(Long id, Integer reviewStatus, String reviewRemark);
/**
* 批量审核材料
*
* @param ids 提交记录ID集合
* @param reviewStatus 审核状态(1-通过 2-驳回)
* @param reviewRemark 审核意见
* @return 结果
*/
Boolean batchReviewSubmissions(Collection<Long> ids, Integer reviewStatus, String reviewRemark);
}
@@ -0,0 +1,123 @@
package org.dromara.stgl.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.stgl.domain.StglMaterialTask;
import org.dromara.stgl.domain.bo.StglMaterialTaskBo;
import org.dromara.stgl.domain.bo.StglMaterialTaskQueryBo;
import org.dromara.stgl.domain.vo.StglMaterialTaskVo;
import java.util.Collection;
import java.util.List;
/**
* 材料收集任务Service接口
*
* @author ruoyi
* @date 2025-01-03
*/
public interface IStglMaterialTaskService extends IService<StglMaterialTask> {
/**
* 查询材料收集任务
*
* @param id 主键
* @return 材料收集任务
*/
StglMaterialTaskVo queryById(Long id);
/**
* 查询材料收集任务列表
*
* @param queryBo 查询条件
* @param pageQuery 分页查询条件
* @return 材料收集任务集合
*/
TableDataInfo<StglMaterialTaskVo> queryPageList(StglMaterialTaskQueryBo queryBo, PageQuery pageQuery);
/**
* 查询材料收集任务列表
*
* @param queryBo 查询条件
* @return 材料收集任务集合
*/
List<StglMaterialTaskVo> queryList(StglMaterialTaskQueryBo queryBo);
/**
* 新增材料收集任务
*
* @param bo 材料收集任务
* @return 结果
*/
Boolean insertByBo(StglMaterialTaskBo bo);
/**
* 修改材料收集任务
*
* @param bo 材料收集任务
* @return 结果
*/
Boolean updateByBo(StglMaterialTaskBo bo);
/**
* 校验并批量删除材料收集任务信息
*
* @param ids 主键集合
* @param isValid 是否校验,true-删除前校验,false-不校验
* @return 结果
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 更新任务状态
*
* @param id 任务ID
* @param taskStatus 任务状态(1-开启 0-关闭)
* @return 结果
*/
Boolean updateTaskStatus(Long id, Integer taskStatus);
/**
* 查询用户可上传的材料收集任务
*
* @param userId 用户ID
* @param activityId 活动ID(可选)
* @return 可上传的任务列表
*/
List<StglMaterialTaskVo> queryUploadableTasksByUser(Long userId, Long activityId);
/**
* 更新任务统计信息
*
* @param taskId 任务ID
* @return 结果
*/
Boolean updateTaskStatistics(Long taskId);
/**
* 查询活动的材料收集任务
*
* @param activityId 活动ID
* @return 任务列表
*/
List<StglMaterialTaskVo> queryTasksByActivityId(Long activityId);
/**
* 验证用户是否有权限上传材料
*
* @param taskId 任务ID
* @param userId 用户ID
* @return 验证结果
*/
Boolean validateUploadPermission(Long taskId, Long userId);
/**
* 根据活动名称模糊查询活动列表(用于选择器)
*
* @param activityName 活动名称
* @return 活动列表
*/
List<StglMaterialTaskVo> queryActivityOptions(String activityName);
}
@@ -112,6 +112,15 @@ public interface IStglMemberService {
*/
Boolean updateMemberRole(Long id, Integer roleType);
/**
* 审核成员申请
*
* @param id 成员ID
* @param approved 是否通过(true-通过,false-拒绝)
* @return 是否审核成功
*/
Boolean approveMember(Long id, Boolean approved);
/**
* 退出社团/队伍
*
@@ -120,4 +129,32 @@ public interface IStglMemberService {
*/
Boolean quitMember(Long id);
/**
* 导入成员数据
*
* @param memberList 成员列表
* @param updateSupport 是否支持更新
* @param operName 操作人名称
* @param memberType 成员类型
* @return 导入结果信息
*/
String importMember(List<StglMemberVo> memberList, Boolean updateSupport, String operName, Integer memberType);
/**
* 获取志愿者成员统计信息
*
* @return 统计信息
*/
Object getVolunteerMemberStats();
/**
* 批量分配队伍
*
* @param ids 成员ID列表
* @param relationId 队伍ID
* @param memberType 成员类型
* @return 是否分配成功
*/
Boolean batchAssignTeam(List<Long> ids, Long relationId, Integer memberType);
}
@@ -0,0 +1,68 @@
package org.dromara.stgl.service;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.stgl.domain.bo.ActivityRatingBo;
import org.dromara.stgl.domain.vo.MyActivityVo;
import org.dromara.stgl.domain.vo.MyClubVo;
import org.dromara.stgl.domain.vo.MyRegistrationVo;
import org.dromara.stgl.domain.vo.MyVolunteerTeamVo;
import java.util.List;
/**
* 我的报名服务接口
*
* @author ruoyi
* @date 2025-01-01
*/
public interface IStglMyService {
/**
* 查询我参与的社团列表
*
* @return 社团列表
*/
List<MyClubVo> queryMyClubs();
/**
* 查询我参与的志愿团队列表
*
* @return 志愿团队列表
*/
List<MyVolunteerTeamVo> queryMyVolunteerTeams();
/**
* 查询我报名的活动列表(带评分状态)
*
* @return 活动列表
*/
List<MyActivityVo> queryMyActivities();
/**
* 分页查询我的报名记录
*
* @param pageQuery 分页参数
* @param registrationType 报名类型(可选)
* @return 报名记录分页信息
*/
TableDataInfo<MyRegistrationVo> queryMyRegistrations(PageQuery pageQuery, String registrationType);
/**
* 对活动进行评分
*
* @param activityId 活动ID
* @param ratingBo 评分信息
* @return 是否成功
*/
Boolean rateActivity(Long activityId, ActivityRatingBo ratingBo);
/**
* 检查用户是否可以对活动评分
*
* @param activityId 活动ID
* @return 是否可以评分
*/
Boolean canRateActivity(Long activityId);
}
@@ -0,0 +1,133 @@
package org.dromara.stgl.service;
import org.dromara.stgl.domain.vo.StglVolunteerTeamVo;
import org.dromara.stgl.domain.bo.StglVolunteerTeamBo;
import org.dromara.stgl.domain.bo.StglVolunteerTeamApplicationBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.xg.domain.vo.XgStudentMsgVo;
import org.dromara.system.domain.vo.SysUserVo;
import java.util.Collection;
import java.util.List;
/**
* 志愿者队伍Service接口
*
* @author Cursor AI
* @date 2025-01-07
*/
public interface IStglVolunteerTeamService {
/**
* 查询志愿者队伍
*/
StglVolunteerTeamVo queryById(Long id);
/**
* 查询志愿者队伍列表
*/
TableDataInfo<StglVolunteerTeamVo> queryPageList(StglVolunteerTeamBo bo, PageQuery pageQuery);
/**
* 查询志愿者队伍列表
*/
List<StglVolunteerTeamVo> queryList(StglVolunteerTeamBo bo);
/**
* 新增志愿者队伍
*/
Boolean insertByBo(StglVolunteerTeamBo bo);
/**
* 修改志愿者队伍
*/
Boolean updateByBo(StglVolunteerTeamBo bo);
/**
* 校验并批量删除志愿者队伍信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 查询志愿者队伍可用选项列表
*/
List<StglVolunteerTeamVo> queryAvailableOptions();
/**
* 根据队长用户ID查询队伍
*/
List<StglVolunteerTeamVo> queryByLeaderUserId(Long leaderUserId);
/**
* 根据队伍类型查询队伍列表
*/
List<StglVolunteerTeamVo> queryByTeamType(String teamType);
/**
* 启用/禁用志愿者队伍
*/
Boolean updateStatus(Long id, Integer status);
/**
* 申请加入志愿者队伍
*/
Boolean applyJoinVolunteerTeam(StglVolunteerTeamApplicationBo applicationBo);
/**
* 根据姓名搜索学生信息(用于队长选择)
*/
List<XgStudentMsgVo> searchStudentByName(String name);
/**
* 查询志愿者队伍报名大厅列表(无数据权限限制)
*/
TableDataInfo<StglVolunteerTeamVo> queryRegistrationPageList(StglVolunteerTeamBo bo, PageQuery pageQuery);
/**
* 查询志愿者队伍详情(学生报名大厅专用,包含用户申请状态)
*/
StglVolunteerTeamVo queryRegistrationById(Long id);
/**
* 志愿者队伍转让
*
* @param teamId 队伍ID
* @param newLeaderUserId 新队长用户ID
* @return 是否转让成功
*/
Boolean transferVolunteerTeam(Long teamId, Long newLeaderUserId);
/**
* 检查当前用户是否为志愿者队伍的队长
*
* @param teamId 队伍ID
* @param userId 用户ID
* @return 是否为队长
*/
Boolean isTeamLeader(Long teamId, Long userId);
/**
* 根据学号获取学生详细信息(用于自动填充)
*/
XgStudentMsgVo getStudentByNo(String studentNo);
/**
* 根据姓名搜索指导老师信息
*/
List<SysUserVo> searchTeacherByName(String name);
/**
* 根据用户ID获取教师详细信息(用于自动填充)
*/
SysUserVo getTeacherById(Long userId);
/**
* 修复所有已存在志愿者队伍的队长成员记录
* 为那些没有对应成员记录的队长补充成员记录
*
* @return 修复的记录数量
*/
Integer fixExistingTeamLeaderRecords();
}
@@ -0,0 +1,188 @@
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 org.dromara.common.satoken.utils.LoginHelper;
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.StglActivityAttendanceBo;
import org.dromara.stgl.domain.vo.StglActivityAttendanceVo;
import org.dromara.stgl.domain.StglActivityAttendance;
import org.dromara.stgl.mapper.StglActivityAttendanceMapper;
import org.dromara.stgl.service.IStglActivityAttendanceService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Date;
/**
* 活动考勤签到Service业务层处理
*
* @author ruoyi
* @date 2025-01-15
*/
@RequiredArgsConstructor
@Service
public class StglActivityAttendanceServiceImpl implements IStglActivityAttendanceService {
private final StglActivityAttendanceMapper baseMapper;
/**
* 查询活动考勤签到
*/
@Override
public StglActivityAttendanceVo queryById(Long id){
return baseMapper.selectVoByIdWithActivity(id);
}
/**
* 查询活动考勤签到列表
*/
@Override
public TableDataInfo<StglActivityAttendanceVo> queryPageList(StglActivityAttendanceBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<StglActivityAttendance> lqw = buildQueryWrapper(bo);
Page<StglActivityAttendanceVo> page = pageQuery.build();
List<StglActivityAttendanceVo> list = baseMapper.selectAttendanceList(lqw);
// 手动分页
int startIndex = (int) ((page.getCurrent() - 1) * page.getSize());
int endIndex = Math.min(startIndex + (int) page.getSize(), list.size());
List<StglActivityAttendanceVo> pageList = list.subList(startIndex, endIndex);
page.setRecords(pageList);
page.setTotal(list.size());
return TableDataInfo.build(page);
}
/**
* 查询活动考勤签到列表
*/
@Override
public List<StglActivityAttendanceVo> queryList(StglActivityAttendanceBo bo) {
LambdaQueryWrapper<StglActivityAttendance> lqw = buildQueryWrapper(bo);
return baseMapper.selectAttendanceList(lqw);
}
private LambdaQueryWrapper<StglActivityAttendance> buildQueryWrapper(StglActivityAttendanceBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<StglActivityAttendance> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getActivityId() != null, StglActivityAttendance::getActivityId, bo.getActivityId());
lqw.eq(bo.getUserId() != null, StglActivityAttendance::getUserId, bo.getUserId());
lqw.like(StringUtils.isNotBlank(bo.getStudentName()), StglActivityAttendance::getStudentName, bo.getStudentName());
lqw.eq(StringUtils.isNotBlank(bo.getStudentNo()), StglActivityAttendance::getStudentNo, bo.getStudentNo());
lqw.like(StringUtils.isNotBlank(bo.getDepartment()), StglActivityAttendance::getDepartment, bo.getDepartment());
lqw.like(StringUtils.isNotBlank(bo.getMajor()), StglActivityAttendance::getMajor, bo.getMajor());
lqw.like(StringUtils.isNotBlank(bo.getClassName()), StglActivityAttendance::getClassName, bo.getClassName());
lqw.eq(bo.getOverallStatus() != null, StglActivityAttendance::getOverallStatus, bo.getOverallStatus());
return lqw;
}
/**
* 新增活动考勤签到
*/
@Override
public Boolean insertByBo(StglActivityAttendanceBo bo) {
StglActivityAttendance add = MapstructUtils.convert(bo, StglActivityAttendance.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改活动考勤签到
*/
@Override
public Boolean updateByBo(StglActivityAttendanceBo bo) {
StglActivityAttendance update = MapstructUtils.convert(bo, StglActivityAttendance.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(StglActivityAttendance entity){
// 校验逻辑可以在此处添加
}
/**
* 批量删除活动考勤签到
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
// 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 查询用户已报名成功且进行中的活动列表
*/
@Override
public List<StglActivityAttendanceVo> queryUserAvailableActivities(Long userId) {
return baseMapper.selectUserAvailableActivities(userId);
}
/**
* 根据活动ID和用户ID查询签到记录
*/
@Override
public StglActivityAttendanceVo queryByActivityAndUser(Long activityId, Long userId) {
return baseMapper.selectByActivityAndUser(activityId, userId);
}
/**
* 用户签到
*/
@Override
public Boolean signIn(StglActivityAttendanceBo bo) {
// 检查是否已存在签到记录
StglActivityAttendanceVo existingRecord = queryByActivityAndUser(bo.getActivityId(), bo.getUserId());
if (existingRecord != null) {
// 如果已存在记录,更新签到信息
bo.setId(existingRecord.getId());
bo.setSignInTime(new Date());
bo.setSignInStatus(1);
bo.setOverallStatus(1); // 已签到
return updateByBo(bo);
} else {
// 如果不存在记录,新增签到记录
bo.setSignInTime(new Date());
bo.setSignInStatus(1);
bo.setSignOutStatus(0);
bo.setOverallStatus(1); // 已签到
return insertByBo(bo);
}
}
/**
* 用户签退
*/
@Override
public Boolean signOut(StglActivityAttendanceBo bo) {
// 必须先签到才能签退
StglActivityAttendanceVo existingRecord = queryByActivityAndUser(bo.getActivityId(), bo.getUserId());
if (existingRecord == null || existingRecord.getSignInStatus() != 1) {
throw new RuntimeException("请先完成签到");
}
// 更新签退信息
bo.setId(existingRecord.getId());
bo.setSignOutTime(new Date());
bo.setSignOutStatus(1);
bo.setOverallStatus(2); // 已签退
return updateByBo(bo);
}
}
@@ -0,0 +1,264 @@
package org.dromara.stgl.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.stgl.domain.StglActivityRegistration;
import org.dromara.stgl.domain.StglActivityTeamInfo;
import org.dromara.stgl.domain.bo.StglActivityRegistrationBo;
import org.dromara.stgl.domain.bo.StglActivityTeamInfoBo;
import org.dromara.stgl.domain.vo.StglActivityRegistrationVo;
import org.dromara.stgl.mapper.StglActivityRegistrationMapper;
import org.dromara.stgl.service.IStglActivityRegistrationService;
import org.dromara.stgl.service.IStglActivityTeamInfoService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
* 活动报名Service业务层处理
*
* @author ruoyi
* @date 2024-12-19
*/
@RequiredArgsConstructor
@Service
public class StglActivityRegistrationServiceImpl extends ServiceImpl<StglActivityRegistrationMapper, StglActivityRegistration> implements IStglActivityRegistrationService {
private final StglActivityRegistrationMapper baseMapper;
private final IStglActivityTeamInfoService teamInfoService;
/**
* 查询活动报名
*/
@Override
public StglActivityRegistrationVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询活动报名列表
*/
@Override
public TableDataInfo<StglActivityRegistrationVo> queryPageList(StglActivityRegistrationBo bo, PageQuery pageQuery) {
// 使用XML中的JOIN查询,确保获取完整数据(活动名称、审核人姓名、评分人姓名)
Page<StglActivityRegistrationVo> page = pageQuery.build();
IPage<StglActivityRegistrationVo> result = baseMapper.selectPageList(page, bo);
return TableDataInfo.build(result);
}
/**
* 查询活动报名列表
*/
@Override
public List<StglActivityRegistrationVo> queryList(StglActivityRegistrationBo bo) {
// 使用XML中的JOIN查询,确保获取完整数据(活动名称、审核人姓名、评分人姓名)
return baseMapper.selectList(bo);
}
/**
* 新增活动报名
*/
@Override
public Boolean insertByBo(StglActivityRegistrationBo bo) {
StglActivityRegistration add = MapstructUtils.convert(bo, StglActivityRegistration.class);
// 设置报名时间为当前时间
if (add.getRegistrationTime() == null) {
add.setRegistrationTime(new Date());
}
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改活动报名
*/
@Override
public Boolean updateByBo(StglActivityRegistrationBo bo) {
StglActivityRegistration update = MapstructUtils.convert(bo, StglActivityRegistration.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(StglActivityRegistration entity) {
// TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除活动报名
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 审核活动报名
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean approvalRegistration(Long id, String approvalStatus, String approvalRemark) {
StglActivityRegistrationVo vo = baseMapper.selectVoById(id);
if (vo == null) {
return false;
}
StglActivityRegistration registration = new StglActivityRegistration();
registration.setId(id);
registration.setApprovalStatus(approvalStatus);
registration.setApprovalRemark(approvalRemark);
registration.setApprovalTime(new Date());
registration.setApprovalBy(LoginHelper.getUserId());
return baseMapper.updateById(registration) > 0;
}
/**
* 录入成绩
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean inputScore(Long id, String score) {
StglActivityRegistrationVo vo = baseMapper.selectVoById(id);
if (vo == null) {
return false;
}
StglActivityRegistration registration = new StglActivityRegistration();
registration.setId(id);
registration.setScore(score);
registration.setScoreTime(new Date());
registration.setScoreBy(LoginHelper.getUserId());
return baseMapper.updateById(registration) > 0;
}
/**
* 检查用户是否已报名该活动
*/
@Override
public Boolean checkUserRegistered(Long activityId, Long userId) {
LambdaQueryWrapper<StglActivityRegistration> lqw = Wrappers.lambdaQuery();
lqw.eq(StglActivityRegistration::getActivityId, activityId);
lqw.eq(StglActivityRegistration::getUserId, userId);
return baseMapper.selectCount(lqw) > 0;
}
/**
* 获取用户在指定活动的报名信息
*/
@Override
public StglActivityRegistrationVo getUserRegistration(Long activityId, Long userId) {
LambdaQueryWrapper<StglActivityRegistration> lqw = Wrappers.lambdaQuery();
lqw.eq(StglActivityRegistration::getActivityId, activityId);
lqw.eq(StglActivityRegistration::getUserId, userId);
return baseMapper.selectVoOne(lqw);
}
/**
* 活动报名
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean register(StglActivityRegistrationBo bo) {
// 检查是否已报名
if (checkUserRegistered(bo.getActivityId(), bo.getUserId())) {
throw new RuntimeException("您已报名该活动,请勿重复报名");
}
// 设置报名时间和状态
bo.setRegistrationTime(new Date());
bo.setApprovalStatus("0"); // 待审核
// 如果是团队报名,需要先创建团队信息
if ("2".equals(bo.getRegistrationType()) && bo.getTeamId() == null) {
// 创建团队信息
StglActivityTeamInfoBo teamBo = new StglActivityTeamInfoBo();
teamBo.setTeamName(bo.getTeamName());
teamBo.setActivityId(bo.getActivityId());
teamBo.setLeaderUserId(bo.getUserId());
teamBo.setLeaderName(bo.getStudentName());
teamBo.setLeaderStudentNo(bo.getStudentNo());
// 设置团队成员信息和描述
if (StringUtils.isNotBlank(bo.getTeamMembers())) {
teamBo.setTeamMembers(bo.getTeamMembers());
}
if (StringUtils.isNotBlank(bo.getTeamDescription())) {
teamBo.setDescription(bo.getTeamDescription());
}
Long teamId = teamInfoService.createTeam(teamBo);
bo.setTeamId(teamId);
}
return insertByBo(bo);
}
/**
* 检查用户是否已报名某活动
*/
@Override
public Boolean checkUserRegistration(Long activityId, Long userId) {
LambdaQueryWrapper<StglActivityRegistration> lqw = Wrappers.lambdaQuery();
lqw.eq(StglActivityRegistration::getActivityId, activityId)
.eq(StglActivityRegistration::getUserId, userId);
return baseMapper.exists(lqw);
}
/**
* 获取用户的报名记录
*/
@Override
public TableDataInfo<StglActivityRegistrationVo> queryUserRegistrations(Long userId, PageQuery pageQuery) {
LambdaQueryWrapper<StglActivityRegistration> lqw = Wrappers.lambdaQuery();
lqw.eq(StglActivityRegistration::getUserId, userId)
.orderByDesc(StglActivityRegistration::getCreateTime);
Page<StglActivityRegistrationVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 批量审核活动报名
*/
@Override
public Boolean batchApprove(List<Long> ids, Integer approvalStatus, String approvalRemark, Long approvalBy) {
List<StglActivityRegistration> updateList = new ArrayList<>();
for (Long id : ids) {
StglActivityRegistration registration = new StglActivityRegistration();
registration.setId(id);
registration.setApprovalStatus(approvalStatus.toString());
registration.setApprovalRemark(approvalRemark);
registration.setApprovalBy(approvalBy);
registration.setApprovalTime(new Date());
updateList.add(registration);
}
return updateBatchById(updateList);
}
}
@@ -0,0 +1,385 @@
package org.dromara.stgl.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.stgl.domain.StglActivity;
import org.dromara.stgl.domain.bo.StglActivityBo;
import org.dromara.stgl.domain.vo.StglActivityVo;
import org.dromara.stgl.mapper.StglActivityMapper;
import org.dromara.stgl.service.IStglActivityService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 活动信息Service业务层处理
*
* @author ruoyi
* @date 2025-01-07
*/
@RequiredArgsConstructor
@Service
public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, StglActivity> implements IStglActivityService {
private final StglActivityMapper baseMapper;
/**
* 查询活动信息
*/
@Override
public StglActivityVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询活动信息列表
*/
@Override
public TableDataInfo<StglActivityVo> queryPageList(StglActivityBo bo, PageQuery pageQuery) {
// 转换为实体对象,使用自定义SQL查询(包含关联信息)
StglActivity activity = BeanUtil.toBean(bo, StglActivity.class);
Page<StglActivityVo> result = baseMapper.selectVoPage(pageQuery.build(), activity);
return TableDataInfo.build(result);
}
/**
* 查询活动信息列表
*/
@Override
public List<StglActivityVo> queryList(StglActivityBo bo) {
// 转换为实体对象,使用自定义SQL查询(包含关联信息)
StglActivity activity = BeanUtil.toBean(bo, StglActivity.class);
List<StglActivityVo> list = baseMapper.selectVoList(activity);
// 处理导出专用的格式化字段
AtomicInteger sequenceCounter = new AtomicInteger(1);
list.forEach(item -> {
// 设置序号
item.setSequenceNumber(sequenceCounter.getAndIncrement());
// 格式化承办方信息显示
item.setCoOrganizersDisplay(formatCoOrganizersForExcel(item.getCoOrganizers()));
// 格式化指导老师显示
item.setInstructorsDisplay(formatInstructorsForExcel(item.getInstructors()));
});
return list;
}
/**
* 查询可报名活动列表(仅显示报名状态为0和1的活动)
*/
@Override
public TableDataInfo<StglActivityVo> queryRegistrableActivityList(StglActivityBo bo, PageQuery pageQuery) {
// 转换为实体对象
StglActivity activity = BeanUtil.toBean(bo, StglActivity.class);
// 设置查询条件:只查询报名状态为0(未开始)和1(报名中)的活动
// 通过设置params参数来传递IN查询条件
Map<String, Object> params = new HashMap<>();
params.put("registrationStatusList", Arrays.asList("0", "1"));
activity.setParams(params);
// 使用XML中定义的复杂查询方法,包含关联查询获取related_club_name等字段
Page<StglActivityVo> result = baseMapper.selectVoPage(pageQuery.build(), activity);
return TableDataInfo.build(result);
}
/**
* 格式化承办方信息用于Excel显示
* 格式:承办方名称:xxx,联系人:xxx,联系电话:xxx(多个承办方换行显示)
*/
private String formatCoOrganizersForExcel(String coOrganizers) {
if (StringUtils.isBlank(coOrganizers)) {
return "";
}
try {
JSONArray coOrganizerArray = JSONUtil.parseArray(coOrganizers);
StringBuilder result = new StringBuilder();
for (int i = 0; i < coOrganizerArray.size(); i++) {
JSONObject coOrganizer = coOrganizerArray.getJSONObject(i);
if (i > 0) {
result.append("\n"); // 多个承办方换行显示
}
String name = coOrganizer.getStr("name", "");
String contact = coOrganizer.getStr("contact", "");
String phone = coOrganizer.getStr("phone", "");
result.append("承办方名称:").append(name)
.append(",联系人:").append(contact)
.append(",联系电话:").append(phone);
}
return result.toString();
} catch (Exception e) {
return coOrganizers; // 解析失败时返回原始数据
}
}
/**
* 格式化指导老师信息用于Excel显示
* 格式:只显示姓名,多个用逗号分隔
*/
private String formatInstructorsForExcel(String instructors) {
if (StringUtils.isBlank(instructors)) {
return "";
}
try {
JSONArray instructorArray = JSONUtil.parseArray(instructors);
StringBuilder result = new StringBuilder();
for (int i = 0; i < instructorArray.size(); i++) {
JSONObject instructor = instructorArray.getJSONObject(i);
if (i > 0) {
result.append(","); // 多个指导老师用逗号分隔
}
String name = instructor.getStr("name", "");
if (StringUtils.isNotBlank(name)) {
result.append(name);
}
}
return result.toString();
} catch (Exception e) {
return instructors; // 解析失败时返回原始数据
}
}
private LambdaQueryWrapper<StglActivity> buildQueryWrapper(StglActivityBo bo) {
LambdaQueryWrapper<StglActivity> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getActivityName()), StglActivity::getActivityName, bo.getActivityName());
lqw.eq(StringUtils.isNotBlank(bo.getActivityType()), StglActivity::getActivityType, bo.getActivityType());
lqw.like(StringUtils.isNotBlank(bo.getActivityTheme()), StglActivity::getActivityTheme, bo.getActivityTheme());
lqw.ge(ObjectUtil.isNotNull(bo.getStartTime()), StglActivity::getStartTime, bo.getStartTime());
lqw.le(ObjectUtil.isNotNull(bo.getEndTime()), StglActivity::getEndTime, bo.getEndTime());
lqw.like(StringUtils.isNotBlank(bo.getLocation()), StglActivity::getLocation, bo.getLocation());
lqw.eq(ObjectUtil.isNotNull(bo.getRelatedClubId()), StglActivity::getRelatedClubId, bo.getRelatedClubId());
lqw.like(StringUtils.isNotBlank(bo.getOrganizerName()), StglActivity::getOrganizerName, bo.getOrganizerName());
lqw.eq(ObjectUtil.isNotNull(bo.getRegistrationType()), StglActivity::getRegistrationType, bo.getRegistrationType());
lqw.ge(ObjectUtil.isNotNull(bo.getRegistrationStart()), StglActivity::getRegistrationStart, bo.getRegistrationStart());
lqw.le(ObjectUtil.isNotNull(bo.getRegistrationEnd()), StglActivity::getRegistrationEnd, bo.getRegistrationEnd());
lqw.eq(ObjectUtil.isNotNull(bo.getRegistrationStatus()), StglActivity::getRegistrationStatus, bo.getRegistrationStatus());
lqw.eq(StringUtils.isNotBlank(bo.getActivityStatus()), StglActivity::getActivityStatus, bo.getActivityStatus());
lqw.eq(ObjectUtil.isNotNull(bo.getIsFinished()), StglActivity::getIsFinished, bo.getIsFinished());
lqw.orderByDesc(StglActivity::getCreateTime);
return lqw;
}
/**
* 新增活动信息
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(StglActivityBo bo) {
StglActivity add = MapstructUtils.convert(bo, StglActivity.class);
validEntityBeforeSave(add);
// 设置默认值
if (add.getIsFinished() == null) {
add.setIsFinished(0);
}
if (add.getNeedApproval() == null) {
add.setNeedApproval(0);
}
if (add.getRegistrationStatus() == null) {
add.setRegistrationStatus(0);
}
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改活动信息
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(StglActivityBo bo) {
StglActivity update = MapstructUtils.convert(bo, StglActivity.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(StglActivity entity) {
// 校验活动名称唯一性
if (StringUtils.isNotBlank(entity.getActivityName())) {
LambdaQueryWrapper<StglActivity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(StglActivity::getActivityName, entity.getActivityName());
if (entity.getId() != null) {
wrapper.ne(StglActivity::getId, entity.getId());
}
boolean exists = baseMapper.exists(wrapper);
if (exists) {
throw new RuntimeException("活动名称已存在");
}
}
// 校验时间逻辑
if (entity.getStartTime() != null && entity.getEndTime() != null) {
if (entity.getStartTime().after(entity.getEndTime())) {
throw new RuntimeException("活动开始时间不能晚于结束时间");
}
}
if (entity.getRegistrationStart() != null && entity.getRegistrationEnd() != null) {
if (entity.getRegistrationStart().after(entity.getRegistrationEnd())) {
throw new RuntimeException("报名开始时间不能晚于报名结束时间");
}
}
// 校验报名人数设置
if (entity.getRegistrationType() != null) {
if (entity.getRegistrationType() == 1 && entity.getMaxParticipants() != null && entity.getMaxParticipants() <= 0) {
throw new RuntimeException("个人报名时总人数上限必须大于0");
}
if (entity.getRegistrationType() == 2) {
if (entity.getMaxTeams() != null && entity.getMaxTeams() <= 0) {
throw new RuntimeException("团队报名时团队数量上限必须大于0");
}
if (entity.getTeamSizeMin() != null && entity.getTeamSizeMax() != null && entity.getTeamSizeMin() > entity.getTeamSizeMax()) {
throw new RuntimeException("每队最小人数不能大于最大人数");
}
}
}
}
/**
* 批量删除活动信息
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 校验是否存在关联数据
for (Long id : ids) {
StglActivityVo activity = queryById(id);
if (activity != null && activity.getRegistrationCount() != null && activity.getRegistrationCount() > 0) {
throw new RuntimeException("活动【" + activity.getActivityName() + "】已有用户报名,不允许删除");
}
}
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 复制活动信息
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean copyActivity(Long sourceId, String newActivityName) {
StglActivityVo sourceActivity = queryById(sourceId);
if (sourceActivity == null) {
throw new RuntimeException("源活动不存在");
}
// 校验新活动名称唯一性
LambdaQueryWrapper<StglActivity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(StglActivity::getActivityName, newActivityName);
boolean exists = baseMapper.exists(wrapper);
if (exists) {
throw new RuntimeException("活动名称已存在");
}
// 获取当前时间
Date now = new Date();
// 先从源活动复制所有数据到新活动对象
StglActivity newActivityEntity = BeanUtil.copyProperties(sourceActivity, StglActivity.class);
// 重置ID和基础字段,让MyBatis-Plus自动生成新的ID
newActivityEntity.setId(null); // 设置为null,让MyBatis-Plus自动生成雪花ID
newActivityEntity.setTenantId(LoginHelper.getTenantId()); // 设置租户ID
newActivityEntity.setCreateDept(LoginHelper.getDeptId()); // 设置创建部门
newActivityEntity.setCreateBy(LoginHelper.getUserId()); // 设置创建者
newActivityEntity.setUpdateBy(LoginHelper.getUserId()); // 设置更新者
newActivityEntity.setCreateTime(now); // 设置创建时间
newActivityEntity.setUpdateTime(now); // 设置更新时间
// 设置业务字段
newActivityEntity.setActivityName(newActivityName);
newActivityEntity.setActivityStatus("1"); // 默认筹备中
newActivityEntity.setRegistrationStatus(0); // 默认未开始
newActivityEntity.setIsFinished(0); // 设置为未完成
newActivityEntity.setSummary(null); // 清空总结
newActivityEntity.setAchievements(null); // 清空成果
// 设置时间为当前时间的基础上延后
newActivityEntity.setStartTime(new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000L)); // 7天后
newActivityEntity.setEndTime(new Date(now.getTime() + 8 * 24 * 60 * 60 * 1000L)); // 8天后
newActivityEntity.setRegistrationStart(now);
newActivityEntity.setRegistrationEnd(new Date(now.getTime() + 6 * 24 * 60 * 60 * 1000L)); // 6天后
// 使用MyBatis-Plus标准insert方法,自动生成雪花ID
boolean result = save(newActivityEntity);
return result;
}
/**
* 查询社团选择器选项
*/
@Override
public List<StglActivityVo> queryClubOptions() {
return baseMapper.selectClubOptions();
}
/**
* 查询志愿者队伍选择器选项
*/
@Override
public List<StglActivityVo> queryVolunteerTeamOptions() {
return baseMapper.selectVolunteerTeamOptions();
}
/**
* 活动总结
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean summarizeActivity(Long id, String summary, String achievements, String summaryAttachments, String achievementsAttachments) {
LambdaUpdateWrapper<StglActivity> wrapper = Wrappers.lambdaUpdate();
wrapper.eq(StglActivity::getId, id);
wrapper.set(StglActivity::getSummary, summary);
wrapper.set(StglActivity::getAchievements, achievements);
wrapper.set(StglActivity::getSummaryAttachments, summaryAttachments);
wrapper.set(StglActivity::getAchievementsAttachments, achievementsAttachments);
wrapper.set(StglActivity::getIsFinished, 1); // 标记为已办活动
wrapper.set(StglActivity::getUpdateTime, new Date());
wrapper.set(StglActivity::getUpdateBy, LoginHelper.getUserId());
return baseMapper.update(null, wrapper) > 0;
}
}
@@ -0,0 +1,140 @@
package org.dromara.stgl.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.stgl.domain.StglActivityTeamInfo;
import org.dromara.stgl.domain.bo.StglActivityTeamInfoBo;
import org.dromara.stgl.domain.vo.StglActivityTeamInfoVo;
import org.dromara.stgl.mapper.StglActivityTeamInfoMapper;
import org.dromara.stgl.service.IStglActivityTeamInfoService;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
/**
* 活动团队信息Service业务层处理
*
* @author ruoyi
* @date 2024-12-19
*/
@RequiredArgsConstructor
@Service
public class StglActivityTeamInfoServiceImpl extends ServiceImpl<StglActivityTeamInfoMapper, StglActivityTeamInfo> implements IStglActivityTeamInfoService {
private final StglActivityTeamInfoMapper baseMapper;
/**
* 查询活动团队信息
*/
@Override
public StglActivityTeamInfoVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询活动团队信息列表
*/
@Override
public TableDataInfo<StglActivityTeamInfoVo> queryPageList(StglActivityTeamInfoBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<StglActivityTeamInfo> lqw = buildQueryWrapper(bo);
Page<StglActivityTeamInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询活动团队信息列表
*/
@Override
public List<StglActivityTeamInfoVo> queryList(StglActivityTeamInfoBo bo) {
LambdaQueryWrapper<StglActivityTeamInfo> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<StglActivityTeamInfo> buildQueryWrapper(StglActivityTeamInfoBo bo) {
LambdaQueryWrapper<StglActivityTeamInfo> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getTeamName()), StglActivityTeamInfo::getTeamName, bo.getTeamName());
lqw.eq(bo.getActivityId() != null, StglActivityTeamInfo::getActivityId, bo.getActivityId());
lqw.eq(bo.getLeaderUserId() != null, StglActivityTeamInfo::getLeaderUserId, bo.getLeaderUserId());
lqw.like(StringUtils.isNotBlank(bo.getLeaderName()), StglActivityTeamInfo::getLeaderName, bo.getLeaderName());
lqw.like(StringUtils.isNotBlank(bo.getLeaderStudentNo()), StglActivityTeamInfo::getLeaderStudentNo, bo.getLeaderStudentNo());
lqw.orderByDesc(StglActivityTeamInfo::getCreateTime);
return lqw;
}
/**
* 新增活动团队信息
*/
@Override
public Boolean insertByBo(StglActivityTeamInfoBo bo) {
StglActivityTeamInfo add = MapstructUtils.convert(bo, StglActivityTeamInfo.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改活动团队信息
*/
@Override
public Boolean updateByBo(StglActivityTeamInfoBo bo) {
StglActivityTeamInfo update = MapstructUtils.convert(bo, StglActivityTeamInfo.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(StglActivityTeamInfo entity) {
// TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除活动团队信息
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 根据活动ID查询团队列表
*/
@Override
public List<StglActivityTeamInfoVo> queryByActivityId(Long activityId) {
LambdaQueryWrapper<StglActivityTeamInfo> lqw = Wrappers.lambdaQuery();
lqw.eq(StglActivityTeamInfo::getActivityId, activityId);
lqw.orderByDesc(StglActivityTeamInfo::getCreateTime);
return baseMapper.selectVoList(lqw);
}
/**
* 创建团队并返回团队ID
*/
@Override
public Long createTeam(StglActivityTeamInfoBo bo) {
StglActivityTeamInfo teamInfo = MapstructUtils.convert(bo, StglActivityTeamInfo.class);
// 设置初始团队人数为1(队长)
teamInfo.setTeamSize(1);
validEntityBeforeSave(teamInfo);
if (baseMapper.insert(teamInfo) > 0) {
return teamInfo.getId();
}
return null;
}
}
@@ -16,6 +16,11 @@ 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 org.dromara.stgl.domain.vo.StglClubVo;
import org.dromara.system.domain.SysUser;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.xg.domain.XgStudentMsg;
import org.dromara.xg.mapper.XgStudentMsgMapper;
import java.util.List;
import java.util.Date;
@@ -33,6 +38,8 @@ public class StglClubRegisterServiceImpl implements IStglClubRegisterService {
private final StglClubMapper clubMapper;
private final StglMemberMapper memberMapper;
private final SysUserMapper sysUserMapper;
private final XgStudentMsgMapper xgStudentMsgMapper;
/**
* 分页查询社团报名大厅列表
@@ -71,7 +78,7 @@ public class StglClubRegisterServiceImpl implements IStglClubRegisterService {
private LambdaQueryWrapper<StglClub> buildQueryWrapper(String clubType, String clubName) {
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
lqw.eq(StglClub::getStatus, 1); // 只查询正常状态的社团
lqw.eq(StglClub::getStatus, 0); // 只查询正常状态的社团(0-正常,1-停用)
lqw.eq(StringUtils.isNotBlank(clubType), StglClub::getClubType, clubType);
lqw.like(StringUtils.isNotBlank(clubName), StglClub::getClubName, clubName);
lqw.orderByDesc(StglClub::getCreateTime);
@@ -105,32 +112,59 @@ public class StglClubRegisterServiceImpl implements IStglClubRegisterService {
vo.setRecruitTime(club.getRecruitTime());
vo.setActivityFrequency(club.getActivityFrequency());
// 查询当前成员数量
LambdaQueryWrapper<StglMember> memberCountLqw = Wrappers.lambdaQuery();
memberCountLqw.eq(StglMember::getMemberType, 1);
memberCountLqw.eq(StglMember::getRelationId, club.getId());
memberCountLqw.eq(StglMember::getStatus, 1);
long memberCount = memberMapper.selectCount(memberCountLqw);
vo.setCurrentMemberCount((int) memberCount);
// 检查是否可报名
boolean canRegister = club.getMemberLimit() == null || club.getMemberLimit() == 0 || memberCount < club.getMemberLimit();
vo.setCanRegister(canRegister);
// 检查当前用户是否已报名
if (userId != null) {
LambdaQueryWrapper<StglMember> userMemberLqw = Wrappers.lambdaQuery();
userMemberLqw.eq(StglMember::getMemberType, 1);
userMemberLqw.eq(StglMember::getRelationId, club.getId());
userMemberLqw.eq(StglMember::getUserId, userId);
userMemberLqw.eq(StglMember::getStatus, 1);
long registeredCount = memberMapper.selectCount(userMemberLqw);
vo.setHasRegistered(registeredCount > 0);
vo.setRegistrationStatus(registeredCount > 0 ? 1 : 0);
} else {
vo.setHasRegistered(false);
vo.setRegistrationStatus(0);
}
// ========== 新增:副社长信息 ==========
vo.setVicePresidentName(club.getVicePresidentName());
vo.setVicePresidentStudentNo(club.getVicePresidentStudentNo());
vo.setVicePresidentDept(club.getVicePresidentDept());
vo.setVicePresidentMajor(club.getVicePresidentMajor());
vo.setVicePresidentClass(club.getVicePresidentClass());
vo.setVicePresidentPhone(club.getVicePresidentPhone());
vo.setVicePresidentsJson(club.getVicePresidentsJson());
// ========== 新增:其他完善字段 ==========
vo.setPhone(club.getPhone());
vo.setEmail(club.getEmail());
vo.setPresidentStudentNo(club.getPresidentStudentNo());
vo.setPresidentMajor(club.getPresidentMajor());
vo.setPresidentClass(club.getPresidentClass());
vo.setPresidentPhone(club.getPresidentPhone());
vo.setAdvisorPhone(club.getAdvisorPhone());
vo.setAdvisorEmail(club.getAdvisorEmail());
vo.setAdvisorsJson(club.getAdvisorsJson()); // 🔥 新增:指导老师JSON数据
vo.setFundingSources(club.getFundingSources());
vo.setDepartments(club.getDepartments());
// ========== 新增:章程文件和备注信息 ==========
vo.setCharterUrl(club.getCharterUrl());
vo.setRemark(club.getRemark());
// 查询社团成员数量(所有已加入的成员)
LambdaQueryWrapper<StglMember> memberCountLqw = Wrappers.lambdaQuery();
memberCountLqw.eq(StglMember::getMemberType, 1); // 社团成员类型
memberCountLqw.eq(StglMember::getRelationId, club.getId()); // 该社团ID
memberCountLqw.eq(StglMember::getStatus, 2); // 只统计已加入的成员(status=2)
long memberCount = memberMapper.selectCount(memberCountLqw);
vo.setCurrentMemberCount((int) memberCount);
vo.setMemberCount((int) memberCount); // 设置前端兼容字段
// 检查是否可报名
boolean canRegister = club.getMemberLimit() == null || club.getMemberLimit() == 0 || memberCount < club.getMemberLimit();
vo.setCanRegister(canRegister);
// 检查当前用户是否已报名
if (userId != null) {
LambdaQueryWrapper<StglMember> userMemberLqw = Wrappers.lambdaQuery();
userMemberLqw.eq(StglMember::getMemberType, 1);
userMemberLqw.eq(StglMember::getRelationId, club.getId());
userMemberLqw.eq(StglMember::getUserId, userId);
userMemberLqw.eq(StglMember::getStatus, 1);
long registeredCount = memberMapper.selectCount(userMemberLqw);
vo.setHasRegistered(registeredCount > 0);
vo.setRegistrationStatus(registeredCount > 0 ? 1 : 0);
} else {
vo.setHasRegistered(false);
vo.setRegistrationStatus(0);
}
return vo;
}).collect(Collectors.toList());
@@ -156,48 +190,63 @@ public class StglClubRegisterServiceImpl implements IStglClubRegisterService {
*
* @param clubId 社团ID
* @param userId 用户ID
* @param reason 申请理由
* @return 是否报名成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean registerClub(Long clubId, Long userId) {
public Boolean registerClub(Long clubId, Long userId, String reason) {
// 检查社团是否存在
StglClub club = clubMapper.selectById(clubId);
if (club == null || club.getStatus() != 1) {
if (club == null || club.getStatus() != 0) {
throw new RuntimeException("社团不存在或已停用");
}
// 检查是否已是成员
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
lqw.eq(StglMember::getMemberType, 1);
lqw.eq(StglMember::getRelationId, clubId);
lqw.eq(StglMember::getUserId, userId);
lqw.eq(StglMember::getStatus, 1);
long count = memberMapper.selectCount(lqw);
if (count > 0) {
Boolean isExists = memberMapper.checkMemberExists(1, clubId, userId);
if (isExists) {
throw new RuntimeException("您已是该社团的成员");
}
// 检查成员上限
if (club.getMemberLimit() != null && club.getMemberLimit() > 0) {
LambdaQueryWrapper<StglMember> memberLqw = Wrappers.lambdaQuery();
memberLqw.eq(StglMember::getMemberType, 1);
memberLqw.eq(StglMember::getRelationId, clubId);
memberLqw.eq(StglMember::getStatus, 1);
long memberCount = memberMapper.selectCount(memberLqw);
Integer memberCount = memberMapper.countClubMembers(clubId);
if (memberCount >= club.getMemberLimit()) {
throw new RuntimeException("该社团成员已满,无法加入");
}
}
// 查询用户信息获取学号
SysUser user = sysUserMapper.selectById(userId);
if (user == null) {
throw new RuntimeException("用户信息不存在");
}
String studentNo = user.getUserName(); // 学号即用户名
String studentName = null;
// 根据学号查询学生详细信息
if (StringUtils.isNotEmpty(studentNo)) {
LambdaQueryWrapper<XgStudentMsg> studentWrapper = Wrappers.<XgStudentMsg>lambdaQuery();
studentWrapper.eq(XgStudentMsg::getStudentNo, studentNo)
.eq(XgStudentMsg::getDeleted, 0);
XgStudentMsg studentMsg = xgStudentMsgMapper.selectOne(studentWrapper);
if (studentMsg != null) {
studentName = studentMsg.getName();
}
}
// 创建成员记录
StglMember member = new StglMember();
member.setMemberType(1); // 社团成员
member.setRelationId(clubId);
member.setUserId(userId);
member.setRoleType(3); // 普通成员
member.setStudentNo(studentNo);
member.setStudentName(studentName != null ? studentName : user.getNickName()); // 如果没有学生信息,使用用户昵称
member.setRoleType(4); // 普通成员
member.setJoinTime(new Date());
member.setStatus(1);
member.setStatus(0); // 待审核状态(stgl_member_status字典,新报名需审核)
member.setRemark(reason); // 将申请理由存储到备注字段
return memberMapper.insert(member) > 0;
}
@@ -227,7 +276,7 @@ public class StglClubRegisterServiceImpl implements IStglClubRegisterService {
throw new RuntimeException("社长和副社长不能直接退出,请先转让职务");
}
member.setStatus(0);
member.setStatus(1); // 设置为停用状态(退出)
return memberMapper.updateById(member) > 0;
}
@@ -239,27 +288,62 @@ public class StglClubRegisterServiceImpl implements IStglClubRegisterService {
*/
@Override
public List<StglClubRegisterVo> queryMyClubs(Long userId) {
// 查询用户参与的社团ID
LambdaQueryWrapper<StglMember> memberLqw = Wrappers.lambdaQuery();
memberLqw.eq(StglMember::getMemberType, 1);
memberLqw.eq(StglMember::getUserId, userId);
memberLqw.eq(StglMember::getStatus, 1);
List<StglMember> members = memberMapper.selectList(memberLqw);
// 使用自定义查询直接获取用户参与的社团列表(包含角色信息)
List<StglClubVo> clubVos = memberMapper.selectUserClubs(userId);
if (members.isEmpty()) {
return List.of();
}
List<Long> clubIds = members.stream().map(StglMember::getRelationId).collect(Collectors.toList());
// 查询社团信息
LambdaQueryWrapper<StglClub> clubLqw = Wrappers.lambdaQuery();
clubLqw.in(StglClub::getId, clubIds);
clubLqw.eq(StglClub::getStatus, 1);
clubLqw.orderByDesc(StglClub::getCreateTime);
List<StglClub> clubs = clubMapper.selectList(clubLqw);
return convertToRegisterVo(clubs);
return clubVos.stream().map(clubVo -> {
StglClubRegisterVo vo = new StglClubRegisterVo();
vo.setId(clubVo.getId());
vo.setClubName(clubVo.getClubName());
vo.setClubType(clubVo.getClubType());
vo.setEstablishDate(clubVo.getEstablishDate());
vo.setDescription(clubVo.getDescription());
vo.setLogoUrl(clubVo.getLogoUrl());
vo.setPresidentName(clubVo.getPresidentName());
vo.setPresidentDept(clubVo.getPresidentDept());
vo.setAdvisorName(clubVo.getAdvisorName());
vo.setAdvisorDept(clubVo.getAdvisorDept());
vo.setMemberLimit(clubVo.getMemberLimit());
vo.setRecruitCycle(clubVo.getRecruitCycle());
vo.setRecruitTime(clubVo.getRecruitTime());
vo.setActivityFrequency(clubVo.getActivityFrequency());
// ========== 新增:副社长信息 ==========
vo.setVicePresidentName(clubVo.getVicePresidentName());
vo.setVicePresidentStudentNo(clubVo.getVicePresidentStudentNo());
vo.setVicePresidentDept(clubVo.getVicePresidentDept());
vo.setVicePresidentMajor(clubVo.getVicePresidentMajor());
vo.setVicePresidentClass(clubVo.getVicePresidentClass());
vo.setVicePresidentPhone(clubVo.getVicePresidentPhone());
vo.setVicePresidentsJson(clubVo.getVicePresidentsJson());
// ========== 新增:其他完善字段 ==========
vo.setPhone(clubVo.getPhone());
vo.setEmail(clubVo.getEmail());
vo.setPresidentStudentNo(clubVo.getPresidentStudentNo());
vo.setPresidentMajor(clubVo.getPresidentMajor());
vo.setPresidentClass(clubVo.getPresidentClass());
vo.setPresidentPhone(clubVo.getPresidentPhone());
vo.setAdvisorPhone(clubVo.getAdvisorPhone());
vo.setAdvisorEmail(clubVo.getAdvisorEmail());
vo.setAdvisorsJson(clubVo.getAdvisorsJson()); // 🔥 新增:指导老师JSON数据
vo.setFundingSources(clubVo.getFundingSources());
vo.setDepartments(clubVo.getDepartments());
// ========== 新增:章程文件和备注信息 ==========
vo.setCharterUrl(clubVo.getCharterUrl());
vo.setRemark(clubVo.getRemark());
// 设置用户在社团中的角色信息
vo.setMyRoleType(clubVo.getMyRoleType());
vo.setMyJoinTime(clubVo.getMyJoinTime());
vo.setMyRoleName(clubVo.getMyRoleName());
// 设置已加入状态
vo.setIsRegistered(true);
vo.setCanRegister(false);
return vo;
}).collect(Collectors.toList());
}
/**
@@ -271,13 +355,7 @@ public class StglClubRegisterServiceImpl implements IStglClubRegisterService {
*/
@Override
public Boolean checkRegistered(Long clubId, Long userId) {
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
lqw.eq(StglMember::getMemberType, 1);
lqw.eq(StglMember::getRelationId, clubId);
lqw.eq(StglMember::getUserId, userId);
lqw.eq(StglMember::getStatus, 1);
long count = memberMapper.selectCount(lqw);
return count > 0;
return memberMapper.checkMemberExists(1, clubId, userId);
}
/**
@@ -289,18 +367,59 @@ public class StglClubRegisterServiceImpl implements IStglClubRegisterService {
*/
@Override
public List<StglClubRegisterVo> queryRecommendClubs(String clubType, Integer limit) {
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
lqw.eq(StglClub::getStatus, 1);
if (StringUtils.isNotBlank(clubType)) {
lqw.eq(StglClub::getClubType, clubType);
}
lqw.orderByDesc(StglClub::getCreateTime);
if (limit != null && limit > 0) {
lqw.last("LIMIT " + limit);
}
// 使用自定义查询按成员数量排序获取热门社团
List<StglClubVo> clubVos = clubMapper.selectPopularClubs(clubType, limit);
List<StglClub> clubs = clubMapper.selectList(lqw);
return convertToRegisterVo(clubs);
return clubVos.stream().map(clubVo -> {
StglClubRegisterVo vo = new StglClubRegisterVo();
vo.setId(clubVo.getId());
vo.setClubName(clubVo.getClubName());
vo.setClubType(clubVo.getClubType());
vo.setEstablishDate(clubVo.getEstablishDate());
vo.setDescription(clubVo.getDescription());
vo.setLogoUrl(clubVo.getLogoUrl());
vo.setPresidentName(clubVo.getPresidentName());
vo.setPresidentDept(clubVo.getPresidentDept());
vo.setAdvisorName(clubVo.getAdvisorName());
vo.setAdvisorDept(clubVo.getAdvisorDept());
vo.setMemberLimit(clubVo.getMemberLimit());
vo.setRecruitCycle(clubVo.getRecruitCycle());
vo.setRecruitTime(clubVo.getRecruitTime());
vo.setActivityFrequency(clubVo.getActivityFrequency());
// ========== 新增:副社长信息 ==========
vo.setVicePresidentName(clubVo.getVicePresidentName());
vo.setVicePresidentStudentNo(clubVo.getVicePresidentStudentNo());
vo.setVicePresidentDept(clubVo.getVicePresidentDept());
vo.setVicePresidentMajor(clubVo.getVicePresidentMajor());
vo.setVicePresidentClass(clubVo.getVicePresidentClass());
vo.setVicePresidentPhone(clubVo.getVicePresidentPhone());
vo.setVicePresidentsJson(clubVo.getVicePresidentsJson());
// ========== 新增:其他完善字段 ==========
vo.setPhone(clubVo.getPhone());
vo.setEmail(clubVo.getEmail());
vo.setPresidentStudentNo(clubVo.getPresidentStudentNo());
vo.setPresidentMajor(clubVo.getPresidentMajor());
vo.setPresidentClass(clubVo.getPresidentClass());
vo.setPresidentPhone(clubVo.getPresidentPhone());
vo.setAdvisorPhone(clubVo.getAdvisorPhone());
vo.setAdvisorEmail(clubVo.getAdvisorEmail());
// ========== 新增:章程文件和备注信息 ==========
vo.setCharterUrl(clubVo.getCharterUrl());
vo.setRemark(clubVo.getRemark());
// 设置成员数量和报名状态
vo.setCurrentMemberCount(clubVo.getMemberCount());
vo.setMemberCount(clubVo.getMemberCount()); // 设置前端兼容字段
boolean canRegister = clubVo.getMemberLimit() == null || clubVo.getMemberLimit() == 0 ||
clubVo.getMemberCount() < clubVo.getMemberLimit();
vo.setCanRegister(canRegister);
vo.setIsRegistered(false); // 推荐列表默认未加入
return vo;
}).collect(Collectors.toList());
}
}
@@ -9,16 +9,38 @@ 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.StglClubBo;
import org.dromara.stgl.domain.vo.StglClubVo;
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.IStglClubService;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.json.utils.JsonUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
// 添加学生信息服务依赖
import org.dromara.xg.domain.XgStudentMsg;
import org.dromara.xg.mapper.XgStudentMsgMapper;
import java.util.stream.Collectors;
import java.util.Collections;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.json.utils.JsonUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Date;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.util.Set;
/**
* 社团信息Service业务层处理
@@ -30,7 +52,12 @@ import java.util.Collection;
@Service
public class StglClubServiceImpl implements IStglClubService {
private static final Logger log = LoggerFactory.getLogger(StglClubServiceImpl.class);
private final StglClubMapper baseMapper;
private final StglMemberMapper memberMapper;
// 添加学生信息Mapper
private final XgStudentMsgMapper studentMsgMapper;
/**
* 查询社团信息
@@ -52,8 +79,21 @@ public class StglClubServiceImpl implements IStglClubService {
*/
@Override
public TableDataInfo<StglClubVo> queryPageList(StglClubBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<StglClub> lqw = buildQueryWrapper(bo);
Page<StglClubVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
// 数据权限控制:如果是stgl_president角色,只能查看自己担任社长的社团
applyDataScope(bo);
// 使用自定义查询方法,包含成员统计
Page<StglClubVo> page = pageQuery.build();
IPage<StglClubVo> result = baseMapper.selectClubPageWithMemberCount(
page,
bo.getClubName(),
bo.getClubType(),
bo.getStatus(),
bo.getEstablishDate(),
bo.getPresidentName(),
bo.getAdvisorName(),
bo.getClubIds()
);
return TableDataInfo.build(result);
}
@@ -65,10 +105,79 @@ public class StglClubServiceImpl implements IStglClubService {
*/
@Override
public List<StglClubVo> queryList(StglClubBo bo) {
// 数据权限控制:如果是stgl_president角色,只能查看自己担任社长的社团
applyDataScope(bo);
LambdaQueryWrapper<StglClub> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
/**
* 应用数据权限控制
*
* @param bo 查询条件
*/
private void applyDataScope(StglClubBo bo) {
try {
// 获取当前登录用户信息
Long currentUserId = LoginHelper.getUserId();
if (currentUserId == null) {
return;
}
Set<String> roleKeys = LoginHelper.getLoginUser().getRolePermission();
// 如果是stgl_president角色且不是管理员,只能查看自己担任社长的社团
if (roleKeys.contains("stgl_president") &&
!roleKeys.contains("admin") &&
!roleKeys.contains("common")) {
// 获取用户担任社长的社团ID列表
List<Long> userClubIds = getUserPresidentClubIds(currentUserId);
if (userClubIds.isEmpty()) {
// 如果不是任何社团的社长,设置一个不存在的ID,返回空结果
bo.setClubIds(Collections.singletonList(-1L));
} else {
// 设置数据权限过滤条件
bo.setClubIds(userClubIds);
}
}
} catch (Exception e) {
// 如果获取权限信息失败,不影响正常查询
log.warn("获取用户权限信息失败: {}", e.getMessage());
}
}
/**
* 获取用户担任社长的社团ID列表
*
* @param userId 用户ID
* @return 社团ID列表
*/
private List<Long> getUserPresidentClubIds(Long userId) {
if (userId == null) {
return Collections.emptyList();
}
try {
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
lqw.eq(StglMember::getMemberType, 1) // 社团成员
.eq(StglMember::getUserId, userId) // 当前用户
.eq(StglMember::getRoleType, 1) // 社长角色
.eq(StglMember::getStatus, 2); // 已加入状态
List<StglMember> members = memberMapper.selectList(lqw);
return members.stream()
.map(StglMember::getRelationId)
.distinct()
.collect(Collectors.toList());
} catch (Exception e) {
log.error("查询用户担任社长的社团失败: {}", e.getMessage(), e);
return Collections.emptyList();
}
}
private LambdaQueryWrapper<StglClub> buildQueryWrapper(StglClubBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
@@ -80,6 +189,12 @@ public class StglClubServiceImpl implements IStglClubService {
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"));
// 数据权限控制:如果指定了clubIds,只查询这些社团
if (CollectionUtils.isNotEmpty(bo.getClubIds())) {
lqw.in(StglClub::getId, bo.getClubIds());
}
lqw.orderByDesc(StglClub::getCreateTime);
return lqw;
}
@@ -91,12 +206,15 @@ public class StglClubServiceImpl implements IStglClubService {
* @return 是否新增成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
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());
// 自动创建社长和副社长的成员记录
createLeaderMemberRecords(add);
}
return flag;
}
@@ -108,10 +226,20 @@ public class StglClubServiceImpl implements IStglClubService {
* @return 是否修改成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(StglClubBo bo) {
StglClub update = MapstructUtils.convert(bo, StglClub.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
// 更新社团基本信息
boolean updateResult = baseMapper.updateById(update) > 0;
if (updateResult) {
// 同步更新副社长的成员记录
syncVicePresidentsInMembers(update);
}
return updateResult;
}
/**
@@ -133,7 +261,7 @@ public class StglClubServiceImpl implements IStglClubService {
// 设置默认状态
if (entity.getStatus() == null) {
entity.setStatus(1);
entity.setStatus(0); // 默认为正常状态(0-正常,1-停用)
}
}
@@ -230,4 +358,603 @@ public class StglClubServiceImpl implements IStglClubService {
return baseMapper.updateById(club) > 0;
}
/**
* 自动创建社长和副社长的成员记录
*
* @param club 社团信息
*/
private void createLeaderMemberRecords(StglClub club) {
Date now = new Date();
// 1. 创建社长成员记录
if (StringUtils.isNotBlank(club.getPresidentStudentNo())) {
StglMember president = new StglMember();
president.setMemberType(1); // 社团成员
president.setRelationId(club.getId());
president.setStudentNo(club.getPresidentStudentNo());
president.setStudentName(club.getPresidentName());
president.setRoleType(1); // 社长
president.setJoinTime(now);
president.setStatus(2); // 已加入状态(stgl_member_status字典)
president.setRemark("社团创建时自动添加");
// 根据学号查找用户ID
Long presidentUserId = findUserIdByStudentNo(club.getPresidentStudentNo());
if (presidentUserId != null) {
president.setUserId(presidentUserId);
}
memberMapper.insert(president);
}
// 2. 创建副社长成员记录 - 支持多个副社长
createVicePresidentMemberRecords(club, now);
}
/**
* 创建副社长成员记录(支持多个副社长)
*
* @param club 社团信息
* @param joinTime 加入时间
*/
private void createVicePresidentMemberRecords(StglClub club, Date joinTime) {
// 1. 处理单个副社长字段(向后兼容)
if (StringUtils.isNotBlank(club.getVicePresidentStudentNo())) {
createSingleVicePresidentRecord(
club.getId(),
club.getVicePresidentStudentNo(),
club.getVicePresidentName(),
joinTime
);
}
// 2. 处理多个副社长JSON数据
if (StringUtils.isNotBlank(club.getVicePresidentsJson())) {
try {
ObjectMapper objectMapper = new ObjectMapper();
List<Map<String, Object>> vicePresidents = objectMapper.readValue(
club.getVicePresidentsJson(),
new TypeReference<List<Map<String, Object>>>() {}
);
for (Map<String, Object> vicePresident : vicePresidents) {
String studentNo = null;
String name = null;
// 尝试从外层获取 studentNo 和 name
if (vicePresident.containsKey("studentNo")) {
studentNo = (String) vicePresident.get("studentNo");
name = (String) vicePresident.get("name");
}
// 如果外层没有,尝试从嵌套的 student 对象获取
if (StringUtils.isBlank(studentNo) && vicePresident.containsKey("student")) {
@SuppressWarnings("unchecked")
Map<String, Object> student = (Map<String, Object>) vicePresident.get("student");
if (student != null) {
studentNo = (String) student.get("studentNo");
name = (String) student.get("name");
}
}
// 如果外层的 name 为空,也尝试从嵌套的 student 对象获取
if (StringUtils.isBlank(name) && vicePresident.containsKey("student")) {
@SuppressWarnings("unchecked")
Map<String, Object> student = (Map<String, Object>) vicePresident.get("student");
if (student != null && StringUtils.isBlank(name)) {
name = (String) student.get("name");
}
}
if (StringUtils.isNotBlank(studentNo) && StringUtils.isNotBlank(name)) {
// 避免重复创建相同学号的成员记录
if (StringUtils.isBlank(club.getVicePresidentStudentNo()) ||
!studentNo.equals(club.getVicePresidentStudentNo())) {
System.out.println("创建副社长成员记录: " + name + "(" + studentNo + ")");
createSingleVicePresidentRecord(club.getId(), studentNo, name, joinTime);
} else {
System.out.println("跳过重复的副社长: " + name + "(" + studentNo + ")");
}
} else {
System.err.println("副社长信息不完整 - studentNo: " + studentNo + ", name: " + name);
System.err.println("原始数据: " + vicePresident);
}
}
} catch (Exception e) {
System.err.println("解析副社长JSON数据失败: " + e.getMessage());
e.printStackTrace();
// 记录错误但不中断处理流程
}
}
}
/**
* 创建单个副社长成员记录
*
* @param clubId 社团ID
* @param studentNo 学号
* @param name 姓名
* @param joinTime 加入时间
*/
private void createSingleVicePresidentRecord(Long clubId, String studentNo, String name, Date joinTime) {
StglMember vicePresident = new StglMember();
vicePresident.setMemberType(1); // 社团成员
vicePresident.setRelationId(clubId);
vicePresident.setStudentNo(studentNo);
vicePresident.setStudentName(name);
vicePresident.setRoleType(2); // 副社长
vicePresident.setJoinTime(joinTime);
vicePresident.setStatus(2); // 已加入状态(stgl_member_status字典)
vicePresident.setRemark("社团创建时自动添加");
// 根据学号查找用户ID
Long vicePresidentUserId = findUserIdByStudentNo(studentNo);
if (vicePresidentUserId != null) {
vicePresident.setUserId(vicePresidentUserId);
}
memberMapper.insert(vicePresident);
}
/**
* 根据学号查找用户ID
*
* @param studentNo 学号
* @return 用户ID
*/
private Long findUserIdByStudentNo(String studentNo) {
try {
if (StringUtils.isBlank(studentNo)) {
return null;
}
// 在xg_student_msg表中根据学号查找学生信息
// 该表的id字段即为用户ID(对应sys_user表的user_id)
LambdaQueryWrapper<XgStudentMsg> wrapper = Wrappers.lambdaQuery();
wrapper.eq(XgStudentMsg::getStudentNo, studentNo)
.eq(XgStudentMsg::getDeleted, 0) // 未删除的记录
.last("LIMIT 1"); // 限制只返回一条记录
XgStudentMsg studentMsg = studentMsgMapper.selectOne(wrapper);
if (studentMsg != null) {
return studentMsg.getId(); // 返回学生的ID,即用户ID
}
} catch (Exception e) {
// 如果查询失败,记录日志但不抛出异常,允许创建没有userId的成员记录
System.err.println("根据学号 " + studentNo + " 查找用户ID失败: " + e.getMessage());
}
return null;
}
/**
* 修复所有已存在社团的成员记录
* 为那些没有对应成员记录的社长和副社长补充成员记录
*
* @return 修复的记录数量
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Integer fixExistingClubMemberRecords() {
int fixedCount = 0;
// 查询所有正常状态的社团
LambdaQueryWrapper<StglClub> clubQuery = Wrappers.lambdaQuery();
clubQuery.eq(StglClub::getStatus, 1);
List<StglClub> clubs = baseMapper.selectList(clubQuery);
for (StglClub club : clubs) {
Date now = new Date();
// 检查并补充社长成员记录
if (StringUtils.isNotBlank(club.getPresidentStudentNo())) {
boolean presidentExists = checkMemberExists(club.getId(), club.getPresidentStudentNo(), 1);
if (!presidentExists) {
StglMember president = new StglMember();
president.setMemberType(1); // 社团成员
president.setRelationId(club.getId());
president.setStudentNo(club.getPresidentStudentNo());
president.setStudentName(club.getPresidentName());
president.setRoleType(1); // 社长
president.setJoinTime(club.getCreateTime() != null ? club.getCreateTime() : now);
president.setStatus(2); // 已加入状态(stgl_member_status字典)
president.setRemark("补充缺失的社长成员记录");
Long presidentUserId = findUserIdByStudentNo(club.getPresidentStudentNo());
if (presidentUserId != null) {
president.setUserId(presidentUserId);
}
memberMapper.insert(president);
fixedCount++;
}
}
// 检查并补充副社长成员记录(支持多个副社长)
fixedCount += fixVicePresidentMemberRecords(club);
}
return fixedCount;
}
/**
* 修复副社长成员记录(支持多个副社长)
*
* @param club 社团信息
* @return 修复的记录数量
*/
private int fixVicePresidentMemberRecords(StglClub club) {
int fixedCount = 0;
Date joinTime = club.getCreateTime() != null ? club.getCreateTime() : new Date();
// 1. 处理单个副社长字段(向后兼容)
if (StringUtils.isNotBlank(club.getVicePresidentStudentNo())) {
boolean vicePresidentExists = checkMemberExists(club.getId(), club.getVicePresidentStudentNo(), 2);
if (!vicePresidentExists) {
fixedCount += createFixedVicePresidentRecord(
club.getId(),
club.getVicePresidentStudentNo(),
club.getVicePresidentName(),
joinTime
) ? 1 : 0;
}
}
// 2. 处理多个副社长JSON数据
if (StringUtils.isNotBlank(club.getVicePresidentsJson())) {
try {
ObjectMapper objectMapper = new ObjectMapper();
List<Map<String, Object>> vicePresidents = objectMapper.readValue(
club.getVicePresidentsJson(),
new TypeReference<List<Map<String, Object>>>() {}
);
for (Map<String, Object> vicePresident : vicePresidents) {
String studentNo = null;
String name = null;
// 尝试从外层获取 studentNo 和 name
if (vicePresident.containsKey("studentNo")) {
studentNo = (String) vicePresident.get("studentNo");
name = (String) vicePresident.get("name");
}
// 如果外层没有,尝试从嵌套的 student 对象获取
if (StringUtils.isBlank(studentNo) && vicePresident.containsKey("student")) {
@SuppressWarnings("unchecked")
Map<String, Object> student = (Map<String, Object>) vicePresident.get("student");
if (student != null) {
studentNo = (String) student.get("studentNo");
name = (String) student.get("name");
}
}
// 如果外层的 name 为空,也尝试从嵌套的 student 对象获取
if (StringUtils.isBlank(name) && vicePresident.containsKey("student")) {
@SuppressWarnings("unchecked")
Map<String, Object> student = (Map<String, Object>) vicePresident.get("student");
if (student != null && StringUtils.isBlank(name)) {
name = (String) student.get("name");
}
}
if (StringUtils.isNotBlank(studentNo) && StringUtils.isNotBlank(name)) {
// 避免重复处理相同学号的副社长
if (StringUtils.isBlank(club.getVicePresidentStudentNo()) ||
!studentNo.equals(club.getVicePresidentStudentNo())) {
boolean exists = checkMemberExists(club.getId(), studentNo, 2);
if (!exists) {
System.out.println("修复副社长成员记录: " + name + "(" + studentNo + ")");
fixedCount += createFixedVicePresidentRecord(club.getId(), studentNo, name, joinTime) ? 1 : 0;
}
}
} else {
System.err.println("修复时副社长信息不完整 - studentNo: " + studentNo + ", name: " + name);
}
}
} catch (Exception e) {
System.err.println("修复时解析副社长JSON数据失败: " + e.getMessage());
}
}
return fixedCount;
}
/**
* 创建修复的副社长成员记录
*
* @param clubId 社团ID
* @param studentNo 学号
* @param name 姓名
* @param joinTime 加入时间
* @return 是否创建成功
*/
private boolean createFixedVicePresidentRecord(Long clubId, String studentNo, String name, Date joinTime) {
try {
StglMember vicePresident = new StglMember();
vicePresident.setMemberType(1); // 社团成员
vicePresident.setRelationId(clubId);
vicePresident.setStudentNo(studentNo);
vicePresident.setStudentName(name);
vicePresident.setRoleType(2); // 副社长
vicePresident.setJoinTime(joinTime);
vicePresident.setStatus(2); // 已加入状态(stgl_member_status字典)
vicePresident.setRemark("补充缺失的副社长成员记录");
Long vicePresidentUserId = findUserIdByStudentNo(studentNo);
if (vicePresidentUserId != null) {
vicePresident.setUserId(vicePresidentUserId);
}
return memberMapper.insert(vicePresident) > 0;
} catch (Exception e) {
System.err.println("创建副社长成员记录失败: " + e.getMessage());
return false;
}
}
/**
* 检查指定社团中是否已存在指定学号和角色的成员记录
*
* @param clubId 社团ID
* @param studentNo 学号
* @param roleType 角色类型
* @return 是否存在
*/
private boolean checkMemberExists(Long clubId, String studentNo, Integer roleType) {
LambdaQueryWrapper<StglMember> query = Wrappers.lambdaQuery();
query.eq(StglMember::getMemberType, 1);
query.eq(StglMember::getRelationId, clubId);
query.eq(StglMember::getStudentNo, studentNo);
query.eq(StglMember::getRoleType, roleType);
query.eq(StglMember::getStatus, 1);
return memberMapper.selectCount(query) > 0;
}
/**
* 同步更新副社长的成员记录
* 在社团修改时调用,确保副社长变更能同步到成员表
*
* @param club 更新后的社团信息
*/
private void syncVicePresidentsInMembers(StglClub club) {
try {
// 1. 删除现有的所有副社长记录(roleType = 2)
LambdaQueryWrapper<StglMember> deleteWrapper = Wrappers.lambdaQuery();
deleteWrapper.eq(StglMember::getRelationId, club.getId())
.eq(StglMember::getMemberType, 1) // 社团成员
.eq(StglMember::getRoleType, 2); // 副社长角色
memberMapper.delete(deleteWrapper);
// 2. 处理单个副社长字段(向后兼容)
if (StringUtils.isNotBlank(club.getVicePresidentStudentNo())) {
createSingleVicePresidentRecord(
club.getId(),
club.getVicePresidentStudentNo(),
club.getVicePresidentName(),
new Date()
);
}
// 3. 处理多个副社长JSON数据
if (StringUtils.isNotBlank(club.getVicePresidentsJson())) {
try {
ObjectMapper objectMapper = new ObjectMapper();
List<Map<String, Object>> vicePresidents = objectMapper.readValue(
club.getVicePresidentsJson(),
new TypeReference<List<Map<String, Object>>>() {}
);
for (Map<String, Object> vicePresident : vicePresidents) {
String studentNo = extractStudentNo(vicePresident);
String name = extractStudentName(vicePresident);
if (StringUtils.isNotBlank(studentNo) && StringUtils.isNotBlank(name)) {
// 避免重复创建相同学号的成员记录
if (StringUtils.isBlank(club.getVicePresidentStudentNo()) ||
!studentNo.equals(club.getVicePresidentStudentNo())) {
createSingleVicePresidentRecord(club.getId(), studentNo, name, new Date());
}
}
}
} catch (Exception e) {
System.err.println("同步副社长时解析JSON数据失败: " + e.getMessage());
e.printStackTrace();
}
}
System.out.println("副社长成员记录同步完成,社团ID: " + club.getId());
} catch (Exception e) {
System.err.println("同步副社长成员记录失败: " + e.getMessage());
e.printStackTrace();
throw new RuntimeException("同步副社长成员记录失败", e);
}
}
/**
* 从副社长数据中提取学号
*/
private String extractStudentNo(Map<String, Object> vicePresident) {
// 尝试从外层获取 studentNo
if (vicePresident.containsKey("studentNo")) {
return (String) vicePresident.get("studentNo");
}
// 如果外层没有,尝试从嵌套的 student 对象获取
if (vicePresident.containsKey("student")) {
@SuppressWarnings("unchecked")
Map<String, Object> student = (Map<String, Object>) vicePresident.get("student");
if (student != null) {
return (String) student.get("studentNo");
}
}
return null;
}
/**
* 从副社长数据中提取姓名
*/
private String extractStudentName(Map<String, Object> vicePresident) {
// 尝试从外层获取 name
if (vicePresident.containsKey("name")) {
return (String) vicePresident.get("name");
}
// 如果外层没有,尝试从嵌套的 student 对象获取
if (vicePresident.containsKey("student")) {
@SuppressWarnings("unchecked")
Map<String, Object> student = (Map<String, Object>) vicePresident.get("student");
if (student != null) {
return (String) student.get("name");
}
}
return null;
}
/**
* 检查社团名称是否存在
*
* @param clubName 社团名称
* @param id 社团ID(排除自己)
* @return 是否存在
*/
@Override
public Boolean checkClubNameExists(String clubName, Long id) {
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
lqw.eq(StglClub::getClubName, clubName);
if (id != null) {
lqw.ne(StglClub::getId, id);
}
long count = baseMapper.selectCount(lqw);
return count > 0;
}
/**
* 验证用户是否为社团社长
*
* @param clubId 社团ID
* @param userId 用户ID
* @return 是否为社长
*/
@Override
public Boolean isClubPresident(Long clubId, Long userId) {
if (clubId == null || userId == null) {
return false;
}
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
lqw.eq(StglMember::getMemberType, 1); // 社团成员
lqw.eq(StglMember::getRelationId, clubId); // 该社团
lqw.eq(StglMember::getUserId, userId); // 指定用户
lqw.eq(StglMember::getRoleType, 1); // 社长角色 (1-社长)
lqw.eq(StglMember::getStatus, 2); // 已加入状态 (2-已加入)
StglMember member = memberMapper.selectOne(lqw);
return member != null;
}
/**
* 社团转让
*
* @param clubId 社团ID
* @param newPresidentUserId 新社长用户ID
* @return 是否转让成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean transferClub(Long clubId, Long newPresidentUserId) {
// 1. 获取当前登录用户ID
Long currentUserId = LoginHelper.getUserId();
if (currentUserId == null) {
throw new RuntimeException("用户未登录");
}
// 2. 验证当前用户是否为该社团的社长
if (!isClubPresident(clubId, currentUserId)) {
throw new RuntimeException("只有社长才能进行社团转让");
}
// 3. 查询社团信息
StglClub club = baseMapper.selectById(clubId);
if (club == null) {
throw new RuntimeException("社团信息不存在");
}
// 4. 查询新社长的学生信息
LambdaQueryWrapper<XgStudentMsg> studentLqw = Wrappers.lambdaQuery();
studentLqw.eq(XgStudentMsg::getId, newPresidentUserId); // 修改为使用id字段
XgStudentMsg newPresidentStudent = studentMsgMapper.selectOne(studentLqw);
if (newPresidentStudent == null) {
throw new RuntimeException("新社长的学生信息不存在");
}
// 3. 查询原社长在成员表中的记录
LambdaQueryWrapper<StglMember> oldPresidentLqw = Wrappers.lambdaQuery();
oldPresidentLqw.eq(StglMember::getMemberType, 1); // 社团成员
oldPresidentLqw.eq(StglMember::getRelationId, clubId);
oldPresidentLqw.eq(StglMember::getRoleType, 1); // 社长
oldPresidentLqw.eq(StglMember::getStatus, 2); // 已加入状态
StglMember oldPresidentMember = memberMapper.selectOne(oldPresidentLqw);
// 4. 查询新社长在成员表中的记录
LambdaQueryWrapper<StglMember> newPresidentLqw = Wrappers.lambdaQuery();
newPresidentLqw.eq(StglMember::getMemberType, 1); // 社团成员
newPresidentLqw.eq(StglMember::getRelationId, clubId);
newPresidentLqw.eq(StglMember::getUserId, newPresidentUserId);
StglMember newPresidentMember = memberMapper.selectOne(newPresidentLqw);
// 5. 更新社团表中的社长信息
StglClub updateClub = new StglClub();
updateClub.setId(clubId);
updateClub.setPresidentName(newPresidentStudent.getName());
updateClub.setPresidentStudentNo(newPresidentStudent.getStudentNo());
updateClub.setPresidentDept(newPresidentStudent.getCollegeName()); // 修改为collegeName
updateClub.setPresidentMajor(newPresidentStudent.getMajorName()); // 修改为majorName
updateClub.setPresidentClass(newPresidentStudent.getClassName());
updateClub.setPresidentPhone(newPresidentStudent.getPhone());
boolean updateResult = baseMapper.updateById(updateClub) > 0;
if (!updateResult) {
throw new RuntimeException("更新社团信息失败");
}
// 6. 更新原社长的成员状态为已退出
if (oldPresidentMember != null) {
StglMember updateOldPresident = new StglMember();
updateOldPresident.setId(oldPresidentMember.getId());
updateOldPresident.setStatus(4); // 已退出状态
memberMapper.updateById(updateOldPresident);
}
// 7. 添加或更新新社长的成员记录
if (newPresidentMember != null) {
// 如果新社长已经是成员,更新角色和状态
StglMember updateNewPresident = new StglMember();
updateNewPresident.setId(newPresidentMember.getId());
updateNewPresident.setRoleType(1); // 社长
updateNewPresident.setStatus(2); // 已加入状态
updateNewPresident.setJoinTime(new Date());
memberMapper.updateById(updateNewPresident);
} else {
// 如果新社长不是成员,新增成员记录
StglMember newMember = new StglMember();
newMember.setMemberType(1); // 社团成员
newMember.setRelationId(clubId);
newMember.setUserId(newPresidentUserId);
newMember.setStudentNo(newPresidentStudent.getStudentNo());
newMember.setStudentName(newPresidentStudent.getName());
newMember.setRoleType(1); // 社长
newMember.setJoinTime(new Date());
newMember.setStatus(2); // 已加入状态
memberMapper.insert(newMember);
}
return true;
}
}
@@ -0,0 +1,282 @@
package org.dromara.stgl.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.stgl.domain.StglMaterialSubmission;
import org.dromara.stgl.domain.bo.StglMaterialSubmissionBo;
import org.dromara.stgl.domain.vo.StglMaterialSubmissionVo;
import org.dromara.stgl.mapper.StglMaterialSubmissionMapper;
import org.dromara.stgl.service.IStglMaterialSubmissionService;
import org.dromara.stgl.service.IStglMaterialTaskService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 材料提交记录Service业务层处理
*
* @author ruoyi
* @date 2025-01-03
*/
@RequiredArgsConstructor
@Service
public class StglMaterialSubmissionServiceImpl extends ServiceImpl<StglMaterialSubmissionMapper, StglMaterialSubmission> implements IStglMaterialSubmissionService {
private final StglMaterialSubmissionMapper baseMapper;
private final IStglMaterialTaskService materialTaskService;
/**
* 查询材料提交记录
*/
@Override
public StglMaterialSubmissionVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询材料提交记录列表
*/
@Override
public TableDataInfo<StglMaterialSubmissionVo> queryPageList(StglMaterialSubmissionBo bo, PageQuery pageQuery) {
StglMaterialSubmission submission = MapstructUtils.convert(bo, StglMaterialSubmission.class);
Page<StglMaterialSubmissionVo> page = baseMapper.selectVoPage(pageQuery.build(), submission);
return TableDataInfo.build(page);
}
/**
* 查询材料提交记录列表
*/
@Override
public List<StglMaterialSubmissionVo> queryList(StglMaterialSubmissionBo bo) {
StglMaterialSubmission submission = MapstructUtils.convert(bo, StglMaterialSubmission.class);
return baseMapper.selectVoList(submission);
}
/**
* 新增材料提交记录
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(StglMaterialSubmissionBo bo) {
StglMaterialSubmission add = MapstructUtils.convert(bo, StglMaterialSubmission.class);
// 设置默认值
if (add.getSubmissionTime() == null) {
add.setSubmissionTime(new Date());
}
if (add.getRoundNumber() == null) {
add.setRoundNumber(1);
}
if (add.getReviewStatus() == null) {
add.setReviewStatus(0); // 默认待审核
}
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
// 更新任务统计信息
materialTaskService.updateTaskStatistics(add.getTaskId());
}
return flag;
}
/**
* 修改材料提交记录
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(StglMaterialSubmissionBo bo) {
StglMaterialSubmission update = MapstructUtils.convert(bo, StglMaterialSubmission.class);
validEntityBeforeSave(update);
boolean flag = baseMapper.updateById(update) > 0;
if (flag) {
// 更新任务统计信息
materialTaskService.updateTaskStatistics(update.getTaskId());
}
return flag;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(StglMaterialSubmission entity) {
// 校验任务是否存在
if (entity.getTaskId() != null) {
// 这里可以添加对任务存在性的校验
}
// 校验提交类型和相关字段的一致性
if (entity.getSubmissionType() != null) {
if (entity.getSubmissionType() == 1 && entity.getUserId() == null) {
throw new RuntimeException("个人提交必须指定用户ID");
}
if (entity.getSubmissionType() == 2 && entity.getTeamId() == null) {
throw new RuntimeException("团队提交必须指定团队ID");
}
}
}
/**
* 批量删除材料提交记录
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 校验是否允许删除
for (Long id : ids) {
StglMaterialSubmissionVo submission = baseMapper.selectVoById(id);
if (submission != null && submission.getReviewStatus() == 1) {
throw new RuntimeException("已审核通过的提交记录不允许删除");
}
}
}
// 获取任务ID集合,用于更新统计信息
List<StglMaterialSubmissionVo> submissions = baseMapper.selectBatchIds(ids)
.stream()
.map(s -> MapstructUtils.convert(s, StglMaterialSubmissionVo.class))
.toList();
boolean flag = baseMapper.deleteBatchIds(ids) > 0;
if (flag) {
// 更新相关任务的统计信息
submissions.stream()
.map(StglMaterialSubmissionVo::getTaskId)
.distinct()
.forEach(taskId -> materialTaskService.updateTaskStatistics(taskId));
}
return flag;
}
/**
* 根据任务ID查询提交记录
*/
@Override
public List<StglMaterialSubmissionVo> queryByTaskId(Long taskId) {
return baseMapper.selectByTaskId(taskId);
}
/**
* 查询用户在指定任务的提交记录
*/
@Override
public StglMaterialSubmissionVo queryByTaskIdAndUserId(Long taskId, Long userId) {
return baseMapper.selectByTaskIdAndUserId(taskId, userId);
}
/**
* 查询团队在指定任务的提交记录
*/
@Override
public StglMaterialSubmissionVo queryByTaskIdAndTeamId(Long taskId, Long teamId) {
return baseMapper.selectByTaskIdAndTeamId(taskId, teamId);
}
/**
* 获取任务的提交统计信息
*/
@Override
public Map<String, Object> getSubmissionStatistics(Long taskId) {
return baseMapper.getSubmissionStatistics(taskId);
}
/**
* 材料上传
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean uploadMaterial(StglMaterialSubmissionBo bo) {
// 验证上传权限
Long userId = LoginHelper.getUserId();
if (!materialTaskService.validateUploadPermission(bo.getTaskId(), userId)) {
throw new RuntimeException("您没有权限上传材料到此任务");
}
// 检查是否已经提交过
StglMaterialSubmissionVo existingSubmission;
if (bo.getSubmissionType() == 1) {
// 个人提交
existingSubmission = queryByTaskIdAndUserId(bo.getTaskId(), userId);
} else {
// 团队提交
existingSubmission = queryByTaskIdAndTeamId(bo.getTaskId(), bo.getTeamId());
}
if (existingSubmission != null) {
// 更新已有记录
bo.setId(existingSubmission.getId());
return updateByBo(bo);
} else {
// 新增记录
bo.setUserId(userId);
return insertByBo(bo);
}
}
/**
* 审核材料
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean reviewSubmission(Long id, Integer reviewStatus, String reviewRemark) {
StglMaterialSubmission submission = new StglMaterialSubmission();
submission.setId(id);
submission.setReviewStatus(reviewStatus);
submission.setReviewTime(new Date());
submission.setReviewBy(LoginHelper.getUserId());
submission.setReviewRemark(reviewRemark);
boolean flag = baseMapper.updateById(submission) > 0;
if (flag) {
// 更新任务统计信息
StglMaterialSubmissionVo submissionVo = baseMapper.selectVoById(id);
if (submissionVo != null) {
materialTaskService.updateTaskStatistics(submissionVo.getTaskId());
}
}
return flag;
}
/**
* 批量审核材料
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean batchReviewSubmissions(Collection<Long> ids, Integer reviewStatus, String reviewRemark) {
Long reviewerId = LoginHelper.getUserId();
Date reviewTime = new Date();
boolean allSuccess = true;
for (Long id : ids) {
boolean success = reviewSubmission(id, reviewStatus, reviewRemark);
if (!success) {
allSuccess = false;
}
}
return allSuccess;
}
}
@@ -0,0 +1,237 @@
package org.dromara.stgl.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.stgl.domain.StglMaterialTask;
import org.dromara.stgl.domain.StglActivityRegistration;
import org.dromara.stgl.domain.bo.StglMaterialTaskBo;
import org.dromara.stgl.domain.bo.StglMaterialTaskQueryBo;
import org.dromara.stgl.domain.vo.StglMaterialTaskVo;
import org.dromara.stgl.mapper.StglMaterialTaskMapper;
import org.dromara.stgl.mapper.StglActivityRegistrationMapper;
import org.dromara.stgl.service.IStglMaterialTaskService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
* 材料收集任务Service业务层处理
*
* @author ruoyi
* @date 2025-01-03
*/
@RequiredArgsConstructor
@Service
public class StglMaterialTaskServiceImpl extends ServiceImpl<StglMaterialTaskMapper, StglMaterialTask> implements IStglMaterialTaskService {
private final StglMaterialTaskMapper baseMapper;
private final StglActivityRegistrationMapper activityRegistrationMapper;
/**
* 查询材料收集任务
*/
@Override
public StglMaterialTaskVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询材料收集任务列表
*/
@Override
public TableDataInfo<StglMaterialTaskVo> queryPageList(StglMaterialTaskQueryBo queryBo, PageQuery pageQuery) {
Page<StglMaterialTaskVo> page = baseMapper.selectVoPage(pageQuery.build(), queryBo);
return TableDataInfo.build(page);
}
/**
* 查询材料收集任务列表
*/
@Override
public List<StglMaterialTaskVo> queryList(StglMaterialTaskQueryBo queryBo) {
return baseMapper.selectVoList(queryBo);
}
/**
* 新增材料收集任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(StglMaterialTaskBo bo) {
StglMaterialTask add = MapstructUtils.convert(bo, StglMaterialTask.class);
// 设置默认值
if (add.getTaskStatus() == null) {
add.setTaskStatus(0); // 默认关闭状态
}
if (add.getRoundNumber() == null) {
add.setRoundNumber(1); // 默认第一轮
}
if (add.getFileSizeLimit() == null) {
add.setFileSizeLimit(10); // 默认10MB
}
if (add.getFileCountLimit() == null) {
add.setFileCountLimit(5); // 默认5个文件
}
// 自动生成任务名称(如果为空)
if (StringUtils.isBlank(add.getTaskName())) {
add.setTaskName("材料收集任务-" + System.currentTimeMillis());
}
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
// 更新统计信息
updateTaskStatistics(add.getId());
}
return flag;
}
/**
* 修改材料收集任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(StglMaterialTaskBo bo) {
StglMaterialTask update = MapstructUtils.convert(bo, StglMaterialTask.class);
validEntityBeforeSave(update);
boolean flag = baseMapper.updateById(update) > 0;
if (flag) {
// 更新统计信息
updateTaskStatistics(update.getId());
}
return flag;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(StglMaterialTask entity) {
// 校验活动是否存在
if (entity.getActivityId() != null) {
// 这里可以添加对活动存在性的校验
}
// 校验截止时间不能早于当前时间
if (entity.getDeadline() != null && entity.getDeadline().before(new Date())) {
throw new RuntimeException("截止时间不能早于当前时间");
}
// 校验文件大小限制
if (entity.getFileSizeLimit() != null && entity.getFileSizeLimit() <= 0) {
throw new RuntimeException("文件大小限制必须大于0");
}
// 校验文件数量限制
if (entity.getFileCountLimit() != null && entity.getFileCountLimit() <= 0) {
throw new RuntimeException("文件数量限制必须大于0");
}
}
/**
* 批量删除材料收集任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 校验是否存在关联的提交记录
for (Long id : ids) {
// 这里可以添加校验逻辑
}
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 更新任务状态
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateTaskStatus(Long id, Integer taskStatus) {
return baseMapper.updateTaskStatus(id, taskStatus) > 0;
}
/**
* 查询用户可上传的材料收集任务
*/
@Override
public List<StglMaterialTaskVo> queryUploadableTasksByUser(Long userId, Long activityId) {
return baseMapper.selectUploadableTasksByUser(userId, activityId);
}
/**
* 更新任务统计信息
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateTaskStatistics(Long taskId) {
return baseMapper.updateTaskStatistics(taskId) > 0;
}
/**
* 查询活动的材料收集任务
*/
@Override
public List<StglMaterialTaskVo> queryTasksByActivityId(Long activityId) {
return baseMapper.selectTasksByActivityId(activityId);
}
/**
* 验证用户是否有权限上传材料
*/
@Override
public Boolean validateUploadPermission(Long taskId, Long userId) {
// 查询任务信息
StglMaterialTaskVo task = baseMapper.selectVoById(taskId);
if (task == null) {
return false;
}
// 检查任务状态
if (task.getTaskStatus() != 1) {
return false;
}
// 检查截止时间
if (task.getDeadline() != null && task.getDeadline().before(new Date())) {
return false;
}
// 检查用户是否已报名且审核通过
LambdaQueryWrapper<StglActivityRegistration> registrationWrapper = Wrappers.lambdaQuery();
registrationWrapper.eq(StglActivityRegistration::getActivityId, task.getActivityId())
.eq(StglActivityRegistration::getUserId, userId)
.eq(StglActivityRegistration::getApprovalStatus, 1); // 审核通过
return activityRegistrationMapper.selectCount(registrationWrapper) > 0;
}
/**
* 根据活动名称模糊查询活动列表(用于选择器)
*/
@Override
public List<StglMaterialTaskVo> queryActivityOptions(String activityName) {
StglMaterialTaskQueryBo queryBo = new StglMaterialTaskQueryBo();
queryBo.setActivityName(activityName);
return baseMapper.selectVoList(queryBo);
}
}
@@ -8,6 +8,7 @@ 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 lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.dromara.stgl.domain.bo.StglMemberBo;
@@ -15,12 +16,19 @@ 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 org.dromara.system.service.ISysUserService;
import cn.hutool.core.collection.CollUtil;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.core.domain.model.LoginUser;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Date;
import java.util.stream.Collectors;
import java.util.Date;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
/**
* 社团成员Service业务层处理
@@ -28,11 +36,13 @@ import java.util.stream.Collectors;
* @author Cursor AI
* @date 2025-01-15
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class StglMemberServiceImpl implements IStglMemberService {
private final StglMemberMapper baseMapper;
private final ISysUserService userService;
/**
* 查询社团成员
@@ -42,7 +52,7 @@ public class StglMemberServiceImpl implements IStglMemberService {
*/
@Override
public StglMemberVo queryById(Long id){
return baseMapper.selectVoById(id);
return baseMapper.selectMemberWithUserInfoById(id);
}
/**
@@ -54,9 +64,50 @@ public class StglMemberServiceImpl implements IStglMemberService {
*/
@Override
public TableDataInfo<StglMemberVo> queryPageList(StglMemberBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<StglMember> lqw = buildQueryWrapper(bo);
Page<StglMemberVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
log.info("查询参数: memberType={}, relationId={}, studentNo={}, studentName={}, roleType={}, status={}, clubName={}, teamName={}",
bo.getMemberType(), bo.getRelationId(), bo.getStudentNo(), bo.getStudentName(),
bo.getRoleType(), bo.getStatus(), bo.getClubName(), bo.getTeamName());
// 应用权限过滤
bo = applyPermissionFilter(bo);
log.info("权限过滤后参数: memberType={}, relationId={}, studentNo={}, studentName={}, roleType={}, status={}, clubName={}, teamName={}",
bo.getMemberType(), bo.getRelationId(), bo.getStudentNo(), bo.getStudentName(),
bo.getRoleType(), bo.getStatus(), bo.getClubName(), bo.getTeamName());
// 使用自定义查询获取包含用户信息的成员列表
List<StglMemberVo> allMembers = baseMapper.selectMemberWithUserInfo(
bo.getMemberType(),
bo.getRelationId(),
bo.getStudentNo(),
bo.getStudentName(),
bo.getRoleType(),
bo.getStatus(),
bo.getClubName(),
bo.getTeamName(),
bo.getUserId()
);
log.info("查询结果: total={}", allMembers.size());
// 手动分页处理
int total = allMembers.size();
int pageNum = pageQuery.getPageNum();
int pageSize = pageQuery.getPageSize();
int startIndex = (pageNum - 1) * pageSize;
int endIndex = Math.min(startIndex + pageSize, total);
List<StglMemberVo> pageMembers = startIndex < total ?
allMembers.subList(startIndex, endIndex) : List.of();
// 构建分页结果
TableDataInfo<StglMemberVo> dataTable = new TableDataInfo<>();
dataTable.setCode(200);
dataTable.setMsg("查询成功");
dataTable.setRows(pageMembers);
dataTable.setTotal(total);
return dataTable;
}
/**
@@ -67,8 +118,21 @@ public class StglMemberServiceImpl implements IStglMemberService {
*/
@Override
public List<StglMemberVo> queryList(StglMemberBo bo) {
LambdaQueryWrapper<StglMember> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
// 应用权限过滤
bo = applyPermissionFilter(bo);
// 使用自定义查询获取包含用户信息的成员列表
return baseMapper.selectMemberWithUserInfo(
bo.getMemberType(),
bo.getRelationId(),
bo.getStudentNo(),
bo.getStudentName(),
bo.getRoleType(),
bo.getStatus(),
bo.getClubName(),
bo.getTeamName(),
bo.getUserId()
);
}
private LambdaQueryWrapper<StglMember> buildQueryWrapper(StglMemberBo bo) {
@@ -141,7 +205,7 @@ public class StglMemberServiceImpl implements IStglMemberService {
entity.setJoinTime(new Date());
}
if (entity.getStatus() == null) {
entity.setStatus(1);
entity.setStatus(2); // 默认为已加入状态(stgl_member_status字典)
}
if (entity.getRoleType() == null) {
entity.setRoleType(3); // 默认为普通成员
@@ -204,13 +268,7 @@ public class StglMemberServiceImpl implements IStglMemberService {
*/
@Override
public Boolean checkMemberExists(Integer memberType, Long relationId, Long userId) {
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
lqw.eq(StglMember::getMemberType, memberType);
lqw.eq(StglMember::getRelationId, relationId);
lqw.eq(StglMember::getUserId, userId);
lqw.eq(StglMember::getStatus, 1);
long count = baseMapper.selectCount(lqw);
return count > 0;
return baseMapper.checkMemberExists(memberType, relationId, userId);
}
/**
@@ -233,7 +291,7 @@ public class StglMemberServiceImpl implements IStglMemberService {
member.setUserId(userId);
member.setRoleType(roleType != null ? roleType : 3);
member.setJoinTime(now);
member.setStatus(1);
member.setStatus(2); // 已加入状态(stgl_member_status字典)
return member;
}).collect(Collectors.toList());
@@ -255,6 +313,36 @@ public class StglMemberServiceImpl implements IStglMemberService {
return baseMapper.updateById(member) > 0;
}
/**
* 审核成员申请
*
* @param id 成员ID
* @param approved 是否通过(true-通过,false-拒绝)
* @return 是否审核成功
*/
@Override
public Boolean approveMember(Long id, Boolean approved) {
StglMember member = baseMapper.selectById(id);
if (member == null) {
throw new RuntimeException("成员记录不存在");
}
if (member.getStatus() != 0) {
throw new RuntimeException("该申请已审核过,无法重复审核");
}
// 更新成员状态
StglMember updateMember = new StglMember();
updateMember.setId(id);
if (approved) {
updateMember.setStatus(2); // 已加入状态(stgl_member_status字典)
} else {
updateMember.setStatus(3); // 已驳回状态(stgl_member_status字典)
}
return baseMapper.updateById(updateMember) > 0;
}
/**
* 退出社团/队伍
*
@@ -265,8 +353,273 @@ public class StglMemberServiceImpl implements IStglMemberService {
public Boolean quitMember(Long id) {
StglMember member = new StglMember();
member.setId(id);
member.setStatus(0);
member.setStatus(4); // 已退出状态(stgl_member_status字典)
return baseMapper.updateById(member) > 0;
}
/**
* 导入成员数据
*
* @param memberList 成员列表
* @param updateSupport 是否支持更新
* @param operName 操作人名称
* @param memberType 成员类型
* @return 导入结果信息
*/
@Override
public String importMember(List<StglMemberVo> memberList, Boolean updateSupport, String operName, Integer memberType) {
if (memberList == null || memberList.isEmpty()) {
return "导入数据为空";
}
int successNum = 0;
int failureNum = 0;
StringBuilder successMsg = new StringBuilder();
StringBuilder failureMsg = new StringBuilder();
for (StglMemberVo memberVo : memberList) {
try {
// 设置成员类型
memberVo.setMemberType(memberType);
// 检查必要字段
if (StringUtils.isBlank(memberVo.getStudentNo())) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、学号不能为空");
continue;
}
// 转换为Bo对象
StglMemberBo memberBo = new StglMemberBo();
memberBo.setMemberType(memberType);
memberBo.setStudentNo(memberVo.getStudentNo());
memberBo.setStudentName(memberVo.getStudentName());
memberBo.setRelationId(memberVo.getRelationId());
memberBo.setRoleType(memberVo.getRoleType() != null ? memberVo.getRoleType() : 1); // 默认普通成员
memberBo.setStatus(memberVo.getStatus() != null ? memberVo.getStatus() : 1); // 默认正常状态
memberBo.setJoinTime(memberVo.getJoinTime() != null ? memberVo.getJoinTime() : new Date());
// 检查是否已存在
LambdaQueryWrapper<StglMember> wrapper = Wrappers.lambdaQuery();
wrapper.eq(StglMember::getMemberType, memberType)
.eq(StglMember::getStudentNo, memberVo.getStudentNo())
.eq(StglMember::getRelationId, memberVo.getRelationId());
StglMember existingMember = baseMapper.selectOne(wrapper);
if (existingMember != null) {
if (updateSupport) {
// 更新现有记录
memberBo.setId(existingMember.getId());
if (updateByBo(memberBo)) {
successNum++;
successMsg.append("<br/>").append(successNum).append("、学号 ").append(memberVo.getStudentNo()).append(" 更新成功");
} else {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(memberVo.getStudentNo()).append(" 更新失败");
}
} else {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(memberVo.getStudentNo()).append(" 已存在");
}
} else {
// 新增记录
if (insertByBo(memberBo)) {
successNum++;
successMsg.append("<br/>").append(successNum).append("、学号 ").append(memberVo.getStudentNo()).append(" 导入成功");
} else {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(memberVo.getStudentNo()).append(" 导入失败");
}
}
} catch (Exception e) {
failureNum++;
String msg = "<br/>" + failureNum + "、学号 " + memberVo.getStudentNo() + " 导入失败:";
failureMsg.append(msg).append(e.getMessage());
}
}
if (failureNum > 0) {
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
throw new RuntimeException(failureMsg.toString());
} else {
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
}
return successMsg.toString();
}
/**
* 获取志愿者成员统计信息
*
* @return 统计信息
*/
@Override
public Object getVolunteerMemberStats() {
// 应用权限过滤查询所有志愿者成员
StglMemberBo bo = new StglMemberBo();
bo.setMemberType(2); // 志愿者成员
bo = applyPermissionFilter(bo);
List<StglMemberVo> allMembers = baseMapper.selectMemberWithUserInfo(
bo.getMemberType(),
bo.getRelationId(),
null, // studentNo
null, // studentName
null, // roleType
null, // status
null, // clubName
null, // teamName
bo.getUserId()
);
// 基于权限过滤后的数据进行统计
long totalCount = allMembers.size();
long activeCount = allMembers.stream()
.mapToLong(member -> member.getStatus() != null && member.getStatus() == 2 ? 1 : 0)
.sum();
long pendingCount = allMembers.stream()
.mapToLong(member -> member.getStatus() != null && member.getStatus() == 1 ? 1 : 0)
.sum();
Map<String, Object> stats = new HashMap<>();
stats.put("totalCount", totalCount);
stats.put("activeCount", activeCount);
stats.put("pendingCount", pendingCount);
stats.put("inactiveCount", totalCount - activeCount - pendingCount);
return stats;
}
/**
* 批量分配队伍
*
* @param ids 成员ID列表
* @param relationId 队伍ID
* @param memberType 成员类型
* @return 是否分配成功
*/
@Override
public Boolean batchAssignTeam(List<Long> ids, Long relationId, Integer memberType) {
if (CollUtil.isEmpty(ids) || relationId == null) {
return false;
}
// 批量更新成员的队伍分配
List<StglMember> members = new ArrayList<>();
for (Long id : ids) {
StglMember member = new StglMember();
member.setId(id);
member.setRelationId(relationId);
member.setMemberType(memberType);
members.add(member);
}
return baseMapper.updateBatchById(members);
}
/**
* 应用权限过滤
* 根据用户角色过滤数据访问权限
* - stgl_volunteer_admin: 可以查看所有志愿者成员
* - stgl_volunteer_captain: 只能查看自己担任队长的队伍成员
*
* @param bo 查询条件
* @return 过滤后的查询条件
*/
private StglMemberBo applyPermissionFilter(StglMemberBo bo) {
// 只对志愿者成员查询应用权限过滤
if (bo.getMemberType() == null || !bo.getMemberType().equals(2)) {
return bo;
}
try {
// 获取当前登录用户信息
Long currentUserId = LoginHelper.getUserId();
// 首先检查超级管理员权限
if (LoginHelper.isSuperAdmin(currentUserId)) {
return bo; // 超级管理员可以查看所有数据
}
LoginUser loginUser = LoginHelper.getLoginUser();
if (loginUser == null) {
bo.setRelationId(-1L);
return bo;
}
Set<String> roles = loginUser.getRolePermission();
// 如果是志愿者管理员,可以查看所有数据
if (roles.contains("stgl_volunteer_admin")) {
return bo; // 不做任何过滤
}
// 如果是志愿者队长,只能查看自己担任队长的队伍成员
if (roles.contains("stgl_volunteer_captain")) {
// 查询用户担任队长的队伍ID列表
List<Long> captainTeamIds = getCaptainTeamIds(currentUserId);
if (captainTeamIds.isEmpty()) {
// 如果用户不是任何队伍的队长,返回空结果
bo.setRelationId(-1L); // 设置一个不存在的关联ID
} else if (bo.getRelationId() == null) {
// 如果没有指定特定队伍,限制查询范围为该用户担任队长的队伍
// 由于查询接口限制,我们只能返回第一个队伍的数据
// 在实际应用中,前端应该明确指定要查询的队伍ID
bo.setRelationId(captainTeamIds.get(0));
} else {
// 如果指定了队伍ID,验证用户是否有权限访问该队伍
if (!captainTeamIds.contains(bo.getRelationId())) {
bo.setRelationId(-1L); // 设置一个不存在的关联ID
}
}
return bo;
}
// 如果用户没有相关角色权限,返回空结果
bo.setRelationId(-1L);
return bo;
} catch (Exception e) {
// 如果获取用户信息失败,返回空结果
bo.setRelationId(-1L);
return bo;
}
}
/**
* 获取用户担任队长的队伍ID列表
*
* @param userId 用户ID
* @return 队伍ID列表
*/
private List<Long> getCaptainTeamIds(Long userId) {
try {
// 查询用户作为队长的志愿者队伍
StglMemberBo captainBo = new StglMemberBo();
captainBo.setMemberType(2); // 志愿者成员
captainBo.setRoleType(0); // 队长角色
List<StglMemberVo> captainRecords = baseMapper.selectMemberWithUserInfo(
captainBo.getMemberType(),
null, // relationId 不限制
null, // studentNo
null, // studentName
captainBo.getRoleType(),
null, // status
null, // clubName
null, // teamName
userId // userId 权限过滤
);
return captainRecords.stream()
.map(StglMemberVo::getRelationId)
.filter(relationId -> relationId != null)
.distinct()
.collect(Collectors.toList());
} catch (Exception e) {
return new ArrayList<>();
}
}
}
@@ -0,0 +1,136 @@
package org.dromara.stgl.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.stgl.domain.StglActivityRating;
import org.dromara.stgl.domain.bo.ActivityRatingBo;
import org.dromara.stgl.domain.vo.MyActivityVo;
import org.dromara.stgl.domain.vo.MyClubVo;
import org.dromara.stgl.domain.vo.MyRegistrationVo;
import org.dromara.stgl.domain.vo.MyVolunteerTeamVo;
import org.dromara.stgl.mapper.StglActivityRatingMapper;
import org.dromara.stgl.mapper.StglMyMapper;
import org.dromara.stgl.service.IStglMyService;
import org.dromara.system.service.ISysUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
/**
* 我的报名服务实现
*
* @author ruoyi
* @date 2025-01-01
*/
@RequiredArgsConstructor
@Service
public class StglMyServiceImpl implements IStglMyService {
private final StglMyMapper stglMyMapper;
private final StglActivityRatingMapper stglActivityRatingMapper;
private final ISysUserService sysUserService;
/**
* 查询我参与的社团列表
*/
@Override
public List<MyClubVo> queryMyClubs() {
Long userId = LoginHelper.getUserId();
return stglMyMapper.selectMyClubs(userId);
}
/**
* 查询我参与的志愿团队列表
*/
@Override
public List<MyVolunteerTeamVo> queryMyVolunteerTeams() {
Long userId = LoginHelper.getUserId();
String tenantId = LoginHelper.getTenantId();
return stglMyMapper.selectMyVolunteerTeams(userId, tenantId);
}
/**
* 查询我报名的活动列表(带评分状态)
*/
@Override
public List<MyActivityVo> queryMyActivities() {
Long userId = LoginHelper.getUserId();
String tenantId = LoginHelper.getTenantId();
return stglMyMapper.selectMyActivities(userId, tenantId);
}
/**
* 分页查询我的报名记录
*/
@Override
public TableDataInfo<MyRegistrationVo> queryMyRegistrations(PageQuery pageQuery, String registrationType) {
Long userId = LoginHelper.getUserId();
Page<MyRegistrationVo> result = stglMyMapper.selectMyRegistrationsPage(pageQuery.build(), userId, registrationType);
return TableDataInfo.build(result);
}
/**
* 对活动进行评分
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean rateActivity(Long activityId, ActivityRatingBo ratingBo) {
Long userId = LoginHelper.getUserId();
// 检查是否已经评分
Long existCount = stglActivityRatingMapper.countByActivityIdAndUserId(activityId, userId);
if (existCount > 0) {
throw new RuntimeException("您已经对此活动进行过评分");
}
// 检查用户是否可以评分(是否报名了该活动且活动已结束)
if (!canRateActivity(activityId)) {
throw new RuntimeException("您暂时无法对此活动进行评分");
}
// 获取用户信息
var userInfo = sysUserService.selectUserById(userId);
// 构建评分记录
StglActivityRating rating = MapstructUtils.convert(ratingBo, StglActivityRating.class);
rating.setActivityId(activityId);
rating.setUserId(userId);
rating.setStudentNo(userInfo.getUserName()); // 使用用户名作为学号
rating.setStudentName(userInfo.getNickName());
// 计算综合评分(三项评分平均值)
double avgScore = (ratingBo.getContentScore() + ratingBo.getOrganizationScore() + ratingBo.getExperienceScore()) / 3.0;
rating.setRatingScore((int) Math.round(avgScore));
rating.setRatingTime(LocalDateTime.now());
return stglActivityRatingMapper.insert(rating) > 0;
}
/**
* 检查用户是否可以对活动评分
*/
@Override
public Boolean canRateActivity(Long activityId) {
Long userId = LoginHelper.getUserId();
String tenantId = LoginHelper.getTenantId();
// 查询用户的活动信息
List<MyActivityVo> activities = stglMyMapper.selectMyActivities(userId, tenantId);
// 查找指定的活动
return activities.stream()
.filter(activity -> activity.getId().equals(activityId))
.findFirst()
.map(MyActivityVo::getCanRate)
.orElse(false);
}
}
@@ -0,0 +1,819 @@
package org.dromara.stgl.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.stgl.domain.StglVolunteerTeam;
import org.dromara.stgl.domain.StglMember;
import org.dromara.stgl.domain.bo.StglVolunteerTeamBo;
import org.dromara.stgl.domain.bo.StglVolunteerTeamApplicationBo;
import org.dromara.stgl.domain.vo.StglVolunteerTeamVo;
import org.dromara.stgl.mapper.StglVolunteerTeamMapper;
import org.dromara.stgl.mapper.StglMemberMapper;
import org.dromara.stgl.service.IStglVolunteerTeamService;
import org.dromara.xg.mapper.XgStudentMsgMapper;
import org.dromara.xg.domain.vo.XgStudentMsgVo;
import org.dromara.xg.domain.XgStudentMsg;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.domain.SysUser;
import org.dromara.common.satoken.utils.LoginHelper;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
* 志愿者队伍Service业务层处理
*
* @author Cursor AI
* @date 2025-01-07
*/
@RequiredArgsConstructor
@Service
public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
private final StglVolunteerTeamMapper baseMapper;
private final StglMemberMapper memberMapper;
private final XgStudentMsgMapper studentMsgMapper;
private final SysUserMapper userMapper;
/**
* 查询志愿者队伍
*/
@Override
public StglVolunteerTeamVo queryById(Long id) {
StglVolunteerTeamVo vo = baseMapper.selectVoById(id);
if (vo != null) {
vo.setCurrentMemberCount(calculateCurrentMemberCount(id));
}
return vo;
}
/**
* 查询志愿者队伍分页列表
*/
@Override
public TableDataInfo<StglVolunteerTeamVo> queryPageList(StglVolunteerTeamBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<StglVolunteerTeam> lqw = buildQueryWrapper(bo);
Page<StglVolunteerTeamVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
// 计算每个队伍的当前成员数量
for (StglVolunteerTeamVo vo : result.getRecords()) {
vo.setCurrentMemberCount(calculateCurrentMemberCount(vo.getId()));
}
return TableDataInfo.build(result);
}
/**
* 查询志愿者队伍列表
*/
@Override
public List<StglVolunteerTeamVo> queryList(StglVolunteerTeamBo bo) {
LambdaQueryWrapper<StglVolunteerTeam> lqw = buildQueryWrapper(bo);
List<StglVolunteerTeamVo> list = baseMapper.selectVoList(lqw);
// 计算每个队伍的当前成员数量
for (StglVolunteerTeamVo vo : list) {
vo.setCurrentMemberCount(calculateCurrentMemberCount(vo.getId()));
}
return list;
}
private LambdaQueryWrapper<StglVolunteerTeam> buildQueryWrapper(StglVolunteerTeamBo bo) {
LambdaQueryWrapper<StglVolunteerTeam> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getTeamName()), StglVolunteerTeam::getTeamName, bo.getTeamName());
lqw.eq(StringUtils.isNotBlank(bo.getTeamType()), StglVolunteerTeam::getTeamType, bo.getTeamType());
lqw.like(StringUtils.isNotBlank(bo.getLeaderName()), StglVolunteerTeam::getLeaderName, bo.getLeaderName());
lqw.eq(StringUtils.isNotBlank(bo.getLeaderStudentNo()), StglVolunteerTeam::getLeaderStudentNo, bo.getLeaderStudentNo());
lqw.eq(ObjectUtil.isNotNull(bo.getLeaderUserId()), StglVolunteerTeam::getLeaderUserId, bo.getLeaderUserId());
lqw.like(StringUtils.isNotBlank(bo.getAdvisorName()), StglVolunteerTeam::getAdvisorName, bo.getAdvisorName());
lqw.eq(ObjectUtil.isNotNull(bo.getStatus()), StglVolunteerTeam::getStatus, bo.getStatus());
lqw.ge(ObjectUtil.isNotNull(bo.getEstablishDate()), StglVolunteerTeam::getEstablishDate, bo.getEstablishDate());
// 数据权限过滤:志愿者队长角色只能看到自己作为队长的队伍
if (StpUtil.hasRole("stgl_volunteer_captain")) {
Long currentUserId = LoginHelper.getUserId();
if (currentUserId != null) {
lqw.eq(StglVolunteerTeam::getLeaderUserId, currentUserId);
}
}
lqw.orderByDesc(StglVolunteerTeam::getCreateTime);
return lqw;
}
/**
* 构建报名大厅查询条件(无数据权限限制)
*/
private LambdaQueryWrapper<StglVolunteerTeam> buildRegistrationQueryWrapper(StglVolunteerTeamBo bo) {
LambdaQueryWrapper<StglVolunteerTeam> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getTeamName()), StglVolunteerTeam::getTeamName, bo.getTeamName());
lqw.eq(StringUtils.isNotBlank(bo.getTeamType()), StglVolunteerTeam::getTeamType, bo.getTeamType());
lqw.like(StringUtils.isNotBlank(bo.getLeaderName()), StglVolunteerTeam::getLeaderName, bo.getLeaderName());
lqw.eq(StringUtils.isNotBlank(bo.getLeaderStudentNo()), StglVolunteerTeam::getLeaderStudentNo, bo.getLeaderStudentNo());
lqw.eq(ObjectUtil.isNotNull(bo.getLeaderUserId()), StglVolunteerTeam::getLeaderUserId, bo.getLeaderUserId());
lqw.like(StringUtils.isNotBlank(bo.getAdvisorName()), StglVolunteerTeam::getAdvisorName, bo.getAdvisorName());
lqw.eq(ObjectUtil.isNotNull(bo.getStatus()), StglVolunteerTeam::getStatus, bo.getStatus());
lqw.ge(ObjectUtil.isNotNull(bo.getEstablishDate()), StglVolunteerTeam::getEstablishDate, bo.getEstablishDate());
// 注意:报名大厅不应用数据权限过滤,所有用户都能看到所有队伍
lqw.orderByDesc(StglVolunteerTeam::getCreateTime);
return lqw;
}
/**
* 新增志愿者队伍
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(StglVolunteerTeamBo bo) {
StglVolunteerTeam add = MapstructUtils.convert(bo, StglVolunteerTeam.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
// 自动创建队长的成员记录
createLeaderMemberRecord(add);
}
return flag;
}
/**
* 修改志愿者队伍
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(StglVolunteerTeamBo bo) {
StglVolunteerTeam update = MapstructUtils.convert(bo, StglVolunteerTeam.class);
validEntityBeforeSave(update);
// 更新队伍基本信息
boolean updateResult = baseMapper.updateById(update) > 0;
if (updateResult) {
// 同步更新队长的成员记录
syncLeaderInMembers(update);
}
return updateResult;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(StglVolunteerTeam entity) {
// 校验队伍名称唯一性
LambdaQueryWrapper<StglVolunteerTeam> lqw = Wrappers.lambdaQuery();
lqw.eq(StglVolunteerTeam::getTeamName, entity.getTeamName());
if (ObjectUtil.isNotNull(entity.getId())) {
lqw.ne(StglVolunteerTeam::getId, entity.getId());
}
boolean exists = baseMapper.exists(lqw);
if (exists) {
throw new RuntimeException("队伍名称已存在,请修改后重试");
}
// 校验队长学号唯一性(一个学生只能担任一个队伍的队长)
LambdaQueryWrapper<StglVolunteerTeam> leaderLqw = Wrappers.lambdaQuery();
leaderLqw.eq(StglVolunteerTeam::getLeaderStudentNo, entity.getLeaderStudentNo());
if (ObjectUtil.isNotNull(entity.getId())) {
leaderLqw.ne(StglVolunteerTeam::getId, entity.getId());
}
boolean leaderExists = baseMapper.exists(leaderLqw);
if (leaderExists) {
throw new RuntimeException("该学生已担任其他队伍队长,请更换队长或联系管理员");
}
}
/**
* 自动创建队长的成员记录
*
* @param team 志愿者队伍信息
*/
private void createLeaderMemberRecord(StglVolunteerTeam team) {
if (StringUtils.isNotBlank(team.getLeaderStudentNo())) {
try {
// 检查是否已存在队长成员记录
boolean exists = checkLeaderMemberExists(team.getId(), team.getLeaderStudentNo());
if (exists) {
System.out.println("队长成员记录已存在,跳过创建: " + team.getLeaderName() + "(" + team.getLeaderStudentNo() + ")");
return;
}
StglMember leader = new StglMember();
leader.setMemberType(2); // 志愿者成员
leader.setRelationId(team.getId());
leader.setUserId(team.getLeaderUserId());
leader.setStudentNo(team.getLeaderStudentNo());
leader.setStudentName(team.getLeaderName());
leader.setRoleType(0); // 队长 (stgl_volunteer_role=0)
leader.setJoinTime(new Date());
leader.setStatus(2); // 已加入状态
leader.setRemark("志愿者队伍创建时自动添加");
// 如果队伍信息中没有leader_user_id,根据学号查找用户ID
if (leader.getUserId() == null && StringUtils.isNotBlank(team.getLeaderStudentNo())) {
Long leaderUserId = findUserIdByStudentNo(team.getLeaderStudentNo());
if (leaderUserId != null) {
leader.setUserId(leaderUserId);
}
}
memberMapper.insert(leader);
System.out.println("成功创建队长成员记录: " + team.getLeaderName() + "(" + team.getLeaderStudentNo() + ")");
} catch (Exception e) {
System.err.println("创建队长成员记录失败: " + e.getMessage());
e.printStackTrace();
// 记录错误但不中断主流程
}
}
}
/**
* 同步更新队长的成员记录
* 在队伍修改时调用,确保队长变更能同步到成员表
*
* @param team 更新后的队伍信息
*/
private void syncLeaderInMembers(StglVolunteerTeam team) {
try {
// 1. 删除现有的队长记录(roleType = 0)
LambdaQueryWrapper<StglMember> deleteWrapper = Wrappers.lambdaQuery();
deleteWrapper.eq(StglMember::getRelationId, team.getId())
.eq(StglMember::getMemberType, 2) // 志愿者成员
.eq(StglMember::getRoleType, 0); // 队长角色
memberMapper.delete(deleteWrapper);
// 2. 创建新的队长成员记录
if (StringUtils.isNotBlank(team.getLeaderStudentNo())) {
StglMember leader = new StglMember();
leader.setMemberType(2); // 志愿者成员
leader.setRelationId(team.getId());
leader.setUserId(team.getLeaderUserId());
leader.setStudentNo(team.getLeaderStudentNo());
leader.setStudentName(team.getLeaderName());
leader.setRoleType(0); // 队长 (stgl_volunteer_role=0)
leader.setJoinTime(new Date());
leader.setStatus(2); // 已加入状态
leader.setRemark("志愿者队伍修改时同步更新");
// 如果队伍信息中没有leader_user_id,根据学号查找用户ID
if (leader.getUserId() == null && StringUtils.isNotBlank(team.getLeaderStudentNo())) {
Long leaderUserId = findUserIdByStudentNo(team.getLeaderStudentNo());
if (leaderUserId != null) {
leader.setUserId(leaderUserId);
}
}
memberMapper.insert(leader);
System.out.println("队长成员记录同步完成,队伍ID: " + team.getId());
}
} catch (Exception e) {
System.err.println("同步队长成员记录失败: " + e.getMessage());
e.printStackTrace();
throw new RuntimeException("同步队长成员记录失败", e);
}
}
/**
* 检查指定队伍中是否已存在指定学号的队长成员记录
*
* @param teamId 队伍ID
* @param studentNo 学号
* @return 是否存在
*/
private boolean checkLeaderMemberExists(Long teamId, String studentNo) {
LambdaQueryWrapper<StglMember> query = Wrappers.lambdaQuery();
query.eq(StglMember::getMemberType, 2); // 志愿者成员
query.eq(StglMember::getRelationId, teamId); // 指定队伍
query.eq(StglMember::getStudentNo, studentNo); // 指定学号
query.eq(StglMember::getRoleType, 0); // 队长角色
query.eq(StglMember::getStatus, 2); // 已加入状态
return memberMapper.selectCount(query) > 0;
}
/**
* 根据学号查找用户ID
*
* @param studentNo 学号
* @return 用户ID
*/
private Long findUserIdByStudentNo(String studentNo) {
try {
if (StringUtils.isBlank(studentNo)) {
return null;
}
// 在xg_student_msg表中根据学号查找学生信息
// 该表的id字段即为用户ID(对应sys_user表的user_id)
LambdaQueryWrapper<XgStudentMsg> wrapper = Wrappers.lambdaQuery();
wrapper.eq(XgStudentMsg::getStudentNo, studentNo)
.last("LIMIT 1"); // 限制只返回一条记录
XgStudentMsg studentMsg = studentMsgMapper.selectOne(wrapper);
if (studentMsg != null) {
return studentMsg.getId(); // 返回学生的ID,即用户ID
}
} catch (Exception e) {
// 如果查询失败,记录日志但不抛出异常,允许创建没有userId的成员记录
System.err.println("根据学号 " + studentNo + " 查找用户ID失败: " + e.getMessage());
}
return null;
}
/**
* 批量删除志愿者队伍
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 删除前校验,检查是否有关联的志愿者记录
// 此处可以添加与志愿者成员表的关联校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 查询志愿者队伍可用选项列表
*/
@Override
public List<StglVolunteerTeamVo> queryAvailableOptions() {
LambdaQueryWrapper<StglVolunteerTeam> lqw = Wrappers.lambdaQuery();
lqw.eq(StglVolunteerTeam::getStatus, 0); // 只查询正常状态的队伍(sys_normal_disable: 0=正常, 1=停用)
lqw.orderByAsc(StglVolunteerTeam::getTeamName);
return baseMapper.selectVoList(lqw);
}
/**
* 根据队长用户ID查询队伍
*/
@Override
public List<StglVolunteerTeamVo> queryByLeaderUserId(Long leaderUserId) {
LambdaQueryWrapper<StglVolunteerTeam> lqw = Wrappers.lambdaQuery();
lqw.eq(StglVolunteerTeam::getLeaderUserId, leaderUserId);
lqw.orderByDesc(StglVolunteerTeam::getCreateTime);
return baseMapper.selectVoList(lqw);
}
/**
* 根据队伍类型查询队伍列表
*/
@Override
public List<StglVolunteerTeamVo> queryByTeamType(String teamType) {
LambdaQueryWrapper<StglVolunteerTeam> lqw = Wrappers.lambdaQuery();
lqw.eq(StglVolunteerTeam::getTeamType, teamType);
lqw.eq(StglVolunteerTeam::getStatus, 1); // 只查询正常状态的队伍
lqw.orderByAsc(StglVolunteerTeam::getTeamName);
return baseMapper.selectVoList(lqw);
}
/**
* 启用/禁用志愿者队伍
*/
@Override
public Boolean updateStatus(Long id, Integer status) {
StglVolunteerTeam entity = new StglVolunteerTeam();
entity.setId(id);
entity.setStatus(status);
return baseMapper.updateById(entity) > 0;
}
/**
* 申请加入志愿者队伍
*/
@Override
public Boolean applyJoinVolunteerTeam(StglVolunteerTeamApplicationBo applicationBo) {
// 检查队伍是否存在且可报名
StglVolunteerTeam team = baseMapper.selectById(applicationBo.getTeamId());
if (team == null) {
throw new RuntimeException("志愿者队伍不存在");
}
if (team.getStatus() != 0) { // 遵循sys_normal_disable字典标准:0=正常,1=停用
throw new RuntimeException("该志愿者队伍暂停招募");
}
// 检查是否已经申请过
LambdaQueryWrapper<StglMember> memberLqw = Wrappers.lambdaQuery();
memberLqw.eq(StglMember::getMemberType, 2) // 2-志愿者
.eq(StglMember::getRelationId, applicationBo.getTeamId())
.eq(StglMember::getStudentNo, applicationBo.getStudentNo());
StglMember existingMember = memberMapper.selectOne(memberLqw);
if (existingMember != null) {
if (existingMember.getStatus() == 0) {
throw new RuntimeException("您的申请正在审核中,请勿重复申请");
} else if (existingMember.getStatus() == 1) {
throw new RuntimeException("您已是该志愿者队伍成员");
} else if (existingMember.getStatus() == 2) {
throw new RuntimeException("您的申请已被拒绝,如需重新申请请联系队长");
}
}
// 创建成员记录
StglMember member = new StglMember();
member.setMemberType(2); // 2-志愿者
member.setRelationId(applicationBo.getTeamId());
member.setUserId(LoginHelper.getUserId()); // 设置当前登录用户ID
member.setStudentName(applicationBo.getStudentName());
member.setStudentNo(applicationBo.getStudentNo());
member.setRoleType(1); // 1-队员(志愿者角色)
member.setStatus(0); // 0-待审核
member.setJoinTime(new Date());
// 只存储用户填写的申请理由
member.setRemark(applicationBo.getApplyReason());
// 保存成员记录
return memberMapper.insert(member) > 0;
}
/**
* 根据姓名搜索学生信息(用于队长选择)
*/
@Override
public List<XgStudentMsgVo> searchStudentByName(String name) {
LambdaQueryWrapper<XgStudentMsg> lqw = Wrappers.lambdaQuery();
lqw.like(XgStudentMsg::getName, name);
lqw.orderByAsc(XgStudentMsg::getName);
lqw.last("LIMIT 10"); // 限制返回数量
List<XgStudentMsg> students = studentMsgMapper.selectList(lqw);
return MapstructUtils.convert(students, XgStudentMsgVo.class);
}
/**
* 根据学号获取学生详细信息(用于自动填充)
*/
@Override
public XgStudentMsgVo getStudentByNo(String studentNo) {
LambdaQueryWrapper<XgStudentMsg> lqw = Wrappers.lambdaQuery();
lqw.eq(XgStudentMsg::getStudentNo, studentNo);
XgStudentMsg student = studentMsgMapper.selectOne(lqw);
return student != null ? MapstructUtils.convert(student, XgStudentMsgVo.class) : null;
}
/**
* 根据姓名搜索指导老师信息
*/
@Override
public List<SysUserVo> searchTeacherByName(String name) {
LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery();
lqw.like(SysUser::getNickName, name);
lqw.eq(SysUser::getDelFlag, "0");
lqw.eq(SysUser::getStatus, "0"); // 正常状态
lqw.orderByAsc(SysUser::getNickName);
lqw.last("LIMIT 10"); // 限制返回数量
List<SysUser> teachers = userMapper.selectList(lqw);
return MapstructUtils.convert(teachers, SysUserVo.class);
}
/**
* 根据用户ID获取教师详细信息(用于自动填充)
*/
@Override
public SysUserVo getTeacherById(Long userId) {
SysUser teacher = userMapper.selectById(userId);
return teacher != null ? MapstructUtils.convert(teacher, SysUserVo.class) : null;
}
/**
* 计算队伍当前成员数量
*/
private Integer calculateCurrentMemberCount(Long teamId) {
if (teamId == null) {
return 0;
}
LambdaQueryWrapper<StglMember> wrapper = Wrappers.lambdaQuery();
wrapper.eq(StglMember::getRelationId, teamId);
wrapper.eq(StglMember::getMemberType, 2); // 2表示志愿者队伍成员
wrapper.eq(StglMember::getStatus, 2); // 只统计已加入状态的成员
Long count = memberMapper.selectCount(wrapper);
return count != null ? count.intValue() : 0;
}
/**
* 修复所有已存在志愿者队伍的队长成员记录
* 为那些没有对应成员记录的队长补充成员记录
*
* @return 修复的记录数量
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Integer fixExistingTeamLeaderRecords() {
int fixedCount = 0;
// 查询所有正常状态的志愿者队伍
LambdaQueryWrapper<StglVolunteerTeam> teamQuery = Wrappers.lambdaQuery();
teamQuery.eq(StglVolunteerTeam::getStatus, 0); // 正常状态的队伍
List<StglVolunteerTeam> teams = baseMapper.selectList(teamQuery);
for (StglVolunteerTeam team : teams) {
// 检查并补充队长成员记录
if (StringUtils.isNotBlank(team.getLeaderStudentNo())) {
boolean leaderExists = checkLeaderMemberExists(team.getId(), team.getLeaderStudentNo());
if (!leaderExists) {
try {
StglMember leader = new StglMember();
leader.setMemberType(2); // 志愿者成员
leader.setRelationId(team.getId());
leader.setUserId(team.getLeaderUserId());
leader.setStudentNo(team.getLeaderStudentNo());
leader.setStudentName(team.getLeaderName());
leader.setRoleType(0); // 队长 (stgl_volunteer_role=0)
leader.setJoinTime(team.getCreateTime() != null ? team.getCreateTime() : new Date());
leader.setStatus(2); // 已加入状态
leader.setRemark("补充缺失的队长成员记录");
// 如果队伍信息中没有leader_user_id,根据学号查找用户ID
if (leader.getUserId() == null && StringUtils.isNotBlank(team.getLeaderStudentNo())) {
Long leaderUserId = findUserIdByStudentNo(team.getLeaderStudentNo());
if (leaderUserId != null) {
leader.setUserId(leaderUserId);
}
}
memberMapper.insert(leader);
fixedCount++;
System.out.println("补充队长成员记录: " + team.getLeaderName() + "(" + team.getLeaderStudentNo() + ") - 队伍: " + team.getTeamName());
} catch (Exception e) {
System.err.println("补充队长成员记录失败: " + team.getLeaderName() + "(" + team.getLeaderStudentNo() + ") - " + e.getMessage());
}
}
}
}
System.out.println("志愿者队伍队长成员记录修复完成,共修复: " + fixedCount + " 条记录");
return fixedCount;
}
/**
* 志愿者队伍转让
*
* @param teamId 队伍ID
* @param newLeaderUserId 新队长用户ID
* @return 是否转让成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean transferVolunteerTeam(Long teamId, Long newLeaderUserId) {
// 1. 获取队伍信息
StglVolunteerTeam team = baseMapper.selectById(teamId);
if (team == null) {
throw new RuntimeException("志愿者队伍不存在");
}
// 2. 获取新队长的学生信息
XgStudentMsg newLeaderStudent = studentMsgMapper.selectOne(
Wrappers.<XgStudentMsg>lambdaQuery()
.eq(XgStudentMsg::getId, newLeaderUserId)
.last("LIMIT 1")
);
if (newLeaderStudent == null) {
throw new RuntimeException("新队长学生信息不存在");
}
// 3. 检查新队长是否已经是其他队伍的队长
long existingTeamCount = baseMapper.selectCount(
Wrappers.<StglVolunteerTeam>lambdaQuery()
.eq(StglVolunteerTeam::getLeaderUserId, newLeaderUserId)
);
if (existingTeamCount > 0) {
throw new RuntimeException("该学生已经是其他志愿者队伍的队长");
}
// 4. 更新队伍信息
StglVolunteerTeam updateTeam = new StglVolunteerTeam();
updateTeam.setId(teamId);
updateTeam.setLeaderUserId(newLeaderUserId);
updateTeam.setLeaderName(newLeaderStudent.getName());
updateTeam.setUpdateBy(LoginHelper.getUserId());
updateTeam.setUpdateTime(new Date());
int updateResult = baseMapper.updateById(updateTeam);
if (updateResult <= 0) {
throw new RuntimeException("更新队伍信息失败");
}
// 5. 更新成员表
Long currentUserId = LoginHelper.getUserId();
// 5.1 查询原队长在成员表中的记录
StglMember oldLeaderMember = null;
if (currentUserId != null) {
oldLeaderMember = memberMapper.selectOne(
Wrappers.<StglMember>lambdaQuery()
.eq(StglMember::getMemberType, 2) // 志愿者队伍成员
.eq(StglMember::getRelationId, teamId)
.eq(StglMember::getRoleType, 0) // 队长角色
.eq(StglMember::getUserId, currentUserId) // 添加当前用户ID条件
.eq(StglMember::getStatus, 2) // 已加入状态
);
}
// 5.2 查询新队长在成员表中的记录
StglMember newLeaderMember = memberMapper.selectOne(
Wrappers.<StglMember>lambdaQuery()
.eq(StglMember::getMemberType, 2) // 志愿者队伍成员
.eq(StglMember::getRelationId, teamId)
.eq(StglMember::getUserId, newLeaderUserId)
);
// 5.3 更新原队长的成员状态为已退出
if (oldLeaderMember != null) {
StglMember updateOldLeader = new StglMember();
updateOldLeader.setId(oldLeaderMember.getId());
updateOldLeader.setStatus(4); // 已退出状态
updateOldLeader.setUpdateBy(LoginHelper.getUserId());
updateOldLeader.setUpdateTime(new Date());
memberMapper.updateById(updateOldLeader);
}
// 5.4 添加或更新新队长的成员记录
if (newLeaderMember != null) {
// 如果新队长已经是成员,更新角色和状态
StglMember updateNewLeader = new StglMember();
updateNewLeader.setId(newLeaderMember.getId());
updateNewLeader.setRoleType(0); // 队长角色
updateNewLeader.setStatus(2); // 已加入状态
updateNewLeader.setJoinTime(new Date());
updateNewLeader.setUpdateBy(LoginHelper.getUserId());
updateNewLeader.setUpdateTime(new Date());
int memberUpdateResult = memberMapper.updateById(updateNewLeader);
if (memberUpdateResult <= 0) {
throw new RuntimeException("更新新队长成员记录失败");
}
} else {
// 如果新队长不是成员,新增成员记录
StglMember newMember = new StglMember();
newMember.setMemberType(2); // 志愿者队伍成员
newMember.setRelationId(teamId);
newMember.setUserId(newLeaderUserId);
newMember.setStudentNo(newLeaderStudent.getStudentNo());
newMember.setStudentName(newLeaderStudent.getName());
newMember.setRoleType(0); // 队长角色
newMember.setJoinTime(new Date());
newMember.setStatus(2); // 已加入状态
newMember.setCreateBy(LoginHelper.getUserId());
newMember.setCreateTime(new Date());
int memberResult = memberMapper.insert(newMember);
if (memberResult <= 0) {
throw new RuntimeException("创建新队长成员记录失败");
}
}
return true;
}
/**
* 检查当前用户是否为志愿者队伍的队长
*
* @param teamId 队伍ID
* @param userId 用户ID
* @return 是否为队长
*/
@Override
public Boolean isTeamLeader(Long teamId, Long userId) {
if (teamId == null || userId == null) {
return false;
}
long count = baseMapper.selectCount(
Wrappers.<StglVolunteerTeam>lambdaQuery()
.eq(StglVolunteerTeam::getId, teamId)
.eq(StglVolunteerTeam::getLeaderUserId, userId)
);
return count > 0;
}
/**
* 查询志愿者队伍报名大厅分页列表(无数据权限限制)
*/
@Override
public TableDataInfo<StglVolunteerTeamVo> queryRegistrationPageList(StglVolunteerTeamBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<StglVolunteerTeam> lqw = buildRegistrationQueryWrapper(bo);
Page<StglVolunteerTeamVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
// 获取当前用户ID
Long currentUserId = null;
try {
currentUserId = LoginHelper.getUserId();
} catch (Exception e) {
// 如果获取不到用户ID,说明未登录,设置默认状态
}
// 计算每个队伍的当前成员数量和用户申请状态
for (StglVolunteerTeamVo vo : result.getRecords()) {
vo.setCurrentMemberCount(calculateCurrentMemberCount(vo.getId()));
// 查询当前用户在此队伍的申请状态
if (currentUserId != null) {
StglMember userMember = getUserMemberStatusInTeam(currentUserId, vo.getId());
if (userMember != null) {
vo.setUserApplicationStatus(userMember.getStatus());
// 状态为0(待审核)或1(审核中)时,表示已申请
vo.setHasApplied(userMember.getStatus() == 0 || userMember.getStatus() == 1);
// 状态为2时,表示已加入
vo.setHasJoined(userMember.getStatus() == 2);
} else {
// 用户未申请此队伍
vo.setUserApplicationStatus(null);
vo.setHasApplied(false);
vo.setHasJoined(false);
}
} else {
// 未登录用户设置默认状态
vo.setUserApplicationStatus(null);
vo.setHasApplied(false);
vo.setHasJoined(false);
}
}
return TableDataInfo.build(result);
}
/**
* 查询志愿者队伍详情(学生报名大厅专用,包含用户申请状态)
*/
@Override
public StglVolunteerTeamVo queryRegistrationById(Long id) {
StglVolunteerTeamVo vo = baseMapper.selectVoById(id);
if (vo != null) {
// 计算当前成员数量
vo.setCurrentMemberCount(calculateCurrentMemberCount(id));
// 获取当前用户ID并计算申请状态
Long currentUserId = null;
try {
currentUserId = LoginHelper.getUserId();
} catch (Exception e) {
// 如果获取不到用户ID,说明未登录,设置默认状态
}
if (currentUserId != null) {
StglMember userMember = getUserMemberStatusInTeam(currentUserId, vo.getId());
if (userMember != null) {
vo.setUserApplicationStatus(userMember.getStatus());
// 状态为0(待审核)或1(审核中)时,表示已申请
vo.setHasApplied(userMember.getStatus() == 0 || userMember.getStatus() == 1);
// 状态为2时,表示已加入
vo.setHasJoined(userMember.getStatus() == 2);
} else {
// 用户未申请此队伍
vo.setUserApplicationStatus(null);
vo.setHasApplied(false);
vo.setHasJoined(false);
}
} else {
// 未登录用户设置默认状态
vo.setUserApplicationStatus(null);
vo.setHasApplied(false);
vo.setHasJoined(false);
}
}
return vo;
}
/**
* 查询用户在指定队伍中的成员状态
*
* @param userId 用户ID
* @param teamId 队伍ID
* @return 成员记录,如果不存在则返回null
*/
private StglMember getUserMemberStatusInTeam(Long userId, Long teamId) {
LambdaQueryWrapper<StglMember> wrapper = Wrappers.lambdaQuery();
wrapper.eq(StglMember::getUserId, userId)
.eq(StglMember::getRelationId, teamId)
.eq(StglMember::getMemberType, 2); // 2表示志愿者成员
List<StglMember> members = memberMapper.selectList(wrapper);
return members.isEmpty() ? null : members.get(0);
}
}
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.stgl.mapper.StglActivityRatingMapper">
<resultMap type="org.dromara.stgl.domain.StglActivityRating" id="StglActivityRatingResult">
<result property="id" column="id"/>
<result property="tenantId" column="tenant_id"/>
<result property="createDept" column="create_dept"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="deleted" column="deleted"/>
<result property="activityId" column="activity_id"/>
<result property="userId" column="user_id"/>
<result property="studentNo" column="student_no"/>
<result property="studentName" column="student_name"/>
<result property="ratingScore" column="rating_score"/>
<result property="ratingComment" column="rating_comment"/>
<result property="ratingTime" column="rating_time"/>
<result property="contentScore" column="content_score"/>
<result property="organizationScore" column="organization_score"/>
<result property="experienceScore" column="experience_score"/>
</resultMap>
<sql id="selectStglActivityRatingVo">
SELECT id, tenant_id, create_dept, create_by, create_time, update_by, update_time, deleted,
activity_id, user_id, student_no, student_name, rating_score, rating_comment, rating_time,
content_score, organization_score, experience_score
FROM stgl_activity_rating
</sql>
<!-- 根据活动ID和用户ID查询评分记录 -->
<select id="selectByActivityIdAndUserId" resultMap="StglActivityRatingResult">
<include refid="selectStglActivityRatingVo"/>
<where>
activity_id = #{activityId}
AND user_id = #{userId}
AND deleted = 0
</where>
LIMIT 1
</select>
<!-- 统计用户对活动的评分记录数量 -->
<select id="countByActivityIdAndUserId" resultType="java.lang.Long">
SELECT COUNT(*)
FROM stgl_activity_rating
<where>
activity_id = #{activityId}
AND user_id = #{userId}
AND deleted = 0
</where>
</select>
<!-- 查询活动平均评分 -->
<select id="selectAverageRatingByActivityId" resultType="java.lang.Double">
SELECT AVG(rating_score)
FROM stgl_activity_rating
<where>
activity_id = #{activityId}
AND deleted = 0
</where>
</select>
</mapper>
@@ -0,0 +1,169 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.stgl.mapper.StglClubMapper">
<resultMap type="org.dromara.stgl.domain.StglClub" id="StglClubResult">
<result property="id" column="id"/>
<result property="clubName" column="club_name"/>
<result property="clubType" column="club_type"/>
<result property="establishDate" column="establish_date"/>
<result property="description" column="description"/>
<result property="email" column="email"/>
<result property="phone" column="phone"/>
<result property="logoUrl" column="logo_url"/>
<result property="presidentName" column="president_name"/>
<result property="presidentStudentNo" column="president_student_no"/>
<result property="presidentDept" column="president_dept"/>
<result property="presidentMajor" column="president_major"/>
<result property="presidentClass" column="president_class"/>
<result property="presidentPhone" column="president_phone"/>
<result property="vicePresidentName" column="vice_president_name"/>
<result property="vicePresidentStudentNo" column="vice_president_student_no"/>
<result property="vicePresidentDept" column="vice_president_dept"/>
<result property="vicePresidentMajor" column="vice_president_major"/>
<result property="vicePresidentClass" column="vice_president_class"/>
<result property="vicePresidentPhone" column="vice_president_phone"/>
<result property="advisorName" column="advisor_name"/>
<result property="advisorDept" column="advisor_dept"/>
<result property="advisorPhone" column="advisor_phone"/>
<result property="advisorEmail" column="advisor_email"/>
<result property="vicePresidentsJson" column="vice_presidents_json"/>
<result property="advisorsJson" column="advisors_json"/>
<result property="memberLimit" column="member_limit"/>
<result property="departments" column="departments"/>
<result property="recruitCycle" column="recruit_cycle"/>
<result property="recruitTime" column="recruit_time"/>
<result property="activityFrequency" column="activity_frequency"/>
<result property="fundingSources" column="funding_sources"/>
<result property="charterUrl" column="charter_url"/>
<result property="status" column="status"/>
<result property="remark" column="remark"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="tenantId" column="tenant_id"/>
<result property="deleted" column="deleted"/>
</resultMap>
<sql id="selectStglClubVo">
select c.id, c.club_name, c.club_type, c.establish_date, c.description, c.email, c.phone, c.logo_url,
c.president_name, c.president_student_no, c.president_dept, c.president_major, c.president_class, c.president_phone,
c.vice_president_name, c.vice_president_student_no, c.vice_president_dept, c.vice_president_major, c.vice_president_class, c.vice_president_phone,
c.vice_presidents_json,
c.advisor_name, c.advisor_dept, c.advisor_phone, c.advisor_email,
c.advisors_json,
c.member_limit, c.departments, c.recruit_cycle, c.recruit_time, c.activity_frequency, c.funding_sources,
c.charter_url, c.status, c.remark, c.create_by, c.create_time, c.update_by, c.update_time, c.tenant_id, c.deleted,
COALESCE(m.member_count, 0) as memberCount
from stgl_club c
LEFT JOIN (
SELECT relation_id, COUNT(*) as member_count
FROM stgl_member
WHERE member_type = 1 AND status = 2 AND deleted = 0
GROUP BY relation_id
) m ON c.id = m.relation_id
</sql>
<!-- 查询社团详情(包含成员统计) -->
<select id="selectClubWithMemberCount" resultType="org.dromara.stgl.domain.vo.StglClubVo">
SELECT
c.id, c.club_name, c.club_type, c.establish_date, c.description,
c.email, c.phone, c.logo_url, c.president_name, c.president_student_no,
c.president_dept, c.president_major, c.president_class, c.president_phone,
c.vice_president_name, c.vice_president_student_no, c.vice_president_dept, c.vice_president_major, c.vice_president_class, c.vice_president_phone,
c.advisor_name, c.advisor_dept, c.advisor_phone, c.advisor_email,
c.member_limit, c.departments, c.recruit_cycle, c.recruit_time,
c.activity_frequency, c.funding_sources, c.charter_url, c.status, c.remark,
c.create_by, c.create_time, c.update_by, c.update_time,
COALESCE(m.member_count, 0) as memberCount
FROM stgl_club c
LEFT JOIN (
SELECT relation_id, COUNT(*) as member_count
FROM stgl_member
WHERE member_type = 1 AND status = 2 AND deleted = 0
GROUP BY relation_id
) m ON c.id = m.relation_id
WHERE c.id = #{id} AND c.deleted = 0
</select>
<!-- 查询热门社团(按成员数量排序) -->
<select id="selectPopularClubs" resultType="org.dromara.stgl.domain.vo.StglClubVo">
SELECT
c.id, c.club_name, c.club_type, c.establish_date, c.description,
c.email, c.phone, c.logo_url, c.president_name, c.president_student_no,
c.president_dept, c.president_major, c.president_class, c.president_phone,
c.vice_president_name, c.vice_president_student_no, c.vice_president_dept, c.vice_president_major, c.vice_president_class, c.vice_president_phone,
c.advisor_name, c.advisor_dept, c.advisor_phone, c.advisor_email,
c.member_limit, c.departments, c.recruit_cycle, c.recruit_time,
c.activity_frequency, c.funding_sources, c.charter_url, c.status, c.remark,
c.create_by, c.create_time, c.update_by, c.update_time,
COALESCE(m.member_count, 0) as memberCount
FROM stgl_club c
LEFT JOIN (
SELECT relation_id, COUNT(*) as member_count
FROM stgl_member
WHERE member_type = 1 AND status = 2 AND deleted = 0
GROUP BY relation_id
) m ON c.id = m.relation_id
WHERE c.status = 1 AND c.deleted = 0
<if test="clubType != null and clubType != ''">
AND c.club_type = #{clubType}
</if>
ORDER BY COALESCE(m.member_count, 0) DESC, c.create_time DESC
<if test="limit != null">
LIMIT #{limit}
</if>
</select>
<!-- 分页查询社团列表(包含成员统计) -->
<select id="selectClubPageWithMemberCount" resultType="org.dromara.stgl.domain.vo.StglClubVo">
SELECT
c.id, c.club_name, c.club_type, c.establish_date, c.description,
c.email, c.phone, c.logo_url, c.president_name, c.president_student_no,
c.president_dept, c.president_major, c.president_class, c.president_phone,
c.vice_president_name, c.vice_president_student_no, c.vice_president_dept, c.vice_president_major, c.vice_president_class, c.vice_president_phone,
c.vice_presidents_json,
c.advisor_name, c.advisor_dept, c.advisor_phone, c.advisor_email,
c.advisors_json,
c.member_limit, c.departments, c.recruit_cycle, c.recruit_time,
c.activity_frequency, c.funding_sources, c.charter_url, c.status, c.remark,
c.create_by, c.create_time, c.update_by, c.update_time,
COALESCE(m.member_count, 0) as memberCount
FROM stgl_club c
LEFT JOIN (
SELECT relation_id, COUNT(*) as member_count
FROM stgl_member
WHERE member_type = 1 AND status = 2 AND deleted = 0
GROUP BY relation_id
) m ON c.id = m.relation_id
WHERE c.deleted = 0
<if test="clubName != null and clubName != ''">
AND c.club_name LIKE CONCAT('%', #{clubName}, '%')
</if>
<if test="clubType != null and clubType != ''">
AND c.club_type = #{clubType}
</if>
<if test="status != null">
AND c.status = #{status}
</if>
<if test="establishDate != null">
AND DATE(c.establish_date) = DATE(#{establishDate})
</if>
<if test="presidentName != null and presidentName != ''">
AND c.president_name LIKE CONCAT('%', #{presidentName}, '%')
</if>
<if test="advisorName != null and advisorName != ''">
AND c.advisor_name LIKE CONCAT('%', #{advisorName}, '%')
</if>
<if test="clubIds != null and clubIds.size() > 0">
AND c.id IN
<foreach collection="clubIds" item="clubId" open="(" separator="," close=")">
#{clubId}
</foreach>
</if>
ORDER BY c.create_time DESC
</select>
</mapper>
@@ -0,0 +1,249 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.stgl.mapper.StglMemberMapper">
<resultMap type="org.dromara.stgl.domain.StglMember" id="StglMemberResult">
<result property="id" column="id"/>
<result property="memberType" column="member_type"/>
<result property="relationId" column="relation_id"/>
<result property="userId" column="user_id"/>
<result property="studentNo" column="student_no"/>
<result property="studentName" column="student_name"/>
<result property="roleType" column="role_type"/>
<result property="joinTime" column="join_time"/>
<result property="status" column="status"/>
<result property="remark" column="remark"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="tenantId" column="tenant_id"/>
<result property="deleted" column="deleted"/>
</resultMap>
<sql id="selectStglMemberVo">
select id, member_type, relation_id, user_id, student_no, student_name,
role_type, join_time, status, remark,
create_by, create_time, update_by, update_time, tenant_id, deleted
from stgl_member
</sql>
<!-- 查询社团成员详情(包含用户信息) -->
<select id="selectMemberWithUserInfoById" resultType="org.dromara.stgl.domain.vo.StglMemberVo">
SELECT
m.id, m.member_type, m.relation_id, m.user_id, m.student_no, m.student_name,
m.role_type, m.join_time, m.status, m.remark,
m.create_by, m.create_time, m.update_by, m.update_time,
u.nick_name, u.phonenumber as phone, u.email,
s.gender, s.college_name as department, s.major_name as major, s.class_name as className,
CASE m.member_type
WHEN 1 THEN '社团成员'
WHEN 2 THEN '志愿者'
ELSE '未知'
END as memberTypeName,
CASE
WHEN m.member_type = 1 THEN
CASE m.role_type
WHEN 1 THEN '社长'
WHEN 2 THEN '副社长'
WHEN 3 THEN '部长'
WHEN 4 THEN '普通成员'
ELSE '未知'
END
WHEN m.member_type = 2 THEN
CASE m.role_type
WHEN 0 THEN '队长'
WHEN 1 THEN '队员'
ELSE '未知'
END
ELSE '未知'
END as roleTypeName,
CASE m.status
WHEN 0 THEN '待审核'
WHEN 1 THEN '审核中'
WHEN 2 THEN '已加入'
WHEN 3 THEN '已驳回'
WHEN 4 THEN '已退出'
ELSE '未知'
END as statusName,
CASE m.member_type
WHEN 1 THEN c.club_name
WHEN 2 THEN vt.team_name
ELSE '未知'
END as relationName,
CASE m.member_type
WHEN 1 THEN c.club_name
WHEN 2 THEN vt.team_name
ELSE '未知'
END as clubName
FROM stgl_member m
LEFT JOIN sys_user u ON m.user_id = u.user_id AND u.del_flag = '0' AND u.tenant_id = '000000'
LEFT JOIN stgl_club c ON m.relation_id = c.id AND c.deleted = 0 AND m.member_type = 1 AND c.tenant_id = '000000'
LEFT JOIN stgl_volunteer_team vt ON m.relation_id = vt.id AND vt.deleted = 0 AND m.member_type = 2 AND vt.tenant_id = '000000'
LEFT JOIN xg_student_msg s ON m.student_no = s.student_no AND s.deleted = 0 AND s.tenant_id = '000000'
WHERE m.id = #{id} AND m.deleted = 0 AND m.tenant_id = '000000'
</select>
<!-- 查询社团成员列表(包含用户信息) -->
<select id="selectMemberWithUserInfo" resultType="org.dromara.stgl.domain.vo.StglMemberVo">
SELECT
m.id, m.member_type, m.relation_id, m.user_id, m.student_no, m.student_name,
m.role_type, m.join_time, m.status, m.remark,
m.create_by, m.create_time, m.update_by, m.update_time,
u.nick_name, u.phonenumber as phone, u.email,
CASE s.gender
WHEN '0' THEN '男'
WHEN '1' THEN '女'
ELSE '未知'
END as gender,
s.college_name as department, s.major_name as major, s.class_name as className,
CASE m.member_type
WHEN 1 THEN '社团成员'
WHEN 2 THEN '志愿者'
ELSE '未知'
END as memberTypeName,
CASE
WHEN m.member_type = 1 THEN
CASE m.role_type
WHEN 1 THEN '社长'
WHEN 2 THEN '副社长'
WHEN 3 THEN '部长'
WHEN 4 THEN '普通成员'
ELSE '未知'
END
WHEN m.member_type = 2 THEN
CASE m.role_type
WHEN 0 THEN '队长'
WHEN 1 THEN '队员'
ELSE '未知'
END
ELSE '未知'
END as roleTypeName,
CASE m.status
WHEN 0 THEN '待审核'
WHEN 1 THEN '审核中'
WHEN 2 THEN '已加入'
WHEN 3 THEN '已驳回'
WHEN 4 THEN '已退出'
ELSE '未知'
END as statusName,
CASE m.member_type
WHEN 1 THEN c.club_name
WHEN 2 THEN vt.team_name
ELSE '未知'
END as relationName,
CASE m.member_type
WHEN 1 THEN c.club_name
WHEN 2 THEN vt.team_name
ELSE '未知'
END as clubName
FROM stgl_member m
LEFT JOIN sys_user u ON m.user_id = u.user_id AND u.del_flag = '0' AND u.tenant_id = '000000'
LEFT JOIN stgl_club c ON m.relation_id = c.id AND c.deleted = 0 AND m.member_type = 1 AND c.tenant_id = '000000'
LEFT JOIN stgl_volunteer_team vt ON m.relation_id = vt.id AND vt.deleted = 0 AND m.member_type = 2 AND vt.tenant_id = '000000'
LEFT JOIN xg_student_msg s ON m.student_no = s.student_no AND s.deleted = 0 AND s.tenant_id = '000000'
WHERE m.deleted = 0 AND m.tenant_id = '000000'
<if test="memberType != null">
AND m.member_type = #{memberType}
</if>
<if test="relationId != null">
AND m.relation_id = #{relationId}
</if>
<if test="studentNo != null and studentNo != ''">
AND m.student_no LIKE CONCAT('%', #{studentNo}, '%')
</if>
<if test="studentName != null and studentName != ''">
AND m.student_name LIKE CONCAT('%', #{studentName}, '%')
</if>
<if test="roleType != null">
AND m.role_type = #{roleType}
</if>
<if test="status != null">
AND m.status = #{status}
</if>
<if test="clubName != null and clubName != ''">
AND c.club_name LIKE CONCAT('%', #{clubName}, '%')
</if>
<if test="teamName != null and teamName != ''">
AND vt.team_name LIKE CONCAT('%', #{teamName}, '%')
</if>
<if test="userId != null">
AND m.user_id = #{userId}
</if>
ORDER BY m.role_type ASC, m.join_time DESC
</select>
<!-- 检查用户是否已加入某个社团/志愿者队伍 -->
<select id="checkMemberExists" resultType="java.lang.Boolean">
SELECT COUNT(*) > 0
FROM stgl_member
WHERE member_type = #{memberType}
AND relation_id = #{relationId}
AND user_id = #{userId}
AND status = 1
AND deleted = 0
</select>
<!-- 查询用户参与的社团列表 -->
<select id="selectUserClubs" resultType="org.dromara.stgl.domain.vo.StglClubVo">
SELECT
c.id, c.club_name, c.club_type, c.establish_date, c.description,
c.email, c.phone, c.logo_url, c.president_name, c.president_student_no,
c.president_dept, c.president_major, c.president_class, c.president_phone,
c.vice_president_name, c.vice_president_student_no, c.advisor_name, c.advisor_dept,
c.member_limit, c.departments, c.recruit_cycle, c.recruit_time,
c.activity_frequency, c.funding_sources, c.charter_url, c.status, c.remark,
c.create_by, c.create_time, c.update_by, c.update_time,
m.role_type as myRoleType,
m.join_time as myJoinTime,
CASE m.role_type
WHEN 1 THEN '社长'
WHEN 2 THEN '副社长'
WHEN 3 THEN '部长'
ELSE '未知'
END as myRoleName
FROM stgl_club c
INNER JOIN stgl_member m ON c.id = m.relation_id
WHERE m.user_id = #{userId}
AND m.member_type = 1
AND m.status = 1
AND m.deleted = 0
AND c.deleted = 0
ORDER BY m.role_type ASC, m.join_time DESC
</select>
<!-- 统计社团成员数量 -->
<select id="countClubMembers" resultType="java.lang.Integer">
SELECT COUNT(*)
FROM stgl_member
WHERE member_type = 1
AND relation_id = #{clubId}
AND status = 1
AND deleted = 0
</select>
<!-- 查询社团管理员(社长和副社长) -->
<select id="selectClubAdmins" resultType="org.dromara.stgl.domain.vo.StglMemberVo">
SELECT
m.id, m.member_type, m.relation_id, m.user_id, m.student_no, m.student_name,
m.role_type, m.join_time, m.status, m.remark,
m.create_by, m.create_time, m.update_by, m.update_time,
u.nick_name, u.phonenumber, u.email as userEmail,
CASE m.role_type
WHEN 1 THEN '社长'
WHEN 2 THEN '副社长'
ELSE '未知'
END as roleTypeName
FROM stgl_member m
LEFT JOIN sys_user u ON m.user_id = u.user_id AND u.del_flag = '0' AND u.tenant_id = '000000'
WHERE m.member_type = 1
AND m.relation_id = #{clubId}
AND m.role_type IN (1, 2)
AND m.status = 1
AND m.deleted = 0
ORDER BY m.role_type ASC
</select>
</mapper>
@@ -0,0 +1,346 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.stgl.mapper.StglMyMapper">
<!-- 我的社团查询 -->
<sql id="selectMyClubsVo">
SELECT
c.id,
c.club_name,
CAST(c.club_type AS CHAR) as club_type,
c.logo_url,
c.president_name,
c.president_dept,
c.advisor_name,
c.advisor_dept,
(SELECT COUNT(*) FROM stgl_member sm WHERE sm.relation_id = c.id AND sm.member_type = 1 AND sm.deleted = 0 AND sm.tenant_id = c.tenant_id) as member_count,
c.member_limit,
CAST(c.status AS CHAR) as status,
c.description,
c.establish_date,
c.create_by,
c.create_time,
c.update_by,
c.update_time,
CAST(m.role_type AS CHAR) as my_role,
m.join_time,
CAST(m.status AS CHAR) as member_status
FROM stgl_club c
INNER JOIN stgl_member m ON c.id = m.relation_id AND m.member_type = 1
</sql>
<select id="selectMyClubs" resultType="org.dromara.stgl.domain.vo.MyClubVo">
<include refid="selectMyClubsVo"/>
<where>
m.user_id = #{userId}
AND m.deleted = 0
AND c.deleted = 0
</where>
ORDER BY m.join_time DESC
</select>
<!-- 我的志愿团队查询 -->
<sql id="selectMyVolunteerTeamsVo">
SELECT
vt.id,
vt.team_name,
vt.leader_name,
vt.leader_dept,
vt.advisor_name,
vt.advisor_dept,
(SELECT COUNT(*) FROM stgl_member sm WHERE sm.relation_id = vt.id AND sm.member_type = 2 AND sm.deleted = 0 AND sm.tenant_id = vt.tenant_id) as current_member_count,
vt.member_limit,
CAST(vt.status AS CHAR) as status,
vt.description,
vt.establish_date,
vt.phone as contact_phone,
vt.email,
vt.create_by,
vt.create_time,
vt.update_by,
vt.update_time,
CAST(m.role_type AS CHAR) as my_role,
m.join_time,
CAST(m.status AS CHAR) as member_status
FROM stgl_volunteer_team vt
INNER JOIN stgl_member m ON vt.id = m.relation_id AND m.member_type = 2
</sql>
<select id="selectMyVolunteerTeams" resultType="org.dromara.stgl.domain.vo.MyVolunteerTeamVo">
<include refid="selectMyVolunteerTeamsVo"/>
<where>
m.user_id = #{userId}
AND m.deleted = 0
AND vt.deleted = 0
AND vt.tenant_id = #{tenantId}
AND m.tenant_id = #{tenantId}
</where>
ORDER BY m.join_time DESC
</select>
<!-- 我的活动查询(带评分状态) -->
<sql id="selectMyActivitiesVo">
SELECT
a.id,
a.activity_name,
CAST(a.activity_type AS CHAR) as activity_type,
a.activity_theme,
a.start_time,
a.end_time,
a.location,
a.organizer_name,
CAST(a.related_type AS CHAR) as related_type,
CASE
WHEN a.related_type = 1 THEN c.club_name
WHEN a.related_type = 2 THEN vt.team_name
ELSE NULL
END as organization_name,
a.instructors,
CAST(a.activity_status AS CHAR) as activity_status,
-- 动态计算报名状态:基于当前时间和报名时间范围
CAST(
CASE
WHEN a.registration_start IS NULL OR a.registration_end IS NULL THEN a.registration_status
WHEN NOW() &lt; a.registration_start THEN '0'
WHEN NOW() &gt;= a.registration_start AND NOW() &lt;= a.registration_end THEN '1'
WHEN NOW() &gt; a.registration_end THEN '2'
ELSE a.registration_status
END AS CHAR
) as registration_status,
a.poster_url,
a.description,
a.create_by,
a.create_time,
a.update_by,
a.update_time,
ar.registration_time as my_registration_time,
CAST(ar.approval_status AS CHAR) as my_registration_status,
CASE WHEN rat.id IS NOT NULL THEN 1 ELSE 0 END as my_rating_status,
rat.rating_score as my_rating_score,
rat.rating_time as my_rating_time,
(SELECT AVG(rating_score) FROM stgl_activity_rating WHERE activity_id = a.id AND deleted = 0) as average_rating,
CASE
WHEN rat.id IS NOT NULL THEN 0
WHEN a.activity_status IN ('4', '5') AND ar.approval_status = '1' THEN 1
ELSE 0
END as can_rate
FROM stgl_activity a
INNER JOIN stgl_activity_registration ar ON a.id = ar.activity_id
LEFT JOIN stgl_club c ON a.related_type = 1 AND a.related_club_id = c.id AND c.deleted = 0 AND c.tenant_id = #{tenantId}
LEFT JOIN stgl_volunteer_team vt ON a.related_type = 2 AND a.related_club_id = vt.id AND vt.deleted = 0 AND vt.tenant_id = #{tenantId}
LEFT JOIN stgl_activity_rating rat ON a.id = rat.activity_id AND rat.user_id = #{userId} AND rat.deleted = 0
</sql>
<select id="selectMyActivities" resultType="org.dromara.stgl.domain.vo.MyActivityVo">
<include refid="selectMyActivitiesVo"/>
<where>
ar.user_id = #{userId}
AND ar.deleted = 0
AND a.deleted = 0
AND a.tenant_id = #{tenantId}
AND ar.tenant_id = #{tenantId}
</where>
ORDER BY ar.registration_time DESC
</select>
<!-- 我的报名记录查询(统一查询社团+志愿团队+活动) -->
<select id="selectMyRegistrations" resultType="org.dromara.stgl.domain.vo.MyRegistrationVo">
(
SELECT
m.id,
'1' as registration_type,
c.id as target_id,
c.club_name as target_name,
(SELECT dict_label FROM sys_dict_data WHERE dict_type = 'stgl_club_type' AND dict_value = CAST(c.club_type AS CHAR) AND tenant_id = '000000') as target_type,
m.join_time as registration_time,
CASE WHEN m.status = '1' THEN '已通过' WHEN m.status = '2' THEN '已拒绝' ELSE '待审核' END as approval_status,
NULL as approval_time,
NULL as approval_by,
m.remark,
CASE WHEN m.status = '1' THEN '正常' ELSE '待审核' END as current_status,
(SELECT dict_label FROM sys_dict_data WHERE dict_type = 'stgl_member_role' AND dict_value = CAST(m.role_type AS CHAR) AND tenant_id = '000000') as role,
c.president_name as organizer,
c.establish_date as time_info,
'' as location,
m.create_by,
m.create_time,
m.update_by,
m.update_time
FROM stgl_member m
INNER JOIN stgl_club c ON m.relation_id = c.id AND m.member_type = 1 AND m.tenant_id = '000000' AND c.tenant_id = '000000'
WHERE m.user_id = #{userId} AND m.deleted = 0 AND c.deleted = 0
)
UNION ALL
(
SELECT
m.id,
'2' as registration_type,
vt.id as target_id,
vt.team_name as target_name,
'志愿服务' as target_type,
m.join_time as registration_time,
CASE WHEN m.status = '1' THEN '已通过' WHEN m.status = '2' THEN '已拒绝' ELSE '待审核' END as approval_status,
NULL as approval_time,
NULL as approval_by,
m.remark,
CASE WHEN m.status = '1' THEN '正常' ELSE '待审核' END as current_status,
(SELECT dict_label FROM sys_dict_data WHERE dict_type = 'stgl_volunteer_role' AND dict_value = CAST(m.role_type AS CHAR) AND tenant_id = '000000') as role,
vt.leader_name as organizer,
vt.establish_date as time_info,
'' as location,
m.create_by,
m.create_time,
m.update_by,
m.update_time
FROM stgl_member m
INNER JOIN stgl_volunteer_team vt ON m.relation_id = vt.id AND m.member_type = 2 AND m.tenant_id = '000000' AND vt.tenant_id = '000000'
WHERE m.user_id = #{userId} AND m.deleted = 0 AND vt.deleted = 0
)
UNION ALL
(
SELECT
ar.id,
'3' as registration_type,
a.id as target_id,
a.activity_name as target_name,
(SELECT dict_label FROM sys_dict_data WHERE dict_type = 'stgl_activity_type' AND dict_value = CAST(a.activity_type AS CHAR) AND tenant_id = '000000') as target_type,
ar.registration_time,
CASE WHEN ar.approval_status = '1' THEN '已通过' WHEN ar.approval_status = '2' THEN '已拒绝' ELSE '待审核' END as approval_status,
ar.approval_time,
ar.approval_by,
ar.remark,
CASE WHEN ar.approval_status = '1' THEN '已报名' ELSE '待审核' END as current_status,
'参与者' as role,
a.organizer_name as organizer,
a.start_time as time_info,
a.location,
ar.create_by,
ar.create_time,
ar.update_by,
ar.update_time
FROM stgl_activity_registration ar
INNER JOIN stgl_activity a ON ar.activity_id = a.id AND ar.tenant_id = '000000' AND a.tenant_id = '000000'
WHERE ar.user_id = #{userId} AND ar.deleted = 0 AND a.deleted = 0
)
<if test="registrationType != null and registrationType != ''">
WHERE registration_type = #{registrationType}
</if>
ORDER BY registration_time DESC
</select>
<!-- 统计我的报名记录总数 -->
<select id="countMyRegistrations" resultType="java.lang.Long">
SELECT COUNT(*) FROM (
(
SELECT m.id
FROM stgl_member m
INNER JOIN stgl_club c ON m.relation_id = c.id AND m.member_type = 1 AND m.tenant_id = '000000' AND c.tenant_id = '000000'
WHERE m.user_id = #{userId} AND m.deleted = 0 AND c.deleted = 0
)
UNION ALL
(
SELECT m.id
FROM stgl_member m
INNER JOIN stgl_volunteer_team vt ON m.relation_id = vt.id AND m.member_type = 2 AND m.tenant_id = '000000' AND vt.tenant_id = '000000'
WHERE m.user_id = #{userId} AND m.deleted = 0 AND vt.deleted = 0
)
UNION ALL
(
SELECT ar.id
FROM stgl_activity_registration ar
INNER JOIN stgl_activity a ON ar.activity_id = a.id AND ar.tenant_id = '000000' AND a.tenant_id = '000000'
WHERE ar.user_id = #{userId} AND ar.deleted = 0 AND a.deleted = 0
)
) total_records
</select>
<!-- 分页查询我的报名记录 -->
<select id="selectMyRegistrationsPage" resultType="org.dromara.stgl.domain.vo.MyRegistrationVo">
SELECT * FROM (
(
SELECT
m.id,
'1' as registration_type,
c.id as target_id,
c.club_name as target_name,
(SELECT dict_label FROM sys_dict_data WHERE dict_type = 'stgl_club_type' AND dict_value = CAST(c.club_type AS CHAR) AND tenant_id = '000000') as target_type,
m.join_time as registration_time,
CASE WHEN m.status = '1' THEN '已通过' WHEN m.status = '2' THEN '已拒绝' ELSE '待审核' END as approval_status,
NULL as approval_time,
NULL as approval_by,
m.remark,
CASE WHEN m.status = '1' THEN '正常' ELSE '待审核' END as current_status,
(SELECT dict_label FROM sys_dict_data WHERE dict_type = 'stgl_member_role' AND dict_value = CAST(m.role_type AS CHAR) AND tenant_id = '000000') as role,
c.president_name as organizer,
c.establish_date as time_info,
'' as location,
m.create_by,
m.create_time,
m.update_by,
m.update_time
FROM stgl_member m
INNER JOIN stgl_club c ON m.relation_id = c.id AND m.member_type = 1 AND m.tenant_id = '000000' AND c.tenant_id = '000000'
WHERE m.user_id = #{userId} AND m.deleted = 0 AND c.deleted = 0
)
UNION ALL
(
SELECT
m.id,
'2' as registration_type,
vt.id as target_id,
vt.team_name as target_name,
'志愿服务' as target_type,
m.join_time as registration_time,
CASE WHEN m.status = '1' THEN '已通过' WHEN m.status = '2' THEN '已拒绝' ELSE '待审核' END as approval_status,
NULL as approval_time,
NULL as approval_by,
m.remark,
CASE WHEN m.status = '1' THEN '正常' ELSE '待审核' END as current_status,
(SELECT dict_label FROM sys_dict_data WHERE dict_type = 'stgl_volunteer_role' AND dict_value = CAST(m.role_type AS CHAR) AND tenant_id = '000000') as role,
vt.leader_name as organizer,
vt.establish_date as time_info,
'' as location,
m.create_by,
m.create_time,
m.update_by,
m.update_time
FROM stgl_member m
INNER JOIN stgl_volunteer_team vt ON m.relation_id = vt.id AND m.member_type = 2 AND m.tenant_id = '000000' AND vt.tenant_id = '000000'
WHERE m.user_id = #{userId} AND m.deleted = 0 AND vt.deleted = 0
)
UNION ALL
(
SELECT
ar.id,
'3' as registration_type,
a.id as target_id,
a.activity_name as target_name,
(SELECT dict_label FROM sys_dict_data WHERE dict_type = 'stgl_activity_type' AND dict_value = CAST(a.activity_type AS CHAR) AND tenant_id = '000000') as target_type,
ar.registration_time,
CASE WHEN ar.approval_status = '1' THEN '已通过' WHEN ar.approval_status = '2' THEN '已拒绝' ELSE '待审核' END as approval_status,
ar.approval_time,
ar.approval_by,
ar.remark,
CASE WHEN ar.approval_status = '1' THEN '已报名' ELSE '待审核' END as current_status,
'参与者' as role,
a.organizer_name as organizer,
a.start_time as time_info,
a.location,
ar.create_by,
ar.create_time,
ar.update_by,
ar.update_time
FROM stgl_activity_registration ar
INNER JOIN stgl_activity a ON ar.activity_id = a.id AND ar.tenant_id = '000000' AND a.tenant_id = '000000'
WHERE ar.user_id = #{userId} AND ar.deleted = 0 AND a.deleted = 0
)
) all_registrations
<if test="registrationType != null and registrationType != ''">
WHERE registration_type = #{registrationType}
</if>
ORDER BY registration_time DESC
</select>
</mapper>
@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.stgl.mapper.StglActivityAttendanceMapper">
<!-- 通用查询结果映射 -->
<resultMap id="StglActivityAttendanceResult" type="org.dromara.stgl.domain.vo.StglActivityAttendanceVo">
<!-- 签到记录字段 -->
<id property="id" column="id"/>
<result property="activityId" column="activity_id"/>
<result property="userId" column="user_id"/>
<result property="studentName" column="student_name"/>
<result property="studentNo" column="student_no"/>
<result property="department" column="department"/>
<result property="major" column="major"/>
<result property="className" column="class_name"/>
<result property="phone" column="phone"/>
<result property="email" column="email"/>
<result property="signInTime" column="sign_in_time"/>
<result property="signInStatus" column="sign_in_status"/>
<result property="signInLocation" column="sign_in_location"/>
<result property="signInDevice" column="sign_in_device"/>
<result property="signInRemark" column="sign_in_remark"/>
<result property="signOutTime" column="sign_out_time"/>
<result property="signOutStatus" column="sign_out_status"/>
<result property="signOutLocation" column="sign_out_location"/>
<result property="signOutDevice" column="sign_out_device"/>
<result property="signOutRemark" column="sign_out_remark"/>
<result property="overallStatus" column="overall_status"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<!-- 活动信息字段 -->
<result property="activityName" column="activity_name"/>
<result property="activityType" column="activity_type"/>
<result property="activityTheme" column="activity_theme"/>
<result property="location" column="location"/>
<result property="startTime" column="start_time"/>
<result property="endTime" column="end_time"/>
<result property="recordTime" column="record_time"/>
</resultMap>
<!-- 基础查询字段 -->
<sql id="selectStglActivityAttendanceVo">
SELECT
sas.id,
sas.activity_id,
sas.user_id,
sas.student_name,
sas.student_no,
sas.department,
sas.major,
sas.class_name,
sas.phone,
sas.email,
sas.sign_in_time,
sas.sign_in_status,
sas.sign_in_location,
sas.sign_in_device,
sas.sign_in_remark,
sas.sign_out_time,
sas.sign_out_status,
sas.sign_out_location,
sas.sign_out_device,
sas.sign_out_remark,
sas.overall_status,
sas.create_by,
sas.create_time,
sas.update_by,
sas.update_time,
-- 活动信息
sa.activity_name,
sa.activity_type,
sa.activity_theme,
sa.location,
sa.start_time,
sa.end_time,
-- 记录时间(根据签到状态取值)
CASE
WHEN sas.overall_status = 2 THEN sas.sign_out_time
WHEN sas.overall_status = 1 THEN sas.sign_in_time
ELSE NULL
END as record_time
FROM stgl_activity_sign sas
LEFT JOIN stgl_activity sa ON sas.activity_id = sa.id
</sql>
<!-- 查询活动考勤签到列表(关联查询活动信息) -->
<select id="selectAttendanceList" parameterType="com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper" resultMap="StglActivityAttendanceResult">
<include refid="selectStglActivityAttendanceVo"/>
<where>
sas.deleted = 0
AND sa.deleted = 0
${ew.customSqlSegment}
</where>
ORDER BY sas.create_time DESC
</select>
<!-- 查询用户已报名成功且进行中的活动列表 -->
<select id="selectUserAvailableActivities" parameterType="Long" resultMap="StglActivityAttendanceResult">
SELECT
sa.id as activity_id,
sa.activity_name,
sa.activity_type,
sa.activity_theme,
sa.location,
sa.start_time,
sa.end_time,
-- 用户信息
u.user_id as user_id,
u.nick_name as student_name,
u.user_name as student_no,
COALESCE(d.dept_name, xsm.college_name) as department,
COALESCE(xsm.major_name, '') as major,
COALESCE(xsm.class_name, '') as class_name,
u.phonenumber as phone,
u.email
FROM stgl_activity sa
INNER JOIN stgl_activity_registration sar ON sa.id = sar.activity_id
LEFT JOIN sys_user u ON sar.user_id = u.user_id
LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
LEFT JOIN xg_student_msg xsm ON u.user_name = xsm.student_no AND xsm.deleted = 0
<where>
sa.deleted = 0
AND sar.deleted = 0
AND u.del_flag = '0'
AND sar.user_id = #{userId}
AND sar.approval_status = 1 -- 报名成功(审核通过)
AND sa.activity_status = '4' -- 进行中
-- 排除已有签到记录的活动
AND NOT EXISTS (
SELECT 1 FROM stgl_activity_sign sas2
WHERE sas2.activity_id = sa.id
AND sas2.user_id = #{userId}
AND sas2.deleted = 0
)
</where>
ORDER BY sa.start_time ASC
</select>
<!-- 根据活动ID和用户ID查询签到记录 -->
<select id="selectByActivityAndUser" resultMap="StglActivityAttendanceResult">
<include refid="selectStglActivityAttendanceVo"/>
<where>
sas.deleted = 0
AND sa.deleted = 0
AND sas.activity_id = #{activityId}
AND sas.user_id = #{userId}
</where>
</select>
<!-- 根据ID查询活动考勤签到详情(关联查询活动信息) -->
<select id="selectVoByIdWithActivity" parameterType="Long" resultMap="StglActivityAttendanceResult">
<include refid="selectStglActivityAttendanceVo"/>
<where>
sas.deleted = 0
AND sa.deleted = 0
AND sas.id = #{id}
</where>
</select>
</mapper>
@@ -0,0 +1,285 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.stgl.mapper.StglActivityMapper">
<resultMap type="org.dromara.stgl.domain.vo.StglActivityVo" id="StglActivityResult">
<result property="id" column="id"/>
<result property="activityName" column="activity_name"/>
<result property="activityType" column="activity_type"/>
<result property="activityTheme" column="activity_theme"/>
<result property="startTime" column="start_time"/>
<result property="endTime" column="end_time"/>
<result property="location" column="location"/>
<result property="description" column="description"/>
<result property="posterUrl" column="poster_url"/>
<result property="relatedClubId" column="related_club_id"/>
<result property="relatedClubName" column="related_club_name"/>
<result property="relatedType" column="related_type"/>
<result property="organizerName" column="organizer_name"/>
<result property="organizerType" column="organizer_type"/>
<result property="organizerContact" column="organizer_contact"/>
<result property="organizerPhone" column="organizer_phone"/>
<result property="coOrganizers" column="co_organizers"/>
<result property="instructors" column="instructors"/>
<result property="registrationType" column="registration_type"/>
<result property="registrationStart" column="registration_start"/>
<result property="registrationEnd" column="registration_end"/>
<result property="registrationStatus" column="registration_status"/>
<result property="maxParticipants" column="max_participants"/>
<result property="maxTeams" column="max_teams"/>
<result property="teamSizeMin" column="team_size_min"/>
<result property="teamSizeMax" column="team_size_max"/>
<result property="needApproval" column="need_approval"/>
<result property="activityStatus" column="activity_status"/>
<result property="isFinished" column="is_finished"/>
<result property="summary" column="summary"/>
<result property="summaryAttachments" column="summary_attachments"/>
<result property="achievements" column="achievements"/>
<result property="achievementsAttachments" column="achievements_attachments"/>
<result property="importSource" column="import_source"/>
<result property="remark" column="remark"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="createByName" column="create_by_name"/>
<result property="registrationCount" column="registration_count"/>
<result property="averageRating" column="average_rating"/>
</resultMap>
<sql id="selectStglActivityVo">
SELECT
sa.id, sa.activity_name, sa.activity_type, sa.activity_theme,
sa.start_time, sa.end_time, sa.location, sa.description,
sa.poster_url, sa.related_club_id, sa.related_type, sa.organizer_name, sa.organizer_type,
sa.organizer_contact, sa.organizer_phone, sa.co_organizers, sa.instructors,
sa.registration_type, sa.registration_start, sa.registration_end,
-- 动态计算报名状态:基于当前时间和报名时间范围
CASE
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
WHEN NOW() &lt; sa.registration_start THEN '0'
WHEN NOW() &gt;= sa.registration_start AND NOW() &lt;= sa.registration_end THEN '1'
WHEN NOW() &gt; sa.registration_end THEN '2'
ELSE sa.registration_status
END AS registration_status,
sa.max_participants, sa.max_teams, sa.team_size_min, sa.team_size_max, sa.need_approval,
sa.activity_status, sa.is_finished, sa.summary, sa.summary_attachments, sa.achievements, sa.achievements_attachments, sa.import_source,
sa.remark, sa.create_by, sa.create_time, sa.update_by, sa.update_time,
-- 关联查询创建者姓名
su.nick_name AS create_by_name,
-- 根据关联类型查询对应的名称
CASE
WHEN sa.related_type = 1 THEN
CASE
WHEN sc.deleted = 1 THEN CONCAT(sc.club_name, '(已删除)')
ELSE sc.club_name
END
WHEN sa.related_type = 2 THEN
CASE
WHEN svt.deleted = 1 THEN CONCAT(svt.team_name, '(已删除)')
ELSE svt.team_name
END
ELSE NULL
END AS related_club_name,
-- 统计报名人数(子查询)
(SELECT COUNT(*) FROM stgl_activity_registration sar
WHERE sar.activity_id = sa.id AND sar.deleted = 0) AS registration_count,
-- 统计平均评分(子查询)
(SELECT ROUND(AVG(rating_score), 1) FROM stgl_activity_rating sar2
WHERE sar2.activity_id = sa.id AND sar2.deleted = 0) AS average_rating
FROM stgl_activity sa
LEFT JOIN sys_user su ON sa.create_by = su.user_id
LEFT JOIN stgl_club sc ON sa.related_club_id = sc.id AND sa.related_type = 1
LEFT JOIN stgl_volunteer_team svt ON sa.related_club_id = svt.id AND sa.related_type = 2
</sql>
<select id="selectVoList" parameterType="org.dromara.stgl.domain.StglActivity" resultMap="StglActivityResult">
<include refid="selectStglActivityVo"/>
<where>
sa.deleted = 0
<if test="activityName != null and activityName != ''">
AND sa.activity_name LIKE CONCAT('%', #{activityName}, '%')
</if>
<if test="activityType != null and activityType != ''">
AND sa.activity_type = #{activityType}
</if>
<if test="activityTheme != null and activityTheme != ''">
AND sa.activity_theme LIKE CONCAT('%', #{activityTheme}, '%')
</if>
<if test="organizerName != null and organizerName != ''">
AND sa.organizer_name LIKE CONCAT('%', #{organizerName}, '%')
</if>
<if test="activityStatus != null and activityStatus != ''">
AND sa.activity_status = #{activityStatus}
</if>
<if test="isFinished != null">
AND sa.is_finished = #{isFinished}
</if>
<if test="registrationStatus != null">
AND (
CASE
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
WHEN NOW() &lt; sa.registration_start THEN '0'
WHEN NOW() &gt;= sa.registration_start AND NOW() &lt;= sa.registration_end THEN '1'
WHEN NOW() &gt; sa.registration_end THEN '2'
ELSE sa.registration_status
END
) = #{registrationStatus}
</if>
<if test="startTime != null">
AND sa.start_time &gt;= #{startTime}
</if>
<if test="endTime != null">
AND sa.end_time &lt;= #{endTime}
</if>
<if test="registrationStart != null">
AND sa.registration_start &gt;= #{registrationStart}
</if>
<if test="registrationEnd != null">
AND sa.registration_end &lt;= #{registrationEnd}
</if>
<if test="relatedClubId != null">
AND sa.related_club_id = #{relatedClubId}
</if>
<!-- 数据权限:非管理员只能查看自己创建的活动 -->
${params.dataScope}
</where>
ORDER BY sa.create_time DESC
</select>
<!-- 分页查询活动信息列表(包含关联信息) -->
<select id="selectVoPage" parameterType="org.dromara.stgl.domain.StglActivity" resultMap="StglActivityResult">
<include refid="selectStglActivityVo"/>
<where>
sa.deleted = 0
<if test="activity.activityName != null and activity.activityName != ''">
AND sa.activity_name like concat('%', #{activity.activityName}, '%')
</if>
<if test="activity.activityType != null and activity.activityType != ''">
AND sa.activity_type = #{activity.activityType}
</if>
<if test="activity.activityTheme != null and activity.activityTheme != ''">
AND sa.activity_theme like concat('%', #{activity.activityTheme}, '%')
</if>
<if test="activity.startTime != null">
AND sa.start_time &gt;= #{activity.startTime}
</if>
<if test="activity.endTime != null">
AND sa.end_time &lt;= #{activity.endTime}
</if>
<if test="activity.location != null and activity.location != ''">
AND sa.location like concat('%', #{activity.location}, '%')
</if>
<if test="activity.relatedClubId != null">
AND sa.related_club_id = #{activity.relatedClubId}
</if>
<if test="activity.relatedType != null and activity.relatedType != ''">
AND sa.related_type = #{activity.relatedType}
</if>
<if test="activity.organizerName != null and activity.organizerName != ''">
AND sa.organizer_name like concat('%', #{activity.organizerName}, '%')
</if>
<if test="activity.organizerType != null and activity.organizerType != ''">
AND sa.organizer_type = #{activity.organizerType}
</if>
<if test="activity.registrationStatus != null and activity.registrationStatus != ''">
AND (
CASE
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
WHEN NOW() &lt; sa.registration_start THEN '0'
WHEN NOW() &gt;= sa.registration_start AND NOW() &lt;= sa.registration_end THEN '1'
WHEN NOW() &gt; sa.registration_end THEN '2'
ELSE sa.registration_status
END
) = #{activity.registrationStatus}
</if>
<!-- 支持报名状态IN查询(用于活动报名大厅) -->
<if test="activity.params != null and activity.params.registrationStatusList != null and activity.params.registrationStatusList.size() > 0">
AND (
CASE
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
WHEN NOW() &lt; sa.registration_start THEN '0'
WHEN NOW() &gt;= sa.registration_start AND NOW() &lt;= sa.registration_end THEN '1'
WHEN NOW() &gt; sa.registration_end THEN '2'
ELSE sa.registration_status
END
) IN
<foreach collection="activity.params.registrationStatusList" item="status" open="(" separator="," close=")">
#{status}
</foreach>
</if>
<if test="activity.activityStatus != null and activity.activityStatus != ''">
AND sa.activity_status = #{activity.activityStatus}
</if>
<if test="activity.isFinished != null">
AND sa.is_finished = #{activity.isFinished}
</if>
<if test="activity.importSource != null and activity.importSource != ''">
AND sa.import_source = #{activity.importSource}
</if>
<if test="activity.tenantId != null and activity.tenantId != ''">
AND sa.tenant_id = #{activity.tenantId}
</if>
<!-- 数据权限:非管理员只能查看自己创建的活动 -->
${activity.params.dataScope}
</where>
ORDER BY sa.create_time DESC
</select>
<select id="selectVoById" parameterType="Long" resultMap="StglActivityResult">
<include refid="selectStglActivityVo"/>
WHERE sa.deleted = 0 AND sa.id = #{id}
</select>
<select id="countByCreateBy" parameterType="Long" resultType="Long">
SELECT COUNT(*) FROM stgl_activity
WHERE create_by = #{createBy} AND deleted = 0
</select>
<select id="selectClubOptions" resultType="org.dromara.stgl.domain.vo.StglActivityVo">
SELECT
id AS relatedClubId,
club_name AS relatedClubName,
1 AS relatedType
FROM stgl_club
WHERE deleted = 0 AND status = 0
ORDER BY club_name
</select>
<select id="selectVolunteerTeamOptions" resultType="org.dromara.stgl.domain.vo.StglActivityVo">
SELECT
id AS relatedClubId,
team_name AS relatedClubName,
2 AS relatedType
FROM stgl_volunteer_team
WHERE deleted = 0 AND status = 0
ORDER BY team_name
</select>
<insert id="copyActivity">
INSERT INTO stgl_activity (
id, tenant_id, create_dept, create_by, create_time, update_by, update_time,
activity_name, activity_type, activity_theme, start_time, end_time, location,
description, poster_url, related_club_id, organizer_name, organizer_type,
organizer_contact, organizer_phone, co_organizers, instructors,
registration_type, registration_start, registration_end, registration_status,
max_participants, max_teams, team_size_min, team_size_max, need_approval,
activity_status, is_finished, summary, achievements, import_source, remark
)
SELECT
#{newActivity.id}, #{newActivity.tenantId}, #{newActivity.createDept},
#{newActivity.createBy}, #{newActivity.createTime}, #{newActivity.updateBy}, #{newActivity.updateTime},
#{newActivity.activityName}, activity_type, activity_theme,
#{newActivity.startTime}, #{newActivity.endTime}, location,
description, poster_url, related_club_id, organizer_name, organizer_type,
organizer_contact, organizer_phone, co_organizers, instructors,
registration_type, #{newActivity.registrationStart}, #{newActivity.registrationEnd},
#{newActivity.registrationStatus}, max_participants, max_teams, team_size_min, team_size_max, need_approval,
#{newActivity.activityStatus}, 0, NULL, NULL, import_source, remark
FROM stgl_activity
WHERE id = #{sourceId} AND deleted = 0
</insert>
</mapper>
Loaded 100 of 288 files, more files were not shown because too many files have changed in this diff. Show more