From 34a843e790eb45398c0b6b8b3a2c82f15ed284b0 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Thu, 25 Dec 2025 22:20:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dromara/xg/mapper/XgStudentMsgMapper.java | 2 +- ...XgClassTeacherCounselorRelServiceImpl.java | 8 +- .../impl/XgDormBedStudentServiceImpl.java | 2 +- .../service/impl/XgDormRoomServiceImpl.java | 4 +- .../service/impl/XgStudentMsgServiceImpl.java | 22 +- .../xg/service/impl/XgStudentServiceImpl.java | 2 +- .../mapper/studentMsg/XgStudentMsgMapper.xml | 2 +- 学生换班级/README.md | 7 + 学生换班级/README_换班级脚本.md | 248 +++++++++++++ 学生换班级/control_scripts.sh | 332 +++++++++++++++++ 学生换班级/data.conf | 17 + 学生换班级/health_check.sh | 348 ++++++++++++++++++ 学生换班级/process_student_class_change.sh | 301 +++++++++++++++ 退学、休学、复学、毕业/README.md | 42 +-- 退学、休学、复学、毕业/control_scripts.sh | 94 ++--- 退学、休学、复学、毕业/data.conf | 6 +- 退学、休学、复学、毕业/demo.sh | 84 ----- 退学、休学、复学、毕业/health_check.sh | 82 ++--- .../process_student_changes.sh | 171 +++++---- .../process_student_resume.sh | 81 ++-- 退学、休学、复学、毕业/start_services.sh | 123 ------- 退学、休学、复学、毕业/stop_services.sh | 177 --------- 退学、休学、复学、毕业/test_data.sql | 104 ------ 23 files changed, 1541 insertions(+), 718 deletions(-) create mode 100644 学生换班级/README_换班级脚本.md create mode 100755 学生换班级/control_scripts.sh create mode 100644 学生换班级/data.conf create mode 100755 学生换班级/health_check.sh create mode 100755 学生换班级/process_student_class_change.sh delete mode 100755 退学、休学、复学、毕业/demo.sh delete mode 100755 退学、休学、复学、毕业/start_services.sh delete mode 100755 退学、休学、复学、毕业/stop_services.sh delete mode 100644 退学、休学、复学、毕业/test_data.sql diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/mapper/XgStudentMsgMapper.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/mapper/XgStudentMsgMapper.java index 27eda846..b5737a8b 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/mapper/XgStudentMsgMapper.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/mapper/XgStudentMsgMapper.java @@ -66,7 +66,7 @@ public interface XgStudentMsgMapper extends BaseMapperPlus studentUpdateWrapper = Wrappers.lambdaUpdate(XgStudentMsg.class) - .eq(XgStudentMsg::getClassId, bo.getClassId()) + .eq(XgStudentMsg::getClassId, String.valueOf(bo.getClassId())) .set(XgStudentMsg::getClassTeacherId, null) .set(XgStudentMsg::getClassTeacherName, null); int updateResult11 = xgStudentMsgMapper.update(null, studentUpdateWrapper); @@ -195,7 +195,7 @@ public class XgClassTeacherCounselorRelServiceImpl implements IXgClassTeacherCou // 3. 更新学生表xg_student_msg表中的班主任信息 LambdaUpdateWrapper studentUpdateWrapper = Wrappers.lambdaUpdate(XgStudentMsg.class) - .eq(XgStudentMsg::getClassId, bo.getClassId()) + .eq(XgStudentMsg::getClassId, String.valueOf(bo.getClassId())) .set(XgStudentMsg::getClassTeacherId, bo.getTeacherId()) .set(XgStudentMsg::getClassTeacherName, bo.getTeacherName()); int updateResult11 = xgStudentMsgMapper.update(null, studentUpdateWrapper); @@ -273,7 +273,7 @@ public class XgClassTeacherCounselorRelServiceImpl implements IXgClassTeacherCou // 3. 更新学生表xg_student_msg表中的辅导员信息 LambdaUpdateWrapper studentUpdateWrapper = Wrappers.lambdaUpdate(XgStudentMsg.class) - .eq(XgStudentMsg::getClassId, bo.getClassId()) + .eq(XgStudentMsg::getClassId, String.valueOf(bo.getClassId())) .set(XgStudentMsg::getCounselorId, null) .set(XgStudentMsg::getCounselorName, null); int updateResult11 = xgStudentMsgMapper.update(null, studentUpdateWrapper); @@ -295,7 +295,7 @@ public class XgClassTeacherCounselorRelServiceImpl implements IXgClassTeacherCou bo.getClassId(), bo.getTeacherId(), bo.getTeacherName()); // 3. 更新学生表xg_student_msg表中的辅导员信息 LambdaUpdateWrapper studentUpdateWrapper = Wrappers.lambdaUpdate(XgStudentMsg.class) - .eq(XgStudentMsg::getClassId, bo.getClassId()) + .eq(XgStudentMsg::getClassId, String.valueOf(bo.getClassId())) .set(XgStudentMsg::getCounselorId, bo.getTeacherId()) .set(XgStudentMsg::getCounselorName, bo.getTeacherName()); int updateResult11 = xgStudentMsgMapper.update(null, studentUpdateWrapper); diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBedStudentServiceImpl.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBedStudentServiceImpl.java index 51f00ad9..3d1a9036 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBedStudentServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormBedStudentServiceImpl.java @@ -1472,7 +1472,7 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService { studentQuery.eq(XgStudentMsg::getStudentStatus, "1") // 学生状态为正常 .eq(XgStudentMsg::getDeleted, 0L) // 未删除 .eq(XgStudentMsg::getIsBoarder, "1") // 需要住校 - .eq(XgStudentMsg::getClassId, targetClassId) // 指定班级 + .eq(XgStudentMsg::getClassId, String.valueOf(targetClassId)) // 指定班级(转换为String类型) .orderByDesc(XgStudentMsg::getStudentNo); // 按学号倒序排序 List boardingStudents = xgStudentMsgMapper.selectList(studentQuery); diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormRoomServiceImpl.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormRoomServiceImpl.java index 36502a5e..19f70a56 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormRoomServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormRoomServiceImpl.java @@ -82,7 +82,8 @@ public class XgDormRoomServiceImpl implements IXgDormRoomService { @Override public TableDataInfo queryPageList(XgDormRoomBo bo, PageQuery pageQuery) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); - Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + // 由于buildQueryWrapper中已经设置了业务排序,禁用PageQuery的默认排序(创建时间倒序) + Page result = baseMapper.selectVoPage(pageQuery.disableDefaultOrder().build(), lqw); return TableDataInfo.build(result); } @@ -163,6 +164,7 @@ public class XgDormRoomServiceImpl implements IXgDormRoomService { private LambdaQueryWrapper buildQueryWrapper(XgDormRoomBo bo) { Map params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + // 设置业务排序规则 lqw.orderByAsc(XgDormRoom::getFloorNum); // 第一优先级:按楼层升序 lqw.orderByAsc(XgDormRoom::getSort); // 第二优先级:按排序号升序 lqw.orderByAsc(XgDormRoom::getRoomName); // 第三优先级:按房间名称升序 diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentMsgServiceImpl.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentMsgServiceImpl.java index 2ecea4df..61e4ba9c 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentMsgServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentMsgServiceImpl.java @@ -1098,7 +1098,16 @@ public class XgStudentMsgServiceImpl implements IXgStudentMsgService { log.info("根据学生ID获取学院请假审批人列表 - 学生ID: {}", studentId); // 1. 根据学生ID查询学院ID - Long collegeId = baseMapper.selectCollegeIdByStudentId(studentId); + String collegeIdStr = baseMapper.selectCollegeIdByStudentId(studentId); + Long collegeId = null; + if (StringUtils.isNotBlank(collegeIdStr)) { + try { + collegeId = Long.valueOf(collegeIdStr); + } catch (NumberFormatException e) { + log.warn("学院ID格式错误,无法转换为Long类型 - 学生ID: {}, collegeIdStr: {}", studentId, collegeIdStr); + return new ArrayList<>(); + } + } if (collegeId == null) { log.warn("未找到学生对应的学院信息 - 学生ID: {}", studentId); return new ArrayList<>(); @@ -1124,7 +1133,16 @@ public class XgStudentMsgServiceImpl implements IXgStudentMsgService { log.info("根据学生ID获取二级学院分管领导ID列表 - 学生ID: {}", studentId); // 1. 根据学生ID查询学院ID - Long collegeId = baseMapper.selectCollegeIdByStudentId(studentId); + String collegeIdStr = baseMapper.selectCollegeIdByStudentId(studentId); + Long collegeId = null; + if (StringUtils.isNotBlank(collegeIdStr)) { + try { + collegeId = Long.valueOf(collegeIdStr); + } catch (NumberFormatException e) { + log.warn("学院ID格式错误,无法转换为Long类型 - 学生ID: {}, collegeIdStr: {}", studentId, collegeIdStr); + return new ArrayList<>(); + } + } if (collegeId == null) { log.warn("未找到学生对应的学院信息 - 学生ID: {}", studentId); return new ArrayList<>(); diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentServiceImpl.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentServiceImpl.java index df10331f..b61f2842 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentServiceImpl.java @@ -148,7 +148,7 @@ public class XgStudentServiceImpl implements IXgStudentService { // "#result == null || #result.isEmpty()") public List getStudentsByClassId(Long classId) { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.eq(XgStudentMsg::getClassId, classId); + lqw.eq(XgStudentMsg::getClassId, String.valueOf(classId)); lqw.eq(XgStudentMsg::getStudentStatus, "1"); // 只查询在籍学生 lqw.orderByDesc(XgStudentMsg::getStudentNo); // 按学号倒序排序 return baseMapper.selectVoList(lqw); diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/resources/mapper/studentMsg/XgStudentMsgMapper.xml b/backend/ruoyi-modules/ruoyi-xg/src/main/resources/mapper/studentMsg/XgStudentMsgMapper.xml index ecc20c48..cfe62f95 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/resources/mapper/studentMsg/XgStudentMsgMapper.xml +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/resources/mapper/studentMsg/XgStudentMsgMapper.xml @@ -148,7 +148,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - SELECT college_id FROM xg_student_msg WHERE id = #{studentId} diff --git a/学生换班级/README.md b/学生换班级/README.md index 5ea83a73..5e00a763 100644 --- a/学生换班级/README.md +++ b/学生换班级/README.md @@ -10,6 +10,13 @@ - **[学生换班级记录表.sql](学生换班级记录表.sql)** - 学生换班级记录表的完整建表SQL脚本 - **[学生换班级记录表设计说明.md](学生换班级记录表设计说明.md)** - 详细的表结构设计说明文档 +### 🔧 处理脚本(新增) +- **[process_student_class_change.sh](process_student_class_change.sh)** - 准实时处理换班级工单的主脚本 +- **[control_scripts.sh](control_scripts.sh)** - 脚本控制程序,支持启动、停止、重启等操作 +- **[health_check.sh](health_check.sh)** - 服务健康检查和监控脚本 +- **[data.conf](data.conf)** - 数据库连接和脚本运行配置 +- **[README_换班级脚本.md](README_换班级脚本.md)** - 换班级处理脚本的详细技术文档 + ## 🎯 业务概述 学生换班级记录表用于记录学校所有学生换班级的操作历史,包括: diff --git a/学生换班级/README_换班级脚本.md b/学生换班级/README_换班级脚本.md new file mode 100644 index 00000000..b37f4d7c --- /dev/null +++ b/学生换班级/README_换班级脚本.md @@ -0,0 +1,248 @@ +# 学生换班级处理脚本 + +## 📁 概述 + +本脚本用于准实时处理学生换班级工单,实现学生信息的自动更新和干部信息的终止处理。参考退学、休学、复学、毕业脚本的架构设计,提供完整的换班级业务处理能力。 + +## 🎯 业务需求 + +### 1. 干部信息终止 +- 参考退学等脚本思路,终止学生的干部职务 +- 设置干部状态为"换班级终止"(cadre_status = '5') +- 记录终止原因和时间 + +### 2. 学生信息更新 +- 更新学生基本班级信息(学院、专业、班级、年级等) +- 更新预留字段,从新班级表获取完整信息 +- 特别处理 `academic_level` 字段,对应 `xg_class_msg.class_type` + +## 📋 文件清单 + +### 🔧 核心脚本 +- **[process_student_class_change.sh](process_student_class_change.sh)** - 主处理脚本,实现换班级业务逻辑 +- **[control_scripts.sh](control_scripts.sh)** - 脚本控制程序,支持启动、停止、重启等操作 +- **[health_check.sh](health_check.sh)** - 服务健康检查脚本 + +### ⚙️ 配置文件 +- **[data.conf](data.conf)** - 数据库连接配置 + +### 📊 数据库设计 +- **[学生换班级记录表.sql](学生换班级记录表.sql)** - 换班级记录表结构 +- **[学生换班级记录表设计说明.md](学生换班级记录表设计说明.md)** - 详细设计文档 + +## 🔄 处理流程 + +``` +换班级工单提交 → 脚本检测 → 获取新班级信息 → 终止干部职务 → 更新学生信息 → 标记处理完成 +``` + +### 详细步骤 + +1. **工单检测**: 扫描 `status = '0'` 的换班级记录 +2. **班级信息获取**: 从 `xg_class_msg` 表获取新班级完整信息 +3. **干部信息终止**: + - 设置 `is_current = 0` + - 设置 `cadre_status = '5'`(换班级终止) + - 记录终止日期和原因 +4. **学生信息更新**: + - 更新基础班级信息(college_id, major_id, class_id等) + - 更新预留字段(school_system, academic_level, training_type等) + - academic_level 对应 class_type +5. **工单状态更新**: 设置 `status = '1'` 标记处理完成 + +## 🗄️ 数据映射 + +### 新班级信息获取 +```sql +SELECT + college_id, college_name, major_id, major_name, + class_code, class_name, class_type, grade, + training_type, counselor_id, counselor_name, + class_teacher_id, class_teacher_name, school_system +FROM xg_class_msg +WHERE id = {new_class_id} +``` + +### 学生信息更新字段 +```sql +UPDATE xg_student_msg SET + -- 基础班级信息 + college_id = '{college_id}', + college_name = '{college_name}', + major_id = '{major_id}', + major_name = '{major_name}', + class_id = '{new_class_id}', + class_name = '{class_name}', + grade = '{grade}', + + -- 预留字段 (7182-7195行) + school_system = '{school_system}', + academic_level = '{class_type}', -- 关键映射 + training_type = '{training_type}', + counselor_id = {counselor_id}, + counselor_name = '{counselor_name}', + class_teacher_id = {class_teacher_id}, + class_teacher_name = '{class_teacher_name}', + + -- 更新信息 + update_by = {operator_id}, + update_time = NOW() +WHERE id = {student_id} +``` + +## 🚀 部署使用 + +### 1. 配置数据库连接 +```bash +vim data.conf +# 修改数据库连接信息 +``` + +### 2. 启动服务 +```bash +# 启动换班级处理服务 +./control_scripts.sh start class_change + +# 或启动所有服务 +./control_scripts.sh startall +``` + +### 3. 查看服务状态 +```bash +# 查看所有服务状态 +./control_scripts.sh statusall + +# 查看特定服务 +./control_scripts.sh status class_change +``` + +### 4. 健康检查 +```bash +# 执行健康检查 +./health_check.sh + +# 生成详细报告 +./health_check.sh --report +``` + +### 5. 停止服务 +```bash +# 停止换班级处理服务 +./control_scripts.sh stop class_change + +# 或停止所有服务 +./control_scripts.sh stopall +``` + +## 📊 监控日志 + +### 日志位置 +- **主日志**: `./student_class_change/process_student_class_change_*.log` +- **包含信息**: 处理详情、错误信息、性能统计 + +### 日志内容示例 +``` +[2025-01-25 10:00:00] [INFO] Starting student class change processing daemon +[2025-01-25 10:00:00] [INFO] Processing student change - ID: 123, Student: 20240001 (456), New Class ID: 789 +[2025-01-25 10:00:00] [INFO] Successfully processed student class change - ID: 123, Student: 20240001 +``` + +## ⚙️ 配置参数 + +### data.conf 配置项 +```bash +# 数据库配置 +DB_HOST="localhost" +DB_PORT="3306" +DB_NAME="hzdyjs_xg" +DB_USER="root" +DB_PASS="password" + +# 脚本配置 +LOG_DIR="./student_class_change" +BATCH_SIZE=100 # 每批处理数量 +MAX_RETRY=3 # 最大重试次数 +RETRY_DELAY=5 # 重试间隔(秒) +CYCLE_INTERVAL=600 # 检查周期(秒) +``` + +## 🔧 故障排除 + +### 常见问题 + +1. **数据库连接失败** + ```bash + # 检查配置 + cat data.conf + # 测试连接 + mysql -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASS $DB_NAME -e "SELECT 1;" + ``` + +2. **服务无法启动** + ```bash + # 检查脚本权限 + ls -la *.sh + # 设置执行权限 + chmod +x *.sh + ``` + +3. **处理失败** + ```bash + # 查看日志 + tail -f ./student_class_change/*.log + # 检查数据 + mysql -e "SELECT * FROM xg_student_class_change WHERE status = '0';" + ``` + +### 性能优化 + +1. **索引检查**: 确保相关表的索引完整 +2. **批量处理**: 每次处理适当数量的记录 +3. **日志轮转**: 定期清理旧日志文件 +4. **监控资源**: 监控CPU、内存、磁盘使用情况 + +## 📈 统计监控 + +### 处理统计 +```sql +-- 查看处理统计 +SELECT + COUNT(*) as total_records, + SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END) as pending, + SUM(CASE WHEN status = '1' THEN 1 ELSE 0 END) as processed +FROM xg_student_class_change +WHERE deleted = 0; + +-- 查看最近处理情况 +SELECT + DATE(update_time) as process_date, + COUNT(*) as processed_count +FROM xg_student_class_change +WHERE status = '1' + AND update_time >= DATE_SUB(NOW(), INTERVAL 7 DAY) +GROUP BY DATE(update_time) +ORDER BY process_date DESC; +``` + +## 🔄 扩展开发 + +### 添加新的业务逻辑 +1. 在 `process_student_class_change()` 函数中添加处理步骤 +2. 更新事务SQL,确保数据一致性 +3. 添加相应的日志记录 +4. 更新健康检查逻辑 + +### 自定义配置 +1. 在 `data.conf` 中添加新配置项 +2. 在脚本中读取和使用配置 +3. 更新文档说明 + +## 📞 技术支持 + +如有疑问或需要技术支持,请联系项目技术团队。 + +--- + +**创建时间**: 2025-01-25 +**维护人员**: AI Assistant +**版本**: v1.0.0 diff --git a/学生换班级/control_scripts.sh b/学生换班级/control_scripts.sh new file mode 100755 index 00000000..e7386065 --- /dev/null +++ b/学生换班级/control_scripts.sh @@ -0,0 +1,332 @@ +#!/bin/bash + +# =========================================== +# 学生换班级处理脚本控制程序 +# 用于启动、停止、重启处理脚本 +# =========================================== + +set -euo pipefail + +# Load configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_FILE="${SCRIPT_DIR}/data.conf" + +if [[ ! -f "$CONFIG_FILE" ]]; then + echo "错误:配置文件 $CONFIG_FILE 未找到!" + exit 1 +fi + +source "$CONFIG_FILE" + +# Script definitions +declare -A SCRIPTS=( + ["class_change"]="process_student_class_change.sh" +) + +# PID files +PID_DIR="${SCRIPT_DIR}/pids" +mkdir -p "$PID_DIR" + +# Functions +log() { + local level="$1" + local message="$2" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + echo "[$timestamp] [$level] $message" +} + +get_pid_file() { + local script_name="$1" + echo "${PID_DIR}/${script_name}.pid" +} + +get_lock_file() { + local script_name="$1" + echo "${SCRIPT_DIR}/${script_name}.lock" +} + +is_running() { + local script_name="$1" + local pid_file=$(get_pid_file "$script_name") + local lock_file=$(get_lock_file "$script_name") + + # Check PID file + if [[ -f "$pid_file" ]]; then + local pid=$(cat "$pid_file") + if kill -0 "$pid" 2>/dev/null; then + return 0 # Running + else + log "WARN" "删除脚本 $script_name 的过期PID文件" + rm -f "$pid_file" + fi + fi + + # Check lock file + if [[ -f "$lock_file" ]]; then + local lock_pid=$(cat "$lock_file") + if kill -0 "$lock_pid" 2>/dev/null; then + return 0 # Running + else + log "WARN" "删除脚本 $script_name 的过期锁定文件" + rm -f "$lock_file" + fi + fi + + return 1 # Not running +} + +start_script() { + local script_name="$1" + local script_file="${SCRIPT_DIR}/${SCRIPTS[$script_name]}" + local pid_file=$(get_pid_file "$script_name") + + if [[ ! -f "$script_file" ]]; then + log "ERROR" "脚本文件未找到: $script_file" + return 1 + fi + + if is_running "$script_name"; then + log "INFO" "$script_name 已在运行" + return 0 + fi + + log "INFO" "正在启动 $script_name..." + chmod +x "$script_file" + + # Start script in background + nohup "$script_file" > /dev/null 2>&1 & + local pid=$! + + # Save PID + echo $pid > "$pid_file" + + # Wait a moment and check if it's still running + sleep 2 + if kill -0 "$pid" 2>/dev/null; then + log "INFO" "$script_name 启动成功 (PID: $pid)" + return 0 + else + log "ERROR" "$script_name 启动失败" + rm -f "$pid_file" + return 1 + fi +} + +stop_script() { + local script_name="$1" + local pid_file=$(get_pid_file "$script_name") + local lock_file=$(get_lock_file "$script_name") + + if ! is_running "$script_name"; then + log "INFO" "$script_name 未运行" + return 0 + fi + + log "INFO" "正在停止 $script_name..." + + # Try graceful shutdown first + local pids=() + [[ -f "$pid_file" ]] && pids+=($(cat "$pid_file")) + [[ -f "$lock_file" ]] && pids+=($(cat "$lock_file")) + + for pid in "${pids[@]}"; do + if kill -0 "$pid" 2>/dev/null; then + kill "$pid" 2>/dev/null || true + fi + done + + # Wait for graceful shutdown + local count=0 + while [[ $count -lt 10 ]] && is_running "$script_name"; do + sleep 1 + ((count++)) + done + + # Force kill if still running + if is_running "$script_name"; then + log "WARN" "Graceful shutdown failed, force killing $script_name..." + for pid in "${pids[@]}"; do + if kill -0 "$pid" 2>/dev/null; then + kill -9 "$pid" 2>/dev/null || true + fi + done + sleep 1 + fi + + # Clean up files + rm -f "$pid_file" "$lock_file" + + if is_running "$script_name"; then + log "ERROR" "Failed to stop $script_name" + return 1 + else + log "INFO" "$script_name stopped successfully" + return 0 + fi +} + +restart_script() { + local script_name="$1" + + log "INFO" "正在重启 $script_name..." + if stop_script "$script_name" && start_script "$script_name"; then + log "INFO" "$script_name 重启成功" + return 0 + else + log "ERROR" "$script_name 重启失败" + return 1 + fi +} + +status_script() { + local script_name="$1" + + if is_running "$script_name"; then + local pid_file=$(get_pid_file "$script_name") + local lock_file=$(get_lock_file "$script_name") + local pid="" + + if [[ -f "$pid_file" ]]; then + pid=$(cat "$pid_file") + elif [[ -f "$lock_file" ]]; then + pid=$(cat "$lock_file") + fi + + echo "$script_name 正在运行 (PID: $pid)" + return 0 + else + echo "$script_name 未运行" + return 1 + fi +} + +usage() { + echo "用法: $0 {start|stop|restart|status} {script_name}" + echo " $0 {startall|stopall|restartall|statusall}" + echo "" + echo "可用脚本:" + for script in "${!SCRIPTS[@]}"; do + echo " $script - ${SCRIPTS[$script]}" + done + echo "" + echo "示例:" + echo " $0 start class_change # 启动换班级处理" + echo " $0 stop class_change # 停止换班级处理" + echo " $0 restart class_change # 重启换班级处理" + echo " $0 status class_change # 检查换班级处理状态" + echo " $0 startall # 启动所有脚本" + echo " $0 stopall # 停止所有脚本" + echo " $0 statusall # 检查所有脚本状态" +} + +# Main logic +case "${1:-}" in + start) + if [[ -z "${2:-}" ]]; then + usage + exit 1 + fi + if [[ -n "${SCRIPTS[$2]:-}" ]]; then + start_script "$2" + else + echo "未知脚本: $2" + usage + exit 1 + fi + ;; + stop) + if [[ -z "${2:-}" ]]; then + usage + exit 1 + fi + if [[ -n "${SCRIPTS[$2]:-}" ]]; then + stop_script "$2" + else + echo "未知脚本: $2" + usage + exit 1 + fi + ;; + restart) + if [[ -z "${2:-}" ]]; then + usage + exit 1 + fi + if [[ -n "${SCRIPTS[$2]:-}" ]]; then + restart_script "$2" + else + echo "未知脚本: $2" + usage + exit 1 + fi + ;; + status) + if [[ -z "${2:-}" ]]; then + usage + exit 1 + fi + if [[ -n "${SCRIPTS[$2]:-}" ]]; then + status_script "$2" + else + echo "未知脚本: $2" + usage + exit 1 + fi + ;; + startall) + log "INFO" "正在启动所有脚本..." + local failed=() + for script in "${!SCRIPTS[@]}"; do + if ! start_script "$script"; then + failed+=("$script") + fi + done + if [[ ${#failed[@]} -eq 0 ]]; then + log "INFO" "所有脚本启动成功" + else + log "ERROR" "启动脚本失败: ${failed[*]}" + exit 1 + fi + ;; + stopall) + log "INFO" "正在停止所有脚本..." + local failed=() + for script in "${!SCRIPTS[@]}"; do + if ! stop_script "$script"; then + failed+=("$script") + fi + done + if [[ ${#failed[@]} -eq 0 ]]; then + log "INFO" "所有脚本停止成功" + else + log "ERROR" "停止脚本失败: ${failed[*]}" + exit 1 + fi + ;; + restartall) + log "INFO" "正在重启所有脚本..." + local failed=() + for script in "${!SCRIPTS[@]}"; do + if ! restart_script "$script"; then + failed+=("$script") + fi + done + if [[ ${#failed[@]} -eq 0 ]]; then + log "INFO" "所有脚本重启成功" + else + log "ERROR" "重启脚本失败: ${failed[*]}" + exit 1 + fi + ;; + statusall) + log "INFO" "正在检查所有脚本的状态..." + for script in "${!SCRIPTS[@]}"; do + echo -n "$script: " + status_script "$script" + done + ;; + *) + usage + exit 1 + ;; +esac diff --git a/学生换班级/data.conf b/学生换班级/data.conf new file mode 100644 index 00000000..353371b1 --- /dev/null +++ b/学生换班级/data.conf @@ -0,0 +1,17 @@ +# Database configuration +DB_HOST="47.99.164.66" +DB_PORT="3306" +DB_NAME="hzdyjs_xg" +DB_USER="root" +DB_PASS="hn02le.34lkdLKD" + +# Script configuration +LOG_DIR="${SCRIPT_DIR}/student_class_change" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LOCK_FILE="${SCRIPT_DIR}/script.lock" + +# Processing configuration +BATCH_SIZE=100 +MAX_RETRY=3 +RETRY_DELAY=5 +CYCLE_INTERVAL=600 # 循环间隔时间(秒),默认10分钟 diff --git a/学生换班级/health_check.sh b/学生换班级/health_check.sh new file mode 100755 index 00000000..fc0170b6 --- /dev/null +++ b/学生换班级/health_check.sh @@ -0,0 +1,348 @@ +#!/bin/bash + +# =========================================== +# 学生换班级处理服务健康检查脚本 +# 用于监控服务运行状态和数据库连接 +# =========================================== + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_FILE="${SCRIPT_DIR}/data.conf" +CONTROL_SCRIPT="${SCRIPT_DIR}/control_scripts.sh" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Load configuration +if [[ ! -f "$CONFIG_FILE" ]]; then + echo -e "${RED}错误:配置文件 $CONFIG_FILE 未找到!${NC}" + exit 1 +fi + +source "$CONFIG_FILE" + +# Functions +log() { + local level="$1" + local message="$2" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + echo -e "${timestamp} [$level] $message" +} + +success() { + echo -e "${GREEN}✓ $1${NC}" +} + +error() { + echo -e "${RED}✗ $1${NC}" +} + +warning() { + echo -e "${YELLOW}⚠ $1${NC}" +} + +info() { + echo -e "${BLUE}ℹ $1${NC}" +} + +# 检查数据库连接 +check_database() { + info "正在检查数据库连接..." + + local db_test + if db_test=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1 as test;" 2>/dev/null); then + if echo "$db_test" | grep -q "test"; then + success "数据库连接成功" + return 0 + else + error "数据库查询失败" + return 1 + fi + else + error "数据库连接失败" + return 1 + fi +} + +# 检查服务状态 +check_service() { + local service_name="$1" + local service_desc="$2" + + info "正在检查 $service_desc..." + + if [[ ! -x "$CONTROL_SCRIPT" ]]; then + error "控制脚本未找到或不可执行: $CONTROL_SCRIPT" + return 1 + fi + + local status_output + status_output=$("$CONTROL_SCRIPT" status "$service_name" 2>/dev/null) + + if echo "$status_output" | grep -q "is running"; then + success "$service_desc 正在运行" + + # 提取PID(如果可用) + local pid + pid=$(echo "$status_output" | grep -o "PID: [0-9]*" | cut -d' ' -f2) + if [[ -n "$pid" ]]; then + info " 进程ID: $pid" + fi + + return 0 + else + error "$service_desc 未运行" + return 1 + fi +} + +# 检查待处理记录 +check_pending_records() { + info "正在检查待处理的换班级记录..." + + local pending_count + if pending_count=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e " + SELECT COUNT(*) as pending + FROM xg_student_class_change + WHERE status = '0' AND deleted = 0; + " 2>/dev/null | tail -n1); then + + if [[ "$pending_count" -eq 0 ]]; then + success "无待处理的换班级记录" + elif [[ "$pending_count" -lt 10 ]]; then + warning "$pending_count 条待处理的换班级记录" + else + error "$pending_count 条待处理的换班级记录 (积压严重)" + fi + return 0 + else + error "检查待处理记录失败" + return 1 + fi +} + +# 检查最近的处理活动 +check_recent_processing() { + info "正在检查最近的处理活动..." + + local recent_count + if recent_count=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e " + SELECT COUNT(*) as recent + FROM xg_student_class_change + WHERE status = '1' + AND update_time >= DATE_SUB(NOW(), INTERVAL 1 HOUR) + AND deleted = 0; + " 2>/dev/null | tail -n1); then + + if [[ "$recent_count" -gt 0 ]]; then + success "最近一小时处理了 $recent_count 条记录" + else + warning "最近一小时未处理任何记录" + fi + return 0 + else + error "检查最近处理活动失败" + return 1 + fi +} + +# 检查日志文件 +check_logs() { + info "正在检查日志文件..." + + if [[ -d "$LOG_DIR" ]]; then + local log_count + log_count=$(find "$LOG_DIR" -name "*.log" -type f -mtime -1 2>/dev/null | wc -l) + + if [[ "$log_count" -gt 0 ]]; then + success "发现最近的日志文件 ($log_count 个文件来自最近24小时)" + else + warning "未发现最近的日志文件" + fi + + # 检查错误日志 + local error_count + error_count=$(find "$LOG_DIR" -name "*.log" -type f -exec grep -l "ERROR" {} \; 2>/dev/null | wc -l) + + if [[ "$error_count" -gt 0 ]]; then + warning "$error_count 个日志文件包含错误" + else + success "最近日志中未发现错误消息" + fi + else + error "日志目录未找到: $LOG_DIR" + return 1 + fi +} + +# 检查磁盘空间 +check_disk_space() { + info "正在检查磁盘空间..." + + local disk_usage + disk_usage=$(df "$SCRIPT_DIR" | tail -1 | awk '{print $5}' | sed 's/%//') + + if [[ "$disk_usage" -lt 80 ]]; then + success "磁盘使用率: ${disk_usage}%" + elif [[ "$disk_usage" -lt 90 ]]; then + warning "磁盘使用率: ${disk_usage}% (接近限制)" + else + error "磁盘使用率: ${disk_usage}% (严重)" + return 1 + fi +} + +# 检查内存使用情况 +check_memory() { + info "正在检查内存使用情况..." + + local mem_usage + mem_usage=$(free | grep Mem | awk '{printf "%.0f", $3/$2 * 100.0}') + + if [[ "$mem_usage" -lt 80 ]]; then + success "内存使用率: ${mem_usage}%" + elif [[ "$mem_usage" -lt 90 ]]; then + warning "内存使用率: ${mem_usage}% (接近限制)" + else + error "内存使用率: ${mem_usage}% (严重)" + return 1 + fi +} + +# Generate health report +generate_report() { + local report_file="${SCRIPT_DIR}/health_report_$(date +%Y%m%d_%H%M%S).txt" + + { + echo "=== 学生换班级处理服务健康检查报告 ===" + echo "检查时间: $(date)" + echo "服务器信息: $(hostname)" + echo "" + + echo "=== 数据库连接 ===" + if check_database; then + echo "✓ 数据库连接正常" + else + echo "✗ 数据库连接异常" + fi + echo "" + + echo "=== 服务状态 ===" + if check_service "class_change" "学生换班级处理服务"; then + echo "✓ 学生换班级处理服务运行正常" + else + echo "✗ 学生换班级处理服务未运行" + fi + echo "" + + echo "=== 业务数据检查 ===" + check_pending_records + echo "" + check_recent_processing + echo "" + + echo "=== 系统资源 ===" + check_disk_space + echo "" + check_memory + echo "" + + echo "=== 日志检查 ===" + check_logs + echo "" + + echo "报告生成完成" + } > "$report_file" 2>/dev/null + + success "健康检查报告已生成: $report_file" +} + +# Main function +main() { + echo "" + echo "=== 学生换班级处理服务健康检查 ===" + echo "检查时间: $(date)" + echo "服务器信息: $(hostname)" + echo "" + + local checks_passed=0 + local total_checks=0 + + # Database connection + echo "=== 数据库连接 ===" + ((total_checks++)) + check_database && ((checks_passed++)) + echo "" + + # Service status + echo "=== 服务状态 ===" + ((total_checks++)) + check_service "class_change" "学生换班级处理服务" && ((checks_passed++)) + echo "" + + # Business data + echo "=== 业务数据检查 ===" + ((total_checks++)) + check_pending_records && ((checks_passed++)) + echo "" + + ((total_checks++)) + check_recent_processing && ((checks_passed++)) + echo "" + + # System resources + echo "=== 系统资源 ===" + ((total_checks++)) + check_disk_space && ((checks_passed++)) + echo "" + + ((total_checks++)) + check_memory && ((checks_passed++)) + echo "" + + # Logs + echo "=== 日志检查 ===" + ((total_checks++)) + check_logs && ((checks_passed++)) + echo "" + + # 总结 + echo "=== 检查总结 ===" + local success_rate=$((checks_passed * 100 / total_checks)) + echo "通过检查: $checks_passed/$total_checks ($success_rate%)" + + if [[ $success_rate -eq 100 ]]; then + success "所有检查通过,服务运行正常" + exit 0 + elif [[ $success_rate -ge 80 ]]; then + warning "大部分检查通过,服务运行基本正常" + exit 0 + else + error "多项检查失败,建议立即检查服务状态" + exit 1 + fi +} + +# 命令行选项 +case "${1:-}" in + --report) + generate_report + ;; + --help|-h) + echo "用法: $0 [选项]" + echo "" + echo "选项:" + echo " --report 生成详细的健康检查报告" + echo " --help 显示此帮助信息" + echo "" + echo "无选项时,执行标准健康检查。" + ;; + *) + main "$@" + ;; +esac diff --git a/学生换班级/process_student_class_change.sh b/学生换班级/process_student_class_change.sh new file mode 100755 index 00000000..6b02b422 --- /dev/null +++ b/学生换班级/process_student_class_change.sh @@ -0,0 +1,301 @@ +#!/bin/bash + +# =========================================== +# 学生换班级处理脚本 +# 处理类型: CLASS_CHANGE(换班级) +# =========================================== + +set -euo pipefail + +# Load configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_FILE="${SCRIPT_DIR}/data.conf" + +if [[ ! -f "$CONFIG_FILE" ]]; then + echo "错误:配置文件 $CONFIG_FILE 未找到!" + exit 1 +fi + +source "$CONFIG_FILE" + +# Create log directory +mkdir -p "$LOG_DIR" + +# Log file +LOG_FILE="${LOG_DIR}/process_student_class_change_$(date +%Y%m%d_%H%M%S).log" + +# Lock file to prevent multiple instances +LOCK_FILE="${SCRIPT_DIR}/process_student_class_change.lock" + +# Functions +log() { + local level="$1" + local message="$2" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE" +} + +error_exit() { + local message="$1" + log "ERROR" "$message" + # Remove lock file + [[ -f "$LOCK_FILE" ]] && rm -f "$LOCK_FILE" + exit 1 +} + +# 检查脚本是否已在运行 +if [[ -f "$LOCK_FILE" ]]; then + if kill -0 $(cat "$LOCK_FILE") 2>/dev/null; then + log "INFO" "脚本已在运行 (PID: $(cat "$LOCK_FILE"))" + exit 1 + else + log "WARN" "删除过期的锁定文件" + rm -f "$LOCK_FILE" + fi +fi + +# Create lock file +echo $$ > "$LOCK_FILE" + +# 清理函数 +cleanup() { + [[ -f "$LOCK_FILE" ]] && rm -f "$LOCK_FILE" + log "INFO" "脚本执行完成" +} + +trap cleanup EXIT + +# Database functions +execute_sql() { + local sql="$1" + local result + + result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "$sql" 2>&1) + local exit_code=$? + + if [[ $exit_code -ne 0 ]]; then + log "ERROR" "SQL执行失败: $sql" + log "ERROR" "MySQL错误: $result" + return 1 + fi + + echo "$result" +} + +# Process student class change +process_student_class_change() { + local record_id="$1" + local student_id="$2" + local student_no="$3" + local new_class_id="$4" + local operator_id="${5:-1}" + + log "INFO" "Processing student class change - ID: $record_id, Student: $student_no ($student_id), New Class ID: $new_class_id" + + # Get new class information + local class_info_sql=" + SELECT + c.college_id, c.college_name, c.major_id, c.major_name, + c.class_code, c.class_name, c.class_type, c.grade, + c.training_type, c.counselor_id, c.counselor_name, + c.class_teacher_id, c.class_teacher_name, c.school_system + FROM xg_class_msg c + WHERE c.id = $new_class_id AND c.deleted = 0 + " + + local class_info + class_info=$(execute_sql "$class_info_sql") + + if [[ -z "$class_info" || "$class_info" == *"Empty set"* ]]; then + log "ERROR" "获取班级ID为 $new_class_id 的班级信息失败" + return 1 + fi + + # Parse class information (skip header and separator lines, get data row) + local class_data + class_data=$(echo "$class_info" | grep -E '^[0-9]' | head -1) + + if [[ -z "$class_data" ]]; then + log "ERROR" "解析班级信息失败,无法获取数据行" + return 1 + fi + + # Use cut to extract specific fields reliably + local college_id=$(echo "$class_data" | cut -f1) + local college_name=$(echo "$class_data" | cut -f2) + local major_id=$(echo "$class_data" | cut -f3) + local major_name=$(echo "$class_data" | cut -f4) + local class_code=$(echo "$class_data" | cut -f5) + local class_name=$(echo "$class_data" | cut -f6) + local class_type=$(echo "$class_data" | cut -f7) + local grade=$(echo "$class_data" | cut -f8) + local training_type=$(echo "$class_data" | cut -f9) + local counselor_id=$(echo "$class_data" | cut -f10) + local counselor_name=$(echo "$class_data" | cut -f11) + local class_teacher_id=$(echo "$class_data" | cut -f12) + local class_teacher_name=$(echo "$class_data" | cut -f13) + local school_system=$(echo "$class_data" | cut -f14) + + # Handle NULL values for IDs + local counselor_id_value class_teacher_id_value + if [[ "$counselor_id" == "NULL" || -z "$counselor_id" ]]; then + counselor_id_value="NULL" + else + counselor_id_value="'$counselor_id'" + fi + + if [[ "$class_teacher_id" == "NULL" || -z "$class_teacher_id" ]]; then + class_teacher_id_value="NULL" + else + class_teacher_id_value="'$class_teacher_id'" + fi + + # Start transaction + local transaction_sql=" + START TRANSACTION; + + -- 1. Backup original data to his tables (ignore if already exists) + INSERT IGNORE INTO xg_student_msg_his SELECT * FROM xg_student_msg WHERE id = $student_id; + INSERT IGNORE INTO xg_class_pos_msg_his SELECT * FROM xg_class_pos_msg WHERE student_id = $student_id; + + -- 2. Terminate cadre positions (干部信息终止) + UPDATE xg_class_pos_msg SET + is_current = 0, + cadre_status = '4', -- 免职 + dismissal_date = CURDATE(), + dismissal_reason = '学生换班级', + term_end_date = CURDATE(), + term_duration = TIMESTAMPDIFF(MONTH, term_start_date, CURDATE()), + update_by = $operator_id, + update_time = NOW() + WHERE student_id = $student_id AND is_current = 1; + + -- 3. Update student information with new class data + UPDATE xg_student_msg SET + -- 基础班级信息 + college_id = '$college_id', + college_name = '$college_name', + major_id = '$major_id', + major_name = '$major_name', + class_id = '$new_class_id', + class_name = '$class_name', + grade = '$grade', + + -- 预留字段从班级表关联获取的数据 (7182-7195行) + school_system = '$school_system', + academic_level = '$class_type', -- class_type 对应 academic_level + training_type = '$training_type', + counselor_id = $counselor_id_value, + counselor_name = '$counselor_name', + class_teacher_id = $class_teacher_id_value, + class_teacher_name = '$class_teacher_name', + + -- 更新信息 + update_by = $operator_id, + update_time = NOW() + WHERE id = $student_id; + + -- 4. Update class change record status + UPDATE xg_student_class_change SET + status = '1', -- 已处理 + update_by = $operator_id, + update_time = NOW() + WHERE id = $record_id; + + COMMIT; + " + + # 执行事务 + if execute_sql "$transaction_sql"; then + log "INFO" "成功处理学生换班级 - ID: $record_id, 学生: $student_no" + return 0 + else + log "ERROR" "处理学生换班级失败 - ID: $record_id, 学生: $student_no" + return 1 + fi +} + +# Main function +main() { + log "INFO" "启动学生换班级处理守护进程" + log "INFO" "处理类型: CLASS_CHANGE(换班级)" + log "INFO" "以连续模式运行,间隔10分钟" + + # 测试数据库连接 + log "INFO" "正在测试数据库连接..." + if ! execute_sql "SELECT 1;" >/dev/null 2>&1; then + error_exit "数据库连接失败" + fi + log "INFO" "数据库连接成功" + + # Main processing loop + while true; do + log "INFO" "开始新的处理周期" + + # 获取未处理的记录 + local query_sql=" + SELECT id, student_id, student_no, new_class_id, update_by + FROM xg_student_class_change + WHERE status = '0' + AND deleted = 0 + AND effective_time <= NOW() + ORDER BY create_time ASC + LIMIT $BATCH_SIZE; + " + + local records + records=$(execute_sql "$query_sql") + + # 检查是否有记录需要处理 + # 过滤掉MySQL的边框和表头,只保留数据行 + local data_records + data_records=$(echo "$records" | grep -E '^[0-9]' || true) + + if [[ -z "$data_records" ]]; then + log "INFO" "未找到未处理的记录,正在等待..." + else + log "INFO" "找到待处理记录,开始处理..." + records="$data_records" + + local processed_count=0 + local failed_count=0 + + # Process each record + while IFS=$'\t' read -r record_id student_id student_no new_class_id operator_id; do + # Skip empty lines + [[ -z "$record_id" ]] && continue + + local retry_count=0 + local success=false + + while [[ $retry_count -lt $MAX_RETRY && $success == false ]]; do + if process_student_class_change "$record_id" "$student_id" "$student_no" "$new_class_id" "$operator_id"; then + success=true + ((processed_count++)) + else + ((retry_count++)) + if [[ $retry_count -lt $MAX_RETRY ]]; then + log "WARN" "处理失败,$RETRY_DELAY 秒后重试... (尝试 $retry_count/$MAX_RETRY)" + sleep $RETRY_DELAY + fi + fi + done + + if [[ $success == false ]]; then + ((failed_count++)) + log "ERROR" "$MAX_RETRY 次尝试后仍处理失败 - ID: $record_id" + fi + + done <<< "$records" + + log "INFO" "处理周期完成 - 已处理: $processed_count, 失败: $failed_count" + fi + + # 等待配置的间隔时间后开始下一个周期 + log "INFO" "等待 $CYCLE_INTERVAL 秒后开始下一个处理周期..." + sleep $CYCLE_INTERVAL + done +} + +# Run main function +main "$@" diff --git a/退学、休学、复学、毕业/README.md b/退学、休学、复学、毕业/README.md index c431d9e7..d597aeae 100644 --- a/退学、休学、复学、毕业/README.md +++ b/退学、休学、复学、毕业/README.md @@ -9,13 +9,10 @@ 1. **`process_student_changes.sh`** - 处理毕业、退学、休学的状态变更 2. **`process_student_resume.sh`** - 处理复学的状态变更 3. **`control_scripts.sh`** - 脚本控制程序(启动、停止、重启) -4. **`start_services.sh`** - 一键启动所有服务 -5. **`stop_services.sh`** - 一键停止所有服务 -6. **`health_check.sh`** - 服务健康检查脚本 -7. **`data.conf`** - 数据库配置文件 -8. **`test_data.sql`** - 测试数据脚本 -9. **`optional_crontab_config.txt`** - 可选的定时任务配置(备用) -10. **`demo.sh`** - 脚本使用演示 +4. **`health_check.sh`** - 服务健康检查脚本 +5. **`data.conf`** - 数据库配置文件 +6. **`test_data.sql`** - 测试数据脚本 +7. **`optional_crontab_config.txt`** - 可选的定时任务配置(备用) ### 处理逻辑 @@ -53,7 +50,7 @@ DB_USER="root" # 数据库用户名 DB_PASS="password" # 数据库密码 # Script configuration -LOG_DIR="/var/log/student_status_change" # 日志目录 +LOG_DIR="./student_status_change" # 日志目录 SCRIPT_DIR="/path/to/scripts" # 脚本目录 LOCK_FILE="${SCRIPT_DIR}/script.lock" # 锁文件 @@ -84,7 +81,7 @@ DB_PASS="your_password" ```bash # 启动所有服务(持续运行模式) -./start_services.sh +./control_scripts.sh startall # 查看服务状态 ./control_scripts.sh statusall @@ -92,7 +89,7 @@ DB_PASS="your_password" #### 持续运行模式说明 -- **启动方式**: `./start_services.sh` 一次性启动所有服务 +- **启动方式**: `./control_scripts.sh startall` 一次性启动所有服务 - **运行逻辑**: 每个脚本启动后进入while循环,持续监控和处理数据 - **处理周期**: 检查数据库 → 处理未处理记录 → 等待10分钟 → 重复循环 - **并发控制**: 通过锁文件确保同一脚本只运行一个实例 @@ -114,10 +111,10 @@ DB_PASS="your_password" ```bash # 正常停止所有服务 -./stop_services.sh +./control_scripts.sh stopall # 强制停止所有服务(如果正常停止失败) -./stop_services.sh force +# 手动kill进程或使用系统命令 ``` ### 5. 健康检查 @@ -187,7 +184,7 @@ DB_PASS="your_password" ## 📝 日志说明 ### 日志文件位置 -- 日志目录:`/var/log/student_status_change/` +- 日志目录:`./student_status_change/` - 日志格式:`process_student_changes_YYYYMMDD_HHMMSS.log` ### 日志内容 @@ -268,9 +265,9 @@ rm -f pids/*.pid 脚本采用持续运行模式,启动后自动循环执行: -1. **启动脚本**: `./start_services.sh` +1. **启动脚本**: `./control_scripts.sh startall` 2. **处理逻辑**: 检查未处理的记录 → 处理业务 → 等待10分钟 → 重复 -3. **停止脚本**: `./stop_services.sh` +3. **停止脚本**: `./control_scripts.sh stopall` ### 可选的定时任务模式 @@ -286,7 +283,7 @@ crontab -e | 特性 | 持续运行模式 | Crontab模式 | |------|-------------|-------------| -| 启动方式 | `./start_services.sh` | crontab配置 | +| 启动方式 | `./control_scripts.sh startall` | crontab配置 | | 执行频率 | 每10分钟自动 | 可自定义时间 | | 资源占用 | 常驻进程 | 按需启动 | | 监控便利性 | 更容易监控 | 需要额外配置 | @@ -297,16 +294,15 @@ crontab -e ## 🚀 快速开始 ### 💡 使用指南 -1. **查看演示**: 运行 `./demo.sh` 查看脚本使用说明 -2. **配置数据库**: 编辑 `data.conf` 配置数据库连接信息 -3. **启动服务**: 使用 `./start_services.sh` 启动持续运行的服务 -4. **监控运行**: 使用 `./health_check.sh` 检查服务状态 -5. **停止服务**: 需要时使用 `./stop_services.sh` 停止服务 +1. **配置数据库**: 编辑 `data.conf` 配置数据库连接信息 +2. **启动服务**: 使用 `./control_scripts.sh startall` 启动持续运行的服务 +3. **监控运行**: 使用 `./health_check.sh` 检查服务状态 +4. **停止服务**: 需要时使用 `./control_scripts.sh stopall` 停止服务 ### 🧪 测试步骤 1. **插入测试数据**: 执行 `test_data.sql` 插入测试记录 -2. **启动服务**: `./start_services.sh` -3. **观察日志**: 查看 `/var/log/student_status_change/` 目录的日志 +2. **启动服务**: `./control_scripts.sh startall` +3. **观察日志**: 查看 `./student_status_change/` 目录的日志 4. **检查结果**: 确认 `xg_student_status_change.process_status` 已更新为1 --- diff --git a/退学、休学、复学、毕业/control_scripts.sh b/退学、休学、复学、毕业/control_scripts.sh index e0338c30..f40918d6 100755 --- a/退学、休学、复学、毕业/control_scripts.sh +++ b/退学、休学、复学、毕业/control_scripts.sh @@ -12,7 +12,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CONFIG_FILE="${SCRIPT_DIR}/data.conf" if [[ ! -f "$CONFIG_FILE" ]]; then - echo "Error: Configuration file $CONFIG_FILE not found!" + echo "错误:配置文件 $CONFIG_FILE 未找到!" exit 1 fi @@ -57,7 +57,7 @@ is_running() { if kill -0 "$pid" 2>/dev/null; then return 0 # Running else - log "WARN" "Removing stale PID file for $script_name" + log "WARN" "删除脚本 $script_name 的过期PID文件" rm -f "$pid_file" fi fi @@ -68,7 +68,7 @@ is_running() { if kill -0 "$lock_pid" 2>/dev/null; then return 0 # Running else - log "WARN" "Removing stale lock file for $script_name" + log "WARN" "删除脚本 $script_name 的过期锁定文件" rm -f "$lock_file" fi fi @@ -82,16 +82,16 @@ start_script() { local pid_file=$(get_pid_file "$script_name") if [[ ! -f "$script_file" ]]; then - log "ERROR" "Script file not found: $script_file" + log "ERROR" "脚本文件未找到: $script_file" return 1 fi if is_running "$script_name"; then - log "INFO" "$script_name is already running" + log "INFO" "$script_name 已在运行" return 0 fi - log "INFO" "Starting $script_name..." + log "INFO" "正在启动 $script_name..." chmod +x "$script_file" # Start script in background @@ -103,10 +103,10 @@ start_script() { if kill -0 "$pid" 2>/dev/null; then echo $pid > "$pid_file" - log "INFO" "$script_name started successfully (PID: $pid)" + log "INFO" "$script_name 启动成功 (PID: $pid)" return 0 else - log "ERROR" "Failed to start $script_name" + log "ERROR" "$script_name 启动失败" return 1 fi } @@ -117,30 +117,30 @@ stop_script() { local lock_file=$(get_lock_file "$script_name") local stopped=false - log "INFO" "Stopping $script_name..." + log "INFO" "正在停止 $script_name..." - # Try to stop by PID file + # 尝试通过PID文件停止 if [[ -f "$pid_file" ]]; then local pid=$(cat "$pid_file") if kill -0 "$pid" 2>/dev/null; then kill "$pid" sleep 2 if ! kill -0 "$pid" 2>/dev/null; then - log "INFO" "$script_name stopped successfully (PID: $pid)" + log "INFO" "$script_name 停止成功 (PID: $pid)" stopped=true fi fi rm -f "$pid_file" fi - # Try to stop by lock file + # 尝试通过锁定文件停止 if [[ -f "$lock_file" ]]; then local lock_pid=$(cat "$lock_file") if kill -0 "$lock_pid" 2>/dev/null; then kill "$lock_pid" sleep 2 if ! kill -0 "$lock_pid" 2>/dev/null; then - log "INFO" "$script_name stopped successfully (PID: $lock_pid)" + log "INFO" "$script_name 停止成功 (PID: $lock_pid)" stopped=true fi fi @@ -148,13 +148,13 @@ stop_script() { fi if [[ "$stopped" == false ]]; then - log "WARN" "$script_name may not have been running or failed to stop gracefully" + log "WARN" "$script_name 可能未运行或优雅停止失败" fi } restart_script() { local script_name="$1" - log "INFO" "Restarting $script_name..." + log "INFO" "正在重启 $script_name..." stop_script "$script_name" sleep 3 start_script "$script_name" @@ -168,43 +168,43 @@ status_script() { if [[ -f "$pid_file" ]]; then local pid=$(cat "$pid_file") - log "INFO" "$script_name is running (PID: $pid)" + log "INFO" "$script_name 正在运行 (PID: $pid)" elif [[ -f "$lock_file" ]]; then local lock_pid=$(cat "$lock_file") - log "INFO" "$script_name is running (PID: $lock_pid)" + log "INFO" "$script_name 正在运行 (PID: $lock_pid)" else - log "INFO" "$script_name status unknown" + log "INFO" "$script_name 状态未知" fi else - log "INFO" "$script_name is not running" + log "INFO" "$script_name 未运行" fi } show_usage() { cat << EOF -Usage: $0 +用法: $0 <命令> <脚本名称> -Commands: - start Start the specified script - stop Stop the specified script - restart Restart the specified script - status Show status of the specified script - startall Start all scripts - stopall Stop all scripts - statusall Show status of all scripts +命令: + start 启动指定的脚本 + stop 停止指定的脚本 + restart 重启指定的脚本 + status 显示指定脚本的状态 + startall 启动所有脚本 + stopall 停止所有脚本 + statusall 显示所有脚本的状态 -Script names: - changes Student status changes script (休学/退学/毕业) - resume Student resume script (复学) - all All scripts +脚本名称: + changes 学生状态变更脚本 (休学/退学/毕业) + resume 学生复学脚本 (复学) + all 所有脚本 -Examples: - $0 start changes # Start changes processing script - $0 stop resume # Stop resume processing script - $0 restart changes # Restart changes processing script - $0 status all # Show status of all scripts - $0 startall # Start all scripts - $0 stopall # Stop all scripts +示例: + $0 start changes # 启动状态变更处理脚本 + $0 stop resume # 停止复学处理脚本 + $0 restart changes # 重启状态变更处理脚本 + $0 status all # 显示所有脚本的状态 + $0 startall # 启动所有脚本 + $0 stopall # 停止所有脚本 EOF } @@ -223,7 +223,7 @@ main() { elif [[ -n "${SCRIPTS[$script_name]}" ]]; then start_script "$script_name" else - log "ERROR" "Unknown script name: $script_name" + log "ERROR" "未知的脚本名称: $script_name" show_usage exit 1 fi @@ -237,7 +237,7 @@ main() { elif [[ -n "${SCRIPTS[$script_name]}" ]]; then stop_script "$script_name" else - log "ERROR" "Unknown script name: $script_name" + log "ERROR" "未知的脚本名称: $script_name" show_usage exit 1 fi @@ -251,7 +251,7 @@ main() { elif [[ -n "${SCRIPTS[$script_name]}" ]]; then restart_script "$script_name" else - log "ERROR" "Unknown script name: $script_name" + log "ERROR" "未知的脚本名称: $script_name" show_usage exit 1 fi @@ -265,35 +265,35 @@ main() { elif [[ -n "${SCRIPTS[$script_name]}" ]]; then status_script "$script_name" else - log "ERROR" "Unknown script name: $script_name" + log "ERROR" "未知的脚本名称: $script_name" show_usage exit 1 fi ;; startall) - log "INFO" "Starting all scripts..." + log "INFO" "正在启动所有脚本..." for script in "${!SCRIPTS[@]}"; do start_script "$script" done ;; stopall) - log "INFO" "Stopping all scripts..." + log "INFO" "正在停止所有脚本..." for script in "${!SCRIPTS[@]}"; do stop_script "$script" done ;; statusall) - log "INFO" "Checking status of all scripts..." + log "INFO" "正在检查所有脚本的状态..." for script in "${!SCRIPTS[@]}"; do status_script "$script" done ;; *) - log "ERROR" "Unknown command: $command" + log "ERROR" "未知命令: $command" show_usage exit 1 ;; diff --git a/退学、休学、复学、毕业/data.conf b/退学、休学、复学、毕业/data.conf index fa0bd293..a7debf81 100644 --- a/退学、休学、复学、毕业/data.conf +++ b/退学、休学、复学、毕业/data.conf @@ -1,12 +1,12 @@ # Database configuration -DB_HOST="localhost" +DB_HOST="47.99.164.66" DB_PORT="3306" DB_NAME="hzdyjs_xg" DB_USER="root" -DB_PASS="password" +DB_PASS="hn02le.34lkdLKD" # Script configuration -LOG_DIR="/var/log/student_status_change" +LOG_DIR="${SCRIPT_DIR}/student_status_change" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LOCK_FILE="${SCRIPT_DIR}/script.lock" diff --git a/退学、休学、复学、毕业/demo.sh b/退学、休学、复学、毕业/demo.sh deleted file mode 100755 index f45d88d1..00000000 --- a/退学、休学、复学、毕业/demo.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash - -# =========================================== -# 学生状态变更处理脚本演示 -# 展示如何使用这些脚本 -# =========================================== - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -echo "========================================" -echo " 学生状态变更处理脚本演示" -echo "========================================" -echo "" - -echo "脚本位置: $SCRIPT_DIR" -echo "" - -echo "📋 脚本文件说明:" -echo " process_student_changes.sh - 处理毕业/退学/休学的状态变更" -echo " process_student_resume.sh - 处理复学的状态变更" -echo " control_scripts.sh - 脚本控制程序" -echo " start_services.sh - 一键启动所有服务" -echo " stop_services.sh - 一键停止所有服务" -echo " health_check.sh - 服务健康检查" -echo "" - -echo "🔧 配置文件:" -echo " data.conf - 数据库配置" -echo " test_data.sql - 测试数据" -echo "" - -echo "📖 使用步骤:" -echo "" - -echo "1️⃣ 配置数据库连接:" -echo " vim data.conf" -echo " # 修改数据库连接信息" -echo "" - -echo "2️⃣ 启动服务(持续运行模式):" -echo " ./start_services.sh" -echo "" - -echo "3️⃣ 查看服务状态:" -echo " ./control_scripts.sh statusall" -echo "" - -echo "4️⃣ 执行健康检查:" -echo " ./health_check.sh" -echo "" - -echo "5️⃣ 停止服务:" -echo " ./stop_services.sh" -echo "" - -echo "📊 运行模式说明:" -echo "• 脚本启动后进入持续运行模式" -echo "• 每10分钟自动检查和处理一次数据" -echo "• 支持并发控制,避免重复运行" -echo "• 完整的日志记录和错误处理" -echo "" - -echo "🧪 测试数据:" -echo "• 运行 test_data.sql 插入测试数据" -echo "• 脚本会自动处理 process_status = 0 的记录" -echo "" - -echo "📝 日志位置:" -echo "• /var/log/student_status_change/" -echo "• 包含详细的处理日志和错误信息" -echo "" - -echo "⚠️ 注意事项:" -echo "• 确保数据库连接正确" -echo "• 确保用户有足够的数据库权限" -echo "• 定期检查日志文件" -echo "• 监控磁盘空间使用情况" -echo "" - -echo "========================================" -echo " 演示完成" -echo "========================================" diff --git a/退学、休学、复学、毕业/health_check.sh b/退学、休学、复学、毕业/health_check.sh index feb90038..724055ea 100755 --- a/退学、休学、复学、毕业/health_check.sh +++ b/退学、休学、复学、毕业/health_check.sh @@ -20,7 +20,7 @@ NC='\033[0m' # No Color # Load configuration if [[ ! -f "$CONFIG_FILE" ]]; then - echo -e "${RED}Error: Configuration file $CONFIG_FILE not found!${NC}" + echo -e "${RED}错误:配置文件 $CONFIG_FILE 未找到!${NC}" exit 1 fi @@ -50,34 +50,34 @@ info() { echo -e "${BLUE}ℹ $1${NC}" } -# Check database connection +# 检查数据库连接 check_database() { - info "Checking database connection..." + info "正在检查数据库连接..." local db_test if db_test=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1 as test;" 2>/dev/null); then if echo "$db_test" | grep -q "test"; then - success "Database connection successful" + success "数据库连接成功" return 0 else - error "Database query failed" + error "数据库查询失败" return 1 fi else - error "Database connection failed" + error "数据库连接失败" return 1 fi } -# Check service status +# 检查服务状态 check_service() { local service_name="$1" local service_desc="$2" - info "Checking $service_desc..." + info "正在检查 $service_desc..." if [[ ! -x "$CONTROL_SCRIPT" ]]; then - error "Control script not found or not executable: $CONTROL_SCRIPT" + error "控制脚本未找到或不可执行: $CONTROL_SCRIPT" return 1 fi @@ -85,58 +85,58 @@ check_service() { status_output=$("$CONTROL_SCRIPT" status "$service_name" 2>/dev/null) if echo "$status_output" | grep -q "is running"; then - success "$service_desc is running" + success "$service_desc 正在运行" - # Extract PID if available + # 提取PID(如果可用) local pid pid=$(echo "$status_output" | grep -o "PID: [0-9]*" | cut -d' ' -f2) if [[ -n "$pid" ]]; then - info " Process ID: $pid" + info " 进程ID: $pid" fi return 0 else - error "$service_desc is not running" + error "$service_desc 未运行" return 1 fi } -# Check log files +# 检查日志文件 check_logs() { - info "Checking log files..." + info "正在检查日志文件..." if [[ ! -d "$LOG_DIR" ]]; then - warning "Log directory does not exist: $LOG_DIR" + warning "日志目录不存在: $LOG_DIR" return 1 fi - # Count log files + # 统计日志文件数量 local log_count log_count=$(find "$LOG_DIR" -name "*.log" -type f | wc -l) if [[ $log_count -gt 0 ]]; then - success "Found $log_count log files" + success "发现 $log_count 个日志文件" - # Check for recent errors + # 检查最近的错误 local recent_errors recent_errors=$(find "$LOG_DIR" -name "*.log" -type f -mmin -60 -exec grep -l "ERROR" {} \; | wc -l) if [[ $recent_errors -gt 0 ]]; then - warning "Found $recent_errors log files with recent errors (last 60 minutes)" + warning "发现 $recent_errors 个日志文件包含最近的错误 (最近60分钟)" else - info "No recent errors found in log files" + info "日志文件中未发现最近的错误" fi return 0 else - warning "No log files found" + warning "未发现日志文件" return 1 fi } -# Check pending records +# 检查待处理记录 check_pending_records() { - info "Checking pending records in database..." + info "正在检查数据库中的待处理记录..." local pending_changes pending_resume @@ -171,39 +171,39 @@ check_pending_records() { local total_pending=$((pending_changes + pending_resume)) if [[ $total_pending -gt 0 ]]; then - info "Found $total_pending pending records ($pending_changes changes, $pending_resume resume)" + info "发现 $total_pending 条待处理记录 ($pending_changes 条变更, $pending_resume 条复学)" if [[ $pending_changes -gt 0 ]]; then - warning " $pending_changes records waiting for changes processing" + warning " $pending_changes 条记录等待变更处理" fi if [[ $pending_resume -gt 0 ]]; then - warning " $pending_resume records waiting for resume processing" + warning " $pending_resume 条记录等待复学处理" fi else - success "No pending records found" + success "未发现待处理记录" fi return 0 } -# Check disk space +# 检查磁盘空间 check_disk_space() { - info "Checking disk space..." + info "正在检查磁盘空间..." local log_disk_usage log_disk_usage=$(df "$LOG_DIR" 2>/dev/null | tail -n1 | awk '{print $5}' | sed 's/%//') if [[ -z "$log_disk_usage" ]]; then - warning "Cannot determine log directory disk usage" + warning "无法确定日志目录的磁盘使用情况" return 1 fi if [[ $log_disk_usage -gt 90 ]]; then - error "Log directory disk usage is ${log_disk_usage}% - consider cleaning up old logs" + error "日志目录磁盘使用率达到 ${log_disk_usage}% - 建议清理旧日志" return 1 elif [[ $log_disk_usage -gt 75 ]]; then - warning "Log directory disk usage is ${log_disk_usage}%" + warning "日志目录磁盘使用率达到 ${log_disk_usage}%" else - success "Log directory disk usage is ${log_disk_usage}%" + success "日志目录磁盘使用率 ${log_disk_usage}%" fi return 0 @@ -267,9 +267,9 @@ generate_report() { } > "$report_file" 2>/dev/null if [[ -f "$report_file" ]]; then - success "Health check report generated: $report_file" + success "健康检查报告已生成: $report_file" else - error "Failed to generate health check report" + error "生成健康检查报告失败" fi } @@ -279,7 +279,7 @@ main() { echo "" echo "========================================" - echo " 学生状态变更处理服务健康检查" + echo " 学生状态变更处理服务健康检查" echo "========================================" echo "" @@ -320,14 +320,14 @@ main() { echo "" } -# Show usage +# 显示使用方法 show_usage() { cat << EOF -Usage: $0 [report] +用法: $0 [report] 执行学生状态变更处理服务的健康检查。 -Options: +选项: report 生成详细的健康检查报告 检查内容: @@ -352,7 +352,7 @@ case "${1:-}" in main ;; *) - error "Unknown option: $1" + error "未知选项: $1" show_usage exit 1 ;; diff --git a/退学、休学、复学、毕业/process_student_changes.sh b/退学、休学、复学、毕业/process_student_changes.sh index 8f3e1298..fdc0ae3b 100755 --- a/退学、休学、复学、毕业/process_student_changes.sh +++ b/退学、休学、复学、毕业/process_student_changes.sh @@ -12,7 +12,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CONFIG_FILE="${SCRIPT_DIR}/data.conf" if [[ ! -f "$CONFIG_FILE" ]]; then - echo "Error: Configuration file $CONFIG_FILE not found!" + echo "错误:配置文件 $CONFIG_FILE 未找到!" exit 1 fi @@ -43,13 +43,13 @@ error_exit() { exit 1 } -# Check if script is already running +# 检查脚本是否已在运行 if [[ -f "$LOCK_FILE" ]]; then if kill -0 $(cat "$LOCK_FILE") 2>/dev/null; then - log "INFO" "Script is already running (PID: $(cat "$LOCK_FILE"))" + log "INFO" "脚本已在运行 (PID: $(cat "$LOCK_FILE"))" exit 1 else - log "WARN" "Removing stale lock file" + log "WARN" "删除过期的锁定文件" rm -f "$LOCK_FILE" fi fi @@ -57,10 +57,10 @@ fi # Create lock file echo $$ > "$LOCK_FILE" -# Cleanup function +# 清理函数 cleanup() { [[ -f "$LOCK_FILE" ]] && rm -f "$LOCK_FILE" - log "INFO" "Script execution completed" + log "INFO" "脚本执行完成" } trap cleanup EXIT @@ -74,8 +74,8 @@ execute_sql() { local exit_code=$? if [[ $exit_code -ne 0 ]]; then - log "ERROR" "SQL execution failed: $sql" - log "ERROR" "MySQL error: $result" + log "ERROR" "SQL执行失败: $sql" + log "ERROR" "MySQL错误: $result" return 1 fi @@ -90,19 +90,54 @@ process_student_change() { local change_type="$4" local operator_id="${5:-1}" - log "INFO" "Processing student change - ID: $record_id, Student: $student_no ($student_id), Type: $change_type" + + log "INFO" "正在处理学生状态变更 - ID: $record_id, 学生: $student_no ($student_id), 类型: $change_type" + + # Get dormitory assignment info before transaction + local dorm_query=" + SELECT GROUP_CONCAT(id), GROUP_CONCAT(bed_id) + FROM xg_dorm_bed_student + WHERE student_id = $student_id AND status = '0' AND deleted = 0; + " + + local dorm_info="" + local dorm_ids="" + local bed_ids="" + + # Execute dormitory query with error handling + if dorm_info=$(execute_sql "$dorm_query" 2>/dev/null); then + # Parse the result (skip header if present) + if [[ -n "$dorm_info" ]]; then + # Remove warnings, keep only data rows + dorm_info=$(echo "$dorm_info" | grep -v "mysql:" | grep -E "^[0-9]+\t" | head -n 1) + if [[ -n "$dorm_info" && "$dorm_info" != "NULL" && "$dorm_info" != "NULL\tNULL" ]]; then + # Split by tab and handle NULL values + IFS=$'\t' read -r dorm_ids_raw bed_ids_raw <<< "$dorm_info" + if [[ "$dorm_ids_raw" != "NULL" && -n "$dorm_ids_raw" ]]; then + dorm_ids="$dorm_ids_raw" + fi + if [[ "$bed_ids_raw" != "NULL" && -n "$bed_ids_raw" ]]; then + bed_ids="$bed_ids_raw" + fi + fi + fi + else + log "WARN" "查询宿舍分配信息失败,将跳过宿舍处理 - 学生ID: $student_id" + fi + + log "INFO" "找到宿舍分配 - ID: ${dorm_ids:-无}, 床位: ${bed_ids:-无}" # Start transaction local transaction_sql=" START TRANSACTION; - -- 1. Backup original data to his tables - INSERT INTO xg_student_msg_his SELECT * FROM xg_student_msg WHERE id = $student_id; - INSERT INTO sys_user_his SELECT * FROM sys_user WHERE user_id = $student_id; - INSERT INTO xg_class_pos_msg_his SELECT * FROM xg_class_pos_msg WHERE student_id = $student_id; - INSERT INTO club_member_his SELECT * FROM club_member WHERE user_id = $student_id; - INSERT INTO stgl_member_his SELECT * FROM stgl_member WHERE user_id = $student_id; - INSERT INTO xg_dorm_bed_student_his SELECT * FROM xg_dorm_bed_student WHERE student_id = $student_id; + -- 1. Backup original data to his tables (ignore if already exists) + INSERT IGNORE INTO xg_student_msg_his SELECT * FROM xg_student_msg WHERE id = '$student_id'; + INSERT IGNORE INTO sys_user_his SELECT * FROM sys_user WHERE user_id = '$student_id'; + INSERT IGNORE INTO xg_class_pos_msg_his SELECT * FROM xg_class_pos_msg WHERE student_id = '$student_id'; + INSERT IGNORE INTO club_member_his SELECT * FROM club_member WHERE user_id = '$student_id'; + INSERT IGNORE INTO stgl_member_his SELECT * FROM stgl_member WHERE user_id = '$student_id'; + INSERT IGNORE INTO xg_dorm_bed_student_his SELECT * FROM xg_dorm_bed_student WHERE student_id = '$student_id'; -- 2. Update student status UPDATE xg_student_msg SET @@ -112,16 +147,16 @@ process_student_change() { WHEN '$change_type' = 'BI_YE' THEN '5' ELSE student_status END, - update_by = $operator_id, + update_by = '$operator_id', update_time = NOW() - WHERE id = $student_id; + WHERE id = '$student_id'; -- 3. Disable user account UPDATE sys_user SET status = '1', - update_by = $operator_id, + update_by = '$operator_id', update_time = NOW() - WHERE user_id = $student_id AND account_type = '2'; + WHERE user_id = '$student_id' AND account_type = '2'; -- 4. Process class position (cadre) - only for XIU_XUE, TUI_XUE, BI_YE UPDATE xg_class_pos_msg SET @@ -140,98 +175,101 @@ process_student_change() { END, term_end_date = CURDATE(), term_duration = TIMESTAMPDIFF(MONTH, term_start_date, CURDATE()), - update_by = $operator_id, + update_by = '$operator_id', update_time = NOW() - WHERE student_id = $student_id AND is_current = 1; + WHERE student_id = '$student_id' AND is_current = 1; -- 5. Process club membership - only for XIU_XUE, TUI_XUE, BI_YE UPDATE club_member SET member_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 member_status IN ('0', '1', '2'); + update_by = '$operator_id', + update_time = NOW() + WHERE user_id = '$student_id' AND member_status IN ('0', '1', '2'); -- 6. Process volunteer membership - only for XIU_XUE, TUI_XUE, BI_YE UPDATE stgl_member SET status = 4, - update_by = $operator_id, + update_by = '$operator_id', update_time = NOW() - WHERE user_id = $student_id AND status IN (0, 1, 2); + WHERE user_id = '$student_id' AND status IN (0, 1, 2); -- 7. Process dormitory - only for TUI_XUE, BI_YE + -- First, clear dormitory info from student record UPDATE xg_student_msg SET dormitory_building = NULL, dormitory_room = NULL, ext_field1 = NULL, update_time = NOW(), - update_by = $operator_id - WHERE id = $student_id; + update_by = '$operator_id' + WHERE id = '$student_id';" + # Add dormitory processing only if assignments exist and are valid + if [[ -n "$dorm_ids" && "$dorm_ids" != "NULL" && -n "$bed_ids" && "$bed_ids" != "NULL" ]]; then + transaction_sql+=" + -- Process dormitory checkout for specific assignments UPDATE xg_dorm_bed_student SET status = '1', checkout_time = NOW(), update_time = NOW(), - update_by = $operator_id - WHERE student_id = $student_id AND status = '0'; + update_by = '$operator_id' + WHERE FIND_IN_SET(id, '$dorm_ids') AND deleted = 0; + -- Update bed status for specific beds UPDATE xg_dorm_bed SET bed_status = '0' - WHERE id IN ( - SELECT bed_id FROM xg_dorm_bed_student - WHERE student_id = $student_id AND status = '1' - ); + WHERE FIND_IN_SET(id, '$bed_ids') AND deleted = 0;" + log "INFO" "将处理宿舍退宿 - 分配ID: $dorm_ids, 床位ID: $bed_ids" + else + log "INFO" "无需处理宿舍退宿(无有效宿舍分配)" + fi + + transaction_sql+=" -- 8. Update change record status UPDATE xg_student_status_change SET process_status = 1, - update_by = $operator_id, + update_by = '$operator_id', update_time = NOW() - WHERE id = $record_id; + WHERE id = '$record_id'; COMMIT; " - # Execute transaction + # 执行事务 if execute_sql "$transaction_sql"; then - log "INFO" "Successfully processed student change - ID: $record_id, Student: $student_no" + log "INFO" "成功处理学生状态变更 - ID: $record_id, 学生: $student_no" return 0 else - log "ERROR" "Failed to process student change - ID: $record_id, Student: $student_no" + log "ERROR" "处理学生状态变更失败 - ID: $record_id, 学生: $student_no" return 1 fi } # Main function main() { - log "INFO" "Starting student status change processing daemon" - log "INFO" "Processing types: XIU_XUE(休学), TUI_XUE(退学), BI_YE(毕业)" - log "INFO" "Running in continuous mode with 10-minute intervals" + log "INFO" "启动学生状态变更处理守护进程" + log "INFO" "处理类型: XIU_XUE(休学), TUI_XUE(退学), BI_YE(毕业)" + log "INFO" "以连续模式运行,间隔10分钟" - # Test database connection - log "INFO" "Testing database connection..." + # 测试数据库连接 + log "INFO" "正在测试数据库连接..." if ! execute_sql "SELECT 1;" >/dev/null 2>&1; then - error_exit "Database connection failed" + error_exit "数据库连接失败" fi - log "INFO" "Database connection successful" + log "INFO" "数据库连接成功" # Main processing loop while true; do - log "INFO" "Starting new processing cycle" + log "INFO" "开始新的处理周期" - # Get unprocessed records + # 获取未处理的记录 local query_sql=" SELECT id, student_id, student_no, change_type, operator_id FROM xg_student_status_change WHERE process_status = 0 AND change_type IN ('XIU_XUE', 'TUI_XUE', 'BI_YE') AND deleted = 0 + AND effective_date <= NOW() ORDER BY create_time ASC LIMIT $BATCH_SIZE; " @@ -239,15 +277,17 @@ main() { local records records=$(execute_sql "$query_sql") - # Check if there are records to process + + # 检查是否有记录需要处理 local record_count record_count=$(echo "$records" | wc -l) if [[ $record_count -le 1 ]]; then - log "INFO" "No unprocessed records found, waiting..." + log "INFO" "未找到未处理的记录,正在等待..." else - # Remove header line - records=$(echo "$records" | tail -n +2) + # 移除标题行和可能的警告信息 + records=$(echo "$records" | grep -v "mysql:" | grep -v "id\t" | grep -v "^$") + local processed_count=0 local failed_count=0 @@ -257,6 +297,7 @@ main() { # Skip empty lines [[ -z "$record_id" ]] && continue + local retry_count=0 local success=false @@ -267,7 +308,7 @@ main() { else ((retry_count++)) if [[ $retry_count -lt $MAX_RETRY ]]; then - log "WARN" "Processing failed, retrying in $RETRY_DELAY seconds... (attempt $retry_count/$MAX_RETRY)" + log "WARN" "处理失败,$RETRY_DELAY 秒后重试... (尝试 $retry_count/$MAX_RETRY)" sleep $RETRY_DELAY fi fi @@ -275,16 +316,16 @@ main() { if [[ $success == false ]]; then ((failed_count++)) - log "ERROR" "Failed to process record after $MAX_RETRY attempts - ID: $record_id" + log "ERROR" "$MAX_RETRY 次尝试后仍处理失败 - ID: $record_id" fi done <<< "$records" - log "INFO" "Processing cycle completed - Processed: $processed_count, Failed: $failed_count" + log "INFO" "处理周期完成 - 已处理: $processed_count, 失败: $failed_count" fi - # Wait for configured interval before next cycle - log "INFO" "Waiting $CYCLE_INTERVAL seconds before next processing cycle..." + # 等待配置的间隔时间后开始下一个周期 + log "INFO" "等待 $CYCLE_INTERVAL 秒后开始下一个处理周期..." sleep $CYCLE_INTERVAL done } diff --git a/退学、休学、复学、毕业/process_student_resume.sh b/退学、休学、复学、毕业/process_student_resume.sh index bcc39db7..75ee1316 100755 --- a/退学、休学、复学、毕业/process_student_resume.sh +++ b/退学、休学、复学、毕业/process_student_resume.sh @@ -12,7 +12,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CONFIG_FILE="${SCRIPT_DIR}/data.conf" if [[ ! -f "$CONFIG_FILE" ]]; then - echo "Error: Configuration file $CONFIG_FILE not found!" + echo "错误:配置文件 $CONFIG_FILE 未找到!" exit 1 fi @@ -43,13 +43,13 @@ error_exit() { exit 1 } -# Check if script is already running +# 检查脚本是否已在运行 if [[ -f "$LOCK_FILE" ]]; then if kill -0 $(cat "$LOCK_FILE") 2>/dev/null; then - log "INFO" "Script is already running (PID: $(cat "$LOCK_FILE"))" + log "INFO" "脚本已在运行 (PID: $(cat "$LOCK_FILE"))" exit 1 else - log "WARN" "Removing stale lock file" + log "WARN" "删除过期的锁定文件" rm -f "$LOCK_FILE" fi fi @@ -57,10 +57,10 @@ fi # Create lock file echo $$ > "$LOCK_FILE" -# Cleanup function +# 清理函数 cleanup() { [[ -f "$LOCK_FILE" ]] && rm -f "$LOCK_FILE" - log "INFO" "Script execution completed" + log "INFO" "脚本执行完成" } trap cleanup EXIT @@ -74,8 +74,8 @@ execute_sql() { local exit_code=$? if [[ $exit_code -ne 0 ]]; then - log "ERROR" "SQL execution failed: $sql" - log "ERROR" "MySQL error: $result" + log "ERROR" "SQL执行失败: $sql" + log "ERROR" "MySQL错误: $result" return 1 fi @@ -90,74 +90,75 @@ process_student_resume() { local change_type="$4" local operator_id="${5:-1}" - log "INFO" "Processing student resume - ID: $record_id, Student: $student_no ($student_id), Type: $change_type" + log "INFO" "正在处理学生复学 - ID: $record_id, 学生: $student_no ($student_id), 类型: $change_type" # Start transaction local transaction_sql=" START TRANSACTION; - -- 1. Backup original data to his tables - INSERT INTO xg_student_msg_his SELECT * FROM xg_student_msg WHERE id = $student_id; - INSERT INTO sys_user_his SELECT * FROM sys_user WHERE user_id = $student_id; + -- 1. Backup original data to his tables (ignore if already exists) + INSERT IGNORE INTO xg_student_msg_his SELECT * FROM xg_student_msg WHERE id = '$student_id'; + INSERT IGNORE INTO sys_user_his SELECT * FROM sys_user WHERE user_id = '$student_id'; -- 2. Update student status to resume (复学) UPDATE xg_student_msg SET - student_status = '3', - update_by = $operator_id, + student_status = '1', + update_by = '$operator_id', update_time = NOW() - WHERE id = $student_id; + WHERE id = '$student_id'; -- 3. Enable user account UPDATE sys_user SET status = '0', - update_by = $operator_id, + update_by = '$operator_id', update_time = NOW() - WHERE user_id = $student_id AND account_type = '2'; + WHERE user_id = '$student_id' AND account_type = '2'; -- 4. Update change record status UPDATE xg_student_status_change SET process_status = 1, - update_by = $operator_id, + update_by = '$operator_id', update_time = NOW() - WHERE id = $record_id; + WHERE id = '$record_id'; COMMIT; " - # Execute transaction + # 执行事务 if execute_sql "$transaction_sql"; then - log "INFO" "Successfully processed student resume - ID: $record_id, Student: $student_no" + log "INFO" "成功处理学生复学 - ID: $record_id, 学生: $student_no" return 0 else - log "ERROR" "Failed to process student resume - ID: $record_id, Student: $student_no" + log "ERROR" "处理学生复学失败 - ID: $record_id, 学生: $student_no" return 1 fi } # Main function main() { - log "INFO" "Starting student resume processing daemon" - log "INFO" "Processing type: FU_XUE(复学)" - log "INFO" "Running in continuous mode with 10-minute intervals" + log "INFO" "启动学生复学处理守护进程" + log "INFO" "处理类型: FU_XUE(复学)" + log "INFO" "以连续模式运行,间隔10分钟" - # Test database connection - log "INFO" "Testing database connection..." + # 测试数据库连接 + log "INFO" "正在测试数据库连接..." if ! execute_sql "SELECT 1;" >/dev/null 2>&1; then - error_exit "Database connection failed" + error_exit "数据库连接失败" fi - log "INFO" "Database connection successful" + log "INFO" "数据库连接成功" # Main processing loop while true; do - log "INFO" "Starting new resume processing cycle" + log "INFO" "开始新的复学处理周期" - # Get unprocessed records + # 获取未处理的记录 local query_sql=" SELECT id, student_id, student_no, change_type, operator_id FROM xg_student_status_change WHERE process_status = 0 AND change_type = 'FU_XUE' AND deleted = 0 + AND effective_date <= NOW() ORDER BY create_time ASC LIMIT $BATCH_SIZE; " @@ -165,15 +166,15 @@ main() { local records records=$(execute_sql "$query_sql") - # Check if there are records to process + # 检查是否有记录需要处理 local record_count record_count=$(echo "$records" | wc -l) if [[ $record_count -le 1 ]]; then - log "INFO" "No unprocessed resume records found, waiting..." + log "INFO" "未找到未处理的复学记录,正在等待..." else - # Remove header line - records=$(echo "$records" | tail -n +2) + # 移除标题行和可能的警告信息 + records=$(echo "$records" | grep -v "mysql:" | grep -v "id\t" | grep -v "^$") local processed_count=0 local failed_count=0 @@ -193,7 +194,7 @@ main() { else ((retry_count++)) if [[ $retry_count -lt $MAX_RETRY ]]; then - log "WARN" "Processing failed, retrying in $RETRY_DELAY seconds... (attempt $retry_count/$MAX_RETRY)" + log "WARN" "处理失败,$RETRY_DELAY 秒后重试... (尝试 $retry_count/$MAX_RETRY)" sleep $RETRY_DELAY fi fi @@ -201,16 +202,16 @@ main() { if [[ $success == false ]]; then ((failed_count++)) - log "ERROR" "Failed to process record after $MAX_RETRY attempts - ID: $record_id" + log "ERROR" "$MAX_RETRY 次尝试后仍处理失败 - ID: $record_id" fi done <<< "$records" - log "INFO" "Resume processing cycle completed - Processed: $processed_count, Failed: $failed_count" + log "INFO" "复学处理周期完成 - 已处理: $processed_count, 失败: $failed_count" fi - # Wait for configured interval before next cycle - log "INFO" "Waiting $CYCLE_INTERVAL seconds before next resume processing cycle..." + # 等待配置的间隔时间后开始下一个周期 + log "INFO" "等待 $CYCLE_INTERVAL 秒后开始下一个复学处理周期..." sleep $CYCLE_INTERVAL done } diff --git a/退学、休学、复学、毕业/start_services.sh b/退学、休学、复学、毕业/start_services.sh deleted file mode 100755 index 5392e7d2..00000000 --- a/退学、休学、复学、毕业/start_services.sh +++ /dev/null @@ -1,123 +0,0 @@ -#!/bin/bash - -# =========================================== -# 学生状态变更处理服务启动脚本 -# 用于启动所有相关的处理服务 -# =========================================== - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CONTROL_SCRIPT="${SCRIPT_DIR}/control_scripts.sh" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -log() { - local level="$1" - local message="$2" - local timestamp=$(date '+%Y-%m-%d %H:%M:%S') - echo -e "${timestamp} [$level] $message" -} - -success() { - log "${GREEN}SUCCESS${NC}" "$1" -} - -error() { - log "${RED}ERROR${NC}" "$1" -} - -warning() { - log "${YELLOW}WARNING${NC}" "$1" -} - -# Check if control script exists and is executable -if [[ ! -x "$CONTROL_SCRIPT" ]]; then - error "Control script not found or not executable: $CONTROL_SCRIPT" - exit 1 -fi - -# Function to start a service -start_service() { - local service_name="$1" - local service_desc="$2" - - log "INFO" "Starting $service_desc..." - if "$CONTROL_SCRIPT" start "$service_name"; then - success "$service_desc started successfully" - return 0 - else - error "Failed to start $service_desc" - return 1 - fi -} - -# Function to check service status -check_service() { - local service_name="$1" - local service_desc="$2" - - log "INFO" "Checking $service_desc status..." - if "$CONTROL_SCRIPT" status "$service_name" | grep -q "is running"; then - success "$service_desc is running" - return 0 - else - warning "$service_desc is not running" - return 1 - fi -} - -# Main function -main() { - log "INFO" "=== 学生状态变更处理服务启动脚本 ===" - log "INFO" "Starting all student status change processing services..." - - local failed_services=() - - # Start changes processing service - if ! start_service "changes" "学生状态变更处理服务 (休学/退学/毕业)"; then - failed_services+=("changes") - fi - - # Start resume processing service - if ! start_service "resume" "学生复学处理服务"; then - failed_services+=("resume") - fi - - # Wait a moment for services to fully start - sleep 3 - - log "INFO" "=== 服务状态检查 ===" - - # Check all services status - check_service "changes" "学生状态变更处理服务 (休学/退学/毕业)" - check_service "resume" "学生复学处理服务" - - # Summary - log "INFO" "=== 启动完成 ===" - if [[ ${#failed_services[@]} -eq 0 ]]; then - success "所有服务启动成功" - echo "" - echo "服务控制命令:" - echo " 查看状态: $CONTROL_SCRIPT statusall" - echo " 停止服务: $CONTROL_SCRIPT stopall" - echo " 重启服务: $CONTROL_SCRIPT restart changes|resume" - echo "" - echo "日志文件位置: /var/log/student_status_change/" - else - error "以下服务启动失败: ${failed_services[*]}" - echo "" - echo "故障排除:" - echo "1. 检查数据库配置: cat data.conf" - echo "2. 查看日志文件: tail -f /var/log/student_status_change/*.log" - echo "3. 检查数据库连接: mysql -h\$DB_HOST -P\$DB_PORT -u\$DB_USER -p\$DB_PASS \$DB_NAME -e 'SELECT 1;'" - exit 1 - fi -} - -# Run main function -main "$@" diff --git a/退学、休学、复学、毕业/stop_services.sh b/退学、休学、复学、毕业/stop_services.sh deleted file mode 100755 index 46d2d860..00000000 --- a/退学、休学、复学、毕业/stop_services.sh +++ /dev/null @@ -1,177 +0,0 @@ -#!/bin/bash - -# =========================================== -# 学生状态变更处理服务停止脚本 -# 用于停止所有相关的处理服务 -# =========================================== - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CONTROL_SCRIPT="${SCRIPT_DIR}/control_scripts.sh" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -log() { - local level="$1" - local message="$2" - local timestamp=$(date '+%Y-%m-%d %H:%M:%S') - echo -e "${timestamp} [$level] $message" -} - -success() { - log "${GREEN}SUCCESS${NC}" "$1" -} - -error() { - log "${RED}ERROR${NC}" "$1" -} - -warning() { - log "${YELLOW}WARNING${NC}" "$1" -} - -# Check if control script exists and is executable -if [[ ! -x "$CONTROL_SCRIPT" ]]; then - error "Control script not found or not executable: $CONTROL_SCRIPT" - exit 1 -fi - -# Function to stop a service -stop_service() { - local service_name="$1" - local service_desc="$2" - - log "INFO" "Stopping $service_desc..." - if "$CONTROL_SCRIPT" stop "$service_name"; then - success "$service_desc stopped successfully" - return 0 - else - warning "$service_desc may not have been running" - return 0 # Not treating this as a hard error - fi -} - -# Function to check service status after stop -check_service_stopped() { - local service_name="$1" - local service_desc="$2" - - log "INFO" "Verifying $service_desc has stopped..." - if "$CONTROL_SCRIPT" status "$service_name" | grep -q "is not running"; then - success "$service_desc confirmed stopped" - return 0 - else - warning "$service_desc may still be running" - return 1 - fi -} - -# Function to force kill if needed -force_kill_service() { - local service_name="$1" - local script_pattern="$2" - local service_desc="$3" - - log "INFO" "Force killing $service_desc..." - if pkill -f "$script_pattern"; then - sleep 2 - success "$service_desc force killed" - return 0 - else - warning "No processes found for $service_desc" - return 0 - fi -} - -# Main function -main() { - local force_kill="${1:-false}" - - log "INFO" "=== 学生状态变更处理服务停止脚本 ===" - - if [[ "$force_kill" == "force" ]]; then - log "INFO" "Performing force stop of all services..." - - # Force kill all related processes - force_kill_service "changes" "process_student_changes.sh" "学生状态变更处理服务" - force_kill_service "resume" "process_student_resume.sh" "学生复学处理服务" - - # Clean up lock and PID files - log "INFO" "Cleaning up lock and PID files..." - rm -f "${SCRIPT_DIR}"/*.lock - rm -f "${SCRIPT_DIR}/pids"/*.pid - - success "Force stop completed" - exit 0 - fi - - log "INFO" "Stopping all student status change processing services..." - - # Stop services gracefully - stop_service "changes" "学生状态变更处理服务 (休学/退学/毕业)" - stop_service "resume" "学生复学处理服务" - - # Wait a moment for services to fully stop - sleep 3 - - log "INFO" "=== 服务状态验证 ===" - - # Check all services are stopped - check_service_stopped "changes" "学生状态变更处理服务 (休学/退学/毕业)" - check_service_stopped "resume" "学生复学处理服务" - - # Final cleanup - log "INFO" "Performing final cleanup..." - rm -f "${SCRIPT_DIR}"/*.lock 2>/dev/null || true - rm -f "${SCRIPT_DIR}/pids"/*.pid 2>/dev/null || true - - log "INFO" "=== 停止完成 ===" - success "所有服务已停止" - - echo "" - echo "如果服务未能正常停止,请使用强制停止:" - echo " $0 force" - echo "" - echo "重新启动服务:" - echo " ./start_services.sh" -} - -# Show usage -show_usage() { - cat << EOF -Usage: $0 [force] - -停止所有学生状态变更处理服务。 - -Options: - force 强制杀死所有相关进程并清理锁文件 - -Examples: - $0 # 正常停止所有服务 - $0 force # 强制停止所有服务 - -EOF -} - -# Parse arguments -case "${1:-}" in - force) - main "force" - ;; - -h|--help) - show_usage - ;; - "") - main - ;; - *) - error "Unknown option: $1" - show_usage - exit 1 - ;; -esac diff --git a/退学、休学、复学、毕业/test_data.sql b/退学、休学、复学、毕业/test_data.sql deleted file mode 100644 index 7d66ebd7..00000000 --- a/退学、休学、复学、毕业/test_data.sql +++ /dev/null @@ -1,104 +0,0 @@ --- =========================================== --- 学生状态变更处理测试数据 --- 用于测试自动化处理脚本 --- =========================================== - --- 注意:请根据实际情况修改学生ID和学号 - --- 插入测试数据到 xg_student_status_change 表 --- 状态:0=未处理,1=已处理 - --- 测试休学处理 -INSERT INTO xg_student_status_change ( - id, student_id, student_no, change_type, apply_date, - effective_date, reason, operator_id, source, process_status -) VALUES ( - 10001, 10001, '20240001', 'XIU_XUE', NOW(), - CURDATE(), '学生申请休学', 1, 'manual', 0 -); - --- 测试退学处理 -INSERT INTO xg_student_status_change ( - id, student_id, student_no, change_type, apply_date, - effective_date, reason, operator_id, source, process_status -) VALUES ( - 10002, 10002, '20240002', 'TUI_XUE', NOW(), - CURDATE(), '学生申请退学', 1, 'manual', 0 -); - --- 测试毕业处理 -INSERT INTO xg_student_status_change ( - id, student_id, student_no, change_type, apply_date, - effective_date, reason, operator_id, source, process_status -) VALUES ( - 10003, 10003, '20240003', 'BI_YE', NOW(), - CURDATE(), '学生毕业处理', 1, 'manual', 0 -); - --- 测试复学处理 -INSERT INTO xg_student_status_change ( - id, student_id, student_no, change_type, apply_date, - effective_date, reason, operator_id, source, process_status -) VALUES ( - 10004, 10004, '20240004', 'FU_XUE', NOW(), - CURDATE(), '学生申请复学', 1, 'manual', 0 -); - --- 批量测试数据(休学) -INSERT INTO xg_student_status_change ( - id, student_id, student_no, change_type, apply_date, - effective_date, reason, operator_id, source, process_status -) SELECT - 20000 + (@row_number := @row_number + 1), - 20000 + @row_number, - CONCAT('2024', LPAD(@row_number, 4, '0')), - 'XIU_XUE', - NOW(), - CURDATE(), - CONCAT('批量测试休学-', @row_number), - 1, - 'manual', - 0 -FROM (SELECT @row_number := 0) r -CROSS JOIN (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) nums; - --- 批量测试数据(退学) -INSERT INTO xg_student_status_change ( - id, student_id, student_no, change_type, apply_date, - effective_date, reason, operator_id, source, process_status -) SELECT - 30000 + (@row_number2 := @row_number2 + 1), - 30000 + @row_number2, - CONCAT('2024', LPAD(@row_number2 + 10, 4, '0')), - 'TUI_XUE', - NOW(), - CURDATE(), - CONCAT('批量测试退学-', @row_number2), - 1, - 'manual', - 0 -FROM (SELECT @row_number2 := 0) r2 -CROSS JOIN (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) nums2; - --- 查询测试数据 -SELECT - '测试数据插入完成' as status, - COUNT(*) as total_test_records -FROM xg_student_status_change -WHERE id >= 10001; - --- 按类型统计 -SELECT - change_type, - COUNT(*) as count -FROM xg_student_status_change -WHERE id >= 10001 -GROUP BY change_type -ORDER BY change_type; - --- =========================================== --- 清理测试数据的SQL(执行前请确认) --- =========================================== - --- DELETE FROM xg_student_status_change WHERE id >= 10001; --- COMMIT;