更新移动端组件,简化认证和主题上下文的创建,添加错误页面组件以提升用户体验,同时更新相关依赖和配置,确保代码结构的清晰性和可维护性。

This commit is contained in:
zyh
2025-04-10 04:39:01 +00:00
parent da05e3a4a1
commit 5d338ca7c5
5 changed files with 89 additions and 41 deletions

View File

@@ -19,9 +19,6 @@
"lodash": "https://esm.d8d.fun/lodash@4.17.21"
},
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext", "deno.ns"],
"jsx": "react",
"jsxFactory": "React.createElement",
"jsxFragmentFactory": "React.Fragment"
"lib": ["dom", "dom.iterable", "esnext", "deno.ns"]
}
}

View File

@@ -53,6 +53,7 @@
"https://esm.d8d.fun/@types/debug@~4.1.12/index.d.ts": "https://esm.d8d.fun/@types/debug@4.1.12/index.d.ts",
"https://esm.d8d.fun/@types/follow-redirects@~1.14.4/index.d.ts": "https://esm.d8d.fun/@types/follow-redirects@1.14.4/index.d.ts",
"https://esm.d8d.fun/@types/lodash-es@~4.17.12/index.d.ts": "https://esm.d8d.fun/@types/lodash-es@4.17.12/index.d.ts",
"https://esm.d8d.fun/@types/lodash@~4.17.16/index.d.ts": "https://esm.d8d.fun/@types/lodash@4.17.16/index.d.ts",
"https://esm.d8d.fun/@types/mime-types@~2.1.4/index.d.ts": "https://esm.d8d.fun/@types/mime-types@2.1.4/index.d.ts",
"https://esm.d8d.fun/@types/ms@~2.1.0/index.d.ts": "https://esm.d8d.fun/@types/ms@2.1.0/index.d.ts",
"https://esm.d8d.fun/@types/proxy-from-env@~1.0.4/index.d.ts": "https://esm.d8d.fun/@types/proxy-from-env@1.0.4/index.d.ts",
@@ -764,6 +765,8 @@
"https://esm.d8d.fun/isexe@3.1.1?target=denonext": "b3c61e7e70b9d56865de461fbcdae702ebf93743143457079a15a60e30dfcf83",
"https://esm.d8d.fun/lodash-es@4.17.21/denonext/lodash-es.mjs": "83b25b8f85872b2805e6b0273c90d6c96960c80a710c55e89a7b399107fc6fa8",
"https://esm.d8d.fun/lodash-es@4.17.21?target=denonext": "1252ccd86311d14f2dd05282cf3e40e1ff76bfa79c71ca49b903e902129944cb",
"https://esm.d8d.fun/lodash@4.17.21": "c2f90ffd948b7a30f054986888bdc2667824115fa48ad583ca8b3a579ca4a5a8",
"https://esm.d8d.fun/lodash@4.17.21/denonext/lodash.mjs": "9d2a44e584d91008f61f974c6d0a32bf9afb1563761e60c366af0a293e8c759b",
"https://esm.d8d.fun/mime-db@1.52.0/denonext/mime-db.mjs": "f93feb3d7150014b71bd0d06c5bd819db56a089b31b8b79a3b0466bb37ef005e",
"https://esm.d8d.fun/mime-types@2.1.35/denonext/mime-types.mjs": "704bdb318816fe1360c90a196f7cb3ba6e25fe207707cc2df873f890ad2e5f44",
"https://esm.d8d.fun/mime-types@2.1.35?target=denonext": "e4cc9a1aabecc1be22d194375ec3b99cc9d51700cc4629ab689975451c0a8ce5",

View File

