fix settings network
This commit is contained in:
parent
0dcccf445e
commit
82c02739b8
@ -39,82 +39,11 @@ struct SettingsAccountView: View {
|
|||||||
.background(Color.primary.opacity(0.03))
|
.background(Color.primary.opacity(0.03))
|
||||||
.cornerRadius(12)
|
.cornerRadius(12)
|
||||||
.overlay(RoundedRectangle(cornerRadius: 12).stroke(Color.primary.opacity(0.05), lineWidth: 1))
|
.overlay(RoundedRectangle(cornerRadius: 12).stroke(Color.primary.opacity(0.05), lineWidth: 1))
|
||||||
|
|
||||||
// MARK: - 网络部分
|
|
||||||
sectionHeader(title: "网络配置", icon: "network")
|
|
||||||
|
|
||||||
if let networkSession = userContext.networkSession {
|
|
||||||
VStack(spacing: 16) {
|
|
||||||
HStack {
|
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
|
||||||
Text("网络")
|
|
||||||
.font(.subheadline)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
|
|
||||||
Text(networkSession.networkName)
|
|
||||||
.font(.headline)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
//
|
|
||||||
// Menu {
|
|
||||||
// ForEach(state.networks, id: \.id) { network in
|
|
||||||
// Button(network.name) {
|
|
||||||
// self.state.selectedNetwork = network
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } label: {
|
|
||||||
// Text("切换网络")
|
|
||||||
// .font(.subheadline)
|
|
||||||
// .padding(.horizontal, 12)
|
|
||||||
// .padding(.vertical, 6)
|
|
||||||
// .background(Capsule().fill(Color.blue.opacity(0.1)))
|
|
||||||
// }
|
|
||||||
// .buttonStyle(.plain)
|
|
||||||
}
|
|
||||||
|
|
||||||
Divider()
|
|
||||||
|
|
||||||
HStack {
|
|
||||||
Button {
|
|
||||||
self.openNetworkUrl(url: networkSession.networkUrl)
|
|
||||||
} label: {
|
|
||||||
Label("进入管理平台", systemImage: "arrow.up.right.square")
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
.foregroundColor(.blue)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Button("查看详情") {
|
|
||||||
self.openNetworkUrl(url: networkSession.networkUrl)
|
|
||||||
}
|
|
||||||
.buttonStyle(.bordered)
|
|
||||||
.controlSize(.small)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(16)
|
|
||||||
.background(Color.primary.opacity(0.03))
|
|
||||||
.cornerRadius(12)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.frame(maxWidth: 600) // 限制宽度防止在大屏幕上显得太散
|
.frame(maxWidth: 600) // 限制宽度防止在大屏幕上显得太散
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func openNetworkUrl(url: String) {
|
|
||||||
if let url = URL(string: url) {
|
|
||||||
openURL(url) { accepted in
|
|
||||||
if accepted {
|
|
||||||
print("浏览器已成功打开")
|
|
||||||
} else {
|
|
||||||
print("打开失败(可能是 URL 格式错误)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开窗口
|
// 打开窗口
|
||||||
private func openMainWindow(id: String) {
|
private func openMainWindow(id: String) {
|
||||||
let window = NSApp.windows.first { win in
|
let window = NSApp.windows.first { win in
|
||||||
|
|||||||
@ -8,57 +8,95 @@ import SwiftUI
|
|||||||
|
|
||||||
struct SettingsNetworkView: View {
|
struct SettingsNetworkView: View {
|
||||||
@Environment(UserContext.self) var userContext: UserContext
|
@Environment(UserContext.self) var userContext: UserContext
|
||||||
|
@Environment(\.openURL) var openURL
|
||||||
|
|
||||||
@State private var selectedExitNode: UserContext.NetworkSession.ExitNode?
|
@State private var selectedExitNode: UserContext.NetworkSession.ExitNode?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
VStack(alignment: .leading, spacing: 24) {
|
VStack(alignment: .leading, spacing: 24) {
|
||||||
|
|
||||||
// MARK: - 网络连接配置
|
// MARK: - 网络部分
|
||||||
networkSectionHeader(title: "连接设置", icon: "wifi.router.fill")
|
sectionHeader(title: "网络配置", icon: "network")
|
||||||
|
|
||||||
if let networkSession = userContext.networkSession {
|
if let networkSession = userContext.networkSession {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 16) {
|
||||||
// // 默认网络项
|
HStack {
|
||||||
// NetworkRow(title: "默认网络", value: state.selectedNetwork.name) {
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
// Menu {
|
Text("网络")
|
||||||
// ForEach(state.networks, id: \.id) { network in
|
.font(.subheadline)
|
||||||
// Button(network.name) {
|
.foregroundColor(.secondary)
|
||||||
// self.state.selectedNetwork = network
|
|
||||||
// }
|
Text(networkSession.networkName)
|
||||||
// }
|
.font(.headline)
|
||||||
// } label: {
|
|
||||||
// actionLabel(text: "切换")
|
|
||||||
// }
|
|
||||||
// .buttonStyle(.plain)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Divider().padding(.leading, 16)
|
|
||||||
|
|
||||||
// 出口节点项
|
|
||||||
NetworkRow(title: "出口节点", value: selectedExitNode?.nodeName ?? "") {
|
|
||||||
Menu {
|
|
||||||
ForEach(networkSession.exitNodes, id: \.uuid) { node in
|
|
||||||
Button {
|
|
||||||
self.selectedExitNode = node
|
|
||||||
} label: {
|
|
||||||
Text(node.nodeName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
actionLabel(text: "更改")
|
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
|
||||||
|
Spacer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
Button {
|
||||||
|
self.openNetworkUrl(url: networkSession.networkUrl)
|
||||||
|
} label: {
|
||||||
|
Label("进入管理平台", systemImage: "arrow.up.right.square")
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.foregroundColor(.blue)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Button("查看详情") {
|
||||||
|
self.openNetworkUrl(url: networkSession.networkUrl)
|
||||||
|
}
|
||||||
|
.buttonStyle(.bordered)
|
||||||
|
.controlSize(.small)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.padding(16)
|
||||||
|
.background(Color.primary.opacity(0.03))
|
||||||
|
.cornerRadius(12)
|
||||||
|
|
||||||
|
// 出口节点项
|
||||||
|
HStack {
|
||||||
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
Text("出口节点")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
if let selectedExitNode = self.selectedExitNode {
|
||||||
|
Text(selectedExitNode.nodeName)
|
||||||
|
.font(.system(size: 15, weight: .medium))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
ForEach(networkSession.exitNodes, id: \.uuid) { node in
|
||||||
|
Button {
|
||||||
|
self.selectedExitNode = node
|
||||||
|
} label: {
|
||||||
|
Text(node.nodeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Text("更改")
|
||||||
|
.font(.subheadline)
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
.padding(.vertical, 4)
|
||||||
|
.background(Capsule().fill(Color.blue.opacity(0.1)))
|
||||||
|
.foregroundColor(.blue)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
|
.padding(16)
|
||||||
.background(Color.primary.opacity(0.03))
|
.background(Color.primary.opacity(0.03))
|
||||||
.cornerRadius(12)
|
.cornerRadius(12)
|
||||||
.overlay(RoundedRectangle(cornerRadius: 12).stroke(Color.primary.opacity(0.05), lineWidth: 1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - 授权与安全
|
// MARK: - 授权与安全
|
||||||
networkSectionHeader(title: "授权状态", icon: "checkmark.shield.fill")
|
sectionHeader(title: "授权状态", icon: "checkmark.shield.fill")
|
||||||
|
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
StatusRow(title: "当前状态", value: "有效", valueColor: .green)
|
StatusRow(title: "当前状态", value: "有效", valueColor: .green)
|
||||||
@ -70,81 +108,41 @@ struct SettingsNetworkView: View {
|
|||||||
}
|
}
|
||||||
.background(Color.primary.opacity(0.03))
|
.background(Color.primary.opacity(0.03))
|
||||||
.cornerRadius(12)
|
.cornerRadius(12)
|
||||||
|
|
||||||
// MARK: - 外部操作
|
|
||||||
HStack(spacing: 16) {
|
|
||||||
Button {
|
|
||||||
|
|
||||||
} label: {
|
|
||||||
Label("进入管理平台", systemImage: "arrow.up.right.app")
|
|
||||||
.font(.subheadline.bold())
|
|
||||||
}
|
|
||||||
.buttonStyle(.borderedProminent)
|
|
||||||
.controlSize(.large)
|
|
||||||
|
|
||||||
Button {
|
|
||||||
|
|
||||||
} label: {
|
|
||||||
Text("查看诊断详情")
|
|
||||||
}
|
|
||||||
.buttonStyle(.bordered)
|
|
||||||
.controlSize(.large)
|
|
||||||
}
|
|
||||||
.padding(.top, 8)
|
|
||||||
}
|
}
|
||||||
.padding(32)
|
.padding(32)
|
||||||
.frame(maxWidth: 600, alignment: .leading)
|
.frame(maxWidth: 600, alignment: .leading)
|
||||||
}
|
}
|
||||||
|
.onAppear {
|
||||||
|
self.selectedExitNode = self.userContext.networkSession?.exitNodes.first
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - 辅助组件
|
// MARK: - 辅助组件
|
||||||
|
|
||||||
private func networkSectionHeader(title: String, icon: String) -> some View {
|
private func openNetworkUrl(url: String) {
|
||||||
|
if let url = URL(string: url) {
|
||||||
|
openURL(url) { accepted in
|
||||||
|
if accepted {
|
||||||
|
print("浏览器已成功打开")
|
||||||
|
} else {
|
||||||
|
print("打开失败(可能是 URL 格式错误)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助头部组件
|
||||||
|
private func sectionHeader(title: String, icon: String) -> some View {
|
||||||
HStack {
|
HStack {
|
||||||
Image(systemName: icon)
|
Image(systemName: icon)
|
||||||
.foregroundColor(.blue)
|
.foregroundColor(.blue)
|
||||||
.font(.system(size: 14, weight: .semibold))
|
|
||||||
|
|
||||||
Text(title)
|
Text(title)
|
||||||
.font(.system(size: 15, weight: .bold))
|
.font(.system(size: 16, weight: .bold))
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
}
|
||||||
.padding(.leading, 4)
|
.padding(.leading, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func actionLabel(text: String) -> some View {
|
|
||||||
Text(text)
|
|
||||||
.font(.subheadline)
|
|
||||||
.padding(.horizontal, 10)
|
|
||||||
.padding(.vertical, 4)
|
|
||||||
.background(Capsule().fill(Color.blue.opacity(0.1)))
|
|
||||||
.foregroundColor(.blue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - 通用行组件
|
|
||||||
struct NetworkRow<Content: View>: View {
|
|
||||||
let title: String
|
|
||||||
let value: String
|
|
||||||
let action: () -> Content
|
|
||||||
|
|
||||||
init(title: String, value: String, @ViewBuilder action: @escaping () -> Content) {
|
|
||||||
self.title = title
|
|
||||||
self.value = value
|
|
||||||
self.action = action
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
HStack {
|
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
|
||||||
Text(title).font(.caption).foregroundColor(.secondary)
|
|
||||||
Text(value).font(.system(size: 15, weight: .medium))
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
action()
|
|
||||||
}
|
|
||||||
.padding(16)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StatusRow: View {
|
struct StatusRow: View {
|
||||||
@ -166,9 +164,3 @@ struct StatusRow: View {
|
|||||||
.padding(16)
|
.padding(16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - 预览辅助
|
|
||||||
#Preview {
|
|
||||||
SettingsNetworkView()
|
|
||||||
.environment(UserContext()) // 确保环境中存在 UserContext
|
|
||||||
}
|
|
||||||
|
|||||||
@ -38,6 +38,14 @@ struct punchnetApp: App {
|
|||||||
self.noticeServer = UDPNoticeCenterServer()
|
self.noticeServer = UDPNoticeCenterServer()
|
||||||
self.noticeServer.start()
|
self.noticeServer.start()
|
||||||
self.appContext = AppContext(noticePort: self.noticeServer.port)
|
self.appContext = AppContext(noticePort: self.noticeServer.port)
|
||||||
|
|
||||||
|
// TODO test
|
||||||
|
self.userContext.networkSession = .init(accessToken: "", username: "", userType: "", audit: 0, networkId: 1, networkName: "测试网络1", networkDomain: "punchnet.com", exitNodes: [
|
||||||
|
.init(nnid: 1, nodeName: "出口1"),
|
||||||
|
.init(nnid: 2, nodeName: "出口2"),
|
||||||
|
.init(nnid: 3, nodeName: "出口2"),
|
||||||
|
])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user