// // LoginView.swift // punchnet // // Created by 安礼成 on 2026/1/15. // import SwiftUI import Observation // 登陆页面 struct LoginView: View { @State private var loginMode: LoginMode = .account enum LoginMode { case token case account } var body: some View { VStack { Text("PunchNet") .font(.system(size: 16, weight: .medium)) HStack(alignment: .center, spacing: 30) { Button { self.loginMode = .token } label: { HStack { Image("logo") .resizable() .clipped() .frame(width: 25, height: 25) Text("密钥登陆") .foregroundColor(self.loginMode == .token ? .blue : .black) } .contentShape(Rectangle()) } .buttonStyle(.plain) Button { self.loginMode = .account } label: { HStack { Image("logo") .resizable() .clipped() .frame(width: 25, height: 25) Text("账户登陆") .foregroundColor(self.loginMode == .account ? .blue : .black) } .contentShape(Rectangle()) } .buttonStyle(.plain) } Group { switch loginMode { case .token: LoginTokenView() case .account: LoginAccountView() } } Spacer() } .frame(width: 400, height: 400) } } struct LoginTokenView: View { @Environment(UserContext.self) var userContext: UserContext @State private var token: String = "" var body: some View { TextField("认证密钥", text: $token) .multilineTextAlignment(.leading) .textFieldStyle(PlainTextFieldStyle()) .frame(width: 200, height: 25) .background(Color.clear) .foregroundColor(Color.black) .overlay( Rectangle() .frame(height: 1) .foregroundColor(.blue) .padding(.top, 25) , alignment: .topLeading) Rectangle() .overlay { Text("登陆") .font(.system(size: 14, weight: .regular)) .foregroundColor(.black) } .frame(width: 120, height: 35) .foregroundColor(Color(red: 74 / 255, green: 207 / 255, blue: 154 / 255)) .cornerRadius(5.0) .onTapGesture { print("call me here") } } } struct LoginAccountView: View { @Environment(UserContext.self) var userContext: UserContext @State private var username: String = "" @State private var password: String = "" @State private var showAlert = false @State private var errorMessage = "" struct LoginResult: Decodable { var accessToken: String var networkId: Int enum CodingKeys: String, CodingKey { case accessToken = "access_token" case networkId = "network_id" } } var body: some View { VStack { TextField("手机号/邮箱", text: $username) .multilineTextAlignment(.leading) .textFieldStyle(PlainTextFieldStyle()) .frame(width: 200, height: 25) .background(Color.clear) .foregroundColor(Color.black) .overlay( Rectangle() .frame(height: 1) .foregroundColor(.blue) .padding(.top, 25) , alignment: .topLeading) SecureField("密码", text: $password) .multilineTextAlignment(.leading) .textFieldStyle(PlainTextFieldStyle()) .frame(width: 200, height: 25) .background(Color.clear) .foregroundColor(Color.black) .overlay( Rectangle() .frame(height: 1) .foregroundColor(.blue) .padding(.top, 25) , alignment: .topLeading) Button { if self.username.isEmpty { self.showAlert = true self.errorMessage = "账号不能为空" } else if self.password.isEmpty { self.showAlert = true self.errorMessage = "密码不能为空" } else { Task { await self.doLogin() } } } label: { Text("登陆") .font(.system(size: 14, weight: .regular)) .foregroundColor(.black) .frame(width: 120, height: 35) } .frame(width: 120, height: 35) .background(Color(red: 74 / 255, green: 207 / 255, blue: 154 / 255)) .cornerRadius(5.0) } .alert(isPresented: $showAlert) { Alert(title: Text("错误提示"), message: Text("账号密码为空")) } } // 执行登陆操作 private func doLogin() async { // let clientId = SystemConfig.getClientId() // do { // let loginResult = try await SDLAPI.loginWithAccountAndPassword(clientId: clientId, username: self.username, password: self.password, as: LoginResult.self) // // print(loginResult.accessToken) // // // 保存信息到KeychainStore // let store = KeychainStore.shared // if let tokenData = loginResult.accessToken.data(using: .utf8) { // try store.save(tokenData, account: self.username) // } // // await MainActor.run { // self.userContext.isLogined = true // self.userContext.loginCredit = .accountAndPasword(account: username, password: password, networkId: loginResult.networkId) // } // // } catch let err as JSONRPCError { // await MainActor.run { // self.showAlert = true // self.errorMessage = err.message // } // } catch { // await MainActor.run { // self.showAlert = true // self.errorMessage = "内部错误,请稍后重试" // } // } } } #Preview { LoginView() }