Files
2025-12-25 18:01:27 +08:00

14 KiB
Raw Permalink Blame History

02-组织关系处理

📋 概述

本分文档详细说明学生退学、休学、毕业、复学处理中的组织关系处理内容,包括班级干部信息和社团成员关系的变更逻辑。

👥 组织关系处理

1. 班级干部信息处理

📊 数据库表结构

表名: xg_class_pos_msg 主键: id (bigint(20), 雪花ID) 核心关联字段:

  • class_id: 班级ID,关联 xg_class_msg.id
  • student_id: 学生ID,关联 xg_student_msg.id
  • student_no: 学号
  • student_name: 学生姓名(冗余字段)

🎯 关键业务字段

基于数据库表结构 xg_class_pos_msg,关键字段如下:

字段名 类型 说明 默认值
is_current tinyint(1) 是否现任(0-非现任,1-现任) 1
cadre_status char(1) 职务任职状态(关联stu_cadre_status字典) 1
appointment_date date 任职日期 -
term_start_date date 任期开始日期 -
term_end_date date 任期结束日期 NULL
term_duration int(11) 任期时长(月) 12
dismissal_date date 离任日期 NULL
dismissal_reason varchar(200) 离任原因 NULL
appointment_method varchar(20) 任命方式(appointment/election/recommendation) appointment

🎯 干部状态字典

系统使用 stu_cadre_status 字典类型,具体定义如下:

状态值 状态名称 说明 样式类
1 在任 正常任职状态 primary
2 到期 任期自然到期 success
3 辞职 干部主动辞职 warning
4 免职 被免去职务 danger
5 调任 职务调整调动 info
6 休学 因学生休学离任 danger

关键字段说明 (基于实体类代码分析):

  • isCurrent: 是否现任 (0-非现任,1-现任)
  • cadreStatus: 学生职务任职状态
  • dismissalDate: 离任日期
  • dismissalReason: 离任原因
  • termStartDate: 任期开始日期
  • termEndDate: 任期结束日期
  • termDuration: 任期时长(月)

🔄 离任业务流程

📋 完整离任流程
1. 验证干部信息存在性和状态
2. 计算任期时长 (term_start_date 到 term_end_date)
3. 更新干部状态为非现任 (is_current = 0)
4. 设置离任状态和原因
5. 更新任期结束日期和离任日期
6. 删除用户角色关联 (sys_user_role)
7. 记录操作日志
💻 后端实现逻辑

控制器接口: POST /xgClassPosMsg/xgClassPosMsg/dismiss/{id} 核心方法: XgClassPosMsgServiceImpl.dismissCadre()

@Override
@Transactional(rollbackFor = Exception.class)
public Boolean dismissCadre(Long id, Date termEndDate, String cadreStatus, String dismissalReason) {
    // 1. 查询并验证干部信息
    XgClassPosMsg classPosMsg = baseMapper.selectById(id);

    // 2. 计算任期时长
    Long termDuration = calculateTermDuration(classPosMsg.getTermStartDate(), termEndDate);

    // 3. 更新干部信息
    XgClassPosMsg updateEntity = new XgClassPosMsg();
    updateEntity.setId(id);
    updateEntity.setTermEndDate(termEndDate);
    updateEntity.setTermDuration(termDuration);
    updateEntity.setCadreStatus(cadreStatus);
    updateEntity.setDismissalReason(dismissalReason);
    updateEntity.setDismissalDate(termEndDate);
    updateEntity.setIsCurrent(0L); // 设置为非现任

    baseMapper.updateById(updateEntity);

    // 4. 删除用户角色关联
    sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
        .eq(SysUserRole::getUserId, classPosMsg.getStudentId()));

    return true;
}
🎨 前端离任界面

文件位置: web/src/views/xg/xsjcxx/xgClassPosMsg/xgClassPosMsg/index.vue 离任按钮: 仅对 is_current = 1 的干部显示

<!-- 离任按钮 -->
<el-tooltip content="离任" placement="top">
  <el-button
    link
    type="warning"
    icon="ArrowDown"
    @click="handleDismissal(scope.row)"
    v-if="scope.row.isCurrent === 1"
  ></el-button>
</el-tooltip>