@@ -1,5 +1,19 @@
{
"version": "4",
"specifiers": {
"npm:@types/node@*": "22.12.0"
},
"npm": {
"@types/node@22.12.0": {
"integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==",
"dependencies": [
"undici-types"
]
},
"undici-types@6.20.0": {
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
}
},
"redirects": {
"https://esm.d8d.fun/@deno/shim-deno-test@^0.5.0?target=denonext": "https://esm.d8d.fun/@deno/shim-deno-test@0.5.0?target=denonext",
"https://esm.d8d.fun/@deno/shim-deno@~0.18.0?target=denonext": "https://esm.d8d.fun/@deno/shim-deno@0.18.2?target=denonext",
@@ -11,6 +25,7 @@
"https://esm.d8d.fun/@types/ms@~2.1.0/index.d.ts": "https://esm.d8d.fun/@types/ms@2.1.0/index.d.ts",
"https://esm.d8d.fun/@types/proxy-from-env@~1.0.4/index.d.ts": "https://esm.d8d.fun/@types/proxy-from-env@1.0.4/index.d.ts",
"https://esm.d8d.fun/@types/react-dom@~19.0.4/X-ZHJlYWN0QDE5LjAuMA/index.d.ts": "https://esm.d8d.fun/@types/react-dom@19.0.6/X-ZHJlYWN0QDE5LjAuMA/index.d.ts",
"https://esm.d8d.fun/@types/react-dom@~19.0.4/client.d.ts": "https://esm.d8d.fun/@types/react-dom@19.0.6/client.d.ts",
"https://esm.d8d.fun/@types/react-dom@~19.0.6/X-ZHJlYWN0QDE5LjAuMA/client.d.ts": "https://esm.d8d.fun/@types/react-dom@19.0.6/X-ZHJlYWN0QDE5LjAuMA/client.d.ts",
"https://esm.d8d.fun/@types/react@~19.0.12/index.d.ts": "https://esm.d8d.fun/@types/react@19.0.14/index.d.ts",
"https://esm.d8d.fun/@types/react@~19.0.12/jsx-runtime.d.ts": "https://esm.d8d.fun/@types/react@19.0.14/jsx-runtime.d.ts",
@@ -61,7 +76,9 @@
"https://esm.d8d.fun/@deno/shim-deno@0.18.2/denonext/shim-deno.mjs": "819d8ac34fdaf60658cf03d137f14adaff3f13a279ffd79cd8797d84a6ac46ab",
"https://esm.d8d.fun/@deno/shim-deno@0.18.2?target=denonext": "ffa3ca347bb6b6530720158f307a2e31b16728fbb52e6432254a07d52fcbc404",
"https://esm.d8d.fun/@heroicons/react@2.1.1/24/outline?deps=react@19.0.0": "d2c14cfd7f3090062c9f968f25d0ddbb277ca76055af1ac3fd22045276571a75",
"https://esm.d8d.fun/@heroicons/react@2.1.1/24/outline?deps=react@19.0.0,react-dom@19.0.0": "5e99f4d40ce60c55b5cf421c3cf3f13df1707cf53152e447b2332570412cd77a",
"https://esm.d8d.fun/@heroicons/react@2.1.1/24/solid?deps=react@19.0.0": "546051c9fdfdca5c7d51cd4cf588fe709da509274c5fcf203d616a5e87bdd595",
"https://esm.d8d.fun/@heroicons/react@2.1.1/X-ZHJlYWN0LWRvbUAxOS4wLjAscmVhY3RAMTkuMC4w/denonext/24/outline.mjs": "640f934a0c987f682032049e5d4a455567db676de47bca0d44e76b72023661f7",
"https://esm.d8d.fun/@heroicons/react@2.1.1/X-ZHJlYWN0QDE5LjAuMA/denonext/24/outline.mjs": "640f934a0c987f682032049e5d4a455567db676de47bca0d44e76b72023661f7",
"https://esm.d8d.fun/@heroicons/react@2.1.1/X-ZHJlYWN0QDE5LjAuMA/denonext/24/solid.mjs": "dcbd0c377d92857b6eb23c7dbb2ee6e650b12aa6ae1ef7fcc10dc1964df8ba47",
"https://esm.d8d.fun/@socket.io/component-emitter@3.1.2/denonext/component-emitter.mjs": "3c6c5f2d64d4933b577a7117df1d8855c51ff01ab3dea8f42af1adcb1a5989e7",
@@ -158,11 +175,15 @@
"https://esm.d8d.fun/proxy-from-env@1.1.0?target=denonext": "bf02a050a1a6aa56ddba25dbea2c355da294630e5c5520fddea4b2f30a9292bc",
"https://esm.d8d.fun/react-dom@19.0.0/X-ZHJlYWN0QDE5LjAuMA/denonext/client.mjs": "af662fd134eea98f37fdcea6142accd0f8a7d2e13c1c3c9e98dc37a8c7aad46b",
"https://esm.d8d.fun/react-dom@19.0.0/X-ZHJlYWN0QDE5LjAuMA/denonext/react-dom.mjs": "a2f7bc344e1d5b7ca47e68665291e206ae4db17ee84f234f3d3e2533b9119f63",
"https://esm.d8d.fun/react-dom@19.0.0/client": "c972c16184c695fc5828dfa61d7f341edbc463d20d8108765c93a98027c24227",
"https://esm.d8d.fun/react-dom@19.0.0/client?deps=react@19.0.0,react-dom@19.0.0": "eaf0dd9b4937f9f7674c02491ce718f461ad49377d8515e71c24ae841f407ded",
"https://esm.d8d.fun/react-dom@19.0.0/denonext/client.mjs": "af662fd134eea98f37fdcea6142accd0f8a7d2e13c1c3c9e98dc37a8c7aad46b",
"https://esm.d8d.fun/react-dom@19.0.0/denonext/react-dom.mjs": "a2f7bc344e1d5b7ca47e68665291e206ae4db17ee84f234f3d3e2533b9119f63",
"https://esm.d8d.fun/react-dom@19.0.0?deps=react@19.0.0,react-dom@19.0.0": "0e49978c3f0fb4a94db9c9318aebd7e1b35651678050871a91ebb080cc3e1f83",
"https://esm.d8d.fun/react-router@7.3.0/X-ZHJlYWN0LWRvbUAxOS4wLjAscmVhY3RAMTkuMC4w/denonext/dist/development/chunk-K6CSEXPM.mjs": "441898046ad7c4fd9a6b53e13a398c9c74c4412c519e942f82b8a77f7af9f9d6",
"https://esm.d8d.fun/react-router@7.3.0/X-ZHJlYWN0LWRvbUAxOS4wLjAscmVhY3RAMTkuMC4w/denonext/react-router.mjs": "b0b05fcfc3a03c5f679cd0bc69ca19aa10abaa977395df00e86b3fb114e5e346",
"https://esm.d8d.fun/react-router@7.3.0?deps=react@19.0.0,react-dom@19.0.0": "ad747718e32a45020d67eb4ff98f9734cb06a10ceb393baac0a965043e96cdf0",
"https://esm.d8d.fun/react@19.0.0": "ab1f4aa20ac56c237bbb204632bdb55f03a0ab005d21944eeb447e5e37879637",
"https://esm.d8d.fun/react@19.0.0/X-ZHJlYWN0LWRvbUAxOS4wLjA/denonext/react.mjs": "87fdb28d39ca8983bdba3e7ec329305f95463cfc70c015b2620b4900fa15efdd",
"https://esm.d8d.fun/react@19.0.0/denonext/jsx-runtime.mjs": "643b749fa9666fbf73619a99fd708722edb4acaa34c8cea7be783a3432367780",
"https://esm.d8d.fun/react@19.0.0/denonext/react.mjs": "87fdb28d39ca8983bdba3e7ec329305f95463cfc70c015b2620b4900fa15efdd",

View File

@@ -57,24 +57,10 @@ const defaultThemeSettings: ThemeSettings = {
};
// 创建认证上下文
const AuthContext = createContext<AuthContextType>({
user: null,
token: null,
login: async () => {},
logout: async () => {},
isAuthenticated: false,
isLoading: true
});
const AuthContext = createContext<AuthContextType | null>(null);
// 创建主题上下文
const ThemeContext = createContext<ThemeContextType>({
isDark: false,
currentTheme: defaultThemeSettings,
updateTheme: () => {},
saveTheme: async () => defaultThemeSettings,
resetTheme: async () => defaultThemeSettings,
toggleTheme: () => {}
});
const ThemeContext = createContext<ThemeContextType | null>(null);
// 认证提供者组件
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
@@ -107,7 +93,6 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
setLocalStorageWithExpiry('token', token, 24); // 24小时过期
setLocalStorageWithExpiry('user', user, 24);
return user;
} catch (error) {
console.error('登录失败:', error);
throw error;
@@ -255,18 +240,19 @@ export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ childre
);
};
// 主题hook
export const useTheme = () => useContext(ThemeContext);
// 使用上下文的钩子
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth必须在AuthProvider内部使用');
}
return context;
};
// 认证hook
export const useAuth = () => useContext(AuthContext);
// API hook
export const useApi = () => {
const { token } = useAuth();
return {
api,
isAuthenticated: !!token
};
};
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme必须在ThemeProvider内部使用');
}
return context;
};

