From a87978e89bfb26d937de1ab4bae49d62a37e3545 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Fri, 16 Jan 2026 16:05:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=84=E7=90=86=E7=AE=80=E5=8D=95=E7=9A=84vi?= =?UTF-8?q?ew=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- punchnet/Views/Login/LoginState.swift | 22 ++ punchnet/Views/{ => Login}/LoginView.swift | 44 ++-- punchnet/Views/Network/NetworkState.swift | 89 ++++++++ punchnet/Views/Network/NetworkView.swift | 241 +++++++++++++++++++++ punchnet/punchnetApp.swift | 3 +- 5 files changed, 372 insertions(+), 27 deletions(-) create mode 100644 punchnet/Views/Login/LoginState.swift rename punchnet/Views/{ => Login}/LoginView.swift (78%) create mode 100644 punchnet/Views/Network/NetworkState.swift create mode 100644 punchnet/Views/Network/NetworkView.swift diff --git a/punchnet/Views/Login/LoginState.swift b/punchnet/Views/Login/LoginState.swift new file mode 100644 index 0000000..607d77a --- /dev/null +++ b/punchnet/Views/Login/LoginState.swift @@ -0,0 +1,22 @@ +// +// LoginState.swift +// punchnet +// +// Created by 安礼成 on 2026/1/16. +// + +import Foundation +import Observation + +@Observable +class LoginState { + enum LoginMode { + case token + case account + } + + var token: String = "" + var account: String = "" + var password: String = "" + var loginMode: LoginMode = .account +} diff --git a/punchnet/Views/LoginView.swift b/punchnet/Views/Login/LoginView.swift similarity index 78% rename from punchnet/Views/LoginView.swift rename to punchnet/Views/Login/LoginView.swift index 800e6c9..fa0c76c 100644 --- a/punchnet/Views/LoginView.swift +++ b/punchnet/Views/Login/LoginView.swift @@ -6,20 +6,11 @@ // import SwiftUI +import Observation // 登陆页面 struct LoginView: View { - @State private var token: String = "" - - @State private var account: String = "" - @State private var password: String = "" - - @State private var loginMode: LoginMode = .account - - enum LoginMode { - case token - case account - } + @State private var state = LoginState() var body: some View { VStack { @@ -33,11 +24,11 @@ struct LoginView: View { .frame(width: 25, height: 25) Text("密钥登陆") - .foregroundColor(loginMode == .token ? .blue : .black) + .foregroundColor(state.loginMode == .token ? .blue : .black) } .contentShape(Rectangle()) .onTapGesture { - self.loginMode = .token + self.state.loginMode = .token } HStack { @@ -46,19 +37,21 @@ struct LoginView: View { .clipped() .frame(width: 25, height: 25) Text("账户登陆") - .foregroundColor(loginMode == .account ? .blue : .black) + .foregroundColor(state.loginMode == .account ? .blue : .black) } .contentShape(Rectangle()) .onTapGesture { - self.loginMode = .account + self.state.loginMode = .account } } - switch loginMode { - case .token: - LoginTokenView(token: self.$token) - case .account: - LoginAccountView(account: $account, password: $password) + Group { + switch state.loginMode { + case .token: + LoginTokenView(state: self.state) + case .account: + LoginAccountView(state: self.state) + } } Spacer() @@ -69,10 +62,10 @@ struct LoginView: View { } struct LoginTokenView: View { - @Binding var token: String + @Bindable var state: LoginState var body: some View { - TextField("认证密钥", text: $token) + TextField("认证密钥", text: self.$state.token) .multilineTextAlignment(.leading) .textFieldStyle(PlainTextFieldStyle()) .frame(width: 200, height: 25) @@ -102,11 +95,10 @@ struct LoginTokenView: View { } struct LoginAccountView: View { - @Binding var account: String - @Binding var password: String + @Bindable var state: LoginState var body: some View { - TextField("手机号/邮箱", text: $account) + TextField("手机号/邮箱", text: $state.account) .multilineTextAlignment(.leading) .textFieldStyle(PlainTextFieldStyle()) .frame(width: 200, height: 25) @@ -119,7 +111,7 @@ struct LoginAccountView: View { .padding(.top, 25) , alignment: .topLeading) - TextField("密码", text: $account) + SecureField("密码", text: $state.password) .multilineTextAlignment(.leading) .textFieldStyle(PlainTextFieldStyle()) .frame(width: 200, height: 25) diff --git a/punchnet/Views/Network/NetworkState.swift b/punchnet/Views/Network/NetworkState.swift new file mode 100644 index 0000000..b85373a --- /dev/null +++ b/punchnet/Views/Network/NetworkState.swift @@ -0,0 +1,89 @@ +// +// NetworkState.swift +// punchnet +// +// Created by 安礼成 on 2026/1/16. +// + +import Foundation +import Observation + +@Observable +class NetworkState { + + // 连接状态 + enum ConnectState { + case waitAuth + case connected + case disconnected + } + + // 展示状态 + enum ShowMode { + case resource + case device + } + + struct Resource { + var id: Int + var status: Int + var name: String + var schema: String + } + + struct Device: Equatable, Hashable { + var id: Int + var status: Int + var name: String + var ipv4: String + var ipv6: String + var system: String + + var resources: [Resource] + + func hash(into hasher: inout Hasher) { + hasher.combine(id) + } + + static func == (lhs: Self, rhs: Self) -> Bool { + return lhs.id == rhs.id + } + } + + struct NetworkModel { + var name: String + } + + var connectState: ConnectState = .connected + var model: NetworkModel = .init(name: "123@abc.com的网络") + + var showModel: ShowMode = .device + + 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] = [ + ] + + init() { + self.devices = [ + .init(id: 1, status: 1, name: "阿里云1", ipv4: "192.168.1.1", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), + .init(id: 2, status: 1, name: "阿里云1", ipv4: "192.168.1.1", ipv6: "fa9d.fa9d.fa9d.fa9d", system: "MacOS 12", resources: self.resources), + .init(id: 3, status: 1, name: "阿里云1", ipv4: "192.168.1.1", 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), + ] + } + +} diff --git a/punchnet/Views/Network/NetworkView.swift b/punchnet/Views/Network/NetworkView.swift new file mode 100644 index 0000000..687bc44 --- /dev/null +++ b/punchnet/Views/Network/NetworkView.swift @@ -0,0 +1,241 @@ +// +// NetworkView.swift +// punchnet +// +// Created by 安礼成 on 2026/1/16. +// + +import SwiftUI + +struct NetworkView: View { + @State private var state = NetworkState() + + var body: some View { + VStack { + HStack(alignment: .center) { + Text(state.model.name) + Text(">") + Spacer() + + Image("logo") + .resizable() + .frame(width: 25, height: 25) + } + + Group { + switch state.connectState { + case .waitAuth: + NetworkWaitAuthView(state: self.state) + case .connected: + NetworkConnctedView(state: self.state) + case .disconnected: + NetworkDisconnctedView(state: self.state) + } + } + + Spacer() + } + .frame(width: 400, height: 400) + .padding(.top, 10) + .padding(.leading, 10) + } +} + +struct NetworkWaitAuthView: View { + @Bindable var state: NetworkState + + var body: some View { + Color.clear + .overlay { + Text("等待确认中") + } + } +} + +struct NetworkDisconnctedView: View { + @Bindable var state: NetworkState + @State var isOn: Bool = false + + var body: some View { + VStack { + HStack { + Toggle("", isOn: $isOn) + .toggleStyle(SwitchToggleStyle(tint: .green)) + + Text("未连接") + + Spacer() + } + + ZStack { + Color.clear + + Button { + print("call me here") + } label: { + Text("连接") + .font(.system(size: 14, weight: .regular)) + .padding([.top, .bottom], 8) + .padding([.leading, .trailing], 30) + .foregroundColor(.white) + + } + .background(Color(red: 74/255, green: 207/255, blue: 154/255)) + .cornerRadius(5) + .frame(width: 120, height: 35) + } + } + + } + +} + +struct NetworkConnctedView: View { + @Bindable var state: NetworkState + @State var isOn: Bool = true + + var body: some View { + VStack { + HStack { + Toggle("", isOn: $isOn) + .toggleStyle(SwitchToggleStyle(tint: .green)) + + Text("已连接") + + Spacer() + } + + Group { + switch state.showModel { + case .resource: + NetworkResourceGroupView(resources: self.state.resources) + case .device: + NetworkDeviceGroupView(devices: self.state.devices, selection: self.state.devices[0]) + } + } + } + } +} + +// 显示资源信息 +struct NetworkResourceGroupView: View { + var resources: [NetworkState.Resource] + + struct NetworkResourceView: View { + var resource: NetworkState.Resource + + var body: some View { + VStack { + HStack { + Text(resource.status == 1 ? "yes" : "no") + + Text(resource.name) + .font(.system(size: 14, weight: .regular)) + } + + Text(resource.schema) + .font(.system(size: 14, weight: .regular)) + .padding(.leading, 30) + + } + } + } + + var body: some View { + LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3), spacing: 8) { + ForEach(resources, id: \.id) { resource in + NetworkResourceView(resource: resource) + } + } + } +} + +// 显示设备信息 +struct NetworkDeviceGroupView: View { + var devices: [NetworkState.Device] + @State private var selection: NetworkState.Device + + init(devices: [NetworkState.Device], selection: NetworkState.Device) { + self.devices = devices + self.selection = selection + } + + var body: some View { + NavigationSplitView { + List(devices, id: \.id, selection: $selection) { device in + NetworkDeviceHeadView(device: device) + } + } detail: { + NetworkDeviceDetailView(device: $selection) + } + } + +} + +struct NetworkDeviceHeadView: View { + var device: NetworkState.Device + + var body: some View { + VStack { + HStack { + Text(device.status == 1 ? "yes" : "no") + + Text(device.name) + .font(.system(size: 14, weight: .regular)) + } + + Text(device.ipv4) + .font(.system(size: 14, weight: .regular)) + .padding(.leading, 30) + } + } +} + +struct NetworkDeviceDetailView: View { + @Binding var device: NetworkState.Device + + var body: some View { + VStack { + HStack { + Text("连接状态") + + Text("\(device.status)") + } + + HStack { + Text("虚拟IPv4") + + Text("\(device.ipv4)") + } + + HStack { + Text("虚拟IPv6") + + Text("\(device.ipv6)") + } + + HStack { + Text("操作系统") + + Text("\(device.system)") + } + + VStack { + Text("服务列表") + + List(device.resources, id: \.id) { resource in + HStack { + Text("\(resource.name)") + Text("\(resource.schema)") + } + } + } + } + } +} + + + +#Preview { + NetworkView() +} diff --git a/punchnet/punchnetApp.swift b/punchnet/punchnetApp.swift index 9e5f4e0..1b094f3 100644 --- a/punchnet/punchnetApp.swift +++ b/punchnet/punchnetApp.swift @@ -44,7 +44,8 @@ struct punchnetApp: App { var body: some Scene { WindowGroup(id: "mainWindow") { - IndexView(noticeServer: self.noticeServer) + //IndexView(noticeServer: self.noticeServer) + LoginView() .onAppear { // 获取主屏幕的尺寸 guard let screenFrame = NSScreen.main?.frame else { return }