393 lines
14 KiB
Markdown
393 lines
14 KiB
Markdown
# 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()`
|
||
|
||
```java
|
||
@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` 的干部显示
|
||
|
||
```vue
|
||
<!-- 离任按钮 -->
|
||
<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批量处理脚本
|
||
```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`
|
||
|
||
```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`
|
||
**状态显示**: 使用字典标签显示成员状态
|
||
|
||
```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批量处理脚本
|
||
```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`
|
||
**关联逻辑**: 当干部离任时,需要清理对应的用户角色关联
|
||
|
||
#### 🔄 清理逻辑
|
||
```java
|
||
// 在干部离任时执行角色清理
|
||
int deleteCount = sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
|
||
.eq(SysUserRole::getUserId, classPosMsg.getStudentId()));
|
||
```
|
||
|
||
#### ⚠️ 注意事项
|
||
- **仅限干部离任**: 普通社团成员退出时不清理角色权限
|
||
- **角色识别**: 根据用户ID清理所有相关角色关联
|
||
- **权限回收**: 确保干部权限及时回收,避免安全风险
|
||
|
||
### 2. 数据一致性保证
|
||
|
||
#### 🛡️ 事务处理要求
|
||
```sql
|
||
-- 建议在学生状态变更的大事务中包含组织关系处理
|
||
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**: 基于代码分析完善技术实现细节和业务逻辑
|
||
- **后续更新**: 根据实际业务需求持续完善
|
||
|
||
---
|
||
|
||
*本分文档详细说明学生状态变更时的组织关系处理逻辑和技术实现,包括班级干部职务和社团成员关系的清理。*
|