feat: 本次提交更新内容如下
登录页面算是完成了
This commit is contained in:
@@ -39,7 +39,7 @@ export function loginWithCode(params:any) {
|
|||||||
|
|
||||||
// 发送验证码
|
// 发送验证码
|
||||||
export function sendVerificationCode(params:any) {
|
export function sendVerificationCode(params:any) {
|
||||||
return request('/v1/auth/send-code',params, 'POST');
|
return request('/v1/auth/code',params, 'POST');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 退出登录
|
// 退出登录
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 20px;
|
padding: 15px;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(20px);
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
padding: 32px 24px;
|
padding: 24px 20px;
|
||||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@@ -109,13 +109,6 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.welcome-text {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
margin: 0 0 4px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #666;
|
color: #666;
|
||||||
@@ -262,17 +255,13 @@
|
|||||||
|
|
||||||
.agreement-section {
|
.agreement-section {
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
padding: 10px;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-radius: 10px;
|
|
||||||
border: 1px solid #e5e5e5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.agreement-checkbox {
|
.agreement-checkbox {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
font-size: 11px;
|
font-size: 12px;
|
||||||
color: #666;
|
color: #666;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -292,7 +281,7 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
text-overflow: clip;
|
text-overflow: clip;
|
||||||
font-size: 11px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.agreement-link {
|
.agreement-link {
|
||||||
@@ -434,10 +423,6 @@
|
|||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.welcome-text {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.third-party-login {
|
.third-party-login {
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import style from "./login.module.scss";
|
|||||||
|
|
||||||
const Login: React.FC = () => {
|
const Login: React.FC = () => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [activeTab, setActiveTab] = useState("password");
|
const [activeTab, setActiveTab] = useState(1); // 1: 密码登录, 2: 验证码登录
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [countdown, setCountdown] = useState(0);
|
const [countdown, setCountdown] = useState(0);
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
@@ -40,38 +40,33 @@ const Login: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 手机号格式验证
|
|
||||||
const validatePhone = (phone: string) => {
|
|
||||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
|
||||||
return phoneRegex.test(phone);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 发送验证码
|
// 发送验证码
|
||||||
const handleSendVerificationCode = async () => {
|
const handleSendVerificationCode = async () => {
|
||||||
const phone = form.getFieldValue("phone");
|
const account = form.getFieldValue("account");
|
||||||
|
|
||||||
if (!phone) {
|
if (!account) {
|
||||||
Toast.show({ content: "请输入手机号", position: "top" });
|
Toast.show({ content: "请输入手机号", position: "top" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validatePhone(phone)) {
|
// 手机号格式验证
|
||||||
|
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||||
|
if (!phoneRegex.test(account)) {
|
||||||
Toast.show({ content: "请输入正确的11位手机号", position: "top" });
|
Toast.show({ content: "请输入正确的11位手机号", position: "top" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await sendVerificationCode(phone);
|
await sendVerificationCode({
|
||||||
|
mobile: account,
|
||||||
|
type: "login",
|
||||||
|
});
|
||||||
|
|
||||||
if (response.code === 200) {
|
Toast.show({ content: "验证码已发送", position: "top" });
|
||||||
Toast.show({ content: "验证码已发送", position: "top" });
|
setCountdown(60);
|
||||||
setCountdown(60);
|
|
||||||
} else {
|
|
||||||
Toast.show({ content: response.msg || "发送失败", position: "top" });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Toast.show({ content: "发送失败,请稍后重试", position: "top" });
|
// 错误已在request中处理,这里不需要额外处理
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -86,46 +81,39 @@ const Login: React.FC = () => {
|
|||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
|
// 添加typeId参数
|
||||||
|
const loginParams = {
|
||||||
|
...values,
|
||||||
|
typeId: activeTab as number,
|
||||||
|
};
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
|
if (activeTab === 1) {
|
||||||
if (activeTab === "password") {
|
response = await loginWithPassword(loginParams);
|
||||||
response = await loginWithPassword(values.phone, values.password);
|
|
||||||
} else {
|
} else {
|
||||||
response = await loginWithCode(values.phone, values.verificationCode);
|
response = await loginWithCode(loginParams);
|
||||||
}
|
}
|
||||||
|
console.log(response, "response");
|
||||||
|
|
||||||
if (response.code === 200 && response.data) {
|
// 更新状态管理(token会自动存储到localStorage,用户信息存储在状态管理中)
|
||||||
// 保存登录信息到localStorage
|
login(response.token, response.member);
|
||||||
localStorage.setItem("token", response.data.token);
|
|
||||||
localStorage.setItem("token_expired", response.data.token_expired);
|
|
||||||
localStorage.setItem("s2_accountId", response.data.member.s2_accountId);
|
|
||||||
localStorage.setItem("userInfo", JSON.stringify(response.data.member));
|
|
||||||
|
|
||||||
// 更新状态管理
|
Toast.show({ content: "登录成功", position: "top" });
|
||||||
login(response.data.token, response.data.member);
|
|
||||||
|
|
||||||
Toast.show({ content: "登录成功", position: "top" });
|
// 跳转到首页或重定向URL
|
||||||
|
const returnUrl = searchParams.get("returnUrl");
|
||||||
// 跳转到首页或重定向URL
|
if (returnUrl) {
|
||||||
const returnUrl = searchParams.get("returnUrl");
|
const decodedUrl = decodeURIComponent(returnUrl);
|
||||||
if (returnUrl) {
|
if (isLoginPage(decodedUrl)) {
|
||||||
const decodedUrl = decodeURIComponent(returnUrl);
|
|
||||||
if (isLoginPage(decodedUrl)) {
|
|
||||||
navigate("/");
|
|
||||||
} else {
|
|
||||||
window.location.href = decodedUrl;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
navigate("/");
|
navigate("/");
|
||||||
|
} else {
|
||||||
|
window.location.href = decodedUrl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast.show({ content: response.msg || "登录失败", position: "top" });
|
navigate("/");
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
Toast.show({
|
// 错误已在request中处理,这里不需要额外处理
|
||||||
content: error?.message || "登录失败,请稍后重试",
|
|
||||||
position: "top",
|
|
||||||
});
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -158,7 +146,6 @@ const Login: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
<h1 className={style["app-name"]}>存客宝</h1>
|
<h1 className={style["app-name"]}>存客宝</h1>
|
||||||
</div>
|
</div>
|
||||||
<p className={style["welcome-text"]}>欢迎回来</p>
|
|
||||||
<p className={style["subtitle"]}>登录您的账户继续使用</p>
|
<p className={style["subtitle"]}>登录您的账户继续使用</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -168,23 +155,23 @@ const Login: React.FC = () => {
|
|||||||
<div className={style["tab-container"]}>
|
<div className={style["tab-container"]}>
|
||||||
<div
|
<div
|
||||||
className={`${style["tab-item"]} ${
|
className={`${style["tab-item"]} ${
|
||||||
activeTab === "password" ? style["active"] : ""
|
activeTab === 1 ? style["active"] : ""
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setActiveTab("password")}
|
onClick={() => setActiveTab(1)}
|
||||||
>
|
>
|
||||||
密码登录
|
密码登录
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`${style["tab-item"]} ${
|
className={`${style["tab-item"]} ${
|
||||||
activeTab === "verification" ? style["active"] : ""
|
activeTab === 2 ? style["active"] : ""
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setActiveTab("verification")}
|
onClick={() => setActiveTab(2)}
|
||||||
>
|
>
|
||||||
验证码登录
|
验证码登录
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`${style["tab-indicator"]} ${
|
className={`${style["tab-indicator"]} ${
|
||||||
activeTab === "verification" ? style["slide"] : ""
|
activeTab === 2 ? style["slide"] : ""
|
||||||
}`}
|
}`}
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -197,7 +184,7 @@ const Login: React.FC = () => {
|
|||||||
>
|
>
|
||||||
{/* 手机号输入 */}
|
{/* 手机号输入 */}
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="phone"
|
name="account"
|
||||||
label="手机号"
|
label="手机号"
|
||||||
rules={[
|
rules={[
|
||||||
{ required: true, message: "请输入手机号" },
|
{ required: true, message: "请输入手机号" },
|
||||||
@@ -218,7 +205,7 @@ const Login: React.FC = () => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
{/* 密码输入 */}
|
{/* 密码输入 */}
|
||||||
{activeTab === "password" && (
|
{activeTab === 1 && (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="password"
|
name="password"
|
||||||
label="密码"
|
label="密码"
|
||||||
@@ -242,7 +229,7 @@ const Login: React.FC = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 验证码输入 */}
|
{/* 验证码输入 */}
|
||||||
{activeTab === "verification" && (
|
{activeTab === 2 && (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="verificationCode"
|
name="verificationCode"
|
||||||
label="验证码"
|
label="验证码"
|
||||||
|
|||||||
@@ -1,54 +1,74 @@
|
|||||||
import { createPersistStore } from '@/store/createPersistStore';
|
import { createPersistStore } from '@/store/createPersistStore';
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
id?: string;
|
id: number;
|
||||||
name: string;
|
account: string;
|
||||||
|
username: string;
|
||||||
phone: string;
|
phone: string;
|
||||||
role: string;
|
avatar: string;
|
||||||
token: string;
|
isAdmin: number;
|
||||||
token_expired?: string;
|
companyId: number;
|
||||||
s2_accountId?: string;
|
typeId: number;
|
||||||
avatar?: string;
|
status: number;
|
||||||
email?: string;
|
s2_accountId: string;
|
||||||
|
createTime: string;
|
||||||
|
updateTime: string | null;
|
||||||
|
lastLoginIp: string;
|
||||||
|
lastLoginTime: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserState {
|
interface UserState {
|
||||||
user: User | null;
|
user: User | null;
|
||||||
|
token: string | null;
|
||||||
isLoggedIn: boolean;
|
isLoggedIn: boolean;
|
||||||
setUser: (user: User) => void;
|
setUser: (user: User) => void;
|
||||||
|
setToken: (token: string) => void;
|
||||||
clearUser: () => void;
|
clearUser: () => void;
|
||||||
login: (token: string, userInfo: any) => void;
|
login: (token: string, userInfo: User) => void;
|
||||||
logout: () => void;
|
logout: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useUserStore = createPersistStore<UserState>(
|
export const useUserStore = createPersistStore<UserState>(
|
||||||
(set) => ({
|
(set) => ({
|
||||||
user: null,
|
user: null,
|
||||||
|
token: null,
|
||||||
isLoggedIn: false,
|
isLoggedIn: false,
|
||||||
setUser: (user) => set({ user, isLoggedIn: true }),
|
setUser: (user) => set({ user, isLoggedIn: true }),
|
||||||
clearUser: () => set({ user: null, isLoggedIn: false }),
|
setToken: (token) => set({ token }),
|
||||||
|
clearUser: () => set({ user: null, token: null, isLoggedIn: false }),
|
||||||
login: (token, userInfo) => {
|
login: (token, userInfo) => {
|
||||||
|
// 只将token存储到localStorage
|
||||||
|
localStorage.setItem('token', token);
|
||||||
|
|
||||||
|
// 用户信息存储在状态管理中
|
||||||
const user: User = {
|
const user: User = {
|
||||||
id: userInfo.id,
|
id: userInfo.id,
|
||||||
name: userInfo.name || userInfo.nickname || userInfo.username,
|
account: userInfo.account,
|
||||||
|
username: userInfo.username,
|
||||||
phone: userInfo.phone,
|
phone: userInfo.phone,
|
||||||
role: userInfo.role || 'user',
|
|
||||||
token,
|
|
||||||
token_expired: userInfo.token_expired,
|
|
||||||
s2_accountId: userInfo.s2_accountId,
|
|
||||||
avatar: userInfo.avatar,
|
avatar: userInfo.avatar,
|
||||||
email: userInfo.email,
|
isAdmin: userInfo.isAdmin,
|
||||||
|
companyId: userInfo.companyId,
|
||||||
|
typeId: userInfo.typeId,
|
||||||
|
status: userInfo.status,
|
||||||
|
s2_accountId: userInfo.s2_accountId,
|
||||||
|
createTime: userInfo.createTime,
|
||||||
|
updateTime: userInfo.updateTime,
|
||||||
|
lastLoginIp: userInfo.lastLoginIp,
|
||||||
|
lastLoginTime: userInfo.lastLoginTime,
|
||||||
};
|
};
|
||||||
set({ user, isLoggedIn: true });
|
set({ user, token, isLoggedIn: true });
|
||||||
},
|
},
|
||||||
logout: () => {
|
logout: () => {
|
||||||
|
// 清除localStorage中的token
|
||||||
localStorage.removeItem('token');
|
localStorage.removeItem('token');
|
||||||
localStorage.removeItem('token_expired');
|
set({ user: null, token: null, isLoggedIn: false });
|
||||||
localStorage.removeItem('s2_accountId');
|
|
||||||
localStorage.removeItem('userInfo');
|
|
||||||
set({ user: null, isLoggedIn: false });
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
'user-store',
|
'user-store',
|
||||||
(state) => ({ user: state.user, isLoggedIn: state.isLoggedIn })
|
(state) => ({
|
||||||
|
user: state.user,
|
||||||
|
token: state.token,
|
||||||
|
isLoggedIn: state.isLoggedIn
|
||||||
|
})
|
||||||
);
|
);
|
||||||
Reference in New Issue
Block a user