Skip to content

Commit a98a7d4

Browse files
author
awesomeYG
committed
feat: 更新前端UI组件和认证系统
- 更新next.config.mjs和proxy.ts配置 - 改进httpClient和认证相关API - 优化登录页面和主页面组件 - 新增RootPageFallback组件 - 更新authProvider和头部组件 - 改进AuthConfigContext和ForumContext
1 parent 583f050 commit a98a7d4

File tree

11 files changed

+271
-137
lines changed

11 files changed

+271
-137
lines changed

ui/front/next.config.mjs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,8 @@ const nextConfig = {
4949
emotion: true,
5050
},
5151

52-
// ESLint 配置 - 减少构建时警告
53-
eslint: {
54-
// 构建时忽略 ESLint 错误,但保留警告
55-
ignoreDuringBuilds: false,
56-
// 可以在这里添加自定义规则
57-
dirs: ['src'],
58-
},
52+
// ESLint 配置已移至 next.config.mjs 外部
53+
// 使用 next lint 命令进行代码检查
5954

6055
// 图片优化配置
6156
images: {
@@ -95,8 +90,12 @@ const nextConfig = {
9590
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
9691
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
9792

98-
// 图片缓存优化
99-
minimumCacheTTL: 60,
93+
// 图片缓存优化 - 增加缓存时间减少重复请求
94+
minimumCacheTTL: 300, // 5分钟缓存
95+
96+
// 图片加载优化
97+
loader: 'default',
98+
unoptimized: false,
10099

101100
// SVG 安全配置
102101
dangerouslyAllowSVG: true,
@@ -150,6 +149,12 @@ const nextConfig = {
150149
source: '/api/:path*',
151150
destination: 'http://10.9.35.17:8090/api/:path*',
152151
basePath: false
152+
},
153+
// 添加图片代理重写,解决图片加载缓慢问题
154+
{
155+
source: '/koala/public/:path*',
156+
destination: 'http://10.9.35.17:8090/koala/public/:path*',
157+
basePath: false
153158
}
154159
]
155160
);

