305 lines
9.7 KiB
Swift
305 lines
9.7 KiB
Swift
//
|
|
// ResetPasswordView.swift
|
|
// punchnet
|
|
//
|
|
// Created by 安礼成 on 2026/3/9.
|
|
//
|
|
import SwiftUI
|
|
|
|
enum ResetPasswordStage {
|
|
case getVerifyCode
|
|
case submitVerifyCode(username: String)
|
|
case resetPassword(username: String)
|
|
}
|
|
|
|
struct ResetPasswordRootView: View {
|
|
@State private var stage: ResetPasswordStage = .getVerifyCode
|
|
|
|
var body: some View {
|
|
switch stage {
|
|
case .getVerifyCode:
|
|
GetVerifyCodeView(stage: $stage)
|
|
case .submitVerifyCode(let username):
|
|
SubmitVerifyCodeView(username: username, stage: $stage)
|
|
case .resetPassword(let username):
|
|
ResetPasswordView(stage: $stage, username: username)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 获取验证码
|
|
struct GetVerifyCodeView: View {
|
|
@Environment(UserContext.self) var userContext: UserContext
|
|
@Binding var stage: ResetPasswordStage
|
|
|
|
@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.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.userContext.sendVerifyCode(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(UserContext.self) var userContext: UserContext
|
|
|
|
@State var username: String
|
|
@Binding var stage: ResetPasswordStage
|
|
|
|
@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.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.userContext.submitVerifyCode(username: username, verifyCode: verifiyCode)
|
|
print("submit verify code result: \(result)")
|
|
} catch {
|
|
self.showAlert = true
|
|
self.errorMessage = error.localizedDescription
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// 重置密码
|
|
struct ResetPasswordView: View {
|
|
@Environment(UserContext.self) var userContext: UserContext
|
|
@Binding var stage: ResetPasswordStage
|
|
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()
|
|
self.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 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.userContext.resetPassword(username: username, password: self.password)
|
|
print("send verify code result: \(result)")
|
|
} catch {
|
|
self.showAlert = true
|
|
self.errorMessage = error.localizedDescription
|
|
}
|
|
}
|
|
|
|
}
|