View File

@@ -7,7 +7,8 @@ import {
Navigate,
useLocation,
useNavigate,
Link
Link,
useRouteError
} from 'react-router';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import dayjs from 'dayjs';
@@ -16,6 +17,7 @@ import { AuthProvider, ThemeProvider, useAuth } from './hooks.tsx';
import HomePage from './pages_index.tsx';
import LoginPage from './pages_login.tsx';
import { GlobalConfig } from "../share/types.ts";
import { ExclamationTriangleIcon, HomeIcon, BellIcon, UserIcon } from '@heroicons/react/24/outline';
// 设置中文语言
dayjs.locale('zh-cn');
@@ -153,6 +155,42 @@ const PageNotFound = () => (
</div>
);
// 添加错误页面组件
const ErrorPage = () => {
const error = useRouteError() as any;
const errorMessage = error?.statusText || error?.message || '未知错误';
return (
<div className="flex flex-col items-center justify-center min-h-screen p-6 text-center bg-gray-50">
<div className="max-w-md w-full bg-white rounded-lg shadow-lg p-8">
<ExclamationTriangleIcon className="h-16 w-16 text-red-600 mx-auto mb-4" />
<h1 className="text-2xl font-medium mb-2"></h1>
<div className="text-gray-500 mb-4"></div>
<div className="bg-red-50 border border-red-200 rounded-md p-4 mb-6">
<p className="text-red-700 text-sm font-medium"></p>
<p className="text-red-600 mt-1 text-sm break-all">{errorMessage}</p>
{error?.stack && (
<details className="mt-2">
<summary className="text-red-700 text-sm cursor-pointer"></summary>
<pre className="mt-2 text-xs text-red-600 overflow-auto p-2 bg-red-50 rounded">
{error.stack}
</pre>
</details>
)}
</div>
<a
href="/mobile"
className="inline-flex items-center justify-center px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors w-full"
>
</a>
</div>
</div>
);
};
// 添加个人页面组件
const ProfilePage = () => (
<div className="p-4">
@@ -232,7 +270,7 @@ const MobileLayout = () => {
location.pathname === '/mobile' ? 'text-blue-600' : 'text-gray-500'
}`}
>
<div className="text-xl mb-1">🏠</div>
<HomeIcon className="w-6 h-6 mb-1" />
<span className="text-xs"></span>
</Link>
<Link
@@ -241,7 +279,7 @@ const MobileLayout = () => {
location.pathname === '/mobile/notifications' ? 'text-blue-600' : 'text-gray-500'
}`}
>
<div className="text-xl mb-1">🔔</div>
<BellIcon className="w-6 h-6 mb-1" />
<span className="text-xs"></span>
</Link>
<Link
@@ -250,7 +288,7 @@ const MobileLayout = () => {
location.pathname === '/mobile/profile' ? 'text-blue-600' : 'text-gray-500'
}`}
>
<div className="text-xl mb-1">👤</div>
<UserIcon className="w-6 h-6 mb-1" />
<span className="text-xs"></span>
</Link>
</div>
@@ -265,11 +303,13 @@ const App = () => {
const router = createBrowserRouter([
{
path: '/',
element: <Navigate to="/mobile" replace />
element: <Navigate to="/mobile" replace />,
errorElement: <ErrorPage />
},
{
path: '/mobile/login',
element: <LoginPage />
element: <LoginPage />,
errorElement: <ErrorPage />
},
{
path: '/mobile',
@@ -278,6 +318,7 @@ const App = () => {
<MobileLayout />
</ProtectedRoute>
),
errorElement: <ErrorPage />,
children: [
{
index: true,