- 所有页面添加响应式CSS,支持手机/电脑自适应 - index.html: 导航栏active状态、表单、统计、借款列表响应式 - analysis.html: 图表、统计卡片响应式 - admin.html: 表格、搜索栏响应式 - reset-password.html: 登录卡片响应式 - 修复导航栏active类:analysis.html的分析标签高亮 - 非本人借款:隐藏修改按钮,快速还款改为快速查看 - 修复main.py重复函数 - 添加debt-manager.sh管理脚本
322 lines
10 KiB
Bash
Executable File
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
|