完善注册流程

This commit is contained in:
anlicheng 2026-03-19 20:43:35 +08:00
parent fd87c244b9
commit ed6ae5c757
2 changed files with 73 additions and 30 deletions

View File

@ -12,12 +12,12 @@ import Observation
class RegisterModel { class RegisterModel {
enum Stage { enum Stage {
case requestVerifyCode case requestVerifyCode(username: String?)
case submitVerifyCode(username: String) case submitVerifyCode(username: String)
case setPassword(username: String) case setPassword(username: String)
} }
var stage: Stage = .requestVerifyCode var stage: Stage = .requestVerifyCode(username: nil)
private let baseParams: [String: Any] = [ private let baseParams: [String: Any] = [
"client_id": SystemConfig.getClientId(), "client_id": SystemConfig.getClientId(),

View File

@ -19,8 +19,8 @@ struct RegisterRootView: View {
Group { Group {
switch registerModel.stage { switch registerModel.stage {
case .requestVerifyCode: case .requestVerifyCode(let username):
RegisterRequestVerifyCodeView() RegisterRequestVerifyCodeView(username: username ?? "")
case .submitVerifyCode(let username): case .submitVerifyCode(let username):
RegisterSubmitVerifyCodeView(username: username) RegisterSubmitVerifyCodeView(username: username)
case .setPassword(let username): case .setPassword(let username):
@ -71,7 +71,7 @@ struct PunchTextField: View {
// MARK: - // MARK: -
struct RegisterRequestVerifyCodeView: View { struct RegisterRequestVerifyCodeView: View {
@Environment(RegisterModel.self) var registerModel @Environment(RegisterModel.self) var registerModel
@State private var username: String = "" @State var username: String = ""
@State private var isProcessing = false @State private var isProcessing = false
// //
@ -155,18 +155,30 @@ struct RegisterSubmitVerifyCodeView: View {
@State private var showAlert: Bool = false @State private var showAlert: Bool = false
@State private var errorMessage: String = "" @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 { var body: some View {
VStack(spacing: 24) { VStack(spacing: 24) {
headerSection(title: "身份验证", subtitle: "验证码已发送至 \(username)") headerSection(title: "身份验证", subtitle: "验证码已发送至 \(username)")
VStack(spacing: 16) { VStack(alignment: .trailing, spacing: 16) {
PunchTextField(icon: "envelope.badge", placeholder: "输入 4 位验证码", text: $code) PunchTextField(icon: "envelope.badge", placeholder: "输入 4 位验证码", text: $code)
Button("没有收到?重新获取") { Button {
// Resend Logic self.resendVerifyCodeAction()
} label: {
if isEnabled {
Text("没有收到?重新获取")
} else {
Text("重新获取 (\(remainingSeconds)s)")
}
} }
.buttonStyle(.link) .buttonStyle(.link)
.font(.caption) .font(.caption)
.disabled(!isEnabled) //
} }
.frame(width: 280) .frame(width: 280)
@ -188,7 +200,7 @@ struct RegisterSubmitVerifyCodeView: View {
Button("返回上一步") { Button("返回上一步") {
withAnimation { withAnimation {
registerModel.stage = .requestVerifyCode registerModel.stage = .requestVerifyCode(username: self.username)
} }
} }
.buttonStyle(.plain) .buttonStyle(.plain)
@ -202,8 +214,37 @@ struct RegisterSubmitVerifyCodeView: View {
.alert(isPresented: $showAlert) { .alert(isPresented: $showAlert) {
Alert(title: Text("提示"), message: Text(errorMessage)) 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() { private func submitVerifyCode() {
self.isProcessing = true self.isProcessing = true
Task { @MainActor in Task { @MainActor in
@ -245,8 +286,22 @@ struct RegisterSetPasswordView: View {
@State private var isProcessing = false @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 { var body: some View {
VStack(spacing: 24) { VStack(spacing: 24) {
@ -255,6 +310,12 @@ struct RegisterSetPasswordView: View {
VStack(spacing: 12) { VStack(spacing: 12) {
PunchTextField(icon: "lock.shield", placeholder: "新密码", text: $password, isSecure: true) PunchTextField(icon: "lock.shield", placeholder: "新密码", text: $password, isSecure: true)
PunchTextField(icon: "lock.shield", placeholder: "确认密码", text: $confirm, 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) .frame(width: 280)
@ -273,38 +334,20 @@ struct RegisterSetPasswordView: View {
.buttonStyle(.borderedProminent) .buttonStyle(.borderedProminent)
.controlSize(.large) .controlSize(.large)
.frame(width: 280) .frame(width: 280)
.disabled(password.isEmpty || password != confirm) .disabled(passwordError != nil)
Spacer() Spacer()
} }
.padding(40) .padding(40)
.alert(isPresented: $showAlert) {
Alert(title: Text("提示"), message: Text(errorMessage))
}
} }
private func handleRegister() { private func handleRegister() {
self.isProcessing = true self.isProcessing = true
Task { @MainActor in 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 { do {
let result = try await self.registerModel.register(username: username, password: self.password) let result = try await self.registerModel.register(username: username, password: self.password)
print("send verify code result: \(result)") print("send verify code result: \(result)")
} catch { } catch {
self.showAlert = true
self.errorMessage = error.localizedDescription self.errorMessage = error.localizedDescription
} }
self.isProcessing = false self.isProcessing = false