线上环境首页重定向bug修复
This commit is contained in:
@@ -5,6 +5,11 @@ server {
|
|||||||
listen 80;
|
listen 80;
|
||||||
server_name 101.200.208.45;
|
server_name 101.200.208.45;
|
||||||
|
|
||||||
|
# 根路径不提供站点,避免跳转或兜底到其他 server
|
||||||
|
location = / {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
# 前端应用路径
|
# 前端应用路径
|
||||||
location /emotion-museum/ {
|
location /emotion-museum/ {
|
||||||
alias /data/www/emotion-museum/;
|
alias /data/www/emotion-museum/;
|
||||||
@@ -95,7 +100,9 @@ server {
|
|||||||
|
|
||||||
# 处理不带末尾斜杠的 /course-of-life 请求
|
# 处理不带末尾斜杠的 /course-of-life 请求
|
||||||
location = /course-of-life {
|
location = /course-of-life {
|
||||||
rewrite ^(.*)$ $1/ permanent;
|
# 不进行 301/302 外部跳转:内部改写到 /course-of-life/ 交给下方 SPA location 处理
|
||||||
|
# 这样 URL 仍是 /course-of-life,但返回内容与 /course-of-life/ 完全一致(且不会触发“下载”)
|
||||||
|
rewrite ^ /course-of-life/ last;
|
||||||
}
|
}
|
||||||
|
|
||||||
# 后端 API 代理
|
# 后端 API 代理
|
||||||
|
|||||||
@@ -17,19 +17,20 @@ import useStore from './store/useStore';
|
|||||||
const ProtectedRoute = ({ children, requireAuth = false, requireOnboarding = false }) => {
|
const ProtectedRoute = ({ children, requireAuth = false, requireOnboarding = false }) => {
|
||||||
const { isLoggedIn, registrationData } = useStore();
|
const { isLoggedIn, registrationData } = useStore();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const hasToken = !!localStorage.getItem('access_token');
|
||||||
|
|
||||||
// 检查是否完成入站流程(有昵称和未来愿景即视为已完成)
|
// 检查是否完成入站流程(有昵称和未来愿景即视为已完成)
|
||||||
const hasCompletedOnboarding = !!(registrationData.nickname && registrationData.future?.vision);
|
const hasCompletedOnboarding = !!(registrationData.nickname && registrationData.future?.vision);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (requireAuth && !isLoggedIn) {
|
if (requireAuth && (!isLoggedIn || !hasToken)) {
|
||||||
navigate('/', { replace: true });
|
navigate('/', { replace: true });
|
||||||
} else if (requireOnboarding && !hasCompletedOnboarding) {
|
} else if (requireOnboarding && !hasCompletedOnboarding) {
|
||||||
navigate('/onboarding', { replace: true });
|
navigate('/onboarding', { replace: true });
|
||||||
}
|
}
|
||||||
}, [isLoggedIn, hasCompletedOnboarding, requireAuth, requireOnboarding, navigate]);
|
}, [isLoggedIn, hasCompletedOnboarding, requireAuth, requireOnboarding, hasToken, navigate]);
|
||||||
|
|
||||||
if (requireAuth && !isLoggedIn) {
|
if (requireAuth && (!isLoggedIn || !hasToken)) {
|
||||||
return <Loader text="正在验证身份..." />;
|
return <Loader text="正在验证身份..." />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +67,7 @@ const PageTransition = ({ children }) => {
|
|||||||
const AnimatedRoutes = () => {
|
const AnimatedRoutes = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { isLoggedIn, registrationData } = useStore();
|
const { isLoggedIn, registrationData } = useStore();
|
||||||
|
const hasToken = !!localStorage.getItem('access_token');
|
||||||
|
|
||||||
// 检查是否完成入站流程(有昵称和未来愿景即视为已完成)
|
// 检查是否完成入站流程(有昵称和未来愿景即视为已完成)
|
||||||
const hasCompletedOnboarding = !!(registrationData.nickname && registrationData.future?.vision);
|
const hasCompletedOnboarding = !!(registrationData.nickname && registrationData.future?.vision);
|
||||||
@@ -77,7 +79,7 @@ const AnimatedRoutes = () => {
|
|||||||
<Route
|
<Route
|
||||||
path="/"
|
path="/"
|
||||||
element={
|
element={
|
||||||
isLoggedIn ? (
|
(isLoggedIn && hasToken) ? (
|
||||||
hasCompletedOnboarding ? (
|
hasCompletedOnboarding ? (
|
||||||
<Navigate to="/dashboard" replace />
|
<Navigate to="/dashboard" replace />
|
||||||
) : (
|
) : (
|
||||||
@@ -130,8 +132,8 @@ const AnimatedRoutes = () => {
|
|||||||
* App 主组件
|
* App 主组件
|
||||||
*/
|
*/
|
||||||
function App() {
|
function App() {
|
||||||
// 生产环境使用 /course-of-life 作为基础路径
|
// 使用 Vite 的 BASE_URL 并移除末尾斜杠,确保 BrowserRouter basename 兼容
|
||||||
const basename = import.meta.env.PROD ? '/course-of-life' : '';
|
const basename = (import.meta.env.BASE_URL || '/').replace(/\/$/, '');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BrowserRouter basename={basename}>
|
<BrowserRouter basename={basename}>
|
||||||
|
|||||||
@@ -60,9 +60,13 @@ api.interceptors.response.use(
|
|||||||
localStorage.removeItem('refresh_token');
|
localStorage.removeItem('refresh_token');
|
||||||
localStorage.removeItem('life_trajectory_v3'); // 清除 Zustand 持久化状态
|
localStorage.removeItem('life_trajectory_v3'); // 清除 Zustand 持久化状态
|
||||||
|
|
||||||
// 避免重复跳转导致的无限循环
|
// 避免重复跳转导致的无限循环;使用 Vite 的 BASE_URL 确保在子路径下跳转
|
||||||
if (window.location.pathname !== '/') {
|
const baseUrl = (import.meta.env.BASE_URL || '/');
|
||||||
window.location.href = '/';
|
const normalize = (p) => (p || '/').replace(/\/+$/, '') || '/';
|
||||||
|
const at = normalize(window.location.pathname);
|
||||||
|
const target = normalize(baseUrl);
|
||||||
|
if (at !== target) {
|
||||||
|
window.location.href = baseUrl; // 仅当不在基路径时跳转
|
||||||
}
|
}
|
||||||
return Promise.reject(new Error('未授权访问,请重新登录'));
|
return Promise.reject(new Error('未授权访问,请重新登录'));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user