激光材料数据平台 1.3.0

公开数据看板、四位 Key 录入面板、管理后台与三级权限、动态字段配置、
PostgreSQL/SQLite 双支持、数据库备份,以及本版新增的成品图上传与预览。

图片相关:
- 录入表单支持相册选图与手机端直接拍照,每条记录最多 6 张
- 浏览器内压缩到最长边 1600 并剥离 EXIF,入库统一为 JPG/PNG
- 二进制直接入库,现有备份自动覆盖图片,部署无需新增卷
- 详情页缩略图宫格与全屏 lightbox,公开看板同样可见

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 22:06:02 +08:00
co-authored by Claude Fable 5
commit edfb216561
49 changed files with 3922 additions and 0 deletions
Executable
+129
View File
@@ -0,0 +1,129 @@
#!/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 Desktophttps://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