ui/front/proxy.ts

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@ export async function proxy(request: NextRequest) {
4444
// 简化的认证检查:只检查是否有有效的token
4545
const isAuthenticated = (() => {
4646
if (!authToken) {
47-
if (process.env.NODE_ENV === 'development') {
48-
console.log('[Middleware] No auth token found');
49-
}
5047
return false;
5148
}
5249

@@ -59,10 +56,6 @@ export async function proxy(request: NextRequest) {
5956
authToken !== "''" &&
6057
authToken.trim().length > 0;
6158

62-
if (process.env.NODE_ENV === 'development') {
63-
console.log('[Middleware] Token valid:', isValid, 'token length:', authToken.length);
64-
}
65-
6659
return isValid;
6760
})();
6861

@@ -87,16 +80,9 @@ export async function proxy(request: NextRequest) {
8780

8881
// 处理认证路由(已登录用户重定向到首页)
8982
if (matchRoute(pathname, AUTH_ROUTES)) {
90-
if (process.env.NODE_ENV === 'development') {
91-
console.log('[Middleware] Auth route detected:', pathname, 'isAuthenticated:', isAuthenticated, 'authToken:', authToken);
92-
}
93-
9483
if (isAuthenticated) {
9584
// 检查是否有重定向参数
9685
const redirectUrl = request.nextUrl.searchParams.get('redirect');
97-
if (process.env.NODE_ENV === 'development') {
98-
console.log('[Middleware] Redirecting authenticated user, redirectUrl:', redirectUrl);
99-
}
10086

10187
if (redirectUrl && redirectUrl !== '/login' && redirectUrl !== '/register') {
10288
// 确保重定向URL是安全的,避免循环重定向
@@ -111,9 +97,16 @@ export async function proxy(request: NextRequest) {
11197
console.warn('Invalid redirect URL:', redirectUrl);
11298
}
11399
}
114-
if (process.env.NODE_ENV === 'development') {
115-
console.log('[Middleware] Redirecting to home page');
100+
101+
// 检查是否是刚登录的情况(通过检查 Referer)
102+
const referer = request.headers.get('referer');
103+
const isFromLogin = referer && referer.includes('/login');
104+
105+
// 如果是刚登录,给客户端一些时间处理跳转,不要立即重定向
106+
if (isFromLogin && pathname === '/login') {
107+
return NextResponse.next();
116108
}
109+
117110
return NextResponse.redirect(new URL('/', request.url));
118111
}
119112
}
@@ -129,10 +122,6 @@ export async function proxy(request: NextRequest) {
129122
try {
130123
const baseURL = process.env.TARGET || '';
131124
const publicAccess = await getServerPublicAccessStatus(baseURL, request);
132-
133-
if (process.env.NODE_ENV === 'development') {
134-
console.log('[Middleware] Public access status:', publicAccess, 'for path:', pathname);
135-
}
136125

137126
// 如果public_access为false,强制跳转到登录页面
138127
if (!publicAccess) {

ui/front/src/api/httpClient.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,6 @@ export const clearCsrfTokenCache = () => {
123123
// 清除所有认证信息的函数
124124
export const clearAuthData = async (callLogoutAPI: boolean = true) => {
125125
if (typeof window !== "undefined") {
126-
console.log("Clearing all authentication data...");
127-
128126
// 清除本地存储的认证信息
129127
localStorage.removeItem("auth_token");
130128
localStorage.removeItem("user");
@@ -148,7 +146,6 @@ export const clearAuthData = async (callLogoutAPI: boolean = true) => {
148146
method: 'POST',
149147
credentials: 'include', // 确保发送 cookie
150148
});
151-
console.log("Server-side cookies cleared successfully");
152149
} catch (error) {
153150
console.warn("Failed to clear server-side cookies:", error);
154151
// 即使服务端清理失败,客户端清理仍然有效
@@ -166,8 +163,6 @@ export const clearAuthData = async (callLogoutAPI: boolean = true) => {
166163
// 触发自定义事件,通知所有组件认证状态已清除
167164
window.dispatchEvent(new CustomEvent('auth:cleared'));
168165
}, 100);
169-
170-
console.log("Authentication data cleared successfully");
171166
}
172167
};
173168

Lines changed: 60 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,100 @@
1-
'use client';
2-
import { postUserLogin, SvcAuthFrontendGetAuth } from '@/api';
3-
import { Message } from '@/components';
4-
import { AuthContext } from '@/components/authProvider';
5-
import LoadingBtn from '@/components/loadingButton';
6-
import { aesCbcEncrypt } from '@/utils/aes';
7-
import { zodResolver } from '@hookform/resolvers/zod';
8-
import { Stack, TextField } from '@mui/material';
9-
import { useLocalStorageState } from 'ahooks';
10-
import Cookies from 'js-cookie';
11-
import { useContext, useEffect } from 'react';
12-
import { useForm } from 'react-hook-form';
13-
import { useSearchParams, useRouter } from 'next/navigation';
14-
import z from 'zod';
1+
'use client'
2+
import { postUserLogin, SvcAuthFrontendGetAuth } from '@/api'
3+
import { Message } from '@/components'
4+
import { AuthContext } from '@/components/authProvider'
5+
import LoadingBtn from '@/components/loadingButton'
6+
import { useForum } from '@/contexts/ForumContext'
7+
import { aesCbcEncrypt } from '@/utils/aes'
8+
import { zodResolver } from '@hookform/resolvers/zod'
9+
import { Stack, TextField } from '@mui/material'
10+
import { useLocalStorageState } from 'ahooks'
11+
import Cookies from 'js-cookie'
12+
import { useContext, useEffect } from 'react'
13+
import { useForm } from 'react-hook-form'
14+
import { useSearchParams, useRouter } from 'next/navigation'
15+
import z from 'zod'
1516

1617
const schema = z.object({
1718
email: z.string().email('邮箱格式不正确').default(''),
1819
password: z.string().min(5, '密码不能少于 5 位').default(''),
19-
});
20+
})
2021

21-
const Account = ({ isChecked, passwordConfig }: { isChecked: boolean, passwordConfig?: SvcAuthFrontendGetAuth }) => {
22+
const Account = ({ isChecked, passwordConfig }: { isChecked: boolean; passwordConfig?: SvcAuthFrontendGetAuth }) => {
2223
const [, setToken] = useLocalStorageState<string>('auth_token', {
2324
defaultValue: '',
24-
});
25-
const { user, loading, fetchUser } = useContext(AuthContext);
26-
const searchParams = useSearchParams();
27-
const router = useRouter();
28-
const redirectUrl = searchParams?.get('redirect');
25+
})
26+
const { user, loading, fetchUser } = useContext(AuthContext)
27+
const { refreshForums } = useForum()
28+
const searchParams = useSearchParams()
29+
const router = useRouter()
30+
const redirectUrl = searchParams?.get('redirect')
2931

3032
const {
3133
register,
3234
handleSubmit,
3335
formState: { errors },
3436
} = useForm({
3537
resolver: zodResolver(schema),
36-
});
38+
})
3739

3840
useEffect(() => {
39-
console.log('[Login Account] useEffect triggered:', {
40-
loading,
41-
userEmail: user.email,
42-
userUid: user.uid,
43-
redirectUrl,
44-
userObject: user
45-
});
46-
4741
// 只有在用户数据加载完成且确实有用户信息时才检查登录状态
42+
// 但是要避免在登录过程中自动重定向,让登录逻辑自己处理跳转
4843
if (!loading && user.email && user.uid && user.uid > 0) {
49-
console.log('[Login Account] User is authenticated, redirecting to:', redirectUrl || '/');
50-
// 如果用户已登录,重定向到指定页面或首页
51-
const targetUrl = redirectUrl || '/';
52-
// 使用 Next.js 路由进行客户端跳转
53-
router.replace(targetUrl);
54-
} else if (!loading && user.uid === 0) {
55-
// 明确知道用户未登录,不需要进一步处理
56-
console.log('[Login Account] User is not authenticated');
57-
} else {
58-
console.log('[Login Account] User state is still loading or indeterminate');
44+
// 注释掉自动重定向,让登录成功后的逻辑自己处理
45+
// const targetUrl = redirectUrl || '/'
46+
// router.replace(targetUrl)
5947
}
60-
}, [loading, user.email, user.uid, redirectUrl]);
48+
}, [loading, user.email, user.uid, redirectUrl])
6149

