package wizard import ( "fmt" "strings" "github.com/charmbracelet/lipgloss" ) // View 渲染视图 func (m model) View() string { if m.done { return successView() } if m.quitting { return quitView() } if m.err != nil { return errorView(m.err) } var page string switch m.currentPage { case PageAgreement: page = m.agreementView() case PageData: page = m.dataView() case PagePublicNetwork: page = m.publicNetworkView() case PageInternalNetwork: page = m.internalNetworkView() case PageDNS: page = m.dnsView() case PageSummary: page = m.summaryView() } content := strings.Builder{} content.WriteString(page) content.WriteString("\n\n") content.WriteString(progressView(m.currentPage, m.totalPages)) return containerStyle.Render(content.String()) } // agreementView 协议页面 func (m model) agreementView() string { title := titleStyle.Render("SunHPC 系统初始化向导") subtitle := subTitleStyle.Render("请先阅读并同意以下协议") agreement := agreementBox.Render(` ┌─────────────────────────────────────────────────────────────┐ │ SunHPC 软件许可协议 │ └─────────────────────────────────────────────────────────────┘ 1. 许可授予 本软件授予您非独占、不可转让的使用许可。 2. 使用限制 - 不得用于非法目的 - 不得反向工程或反编译 - 不得移除版权标识 3. 免责声明 本软件按"原样"提供,不提供任何明示或暗示的保证。 4. 责任限制 在任何情况下,作者不对因使用本软件造成的任何损失负责。 5. 协议终止 如违反本协议条款,许可将自动终止。 ─────────────────────────────────────────────────────────────── 请仔细阅读以上条款,点击"接受"表示您同意并遵守本协议。 ─────────────────────────────────────────────────────────────── `) var acceptBtn, rejectBtn string if m.agreementIdx == 0 { rejectBtn = selectedButton.Render(">> 拒绝 <<") acceptBtn = selectedButton.Render(" 同意 ") } else { rejectBtn = selectedButton.Render(" 拒绝 ") acceptBtn = selectedButton.Render(">> 同意 <<") } buttonGroup := lipgloss.JoinHorizontal( lipgloss.Center, acceptBtn, " ", rejectBtn) // ✅ 添加调试信息(确认 agreementIdx 的值) // debugInfo := lipgloss.NewStyle().Foreground(lipgloss.Color("#888888")). // Render(fmt.Sprintf("[DEBUG: idx=%d]", m.agreementIdx),) hint := hintStyle.Render("使用 <- -> 或 Tab 选择,Enter 确认") return lipgloss.JoinVertical(lipgloss.Center, title, "", subtitle, "", agreement, "", buttonGroup, "", // debugInfo, "", // ✅ 显示调试信息 hint, ) } // dataView 数据接收页面 func (m model) dataView() string { title := titleStyle.Render("集群基础配置") subtitle := subTitleStyle.Render("请填写系统基本信息") var inputs strings.Builder for i, ti := range m.textInputs { info := fmt.Sprintf("%-10s|", m.inputLabels[i]) input := inputBox.Render(info + ti.View()) inputs.WriteString(input + "\n") } buttons := m.renderNavButtons() hint := hintStyle.Render("使用 Up/Down 或 Tab 切换、Enter 确认") return lipgloss.JoinVertical(lipgloss.Center, title, "", subtitle, "", inputs.String(), "", buttons, "", hint, ) } // publicNetworkView 公网设置页面 func (m model) publicNetworkView() string { title := titleStyle.Render("公网配置") subtitle := subTitleStyle.Render("请配置网络接口信息") autoDetect := infoStyle.Render("[*] 自动检测网络接口: eth0, eth1, ens33") var inputs strings.Builder for i, ti := range m.textInputs { info := fmt.Sprintf("%-10s|", m.inputLabels[i]) input := inputBox.Render(info + ti.View()) inputs.WriteString(input + "\n") } buttons := m.renderNavButtons() hint := hintStyle.Render("使用 Up/Down 或 Tab 切换、Enter 确认") return lipgloss.JoinVertical(lipgloss.Center, title, "", subtitle, "", autoDetect, "", inputs.String(), "", buttons, "", hint, ) } // internalNetworkView 内网配置页面 func (m model) internalNetworkView() string { title := titleStyle.Render("内网配置") subtitle := subTitleStyle.Render("请配置内网信息") var inputs strings.Builder for i, ti := range m.textInputs { info := fmt.Sprintf("%-10s|", m.inputLabels[i]) input := inputBox.Render(info + ti.View()) inputs.WriteString(input + "\n") } buttons := m.renderNavButtons() hint := hintStyle.Render("使用 Up/Down 或 Tab 切换、Enter 确认") return lipgloss.JoinVertical(lipgloss.Center, title, "", subtitle, "", inputs.String(), "", buttons, "", hint, ) } // dnsView DNS 配置页面 func (m model) dnsView() string { title := titleStyle.Render("DNS 配置") subtitle := subTitleStyle.Render("请配置 DNS 服务器") var inputs strings.Builder for i, ti := range m.textInputs { info := fmt.Sprintf("%-10s|", m.inputLabels[i]) input := inputBox.Render(info + ti.View()) inputs.WriteString(input + "\n") } buttons := m.renderNavButtons() hint := hintStyle.Render("使用 Up/Down 或 Tab 切换、Enter 确认") return lipgloss.JoinVertical(lipgloss.Center, title, "", subtitle, "", inputs.String(), "", buttons, "", hint, ) } // summaryView 总结页面 func (m model) summaryView() string { title := titleStyle.Render("配置总结") subtitle := subTitleStyle.Render("请确认以下配置信息") summary := summaryBox.Render(fmt.Sprintf(` +---------------------------------------------+ 基本信息 +---------------------------------------------+ 主机名:%-35s 国 家: %-31s 地 区:%-31s 时 区:%-38s 主 页:%-38s +---------------------------------------------+ 数据库 +---------------------------------------------+ 地 址:%-38s 名 称:%-38s 软 件:%-33s +---------------------------------------------+ 公网配置 +---------------------------------------------+ 接 口:%-38s 地 址: %-41s 掩 码:%-38s 网 关:%-38s +---------------------------------------------+ 内网配置 +---------------------------------------------+ 接 口:%-38s 地 址: %-41s 掩 码:%-38s +---------------------------------------------+ DNS +---------------------------------------------+ 主 DNS: %-37s 备 DNS: %-37s +---------------------------------------------+ `, m.config.Hostname, m.config.Country, m.config.Region, m.config.Timezone, m.config.HomePage, m.config.DBAddress, m.config.DBName, m.config.DataAddress, m.config.PublicInterface, m.config.IPAddress, m.config.Netmask, m.config.Gateway, m.config.InternalInterface, m.config.InternalIP, m.config.InternalMask, m.config.DNSPrimary, m.config.DNSSecondary, )) var buttons string if m.focusIndex == 0 { buttons = selectedButton.Render("[>] 执行初始化") + " " + normalButton.Render("[ ] 取消") } else { buttons = normalButton.Render("[>] 执行初始化") + " " + selectedButton.Render("[ ] 取消") } hint := hintStyle.Render("使用 <- -> 或 Tab 选择,Enter 确认") return lipgloss.JoinVertical(lipgloss.Center, title, "", subtitle, "", summary, "", buttons, "", hint, ) } // progressView 进度条 func progressView(current PageType, total int) string { progress := "" for i := 0; i < total; i++ { if i < int(current) { progress += "[+]" } else if i == int(current) { progress += "[-]" } else { progress += "[ ]" } if i < total-1 { progress += " " } } labels := []string{"协议", "数据", "公网", "内网", "DNS", "总结"} label := labelStyle.Render(labels[current]) return progressStyle.Render(progress) + " " + label } // successView 成功视图 func successView() string { return containerStyle.Render(lipgloss.JoinVertical(lipgloss.Center, successTitle.Render("初始化完成!"), "", successMsg.Render("系统配置已保存,正在初始化..."), "", hintStyle.Render("按任意键退出"), )) } // quitView 退出视图 func quitView() string { return containerStyle.Render(lipgloss.JoinVertical(lipgloss.Center, errorTitle.Render("已取消"), "", errorMsg.Render("初始化已取消,未保存任何配置"), )) } // errorView 错误视图 func errorView(err error) string { return containerStyle.Render(lipgloss.JoinVertical(lipgloss.Center, errorTitle.Render("错误"), "", errorMsg.Render(err.Error()), "", hintStyle.Render("按 Ctrl+C 退出"), )) } // navButtons 导航按钮 func navButtons(m model, prev, next string) string { var btns string if m.currentPage == 0 { btns = normalButton.Render(prev) + " " + selectedButton.Render(next) } else { btns = selectedButton.Render(prev) + " " + normalButton.Render(next) } return btns } func (m model) renderNavButtons() string { var prevBtn, nextBtn string switch m.focusType { case FocusTypePrev: // 焦点在"上一步" prevBtn = selectedButton.Render("<< 上一步 >>") nextBtn = normalButton.Render("下一步 >>") case FocusTypeNext: // 焦点在"下一步" prevBtn = normalButton.Render("<< 上一步") nextBtn = selectedButton.Render("<< 下一步 >>") default: // 焦点在输入框 prevBtn = normalButton.Render("<< 上一步") nextBtn = normalButton.Render("下一步 >>") } return lipgloss.JoinHorizontal( lipgloss.Center, prevBtn, " ", nextBtn, ) }