This commit is contained in:
parent
ef9c607e6b
commit
1e4da027ea
|
|
@ -6,59 +6,66 @@ import reflex as rx
|
||||||
from application.pages.index import render_index
|
from application.pages.index import render_index
|
||||||
|
|
||||||
app = rx.App(
|
app = rx.App(
|
||||||
|
theme=rx.theme(),
|
||||||
style={
|
style={
|
||||||
"root": {
|
"--prismui-background-color-1": "#ffffff", # 背景颜色:白色
|
||||||
"font-family": "HuaweiFont,Helvetica,Arial,PingFangSC-Regular,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Microsoft JhengHei",
|
|
||||||
},
|
|
||||||
"*": {
|
|
||||||
"margin": "0",
|
|
||||||
"padding": "0",
|
|
||||||
"box_sizing": "border-box",
|
|
||||||
"background-color": "transparent",
|
|
||||||
"gap": "0",
|
|
||||||
},
|
|
||||||
# 覆盖伪元素 ::before 和 ::after
|
|
||||||
"*::before, *::after": {
|
|
||||||
"box_sizing": "border-box",
|
|
||||||
},
|
|
||||||
"--prismui-background-1": "linear-gradient(to bottom, #D0C9FF 0%, #E6D6F0 8%, #F1DBEA 12%, #C8DCFB 40%, #ABC6F6 60%, #87AEFE 90%)",
|
|
||||||
"--prismui-background-color-1": "#ffffff", # 纯白背景色
|
|
||||||
"--prismui-background-color-2": "#ebebeb",
|
"--prismui-background-color-2": "#ebebeb",
|
||||||
"--prismui-background-color-3": "#f6f6f8",
|
"--prismui-background-color-3": "#f6f6f8",
|
||||||
"--prismui-background-color-4": "#babbc0",
|
"--prismui-background-color-4": "#babbc0",
|
||||||
|
"--prismui-background-1": "linear-gradient(to bottom, #D0C9FF 0%, #E6D6F0 8%, #F1DBEA 12%, #C8DCFB 40%, #ABC6F6 60%, #87AEFE 90%)", # 背景:用于主页面渐变背景
|
||||||
|
"--prismui-font-family": "HuaweiFont,Helvetica,Arial,PingFangSC-Regular,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Microsoft JhengHei", # 字体
|
||||||
|
"--prismui-font-size-1": "12px",
|
||||||
|
"--prismui-font-size-2": "14px", # 字体大小:常用于正文
|
||||||
|
"--prismui-font-size-3": "20px",
|
||||||
|
"--prismui-font-weight-1": "normal", # 字体粗细:常用于正文
|
||||||
|
"--prismui-font-weight-2": "500",
|
||||||
|
"--prismui-font-weight-3": "700",
|
||||||
|
"--prismui-color-1": "#252b3a", # 颜色:深灰色,常用于标题和正文颜色
|
||||||
|
"--prismui-color-2": "#575d6c", # 颜色:中灰色,常用于副标题
|
||||||
|
"--prismui-color-3": "#babbc0", # 颜色:浅灰色,常用于占位符
|
||||||
|
"--prismui-color-4": "rgba(6, 10, 38, 0.24)", # 颜色:浅灰色,常用于不可点击元素
|
||||||
|
"--prismui-color-5": "#5e7ce0", # 颜色:蓝色,常用于可点击元素
|
||||||
|
"--prismui-color-6": "#f66f6a", # 颜色:红色,常用于错误提示
|
||||||
|
"--prismui-border-1": "1px solid rgba(6, 10, 38, 0.06)", # 边框样式
|
||||||
"--mc-float-block-shadow": "#d5d5d5",
|
"--mc-float-block-shadow": "#d5d5d5",
|
||||||
"--devui-global-bg": "#f6f6f8",
|
"--devui-global-bg": "#f6f6f8",
|
||||||
"--mc-global-bg": "linear-gradient(to bottom, #D0C9FF 0%, #E6D6F0 8%, #F1DBEA 12%, #C8DCFB 40%, #ABC6F6 60%, #87AEFE 90%)",
|
"--mc-global-bg": "linear-gradient(to bottom, #D0C9FF 0%, #E6D6F0 8%, #F1DBEA 12%, #C8DCFB 40%, #ABC6F6 60%, #87AEFE 90%)",
|
||||||
"--mc-box-shadow": "#191919",
|
"--mc-box-shadow": "#191919",
|
||||||
"--devui-shadow-length-connected-overlay": "0px 0px 12px 0px #000000",
|
"--devui-shadow-length-connected-overlay": "0px 0px 12px 0px #000000",
|
||||||
"--prismui-box-shadow-1": "0 4px 12px #0000001a", # 导航按钮阴影
|
"--prismui-box-shadow-1": "0 4px 64px 0 #0000001a", # 登录卡片阴影
|
||||||
|
"--prismui-box-shadow-2": "0 4px 12px #0000001a", # 导航按钮阴影
|
||||||
"--devui-icon-fill-weak": "#babbc0",
|
"--devui-icon-fill-weak": "#babbc0",
|
||||||
"--prismui-background-color-weak": "#babbc0",
|
"--prismui-background-color-weak": "#babbc0",
|
||||||
"--devui-border-radius-feedback": "4px",
|
"--devui-border-radius-feedback": "4px",
|
||||||
|
"--prismui-border-1": "1px solid rgba(6, 10, 38, 0.06)",
|
||||||
"--prismui-border-radius": "8px",
|
"--prismui-border-radius": "8px",
|
||||||
"--prismui-border-radius-1": "8px",
|
"--prismui-border-radius-1": "8px",
|
||||||
|
"--prismui-border-radius-2": "12px",
|
||||||
|
"--prismui-border-radius-3": "20px",
|
||||||
"--devui-border-radius-full": "100px",
|
"--devui-border-radius-full": "100px",
|
||||||
"--font-family": "HuaweiFont,Helvetica,Arial,PingFangSC-Regular,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Microsoft JhengHei",
|
"box-shadow": "none",
|
||||||
"--prismui-font-size": "14px",
|
"background-color": "var(--prismui-background-color-1)", # 默认背景颜色
|
||||||
"--prismui-font-size-1": "14px",
|
"font_family": "var(--prismui-font-family)",
|
||||||
"--prismui-font-size-2": "12px",
|
"font_size": "var(--prismui-font-size-2)",
|
||||||
"--prismui-font-size-sm": "12px",
|
"font_weight": "var(--prismui-font-weight-1)",
|
||||||
"--prismui-font-weight-1": "700",
|
"color": "var(--prismui-color-1)",
|
||||||
"--devui-font-size": "14px",
|
"*": {
|
||||||
"--devui-font-size-lg": "14px",
|
"margin": "0",
|
||||||
"--prismui-color-text": "#252b3a",
|
"padding": "0",
|
||||||
"--prismui-color-text-light": "#babbc0",
|
"gap": "0",
|
||||||
"--prismui-color-1": "#252b3a", # 文本颜色
|
},
|
||||||
"--prismui-color-2": "#575d6c",
|
"*::before, *::after": {
|
||||||
"--prismui-color-3": "#babbc0",
|
"box-sizing": "border-box",
|
||||||
"--devui-text-weak": "#575d6c",
|
},
|
||||||
"--devui-light-text": "#ffffff",
|
"* .rt-TextFieldRoot, * textarea": {
|
||||||
"--placeholder": "#babbc0",
|
"border": "var(--prismui-border-1)",
|
||||||
"--devui-aide-text": "#71757f",
|
"outline": "none",
|
||||||
"--devui-primary": "#5e7ce0",
|
"box-shadow": "none",
|
||||||
"--devui-brand": "#5e7ce0",
|
},
|
||||||
"--devui-brand-hover": "#7693f5",
|
"*::placeholder": {
|
||||||
"--devui-dividing-line": "#f2f2f3",
|
"color": "var(--prismui-color-3)",
|
||||||
|
"opacity": 1,
|
||||||
|
}, # 覆盖占位符样式
|
||||||
}, # 自定义主题颜色
|
}, # 自定义主题颜色
|
||||||
) # 此处变量名需使用 app ,具体原因目前尚不清楚
|
) # 此处变量名需使用 app ,具体原因目前尚不清楚
|
||||||
# 注册首页路由
|
# 注册首页路由
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ def render_nav_button(
|
||||||
is_actived, "var(--prismui-background-color-1)", "transparent"
|
is_actived, "var(--prismui-background-color-1)", "transparent"
|
||||||
),
|
),
|
||||||
border_radius="var(--prismui-border-radius-1)",
|
border_radius="var(--prismui-border-radius-1)",
|
||||||
box_shadow=rx.cond(is_actived, "var(--prismui-box-shadow-1)", "none"),
|
box_shadow=rx.cond(is_actived, "var(--prismui-box-shadow-2)", "none"),
|
||||||
),
|
),
|
||||||
# 渲染标签
|
# 渲染标签
|
||||||
rx.text(
|
rx.text(
|
||||||
|
|
@ -126,39 +126,95 @@ def render_login_window() -> rx.Component:
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
rx.text(
|
rx.text(
|
||||||
"登录",
|
"登录解锁更多功能",
|
||||||
font_size="20px",
|
line_height="32px",
|
||||||
font_weight="600",
|
font_size="var(--prismui-font-size-3)",
|
||||||
|
font_weight="var(--prismui-font-weight-2)",
|
||||||
margin_bottom="24px",
|
margin_bottom="24px",
|
||||||
),
|
),
|
||||||
rx.input(
|
rx.input(
|
||||||
placeholder="请输入邮箱地址",
|
placeholder="请输入邮箱地址",
|
||||||
value=AuthState.email,
|
value=AuthState.email,
|
||||||
on_change=AuthState.set_email,
|
|
||||||
width="100%",
|
width="100%",
|
||||||
|
height="45px",
|
||||||
|
margin_bottom="24px",
|
||||||
|
padding="4px",
|
||||||
|
border_radius="var(--prismui-border-radius-2)",
|
||||||
|
line_height="16px",
|
||||||
|
# 值变化事件:设置邮箱
|
||||||
|
on_change=AuthState.set_email,
|
||||||
|
# 获取焦点事件:清除提示信息
|
||||||
|
on_focus=AuthState.reset_notification,
|
||||||
),
|
),
|
||||||
|
# 自定义验证码输入框
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
rx.input(
|
rx.input(
|
||||||
placeholder="请输入验证码",
|
placeholder="请输入验证码",
|
||||||
|
max_length=6,
|
||||||
value=AuthState.captcha,
|
value=AuthState.captcha,
|
||||||
on_change=AuthState.set_captcha,
|
|
||||||
flex=1,
|
flex=1,
|
||||||
|
height="100%",
|
||||||
|
padding="4px",
|
||||||
|
line_height="16px",
|
||||||
|
border="none",
|
||||||
|
# 值变化事件:设置验证码
|
||||||
|
on_change=AuthState.set_captcha,
|
||||||
|
style={
|
||||||
|
"&": {
|
||||||
|
"border": "none !important",
|
||||||
|
}, # 清除父元素边框
|
||||||
|
},
|
||||||
),
|
),
|
||||||
rx.button(
|
rx.text(
|
||||||
|
# 若验证码发送倒计时大于0则显示倒计时,否则显示获取验证码
|
||||||
rx.cond(
|
rx.cond(
|
||||||
AuthState.captcha_sending_countdown > 0,
|
AuthState.captcha_sending_countdown,
|
||||||
f"{AuthState.captcha_sending_countdown} s111111",
|
f"{AuthState.captcha_sending_countdown} s",
|
||||||
"获取验证码",
|
"获取验证码",
|
||||||
),
|
),
|
||||||
variant="outline",
|
margin="0 8px",
|
||||||
width="120px",
|
line_height="16px",
|
||||||
|
color=rx.cond(
|
||||||
|
AuthState.is_captcha_sending_disabled,
|
||||||
|
"var(--prismui-color-4)",
|
||||||
|
"var(--prismui-color-5)",
|
||||||
|
),
|
||||||
|
cursor="pointer",
|
||||||
on_click=AuthState.send_captcha,
|
on_click=AuthState.send_captcha,
|
||||||
disabled=AuthState.captcha_sending_countdown > 0,
|
|
||||||
),
|
),
|
||||||
gap="8px",
|
|
||||||
width="100%",
|
width="100%",
|
||||||
|
height="45px",
|
||||||
|
align_items="center",
|
||||||
|
border="var(--prismui-border-1)",
|
||||||
|
border_radius="var(--prismui-border-radius-2)",
|
||||||
|
),
|
||||||
|
rx.cond(
|
||||||
|
AuthState.captcha_sending_countdown,
|
||||||
|
rx.hstack(
|
||||||
|
rx.icon(
|
||||||
|
"circle-check",
|
||||||
|
width="14px",
|
||||||
|
height="14px",
|
||||||
|
color="var(--prismui-color-2)",
|
||||||
|
),
|
||||||
|
rx.text(
|
||||||
|
"验证码已发送,请耐心等待",
|
||||||
|
line_height="14px",
|
||||||
|
font_size="var(--prismui-font-size-1)",
|
||||||
|
color="var(--prismui-color-2)",
|
||||||
|
),
|
||||||
|
margin="10px 0",
|
||||||
|
gap="4px",
|
||||||
|
),
|
||||||
|
rx.text(
|
||||||
|
AuthState.notification,
|
||||||
|
width="100%",
|
||||||
|
text_align="left",
|
||||||
|
line_height="20px",
|
||||||
|
font_size="12px",
|
||||||
|
color="var(--prismui-color-6)",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
rx.text(AuthState.notification, color="red", font_size="12px"),
|
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
rx.checkbox(
|
rx.checkbox(
|
||||||
checked=AuthState.is_policies_agreed,
|
checked=AuthState.is_policies_agreed,
|
||||||
|
|
@ -184,12 +240,11 @@ def render_login_window() -> rx.Component:
|
||||||
color="#666",
|
color="#666",
|
||||||
margin_top="8px",
|
margin_top="8px",
|
||||||
),
|
),
|
||||||
width="360px",
|
width="396px",
|
||||||
gap="16px",
|
padding="40px 48px 0 48px",
|
||||||
padding="40px 32px",
|
background_color="var(--prismui-background-color-1)",
|
||||||
align_items="start",
|
align_items="center",
|
||||||
),
|
),
|
||||||
rx.divider(orientation="vertical"),
|
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
rx.image(
|
rx.image(
|
||||||
src="/qrcode.png",
|
src="/qrcode.png",
|
||||||
|
|
@ -211,15 +266,18 @@ def render_login_window() -> rx.Component:
|
||||||
padding="40px 32px",
|
padding="40px 32px",
|
||||||
style={"background": "#f8f9fc"},
|
style={"background": "#f8f9fc"},
|
||||||
),
|
),
|
||||||
|
border="1px solid #2222220f",
|
||||||
|
border_radius="var(--prismui-border-radius-3)",
|
||||||
|
box_shadow="0 4px 64px 0 #0000001a",
|
||||||
|
overflow="hidden",
|
||||||
),
|
),
|
||||||
position="fixed",
|
position="absolute",
|
||||||
top="0",
|
top="0",
|
||||||
left="0",
|
left="0",
|
||||||
|
z_index="9999",
|
||||||
width="100vw",
|
width="100vw",
|
||||||
height="100vh",
|
height="100vh",
|
||||||
bg="rgba(255, 255, 255, 0.85)",
|
backdrop_filter="blur(4px)",
|
||||||
z_index="9999",
|
|
||||||
overflow="hidden",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import re
|
||||||
from typing import Any, AsyncGenerator, Coroutine, cast
|
from typing import Any, AsyncGenerator, Coroutine, cast
|
||||||
from aiosmtplib import SMTP, SMTPException
|
from aiosmtplib import SMTP, SMTPException
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
from reflex.event import EventCallback
|
||||||
|
|
||||||
from application.states.database import DatabaseState
|
from application.states.database import DatabaseState
|
||||||
|
|
||||||
|
|
@ -52,6 +53,14 @@ class AuthState(rx.State):
|
||||||
|
|
||||||
self.user_id = ""
|
self.user_id = ""
|
||||||
|
|
||||||
|
@rx.event
|
||||||
|
def reset_notification(self) -> None:
|
||||||
|
"""
|
||||||
|
清除提示信息
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
self.notification = ""
|
||||||
|
|
||||||
@rx.event
|
@rx.event
|
||||||
def set_email(self, email: str) -> None:
|
def set_email(self, email: str) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
@ -61,65 +70,50 @@ class AuthState(rx.State):
|
||||||
"""
|
"""
|
||||||
self.email = email.strip()
|
self.email = email.strip()
|
||||||
|
|
||||||
@rx.event
|
@rx.var
|
||||||
def set_captcha(self, captcha: str) -> None:
|
def is_captcha_sending_disabled(self) -> bool:
|
||||||
"""
|
"""
|
||||||
设置验证码
|
验证码发送禁用状态
|
||||||
:param captcha: 验证码
|
:return: 禁用状态,True 表示禁用,False 表示未禁用
|
||||||
:return: None
|
|
||||||
"""
|
"""
|
||||||
self.captcha = captcha.strip()
|
|
||||||
|
|
||||||
@rx.event
|
|
||||||
def toggle_policies_agreed(self) -> None:
|
|
||||||
"""
|
"""
|
||||||
切换协议同意状态
|
邮箱为空或验证码发送倒计时大于0时禁用
|
||||||
:return: None
|
|
||||||
"""
|
"""
|
||||||
self.is_policies_agreed = not self.is_policies_agreed
|
return not self.email or self.captcha_sending_countdown > 0
|
||||||
|
|
||||||
def validate_email(self) -> bool:
|
def validate_email(self) -> bool:
|
||||||
"""
|
"""
|
||||||
验证邮箱
|
校验邮箱
|
||||||
:return: 验证是否通过,True 表示校验通过,False 表示校验不通过
|
:return: 校验结果,True 表示校验通过,False 表示校验不通过
|
||||||
"""
|
"""
|
||||||
self.notification = ""
|
|
||||||
# 非空校验
|
# 非空校验
|
||||||
if not self.email:
|
if not self.email:
|
||||||
self.notification = "请输入邮箱"
|
self.notification = "请输入邮箱"
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 格式校验
|
# 格式校验
|
||||||
|
"""
|
||||||
|
邮箱由用户名@域名组成,其中:
|
||||||
|
1)用户名首字符为字母或数字,中间可穿插下划线、短横线、加号或点,符号后为字母或数字;
|
||||||
|
2)域名由若干子域名段和顶级域名段组成,各段之间用点分隔,其中:
|
||||||
|
-- 子域名段:首字符为字母或数字,中间可穿插下划线或短横线,符号后为字母或数字;
|
||||||
|
-- 顶级域名段:至少包含两个字母或数字;
|
||||||
|
"""
|
||||||
if not re.fullmatch(
|
if not re.fullmatch(
|
||||||
r"^[a-zA-Z0-9]+([_\-+.][a-zA-Z0-9_\-+]+)*@[a-zA-Z0-9]+(\-[a-zA-Z0-9\-]+)*(\.[a-zA-Z0-9]+(\-[a-zA-Z0-9\-]+)*)*\.[a-zA-Z0-9]{2,}$",
|
r"^[a-zA-Z0-9]+([_\-+.][a-zA-Z0-9_\-+]+)*@[a-zA-Z0-9]+(\-[a-zA-Z0-9\-]+)*(\.[a-zA-Z0-9]+(\-[a-zA-Z0-9\-]+)*)*\.[a-zA-Z0-9]{2,}$",
|
||||||
self.email,
|
self.email,
|
||||||
):
|
):
|
||||||
self.notification = "邮箱格式不正确,请重新输入"
|
self.notification = "邮箱格式不正确,请重新输入"
|
||||||
return False
|
return False
|
||||||
return True
|
|
||||||
|
|
||||||
def validate_captcha(self) -> bool:
|
|
||||||
"""
|
|
||||||
验证验证码
|
|
||||||
:return: 验证是否通过,True 表示校验通过,False 表示校验不通过
|
|
||||||
"""
|
|
||||||
self.notification = ""
|
self.notification = ""
|
||||||
# 非空校验
|
|
||||||
if not self.captcha:
|
|
||||||
self.notification = "请输入验证码"
|
|
||||||
return False
|
|
||||||
# 格式校验
|
|
||||||
if not re.fullmatch(r"^\d{6}$", self.captcha):
|
|
||||||
self.notification = "验证码格式不正确,请重新输入"
|
|
||||||
return False
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@rx.event(background=True)
|
@rx.event(background=True)
|
||||||
async def resend_captcha_countdown(self) -> None:
|
async def resend_captcha_countdown_(self) -> None:
|
||||||
"""
|
"""
|
||||||
重新发送验证码倒计时
|
再次发送验证码倒计时(后台任务)
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
async with self:
|
async with self:
|
||||||
self.captcha_sending_countdown = 59
|
self.captcha_sending_countdown = 59
|
||||||
|
|
||||||
|
|
@ -131,7 +125,7 @@ class AuthState(rx.State):
|
||||||
@rx.event(background=True)
|
@rx.event(background=True)
|
||||||
async def send_captcha_(self) -> None:
|
async def send_captcha_(self) -> None:
|
||||||
"""
|
"""
|
||||||
发送验证码
|
发送验证码(后台任务)
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
async with self:
|
async with self:
|
||||||
|
|
@ -140,7 +134,7 @@ class AuthState(rx.State):
|
||||||
database_state = await self.get_state(DatabaseState)
|
database_state = await self.get_state(DatabaseState)
|
||||||
captcha = await database_state.create_captchas_record(email=self.email)
|
captcha = await database_state.create_captchas_record(email=self.email)
|
||||||
|
|
||||||
# 构建邮件
|
# 构建验证码邮件
|
||||||
message = MIMEText(
|
message = MIMEText(
|
||||||
CAPTCHA_HTML_TEMPLATE.format(captcha=captcha),
|
CAPTCHA_HTML_TEMPLATE.format(captcha=captcha),
|
||||||
"html",
|
"html",
|
||||||
|
|
@ -166,21 +160,52 @@ class AuthState(rx.State):
|
||||||
self.captcha_sending_countdown = 0
|
self.captcha_sending_countdown = 0
|
||||||
|
|
||||||
@rx.event
|
@rx.event
|
||||||
async def send_captcha(self) -> AsyncGenerator:
|
async def send_captcha(self) -> AsyncGenerator[EventCallback, None]:
|
||||||
"""
|
"""
|
||||||
发送验证码
|
发送验证码
|
||||||
:return: None
|
:return: AsyncGenerator[EventCallback, None]
|
||||||
"""
|
"""
|
||||||
self.notification = ""
|
# 校验邮箱
|
||||||
|
|
||||||
# 验证邮箱
|
|
||||||
if not self.validate_email():
|
if not self.validate_email():
|
||||||
return
|
return
|
||||||
|
|
||||||
# 将重新发送验证码倒计时和发送验证码事件添加至后台任务队列
|
# 将再次发送验证码倒计时和发送验证码事件添加至后台任务队列
|
||||||
yield type(self).resend_captcha_countdown
|
yield type(self).resend_captcha_countdown_
|
||||||
yield type(self).send_captcha_
|
yield type(self).send_captcha_
|
||||||
|
|
||||||
|
@rx.event
|
||||||
|
def set_captcha(self, captcha: str) -> None:
|
||||||
|
"""
|
||||||
|
设置验证码
|
||||||
|
:param captcha: 验证码
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
self.captcha = captcha.strip()
|
||||||
|
|
||||||
|
def validate_captcha(self) -> bool:
|
||||||
|
"""
|
||||||
|
校验验证码
|
||||||
|
:return: 验证是否通过,True 表示校验通过,False 表示校验不通过
|
||||||
|
"""
|
||||||
|
self.notification = ""
|
||||||
|
# 非空校验
|
||||||
|
if not self.captcha:
|
||||||
|
self.notification = "请输入验证码"
|
||||||
|
return False
|
||||||
|
# 格式校验
|
||||||
|
if not re.fullmatch(r"^\d{6}$", self.captcha):
|
||||||
|
self.notification = "验证码格式不正确,请重新输入"
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@rx.event
|
||||||
|
def toggle_policies_agreed(self) -> None:
|
||||||
|
"""
|
||||||
|
切换协议同意状态
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
self.is_policies_agreed = not self.is_policies_agreed
|
||||||
|
|
||||||
@rx.event
|
@rx.event
|
||||||
async def login(self) -> None:
|
async def login(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
@ -189,7 +214,7 @@ class AuthState(rx.State):
|
||||||
"""
|
"""
|
||||||
self.is_logging_in = True
|
self.is_logging_in = True
|
||||||
|
|
||||||
# 验证邮箱
|
# 验证邮箱格式
|
||||||
if not self.validate_email():
|
if not self.validate_email():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in New Issue