优化 Docker 镜像打包脚本并修复管理端赛事操作列布局

- 打包脚本默认 tag 改为 latest,支持 --service 单服务构建/导出
- 新增 api/player/admin 三个独立 bat,更新文档与 manifest
- 联赛赛事面板操作列加宽、横向滚动与按钮换行,避免操作按钮被裁切

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-15 16:35:49 +08:00
parent bb868e0ea5
commit be5b4a4921
8 changed files with 263 additions and 101 deletions

View File

@@ -1,11 +1,14 @@
# 构建 api / player / admin 生产镜像并导出为 tar
# 用法(在项目根目录或本目录执行均可):
# .\docs\docker\build-and-export-images.ps1
# .\docs\docker\build-and-export-images.ps1 -Service admin
# .\docs\docker\build-and-export-images.ps1 -Tag v1.2.3
# .\build-and-export-images.ps1 -UseCache
# .\build-and-export-images.ps1 -ExportOnly
# .\docs\docker\build-and-export-images.ps1 -UseCache
# .\docs\docker\build-and-export-images.ps1 -ExportOnly
param(
[ValidateSet("all", "api", "player", "admin")]
[string]$Service = "all",
[string]$Tag = $env:IMAGE_TAG,
[switch]$UseCache,
[switch]$ExportOnly,
@@ -18,14 +21,14 @@ Set-Location $Root
$ComposeFile = "docker-compose.prod.yml"
$EnvFile = ".env.docker"
$Services = @("api", "player", "admin")
$AllServices = @("api", "player", "admin")
function Get-DefaultTag {
try {
$short = (& git rev-parse --short HEAD 2>$null).Trim()
if ($short) { return $short }
} catch {}
return Get-Date -Format "yyyyMMdd-HHmmss"
function Get-DefaultTag { "latest" }
function Get-DefaultOutput {
param([string]$Svc, [string]$ImageTag)
if ($Svc -eq "all") { return "thebet365-images-$ImageTag.tar" }
return "thebet365-$Svc-$ImageTag.tar"
}
function Assert-ImageTag {
@@ -52,19 +55,23 @@ if ([string]::IsNullOrWhiteSpace($Tag)) {
$Tag = Get-DefaultTag
}
Assert-ImageTag $Tag
$BuildServices = if ($Service -eq "all") { $AllServices } else { @($Service) }
$SaveImages = $BuildServices | ForEach-Object { "thebet365-${_}:${Tag}" }
if ([string]::IsNullOrWhiteSpace($Output)) {
$Output = "thebet365-images-$Tag.tar"
$Output = Get-DefaultOutput -Svc $Service -ImageTag $Tag
}
if (-not $ExportOnly) {
Write-Host "==> 构建镜像: $($Services -join ', ') (tag: $Tag)"
Write-Host "==> 构建镜像: $($BuildServices -join ', ') (tag: $Tag)"
$buildArgs = @(
"compose", "-f", $ComposeFile, "--env-file", $EnvFile, "build"
)
if (-not $UseCache) {
$buildArgs += "--no-cache"
}
$buildArgs += $Services
$buildArgs += $BuildServices
$oldImageTag = $env:IMAGE_TAG
try {
$env:IMAGE_TAG = $Tag
@@ -77,12 +84,8 @@ if (-not $ExportOnly) {
$OutputPath = if ([System.IO.Path]::IsPathRooted($Output)) { $Output } else { Join-Path $Root $Output }
Write-Host "==> 导出镜像 -> $OutputPath"
& docker save `
"thebet365-api:${Tag}" `
"thebet365-player:${Tag}" `
"thebet365-admin:${Tag}" `
-o $OutputPath
Write-Host "==> 导出镜像 ($Service) -> $OutputPath"
& docker save @SaveImages -o $OutputPath
if ($LASTEXITCODE -ne 0) { throw "docker save 失败,退出码 $LASTEXITCODE" }
$manifestPath = if ($OutputPath.EndsWith(".tar")) {
@@ -103,34 +106,35 @@ try {
} catch {}
$tarHash = (Get-FileHash -Algorithm SHA256 $OutputPath).Hash.ToLowerInvariant()
$apiImageId = (& docker image inspect "thebet365-api:${Tag}" --format "{{.Id}}").Trim()
$playerImageId = (& docker image inspect "thebet365-player:${Tag}" --format "{{.Id}}").Trim()
$adminImageId = (& docker image inspect "thebet365-admin:${Tag}" --format "{{.Id}}").Trim()
@(
$manifestLines = @(
"tag=$Tag"
"service=$Service"
"built_at=$((Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))"
"git_commit=$gitCommit"
"git_dirty=$gitDirty"
"tar=$([System.IO.Path]::GetFileName($OutputPath))"
"tar_sha256=$tarHash"
"api_image=thebet365-api:${Tag}"
"api_image_id=$apiImageId"
"player_image=thebet365-player:${Tag}"
"player_image_id=$playerImageId"
"admin_image=thebet365-admin:${Tag}"
"admin_image_id=$adminImageId"
) | Set-Content -Encoding UTF8 $manifestPath
)
foreach ($svc in $BuildServices) {
$imageId = (& docker image inspect "thebet365-${svc}:${Tag}" --format "{{.Id}}").Trim()
if ($Service -eq "all") {
$manifestLines += "${svc}_image=thebet365-${svc}:${Tag}"
$manifestLines += "${svc}_image_id=$imageId"
} else {
$manifestLines += "image=thebet365-${svc}:${Tag}"
$manifestLines += "image_id=$imageId"
}
}
$manifestLines | Set-Content -Encoding UTF8 $manifestPath
$sizeMb = [math]::Round((Get-Item $OutputPath).Length / 1MB, 2)
Write-Host "完成: $OutputPath (${sizeMb} MB)"
Write-Host "Manifest: $manifestPath"
$recreate = if ($Service -eq "all") { "api player admin" } else { $Service }
Write-Host @"
:
./scripts/deploy-first.sh --images $([System.IO.Path]::GetFileName($OutputPath)) --tag $Tag
:
./scripts/deploy-update.sh --images $([System.IO.Path]::GetFileName($OutputPath)) --tag $Tag
:
docker load -i $([System.IO.Path]::GetFileName($OutputPath))
docker compose -f docker-compose.prod.yml --env-file .env.docker up -d --force-recreate $recreate
"@