<!-- 离任对话框 -->
<el-dialog title="班级干部离任" v-model="dismissalDialog.visible" width="500px" append-to-body>
  <el-form ref="dismissalFormRef" :model="dismissalForm" :rules="dismissalRules" label-width="140px">
    <!-- 当前信息(只读) -->
    <el-form-item label="班级名称" prop="className">
      <el-input v-model="dismissalForm.className" disabled />
    </el-form-item>
    <el-form-item label="学生姓名" prop="studentName">
      <el-input v-model="dismissalForm.studentName" disabled />
    </el-form-item>
    <el-form-item label="任期开始日期" prop="termStartDate">
      <el-input v-model="dismissalForm.termStartDate" disabled />
    </el-form-item>

    <!-- 离任信息(可填写) -->
    <el-form-item label="任期结束日期" prop="termEndDate">
      <el-date-picker
        clearable
        v-model="dismissalForm.termEndDate"
        type="date"
        value-format="YYYY-MM-DD"
        placeholder="请选择任期结束日期"
        style="width: 100%"
      />
    </el-form-item>
    <el-form-item label="离任状态" prop="cadreStatus">
      <el-select v-model="dismissalForm.cadreStatus" placeholder="请选择离任状态">
        <el-option label="到期" value="2" />
        <el-option label="辞职" value="3" />
        <el-option label="免职" value="4" />
        <el-option label="调任" value="5" />
        <el-option label="休学" value="6" />
      </el-select>
    </el-form-item>
    <el-form-item label="离任原因" prop="dismissalReason">
      <el-input v-model="dismissalForm.dismissalReason" type="textarea" placeholder="请输入离任原因" />
    </el-form-item>
  </el-form>
</el-dialog>

🔄 学生状态变更时的干部处理逻辑

  • 休学: cadre_status = '6'(休学),is_current = 0,dismissal_reason = '学生休学'
  • 退学: cadre_status = '4'(免职),is_current = 0,dismissal_reason = '学生退学'
  • 毕业: cadre_status = '4'(免职),is_current = 0,dismissal_reason = '学生毕业'

💾 SQL批量处理脚本

-- 参数说明:
-- @student_id: 学生ID
-- @change_type: 变更类型 (XIU_XUE-休学, TUI_XUE-退学, BI_YE-毕业)
-- @operator_id: 操作员ID
-- @dismissal_date: 离任日期 (默认为当前日期)

SET @dismissal_date = COALESCE(@dismissal_date, CURDATE());

-- 1. 更新干部状态(休学)
UPDATE xg_class_pos_msg
SET is_current = 0,
    cadre_status = '6',  -- 休学状态
    term_end_date = @dismissal_date,
    dismissal_date = @dismissal_date,
    dismissal_reason = '学生休学',
    term_duration = TIMESTAMPDIFF(MONTH, term_start_date, @dismissal_date),
    update_by = @operator_id,
    update_time = NOW()
WHERE student_id = @student_id
  AND is_current = 1
  AND deleted = 0
  AND @change_type = 'XIU_XUE';

-- 2. 更新干部状态(退学/毕业)
UPDATE xg_class_pos_msg
SET is_current = 0,
    cadre_status = '4',  -- 免职状态
    term_end_date = @dismissal_date,
    dismissal_date = @dismissal_date,
    dismissal_reason = CASE
        WHEN @change_type = 'TUI_XUE' THEN '学生退学'
        WHEN @change_type = 'BI_YE' THEN '学生毕业'
        ELSE '学生状态变更'
    END,
    term_duration = TIMESTAMPDIFF(MONTH, term_start_date, @dismissal_date),
    update_by = @operator_id,
    update_time = NOW()
WHERE student_id = @student_id
  AND is_current = 1
  AND deleted = 0
  AND @change_type IN ('TUI_XUE', 'BI_YE');

2. 社团成员关系处理

📊 数据库表结构

表名: stgl_member (原名 club_member,现已重构) 主键: id (bigint(20)) 核心关联字段:

  • user_id: 用户ID,关联学生用户ID
  • student_no: 学号
  • student_name: 学生姓名(冗余字段)
  • relation_id: 关联ID(社团ID或志愿者队伍ID)
  • member_type: 成员类型(1-社团成员,2-志愿者)

🎯 成员状态字典

系统使用 stgl_member_status 字典类型,具体定义如下:

状态值 状态名称 说明 样式类
0 待审核 申请加入,等待审核 warning
1 审核中 正在审核中 info
2 已加入 正式成员 success
3 已驳回 审核未通过 danger
4 已退出 已退出组织 danger

关键字段说明 (基于实体类代码分析):

  • memberType: 成员类型 (1-社团成员,2-志愿者)
  • userId: 用户ID,对应学生ID
  • studentNo: 学号
  • studentName: 学生姓名
  • roleType: 角色类型 (社长、副社长、部长、普通成员)
  • joinTime: 加入时间
  • status: 状态 (0-待审核,1-审核中,2-已加入,3-已驳回,4-已退出)

🔄 退出处理逻辑

📋 退出业务规则
  • 适用范围: 对所有状态为"待审核"(0)、"审核中"(1)、"已加入"(2)的成员
  • 处理方式: 将状态更新为"已退出"(4)
  • 数据保留: 保留历史记录,不物理删除
  • 关联清理: 不涉及其他关联数据的清理
💻 后端实现逻辑

所在模块: ruoyi-stgl (社团管理模块) 实体类: StglMember.java 服务类: StglMemberServiceImpl.java

