学生资料设置、头像与自动备份恢复。
首页卡片支持修改/删除;详情页设置 Tab 可维护学校、年级与头像;系统设置新增数据备份下载与恢复;备份默认存 /root/grade-archive-backups,详见 docs/BACKUP.md。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+25
-7
@@ -1,9 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
# 中学成绩档案 — 数据备份(数据库 + uploads,统一 tar.gz)
|
||||
set -euo pipefail
|
||||
|
||||
INSTALL_DIR="${INSTALL_DIR:-/opt/secondary-school-grade-archive}"
|
||||
BACKUP_DIR="${BACKUP_DIR:-${INSTALL_DIR}/backups}"
|
||||
BACKUP_DIR="${BACKUP_DIR:-/root/grade-archive-backups}"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
ARCHIVE="${BACKUP_DIR}/grade-archive_${TIMESTAMP}.tar.gz"
|
||||
WORK=$(mktemp -d)
|
||||
|
||||
cleanup() {
|
||||
rm -rf "${WORK}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
cd "${INSTALL_DIR}"
|
||||
# shellcheck disable=SC1090
|
||||
@@ -12,11 +20,21 @@ mkdir -p "${BACKUP_DIR}"
|
||||
|
||||
echo "[INFO] 备份数据库…"
|
||||
PGPASSWORD="${POSTGRES_PASSWORD}" pg_dump -h 127.0.0.1 -U "${POSTGRES_USER}" "${POSTGRES_DB}" \
|
||||
> "${BACKUP_DIR}/db_${TIMESTAMP}.sql"
|
||||
--no-owner --no-privileges --clean --if-exists \
|
||||
> "${WORK}/database.sql"
|
||||
|
||||
echo "[INFO] 备份 uploads…"
|
||||
tar -czf "${BACKUP_DIR}/uploads_${TIMESTAMP}.tar.gz" -C "${INSTALL_DIR}" uploads/
|
||||
cat > "${WORK}/manifest.json" <<EOF
|
||||
{
|
||||
"app": "secondary-school-grade-archive",
|
||||
"created_at": "$(date -Iseconds)",
|
||||
"database": "${POSTGRES_DB}"
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "[INFO] 完成:"
|
||||
echo " ${BACKUP_DIR}/db_${TIMESTAMP}.sql"
|
||||
echo " ${BACKUP_DIR}/uploads_${TIMESTAMP}.tar.gz"
|
||||
echo "[INFO] 打包 uploads…"
|
||||
tar -czf "${ARCHIVE}" -C "${WORK}" database.sql manifest.json -C "${INSTALL_DIR}" uploads/
|
||||
|
||||
echo "[INFO] 完成: ${ARCHIVE}"
|
||||
|
||||
# 清理 30 天前的备份
|
||||
find "${BACKUP_DIR}" -name 'grade-archive_*.tar.gz' -mtime +30 -delete 2>/dev/null || true
|
||||
|
||||
+17
-1
@@ -149,6 +149,9 @@ POSTGRES_PASSWORD=${pg_pass}
|
||||
POSTGRES_DB=student_archive
|
||||
DATABASE_URL=postgresql://${pg_user}:${pg_pass}@127.0.0.1:5432/student_archive
|
||||
UPLOAD_DIR=${INSTALL_DIR}/uploads
|
||||
BACKUP_DIR=/root/grade-archive-backups
|
||||
BACKUP_RETENTION_DAYS=30
|
||||
AUTO_BACKUP_INTERVAL_HOURS=24
|
||||
CORS_ORIGINS=http://${server_ip}:${WEB_PORT},http://127.0.0.1:${WEB_PORT},http://localhost:${WEB_PORT}
|
||||
# OCR 同机 GPU Worker(screen 常驻)
|
||||
OCR_SERVICE_URL=http://127.0.0.1:${OCR_PORT}
|
||||
@@ -237,10 +240,21 @@ setup_systemd() {
|
||||
start_service() {
|
||||
log_info "启动主程序…"
|
||||
cd "${INSTALL_DIR}"
|
||||
mkdir -p uploads backups
|
||||
mkdir -p uploads backups /root/grade-archive-backups
|
||||
chmod +x deploy/backup.sh deploy/restore.sh 2>/dev/null || true
|
||||
systemctl restart grade-archive
|
||||
}
|
||||
|
||||
setup_backup_cron() {
|
||||
log_info "配置每日自动备份(/root/grade-archive-backups)…"
|
||||
cat > /etc/cron.d/grade-archive-backup <<EOF
|
||||
SHELL=/bin/bash
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
0 3 * * * root INSTALL_DIR=${INSTALL_DIR} BACKUP_DIR=/root/grade-archive-backups bash ${INSTALL_DIR}/deploy/backup.sh >> /var/log/grade-archive-backup.log 2>&1
|
||||
EOF
|
||||
chmod 644 /etc/cron.d/grade-archive-backup
|
||||
}
|
||||
|
||||
wait_healthy() {
|
||||
local i
|
||||
log_info "等待主程序就绪(最多 2 分钟)…"
|
||||
@@ -285,6 +299,7 @@ print_summary() {
|
||||
echo ""
|
||||
echo " 主程序: systemctl status grade-archive"
|
||||
echo " 更新: sudo bash ${INSTALL_DIR}/deploy/update.sh"
|
||||
echo " 备份说明: docs/BACKUP.md"
|
||||
echo " 卸载: sudo bash ${INSTALL_DIR}/deploy/uninstall.sh"
|
||||
echo " 微信 dekun03 手机 18364911125"
|
||||
echo "=========================================="
|
||||
@@ -305,6 +320,7 @@ main() {
|
||||
setup_ocr_gpu
|
||||
stop_legacy_pm2
|
||||
setup_systemd
|
||||
setup_backup_cron
|
||||
start_service
|
||||
wait_healthy
|
||||
print_summary
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
# 中学成绩档案 — 从备份包恢复(命令行,适合新服务器迁移)
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "用法: sudo bash deploy/restore.sh /path/to/grade-archive_YYYYMMDD_HHMMSS.tar.gz"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ARCHIVE="$1"
|
||||
INSTALL_DIR="${INSTALL_DIR:-/opt/secondary-school-grade-archive}"
|
||||
WORK=$(mktemp -d)
|
||||
|
||||
cleanup() {
|
||||
rm -rf "${WORK}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
if [[ ! -f "${ARCHIVE}" ]]; then
|
||||
echo "[ERROR] 备份文件不存在: ${ARCHIVE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "${INSTALL_DIR}"
|
||||
# shellcheck disable=SC1090
|
||||
source .env
|
||||
|
||||
echo "[WARN] 即将恢复数据库与 uploads,当前数据将被覆盖。"
|
||||
read -rp "确认继续?[y/N] " confirm
|
||||
if [[ "${confirm}" != "y" && "${confirm}" != "Y" ]]; then
|
||||
echo "已取消"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "[INFO] 解压备份…"
|
||||
tar -xzf "${ARCHIVE}" -C "${WORK}"
|
||||
|
||||
if [[ ! -f "${WORK}/database.sql" ]]; then
|
||||
echo "[ERROR] 备份包缺少 database.sql"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[INFO] 恢复数据库…"
|
||||
PGPASSWORD="${POSTGRES_PASSWORD}" psql -h 127.0.0.1 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" \
|
||||
-v ON_ERROR_STOP=1 -f "${WORK}/database.sql"
|
||||
|
||||
if [[ -d "${WORK}/uploads" ]]; then
|
||||
echo "[INFO] 恢复 uploads…"
|
||||
rm -rf "${INSTALL_DIR}/uploads"
|
||||
cp -a "${WORK}/uploads" "${INSTALL_DIR}/uploads"
|
||||
fi
|
||||
|
||||
echo "[INFO] 重启服务…"
|
||||
systemctl restart grade-archive 2>/dev/null || true
|
||||
|
||||
echo "[INFO] 恢复完成"
|
||||
Reference in New Issue
Block a user