From ed6ae5c7570cf47df46ae2b25fce76e05cea9601 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Thu, 19 Mar 2026 20:43:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=B3=A8=E5=86=8C=E6=B5=81?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- punchnet/Views/Register/RegisterModel.swift | 4 +- punchnet/Views/Register/RegisterView.swift | 99 +++++++++++++++------ 2 files changed, 73 insertions(+), 30 deletions(-) diff --git a/punchnet/Views/Register/RegisterModel.swift b/punchnet/Views/Register/RegisterModel.swift index 78b58b4..933f963 100644 --- a/punchnet/Views/Register/RegisterModel.swift +++ b/punchnet/Views/Register/RegisterModel.swift @@ -12,12 +12,12 @@ import Observation class RegisterModel { enum Stage { - case requestVerifyCode + case requestVerifyCode(username: String?) case submitVerifyCode(username: String) case setPassword(username: String) } - var stage: Stage = .requestVerifyCode + var stage: Stage = .requestVerifyCode(username: nil) private let baseParams: [String: Any] = [ "client_id": SystemConfig.getClientId(), diff --git a/punchnet/Views/Register/RegisterView.swift b/punchnet/Views/Register/RegisterView.swift index 0ed43fe..0bae27d 100644 --- a/punchnet/Views/Register/RegisterView.swift +++ b/punchnet/Views/Register/RegisterView.swift @@ -19,8 +19,8 @@ struct RegisterRootView: View { Group { switch registerModel.stage { - case .requestVerifyCode: - RegisterRequestVerifyCodeView() + case .requestVerifyCode(let username): + RegisterRequestVerifyCodeView(username: username ?? "") case .submitVerifyCode(let username): RegisterSubmitVerifyCodeView(username: username) case .setPassword(let username): @@ -71,7 +71,7 @@ struct PunchTextField: View { // MARK: - 第一步:获取验证码 struct RegisterRequestVerifyCodeView: View { @Environment(RegisterModel.self) var registerModel - @State private var username: String = "" + @State var username: String = "" @State private var isProcessing = false // 错误提示 @@ -154,19 +154,31 @@ struct RegisterSubmitVerifyCodeView: View { // 错误提示 @State private var showAlert: Bool = false @State private var errorMessage: String = "" + + // 重新发送是否可以使用 + @State private var isEnabled: Bool = false + @State private var remainingSeconds = 60 + @State private var timer: Timer? = nil var body: some View { VStack(spacing: 24) { headerSection(title: "身份验证", subtitle: "验证码已发送至 \(username)") - VStack(spacing: 16) { + VStack(alignment: .trailing, spacing: 16) { PunchTextField(icon: "envelope.badge", placeholder: "输入 4 位验证码", text: $code) - Button("没有收到?重新获取") { - // Resend Logic + Button { + self.resendVerifyCodeAction() + } label: { + if isEnabled { + Text("没有收到?重新获取") + } else { + Text("重新获取 (\(remainingSeconds)s)") + } } .buttonStyle(.link) .font(.caption) + .disabled(!isEnabled) // 倒计时期间禁用按钮 } .frame(width: 280) @@ -188,7 +200,7 @@ struct RegisterSubmitVerifyCodeView: View { Button("返回上一步") { withAnimation { - registerModel.stage = .requestVerifyCode + registerModel.stage = .requestVerifyCode(username: self.username) } } .buttonStyle(.plain) @@ -202,8 +214,37 @@ struct RegisterSubmitVerifyCodeView: View { .alert(isPresented: $showAlert) { Alert(title: Text("提示"), message: Text(errorMessage)) } + .task { + await self.startCountdown() + } + } + + // 重新发送验证码 + private func resendVerifyCodeAction() { + Task { + do { + let result = try await self.registerModel.requestVerifyCode(username: username) + print("send verify code result: \(result)") + } catch let err { + print("resend verify get error: \(err)") + } + // 重新计时 + await self.startCountdown() + } + } + + // 重新倒计时 + private func startCountdown() async { + self.isEnabled = false + self.remainingSeconds = 60 + for sec in (1...self.remainingSeconds).reversed() { + self.remainingSeconds = sec + try? await Task.sleep(nanoseconds: 1_000_000_000) + } + self.isEnabled = true } + // 提交验证码 private func submitVerifyCode() { self.isProcessing = true Task { @MainActor in @@ -245,8 +286,22 @@ struct RegisterSetPasswordView: View { @State private var isProcessing = false // 错误提示 - @State private var showAlert: Bool = false - @State private var errorMessage: String = "" + @State private var errorMessage: String? + + // 提示错误信息 + var passwordError: String? { + if password.isEmpty || confirm.isEmpty { + return nil + } + + if password != confirm { + return "两次输入的密码不一致" + } + if password.count < 8 { + return "密码至少需要 8 位" + } + return nil + } var body: some View { VStack(spacing: 24) { @@ -255,6 +310,12 @@ struct RegisterSetPasswordView: View { VStack(spacing: 12) { PunchTextField(icon: "lock.shield", placeholder: "新密码", text: $password, isSecure: true) PunchTextField(icon: "lock.shield", placeholder: "确认密码", text: $confirm, isSecure: true) + if let error = passwordError { + Text(error) + .font(.caption) + .foregroundColor(.red) + .frame(width: 280, alignment: .leading) + } } .frame(width: 280) @@ -273,38 +334,20 @@ struct RegisterSetPasswordView: View { .buttonStyle(.borderedProminent) .controlSize(.large) .frame(width: 280) - .disabled(password.isEmpty || password != confirm) + .disabled(passwordError != nil) Spacer() } .padding(40) - .alert(isPresented: $showAlert) { - Alert(title: Text("提示"), message: Text(errorMessage)) - } } private func handleRegister() { self.isProcessing = true Task { @MainActor in - if password.isEmpty { - self.showAlert = true - self.errorMessage = "请输入新密码" - self.isProcessing = false - return - } - - if confirm.isEmpty || confirm != password { - self.showAlert = true - self.errorMessage = "两次输入的密码不一致" - self.isProcessing = false - return - } - do { let result = try await self.registerModel.register(username: username, password: self.password) print("send verify code result: \(result)") } catch { - self.showAlert = true self.errorMessage = error.localizedDescription } self.isProcessing = false