Files
subtrack/scripts/shots.ps1
T
chun_qiu f047662129
build / build-and-test (push) Failing after 1m24s
首次推送
2026-10-18 19:44:38 +08:00

128 lines
5.5 KiB
PowerShell

# 用无头 Chrome 截图,做视觉验收
# 用法: powershell -NoProfile -ExecutionPolicy Bypass -File scripts\shots.ps1 -Base http://127.0.0.1:18080
param(
[string]$Base = 'http://127.0.0.1:18080',
[string]$User = 'admin',
[string]$Pass = 'daili123',
[string]$OutDir = ''
)
$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
if (-not $OutDir) { $OutDir = Join-Path $root 'shots' }
New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
$chrome = 'C:\Program Files\Google\Chrome\Application\chrome.exe'
if (-not (Test-Path $chrome)) { throw '找不到 Chrome' }
# 1) 登录拿会话 cookie
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
Invoke-WebRequest -Uri "$Base/login" -WebSession $session -UseBasicParsing | Out-Null
Invoke-WebRequest -Uri "$Base/login" -Method POST -WebSession $session -UseBasicParsing -Body @{
username = $User; password = $Pass; next = '/calendar'
} | Out-Null
$cookie = ($session.Cookies.GetCookies($Base) | Where-Object { $_.Name -eq 'daili_sid' } | Select-Object -First 1)
if (-not $cookie) { throw '登录失败,拿不到会话' }
$token = $cookie.Value
# 2) 拿一个订阅 ID 用于「追加面板」截图
$custID = ''
$subID = ''
$r = Invoke-WebRequest -Uri "$Base/customers?q=7001" -WebSession $session -UseBasicParsing
if ($r.Content -match '/customers/(\d+)') {
$custID = $matches[1]
$r2 = Invoke-WebRequest -Uri "$Base/customers/$custID" -WebSession $session -UseBasicParsing
if ($r2.Content -match 'id="sub-(\d+)"') { $subID = $matches[1] }
}
# 3) 启动 Chrome
$profile = Join-Path $root ('.chrome-profile-' + (Get-Date).ToString('HHmmss'))
$chromeArgs = @(
'--headless=new', '--disable-gpu', '--hide-scrollbars', '--no-sandbox',
'--no-first-run', '--no-default-browser-check', '--disable-extensions',
'--disable-crash-reporter', '--disable-breakpad',
'--force-device-scale-factor=1', '--remote-debugging-port=9222',
"--user-data-dir=$profile", '--window-size=1440,1000', 'about:blank'
)
$chromeProc = Start-Process -FilePath $chrome -ArgumentList $chromeArgs -PassThru
$targets = $null
for ($i = 0; $i -lt 20; $i++) {
Start-Sleep -Milliseconds 500
try {
$targets = Invoke-RestMethod 'http://127.0.0.1:9222/json'
if ($targets) { break }
} catch { }
}
if (-not $targets) {
Stop-Process -Id $chromeProc.Id -Force -ErrorAction SilentlyContinue
throw 'Chrome 调试端口未就绪'
}
$page = $targets | Where-Object { $_.type -eq 'page' } | Select-Object -First 1
if (-not $page) { throw '拿不到调试目标' }
$script:ws = New-Object System.Net.WebSockets.ClientWebSocket
$script:ws.ConnectAsync([Uri]$page.webSocketDebuggerUrl, [Threading.CancellationToken]::None).Wait()
$script:msgId = 0
function Send-CDP {
param([string]$Method, $Params)
$script:msgId++
$payload = @{ id = $script:msgId; method = $Method; params = $Params } | ConvertTo-Json -Depth 12 -Compress
$bytes = [Text.Encoding]::UTF8.GetBytes($payload)
$seg = New-Object 'System.ArraySegment[byte]' -ArgumentList @(, $bytes)
$script:ws.SendAsync($seg, [Net.WebSockets.WebSocketMessageType]::Text, $true, [Threading.CancellationToken]::None).Wait()
while ($true) {
$ms = New-Object System.IO.MemoryStream
do {
$buf = New-Object byte[] 131072
$segR = New-Object 'System.ArraySegment[byte]' -ArgumentList @(, $buf)
$res = $script:ws.ReceiveAsync($segR, [Threading.CancellationToken]::None).Result
$ms.Write($buf, 0, $res.Count)
} while (-not $res.EndOfMessage)
$text = [Text.Encoding]::UTF8.GetString($ms.ToArray())
$msg = $text | ConvertFrom-Json
if ($msg.id -eq $script:msgId) { return $msg }
}
}
function Shoot {
param([string]$Name, [string]$Path, [int]$Width = 1440, [int]$Height = 1000, [bool]$SetCookie = $true)
Send-CDP 'Emulation.setDeviceMetricsOverride' @{
width = $Width; height = $Height; deviceScaleFactor = 1; mobile = ($Width -lt 600)
} | Out-Null
if ($SetCookie) {
Send-CDP 'Network.setCookie' @{
name = 'daili_sid'; value = $token; domain = '127.0.0.1'; path = '/'; httpOnly = $true
} | Out-Null
}
Send-CDP 'Page.navigate' @{ url = "$Base$Path" } | Out-Null
Start-Sleep -Milliseconds 900
$shot = Send-CDP 'Page.captureScreenshot' @{ format = 'png'; captureBeyondViewport = $false }
$file = Join-Path $OutDir "$Name.png"
[System.IO.File]::WriteAllBytes($file, [Convert]::FromBase64String($shot.result.data))
Write-Host (" shot {0,-16} <- {1}{2}" -f $Name, $Base, $Path) -ForegroundColor DarkGray
}
Send-CDP 'Network.enable' @{} | Out-Null
Send-CDP 'Page.enable' @{} | Out-Null
Shoot 'login' '/login' 1440 900 $false
Shoot 'calendar' '/calendar' 1440 1000
Shoot 'customers' '/customers' 1440 900
if ($custID) { Shoot 'customer-detail' "/customers/$custID" 1440 1100 }
if ($custID -and $subID) {
$today = (Get-Date).ToString('yyyy-MM-dd')
Shoot 'extend-panel' ("/customers/{0}?extend={1}#extend" -f $custID, $subID) 1440 1200
}
Shoot 'subscriptions' '/subscriptions?state=all' 1440 900
Shoot 'packages' '/packages' 1440 800
Shoot 'package-form' '/packages/new' 1200 940
Shoot 'customer-form' '/customers/new' 1000 900
Shoot 'settings' '/settings' 1440 1000
Shoot 'screen' '/screen' 1600 900
Shoot 'calendar-mobile' '/calendar' 390 844
$script:ws.Dispose()
Stop-Process -Id $chromeProc.Id -Force -ErrorAction SilentlyContinue
Write-Host '截图完成' -ForegroundColor Green