公开数据看板、四位 Key 录入面板、管理后台与三级权限、动态字段配置、 PostgreSQL/SQLite 双支持、数据库备份,以及本版新增的成品图上传与预览。 图片相关: - 录入表单支持相册选图与手机端直接拍照,每条记录最多 6 张 - 浏览器内压缩到最长边 1600 并剥离 EXIF,入库统一为 JPG/PNG - 二进制直接入库,现有备份自动覆盖图片,部署无需新增卷 - 详情页缩略图宫格与全屏 lightbox,公开看板同样可见 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
130 lines
3.5 KiB
Bash
Executable File
130 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -Eeuo pipefail
|
||
|
||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
cd "$ROOT_DIR"
|
||
|
||
ENV_FILE="$ROOT_DIR/.env"
|
||
CREATED_ENV=0
|
||
|
||
log() {
|
||
printf '\033[1;34m[laser-data]\033[0m %s\n' "$*"
|
||
}
|
||
|
||
fail() {
|
||
printf '\033[1;31m[laser-data] 启动失败:\033[0m%s\n' "$*" >&2
|
||
exit 1
|
||
}
|
||
|
||
random_value() {
|
||
if command -v openssl >/dev/null 2>&1; then
|
||
openssl rand -hex "$1"
|
||
else
|
||
head -c "$1" /dev/urandom | od -An -tx1 | tr -d ' \n'
|
||
fi
|
||
}
|
||
|
||
env_value() {
|
||
local key="$1"
|
||
sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1
|
||
}
|
||
|
||
ensure_env_value() {
|
||
local key="$1"
|
||
local value="$2"
|
||
if ! grep -q "^${key}=" "$ENV_FILE"; then
|
||
printf '%s=%s\n' "$key" "$value" >> "$ENV_FILE"
|
||
fi
|
||
}
|
||
|
||
on_error() {
|
||
printf '\n'
|
||
log "最近的容器日志:"
|
||
docker compose logs --tail=60 web db 2>/dev/null || true
|
||
}
|
||
trap on_error ERR
|
||
|
||
command -v docker >/dev/null 2>&1 || fail "未找到 Docker。请先安装 Docker Desktop:https://www.docker.com/products/docker-desktop/"
|
||
|
||
if ! docker info >/dev/null 2>&1; then
|
||
if [[ "$(uname -s)" == "Darwin" ]] && [[ -d "/Applications/Docker.app" ]]; then
|
||
log "Docker Desktop 尚未运行,正在启动..."
|
||
open -a Docker
|
||
for _ in $(seq 1 90); do
|
||
docker info >/dev/null 2>&1 && break
|
||
sleep 2
|
||
done
|
||
fi
|
||
fi
|
||
docker info >/dev/null 2>&1 || fail "Docker 服务未运行,请启动 Docker Desktop 后重新执行 ./start.sh"
|
||
docker compose version >/dev/null 2>&1 || fail "当前 Docker 未安装 Compose 插件"
|
||
|
||
if [[ ! -f "$ENV_FILE" ]]; then
|
||
CREATED_ENV=1
|
||
ADMIN_PASSWORD="Admin-$(random_value 8)"
|
||
cat > "$ENV_FILE" <<EOF
|
||
APP_NAME=激光材料数据平台
|
||
APP_PORT=5980
|
||
APP_SECRET=$(random_value 32)
|
||
ADMIN_USERNAME=admin
|
||
ADMIN_PASSWORD=${ADMIN_PASSWORD}
|
||
POSTGRES_PASSWORD=$(random_value 24)
|
||
SESSION_HOURS=12
|
||
BACKUP_KEEP_DAYS=30
|
||
EOF
|
||
chmod 600 "$ENV_FILE"
|
||
log "已生成 .env 和随机初始密码"
|
||
else
|
||
ensure_env_value "APP_SECRET" "$(random_value 32)"
|
||
ensure_env_value "APP_PORT" "5980"
|
||
ensure_env_value "ADMIN_USERNAME" "admin"
|
||
ensure_env_value "ADMIN_PASSWORD" "Admin-$(random_value 8)"
|
||
ensure_env_value "POSTGRES_PASSWORD" "$(random_value 24)"
|
||
ensure_env_value "SESSION_HOURS" "12"
|
||
ensure_env_value "BACKUP_KEEP_DAYS" "30"
|
||
chmod 600 "$ENV_FILE"
|
||
log "使用现有 .env 配置"
|
||
fi
|
||
|
||
mkdir -p backups
|
||
|
||
log "正在构建并启动网站与 PostgreSQL..."
|
||
docker compose up -d --build
|
||
|
||
APP_PORT="$(env_value APP_PORT)"
|
||
log "等待网站完成初始化..."
|
||
HEALTHY=0
|
||
for _ in $(seq 1 60); do
|
||
if curl -fsS "http://127.0.0.1:${APP_PORT}/health" >/dev/null 2>&1; then
|
||
HEALTHY=1
|
||
break
|
||
fi
|
||
sleep 2
|
||
done
|
||
|
||
if [[ "$HEALTHY" != "1" ]]; then
|
||
fail "网站在 120 秒内未通过健康检查,请查看上方日志"
|
||
fi
|
||
|
||
ADMIN_USERNAME="$(env_value ADMIN_USERNAME)"
|
||
ADMIN_PASSWORD="$(env_value ADMIN_PASSWORD)"
|
||
|
||
printf '\n'
|
||
printf '\033[1;32m网站已启动\033[0m\n'
|
||
printf '访问地址: http://localhost:%s\n' "$APP_PORT"
|
||
printf '管理员用户名: %s\n' "$ADMIN_USERNAME"
|
||
if [[ "$CREATED_ENV" == "1" ]]; then
|
||
printf '管理员初始密码:%s\n' "$ADMIN_PASSWORD"
|
||
printf '首次登录后请立即修改密码。\n'
|
||
else
|
||
printf '管理员密码: 使用现有 .env 中的 ADMIN_PASSWORD\n'
|
||
fi
|
||
printf '停止服务: docker compose down\n'
|
||
printf '查看日志: docker compose logs -f web\n\n'
|
||
|
||
if [[ "$(uname -s)" == "Darwin" ]]; then
|
||
open "http://localhost:${APP_PORT}" >/dev/null 2>&1 || true
|
||
elif command -v xdg-open >/dev/null 2>&1; then
|
||
xdg-open "http://localhost:${APP_PORT}" >/dev/null 2>&1 || true
|
||
fi
|