Files
hzdyjs/学生换班级/process_student_class_change.sh
T
2025-12-25 22:20:22 +08:00

302 lines
9.3 KiB
Bash
Executable File

#!/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 "$@"