6250
// 监听认证清除事件,避免在登出后重复检查
6351
useEffect(() => {
6452
const handleAuthCleared = () => {
65-
console.log('[Login Account] Auth cleared event received, user should be logged out');
6653
// 认证清除后,确保用户状态为未登录
6754
// 这里不需要额外处理,因为 AuthProvider 已经会重置用户状态
68-
};
55+
}
6956

7057
if (typeof window !== 'undefined') {
71-
window.addEventListener('auth:cleared', handleAuthCleared);
58+
window.addEventListener('auth:cleared', handleAuthCleared)
7259
return () => {
73-
window.removeEventListener('auth:cleared', handleAuthCleared);
74-
};
60+
window.removeEventListener('auth:cleared', handleAuthCleared)
61+
}
7562
}
76-
}, []);
63+
}, [])
7764
const onSubmit = (data: z.infer<typeof schema>) => {
78-
const { password, email } = data;
79-
const ciphertext = aesCbcEncrypt(password?.trim());
65+
const { password, email } = data
66+
const ciphertext = aesCbcEncrypt(password?.trim())
8067
return postUserLogin({ email, password: ciphertext })
8168
.then(async (res) => {
82-
setToken(res);
69+
setToken(res)
8370
Cookies.set('auth_token', res, {
8471
path: '/',
8572
expires: 7, // 7 天
8673
sameSite: 'Lax',
87-
});
74+
})
8875
await fetchUser()
76+
77+
// 直接调用refreshForums刷新论坛数据
78+
const refreshedForums = await refreshForums()
79+
8980
// 登录成功后重定向
90-
const targetUrl = redirectUrl || '/';
91-
router.replace(targetUrl);
81+
let targetUrl = redirectUrl
82+
83+
if (!targetUrl) {
84+
if (refreshedForums && refreshedForums.length > 0) {
85+
const forumUrl = `/forum/${refreshedForums[0].id}`
86+
router.replace(forumUrl)
87+
} else {
88+
router.replace('/')
89+
}
90+
} else {
91+
router.replace(targetUrl)
92+
}
9293
})
9394
.catch((e) => {
94-
Message.error(e || '登录失败');
95-
});
96-
};
95+
Message.error(e || '登录失败')
96+
})
97+
}
9798

9899
return (
99100
<Stack gap={2} sx={{ width: '100%', alignItems: 'center' }}>
@@ -131,7 +132,7 @@ const Account = ({ isChecked, passwordConfig }: { isChecked: boolean, passwordCo
131132
{passwordConfig?.button_desc || '登录'}
132133
</LoadingBtn>
133134
</Stack>
134-
);
135-
};
135+
)
136+
}
136137

137-
export default Account;
138+
export default Account

ui/front/src/app/page.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
11
import { getForum } from '@/api'
22
import { safeApiCall } from '@/lib/error-utils'
33
import { redirect } from 'next/navigation'
4+
import { cookies } from 'next/headers'
5+
import RootPageFallback from '@/components/RootPageFallback'
46

57
// 根路径重定向到第一个板块 - 服务端重定向
68
export default async function RootPage() {
9+
// 检查用户是否已登录
10+
const cookieStore = await cookies()
11+
const authToken = cookieStore.get('auth_token')?.value
12+
console.log('-----')
713
const forums = await safeApiCall(
814
() => getForum(),
915
[],
1016
'Failed to fetch forums for root page redirect'
1117
)
1218

1319
if (forums && forums.length > 0) {
20+
// 有论坛数据,重定向到第一个论坛
1421
redirect(`/forum/${forums[0].id}`)
22+
} else if (authToken) {
23+
// 用户已登录但没有论坛数据,使用客户端fallback组件
24+
return <RootPageFallback />
1525
} else {
26+
// 用户未登录,重定向到登录页面
1627
redirect('/login')
1728
}
1829
}

0 commit comments

Comments
 (0)