修复ui问题

This commit is contained in:
qaq
2025-08-20 15:34:05 +08:00
parent c43e0fecdc
commit 8dc171fe4b
20 changed files with 13515 additions and 273861 deletions
+10 -8
View File
@@ -1,4 +1,4 @@
import { Route, Routes } from "react-router-dom";
import { Route, Routes, useNavigate } from "react-router-dom";
import { useEffect, useState } from "react";
import IndexPage from "@/pages/index";
@@ -58,17 +58,18 @@ const useH5Mode = () => {
return isH5;
};
// 简化的路由保护组件 - 使用浏览器重定向避免React循环
// 简化的路由保护组件 - 使用 React Router 导航避免循环
const ProtectedRoute = ({ children, useSimpleLayout = false }: { children: React.ReactNode, useSimpleLayout?: boolean }) => {
const authenticated = isLoggedIn();
const isH5 = useH5Mode();
const navigate = useNavigate();
useEffect(() => {
if (!authenticated) {
// 使用浏览器原生重定向,避免React渲染循环
window.location.replace('/');
// 使用 React Router 导航,避免无限跳转
navigate('/', { replace: true });
}
}, [authenticated]);
}, [authenticated, navigate]);
if (!authenticated) {
return (
@@ -95,13 +96,14 @@ const ProtectedRoute = ({ children, useSimpleLayout = false }: { children: React
// 登录页面路由组件 - 已登录则重定向到dashboard
const LoginRoute = () => {
const authenticated = isLoggedIn();
const navigate = useNavigate();
useEffect(() => {
if (authenticated) {
// 使用浏览器原生重定向
window.location.replace('/dashboard');
// 使用 React Router 导航,避免无限跳转
navigate('/dashboard', { replace: true });
}
}, [authenticated]);
}, [authenticated, navigate]);
if (authenticated) {
return (
+16 -4
View File
@@ -1,5 +1,5 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { useNavigate, useLocation } from 'react-router-dom';
import { Button } from "@heroui/button";
import { Logo } from '@/components/icons';
@@ -11,15 +11,27 @@ export default function H5SimpleLayout({
children: React.ReactNode;
}) {
const navigate = useNavigate();
const location = useLocation();
// 路由切换时回到顶部,避免上一页滚动位置保留
React.useEffect(() => {
try {
window.scrollTo({ top: 0, left: 0, behavior: 'auto' });
} catch (e) {
window.scrollTo(0, 0);
}
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}, [location.pathname]);
const handleBack = () => {
navigate('/profile');
};
return (
<div className="flex flex-col h-screen bg-gray-100 dark:bg-black">
<div className="flex flex-col min-h-screen bg-gray-100 dark:bg-black">
{/* 顶部导航栏 */}
<header className="bg-white dark:bg-black shadow-sm border-b border-gray-200 dark:border-gray-600 h-14 flex items-center justify-between px-4 relative z-10">
<header className="bg-white dark:bg-black shadow-sm border-b border-gray-200 dark:border-gray-600 h-14 safe-top flex-shrink-0 flex items-center justify-between px-4 relative z-10">
<div className="flex items-center gap-2">
<Button
isIconOnly
@@ -40,7 +52,7 @@ export default function H5SimpleLayout({
</header>
{/* 主内容区域 */}
<main className="flex-1 overflow-y-auto bg-gray-100 dark:bg-black">
<main className="flex-1 bg-gray-100 dark:bg-black pb-0">
{children}
</main>
</div>
+18 -4
View File
@@ -98,10 +98,21 @@ export default function H5Layout({
!item.adminOnly || isAdmin
);
// 路由切换时回到页面顶部,避免上一页的滚动位置遗留
useEffect(() => {
try {
window.scrollTo({ top: 0, left: 0, behavior: 'auto' });
} catch (e) {
window.scrollTo(0, 0);
}
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}, [location.pathname]);
return (
<div className="flex flex-col h-screen bg-gray-100 dark:bg-black">
<div className="flex flex-col min-h-screen bg-gray-100 dark:bg-black">
{/* 顶部导航栏 */}
<header className="bg-white dark:bg-black shadow-sm border-b border-gray-200 dark:border-gray-600 h-14 flex items-center justify-between px-4 relative z-10">
<header className="bg-white dark:bg-black shadow-sm border-b border-gray-200 dark:border-gray-600 h-14 safe-top flex-shrink-0 flex items-center justify-between px-4 relative z-10">
<div className="flex items-center gap-2">
<Logo size={20} />
<h1 className="text-sm font-bold text-foreground">{siteConfig.name}</h1>
@@ -112,12 +123,15 @@ export default function H5Layout({
</header>
{/* 主内容区域 */}
<main className="flex-1 overflow-y-auto bg-gray-100 dark:bg-black">
<main className="flex-1 bg-gray-100 dark:bg-black">
{children}
</main>
{/* 用于给固定 Tabbar 腾出空间的占位元素 */}
<div aria-hidden className="h-16 safe-bottom" />
{/* 底部Tabbar */}
<nav className="bg-white dark:bg-black border-t border-gray-200 dark:border-gray-600 h-16 flex items-center justify-around px-2 relative z-10">
<nav className="bg-white dark:bg-black border-t border-gray-200 dark:border-gray-600 h-16 safe-bottom flex-shrink-0 flex items-center justify-around px-2 fixed bottom-0 left-0 right-0 z-30">
{filteredTabItems.map((item) => {
const isActive = location.pathname === item.path;
return (
+3 -21
View File
@@ -1,34 +1,16 @@
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { MemoryRouter } from "react-router-dom";
import App from "./App.tsx";
import { Provider } from "./provider.tsx";
import "@/styles/globals.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<BrowserRouter>
<MemoryRouter>
<Provider>
<App />
</Provider>
</BrowserRouter>
</MemoryRouter>
);
/**
import ReactDOM from "react-dom/client";
import { HashRouter } from "react-router-dom";
import App from "./App.tsx";
import { Provider } from "./provider.tsx";
import "@/styles/globals.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<HashRouter>
<Provider>
<App />
</Provider>
</HashRouter>
);
*/
+4 -2
View File
@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Button } from "@heroui/button";
import { Card, CardBody, CardHeader } from "@heroui/card";
import { Input } from "@heroui/input";
@@ -121,6 +122,7 @@ const getInitialConfigs = (): Record<string, string> => {
};
export default function ConfigPage() {
const navigate = useNavigate();
const initialConfigs = getInitialConfigs();
const [configs, setConfigs] = useState<Record<string, string>>(initialConfigs);
const [loading, setLoading] = useState(Object.keys(initialConfigs).length === 0); // 如果有缓存数据,不显示loading
@@ -132,10 +134,10 @@ export default function ConfigPage() {
useEffect(() => {
if (!isAdmin()) {
toast.error('权限不足,只有管理员可以访问此页面');
window.location.href = '/dashboard';
navigate('/dashboard', { replace: true });
return;
}
}, []);
}, [navigate]);
// 加载配置数据(优先从缓存)
const loadConfigs = async (currentConfigs?: Record<string, string>) => {
+1 -1
View File
@@ -95,7 +95,7 @@ export default function ProfilePage() {
// 退出登录
const handleLogout = () => {
safeLogout();
window.location.href = '/';
navigate('/', { replace: true });
};
// 密码表单验证
+1 -1
View File
@@ -119,7 +119,7 @@ export const SettingsPage = () => {
loadPanelAddresses();
}
} catch (error) {
toast.error('添加失败');
toast.error('添加失败' + error);
}
};
+25
View File
@@ -7,6 +7,16 @@ html, body {
overflow-x: hidden;
}
/* 现代浏览器使用 100dvh,避免地址栏收起/展开导致的布局跳动 */
@supports (height: 100dvh) {
.h-screen {
height: 100dvh;
}
.min-h-screen {
min-height: 100dvh;
}
}
/* 解决移动端100vh问题 */
@supports (-webkit-touch-callout: none) {
.h-screen {
@@ -30,6 +40,21 @@ html, body {
}
/* 安全区域变量与工具类(适配刘海/底部手势条) */
:root {
--safe-area-top: env(safe-area-inset-top, 0px);
--safe-area-bottom: env(safe-area-inset-bottom, 0px);
}
.safe-top {
padding-top: var(--safe-area-top);
}
.safe-bottom {
padding-bottom: var(--safe-area-bottom);
}
/* 验证码弹层动画 */
.captcha-modal-enter {
animation: captchaModalIn 0.3s ease-out forwards;