Files
debt-manager/debt-manager.sh
OP 056c4defec v2.4: 响应式布局 + 借款按钮优化
- 所有页面添加响应式CSS,支持手机/电脑自适应
- index.html: 导航栏active状态、表单、统计、借款列表响应式
- analysis.html: 图表、统计卡片响应式
- admin.html: 表格、搜索栏响应式
- reset-password.html: 登录卡片响应式
- 修复导航栏active类:analysis.html的分析标签高亮
- 非本人借款:隐藏修改按钮,快速还款改为快速查看
- 修复main.py重复函数
- 添加debt-manager.sh管理脚本
2026-07-01 22:50:09 +08:00

322 lines
10 KiB
Bash
Executable File

#!/bin/bash
# ============================================
# 债务管理系统 - 管理脚本 v2.3
# ============================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
INSTALL_DIR="/opt/debt-manager"
show_logo() {
clear
echo -e "${CYAN}"
echo "╔══════════════════════════════════════════════╗"
echo "║ 债务管理系统 Debt Manager ║"
echo "║ 个人/小团队债务管理平台 ║"
echo "║ 版本: v2.3 ║"
echo "╚══════════════════════════════════════════════╝"
echo -e "${NC}"
}
detect_arch() {
ARCH=$(uname -m)
case "$ARCH" in
x86_64|amd64) ARCH_NAME="x86" ;;
aarch64|arm64) ARCH_NAME="arm64" ;;
*) echo -e "${RED}不支持的架构: $ARCH${NC}"; return 1 ;;
esac
echo -e "${CYAN}架构: $ARCH_NAME${NC}"
}
check_docker() {
if ! command -v docker &> /dev/null; then
echo -e "${RED}请先安装 Docker${NC}"; exit 1
fi
if ! docker compose version &> /dev/null; then
echo -e "${RED}请先安装 Docker Compose${NC}"; exit 1
fi
}
gen_password() { openssl rand -hex 16; }
get_script_dir() {
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do
DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
cd -P "$(dirname "$SOURCE")" && pwd
}
# 检查镜像是否存在
check_images_exist() {
local backend_image="debt-manager-backend:${ARCH_NAME}"
local frontend_image="debt-manager-frontend:${ARCH_NAME}"
local postgres_image="postgres:15-alpine"
local backend_exists=$(docker image inspect "$backend_image" 2>/dev/null && echo "yes" || echo "no")
local frontend_exists=$(docker image inspect "$frontend_image" 2>/dev/null && echo "yes" || echo "no")
local postgres_exists=$(docker image inspect "$postgres_image" 2>/dev/null && echo "yes" || echo "no")
if [ "$backend_exists" = "yes" ] && [ "$frontend_exists" = "yes" ] && [ "$postgres_exists" = "yes" ]; then
return 0
else
return 1
fi
}
# 加载镜像(如果不存在)
load_images_if_needed() {
local script_dir="$1"
if check_images_exist; then
echo -e "${GREEN}镜像已存在,跳过加载${NC}"
return 0
fi
echo -e "${CYAN}加载镜像...${NC}"
local loaded=0
for f in "$script_dir/deploy/"*-${ARCH_NAME}.tar.gz "$script_dir/deploy/postgres"*.tar.gz; do
if [ -f "$f" ]; then
local img_name=$(basename "$f" .tar.gz)
if docker image inspect "$img_name" &>/dev/null; then
echo -e " ${GREEN}${NC} $img_name (已存在)"
else
echo -e " 加载 $img_name ..."
docker load < "$f" 2>/dev/null && loaded=$((loaded+1))
fi
fi
done
if [ $loaded -gt 0 ]; then
echo -e "${GREEN}加载了 $loaded 个镜像${NC}"
fi
}
# 验证所有容器运行状态
verify_containers() {
echo -e "${CYAN}验证容器状态...${NC}"
local all_up=true
for svc in db backend frontend; do
local status=$(docker compose ps --format '{{.Status}}' --filter "name=$svc" 2>/dev/null)
if echo "$status" | grep -q "Up"; then
echo -e " ${GREEN}${NC} $svc: 运行中"
else
echo -e " ${RED}${NC} $svc: 未运行 ($status)"
all_up=false
fi
done
if $all_up; then
echo -e "${GREEN}所有容器运行正常${NC}"
return 0
else
echo -e "${RED}部分容器未正常运行${NC}"
return 1
fi
}
show_menu() {
echo -e "${YELLOW}请选择操作:${NC}"
echo ""
echo " 1) 安装系统"
echo " 2) 更新系统"
echo " 3) 卸载系统"
echo " 4) 重置系统"
echo " 5) 查看状态"
echo " 0) 退出"
echo ""
read -p "请输入选项 [0-5]: " choice
}
install_system() {
echo -e "${CYAN}═══ 安装债务管理系统 ═══${NC}"
if [ -d "$INSTALL_DIR" ]; then
echo -e "${YELLOW}系统已安装,是否覆盖? (y/N)${NC}"
read -p "> " confirm
[ "$confirm" != "y" ] && return
cd "$INSTALL_DIR" && docker compose down 2>/dev/null || true
fi
detect_arch || return
SCRIPT_DIR="$(get_script_dir)"
mkdir -p "$INSTALL_DIR" && cd "$INSTALL_DIR"
# 复制 docker-compose 文件
if [ -f "$SCRIPT_DIR/deploy/docker-compose.${ARCH_NAME}.yml" ]; then
cp "$SCRIPT_DIR/deploy/docker-compose.${ARCH_NAME}.yml" docker-compose.yml
elif [ -f "$SCRIPT_DIR/docker-compose.yml" ]; then
cp "$SCRIPT_DIR/docker-compose.yml" docker-compose.yml
else
echo -e "${RED}找不到 docker-compose 配置文件${NC}"; return 1
fi
# 复制镜像文件
if [ -d "$SCRIPT_DIR/deploy" ]; then
for f in "$SCRIPT_DIR/deploy/"*-${ARCH_NAME}.tar.gz "$SCRIPT_DIR/deploy/postgres"*.tar.gz; do
[ -f "$f" ] && cp "$f" .
done
fi
[ -f "$SCRIPT_DIR/restore.sh" ] && cp "$SCRIPT_DIR/restore.sh" . && chmod +x restore.sh
# 生成密钥
DB_PASS=$(gen_password)
SECRET=$(gen_password)
cat > .env << EOF
POSTGRES_DB=debt_manager
POSTGRES_USER=postgres
POSTGRES_PASSWORD=$DB_PASS
DATABASE_URL=postgresql+asyncpg://postgres:$DB_PASS@db:5432/debt_manager
SECRET_KEY=$SECRET
EOF
# 检查并加载镜像
load_images_if_needed "$SCRIPT_DIR"
# 启动
echo -e "${CYAN}启动服务...${NC}"
docker compose up -d
echo -e "${CYAN}等待服务启动...${NC}"
sleep 10
# 验证容器
if verify_containers; then
IP=$(hostname -I 2>/dev/null | awk '{print $1}' || echo "localhost")
echo ""
echo -e "${GREEN}═══ 安装成功! ═══${NC}"
echo -e " 前台: ${CYAN}http://$IP:806${NC}"
echo -e " 后台: ${CYAN}http://$IP:806/admin.html${NC}"
echo -e " 管理员: ${CYAN}admin / admin123${NC}"
echo -e " ${YELLOW}请立即修改默认密码!${NC}"
else
echo -e "${RED}启动失败,查看日志:${NC}"
docker compose logs --tail=30
fi
}
update_system() {
echo -e "${CYAN}═══ 更新债务管理系统 ═══${NC}"
[ ! -d "$INSTALL_DIR" ] && { echo -e "${YELLOW}系统未安装${NC}"; return; }
cd "$INSTALL_DIR"
detect_arch || return
SCRIPT_DIR="$(get_script_dir)"
# 备份
echo -e "${CYAN}备份数据库...${NC}"
docker compose exec -T db pg_dump -U postgres debt_manager > "backup_$(date +%Y%m%d_%H%M%S).sql" 2>/dev/null || true
echo -e "${GREEN}备份完成${NC}"
# 更新文件
[ -f "$SCRIPT_DIR/deploy/docker-compose.${ARCH_NAME}.yml" ] && cp "$SCRIPT_DIR/deploy/docker-compose.${ARCH_NAME}.yml" docker-compose.yml
if [ -d "$SCRIPT_DIR/deploy" ]; then
for f in "$SCRIPT_DIR/deploy/"*-${ARCH_NAME}.tar.gz "$SCRIPT_DIR/deploy/postgres"*.tar.gz; do
[ -f "$f" ] && cp "$f" .
done
fi
# 检查并加载新镜像
load_images_if_needed "$SCRIPT_DIR"
echo -e "${CYAN}重启服务...${NC}"
docker compose down && docker compose up -d
echo -e "${CYAN}等待服务启动...${NC}"
sleep 8
if verify_containers; then
echo -e "${GREEN}更新完成!${NC}"
else
echo -e "${RED}更新失败,查看日志:${NC}"
docker compose logs --tail=30
fi
}
uninstall_system() {
echo -e "${CYAN}═══ 卸载债务管理系统 ═══${NC}"
[ ! -d "$INSTALL_DIR" ] && { echo -e "${YELLOW}系统未安装${NC}"; return; }
echo -e "${RED}警告: 将删除所有数据,包括数据库!${NC}"
read -p "输入 YES 确认: " confirm
[ "$confirm" != "YES" ] && { echo -e "${RED}已取消${NC}"; return; }
cd "$INSTALL_DIR" && docker compose down -v 2>/dev/null || true
rm -rf "$INSTALL_DIR"
echo -e "${GREEN}卸载完成${NC}"
}
reset_system() {
echo -e "${CYAN}═══ 重置债务管理系统 ═══${NC}"
[ ! -d "$INSTALL_DIR" ] && { echo -e "${RED}系统未安装${NC}"; return; }
echo -e "${RED}警告: 将清空所有数据!${NC}"
read -p "输入 YES 确认: " confirm
[ "$confirm" != "YES" ] && { echo -e "${RED}已取消${NC}"; return; }
cd "$INSTALL_DIR"
echo -e "${CYAN}备份数据...${NC}"
docker compose exec -T db pg_dump -U postgres debt_manager > "pre_reset_$(date +%Y%m%d_%H%M%S).sql" 2>/dev/null || true
docker compose down -v 2>/dev/null || true
docker volume rm debt-manager_pgdata 2>/dev/null || true
DB_PASS=$(gen_password)
SECRET=$(gen_password)
cat > .env << EOF
POSTGRES_DB=debt_manager
POSTGRES_USER=postgres
POSTGRES_PASSWORD=$DB_PASS
DATABASE_URL=postgresql+asyncpg://postgres:$DB_PASS@db:5432/debt_manager
SECRET_KEY=$SECRET
EOF
docker compose up -d
echo -e "${CYAN}等待服务启动...${NC}"
sleep 10
if verify_containers; then
echo -e "${GREEN}重置完成!${NC}"
echo -e " 管理员: ${CYAN}admin / admin123${NC}"
else
echo -e "${RED}重置失败,查看日志:${NC}"
docker compose logs --tail=30
fi
}
show_status() {
[ ! -d "$INSTALL_DIR" ] && { echo -e "${YELLOW}系统未安装${NC}"; return; }
cd "$INSTALL_DIR"
echo -e "${CYAN}═══ 服务状态 ═══${NC}"
docker compose ps
echo ""
echo -e "${CYAN}磁盘使用:${NC}"
du -sh "$INSTALL_DIR" 2>/dev/null || true
}
main() {
show_logo
check_docker
while true; do
show_menu
case $choice in
1) install_system ;;
2) update_system ;;
3) uninstall_system ;;
4) reset_system ;;
5) show_status ;;
0) echo -e "${GREEN}再见!${NC}"; exit 0 ;;
*) echo -e "${RED}无效选项${NC}" ;;
esac
echo ""
read -p "按回车继续..." _
done
}
main