fix views

This commit is contained in:
anlicheng 2026-02-26 15:34:58 +08:00
parent a18d07924f
commit fd22574db1
3 changed files with 191 additions and 176 deletions

View File

@ -30,6 +30,9 @@ struct SDLAPIClient {
request.httpBody = postData request.httpBody = postData
let (data, _) = try await URLSession.shared.data(for: request) let (data, _) = try await URLSession.shared.data(for: request)
NSLog("response is: \(String(bytes: data, encoding: .utf8))")
let apiResponse = try JSONDecoder().decode(SDLAPIResponse<T>.self, from: data) let apiResponse = try JSONDecoder().decode(SDLAPIResponse<T>.self, from: data)
if apiResponse.code == 0, let data = apiResponse.data { if apiResponse.code == 0, let data = apiResponse.data {

View File

@ -18,43 +18,61 @@ class NetworkModel {
case disconnected case disconnected
} }
//
enum ShowMode {
case resource
case device
}
// //
struct Resource { struct Resource: Codable {
var id: Int var id: Int
var status: Int
var name: String 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 id: Int
var status: Int
var name: String var name: String
var ipv4: String var ip: String
var ipv6: String
var system: String var system: String
var connectStatus: Int
var resources: [Resource]
func hash(into hasher: inout Hasher) { func hash(into hasher: inout Hasher) {
hasher.combine(id) 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 { static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.id == rhs.id 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 connectState: ConnectState = .disconnected
var showModel: ShowMode = .device
// //
var isOn: Bool = false { var isOn: Bool = false {
@ -68,51 +86,37 @@ class NetworkModel {
} }
// //
var selectedDevice: Device? var selectedNode: Node?
var resources: [Resource] = [ var ip: String = ""
.init(id: 1, status: 1, name: "OA", schema: "http://100.92.108.1:8080"), var resourceList: [Resource] = []
.init(id: 2, status: 0, name: "数据资源", schema: "http://100.92.108.1:8080"), var nodeList: [Node] = []
.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() { 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?) { func changeSelectedNode(nodeId: Int?) {
if let deviceId { if let nodeId {
if let device = self.devices.first(where: { $0.id == deviceId}) { if let node = self.nodeList.first(where: { $0.id == nodeId}) {
self.selectedDevice = device self.selectedNode = node
} }
} }
} }
// func connect() async throws { @MainActor
// let params: [String: Any] = [ func connect(networkSession: UserContext.NetworkSession) async throws {
// "client_id": SystemConfig.getClientId(), let params: [String: Any] = [
// "access_token": networkSession.accessToken "client_id": SystemConfig.getClientId(),
// ] "access_token": networkSession.accessToken
// ]
// try await SDLAPIClient.doPost(path: "/connect", params: params, as: <#T##Decodable.Type#>)
// }
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
}
} }

View File

@ -10,6 +10,13 @@ import SwiftUI
struct NetworkView: View { struct NetworkView: View {
@Environment(UserContext.self) var userContext: UserContext @Environment(UserContext.self) var userContext: UserContext
@State private var networkModel = NetworkModel() @State private var networkModel = NetworkModel()
@State private var showMode: ShowMode = .resource
//
enum ShowMode {
case resource
case device
}
var body: some View { var body: some View {
VStack { VStack {
@ -25,6 +32,7 @@ struct NetworkView: View {
HStack { HStack {
Toggle("", isOn: $networkModel.isOn) Toggle("", isOn: $networkModel.isOn)
.toggleStyle(SwitchToggleStyle(tint: .green)) .toggleStyle(SwitchToggleStyle(tint: .green))
.disabled(true)
Text("已连接") Text("已连接")
@ -36,13 +44,13 @@ struct NetworkView: View {
// //
HStack { HStack {
Button { Button {
self.networkModel.showModel = .resource self.showMode = .resource
} label: { } label: {
Text("资源") Text("资源")
} }
Button { Button {
self.networkModel.showModel = .device self.showMode = .device
} label: { } label: {
Text("设备") Text("设备")
} }
@ -55,7 +63,14 @@ struct NetworkView: View {
case .waitAuth: case .waitAuth:
NetworkWaitAuthView(networkModel: self.networkModel) NetworkWaitAuthView(networkModel: self.networkModel)
case .connected: case .connected:
NetworkConnctedView(networkModel: self.networkModel) Group {
switch self.showMode {
case .resource:
NetworkResourceGroupView(networkModel: self.networkModel)
case .device:
NetworkDeviceGroupView(networkModel: self.networkModel)
}
}
case .disconnected: case .disconnected:
NetworkDisconnctedView(networkModel: self.networkModel) NetworkDisconnctedView(networkModel: self.networkModel)
} }
@ -80,16 +95,25 @@ struct NetworkView: View {
// //
struct NetworkDisconnctedView: View { struct NetworkDisconnctedView: View {
@Bindable var networkModel: NetworkModel @Bindable var networkModel: NetworkModel
@Environment(UserContext.self) var userContext: UserContext
@State private var showAlert = false
@State private var errorMessage = ""
var body: some View { var body: some View {
ZStack { ZStack {
Color.clear Color.clear
VStack { VStack {
Button { Button {
Task { Task { @MainActor in
try await startVpn() do {
try await self.connect()
try await self.startVpn()
} catch let err {
self.showAlert = true
self.errorMessage = err.localizedDescription
}
} }
} label: { } label: {
Text("连接") Text("连接")
@ -120,9 +144,19 @@ struct NetworkDisconnctedView: View {
.frame(width: 120, height: 35) .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 { private func startVpn() async throws {
let clientId = SystemConfig.getClientId() let clientId = SystemConfig.getClientId()
@ -143,151 +177,125 @@ struct NetworkDisconnctedView: View {
// //
struct NetworkConnctedView: View { //
struct NetworkResourceGroupView: View {
@Bindable var networkModel: NetworkModel @Bindable var networkModel: NetworkModel
var body: some View { var body: some View {
Group { LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3), spacing: 8) {
switch networkModel.showModel { ForEach(self.networkModel.resourceList, id: \.id) { resource in
case .resource: NetworkResourceView(resource: resource)
NetworkResourceGroupView(networkModel: self.networkModel)
case .device:
NetworkDeviceGroupView(networkModel: self.networkModel)
} }
} }
} }
} }
extension NetworkConnctedView { struct NetworkResourceView: View {
var resource: NetworkModel.Resource
// var body: some View {
struct NetworkResourceGroupView: View { VStack {
@Bindable var networkModel: NetworkModel HStack {
Text(resource.connectionStatus)
var body: some View { Text(resource.name)
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))
}
Text(resource.schema)
.font(.system(size: 14, weight: .regular)) .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 { struct NetworkNodeHeadView: View {
NavigationSplitView { var node: NetworkModel.Node
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)
}
}
} var body: some View {
VStack {
HStack {
Text(node.connectStatus == 1 ? "yes" : "no")
struct NetworkDeviceHeadView: View { Text(node.name)
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))
}
Text(device.ipv4)
.font(.system(size: 14, weight: .regular)) .font(.system(size: 14, weight: .regular))
.padding(.leading, 30)
} }
Text(node.ip)
.font(.system(size: 14, weight: .regular))
.padding(.leading, 30)
} }
} }
}
struct NetworkDeviceDetailView: View { struct NetworkNodeDetailView: View {
@Binding var device: NetworkModel.Device? @Binding var node: NetworkModel.Node?
var body: some View { var body: some View {
Group { Group {
if let device { if let node {
List { List {
Section { Section {
HStack { HStack {
Text("连接状态") Text("连接状态")
Text("\(device.status)") Text("\(node.connectStatus)")
Spacer() Spacer()
}
HStack {
Text("虚拟IPv4")
Text("\(device.ipv4)")
Spacer()
}
HStack {
Text("虚拟IPv6")
Text("\(device.ipv6)")
Spacer()
}
HStack {
Text("操作系统")
Text("\(device.system)")
Spacer()
}
} }
Section("服务列表") { HStack {
ForEach(device.resources, id: \.id) { resource in Text("虚拟IPv4")
HStack {
Text("\(resource.name)") Text("\(node.ip)")
Text("\(resource.schema)") 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()
} }
} }
} }