Files
hzdyjs/backend/ruoyi-modules/ruoyi-stgl/src/main/resources/mapper/stgl/StglActivityMapper.xml
T
“wuzhen”andCursor da8d332fac fix(security): 修复网安扫描相关严重/高危/中危漏洞并加固学生密码重置
关闭工作流 SpEL 命令执行与社团活动 SQL 注入,补齐越权、调试接口、登录喷洒和异常回显等问题;学生密码改为随机临时密码,Web/移动端支持复制。

Constraint: 流程发起/办理接口保持仅登录校验,避免影响请假审批
Rejected: 开启验证码 | Web/移动端登录页均未实现,开启会导致无法登录
Confidence: high
Scope-risk: broad
Not-tested: 生产环境与社团社长/指导老师视角
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-26 13:44:51 +08:00

470 lines
26 KiB
XML

<?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="relatedDeptId" column="related_dept_id"/>
<result property="relatedDeptName" column="related_dept_name"/>
<result property="relatedDeptIds" column="related_dept_ids"/>
<result property="relatedDeptNames" column="related_dept_names"/>
<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="activityRange" column="activity_range"/>
<result property="activityStatus" column="activity_status"/>
<result property="originalActivityStatus" column="original_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_dept_id, sa.related_dept_name, sa.related_dept_ids, sa.related_dept_names,
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.activity_status IN ('0', '2', '7') THEN NULL
-- 已取消的活动设置为已关闭
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
-- 只有审批通过的活动(已通过、进行中、已结束)才根据时间计算报名状态
WHEN sa.activity_status IN ('3', '4', '5') THEN
CASE
-- 已结束的活动强制设置报名结束
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
-- 已通过和进行中的活动根据报名时间判断
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
<![CDATA[WHEN NOW() > sa.registration_end THEN '2']]>
ELSE sa.registration_status
END
-- 其他情况保持原状态
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_range,
-- 动态计算活动状态:审批通过后根据时间自动更新状态
CASE
-- 手动控制的状态保持不变(草稿、待审批、已取消、已驳回)
WHEN sa.activity_status IN ('0', '2', '6', '7') THEN sa.activity_status
-- 审批通过后的状态根据时间自动计算
WHEN sa.activity_status IN ('3', '4', '5') THEN
CASE
<![CDATA[WHEN NOW() < sa.start_time THEN '3']]> -- 已通过(未开始)
<![CDATA[WHEN NOW() >= sa.start_time AND NOW() <= sa.end_time THEN '4']]> -- 进行中
<![CDATA[WHEN NOW() > sa.end_time THEN '5']]> -- 已结束
ELSE sa.activity_status
END
-- 其他情况保持原状态
ELSE sa.activity_status
END AS activity_status,
-- 返回原始活动状态(用于权限控制)
sa.activity_status AS original_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 AND sar.approval_status = 1) 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.activity_status IN ('0', '2', '7') THEN NULL
-- 已取消的活动设置为已关闭
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
-- 只有审批通过的活动(已通过、进行中、已结束)才根据时间计算报名状态
WHEN sa.activity_status IN ('3', '4', '5') THEN
CASE
-- 已结束的活动强制设置报名结束
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
-- 已通过和进行中的活动根据报名时间判断
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
<![CDATA[WHEN NOW() > sa.registration_end THEN '2']]>
ELSE sa.registration_status
END
-- 其他情况保持原状态
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="relatedDeptId != null">
AND sa.related_dept_id = #{relatedDeptId}
</if>
<if test="relatedClubId != null">
AND sa.related_club_id = #{relatedClubId}
</if>
<!-- 数据权限:非管理员只能查看自己创建的活动 -->
<if test="params != null">
<if test="params.dsCreateBy != null">
AND sa.create_by = #{params.dsCreateBy}
</if>
<if test="params.dsInstructor != null">
AND (1 = 0
<if test="params.dsClubIds != null and params.dsClubIds.size() > 0">
OR (sa.related_type = 1 AND sa.related_club_id IN
<foreach collection="params.dsClubIds" item="dsId" open="(" separator="," close=")">#{dsId}</foreach>)
</if>
<if test="params.dsTeamIds != null and params.dsTeamIds.size() > 0">
OR (sa.related_type = 2 AND sa.related_club_id IN
<foreach collection="params.dsTeamIds" item="dsId" open="(" separator="," close=")">#{dsId}</foreach>)
</if>
<if test="params.dsActivityIds != null and params.dsActivityIds.size() > 0">
OR sa.id IN
<foreach collection="params.dsActivityIds" item="dsId" open="(" separator="," close=")">#{dsId}</foreach>
</if>
)
</if>
</if>
</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.activityStatus != null and activity.activityStatus != ''">
AND (
CASE
-- 手动控制的状态保持不变(草稿、待审批、已取消、已驳回)
WHEN sa.activity_status IN ('0', '2', '6', '7') THEN sa.activity_status
-- 审批通过后的状态根据时间自动计算
WHEN sa.activity_status IN ('3', '4', '5') THEN
CASE
<![CDATA[WHEN NOW() < sa.start_time THEN '3']]> -- 已通过(未开始)
<![CDATA[WHEN NOW() >= sa.start_time AND NOW() <= sa.end_time THEN '4']]> -- 进行中
<![CDATA[WHEN NOW() > sa.end_time THEN '5']]> -- 已结束
ELSE sa.activity_status
END
-- 其他情况保持原状态
ELSE sa.activity_status
END
) = #{activity.activityStatus}
</if>
<if test="activity.registrationStatus != null and activity.registrationStatus != ''">
AND (
CASE
-- 草稿、待审批、已驳回状态不映射报名状态,保持为空
WHEN sa.activity_status IN ('0', '2', '7') THEN NULL
-- 已取消的活动设置为已关闭
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
-- 只有审批通过的活动(已通过、进行中、已结束)才根据时间计算报名状态
WHEN sa.activity_status IN ('3', '4', '5') THEN
CASE
-- 已结束的活动强制设置报名结束
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
-- 已通过和进行中的活动根据报名时间判断
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
<![CDATA[WHEN NOW() > sa.registration_end THEN '2']]>
ELSE sa.registration_status
END
-- 其他情况保持原状态
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.activity_status IN ('0', '2', '7') THEN NULL
-- 已取消的活动设置为已关闭
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
-- 只有审批通过的活动(已通过、进行中、已结束)才根据时间计算报名状态
WHEN sa.activity_status IN ('3', '4', '5') THEN
CASE
-- 已结束的活动强制设置报名结束
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
-- 已通过和进行中的活动根据报名时间判断
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
<![CDATA[WHEN NOW() > sa.registration_end THEN '2']]>
ELSE sa.registration_status
END
-- 其他情况保持原状态
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>
<if test="activity.relatedDeptId != null">
AND sa.related_dept_id = #{activity.relatedDeptId}
</if>
<if test="activity.relatedClubId != null">
AND sa.related_club_id = #{activity.relatedClubId}
</if>
<!-- 活动面向群体过滤:当activity_range=1时,只有组织成员才能看到 -->
<if test="activity.params != null and activity.params.userOrganizations != null">
AND (
sa.activity_range = 0
OR (
sa.activity_range = 1
<choose>
<when test="activity.params.userOrganizations.size() > 0">
AND CONCAT(sa.related_type, '-', sa.related_club_id) IN
<foreach collection="activity.params.userOrganizations" item="org" open="(" separator="," close=")">
#{org}
</foreach>
</when>
<otherwise>
AND 1 = 0
</otherwise>
</choose>
)
)
</if>
<!-- 数据权限:非管理员只能查看自己创建的活动 -->
<if test="activity.params != null">
<if test="activity.params.dsCreateBy != null">
AND sa.create_by = #{activity.params.dsCreateBy}
</if>
<if test="activity.params.dsInstructor != null">
AND (1 = 0
<if test="activity.params.dsClubIds != null and activity.params.dsClubIds.size() > 0">
OR (sa.related_type = 1 AND sa.related_club_id IN
<foreach collection="activity.params.dsClubIds" item="dsId" open="(" separator="," close=")">#{dsId}</foreach>)
</if>
<if test="activity.params.dsTeamIds != null and activity.params.dsTeamIds.size() > 0">
OR (sa.related_type = 2 AND sa.related_club_id IN
<foreach collection="activity.params.dsTeamIds" item="dsId" open="(" separator="," close=")">#{dsId}</foreach>)
</if>
<if test="activity.params.dsActivityIds != null and activity.params.dsActivityIds.size() > 0">
OR sa.id IN
<foreach collection="activity.params.dsActivityIds" item="dsId" open="(" separator="," close=")">#{dsId}</foreach>
</if>
)
</if>
</if>
</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, create_time DESC
</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, create_time DESC
</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_dept_id, related_dept_name, related_dept_ids, related_dept_names,
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_dept_id, related_dept_name, related_dept_ids, related_dept_names,
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>