// // ResetPasswordView.swift // punchnet // // Created by 安礼成 on 2026/3/9. // import SwiftUI struct ResetPasswordRootView: View { @State private var resetPasswordModel = ResetPasswordModel() var body: some View { Group { switch resetPasswordModel.stage { case .requestVerifyCode: GetVerifyCodeView() case .submitVerifyCode(let username): SubmitVerifyCodeView(username: username) case .resetPassword(let username): ResetPasswordView(username: username) } } .environment(resetPasswordModel) } } // 获取验证码 struct GetVerifyCodeView: View { @Environment(ResetPasswordModel.self) var resetPasswordModel: ResetPasswordModel @State private var username: String = "" @State private var showAlert = false @State private var errorMessage = "" var body: some View { VStack(spacing: 30) { // 标题 Text("重置密码") .font(.system(size: 18, weight: .medium)) VStack(alignment: .leading, spacing: 16) { TextField("手机号/邮箱", text: $username) .textFieldStyle(.plain) .frame(width: 260, height: 28) .overlay( Rectangle() .frame(height: 1) .foregroundColor(.blue), alignment: .bottom ) } Button { Task { @MainActor in //await self.sendVerifyCode() withAnimation { self.resetPasswordModel.stage = .submitVerifyCode(username: self.username) } } } label: { Text("获取验证码") .font(.system(size: 14)) .foregroundColor(.black) .frame(width: 160, height: 36) .background(Color(red: 74/255, green: 207/255, blue: 154/255)) } .frame(width: 160, height: 36) .cornerRadius(6) Spacer() } .padding(.top, 40) .frame(width: 400, height: 400) .alert(isPresented: $showAlert) { Alert(title: Text("提示"), message: Text(self.errorMessage)) } } private func sendVerifyCode() async { if username.isEmpty { self.showAlert = true self.errorMessage = "手机号/邮箱为空" return } switch SDLUtil.identifyContact(username) { case .email, .phone: do { let result = try await self.resetPasswordModel.requestVerifyCode(username: username) print("send verify code result: \(result)") } catch { self.showAlert = true self.errorMessage = error.localizedDescription } case .invalid: self.showAlert = true self.errorMessage = "手机号/邮箱格式错误" } } } // 输入验证码 struct SubmitVerifyCodeView: View { @Environment(ResetPasswordModel.self) var resetPasswordModel: ResetPasswordModel @State var username: String @State private var verifiyCode: String = "" @State private var showAlert = false @State private var errorMessage = "" var body: some View { VStack(spacing: 30) { // 标题 Text("重置密码") .font(.system(size: 18, weight: .medium)) VStack(alignment: .leading, spacing: 16) { TextField("手机号/邮箱", text: $username) .textFieldStyle(.plain) .frame(width: 260, height: 28) .disabled(true) .overlay( Rectangle() .frame(height: 1) .foregroundColor(.blue), alignment: .bottom ) HStack { TextField("验证码", text: $verifiyCode) .textFieldStyle(.plain) .frame(width: 260, height: 28) .overlay( Rectangle() .frame(height: 1) .foregroundColor(.blue), alignment: .bottom ) Spacer() Button { Task { @MainActor in //await self.sendVerifyCode() } } label: { Text("再次获取") .font(.system(size: 14)) .foregroundColor(.black) .frame(width: 160, height: 36) .background(Color(red: 74/255, green: 207/255, blue: 154/255)) } .frame(width: 160, height: 36) .cornerRadius(6) } } Button { Task { @MainActor in await self.submitVerifyCode() withAnimation { self.resetPasswordModel.stage = .resetPassword(username: username) } } } label: { Text("设置密码") .font(.system(size: 14)) .foregroundColor(.black) .frame(width: 160, height: 36) .background(Color(red: 74/255, green: 207/255, blue: 154/255)) } .frame(width: 160, height: 36) .cornerRadius(6) Spacer() } .padding(.top, 40) .frame(width: 400, height: 400) .alert(isPresented: $showAlert) { Alert(title: Text("提示"), message: Text(self.errorMessage)) } } private func submitVerifyCode() async { if verifiyCode.isEmpty { self.showAlert = true self.errorMessage = "请输入验证码" return } if verifiyCode.count != 4 { self.showAlert = true self.errorMessage = "验证码错误" return } do { let result = try await self.resetPasswordModel.submitVerifyCode(username: username, verifyCode: verifiyCode) print("submit verify code result: \(result)") } catch { self.showAlert = true self.errorMessage = error.localizedDescription } } } // 重置密码 struct ResetPasswordView: View { @Environment(ResetPasswordModel.self) var resetPasswordModel: ResetPasswordModel var username: String @State private var password: String = "" @State private var confirmPassword: String = "" @State private var showAlert = false @State private var errorMessage = "" var body: some View { VStack(spacing: 30) { // 标题 Text("重置密码") .font(.system(size: 18, weight: .medium)) VStack(alignment: .leading, spacing: 16) { SecureField("新密码", text: $password) .textFieldStyle(.plain) .frame(width: 260, height: 28) .overlay( Rectangle() .frame(height: 1) .foregroundColor(.blue), alignment: .bottom ) SecureField("再次输入密码", text: $confirmPassword) .textFieldStyle(.plain) .frame(width: 260, height: 28) .overlay( Rectangle() .frame(height: 1) .foregroundColor(.blue), alignment: .bottom ) } Button { Task { @MainActor in await self.resetPassword() } } label: { Text("保存") .font(.system(size: 14)) .foregroundColor(.black) .frame(width: 160, height: 36) .background(Color(red: 74/255, green: 207/255, blue: 154/255)) } .frame(width: 160, height: 36) .cornerRadius(6) Spacer() } .padding(.top, 40) .frame(width: 400, height: 400) .alert(isPresented: $showAlert) { Alert(title: Text("提示"), message: Text(self.errorMessage)) } } private func resetPassword() async { if password.isEmpty { self.showAlert = true self.errorMessage = "请输入新密码" return } if confirmPassword.isEmpty || confirmPassword != password { self.showAlert = true self.errorMessage = "两次输入的密码不一致" return } do { let result = try await self.resetPasswordModel.resetPassword(username: username, password: self.password) print("send verify code result: \(result)") } catch { self.showAlert = true self.errorMessage = error.localizedDescription } } }