From fd22574db14e0222560d6dc71653074c24401367 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Thu, 26 Feb 2026 15:34:58 +0800 Subject: [PATCH] fix views --- punchnet/Core/SDLAPIClient.swift | 3 + punchnet/Views/Network/NetworkModel.swift | 112 +++++----- punchnet/Views/Network/NetworkView.swift | 252 +++++++++++----------- 3 files changed, 191 insertions(+), 176 deletions(-) diff --git a/punchnet/Core/SDLAPIClient.swift b/punchnet/Core/SDLAPIClient.swift index 1500bdb..df736bc 100644 --- a/punchnet/Core/SDLAPIClient.swift +++ b/punchnet/Core/SDLAPIClient.swift @@ -30,6 +30,9 @@ struct SDLAPIClient { request.httpBody = postData let (data, _) = try await URLSession.shared.data(for: request) + + NSLog("response is: \(String(bytes: data, encoding: .utf8))") + let apiResponse = try JSONDecoder().decode(SDLAPIResponse.self, from: data) if apiResponse.code == 0, let data = apiResponse.data { diff --git a/punchnet/Views/Network/NetworkModel.swift b/punchnet/Views/Network/NetworkModel.swift index a1dc29a..b5075bc 100644 --- a/punchnet/Views/Network/NetworkModel.swift +++ b/punchnet/Views/Network/NetworkModel.swift @@ -18,43 +18,61 @@ class NetworkModel { case disconnected } - // 展示状态 - enum ShowMode { - case resource - case device - } - // 资源列表 - struct Resource { + struct Resource: Codable { var id: Int - var status: Int var name: String - var schema: String + var url: String + var connectionStatus: String + + enum CodingKeys: String, CodingKey { + case id + case name + case url + case connectionStatus = "connection_status" + } } // 设备列表 - struct Device { + struct Node: Codable { var id: Int - var status: Int var name: String - var ipv4: String - var ipv6: String + var ip: String var system: String - - var resources: [Resource] - + var connectStatus: Int + func hash(into hasher: inout Hasher) { hasher.combine(id) } + enum CodingKeys: String, CodingKey { + case id + case name + case ip + case system + case connectStatus = "connect_status" + } + static func == (lhs: Self, rhs: Self) -> Bool { return lhs.id == rhs.id } } + struct NetworkContext: Codable { + let ip: String + let resourceList: [Resource] + let nodeList: [Node] + + enum CodingKeys: String, CodingKey { + case ip + case resourceList = "resource_list" + case nodeList = "node_list" + } + + } + // 状态管理 var connectState: ConnectState = .disconnected - var showModel: ShowMode = .device // 网络连接开关 var isOn: Bool = false { @@ -68,51 +86,37 @@ class NetworkModel { } // 当前选中的设备 - var selectedDevice: Device? + var selectedNode: Node? - var resources: [Resource] = [ - .init(id: 1, status: 1, name: "OA", schema: "http://100.92.108.1:8080"), - .init(id: 2, status: 0, name: "数据资源", schema: "http://100.92.108.1:8080"), - .init(id: 3, status: 1, name: "OA", schema: "http://100.92.108.1:8080"), - .init(id: 4, status: 0, name: "TEST", schema: "http://100.92.108.1:8080"), - .init(id: 10, status: 1, name: "YES", schema: "http://100.92.108.1:8080"), - .init(id: 11, status: 0, name: "DEBUG", schema: "http://100.92.108.1:8080"), - ] - - var devices: [Device] = [ - ] + var ip: String = "" + var resourceList: [Resource] = [] + var nodeList: [Node] = [] init() { - self.devices = [ - .init(id: 1, status: 1, name: "test1", ipv4: "192.168.1.1", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), - .init(id: 2, status: 1, name: "test2", ipv4: "192.168.1.2", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), - .init(id: 3, status: 1, name: "test3", ipv4: "192.168.1.3", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), - .init(id: 4, status: 1, name: "阿里云1", ipv4: "192.168.1.1", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), - .init(id: 5, status: 1, name: "阿里云1", ipv4: "192.168.1.1", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), - .init(id: 15, status: 1, name: "阿里云1", ipv4: "192.168.1.1", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), - .init(id: 25, status: 1, name: "阿里云1", ipv4: "192.168.1.1", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), - .init(id: 35, status: 1, name: "阿里云1", ipv4: "192.168.1.1", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), - .init(id: 45, status: 1, name: "阿里云1", ipv4: "192.168.1.1", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), - .init(id: 55, status: 1, name: "阿里云1", ipv4: "192.168.1.1", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), - ] + } - func changeSelectedDevice(deviceId: Int?) { - if let deviceId { - if let device = self.devices.first(where: { $0.id == deviceId}) { - self.selectedDevice = device + func changeSelectedNode(nodeId: Int?) { + if let nodeId { + if let node = self.nodeList.first(where: { $0.id == nodeId}) { + self.selectedNode = node } } } -// func connect() async throws { -// let params: [String: Any] = [ -// "client_id": SystemConfig.getClientId(), -// "access_token": networkSession.accessToken -// ] -// -// try await SDLAPIClient.doPost(path: "/connect", params: params, as: <#T##Decodable.Type#>) -// } - + @MainActor + func connect(networkSession: UserContext.NetworkSession) async throws { + let params: [String: Any] = [ + "client_id": SystemConfig.getClientId(), + "access_token": networkSession.accessToken + ] + + let networkContext = try await SDLAPIClient.doPost(path: "/connect", params: params, as: NetworkContext.self) + self.ip = networkContext.ip + self.resourceList = networkContext.resourceList + self.nodeList = networkContext.nodeList + self.connectState = .connected + self.isOn = true + } } diff --git a/punchnet/Views/Network/NetworkView.swift b/punchnet/Views/Network/NetworkView.swift index 4f3dfe0..f96738a 100644 --- a/punchnet/Views/Network/NetworkView.swift +++ b/punchnet/Views/Network/NetworkView.swift @@ -10,6 +10,13 @@ import SwiftUI struct NetworkView: View { @Environment(UserContext.self) var userContext: UserContext @State private var networkModel = NetworkModel() + @State private var showMode: ShowMode = .resource + + // 展示状态 + enum ShowMode { + case resource + case device + } var body: some View { VStack { @@ -25,6 +32,7 @@ struct NetworkView: View { HStack { Toggle("", isOn: $networkModel.isOn) .toggleStyle(SwitchToggleStyle(tint: .green)) + .disabled(true) Text("已连接") @@ -36,13 +44,13 @@ struct NetworkView: View { // 显示设备和资源选项 HStack { Button { - self.networkModel.showModel = .resource + self.showMode = .resource } label: { Text("资源") } Button { - self.networkModel.showModel = .device + self.showMode = .device } label: { Text("设备") } @@ -55,7 +63,14 @@ struct NetworkView: View { case .waitAuth: NetworkWaitAuthView(networkModel: self.networkModel) case .connected: - NetworkConnctedView(networkModel: self.networkModel) + Group { + switch self.showMode { + case .resource: + NetworkResourceGroupView(networkModel: self.networkModel) + case .device: + NetworkDeviceGroupView(networkModel: self.networkModel) + } + } case .disconnected: NetworkDisconnctedView(networkModel: self.networkModel) } @@ -80,16 +95,25 @@ struct NetworkView: View { // 网络处于未连接状态 struct NetworkDisconnctedView: View { @Bindable var networkModel: NetworkModel + @Environment(UserContext.self) var userContext: UserContext + + @State private var showAlert = false + @State private var errorMessage = "" var body: some View { ZStack { Color.clear VStack { - Button { - Task { - try await startVpn() + Task { @MainActor in + do { + try await self.connect() + try await self.startVpn() + } catch let err { + self.showAlert = true + self.errorMessage = err.localizedDescription + } } } label: { Text("连接") @@ -120,9 +144,19 @@ struct NetworkDisconnctedView: View { .frame(width: 120, height: 35) } } + .alert(isPresented: $showAlert) { + Alert(title: Text("提示"), message: Text(self.errorMessage)) + } } + private func connect() async throws { + guard let networkSession = userContext.networkSession else { + return + } + try await networkModel.connect(networkSession: networkSession) + } + // 执行登陆操作 private func startVpn() async throws { let clientId = SystemConfig.getClientId() @@ -143,151 +177,125 @@ struct NetworkDisconnctedView: View { // 网络处于连接状态 -struct NetworkConnctedView: View { +// 显示资源信息 +struct NetworkResourceGroupView: View { @Bindable var networkModel: NetworkModel var body: some View { - Group { - switch networkModel.showModel { - case .resource: - NetworkResourceGroupView(networkModel: self.networkModel) - case .device: - NetworkDeviceGroupView(networkModel: self.networkModel) + LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3), spacing: 8) { + ForEach(self.networkModel.resourceList, id: \.id) { resource in + NetworkResourceView(resource: resource) } } } } -extension NetworkConnctedView { +struct NetworkResourceView: View { + var resource: NetworkModel.Resource - // 显示资源信息 - struct NetworkResourceGroupView: View { - @Bindable var networkModel: NetworkModel - - var body: some View { - LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3), spacing: 8) { - ForEach(self.networkModel.resources, id: \.id) { resource in - NetworkResourceView(resource: resource) - } - } - } - } - - struct NetworkResourceView: View { - var resource: NetworkModel.Resource - - var body: some View { - VStack { - HStack { - Text(resource.status == 1 ? "yes" : "no") - - Text(resource.name) - .font(.system(size: 14, weight: .regular)) - } + var body: some View { + VStack { + HStack { + Text(resource.connectionStatus) - Text(resource.schema) + Text(resource.name) .font(.system(size: 14, weight: .regular)) - .padding(.leading, 30) - } + + Text(resource.url) + .font(.system(size: 14, weight: .regular)) + .padding(.leading, 30) + + } + } +} + +// 显示设备信息 +struct NetworkDeviceGroupView: View { + @Bindable var networkModel: NetworkModel + @State private var selectedId: Int? + + var body: some View { + NavigationSplitView { + List(self.networkModel.nodeList, id: \.id, selection: $selectedId) { node in + NetworkNodeHeadView(node: node) + } + .listStyle(.sidebar) + .onChange(of: selectedId) { + self.networkModel.changeSelectedNode(nodeId: selectedId) + } + .onAppear { + if selectedId == nil { + selectedId = self.networkModel.nodeList.first?.id + } + } + } detail: { + NetworkNodeDetailView(node: $networkModel.selectedNode) } } - // 显示设备信息 - struct NetworkDeviceGroupView: View { - @Bindable var networkModel: NetworkModel - @State private var selectedId: Int? - - var body: some View { - NavigationSplitView { - List(self.networkModel.devices, id: \.id, selection: $selectedId) { device in - NetworkDeviceHeadView(device: device) - } - .listStyle(.sidebar) - .onChange(of: selectedId) { - self.networkModel.changeSelectedDevice(deviceId: selectedId) - } - .onAppear { - if selectedId == nil { - selectedId = self.networkModel.devices.first?.id - } - } - } detail: { - NetworkDeviceDetailView(device: $networkModel.selectedDevice) - } - } - - } +} + +struct NetworkNodeHeadView: View { + var node: NetworkModel.Node - struct NetworkDeviceHeadView: View { - var device: NetworkModel.Device - - var body: some View { - VStack { - HStack { - Text(device.status == 1 ? "yes" : "no") - - Text(device.name) - .font(.system(size: 14, weight: .regular)) - } + var body: some View { + VStack { + HStack { + Text(node.connectStatus == 1 ? "yes" : "no") - Text(device.ipv4) + Text(node.name) .font(.system(size: 14, weight: .regular)) - .padding(.leading, 30) } + + Text(node.ip) + .font(.system(size: 14, weight: .regular)) + .padding(.leading, 30) } } +} + +struct NetworkNodeDetailView: View { + @Binding var node: NetworkModel.Node? - struct NetworkDeviceDetailView: View { - @Binding var device: NetworkModel.Device? - - var body: some View { - Group { - if let device { - List { - Section { - HStack { - Text("连接状态") - - Text("\(device.status)") - - Spacer() - } + var body: some View { + Group { + if let node { + List { + Section { + HStack { + Text("连接状态") - HStack { - Text("虚拟IPv4") - - Text("\(device.ipv4)") - Spacer() - } + Text("\(node.connectStatus)") - HStack { - Text("虚拟IPv6") - - Text("\(device.ipv6)") - Spacer() - } - - HStack { - Text("操作系统") - - Text("\(device.system)") - Spacer() - } + Spacer() } - Section("服务列表") { - ForEach(device.resources, id: \.id) { resource in - HStack { - Text("\(resource.name)") - Text("\(resource.schema)") - } - } + HStack { + Text("虚拟IPv4") + + Text("\(node.ip)") + Spacer() + } + + HStack { + Text("操作系统") + Text("\(node.system)") + Spacer() } } - } else { - EmptyView() + + // Section("服务列表") { + // ForEach(device.resources, id: \.id) { resource in + // HStack { + // Text("\(resource.name)") + // Text("\(resource.schema)") + // } + // } + // } } + } else { + EmptyView() } } }