From 40f99f14f50bb4af67dbecedd91725479320ead9 Mon Sep 17 00:00:00 2001 From: mackt <1033530438@qq.com> Date: Wed, 17 Apr 2024 21:57:23 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=89=B4=E6=9D=83=E5=90=8E=E5=BC=B9?= =?UTF-8?q?=E5=87=BA=20LoginModal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vol/list/[category]/[[...page]]/page.tsx | 5 +-- src/components/Login/LoginForm.tsx | 29 +++++++++++----- src/components/Login/LoginModal.tsx | 4 +-- src/components/Login/RedirectCheck.tsx | 34 +++++++++++++++++++ src/components/index.ts | 3 +- src/lib/cache.ts | 8 +++++ src/middleware.ts | 24 +++++++------ src/store/user.ts | 25 +++++++++++--- src/utils/login.ts | 8 +++++ 9 files changed, 111 insertions(+), 29 deletions(-) create mode 100644 src/components/Login/RedirectCheck.tsx create mode 100644 src/lib/cache.ts create mode 100644 src/utils/login.ts diff --git a/src/app/vol/list/[category]/[[...page]]/page.tsx b/src/app/vol/list/[category]/[[...page]]/page.tsx index bd7554b..b554d31 100644 --- a/src/app/vol/list/[category]/[[...page]]/page.tsx +++ b/src/app/vol/list/[category]/[[...page]]/page.tsx @@ -1,7 +1,7 @@ /** 期刊列表 */ import { notFound } from 'next/navigation'; -import { Category, JournalRecommendList, Pagination, JournalItem } from '@/components'; +import { Category, JournalRecommendList, Pagination, JournalItem, RedirectCheck } from '@/components'; import { apiSearchCategoryList, apiGetJournalRecommendWithCollect, apiJournalList } from '@/services'; import type { Metadata } from 'next'; @@ -58,6 +58,8 @@ export default async function Journal({ params }: { params: { category?: string; return (
+ + {/* 左侧 */}
{/* category */} @@ -85,7 +87,6 @@ export default async function Journal({ params }: { params: { category?: string; link={`/vol/list/${category}`} />
- {/* 右侧 */}
{/* 热门推荐 */} diff --git a/src/components/Login/LoginForm.tsx b/src/components/Login/LoginForm.tsx index 19363d5..9ef2845 100644 --- a/src/components/Login/LoginForm.tsx +++ b/src/components/Login/LoginForm.tsx @@ -6,21 +6,26 @@ import { debounce } from 'lodash'; import { useRouter } from 'next/navigation'; import { useShallow } from 'zustand/react/shallow'; +import { useLoginRedirect } from '@/utils/login'; +import { setAccessToken } from '@/lib/cache'; + import { Button } from '@/components'; -import { apiSendSMS } from '@/services'; +import { apiSendSMS, apiUserLogin, getUserInfo } from '@/services'; import useUserStore from '@/store/user'; -export default function LoginForm({ redirect }: { redirect: string }) { +export default function LoginForm() { + const redirect = useLoginRedirect(); const router = useRouter(); - const { userLogin, setShowLogin } = useUserStore( + const { userLogin, setShowLogin, getUserInfo } = useUserStore( useShallow((state) => ({ userLogin: state.userLogin, setShowLogin: state.setShowLogin, + getUserInfo: state.getUserInfo, })), ); - const [phone, setPhone] = useState('17861518060'); // 手机号 - const [authCode, seAuthCode] = useState('111111'); // 验证码 + const [phone, setPhone] = useState('18812345678'); // 手机号 + const [authCode, seAuthCode] = useState('123456'); // 验证码 const [errorText, setErrorText] = useState(''); // 验证码 const [time, setTime] = useState(0); // 倒计时 const [btnLoading, setBtnLoading] = useState(false); @@ -46,18 +51,24 @@ export default function LoginForm({ redirect }: { redirect: string }) { // 登录 const handleLogin = async () => { setBtnLoading(true); - const result = await userLogin({ mobile: phone, mobileCheckCode: authCode, deviceId: '1' }); + const result = await apiUserLogin({ mobile: phone, mobileCheckCode: authCode, deviceId: '1' }); + // const result = { + // code: 200, + // data: 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxNzc5MDMxOTU1MzUwODg0MzUyIiwic3ViIjoi6ZuA5LmQLVQ5WkhteGkxVSIsImlhdCI6MTcxMzMzNTY1MCwiYXZhdGFyIjoidXNlci9hdmF0YXIvZGVmYXVsdC5wbmciLCJyb2xlcyI6InVzZXIiLCJleHAiOjE3MTM5NDA0NTB9.YtNph3J4XPyADfFAgCpUvh5VE4RgSRC0FH1ZDcNtPhU', + // message: '登录成功', + // }; if (result.code === 200) { setShowLogin(false); - console.log({ redirect }); - redirect ? router.replace(redirect) : window.location.reload(); + setAccessToken(result.data); + await getUserInfo(); + router.replace(redirect); } else { setErrorText(result.message); setBtnLoading(false); } }; - // 输入框,只允许输入数字 + // 输入框只允许输入数字 const handleInputChange = (e: React.ChangeEvent, fn: (text: string) => void) => { if (errorText) setErrorText(''); const inputValue = e.target.value; diff --git a/src/components/Login/LoginModal.tsx b/src/components/Login/LoginModal.tsx index 26ca7c4..ce8153d 100644 --- a/src/components/Login/LoginModal.tsx +++ b/src/components/Login/LoginModal.tsx @@ -5,7 +5,7 @@ import LoginForm from './LoginForm'; import useUserStore from '@/store/user'; -export default function LoginCard({ redirect }: { redirect: string }) { +export default function LoginCard() { const { setShowLogin } = useUserStore( useShallow((state) => ({ setShowLogin: state.setShowLogin, @@ -38,7 +38,7 @@ export default function LoginCard({ redirect }: { redirect: string }) { /> {/* form */} - +
注册登录即代表同意{' '} diff --git a/src/components/Login/RedirectCheck.tsx b/src/components/Login/RedirectCheck.tsx new file mode 100644 index 0000000..5deea25 --- /dev/null +++ b/src/components/Login/RedirectCheck.tsx @@ -0,0 +1,34 @@ +'use client'; + +import { useEffect } from 'react'; + +import { usePathname, useSearchParams } from 'next/navigation'; +import { parseCookies } from 'nookies'; +import { useShallow } from 'zustand/react/shallow'; + +import useUserStore from '@/store/user'; + +export default function RedirectCheck() { + const pathName = usePathname(); + const searchParams = useSearchParams(); + const { token } = parseCookies(); + const { setShowLogin } = useUserStore( + useShallow((state) => ({ + setShowLogin: state.setShowLogin, + })), + ); + + useEffect(() => { + if (typeof window === 'undefined') return; // 不在浏览器环境 + + const serach = new URLSearchParams(window.location.search); + const redirect = serach.get('redirect'); + + if (redirect && !token) { + setShowLogin(true); + return; + } + }, [pathName, searchParams, typeof window !== 'undefined' ? window.location.search : '']); + + return <>; +} diff --git a/src/components/index.ts b/src/components/index.ts index 687cca0..ecf8e09 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,5 +1,5 @@ export { default as Logo } from './Logo'; -export { default as Header } from './Header/index'; +export { default as Header } from './Header/Header'; export { default as Footer } from './Footer'; // Icon @@ -12,6 +12,7 @@ export { default as ContributorCard } from './ContributorCard'; // Login export { default as LoginModal } from './Login/LoginModal'; export { default as LoginForm } from './Login/LoginForm'; +export { default as RedirectCheck } from './Login/RedirectCheck'; // Journal export { default as JournalItem } from './Journal/JournalItem'; diff --git a/src/lib/cache.ts b/src/lib/cache.ts new file mode 100644 index 0000000..d999c7c --- /dev/null +++ b/src/lib/cache.ts @@ -0,0 +1,8 @@ +import { setCookie } from 'nookies'; + +export function setAccessToken(token: string) { + setCookie(null, 'token', token, { + maxAge: 7 * 24 * 60 * 60, + path: '/', + }); +} diff --git a/src/middleware.ts b/src/middleware.ts index 2685e1a..1ad6375 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -2,17 +2,21 @@ import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; -export async function middleware(request: NextRequest) { - const token = request.cookies.get('token' as any)?.value; - if (token) return NextResponse.next(); - // 307: 临时重定向 - return NextResponse.redirect(new URL(`/?redirect=${encodeURIComponent(request.nextUrl.pathname)}`, request.url), 307); +export async function middleware(req: NextRequest) { + const { pathname, origin, basePath } = req.nextUrl; + const cookieKey: string = 'token'; + + if (req.cookies.has(cookieKey)) { + return NextResponse.next(); + } + + const decodedPathname = decodeURIComponent(pathname); // 解码 pathname + const signInUrl = new URL(`${basePath}/?redirect=${decodedPathname}`, origin); + const redirectResponse = NextResponse.redirect(signInUrl, 307); + redirectResponse.headers.set('x-middleware-cache', 'no-cache'); // no-cache: 禁用缓存,以保证 cookie 状态是最新的 + return redirectResponse; } export const config = { - matcher: [ - // '/((?!api|_next/static|_next/image|favicon.ico).*)', - '/my/:path*', - '/vol/list/:path*', - ], + matcher: ['/my/:path*', '/vol/list/:path*'], }; diff --git a/src/store/user.ts b/src/store/user.ts index 330880d..ceedb5f 100644 --- a/src/store/user.ts +++ b/src/store/user.ts @@ -75,15 +75,30 @@ const useUserStore = create()( ), setUserInfo, userLogin: async (params) => { - const result = await apiUserLogin(params); + const result = { code: 200, data: '1', message: '登录成功' }; if (result.code === 200) { - setCookie(null, 'token', result.data, { - maxAge: 7 * 24 * 60 * 60, - path: '/', - }); + setCookie( + null, + 'token', + 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxNzc5MDMxOTU1MzUwODg0MzUyIiwic3ViIjoi6ZuA5LmQLVQ5WkhteGkxVSIsImlhdCI6MTcxMzMzNTY1MCwiYXZhdGFyIjoidXNlci9hdmF0YXIvZGVmYXVsdC5wbmciLCJyb2xlcyI6InVzZXIiLCJleHAiOjE3MTM5NDA0NTB9.YtNph3J4XPyADfFAgCpUvh5VE4RgSRC0FH1ZDcNtPhU', + { + maxAge: 7 * 24 * 60 * 60, + path: '/', + }, + ); await getUserInfo(); } + return result; + // const result = await apiUserLogin(params); + // if (result.code === 200) { + // setCookie(null, 'token', result.data, { + // maxAge: 7 * 24 * 60 * 60, + // path: '/', + // }); + // await getUserInfo(); + // } + // return result; }, getUserInfo, }; diff --git a/src/utils/login.ts b/src/utils/login.ts new file mode 100644 index 0000000..fd0e82a --- /dev/null +++ b/src/utils/login.ts @@ -0,0 +1,8 @@ +import { useSearchParams } from 'next/navigation'; + +export const useLoginRedirect = () => { + const searchParams = useSearchParams(); + const redirect = searchParams.get('redirect'); + if (!redirect) return '/'; + return redirect; +};