yggdrasil/pages/
register.rs1use dioxus::prelude::*;
7use dioxus::router::components::Link;
8
9use crate::api::auth::{register, AuthResponse};
10use crate::components::forms::{AlertBox, FormInput, FormLabel, BUTTON_PRIMARY_CLASS};
11use crate::router::Route;
12
13#[component]
15pub fn Register() -> Element {
16 let mut username = use_signal(|| "".to_string());
18 let mut email = use_signal(|| "".to_string());
19 let mut password = use_signal(|| "".to_string());
20 let mut confirm_password = use_signal(|| "".to_string());
21 let mut error = use_signal(|| None::<String>);
23 let mut success = use_signal(|| false);
24 let mut loading = use_signal(|| false);
25
26 let on_submit = Callback::new(move |_| {
28 if loading() {
29 return;
30 }
31 error.set(None);
32 success.set(false);
33
34 if password().len() < 8 {
36 error.set(Some("密码长度至少 8 位".to_string()));
37 return;
38 }
39 if password() != confirm_password() {
40 error.set(Some("两次输入的密码不一致".to_string()));
41 return;
42 }
43
44 let username_val = username();
45 let email_val = email();
46 let password_val = password();
47
48 loading.set(true);
49
50 spawn(async move {
52 match register(username_val, email_val, password_val).await {
53 Ok(AuthResponse { success: true, .. }) => {
54 success.set(true);
55 }
56 Ok(AuthResponse {
57 success: false,
58 message,
59 ..
60 }) => {
61 error.set(Some(message));
62 }
63 Err(e) => {
64 error.set(Some(format!("请求失败: {}", e)));
65 }
66 }
67 loading.set(false);
68 });
69 });
70
71 let is_loading = loading();
72
73 rsx! {
74 div { class: "min-h-screen flex items-center justify-center bg-paper-theme",
75 div { class: "w-full max-w-md p-8 bg-paper-entry rounded-2xl border border-paper-border shadow-sm",
76 h1 { class: "text-2xl font-bold text-center text-paper-primary mb-2",
77 "注册"
78 }
79 p { class: "text-sm text-center text-paper-secondary mb-6",
80 "首个注册账号将自动成为管理员"
81 }
82
83 if success() {
84 div { class: "mb-4 p-3 bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300 rounded-lg text-center",
85 "注册成功!"
86 Link {
87 class: "block mt-2 text-paper-accent hover:underline cursor-pointer",
88 to: Route::Login {},
89 "去登录"
90 }
91 }
92 }
93
94 if let Some(err) = error() {
95 AlertBox { message: err, variant: "error" }
96 }
97
98 div { class: "space-y-4",
99 div {
100 FormLabel {
101 label: "用户名",
102 html_for: Some("register-username".to_string()),
103 }
104 FormInput {
105 id: Some("register-username".to_string()),
106 r#type: "text",
107 placeholder: "3-50 位字符",
108 value: username(),
109 disabled: is_loading,
110 oninput: move |v: String| username.set(v),
111 onkeydown: Some(
113 EventHandler::new(move |e: KeyboardEvent| {
114 if e.key() == Key::Enter {
115 on_submit(())
116 }
117 }),
118 ),
119 }
120 }
121 div {
122 FormLabel {
123 label: "邮箱",
124 html_for: Some("register-email".to_string()),
125 }
126 FormInput {
127 id: Some("register-email".to_string()),
128 r#type: "email",
129 placeholder: "your@email.com",
130 value: email(),
131 disabled: is_loading,
132 oninput: move |v: String| email.set(v),
133 onkeydown: Some(
135 EventHandler::new(move |e: KeyboardEvent| {
136 if e.key() == Key::Enter {
137 on_submit(())
138 }
139 }),
140 ),
141 }
142 }
143 div {
144 FormLabel {
145 label: "密码",
146 html_for: Some("register-password".to_string()),
147 }
148 FormInput {
149 id: Some("register-password".to_string()),
150 r#type: "password",
151 placeholder: "至少 8 位",
152 value: password(),
153 disabled: is_loading,
154 oninput: move |v: String| password.set(v),
155 onkeydown: Some(
157 EventHandler::new(move |e: KeyboardEvent| {
158 if e.key() == Key::Enter {
159 on_submit(())
160 }
161 }),
162 ),
163 }
164 }
165 div {
166 FormLabel {
167 label: "确认密码",
168 html_for: Some("register-confirm-password".to_string()),
169 }
170 FormInput {
171 id: Some("register-confirm-password".to_string()),
172 r#type: "password",
173 placeholder: "再次输入密码",
174 value: confirm_password(),
175 disabled: is_loading,
176 oninput: move |v: String| confirm_password.set(v),
177 onkeydown: Some(
179 EventHandler::new(move |e: KeyboardEvent| {
180 if e.key() == Key::Enter {
181 on_submit(())
182 }
183 }),
184 ),
185 }
186 }
187 button {
188 class: "{BUTTON_PRIMARY_CLASS}",
189 class: if is_loading { "opacity-60 cursor-not-allowed" },
190 disabled: is_loading,
191 onclick: move |_| on_submit(()),
192 if is_loading {
193 "注册中..."
194 } else {
195 "注册"
196 }
197 }
198 }
199 p { class: "mt-4 text-center text-sm text-paper-secondary",
200 "已有账号?"
201 Link {
202 class: "text-paper-accent hover:underline cursor-pointer",
203 to: Route::Login {},
204 "去登录"
205 }
206 }
207 }
208 }
209 }
210}