e33bfe71bf
CI/CD Pipeline / Build Production Runtime Images (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Failing after 53h21m49s
CI/CD Pipeline / Deploy Staging (push) Failing after 53h22m44s
CI/CD Pipeline / Frontend Lint (push) Failing after 53h23m14s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 53h24m0s
- useLogout hook: navigate('/login') → navigate('/')
- client.ts 无refresh_token自动登出: href='/login' → href='/'
- client.ts 刷新失败自动登出: href='/login' → href='/'
- 已排查所有退出入口:仅Header头像菜单有手动退出按钮,行为一致
- ProtectedRoute未登录拦截仍跳/login(正确行为,非退出场景)
95 lines
2.4 KiB
TypeScript
95 lines
2.4 KiB
TypeScript
/**
|
|
* 认证相关 Hooks
|
|
*/
|
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
import { useNavigate } from "react-router-dom";
|
|
import * as authApi from "@/api/auth";
|
|
import { useAuthStore } from "@/store/authStore";
|
|
|
|
// 登录 Hook
|
|
export const useLogin = () => {
|
|
const navigate = useNavigate();
|
|
const setAuth = useAuthStore((state) => state.setAuth);
|
|
|
|
const mutation = useMutation({
|
|
mutationFn: authApi.login,
|
|
});
|
|
|
|
// 手动处理成功后的逻辑
|
|
const login = async (credentials: Parameters<typeof authApi.login>[0]) => {
|
|
const data = await mutation.mutateAsync(credentials);
|
|
const refreshToken = data.refresh_token ?? null;
|
|
|
|
// 先保存 token
|
|
localStorage.setItem("access_token", data.access_token);
|
|
if (refreshToken) {
|
|
localStorage.setItem("refresh_token", refreshToken);
|
|
} else {
|
|
localStorage.removeItem("refresh_token");
|
|
}
|
|
|
|
// 获取用户信息
|
|
const user = await authApi.getCurrentUser();
|
|
setAuth(user, data.access_token, refreshToken);
|
|
navigate("/");
|
|
return data;
|
|
};
|
|
|
|
return { ...mutation, mutateAsync: login };
|
|
};
|
|
|
|
// 注册 Hook
|
|
export const useRegister = () => {
|
|
const navigate = useNavigate();
|
|
|
|
const mutation = useMutation({
|
|
mutationFn: authApi.register,
|
|
});
|
|
|
|
const register = async (data: Parameters<typeof authApi.register>[0]) => {
|
|
const result = await mutation.mutateAsync(data);
|
|
navigate("/login", {
|
|
state: { message: "注册成功!请查收验证邮件。" },
|
|
});
|
|
return result;
|
|
};
|
|
|
|
return { ...mutation, mutateAsync: register };
|
|
};
|
|
|
|
// 登出 Hook
|
|
export const useLogout = () => {
|
|
const navigate = useNavigate();
|
|
const clearAuth = useAuthStore((state) => state.clearAuth);
|
|
const queryClient = useQueryClient();
|
|
|
|
const mutation = useMutation({
|
|
mutationFn: authApi.logout,
|
|
});
|
|
|
|
const logout = async () => {
|
|
try {
|
|
await mutation.mutateAsync();
|
|
} catch (error) {
|
|
// 即使登出失败也清除本地状态
|
|
} finally {
|
|
clearAuth();
|
|
queryClient.clear();
|
|
navigate("/");
|
|
}
|
|
};
|
|
|
|
return { ...mutation, mutateAsync: logout };
|
|
};
|
|
|
|
// 获取当前用户 Hook
|
|
export const useCurrentUser = () => {
|
|
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
|
|
|
return useQuery({
|
|
queryKey: ["currentUser"],
|
|
queryFn: authApi.getCurrentUser,
|
|
enabled: isAuthenticated,
|
|
});
|
|
};
|