diff --git a/.env.docker.example b/.env.docker.example index 977d457..6656ac6 100644 --- a/.env.docker.example +++ b/.env.docker.example @@ -22,9 +22,28 @@ RUN_MIGRATIONS_ON_START=false # 对外端口(宝塔/Nginx 反代推荐只暴露前端,API 经反向代理访问) BIND_ADDR=127.0.0.1 -PLAYER_PORT=8082 ADMIN_PORT=8081 +# ── 四套 player 镜像 tag 与宿主机端口 ────────────────────────── +# main(暗金主站) +PLAYER_IMAGE_TAG=main +PLAYER_PORT=8082 + +# theme-2(Pinnacle 蓝白) +PLAYER2_IMAGE_TAG=theme-2 +PLAYER2_PORT=8083 + +# theme-3(统一移动端视觉) +PLAYER3_IMAGE_TAG=theme-3 +PLAYER3_PORT=8084 + +# theme-4(海军蓝暗色极简) +PLAYER4_IMAGE_TAG=theme-4 +PLAYER4_PORT=8085 + +# CORS 白名单:四个玩家站域名 + 管理后台(逗号分隔,勿含空格,勿带末尾 /) +# CORS_ORIGINS=https://www.example.com,https://theme2.example.com,https://theme3.example.com,https://theme4.example.com,https://admin.example.com + # 管理端构建时注入:生成邀请注册链接的玩家端公网地址(勿带末尾 /) VITE_PLAYER_URL=https://www.thebet365.net diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 7f71f6a..bcb5714 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -75,7 +75,7 @@ services: - thebet365 player: - image: thebet365-player:${IMAGE_TAG:-latest} + image: thebet365-player:${PLAYER_IMAGE_TAG:-main} build: context: . dockerfile: docker/player/Dockerfile diff --git a/docker-compose.themes.yml b/docker-compose.themes.yml new file mode 100644 index 0000000..c0a6dc6 --- /dev/null +++ b/docker-compose.themes.yml @@ -0,0 +1,59 @@ +# 四套主题扩展 — 与 docker-compose.prod.yml 合并使用: +# docker compose -f docker-compose.prod.yml -f docker-compose.themes.yml --env-file .env.docker up -d +# +# 关联文档:docs/四套主题Docker部署任务.md + +services: + player2: + image: thebet365-player:${PLAYER2_IMAGE_TAG:-theme-2} + container_name: thebet365-player2 + depends_on: + api: + condition: service_healthy + ports: + - '${BIND_ADDR:-127.0.0.1}:${PLAYER2_PORT:-8083}:80' + healthcheck: + test: ['CMD-SHELL', 'wget -q -O /dev/null http://127.0.0.1/ || exit 1'] + interval: 10s + timeout: 5s + retries: 6 + start_period: 10s + restart: unless-stopped + networks: + - thebet365 + + player3: + image: thebet365-player:${PLAYER3_IMAGE_TAG:-theme-3} + container_name: thebet365-player3 + depends_on: + api: + condition: service_healthy + ports: + - '${BIND_ADDR:-127.0.0.1}:${PLAYER3_PORT:-8084}:80' + healthcheck: + test: ['CMD-SHELL', 'wget -q -O /dev/null http://127.0.0.1/ || exit 1'] + interval: 10s + timeout: 5s + retries: 6 + start_period: 10s + restart: unless-stopped + networks: + - thebet365 + + player4: + image: thebet365-player:${PLAYER4_IMAGE_TAG:-theme-4} + container_name: thebet365-player4 + depends_on: + api: + condition: service_healthy + ports: + - '${BIND_ADDR:-127.0.0.1}:${PLAYER4_PORT:-8085}:80' + healthcheck: + test: ['CMD-SHELL', 'wget -q -O /dev/null http://127.0.0.1/ || exit 1'] + interval: 10s + timeout: 5s + retries: 6 + start_period: 10s + restart: unless-stopped + networks: + - thebet365 diff --git a/docs/docker/build-and-export-all-themes.bat b/docs/docker/build-and-export-all-themes.bat new file mode 100644 index 0000000..c744faf --- /dev/null +++ b/docs/docker/build-and-export-all-themes.bat @@ -0,0 +1,204 @@ +@echo off +setlocal EnableDelayedExpansion + +REM ================================================================ +REM build-and-export-all-themes.bat +REM +REM Four-theme player image batch builder. +REM Automatically switches Git branches to build each theme. +REM Usage: +REM docs\docker\build-and-export-all-themes.bat +REM docs\docker\build-and-export-all-themes.bat --use-cache +REM docs\docker\build-and-export-all-themes.bat --export-only +REM docs\docker\build-and-export-all-themes.bat --skip-api-admin +REM +REM Output files (project root, already in .gitignore): +REM thebet365-player-main.tar -> thebet365-player:main +REM thebet365-player-theme-2.tar -> thebet365-player:theme-2 +REM thebet365-player-theme-3.tar -> thebet365-player:theme-3 +REM thebet365-player-theme-4.tar -> thebet365-player:theme-4 +REM thebet365-images-latest.tar -> api:latest + admin:latest +REM +REM Related: docs\si-tao-zhuti-docker-bushu-renwu.md +REM ================================================================ + +cd /d "%~dp0..\.." + +set "USE_CACHE=0" +set "EXPORT_ONLY=0" +set "SKIP_API_ADMIN=0" + +:parse_args +if "%~1"=="" goto args_done +if /i "%~1"=="--use-cache" set "USE_CACHE=1" & shift & goto parse_args +if /i "%~1"=="--export-only" set "EXPORT_ONLY=1" & shift & goto parse_args +if /i "%~1"=="--skip-api-admin" set "SKIP_API_ADMIN=1" & shift & goto parse_args +if /i "%~1"=="-h" goto show_help +if /i "%~1"=="--help" goto show_help +if /i "%~1"=="/?" goto show_help +echo Unknown argument: %~1 +goto show_help + +:show_help +echo. +echo Usage: docs\docker\build-and-export-all-themes.bat [options] +echo. +echo --use-cache Use Docker build cache (default: --no-cache) +echo --export-only Skip build, export existing images only +echo --skip-api-admin Only build 4 player themes, skip api/admin +echo -h, --help Show this help +echo. +echo Output (project root): +echo thebet365-player-main.tar +echo thebet365-player-theme-2.tar +echo thebet365-player-theme-3.tar +echo thebet365-player-theme-4.tar +echo thebet365-images-latest.tar (api + admin, unless --skip-api-admin) +echo. +exit /b 0 + +:args_done + +REM -- Validate docker is available +where docker >nul 2>&1 +if errorlevel 1 ( + echo ERROR: docker not found. Please start Docker Desktop first. + exit /b 1 +) + +REM -- Record current branch so we can restore it +set "ORIGINAL_BRANCH=" +for /f "delims=" %%B in ('git rev-parse --abbrev-ref HEAD 2^>nul') do set "ORIGINAL_BRANCH=%%B" +if not defined ORIGINAL_BRANCH ( + echo ERROR: Cannot determine current Git branch. Run this script from the repo root. + exit /b 1 +) +echo [INFO] Current branch: %ORIGINAL_BRANCH% + +REM -- Warn about dirty working tree +git diff --quiet 2>nul +set "D1=!ERRORLEVEL!" +git diff --cached --quiet 2>nul +set "D2=!ERRORLEVEL!" +if not "!D1!"=="0" echo [WARN] Unstaged changes detected. Consider running 'git stash' first. +if not "!D2!"=="0" echo [WARN] Staged changes detected. Consider running 'git stash' first. + +REM -- Build extra arguments for the base script +set "EXTRA_ARGS=" +if "%USE_CACHE%"=="1" set "EXTRA_ARGS=!EXTRA_ARGS! --use-cache" +if "%EXPORT_ONLY%"=="1" set "EXTRA_ARGS=!EXTRA_ARGS! --export-only" + +set "FAILED_THEMES=" +set "SUCCESS_COUNT=0" + +REM ================================================================ +REM Build each player theme: call :build_theme +REM ================================================================ + +call :build_theme main main +call :build_theme theme-2 theme-2 +call :build_theme theme-3 theme-3 +call :build_theme theme-4 theme-4 + +REM -- Restore original branch +echo. +echo [INFO] Restoring original branch: %ORIGINAL_BRANCH% +git checkout %ORIGINAL_BRANCH% >nul 2>&1 +if errorlevel 1 ( + echo [WARN] Could not restore branch %ORIGINAL_BRANCH%. Please run: git checkout %ORIGINAL_BRANCH% +) else ( + echo [INFO] Restored to %ORIGINAL_BRANCH% +) + +REM -- Build api + admin on main branch +if "%SKIP_API_ADMIN%"=="0" ( + echo. + echo [INFO] Building api + admin (tag: latest) on main branch... + git checkout main >nul 2>&1 + call docs\docker\build-and-export-images.bat --tag latest!EXTRA_ARGS! + if errorlevel 1 ( + echo [ERROR] api/admin build failed + set "FAILED_THEMES=!FAILED_THEMES! api/admin" + ) else ( + set /a SUCCESS_COUNT+=1 + ) + echo. + echo [INFO] Restoring original branch: %ORIGINAL_BRANCH% + git checkout %ORIGINAL_BRANCH% >nul 2>&1 +) + +REM ================================================================ +REM Summary +REM ================================================================ +echo. +echo ================================================================ +echo BUILD SUMMARY +echo ================================================================ +echo Succeeded: !SUCCESS_COUNT! task(s) +if defined FAILED_THEMES ( + echo Failed: !FAILED_THEMES! + echo. + echo Tip: Retry failed themes manually: + echo git checkout ^ + echo docs\docker\build-and-export-images.bat --service player --tag ^ + echo ================================================================ + echo. + endlocal + exit /b 1 +) else ( + echo. + echo All done! Output files in project root: + echo thebet365-player-main.tar + echo thebet365-player-theme-2.tar + echo thebet365-player-theme-3.tar + echo thebet365-player-theme-4.tar + if "%SKIP_API_ADMIN%"=="0" ( + echo thebet365-images-latest.tar (api + admin) + ) + echo. + echo Server import commands: + echo docker load -i thebet365-images-latest.tar + echo docker load -i thebet365-player-main.tar + echo docker load -i thebet365-player-theme-2.tar + echo docker load -i thebet365-player-theme-3.tar + echo docker load -i thebet365-player-theme-4.tar + echo. + echo Start (first multi-theme deploy): + echo docker compose -f docker-compose.prod.yml -f docker-compose.themes.yml --env-file .env.docker up -d + echo ================================================================ + echo. +) +endlocal +exit /b 0 + + +REM ================================================================ +REM :build_theme +REM Switch to the given branch, build player image, tag success/fail +REM ================================================================ +:build_theme +set "THEME_BRANCH=%~1" +set "THEME_TAG=%~2" + +echo. +echo ---------------------------------------------------------------- +echo [INFO] Theme: %THEME_BRANCH% (image tag: %THEME_TAG%) +echo ---------------------------------------------------------------- + +git checkout %THEME_BRANCH% >nul 2>&1 +if errorlevel 1 ( + echo [ERROR] Cannot switch to branch %THEME_BRANCH% -- skipping + set "FAILED_THEMES=!FAILED_THEMES! %THEME_BRANCH%" + exit /b 0 +) +echo [INFO] Switched to %THEME_BRANCH% + +call docs\docker\build-and-export-images.bat --service player --tag %THEME_TAG%!EXTRA_ARGS! +if errorlevel 1 ( + echo [ERROR] Player build failed for %THEME_BRANCH% + set "FAILED_THEMES=!FAILED_THEMES! %THEME_BRANCH%" +) else ( + echo [OK] thebet365-player:%THEME_TAG% exported successfully + set /a SUCCESS_COUNT+=1 +) +exit /b 0 diff --git a/docs/docker/build-and-export-images.bat b/docs/docker/build-and-export-images.bat index 2563057..44fea38 100644 --- a/docs/docker/build-and-export-images.bat +++ b/docs/docker/build-and-export-images.bat @@ -8,6 +8,9 @@ REM docs\docker\build-and-export-images.bat --service admin REM docs\docker\build-and-export-images.bat --tag v1.2.3 REM docs\docker\build-and-export-images.bat --use-cache REM docs\docker\build-and-export-images.bat --export-only +REM +REM 四套主题玩家端一键打包(自动切分支,推荐): +REM docs\docker\build-and-export-all-themes.bat cd /d "%~dp0..\.." @@ -78,6 +81,9 @@ echo docs\docker\build-and-export-images.bat --service admin echo docs\docker\build-and-export-admin.bat echo docs\docker\build-and-export-admin.bat --export-only echo. +echo 四套主题玩家端批量打包(自动切分支,推荐): +echo docs\docker\build-and-export-all-themes.bat +echo. exit /b 0 :args_done @@ -228,6 +234,7 @@ if /i "%SERVICE%"=="api" exit /b 0 if /i "%SERVICE%"=="player" exit /b 0 if /i "%SERVICE%"=="admin" exit /b 0 echo ERROR: invalid --service: %SERVICE% (use api, player, admin, or all) +echo TIP: 四套主题一键打包请使用 docs\docker\build-and-export-all-themes.bat exit /b 1 :validate_tag diff --git a/docs/docker/build-and-export-images.ps1 b/docs/docker/build-and-export-images.ps1 index 02653cf..a87be55 100644 --- a/docs/docker/build-and-export-images.ps1 +++ b/docs/docker/build-and-export-images.ps1 @@ -5,6 +5,10 @@ # .\docs\docker\build-and-export-images.ps1 -Tag v1.2.3 # .\docs\docker\build-and-export-images.ps1 -UseCache # .\docs\docker\build-and-export-images.ps1 -ExportOnly +# +# ҶһԶз֧Ƽ +# docs\docker\build-and-export-all-themes.bat + param( [ValidateSet("all", "api", "player", "admin")] @@ -34,20 +38,20 @@ function Get-DefaultOutput { function Assert-ImageTag { param([string]$Value) if ($Value -notmatch '^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$') { - throw "镜像 tag 不合法: $Value" + throw "镜像 tag 不合? $Value" } } if (-not (Test-Path $ComposeFile)) { - throw "未找到 $ComposeFile(当前目录: $Root)" + throw "未找?$ComposeFile(当前目? $Root? } if (-not (Test-Path $EnvFile)) { if (Test-Path ".env.docker.example") { - Write-Warning "未找到 .env.docker,使用 .env.docker.example(生产请复制并修改密钥)" + Write-Warning "未找?.env.docker,使?.env.docker.example(生产请复制并修改密钥)" $EnvFile = ".env.docker.example" } else { - throw "未找到 .env.docker 或 .env.docker.example" + throw "未找?.env.docker ?.env.docker.example" } } diff --git a/docs/docker/build-and-export-player-main.bat b/docs/docker/build-and-export-player-main.bat new file mode 100644 index 0000000..662d4f4 --- /dev/null +++ b/docs/docker/build-and-export-player-main.bat @@ -0,0 +1,30 @@ +@echo off +REM Build and export main player theme only. +REM Automatically switches to 'main' branch, builds, and restores original branch. +REM Usage: docs\docker\build-and-export-player-main.bat [options] + +cd /d "%~dp0..\.." +set "BRANCH=main" +set "TAG=main" + +set "ORIGINAL_BRANCH=" +for /f "delims=" %%B in ('git rev-parse --abbrev-ref HEAD 2^>nul') do set "ORIGINAL_BRANCH=%%B" +if not defined ORIGINAL_BRANCH ( + echo ERROR: Cannot determine current Git branch. + exit /b 1 +) + +echo [INFO] Switching to branch %BRANCH%... +git checkout %BRANCH% >nul 2>&1 +if errorlevel 1 ( + echo [ERROR] Cannot switch to branch %BRANCH% + exit /b 1 +) + +call docs\docker\build-and-export-images.bat --service player --tag %TAG% %* +set "BUILD_STATUS=%ERRORLEVEL%" + +echo [INFO] Restoring original branch: %ORIGINAL_BRANCH% +git checkout %ORIGINAL_BRANCH% >nul 2>&1 + +exit /b %BUILD_STATUS% diff --git a/docs/docker/build-and-export-player-theme-2.bat b/docs/docker/build-and-export-player-theme-2.bat new file mode 100644 index 0000000..acfa6fc --- /dev/null +++ b/docs/docker/build-and-export-player-theme-2.bat @@ -0,0 +1,30 @@ +@echo off +REM Build and export theme-2 player theme only. +REM Automatically switches to 'theme-2' branch, builds, and restores original branch. +REM Usage: docs\docker\build-and-export-player-theme-2.bat [options] + +cd /d "%~dp0..\.." +set "BRANCH=theme-2" +set "TAG=theme-2" + +set "ORIGINAL_BRANCH=" +for /f "delims=" %%B in ('git rev-parse --abbrev-ref HEAD 2^>nul') do set "ORIGINAL_BRANCH=%%B" +if not defined ORIGINAL_BRANCH ( + echo ERROR: Cannot determine current Git branch. + exit /b 1 +) + +echo [INFO] Switching to branch %BRANCH%... +git checkout %BRANCH% >nul 2>&1 +if errorlevel 1 ( + echo [ERROR] Cannot switch to branch %BRANCH% + exit /b 1 +) + +call docs\docker\build-and-export-images.bat --service player --tag %TAG% %* +set "BUILD_STATUS=%ERRORLEVEL%" + +echo [INFO] Restoring original branch: %ORIGINAL_BRANCH% +git checkout %ORIGINAL_BRANCH% >nul 2>&1 + +exit /b %BUILD_STATUS% diff --git a/docs/docker/build-and-export-player-theme-3.bat b/docs/docker/build-and-export-player-theme-3.bat new file mode 100644 index 0000000..b17d4b2 --- /dev/null +++ b/docs/docker/build-and-export-player-theme-3.bat @@ -0,0 +1,30 @@ +@echo off +REM Build and export theme-3 player theme only. +REM Automatically switches to 'theme-3' branch, builds, and restores original branch. +REM Usage: docs\docker\build-and-export-player-theme-3.bat [options] + +cd /d "%~dp0..\.." +set "BRANCH=theme-3" +set "TAG=theme-3" + +set "ORIGINAL_BRANCH=" +for /f "delims=" %%B in ('git rev-parse --abbrev-ref HEAD 2^>nul') do set "ORIGINAL_BRANCH=%%B" +if not defined ORIGINAL_BRANCH ( + echo ERROR: Cannot determine current Git branch. + exit /b 1 +) + +echo [INFO] Switching to branch %BRANCH%... +git checkout %BRANCH% >nul 2>&1 +if errorlevel 1 ( + echo [ERROR] Cannot switch to branch %BRANCH% + exit /b 1 +) + +call docs\docker\build-and-export-images.bat --service player --tag %TAG% %* +set "BUILD_STATUS=%ERRORLEVEL%" + +echo [INFO] Restoring original branch: %ORIGINAL_BRANCH% +git checkout %ORIGINAL_BRANCH% >nul 2>&1 + +exit /b %BUILD_STATUS% diff --git a/docs/docker/build-and-export-player-theme-4.bat b/docs/docker/build-and-export-player-theme-4.bat new file mode 100644 index 0000000..2e20b6d --- /dev/null +++ b/docs/docker/build-and-export-player-theme-4.bat @@ -0,0 +1,30 @@ +@echo off +REM Build and export theme-4 player theme only. +REM Automatically switches to 'theme-4' branch, builds, and restores original branch. +REM Usage: docs\docker\build-and-export-player-theme-4.bat [options] + +cd /d "%~dp0..\.." +set "BRANCH=theme-4" +set "TAG=theme-4" + +set "ORIGINAL_BRANCH=" +for /f "delims=" %%B in ('git rev-parse --abbrev-ref HEAD 2^>nul') do set "ORIGINAL_BRANCH=%%B" +if not defined ORIGINAL_BRANCH ( + echo ERROR: Cannot determine current Git branch. + exit /b 1 +) + +echo [INFO] Switching to branch %BRANCH%... +git checkout %BRANCH% >nul 2>&1 +if errorlevel 1 ( + echo [ERROR] Cannot switch to branch %BRANCH% + exit /b 1 +) + +call docs\docker\build-and-export-images.bat --service player --tag %TAG% %* +set "BUILD_STATUS=%ERRORLEVEL%" + +echo [INFO] Restoring original branch: %ORIGINAL_BRANCH% +git checkout %ORIGINAL_BRANCH% >nul 2>&1 + +exit /b %BUILD_STATUS% diff --git a/docs/docker/镜像构建与导出.md b/docs/docker/镜像构建与导出.md index 3717c7b..6c9a37b 100644 --- a/docs/docker/镜像构建与导出.md +++ b/docs/docker/镜像构建与导出.md @@ -14,8 +14,13 @@ |------|----------| | `docs/docker/build-and-export-images.bat` | Windows(CMD,构建全部) | | `docs/docker/build-and-export-api.bat` | Windows(仅 api,可双击) | -| `docs/docker/build-and-export-player.bat` | Windows(仅 player,可双击) | +| `docs/docker/build-and-export-player.bat` | Windows(仅单分支 player,可双击) | +| `docs/docker/build-and-export-player-main.bat` | Windows(仅主站/暗金主题,自动切分支) | +| `docs/docker/build-and-export-player-theme-2.bat` | Windows(仅 theme-2 蓝白主题,自动切分支) | +| `docs/docker/build-and-export-player-theme-3.bat` | Windows(仅 theme-3 移动主题,自动切分支) | +| `docs/docker/build-and-export-player-theme-4.bat` | Windows(仅 theme-4 海军蓝极简,自动切分支) | | `docs/docker/build-and-export-admin.bat` | Windows(仅 admin,可双击) | +| `docs/docker/build-and-export-all-themes.bat` | Windows(**四套主题 player 一键打包**,自动切分支) | | `docs/docker/build-and-export-images.ps1` | Windows(PowerShell) | | `docs/docker/build-and-export-images.sh` | Linux / macOS / Git Bash | @@ -118,6 +123,65 @@ docs\docker\build-and-export-images.bat --export-only --- +## 三、四套主题玩家端打包 + +> 关联文档:[四套主题Docker部署任务.md](../四套主题Docker部署任务.md)「阶段 C」 + +### 一键打包(推荐) + +脚本会自动:切到各主题分支 → 构建 player 镜像 → 导出 tar → 切回原分支 → 构建 api/admin。 + +```bat +cd C:\path\to\thebet365 +docs\docker\build-and-export-all-themes.bat +``` + +可选参数: + +| 参数 | 说明 | +|------|------| +| `--use-cache` | 使用 Docker 层缓存,加快重复构建速度 | +| `--export-only` | 跳过构建,仅导出本地已有镜像 | +| `--skip-api-admin` | 只打四套 player,跳过 api/admin | + +### 产物 + +| tar 文件 | 加载后镜像名 | +|----------|----------------| +| `thebet365-player-main.tar` | `thebet365-player:main` | +| `thebet365-player-theme-2.tar` | `thebet365-player:theme-2` | +| `thebet365-player-theme-3.tar` | `thebet365-player:theme-3` | +| `thebet365-player-theme-4.tar` | `thebet365-player:theme-4` | +| `thebet365-images-latest.tar` | `thebet365-api:latest` + `thebet365-admin:latest` | + +### 分支要求 + +- 执行前确保 `main`、`theme-2`、`theme-3`、`theme-4` 四个分支在本地均已拉取 +- 工作区若有未提交变更,脚本会给出 WARN;建议先 `git stash` 后再运行 +- 若某一分支切换失败,该分支会被跳过并标记失败,其余分支仍继续构建 + +### 手动逐一打包(有明确失败时) + +```bat +git checkout main +docs\docker\build-and-export-images.bat --service player --tag main + +git checkout theme-2 +docs\docker\build-and-export-images.bat --service player --tag theme-2 + +git checkout theme-3 +docs\docker\build-and-export-images.bat --service player --tag theme-3 + +git checkout theme-4 +docs\docker\build-and-export-images.bat --service player --tag theme-4 + +REM 最后打 api + admin +git checkout main +docs\docker\build-and-export-images.bat --tag latest +``` + +--- + ## 四、构建产物 | 镜像名 | 说明 | diff --git a/docs/四套主题Docker部署任务.md b/docs/四套主题Docker部署任务.md index 29bc27b..d0f0ffa 100644 --- a/docs/四套主题Docker部署任务.md +++ b/docs/四套主题Docker部署任务.md @@ -37,11 +37,11 @@ ### 阶段 A — 仓库改动(一次性) -- [ ] **A1** 新增 `docker-compose.themes.yml`(player2 / player3 / player4 服务定义) -- [ ] **A2** 更新 `.env.docker.example`(`PLAYER2_*` ~ `PLAYER4_*`、`CORS_ORIGINS` 示例) -- [ ] **A3** 更新 `docker-compose.prod.yml` 中 `player` 使用 `PLAYER_IMAGE_TAG`(与 `IMAGE_TAG` 解耦,见下文片段) -- [ ] **A4**(可选)在 `docs/Docker部署指南.md` 增加「多主题」小节链接到本文 -- [ ] **A5**(可选)在 `AGENTS.md` 文档索引增加本文链接 +- [x] **A1** 新增 `docker-compose.themes.yml`(player2 / player3 / player4 服务定义) +- [x] **A2** 更新 `.env.docker.example`(`PLAYER2_*` ~ `PLAYER4_*`、`CORS_ORIGINS` 示例) +- [x] **A3** 更新 `docker-compose.prod.yml` 中 `player` 使用 `PLAYER_IMAGE_TAG`(与 `IMAGE_TAG` 解耦,见下文片段) +- [x] **A4**(可选)在 `docs/Docker部署指南.md` 增加「多主题」小节链接到本文 +- [x] **A5**(可选)在 `AGENTS.md` 文档索引增加本文链接 ### 阶段 B — 各主题分支同步 main 功能(发版前每个 theme 分支各做一遍)