- start.ps1: 局域网 IP 自动检测, 部署完成提示默认账户 admin/123456 - start.ps1: 修复 UTF-8 BOM 避免 PowerShell 5.1 解析闪退 - docker-compose: dozzle 容器增加 restart 与 logging 配置 - 新增 reset-docker-network.ps1 网络重置脚本 - README: 顶部增加 Linux/Windows 一键部署命令, Windows 权限说明 Made-with: Cursor
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
#Requires -Version 5.1
|
||||
#Requires -Version 5.1
|
||||
# EasyAI Windows 一键部署脚本
|
||||
# 仅支持 IP 访问(本地/局域网),不含域名与 HTTPS
|
||||
# 一行命令: git clone https://git.51easyai.com/wangbo/easyai; cd easyai; .\start.ps1
|
||||
|
||||
# 设置控制台编码为 UTF-8,确保中文正确显示
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
$OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$script:LogFile = Join-Path (if ($PSScriptRoot) { $PSScriptRoot } else { $env:TEMP }) "start.ps1.log"
|
||||
$script:LogDir = $PSScriptRoot
|
||||
if (-not $script:LogDir) { $script:LogDir = $env:TEMP }
|
||||
$script:LogFile = Join-Path $script:LogDir "start.ps1.log"
|
||||
# 尽早写入启动标记,便于闪退时排查
|
||||
try { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === 脚本加载 ===" | Out-File -FilePath $script:LogFile -Append -Encoding utf8 } catch { }
|
||||
|
||||
@@ -19,7 +25,12 @@ function Write-Log {
|
||||
trap {
|
||||
$errMsg = $_.Exception.Message
|
||||
$errStack = if ($_.ScriptStackTrace) { " | 堆栈: $($_.ScriptStackTrace)" } else { "" }
|
||||
Write-Log "错误退出: $errMsg$errStack"
|
||||
try {
|
||||
$logPath = $script:LogFile
|
||||
if (-not $logPath) { $logPath = Join-Path $env:TEMP "start.ps1.log" }
|
||||
$logLine = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] 错误退出: $errMsg$errStack"
|
||||
Add-Content -Path $logPath -Value $logLine -Encoding UTF8 -ErrorAction SilentlyContinue
|
||||
} catch { }
|
||||
try {
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Red
|
||||
@@ -91,13 +102,29 @@ function Run-DeployQuestions {
|
||||
Write-Step "已选择本地访问"
|
||||
}
|
||||
"2" {
|
||||
Write-Host " 提示: 可在本机运行 ipconfig 查看 IPv4 地址"
|
||||
$lanIp = Read-Host "请输入本机局域网 IP 地址"
|
||||
$lanIp = $lanIp.Trim()
|
||||
if ([string]::IsNullOrWhiteSpace($lanIp)) {
|
||||
Write-Err "IP 不能为空"
|
||||
# 自动获取局域网 IP(排除回环和 APIPA 地址)
|
||||
$detectedIp = $null
|
||||
try {
|
||||
$addrs = Get-NetIPAddress -AddressFamily IPv4 -ErrorAction SilentlyContinue | Where-Object {
|
||||
$_.InterfaceAlias -notlike "*Loopback*" -and
|
||||
$_.IPAddress -notmatch "^127\." -and
|
||||
$_.IPAddress -notmatch "^169\.254\."
|
||||
}
|
||||
$detectedIp = ($addrs | Sort-Object InterfaceIndex | Select-Object -First 1).IPAddress
|
||||
} catch { }
|
||||
if ($detectedIp) {
|
||||
$defaultHint = "回车使用 [$detectedIp]"
|
||||
Write-Host " 检测到局域网 IP: $detectedIp"
|
||||
$inputIp = Read-Host "请输入本机局域网 IP($defaultHint 或手动输入)"
|
||||
$inputIp = $inputIp.Trim()
|
||||
$script:DeployIP = if ([string]::IsNullOrWhiteSpace($inputIp)) { $detectedIp } else { $inputIp }
|
||||
} else {
|
||||
Write-Host " 提示: 未自动检测到局域网 IP,可在本机运行 ipconfig 查看"
|
||||
$lanIp = Read-Host "请输入本机局域网 IP 地址"
|
||||
$lanIp = $lanIp.Trim()
|
||||
if ([string]::IsNullOrWhiteSpace($lanIp)) { Write-Err "IP 不能为空" }
|
||||
$script:DeployIP = $lanIp
|
||||
}
|
||||
$script:DeployIP = $lanIp
|
||||
Write-Warn "请确保防火墙已放行 3001、3002、3003 端口"
|
||||
}
|
||||
default {
|
||||
@@ -152,6 +179,95 @@ function Test-DockerInstalled {
|
||||
}
|
||||
}
|
||||
|
||||
# 检查 Docker 引擎是否已启动并可响应(带超时,避免 docker info 卡住)
|
||||
function Test-DockerRunning {
|
||||
param([int]$TimeoutSeconds = 10)
|
||||
try {
|
||||
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$psi.FileName = "docker"
|
||||
$psi.Arguments = "info"
|
||||
$psi.RedirectStandardOutput = $true
|
||||
$psi.RedirectStandardError = $true
|
||||
$psi.UseShellExecute = $false
|
||||
$psi.CreateNoWindow = $true
|
||||
$p = [System.Diagnostics.Process]::Start($psi)
|
||||
$exited = $p.WaitForExit($TimeoutSeconds * 1000)
|
||||
if (-not $exited) {
|
||||
try { $p.Kill() } catch { }
|
||||
return $false
|
||||
}
|
||||
return ($p.ExitCode -eq 0)
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# 启动 Docker Desktop 并等待就绪
|
||||
function Start-DockerDesktopAndWait {
|
||||
param(
|
||||
[int]$MaxWaitSeconds = 120,
|
||||
[int]$CheckIntervalSeconds = 5
|
||||
)
|
||||
|
||||
Write-Step "Docker 未运行,正在启动 Docker Desktop..."
|
||||
$dockerDesktopPath = "${env:ProgramFiles}\Docker\Docker\Docker Desktop.exe"
|
||||
if (-not (Test-Path $dockerDesktopPath)) {
|
||||
$dockerDesktopPath = "${env:ProgramFiles(x86)}\Docker\Docker\Docker Desktop.exe"
|
||||
}
|
||||
if (-not (Test-Path $dockerDesktopPath)) {
|
||||
Write-Warn "未找到 Docker Desktop 可执行文件"
|
||||
Write-Host "请手动启动 Docker Desktop 后重新运行本脚本。"
|
||||
return $false
|
||||
}
|
||||
|
||||
# 尝试使用 docker desktop start(Docker Desktop 4.38+ 支持)
|
||||
$useCli = $false
|
||||
try {
|
||||
$null = & docker desktop start 2>&1
|
||||
$useCli = $true
|
||||
Write-Step "已通过 docker desktop start 发送启动命令"
|
||||
} catch {
|
||||
# 回退到直接启动进程
|
||||
}
|
||||
|
||||
if (-not $useCli) {
|
||||
Start-Process -FilePath $dockerDesktopPath -WindowStyle Hidden
|
||||
Write-Step "已启动 Docker Desktop 进程"
|
||||
}
|
||||
|
||||
Write-Host "等待 Docker 引擎就绪(最长 $MaxWaitSeconds 秒)..." -ForegroundColor Cyan
|
||||
$elapsed = 0
|
||||
while ($elapsed -lt $MaxWaitSeconds) {
|
||||
Start-Sleep -Seconds $CheckIntervalSeconds
|
||||
$elapsed += $CheckIntervalSeconds
|
||||
Write-Host " 已等待 $elapsed 秒..." -NoNewline
|
||||
if (Test-DockerRunning) {
|
||||
Write-Host " 完成" -ForegroundColor Green
|
||||
Write-Ok "Docker 已就绪"
|
||||
return $true
|
||||
}
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Write-Warn "等待超时,Docker 可能仍在启动中"
|
||||
Write-Host "请稍后手动执行 docker info 确认,或重新运行本脚本。"
|
||||
return $false
|
||||
}
|
||||
|
||||
# 确保 Docker 已安装且运行,若未运行则尝试启动
|
||||
function Ensure-DockerRunning {
|
||||
if (-not (Test-DockerInstalled)) {
|
||||
return $false
|
||||
}
|
||||
if (Test-DockerRunning) {
|
||||
Write-Ok "Docker 引擎已运行"
|
||||
$v = docker --version 2>$null
|
||||
if ($v) { Write-Host " $v" }
|
||||
return $true
|
||||
}
|
||||
return (Start-DockerDesktopAndWait)
|
||||
}
|
||||
|
||||
function Install-DockerDesktop {
|
||||
$isWin = ($env:OS -eq "Windows_NT") -or ($PSVersionTable.PSVersion.Major -ge 6 -and $IsWindows)
|
||||
if (-not $isWin) {
|
||||
@@ -192,8 +308,14 @@ function Test-Docker {
|
||||
|
||||
if (Test-DockerInstalled) {
|
||||
Write-Ok "Docker 已安装"
|
||||
$v = docker --version 2>$null
|
||||
if ($v) { Write-Host " $v" }
|
||||
# 检查并确保 Docker 引擎运行
|
||||
if (-not (Ensure-DockerRunning)) {
|
||||
Write-Warn "Docker 未能自动启动"
|
||||
Write-Host ""
|
||||
Write-Host "请手动启动 Docker Desktop,确认其完全启动后再重新运行本脚本。"
|
||||
Wait-ForExit
|
||||
exit 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -258,11 +380,17 @@ function Main {
|
||||
if ((Test-Path ".env") -and -not $env:DEPLOY_FORCE_RECONFIG -and -not $env:DEPLOY_IP) {
|
||||
Write-Step "📁 检测到已有 .env 配置"
|
||||
$reconfigure = Read-Host "是否重新配置访问方式?[y/N]"
|
||||
if ($reconfigure -notmatch '^[yY]') {
|
||||
$trimmed = $reconfigure.Trim().ToLower()
|
||||
$startsWithY = ($trimmed.Length -gt 0) -and ($trimmed[0] -eq [char]121)
|
||||
if (-not $startsWithY) {
|
||||
Write-Step "使用现有配置继续..."
|
||||
# 从现有 .env 读取 IP(用于最后输出)
|
||||
$line = Get-Content ".env" | Where-Object { $_ -match '^NUXT_PUBLIC_BASE_APIURL=http://([^:]+):3001' } | Select-Object -First 1
|
||||
if ($line -match 'http://([^:]+):3001') { $script:DeployIP = $Matches[1] }
|
||||
$line = Get-Content ".env" -Encoding UTF8 | Where-Object { $_ -like "NUXT_PUBLIC_BASE_APIURL=*" } | Select-Object -First 1
|
||||
if ($line -and $line -like "*:3001*") {
|
||||
$prefix = ".*http://"
|
||||
$suffix = ":3001.*"
|
||||
$script:DeployIP = ($line -replace $prefix, "" -replace $suffix, "").Trim()
|
||||
}
|
||||
$script:DeployModeSkip = $true
|
||||
}
|
||||
}
|
||||
@@ -293,6 +421,8 @@ function Main {
|
||||
Write-Host "================================"
|
||||
$accessIp = if ($script:DeployIP) { $script:DeployIP } else { "127.0.0.1" }
|
||||
Write-Host "访问地址: http://${accessIp}:3010"
|
||||
Write-Host "默认登录账户: admin"
|
||||
Write-Host "默认登录密码: 123456"
|
||||
Write-Host ""
|
||||
Wait-ForExit
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user