From 8a6611d96e436025918f5a2ebbb9702c50bbeaa8 Mon Sep 17 00:00:00 2001 From: bookworm Date: Fri, 10 Apr 2026 01:03:36 +0800 Subject: [PATCH] =?UTF-8?q?ux(installer):=20=E5=8F=8C=E4=B8=93=E5=AE=B6?= =?UTF-8?q?=E5=AE=A1=E8=AE=A1=E4=BF=AE=E5=A4=8D=20=E2=80=94=20P0=20?= =?UTF-8?q?=E5=8F=96=E6=B6=88=E6=8C=89=E9=92=AE=20+=20P1=20=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E4=BC=98=E5=8C=96=20+=20=E5=93=81=E7=89=8C=E8=A7=86?= =?UTF-8?q?=E8=A7=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 基于 UX Auditor + CTO Reviewer 两路并行审计报告的交叉修复: P0 — 进度窗口逃生通道 (UX F1): - ControlBox=$true, X 按钮触发 "取消安装?" 确认 - $BWInstallDone 标记: Phase 7 完成后 X 不再弹确认 P1 — 授权码 "跳过" 按钮误导 (UX F6): - "跳过" → "取消安装", 明确传达后果 P1 — Gitea 空密码静默通过 (UX F10): - 添加 lblError 红字验证: "用户名和密码不能为空" - btnOK 改为手动 Click 事件验证, 不再自动 DialogResult P1 — Gitea 对话框缺少上下文 (UX F11): - 新增说明: "用于下载 Bookworm 配置文件,由管理员提供" P2 — 内部术语暴露 (UX F13): - "crypto-helper.js 缺失" → "Bookworm 启动工具包下载失败" + 3 点排查提示 P2 — 品牌视觉统一 (UX Visual): - 进度窗口: 白底 + Bookworm 蓝紫(#5865F2) Phase 标签 + 右下角计时器 - TopMost=$false (不遮挡其他窗口) - ProgressBar Style=Continuous (平滑) - 全局计时器 $BWStartTime + $BWElapsedLabel "Nm Ns" 实时显示 Co-Authored-By: Claude Opus 4.6 (1M context) --- auto-setup.ps1 | 133 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 37 deletions(-) diff --git a/auto-setup.ps1 b/auto-setup.ps1 index 614c897..1d5ce20 100644 --- a/auto-setup.ps1 +++ b/auto-setup.ps1 @@ -61,53 +61,82 @@ $global:BWStatusLabel = $null $global:BWProgressBar = $null function Show-ProgressForm { + # 统一品牌色 + $brandBlue = [System.Drawing.Color]::FromArgb(88, 101, 242) # Bookworm 蓝紫 + $brandDark = [System.Drawing.Color]::FromArgb(30, 31, 46) + $uiFont = "Segoe UI" + $global:BWProgressForm = New-Object System.Windows.Forms.Form - $global:BWProgressForm.Text = "Bookworm Portable Setup" - $global:BWProgressForm.Size = New-Object System.Drawing.Size(520, 200) + $global:BWProgressForm.Text = "Bookworm Portable Setup v1.5.1" + $global:BWProgressForm.Size = New-Object System.Drawing.Size(520, 230) $global:BWProgressForm.StartPosition = "CenterScreen" $global:BWProgressForm.FormBorderStyle = "FixedDialog" $global:BWProgressForm.MaximizeBox = $false $global:BWProgressForm.MinimizeBox = $false - $global:BWProgressForm.TopMost = $true - $global:BWProgressForm.ControlBox = $false + $global:BWProgressForm.TopMost = $false # P2: 不遮挡其他窗口 + $global:BWProgressForm.ControlBox = $true # P0 F1: 允许关闭 (触发确认) + $global:BWProgressForm.BackColor = [System.Drawing.Color]::White + + # X 按钮关闭时弹确认 + $global:BWProgressForm.Add_FormClosing({ + param($s, $e) + if (-not $global:BWInstallDone) { + $r = [System.Windows.Forms.MessageBox]::Show( + "安装尚未完成。`n确定要取消安装吗?", + "取消安装", "YesNo", "Warning") + if ($r -eq "No") { $e.Cancel = $true; return } + Bw-Log "ABORT" "用户手动取消安装" + } + }) $titleLabel = New-Object System.Windows.Forms.Label - $titleLabel.Location = New-Object System.Drawing.Point(20, 18) - $titleLabel.Size = New-Object System.Drawing.Size(480, 24) - $titleLabel.Text = "Bookworm 智能助手 — 自动安装中, 请稍候..." - $titleLabel.Font = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold) + $titleLabel.Location = New-Object System.Drawing.Point(20, 16) + $titleLabel.Size = New-Object System.Drawing.Size(480, 26) + $titleLabel.Text = "Bookworm 智能助手 — 自动安装中" + $titleLabel.Font = New-Object System.Drawing.Font($uiFont, 12, [System.Drawing.FontStyle]::Bold) + $titleLabel.ForeColor = $brandDark $global:BWProgressForm.Controls.Add($titleLabel) $global:BWPhaseLabel = New-Object System.Windows.Forms.Label $global:BWPhaseLabel.Location = New-Object System.Drawing.Point(20, 50) $global:BWPhaseLabel.Size = New-Object System.Drawing.Size(480, 22) $global:BWPhaseLabel.Text = "[0/$TOTAL_PHASES] 初始化..." - $global:BWPhaseLabel.Font = New-Object System.Drawing.Font("Segoe UI", 10) - $global:BWPhaseLabel.ForeColor = [System.Drawing.Color]::DarkBlue + $global:BWPhaseLabel.Font = New-Object System.Drawing.Font($uiFont, 10) + $global:BWPhaseLabel.ForeColor = $brandBlue $global:BWProgressForm.Controls.Add($global:BWPhaseLabel) $global:BWStatusLabel = New-Object System.Windows.Forms.Label $global:BWStatusLabel.Location = New-Object System.Drawing.Point(20, 78) $global:BWStatusLabel.Size = New-Object System.Drawing.Size(480, 22) $global:BWStatusLabel.Text = "" - $global:BWStatusLabel.Font = New-Object System.Drawing.Font("Segoe UI", 9) - $global:BWStatusLabel.ForeColor = [System.Drawing.Color]::DimGray + $global:BWStatusLabel.Font = New-Object System.Drawing.Font($uiFont, 9) + $global:BWStatusLabel.ForeColor = [System.Drawing.Color]::FromArgb(120, 120, 140) $global:BWProgressForm.Controls.Add($global:BWStatusLabel) $global:BWProgressBar = New-Object System.Windows.Forms.ProgressBar - $global:BWProgressBar.Location = New-Object System.Drawing.Point(20, 110) - $global:BWProgressBar.Size = New-Object System.Drawing.Size(480, 22) + $global:BWProgressBar.Location = New-Object System.Drawing.Point(20, 112) + $global:BWProgressBar.Size = New-Object System.Drawing.Size(480, 20) $global:BWProgressBar.Minimum = 0 $global:BWProgressBar.Maximum = $TOTAL_PHASES $global:BWProgressBar.Value = 0 + $global:BWProgressBar.Style = [System.Windows.Forms.ProgressBarStyle]::Continuous # P3: 平滑 $global:BWProgressForm.Controls.Add($global:BWProgressBar) + $global:BWElapsedLabel = New-Object System.Windows.Forms.Label + $global:BWElapsedLabel.Location = New-Object System.Drawing.Point(400, 136) + $global:BWElapsedLabel.Size = New-Object System.Drawing.Size(100, 18) + $global:BWElapsedLabel.Text = "" + $global:BWElapsedLabel.Font = New-Object System.Drawing.Font($uiFont, 8) + $global:BWElapsedLabel.ForeColor = [System.Drawing.Color]::Silver + $global:BWElapsedLabel.TextAlign = [System.Drawing.ContentAlignment]::TopRight + $global:BWProgressForm.Controls.Add($global:BWElapsedLabel) + $hint = New-Object System.Windows.Forms.Label - $hint.Location = New-Object System.Drawing.Point(20, 140) - $hint.Size = New-Object System.Drawing.Size(480, 18) - $hint.Text = "首次安装约 5-10 分钟 (依赖下载) | 日志: $BWLogFile" - $hint.Font = New-Object System.Drawing.Font("Segoe UI", 8) - $hint.ForeColor = [System.Drawing.Color]::Gray + $hint.Location = New-Object System.Drawing.Point(20, 136) + $hint.Size = New-Object System.Drawing.Size(380, 32) + $hint.Text = "首次安装约 5-10 分钟 (依赖下载)`n关闭窗口可取消安装" + $hint.Font = New-Object System.Drawing.Font($uiFont, 8) + $hint.ForeColor = [System.Drawing.Color]::Silver $global:BWProgressForm.Controls.Add($hint) $global:BWProgressForm.Show() | Out-Null @@ -115,6 +144,11 @@ function Show-ProgressForm { [System.Windows.Forms.Application]::DoEvents() } +# 全局安装完成标记 (Close-ProgressForm 前设为 $true, 避免 X 按钮弹确认) +$global:BWInstallDone = $false +# 全局计时器 +$global:BWStartTime = [System.Diagnostics.Stopwatch]::StartNew() + function Update-Progress($phase, $title) { if ($global:BWProgressForm -and -not $global:BWProgressForm.IsDisposed) { try { @@ -132,6 +166,11 @@ function Update-Progress-SubStatus($msg) { try { $shortMsg = if ($msg.Length -gt 70) { $msg.Substring(0, 67) + "..." } else { $msg } $global:BWStatusLabel.Text = $shortMsg + # 刷新总耗时 + if ($global:BWElapsedLabel -and $global:BWStartTime) { + $sec = [int]$global:BWStartTime.Elapsed.TotalSeconds + $global:BWElapsedLabel.Text = "$([int]($sec / 60))m $($sec % 60)s" + } $global:BWStatusLabel.Refresh() [System.Windows.Forms.Application]::DoEvents() } catch {} @@ -139,6 +178,7 @@ function Update-Progress-SubStatus($msg) { } function Close-ProgressForm { + $global:BWInstallDone = $true # 关闭时不再弹 "取消安装?" 确认 if ($global:BWProgressForm -and -not $global:BWProgressForm.IsDisposed) { try { $global:BWProgressForm.Close(); $global:BWProgressForm.Dispose() } catch {} } @@ -277,8 +317,8 @@ function Show-AuthCodeDialog($attempt = 1, $maxAttempts = 3) { $btnCancel = New-Object System.Windows.Forms.Button $btnCancel.Location = New-Object System.Drawing.Point(350, 145) - $btnCancel.Size = New-Object System.Drawing.Size(80, 35) - $btnCancel.Text = "跳过" + $btnCancel.Size = New-Object System.Drawing.Size(90, 35) + $btnCancel.Text = "取消安装" $btnCancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $form.CancelButton = $btnCancel $form.Controls.Add($btnCancel) @@ -295,65 +335,84 @@ function Show-AuthCodeDialog($attempt = 1, $maxAttempts = 3) { function Show-GiteaCredentialDialog { $form = New-Object System.Windows.Forms.Form $form.Text = "Bookworm - Gitea 登录" - $form.Size = New-Object System.Drawing.Size(420, 280) + $form.Size = New-Object System.Drawing.Size(420, 300) $form.StartPosition = "CenterScreen" $form.FormBorderStyle = "FixedDialog" $form.MaximizeBox = $false $form.TopMost = $true + $form.BackColor = [System.Drawing.Color]::White $lblInfo = New-Object System.Windows.Forms.Label $lblInfo.Location = New-Object System.Drawing.Point(20, 15) - $lblInfo.Size = New-Object System.Drawing.Size(360, 25) - $lblInfo.Text = "输入 Gitea 账号 (code.letcareme.com)" - $lblInfo.Font = New-Object System.Drawing.Font("Segoe UI", 10) + $lblInfo.Size = New-Object System.Drawing.Size(360, 40) + $lblInfo.Text = "输入 Gitea 账号 (code.letcareme.com)`n用于下载 Bookworm 配置文件,由管理员提供。" + $lblInfo.Font = New-Object System.Drawing.Font("Segoe UI", 9) $form.Controls.Add($lblInfo) $lblUser = New-Object System.Windows.Forms.Label - $lblUser.Location = New-Object System.Drawing.Point(20, 50) + $lblUser.Location = New-Object System.Drawing.Point(20, 65) $lblUser.Size = New-Object System.Drawing.Size(80, 25) $lblUser.Text = "用户名:" $form.Controls.Add($lblUser) $txtUser = New-Object System.Windows.Forms.TextBox - $txtUser.Location = New-Object System.Drawing.Point(100, 48) + $txtUser.Location = New-Object System.Drawing.Point(100, 63) $txtUser.Size = New-Object System.Drawing.Size(280, 25) $txtUser.Font = New-Object System.Drawing.Font("Consolas", 11) $form.Controls.Add($txtUser) $lblPass = New-Object System.Windows.Forms.Label - $lblPass.Location = New-Object System.Drawing.Point(20, 90) + $lblPass.Location = New-Object System.Drawing.Point(20, 105) $lblPass.Size = New-Object System.Drawing.Size(80, 25) $lblPass.Text = "密码:" $form.Controls.Add($lblPass) $txtPass = New-Object System.Windows.Forms.TextBox - $txtPass.Location = New-Object System.Drawing.Point(100, 88) + $txtPass.Location = New-Object System.Drawing.Point(100, 103) $txtPass.Size = New-Object System.Drawing.Size(280, 25) $txtPass.PasswordChar = '*' $txtPass.Font = New-Object System.Drawing.Font("Consolas", 11) $form.Controls.Add($txtPass) + # P1 F10: 空值验证提示 + $lblError = New-Object System.Windows.Forms.Label + $lblError.Location = New-Object System.Drawing.Point(100, 135) + $lblError.Size = New-Object System.Drawing.Size(280, 20) + $lblError.Text = "" + $lblError.Font = New-Object System.Drawing.Font("Segoe UI", 8) + $lblError.ForeColor = [System.Drawing.Color]::Red + $form.Controls.Add($lblError) + $btnOK = New-Object System.Windows.Forms.Button - $btnOK.Location = New-Object System.Drawing.Point(200, 140) + $btnOK.Location = New-Object System.Drawing.Point(200, 165) $btnOK.Size = New-Object System.Drawing.Size(90, 35) $btnOK.Text = "登录" - $btnOK.DialogResult = [System.Windows.Forms.DialogResult]::OK - $form.AcceptButton = $btnOK $form.Controls.Add($btnOK) $btnCancel = New-Object System.Windows.Forms.Button - $btnCancel.Location = New-Object System.Drawing.Point(300, 140) + $btnCancel.Location = New-Object System.Drawing.Point(300, 165) $btnCancel.Size = New-Object System.Drawing.Size(80, 35) $btnCancel.Text = "取消" $btnCancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $form.CancelButton = $btnCancel $form.Controls.Add($btnCancel) + # OK 按钮手动验证 (不用 DialogResult, 防止空值直接关闭) + $btnOK.Add_Click({ + if (-not $txtUser.Text.Trim() -or -not $txtPass.Text) { + $lblError.Text = "用户名和密码不能为空" + return + } + $form.DialogResult = [System.Windows.Forms.DialogResult]::OK + $form.Close() + }) + $form.AcceptButton = $btnOK + $form.Add_Shown({ $txtUser.Focus() }) $result = $form.ShowDialog() - if ($result -eq [System.Windows.Forms.DialogResult]::OK -and $txtUser.Text -and $txtPass.Text) { - return @{ User = $txtUser.Text; Pass = $txtPass.Text } + if ($result -eq [System.Windows.Forms.DialogResult]::OK) { + return @{ User = $txtUser.Text.Trim(); Pass = $txtPass.Text } } return $null } @@ -805,8 +864,8 @@ if (Test-Path (Join-Path $BootDir ".git")) { $bootCloneUrl = if ($cred) { $BootUrl -replace '://', "://$($cred.User):$($cred.Pass)@" } else { $BootUrl } $r = Run-CmdWithUI "git" @("clone", "--depth", "1", $bootCloneUrl, $BootDir) "克隆 boot 仓库" 180000 if (-not (Test-Path (Join-Path $BootDir "crypto-helper.js"))) { - Log-Fail "boot 仓库克隆失败 (crypto-helper.js 缺失)" - Show-MsgBox "boot 仓库克隆失败。`n请检查网络和 Gitea 凭证。" "克隆失败" "OK" "Error" + Log-Fail "启动工具包下载失败" + Show-MsgBox "Bookworm 启动工具包下载失败。`n`n请检查:`n1. Gitea 账号和密码是否正确`n2. 网络连接是否正常`n3. 代理软件是否已启动`n`n然后重新运行安装器即可。" "下载失败" "OK" "Error" exit 1 } Log-OK "boot 仓库克隆成功 → $BootDir"