完善注册流程
This commit is contained in:
parent
c9c507974e
commit
9fcb902090
@ -176,6 +176,9 @@ struct LoginAccountView: View {
|
|||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.appContext.appScene = .logined
|
self.appContext.appScene = .logined
|
||||||
}
|
}
|
||||||
|
} catch let err as SDLAPIError {
|
||||||
|
self.showAlert = true
|
||||||
|
self.errorMessage = err.message
|
||||||
} catch let err {
|
} catch let err {
|
||||||
self.showAlert = true
|
self.showAlert = true
|
||||||
self.errorMessage = err.localizedDescription
|
self.errorMessage = err.localizedDescription
|
||||||
|
|||||||
@ -13,15 +13,19 @@ import SwiftUI
|
|||||||
class ResetPasswordModel {
|
class ResetPasswordModel {
|
||||||
|
|
||||||
enum Stage: Equatable {
|
enum Stage: Equatable {
|
||||||
case requestVerifyCode(username: String?)
|
case requestVerifyCode
|
||||||
case submitVerifyCode(username: String, sessionId: Int)
|
case submitVerifyCode
|
||||||
case resetPassword(username: String, sessionId: Int)
|
case resetPassword
|
||||||
case success
|
case success
|
||||||
}
|
}
|
||||||
|
|
||||||
var stage: Stage = .requestVerifyCode(username: nil)
|
var stage: Stage = .requestVerifyCode
|
||||||
var transitionEdge: Edge = .trailing // 默认从右进入
|
var transitionEdge: Edge = .trailing // 默认从右进入
|
||||||
|
|
||||||
|
// 保存内部状态
|
||||||
|
var username: String = ""
|
||||||
|
var sessionId: Int = 0
|
||||||
|
|
||||||
// 重置会话信息
|
// 重置会话信息
|
||||||
struct ResetPasswordSession: Codable {
|
struct ResetPasswordSession: Codable {
|
||||||
let sessionId: Int
|
let sessionId: Int
|
||||||
|
|||||||
@ -20,12 +20,12 @@ struct ResetPasswordRootView: View {
|
|||||||
|
|
||||||
Group {
|
Group {
|
||||||
switch resetPasswordModel.stage {
|
switch resetPasswordModel.stage {
|
||||||
case .requestVerifyCode(let username):
|
case .requestVerifyCode:
|
||||||
GetVerifyCodeView(username: username ?? "")
|
GetVerifyCodeView()
|
||||||
case .submitVerifyCode(let username, let sessionId):
|
case .submitVerifyCode:
|
||||||
SubmitVerifyCodeView(username: username, sessionId: sessionId)
|
SubmitVerifyCodeView()
|
||||||
case .resetPassword(let username, let sessionId):
|
case .resetPassword:
|
||||||
ResetPasswordView(username: username, sessionId: sessionId)
|
ResetPasswordView()
|
||||||
case .success:
|
case .success:
|
||||||
ResetPasswordSuccessView()
|
ResetPasswordSuccessView()
|
||||||
}
|
}
|
||||||
@ -67,20 +67,23 @@ struct ResetPasswordRootView: View {
|
|||||||
// MARK: - 2. 第一步:获取验证码
|
// MARK: - 2. 第一步:获取验证码
|
||||||
struct GetVerifyCodeView: View {
|
struct GetVerifyCodeView: View {
|
||||||
@Environment(ResetPasswordModel.self) var resetPasswordModel
|
@Environment(ResetPasswordModel.self) var resetPasswordModel
|
||||||
@State var username: String = ""
|
|
||||||
@State private var isProcessing = false
|
@State private var isProcessing = false
|
||||||
@State private var showAlert = false
|
@State private var showAlert = false
|
||||||
@State private var errorMessage = ""
|
@State private var errorMessage = ""
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@Bindable var model = resetPasswordModel
|
||||||
|
|
||||||
VStack(spacing: 24) {
|
VStack(spacing: 24) {
|
||||||
headerSection(title: "重置密码", subtitle: "请输入关联的邮箱来验证身份")
|
headerSection(title: "重置密码", subtitle: "请输入关联的邮箱来验证身份")
|
||||||
|
|
||||||
PunchTextField(icon: "person.crop.circle", placeholder: "邮箱", text: $username)
|
PunchTextField(icon: "person.crop.circle", placeholder: "邮箱", text: $model.username)
|
||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
self.sendVerifyCode()
|
Task { @MainActor in
|
||||||
|
await self.sendVerifyCode(username: model.username)
|
||||||
|
}
|
||||||
} label: {
|
} label: {
|
||||||
Text("获取验证码")
|
Text("获取验证码")
|
||||||
.fontWeight(.medium)
|
.fontWeight(.medium)
|
||||||
@ -89,7 +92,7 @@ struct GetVerifyCodeView: View {
|
|||||||
.buttonStyle(.borderedProminent)
|
.buttonStyle(.borderedProminent)
|
||||||
.controlSize(.large)
|
.controlSize(.large)
|
||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
.disabled(!SDLUtil.isValidIdentifyContact(username) || isProcessing)
|
.disabled(!SDLUtil.isValidIdentifyContact(model.username) || isProcessing)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
@ -100,30 +103,31 @@ struct GetVerifyCodeView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送验证码
|
// 发送验证码
|
||||||
private func sendVerifyCode() {
|
private func sendVerifyCode(username: String) async {
|
||||||
self.isProcessing = true
|
self.isProcessing = true
|
||||||
Task { @MainActor in
|
defer {
|
||||||
do {
|
|
||||||
let resetSession = try await resetPasswordModel.requestVerifyCode(username: username)
|
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
|
||||||
resetPasswordModel.stage = .submitVerifyCode(username: username, sessionId: resetSession.sessionId)
|
|
||||||
resetPasswordModel.transitionEdge = .trailing
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
self.errorMessage = error.localizedDescription
|
|
||||||
self.showAlert = true
|
|
||||||
}
|
|
||||||
self.isProcessing = false
|
self.isProcessing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
let resetSession = try await resetPasswordModel.requestVerifyCode(username: username)
|
||||||
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
|
self.resetPasswordModel.stage = .submitVerifyCode
|
||||||
|
self.resetPasswordModel.sessionId = resetSession.sessionId
|
||||||
|
|
||||||
|
self.resetPasswordModel.transitionEdge = .trailing
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
self.errorMessage = error.localizedDescription
|
||||||
|
self.showAlert = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - 3. 第二步:验证验证码
|
// MARK: - 3. 第二步:验证验证码
|
||||||
struct SubmitVerifyCodeView: View {
|
struct SubmitVerifyCodeView: View {
|
||||||
@Environment(ResetPasswordModel.self) var resetPasswordModel
|
@Environment(ResetPasswordModel.self) var resetPasswordModel: ResetPasswordModel
|
||||||
let username: String
|
|
||||||
let sessionId: Int
|
|
||||||
|
|
||||||
@State private var code: String = ""
|
@State private var code: String = ""
|
||||||
@State private var isProcessing = false
|
@State private var isProcessing = false
|
||||||
@ -142,13 +146,15 @@ struct SubmitVerifyCodeView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 24) {
|
VStack(spacing: 24) {
|
||||||
headerSection(title: "身份验证", subtitle: "验证码已发送至 \(username)")
|
headerSection(title: "身份验证", subtitle: "验证码已发送至 \(self.resetPasswordModel.username)")
|
||||||
|
|
||||||
VStack(alignment: .trailing, spacing: 16) {
|
VStack(alignment: .trailing, spacing: 16) {
|
||||||
PunchTextField(icon: "envelope.badge", placeholder: "输入 6 位验证码", text: $code)
|
PunchTextField(icon: "envelope.badge", placeholder: "输入 6 位验证码", text: $code)
|
||||||
|
|
||||||
Button(isResendEnabled ? "重新获取" : "重新获取 (\(remainingSeconds)s)") {
|
Button(isResendEnabled ? "重新获取" : "重新获取 (\(remainingSeconds)s)") {
|
||||||
self.resendAction()
|
Task { @MainActor in
|
||||||
|
await self.resendAction(username: self.resetPasswordModel.username)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(.link)
|
.buttonStyle(.link)
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
@ -158,7 +164,9 @@ struct SubmitVerifyCodeView: View {
|
|||||||
|
|
||||||
VStack(spacing: 12) {
|
VStack(spacing: 12) {
|
||||||
Button {
|
Button {
|
||||||
self.submitAction()
|
Task { @MainActor in
|
||||||
|
await self.submitAction(sessionId: self.resetPasswordModel.sessionId)
|
||||||
|
}
|
||||||
} label: {
|
} label: {
|
||||||
Text("验证并继续")
|
Text("验证并继续")
|
||||||
.fontWeight(.medium)
|
.fontWeight(.medium)
|
||||||
@ -170,7 +178,7 @@ struct SubmitVerifyCodeView: View {
|
|||||||
|
|
||||||
Button("返回上一步") {
|
Button("返回上一步") {
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
self.resetPasswordModel.stage = .requestVerifyCode(username: self.username)
|
self.resetPasswordModel.stage = .requestVerifyCode
|
||||||
self.resetPasswordModel.transitionEdge = .leading
|
self.resetPasswordModel.transitionEdge = .leading
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,11 +198,9 @@ struct SubmitVerifyCodeView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func resendAction() {
|
private func resendAction(username: String) async {
|
||||||
Task {
|
_ = try? await resetPasswordModel.requestVerifyCode(username: username)
|
||||||
_ = try? await resetPasswordModel.requestVerifyCode(username: username)
|
await startCountdown()
|
||||||
await startCountdown()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func startCountdown() async {
|
private func startCountdown() async {
|
||||||
@ -207,31 +213,34 @@ struct SubmitVerifyCodeView: View {
|
|||||||
self.isResendEnabled = true
|
self.isResendEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private func submitAction() {
|
private func submitAction(sessionId: Int) async {
|
||||||
self.isProcessing = true
|
self.isProcessing = true
|
||||||
Task { @MainActor in
|
defer {
|
||||||
do {
|
|
||||||
let result = try await resetPasswordModel.submitVerifyCode(sessionId: sessionId, verifyCode: code)
|
|
||||||
NSLog("reset password submit verify code result: \(result)")
|
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
|
||||||
self.resetPasswordModel.stage = .resetPassword(username: username, sessionId: sessionId)
|
|
||||||
self.resetPasswordModel.transitionEdge = .trailing
|
|
||||||
}
|
|
||||||
} catch let err as SDLAPIError {
|
|
||||||
self.errorMessage = err.message
|
|
||||||
self.showAlert = true
|
|
||||||
}
|
|
||||||
self.isProcessing = false
|
self.isProcessing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
let result = try await resetPasswordModel.submitVerifyCode(sessionId: sessionId, verifyCode: code)
|
||||||
|
NSLog("reset password submit verify code result: \(result)")
|
||||||
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
|
self.resetPasswordModel.stage = .resetPassword
|
||||||
|
self.resetPasswordModel.transitionEdge = .trailing
|
||||||
|
}
|
||||||
|
} catch let err as SDLAPIError {
|
||||||
|
self.showAlert = true
|
||||||
|
self.errorMessage = err.message
|
||||||
|
} catch let err {
|
||||||
|
self.showAlert = true
|
||||||
|
self.errorMessage = err.localizedDescription
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - 4. 第三步:重置密码
|
// MARK: - 4. 第三步:重置密码
|
||||||
struct ResetPasswordView: View {
|
struct ResetPasswordView: View {
|
||||||
@Environment(ResetPasswordModel.self) var resetPasswordModel
|
@Environment(ResetPasswordModel.self) var resetPasswordModel: ResetPasswordModel
|
||||||
let username: String
|
|
||||||
let sessionId: Int
|
|
||||||
@State private var password = ""
|
@State private var password = ""
|
||||||
@State private var confirm = ""
|
@State private var confirm = ""
|
||||||
@State private var isProcessing = false
|
@State private var isProcessing = false
|
||||||
@ -264,7 +273,7 @@ struct ResetPasswordView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 24) {
|
VStack(spacing: 24) {
|
||||||
headerSection(title: "设置新密码", subtitle: "请为账号 \(username) 设置一个强密码")
|
headerSection(title: "设置新密码", subtitle: "请为账号 \(self.resetPasswordModel.username) 设置一个强密码")
|
||||||
|
|
||||||
VStack(spacing: 12) {
|
VStack(spacing: 12) {
|
||||||
PunchTextField(icon: "lock.shield", placeholder: "新密码 (至少8位)", text: $password, isSecure: true)
|
PunchTextField(icon: "lock.shield", placeholder: "新密码 (至少8位)", text: $password, isSecure: true)
|
||||||
@ -280,7 +289,9 @@ struct ResetPasswordView: View {
|
|||||||
.frame(width: 280)
|
.frame(width: 280)
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
self.handleReset()
|
Task { @MainActor in
|
||||||
|
await self.handleReset(sessionId: self.resetPasswordModel.sessionId)
|
||||||
|
}
|
||||||
} label: {
|
} label: {
|
||||||
Text("重置密码并登录")
|
Text("重置密码并登录")
|
||||||
.fontWeight(.medium)
|
.fontWeight(.medium)
|
||||||
@ -299,29 +310,31 @@ struct ResetPasswordView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleReset() {
|
private func handleReset(sessionId: Int) async {
|
||||||
self.isProcessing = true
|
self.isProcessing = true
|
||||||
Task { @MainActor in
|
defer {
|
||||||
do {
|
|
||||||
let result = try await resetPasswordModel.resetPassword(sessionId: sessionId, newPassword: password)
|
|
||||||
print("密码重置成功: \(result)")
|
|
||||||
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
|
||||||
self.resetPasswordModel.stage = .success
|
|
||||||
self.resetPasswordModel.transitionEdge = .trailing
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
self.showAlert = true
|
|
||||||
self.errorMessage = "重置失败, 请稍后重试"
|
|
||||||
}
|
|
||||||
self.isProcessing = false
|
self.isProcessing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
let result = try await resetPasswordModel.resetPassword(sessionId: sessionId, newPassword: password)
|
||||||
|
print("密码重置成功: \(result)")
|
||||||
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
|
self.resetPasswordModel.stage = .success
|
||||||
|
self.resetPasswordModel.transitionEdge = .trailing
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
self.showAlert = true
|
||||||
|
self.errorMessage = "重置失败, 请稍后重试"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ResetPasswordSuccessView: View {
|
struct ResetPasswordSuccessView: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(AppContext.self) var appContext: AppContext
|
||||||
|
@Environment(ResetPasswordModel.self) var resetPasswordModel: ResetPasswordModel
|
||||||
|
|
||||||
// 动画状态
|
// 动画状态
|
||||||
@State private var animateIcon = false
|
@State private var animateIcon = false
|
||||||
@State private var animateText = false
|
@State private var animateText = false
|
||||||
@ -357,7 +370,9 @@ struct ResetPasswordSuccessView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
dismiss() // 关闭重置窗口
|
withAnimation(.spring(duration: 0.6, bounce: 0.2)) {
|
||||||
|
self.appContext.appScene = .login(username: self.resetPasswordModel.username)
|
||||||
|
}
|
||||||
}) {
|
}) {
|
||||||
Text("返回登录")
|
Text("返回登录")
|
||||||
.fontWeight(.bold)
|
.fontWeight(.bold)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user