本分文档提供完整的学生退学、休学、毕业处理SQL脚本,包括数据库事务处理、错误处理和操作日志记录。基于对前后端代码的深入分析,脚本涵盖了所有相关业务模块的联动处理。
-- ===========================================
-- 学生状态变更通用处理存储过程
-- 支持:休学(XIU_XUE)、退学(TUI_XUE)、复学(FU_XUE)、毕业(BI_YE)
-- 参数说明:
-- @student_id: 学生ID
-- @student_no: 学生学号
-- @change_type: 变更类型
-- @operator_id: 操作员ID
-- @effective_date: 生效日期 (可选,默认当前日期)
-- ===========================================
DELIMITER //
CREATE PROCEDURE process_student_status_change(
IN p_student_id BIGINT,
IN p_student_no VARCHAR(32),
IN p_change_type VARCHAR(20),
IN p_operator_id BIGINT,
IN p_effective_date DATE
)
BEGIN
DECLARE v_current_time DATETIME DEFAULT NOW();
DECLARE v_effective_date DATE DEFAULT COALESCE(p_effective_date, CURDATE());
DECLARE v_new_student_status VARCHAR(10);
DECLARE v_disable_user_account BOOLEAN DEFAULT FALSE;
DECLARE v_exit_reason VARCHAR(100);
DECLARE v_cadre_status VARCHAR(10);
DECLARE v_dismissal_reason VARCHAR(200);
DECLARE v_error_message VARCHAR(500);
DECLARE v_affected_rows INT DEFAULT 0;
-- 声明异常处理
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SET v_error_message = CONCAT('学生状态变更处理失败: ', p_change_type, ', 学生ID: ', p_student_id);
-- 记录错误日志
INSERT INTO sys_oper_log (
title, business_type, method, request_method, operator_type,
oper_name, dept_name, oper_url, oper_ip, oper_location,
oper_param, json_result, status, error_msg, oper_time, cost_time
) VALUES (
'学生状态变更', 'UPDATE', 'processStudentStatusChange', 'PROCEDURE', 'MANAGE',
'系统', '教务处', '/student/status/change', '127.0.0.1', '本地',
CONCAT('学生ID:', p_student_id, ',变更类型:', p_change_type), '{}', 1, v_error_message, v_current_time, 0
);
RESIGNAL;
END;
-- 开始事务
START TRANSACTION;
-- 1. 验证学生存在性
SELECT COUNT(1) INTO v_affected_rows FROM xg_student_msg
WHERE id = p_student_id AND deleted = 0;
IF v_affected_rows = 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '学生不存在或已被删除';
END IF;
-- 2. 根据变更类型设置参数
CASE p_change_type
WHEN 'XIU_XUE' THEN
SET v_new_student_status = '2'; -- 休学
SET v_disable_user_account = FALSE; -- 休学可保留账号
SET v_exit_reason = '学生休学';
SET v_cadre_status = '6'; -- 休学离任
SET v_dismissal_reason = '学生休学';
WHEN 'TUI_XUE' THEN
SET v_new_student_status = '4'; -- 退学
SET v_disable_user_account = TRUE; -- 退学必须禁用账号
SET v_exit_reason = '学生退学';
SET v_cadre_status = '4'; -- 免职离任
SET v_dismissal_reason = '学生退学';
WHEN 'FU_XUE' THEN
SET v_new_student_status = '3'; -- 复学
SET v_disable_user_account = FALSE; -- 复学恢复账号
SET v_exit_reason = NULL; -- 复学不涉及退出
SET v_cadre_status = NULL; -- 复学不涉及干部
SET v_dismissal_reason = NULL;
WHEN 'BI_YE' THEN
SET v_new_student_status = '5'; -- 毕业
SET v_disable_user_account = TRUE; -- 毕业禁用账号
SET v_exit_reason = '学生毕业';
SET v_cadre_status = '4'; -- 免职离任
SET v_dismissal_reason = '学生毕业';
ELSE
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '无效的变更类型';
END CASE;
-- 3. 创建状态变更记录
INSERT INTO xg_student_status_change (
student_id, student_no, change_type, apply_date,
effective_date, operator_id, source, process_status
) VALUES (
p_student_id, p_student_no, p_change_type, v_current_time,
v_effective_date, p_operator_id, 'system', 1
);
-- 4. 备份原始数据到his表
INSERT INTO xg_student_msg_his SELECT * FROM xg_student_msg WHERE id = p_student_id;
INSERT INTO sys_user_his SELECT * FROM sys_user WHERE user_id = p_student_id;
-- 5. 更新学生学籍状态
UPDATE xg_student_msg
SET student_status = v_new_student_status,
update_by = p_operator_id,
update_time = v_current_time
WHERE id = p_student_id AND deleted = 0;
-- 6. 处理用户账号状态
IF v_disable_user_account THEN
UPDATE sys_user
SET status = '1',
update_by = p_operator_id,
update_time = v_current_time
WHERE user_id = p_student_id AND account_type = '2' AND del_flag = '0';
ELSE
UPDATE sys_user
SET status = '0',
update_by = p_operator_id,
update_time = v_current_time
WHERE user_id = p_student_id AND account_type = '2' AND del_flag = '0';
END IF;
-- 6. 处理班级干部信息(休学、退学、毕业)
IF p_change_type IN ('XIU_XUE', 'TUI_XUE', 'BI_YE') THEN
UPDATE xg_class_pos_msg
SET is_current = 0,
cadre_status = v_cadre_status,
dismissal_date = v_effective_date,
dismissal_reason = v_dismissal_reason,
term_end_date = v_effective_date,
term_duration = TIMESTAMPDIFF(MONTH, term_start_date, v_effective_date),
update_by = p_operator_id,
update_time = v_current_time
WHERE student_id = p_student_id AND is_current = 1 AND deleted = 0;
-- 清理干部用户角色权限
DELETE FROM sys_user_role
WHERE user_id = p_student_id;
END IF;
-- 7. 处理社团成员关系(休学、退学、毕业)
IF p_change_type IN ('XIU_XUE', 'TUI_XUE', 'BI_YE') THEN
UPDATE stgl_member
SET status = 4, -- 已退出
update_by = p_operator_id,
update_time = v_current_time,
remark = CONCAT(COALESCE(remark, ''), ' | ', v_exit_reason, ' - ', v_current_time)
WHERE user_id = p_student_id AND status IN (0, 1, 2) AND deleted = 0;
END IF;
-- 11. 处理宿舍住宿关系(退学、毕业)
IF p_change_type IN ('TUI_XUE', 'BI_YE') THEN
UPDATE xg_dorm_bed_student
SET status = '1',
checkout_time = v_current_time,
update_by = p_operator_id,
update_time = v_current_time,
remark = CONCAT(COALESCE(remark, ''), ' | ', v_exit_reason, '退宿')
WHERE student_id = p_student_id AND status = '0' AND deleted = '0';
END IF;
-- 提交事务
COMMIT;
-- 记录操作日志
INSERT INTO sys_oper_log (
title, business_type, method, request_method, operator_type,
oper_name, dept_name, oper_url, oper_ip, oper_location,
oper_param, json_result, status, error_msg, oper_time, cost_time
) VALUES (
'学生状态变更', 'UPDATE', 'processStudentStatusChange', 'PROCEDURE', 'MANAGE',
'系统', '教务处', '/student/status/change', '127.0.0.1', '本地',
CONCAT('学生ID:', p_student_id, ',学号:', p_student_no, ',变更类型:', p_change_type), '{}', 0, NULL, v_current_time, 0
);
END //
DELIMITER ;
-- ===========================================
-- 学生退学处理专用脚本
-- 参数说明:
-- @student_id: 学生ID
-- @student_no: 学生学号
-- @operator_id: 操作员ID
-- ===========================================
DELIMITER //
CREATE PROCEDURE process_student_dropout(
IN p_student_id BIGINT,
IN p_student_no VARCHAR(32),
IN p_operator_id BIGINT
)
BEGIN
CALL process_student_status_change(p_student_id, p_student_no, 'TUI_XUE', p_operator_id, CURDATE());
END //
DELIMITER ;
-- 调用示例:
-- CALL process_student_dropout(123456789, '20240001', 1);
-- ===========================================
-- 学生休学处理专用脚本
-- 参数说明:
-- @student_id: 学生ID
-- @student_no: 学生学号
-- @operator_id: 操作员ID
-- ===========================================
DELIMITER //
CREATE PROCEDURE process_student_suspend(
IN p_student_id BIGINT,
IN p_student_no VARCHAR(32),
IN p_operator_id BIGINT
)
BEGIN
CALL process_student_status_change(p_student_id, p_student_no, 'XIU_XUE', p_operator_id, CURDATE());
END //
DELIMITER ;
-- 调用示例:
-- CALL process_student_suspend(123456789, '20240001', 1);
-- ===========================================
-- 学生毕业处理专用脚本
-- 参数说明:
-- @student_id: 学生ID
-- @student_no: 学生学号
-- @operator_id: 操作员ID
-- ===========================================
DELIMITER //
CREATE PROCEDURE process_student_graduation(
IN p_student_id BIGINT,
IN p_student_no VARCHAR(32),
IN p_operator_id BIGINT
)
BEGIN
CALL process_student_status_change(p_student_id, p_student_no, 'BI_YE', p_operator_id, CURDATE());
END //
DELIMITER ;
-- 调用示例:
-- CALL process_student_graduation(123456789, '20240001', 1);
graph TD
A[开始] --> B[验证学生信息]
B --> C{学生存在?}
C -->|否| D[抛出异常]
C -->|是| E{变更类型}
E -->|休学| F[设置休学参数]
E -->|退学| G[设置退学参数]
E -->|复学| H[设置复学参数]
E -->|毕业| I[设置毕业参数]
F --> J[创建变更记录]
G --> J
H --> J
I --> J
J --> K[更新学生学籍状态]
K --> L[处理用户账号状态]
L --> M{需要禁用账号?}
M -->|是| N[禁用用户账号]
M -->|否| O[保留用户账号]
N --> P{涉及组织关系?}
O --> P
P -->|是| Q[处理班级干部关系]
P -->|否| R[跳过组织关系处理]
Q --> S[处理社团成员关系]
R --> T[处理经济资助]
S --> T
T --> U[奖学金申请处理]
T --> V[勤工俭学申请处理]
T --> W[贫困生认定处理]
U --> X{涉及住宿管理?}
V --> X
W --> X
X -->|是| Y[处理宿舍关系]
X -->|否| Z[处理心理健康]
Y --> Z
Z --> AA[心理咨询预约取消]
AA --> BB{涉及实践活动?}
BB -->|是| CC[取消学生活动报名]
BB -->|否| DD[跳过实践活动处理]
CC --> EE[终止实习信息]
EE --> FF[记录操作日志]
DD --> FF
FF --> GG[提交事务]
GG --> HH[结束]
D --> II[异常处理]
II --> JJ[回滚事务]
JJ --> KK[记录错误日志]
XgStudentMsg.java - 学生信息实体XgStudentStatusChange.java - 状态变更记录实体XgStudentStatusChangeController.java - API接口层XgStudentStatusChangeServiceImpl.java - 业务逻辑层XgStudentStatusChangeMapper.java - 数据访问层@Service
@RequiredArgsConstructor
public class XgStudentStatusChangeServiceImpl implements IXgStudentStatusChangeService {
private final XgStudentStatusChangeMapper baseMapper;
private final XgStudentMsgMapper studentMapper;
private final SysUserMapper userMapper;
private final XgClassPosMsgMapper classPosMapper;
private final StglMemberMapper memberMapper;
@Transactional(rollbackFor = Exception.class)
public Boolean processStudentStatusChange(XgStudentStatusChangeBo bo) {
// 1. 验证学生信息
XgStudentMsg student = validateStudent(bo.getStudentId());
// 2. 验证业务规则
validateChangeRules(student, bo.getChangeType());
// 3. 创建变更记录
XgStudentStatusChange change = createChangeRecord(bo);
// 4. 更新学生状态
updateStudentStatus(student, bo.getChangeType(), bo.getOperatorId());
// 5. 处理用户账号
handleUserAccount(student, bo.getChangeType(), bo.getOperatorId());
// 6. 处理组织关系
handleOrganizationRelations(student, bo.getChangeType(), bo.getOperatorId());
// 7. 处理经济资助
handleEconomicSupport(student, bo.getChangeType(), bo.getOperatorId());
// 8. 处理其他业务
handleOtherBusiness(student, bo.getChangeType(), bo.getOperatorId());
// 9. 记录操作日志
logOperation(change);
return true;
}
private XgStudentMsg validateStudent(Long studentId) {
XgStudentMsg student = studentMapper.selectById(studentId);
if (student == null || student.getDeleted() == 1L) {
throw new ServiceException("学生不存在或已被删除");
}
return student;
}
private void validateChangeRules(XgStudentMsg student, String changeType) {
String currentStatus = student.getStudentStatus();
// 状态变更规则验证
switch (changeType) {
case "XIU_XUE": // 休学
if (!"1".equals(currentStatus)) { // 必须是在读状态
throw new ServiceException("只有在读学生才能申请休学");
}
break;
case "TUI_XUE": // 退学
if ("5".equals(currentStatus)) { // 毕业状态不能退学
throw new ServiceException("已毕业学生不能退学");
}
break;
case "FU_XUE": // 复学
if (!"2".equals(currentStatus)) { // 必须是休学状态
throw new ServiceException("只有休学学生才能复学");
}
break;
case "BI_YE": // 毕业
if (!"1".equals(currentStatus) && !"3".equals(currentStatus)) {
throw new ServiceException("只有在读或复学学生才能毕业");
}
break;
}
}
}
文件位置: web/src/views/xg/xsjcxx/xgStudentStatusChange/index.vue
<template>
<div class="app-container">
<!-- 查询表单 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="学号" prop="studentNo">
<el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="变更类型" prop="changeType">
<el-select v-model="queryParams.changeType" placeholder="请选择变更类型" clearable style="width: 200px">
<el-option label="休学" value="XIU_XUE" />
<el-option label="退学" value="TUI_XUE" />
<el-option label="复学" value="FU_XUE" />
<el-option label="毕业" value="BI_YE" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['studentMsg:studentStatusChange:add']">
新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate" v-hasPermi="['studentMsg:studentStatusChange:edit']">
修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete" v-hasPermi="['studentMsg:studentStatusChange:remove']">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Operation" @click="handleBatchProcess" v-hasPermi="['studentMsg:studentStatusChange:process']">
批量处理
</el-button>
</el-col>
</el-row>
<!-- 数据表格 -->
<el-table v-loading="loading" :data="statusChangeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column label="学号" align="center" prop="studentNo" />
<el-table-column label="学生姓名" align="center">
<template #default="scope">
<span>{{ scope.row.studentName }}</span>
</template>
</el-table-column>
<el-table-column label="变更类型" align="center" prop="changeType">
<template #default="scope">
<el-tag :type="getChangeTypeTagType(scope.row.changeType)">
{{ getChangeTypeLabel(scope.row.changeType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="生效日期" align="center" prop="effectiveDate" width="120">
<template #default="scope">
<span>{{ parseTime(scope.row.effectiveDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="处理状态" align="center" prop="processStatus" width="100">
<template #default="scope">
<el-tag :type="scope.row.processStatus === 1 ? 'success' : 'warning'">
{{ scope.row.processStatus === 1 ? '已处理' : '未处理' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作员" align="center" prop="operatorName" />
<el-table-column label="操作时间" align="center" prop="createTime" width="180" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button size="small" type="text" icon="View" @click="handleView(scope.row)" v-hasPermi="['studentMsg:studentStatusChange:query']">详情</el-button>
<el-button size="small" type="text" icon="Edit" @click="handleUpdate(scope.row)" v-if="scope.row.processStatus === 0" v-hasPermi="['studentMsg:studentStatusChange:edit']">修改</el-button>
<el-button size="small" type="text" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['studentMsg:studentStatusChange:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 状态变更对话框 -->
<el-dialog :title="title" v-model="open" width="600px" append-to-body>
<el-form ref="statusChangeForm" :model="form" :rules="rules" label-width="100px">
<!-- 学生信息选择 -->
<el-row>
<el-col :span="12">
<el-form-item label="学号" prop="studentNo">
<el-input v-model="form.studentNo" placeholder="请输入学号" @blur="handleStudentNoBlur" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="学生姓名">
<el-input v-model="form.studentName" disabled />
</el-form-item>
</el-col>
</el-row>
<!-- 变更信息 -->
<el-row>
<el-col :span="12">
<el-form-item label="变更类型" prop="changeType">
<el-select v-model="form.changeType" placeholder="请选择变更类型" style="width: 100%">
<el-option label="休学" value="XIU_XUE" />
<el-option label="退学" value="TUI_XUE" />
<el-option label="复学" value="FU_XUE" />
<el-option label="毕业" value="BI_YE" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="生效日期" prop="effectiveDate">
<el-date-picker
v-model="form.effectiveDate"
type="date"
placeholder="选择生效日期"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="变更原因" prop="reason">
<el-input
v-model="form.reason"
type="textarea"
placeholder="请输入变更原因"
maxlength="500"
show-word-limit
:rows="3"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
| 当前状态 | 可变更状态 | 说明 | 账号处理 | 组织关系 | 经济资助 | 住宿管理 |
|---|---|---|---|---|---|---|
| 在读(1) | 休学(2)、退学(4)、毕业(5) | 正常学籍状态 | 休学保留,退学/毕业禁用 | 处理干部和社团 | 终止申请 | 退学/毕业退宿 |
| 休学(2) | 复学(3)、退学(4) | 休学后状态 | 复学恢复,退学禁用 | 退学处理干部和社团 | 终止申请 | 退学退宿 |
| 复学(3) | 休学(2)、退学(4)、毕业(5) | 复学后状态 | 毕业禁用 | 退学处理干部和社团 | 终止申请 | 退学/毕业退宿 |
| 其他状态 | 需特殊审批 | 异常状态 | 根据情况 | 根据情况 | 根据情况 | 根据情况 |
本分文档基于对前后端代码的深入分析,提供完整的SQL处理脚本和详细的技术实现方案,确保业务逻辑的准确性和系统的高可用性。