param( [string]$ProjectRoot = "D:\AI Code\3danzhuang\furniture-3d-system", [string]$OutputRoot = "D:\AI Code\3danzhuang" ) $ErrorActionPreference = 'Stop' if (-not (Test-Path -LiteralPath $ProjectRoot)) { throw "项目目录不存在: $ProjectRoot" } function Get-EnvValue { param( [string]$Path, [string]$Key ) if (-not (Test-Path -LiteralPath $Path)) { return $null } $line = Get-Content -LiteralPath $Path | Where-Object { $_ -match "^$([regex]::Escape($Key))=" } | Select-Object -First 1 if (-not $line) { return $null } $value = $line.Substring($line.IndexOf('=') + 1).Trim() if ($value.Length -ge 2) { if (($value.StartsWith('"') -and $value.EndsWith('"')) -or ($value.StartsWith("'") -and $value.EndsWith("'"))) { $value = $value.Substring(1, $value.Length - 2) } } return $value } $localEnvPath = Join-Path $ProjectRoot '.env' $jwtSecret = Get-EnvValue -Path $localEnvPath -Key 'JWT_SECRET' if ([string]::IsNullOrWhiteSpace($jwtSecret) -or $jwtSecret.Length -lt 32) { $jwtSecret = 'wyj-test-jwt-secret-20260410-solidjoin-3d' } $nextAuthSecret = Get-EnvValue -Path $localEnvPath -Key 'NEXTAUTH_SECRET' if ([string]::IsNullOrWhiteSpace($nextAuthSecret)) { $nextAuthSecret = $jwtSecret } $timestamp = Get-Date -Format 'yyyyMMdd-HHmmss' $archiveName = "deploy-furniture-wyj-test-$timestamp.tar.gz" $scriptName = "deploy-furniture-wyj-test-$timestamp.sh" $archivePath = Join-Path $OutputRoot $archiveName $scriptPath = Join-Path $OutputRoot $scriptName $includePaths = @( 'furniture-3d-system/package.json' 'furniture-3d-system/package-lock.json' 'furniture-3d-system/next.config.js' 'furniture-3d-system/postcss.config.mjs' 'furniture-3d-system/tsconfig.json' 'furniture-3d-system/next-env.d.ts' 'furniture-3d-system/prisma.config.ts' 'furniture-3d-system/src' 'furniture-3d-system/public' 'furniture-3d-system/prisma' 'furniture-3d-system/scripts' 'furniture-3d-system/lib' ) Push-Location (Split-Path $ProjectRoot -Parent) try { if (Test-Path -LiteralPath $archivePath) { Remove-Item -LiteralPath $archivePath -Force } tar -czf $archivePath @includePaths } finally { Pop-Location } $shellScript = @' set -e BASE=/root/codex-workspaces/furniture-3d-system-wyj-test APP=$BASE/furniture-3d-system ARCHIVE=/root/codex-workspaces/__ARCHIVE_NAME__ DB_NAME=furniture3d_wyj_test DB_USER=furniture3d_wyj_test DB_PASS='F3dWyjTest_3200_20260407' APP_PORT=3200 BUCKET=furniture-3d-models-wyj-test MINIO_USER=furniture3dtest MINIO_PASS='F3dMinio_39100_20260331' S3_ENDPOINT='http://127.0.0.1:39100' S3_PUBLIC_ENDPOINT='http://192.168.42.134:39100' mkdir -p $BASE rm -rf $APP cd $BASE tar -xzf $ARCHIVE sudo -u postgres psql -d postgres </dev/null && mc mb -p local/$BUCKET >/dev/null 2>&1 || true && mc anonymous set download local/$BUCKET >/dev/null" cd $APP export PUPPETEER_SKIP_DOWNLOAD=true npm install --no-audit --no-fund PUPPETEER_CACHE_DIR=/root/.cache/puppeteer npx puppeteer browsers install chrome-headless-shell@stable sudo -u postgres psql -d $DB_NAME </dev/null 2>&1 || true pm2 start /bin/bash --name furniture-3d-system-wyj-test --cwd $APP -- -lc "set -a; source ./.env; set +a; mkdir -p .next/standalone/.next; rm -rf .next/standalone/.next/static .next/standalone/public; cp -R .next/static .next/standalone/.next/static; cp -R public .next/standalone/public; exec env PORT=$APP_PORT HOSTNAME=0.0.0.0 node .next/standalone/server.js" pm2 save >/dev/null sleep 5 curl -I -s http://127.0.0.1:$APP_PORT | sed -n '1,12p' ls -1dt /root/codex-workspaces/deploy-furniture-wyj-test-*.tar.gz 2>/dev/null | tail -n +4 | xargs -r rm -f echo '=== DONE ===' pm2 describe furniture-3d-system-wyj-test | sed -n '1,35p' '@ $shellScript = $shellScript.Replace('__ARCHIVE_NAME__', $archiveName) $shellScript = $shellScript.Replace('__JWT_SECRET__', $jwtSecret) $shellScript = $shellScript.Replace('__NEXTAUTH_SECRET__', $nextAuthSecret) [System.IO.File]::WriteAllText($scriptPath, $shellScript, [System.Text.UTF8Encoding]::new($false)) $archive = Get-Item -LiteralPath $archivePath [PSCustomObject]@{ Archive = $archive.FullName ArchiveMB = [math]::Round($archive.Length / 1MB, 2) Script = $scriptPath IncludedPaths = $includePaths -join ', ' }