// 社团成员实体类关键字段
@Data
@TableName("stgl_member")
public class StglMember extends TenantEntity {
    private Long userId;           // 用户ID
    private String studentNo;      // 学号
    private String studentName;    // 学生姓名
    private Integer memberType;    // 成员类型:1-社团成员,2-志愿者
    private Long relationId;       // 关联ID
    private Integer status;        // 状态:0-待审核,1-审核中,2-已加入,3-已驳回,4-已退出
    private String roleType;       // 角色类型
    private Date joinTime;         // 加入时间
}
🎨 前端界面展示

管理界面: stgl/member/index.vue 状态显示: 使用字典标签显示成员状态

<!-- 成员状态列 -->
<el-table-column label="状态" align="center" prop="status" width="100">
  <template #default="scope">
    <dict-tag :options="stgl_member_status" :value="scope.row.status" />
  </template>
</el-table-column>

🔄 学生状态变更时的成员处理逻辑

  • 休学: 成员状态改为 4(已退出),退出原因为"学生休学"
  • 退学: 成员状态改为 4(已退出),退出原因为"学生退学"
  • 毕业: 成员状态改为 4(已退出),退出原因为"学生毕业"

💾 SQL批量处理脚本

-- 参数说明:
-- @student_id: 学生ID (对应user_id)
-- @change_type: 变更类型 (XIU_XUE-休学, TUI_XUE-退学, BI_YE-毕业)
-- @operator_id: 操作员ID

-- 更新社团/志愿者成员状态为已退出
UPDATE stgl_member
SET status = 4,  -- 已退出状态
    update_by = @operator_id,
    update_time = NOW(),
    remark = CONCAT(COALESCE(remark, ''), ' | 退出原因:', CASE
        WHEN @change_type = 'XIU_XUE' THEN '学生休学'
        WHEN @change_type = 'TUI_XUE' THEN '学生退学'
        WHEN @change_type = 'BI_YE' THEN '学生毕业'
        ELSE '学生状态变更'
    END, ' - ', NOW())
WHERE user_id = @student_id
  AND status IN (0, 1, 2)  -- 待审核、审核中、已加入
  AND deleted = 0;

🔗 关联数据处理

1. 用户角色权限清理

📋 角色关联表

表名: sys_user_role 关联逻辑: 当干部离任时,需要清理对应的用户角色关联

🔄 清理逻辑

// 在干部离任时执行角色清理
int deleteCount = sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
    .eq(SysUserRole::getUserId, classPosMsg.getStudentId()));

⚠️ 注意事项

  • 仅限干部离任: 普通社团成员退出时不清理角色权限
  • 角色识别: 根据用户ID清理所有相关角色关联
  • 权限回收: 确保干部权限及时回收,避免安全风险

2. 数据一致性保证

🛡️ 事务处理要求

-- 建议在学生状态变更的大事务中包含组织关系处理
START TRANSACTION;

-- 1. 备份原始数据到his表
INSERT INTO xg_class_pos_msg_his SELECT * FROM xg_class_pos_msg WHERE student_id = ?;
INSERT INTO stgl_member_his SELECT * FROM stgl_member WHERE user_id = ?;

-- 2. 处理班级干部关系(仅退学、休学、毕业时)
UPDATE xg_class_pos_msg SET is_current = 0, cadre_status = ?, term_end_date = NOW(), dismissal_date = NOW(), dismissal_reason = ? WHERE student_id = ?;

-- 3. 处理社团成员关系(仅退学、休学、毕业时)
UPDATE stgl_member SET status = 4 WHERE user_id = ?;

-- 4. 清理用户角色(如果需要)
DELETE FROM sys_user_role WHERE user_id = ?;

COMMIT;

📊 处理统计

处理类型 涉及表数量 主要操作
班级干部 2 (干部表+角色表) 更新状态+清理权限
社团成员 1 (成员表) 更新状态
总计 3个表 状态更新+权限清理

⚠️ 重要注意事项

1. 业务规则约束

  • 干部离任: 必须通过专门的离任接口,计算任期时长
  • 成员退出: 直接更新状态,不涉及权限清理
  • 数据保留: 所有操作都保留历史记录,便于审计
  • 状态验证: 操作前验证当前状态的合法性

2. 权限与安全

  • 操作权限: 干部离任需要专门的权限验证
  • 角色清理: 确保干部权限及时回收,防止权限泄露
  • 审计记录: 记录所有组织关系变更的操作日志
  • 数据完整性: 保证关联数据的完整性约束

3. 性能优化建议

  • 批量处理: 支持对多个学生的组织关系批量处理
  • 索引优化: 确保学生ID相关的查询有适当索引
  • 事务控制: 使用合适的事务隔离级别保证数据一致性
  • 异步处理: 大批量操作考虑异步处理机制

📅 更新记录

  • 2025-12-XX: 分文档创建,包含组织关系处理逻辑
  • 2025-12-XX: 基于代码分析完善技术实现细节和业务逻辑
  • 后续更新: 根据实际业务需求持续完善

本分文档详细说明学生状态变更时的组织关系处理逻辑和技术实现,包括班级干部职务和社团成员关系的清理。