fix: 鉴权后弹出 LoginModal

mack-mac
mackt 7 months ago
parent 137939d91c
commit 40f99f14f5

@ -1,7 +1,7 @@
/** 期刊列表 */ /** 期刊列表 */
import { notFound } from 'next/navigation'; 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 { apiSearchCategoryList, apiGetJournalRecommendWithCollect, apiJournalList } from '@/services';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
@ -58,6 +58,8 @@ export default async function Journal({ params }: { params: { category?: string;
return ( return (
<main className="flex flex-row justify-between w-[1200px] mx-auto pt-[80px] pb-[104px] "> <main className="flex flex-row justify-between w-[1200px] mx-auto pt-[80px] pb-[104px] ">
<RedirectCheck />
{/* 左侧 */} {/* 左侧 */}
<div className="w-[712px] mt-[50px]"> <div className="w-[712px] mt-[50px]">
{/* category */} {/* category */}
@ -85,7 +87,6 @@ export default async function Journal({ params }: { params: { category?: string;
link={`/vol/list/${category}`} link={`/vol/list/${category}`}
/> />
</div> </div>
{/* 右侧 */} {/* 右侧 */}
<div className="w-[346px] mt-[218px]"> <div className="w-[346px] mt-[218px]">
{/* 热门推荐 */} {/* 热门推荐 */}

@ -6,21 +6,26 @@ import { debounce } from 'lodash';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useShallow } from 'zustand/react/shallow'; import { useShallow } from 'zustand/react/shallow';
import { useLoginRedirect } from '@/utils/login';
import { setAccessToken } from '@/lib/cache';
import { Button } from '@/components'; import { Button } from '@/components';
import { apiSendSMS } from '@/services'; import { apiSendSMS, apiUserLogin, getUserInfo } from '@/services';
import useUserStore from '@/store/user'; import useUserStore from '@/store/user';
export default function LoginForm({ redirect }: { redirect: string }) { export default function LoginForm() {
const redirect = useLoginRedirect();
const router = useRouter(); const router = useRouter();
const { userLogin, setShowLogin } = useUserStore( const { userLogin, setShowLogin, getUserInfo } = useUserStore(
useShallow((state) => ({ useShallow((state) => ({
userLogin: state.userLogin, userLogin: state.userLogin,
setShowLogin: state.setShowLogin, setShowLogin: state.setShowLogin,
getUserInfo: state.getUserInfo,
})), })),
); );
const [phone, setPhone] = useState<string>('17861518060'); // 手机号 const [phone, setPhone] = useState<string>('18812345678'); // 手机号
const [authCode, seAuthCode] = useState<string>('111111'); // 验证码 const [authCode, seAuthCode] = useState<string>('123456'); // 验证码
const [errorText, setErrorText] = useState<string>(''); // 验证码 const [errorText, setErrorText] = useState<string>(''); // 验证码
const [time, setTime] = useState<number>(0); // 倒计时 const [time, setTime] = useState<number>(0); // 倒计时
const [btnLoading, setBtnLoading] = useState<boolean>(false); const [btnLoading, setBtnLoading] = useState<boolean>(false);
@ -46,18 +51,24 @@ export default function LoginForm({ redirect }: { redirect: string }) {
// 登录 // 登录
const handleLogin = async () => { const handleLogin = async () => {
setBtnLoading(true); 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) { if (result.code === 200) {
setShowLogin(false); setShowLogin(false);
console.log({ redirect }); setAccessToken(result.data);
redirect ? router.replace(redirect) : window.location.reload(); await getUserInfo();
router.replace(redirect);
} else { } else {
setErrorText(result.message); setErrorText(result.message);
setBtnLoading(false); setBtnLoading(false);
} }
}; };
// 输入框只允许输入数字 // 输入框只允许输入数字
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>, fn: (text: string) => void) => { const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>, fn: (text: string) => void) => {
if (errorText) setErrorText(''); if (errorText) setErrorText('');
const inputValue = e.target.value; const inputValue = e.target.value;

@ -5,7 +5,7 @@ import LoginForm from './LoginForm';
import useUserStore from '@/store/user'; import useUserStore from '@/store/user';
export default function LoginCard({ redirect }: { redirect: string }) { export default function LoginCard() {
const { setShowLogin } = useUserStore( const { setShowLogin } = useUserStore(
useShallow((state) => ({ useShallow((state) => ({
setShowLogin: state.setShowLogin, setShowLogin: state.setShowLogin,
@ -38,7 +38,7 @@ export default function LoginCard({ redirect }: { redirect: string }) {
/> />
{/* form */} {/* form */}
<LoginForm redirect={redirect} /> <LoginForm />
<div className="absolute bottom-[30px] left-0 right-0 text-[13px] leading-[18px] text-[rgba(0,0,0,0.4)] text-center"> <div className="absolute bottom-[30px] left-0 right-0 text-[13px] leading-[18px] text-[rgba(0,0,0,0.4)] text-center">
{' '} {' '}

@ -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 <></>;
}

@ -1,5 +1,5 @@
export { default as Logo } from './Logo'; 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'; export { default as Footer } from './Footer';
// Icon // Icon
@ -12,6 +12,7 @@ export { default as ContributorCard } from './ContributorCard';
// Login // Login
export { default as LoginModal } from './Login/LoginModal'; export { default as LoginModal } from './Login/LoginModal';
export { default as LoginForm } from './Login/LoginForm'; export { default as LoginForm } from './Login/LoginForm';
export { default as RedirectCheck } from './Login/RedirectCheck';
// Journal // Journal
export { default as JournalItem } from './Journal/JournalItem'; export { default as JournalItem } from './Journal/JournalItem';

@ -0,0 +1,8 @@
import { setCookie } from 'nookies';
export function setAccessToken(token: string) {
setCookie(null, 'token', token, {
maxAge: 7 * 24 * 60 * 60,
path: '/',
});
}

@ -2,17 +2,21 @@ import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server'; import type { NextRequest } from 'next/server';
export async function middleware(request: NextRequest) { export async function middleware(req: NextRequest) {
const token = request.cookies.get('token' as any)?.value; const { pathname, origin, basePath } = req.nextUrl;
if (token) return NextResponse.next(); const cookieKey: string = 'token';
// 307: 临时重定向
return NextResponse.redirect(new URL(`/?redirect=${encodeURIComponent(request.nextUrl.pathname)}`, request.url), 307); 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 = { export const config = {
matcher: [ matcher: ['/my/:path*', '/vol/list/:path*'],
// '/((?!api|_next/static|_next/image|favicon.ico).*)',
'/my/:path*',
'/vol/list/:path*',
],
}; };

@ -75,15 +75,30 @@ const useUserStore = create<UserState>()(
), ),
setUserInfo, setUserInfo,
userLogin: async (params) => { userLogin: async (params) => {
const result = await apiUserLogin(params); const result = { code: 200, data: '1', message: '登录成功' };
if (result.code === 200) { if (result.code === 200) {
setCookie(null, 'token', result.data, { setCookie(
maxAge: 7 * 24 * 60 * 60, null,
path: '/', 'token',
}); 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxNzc5MDMxOTU1MzUwODg0MzUyIiwic3ViIjoi6ZuA5LmQLVQ5WkhteGkxVSIsImlhdCI6MTcxMzMzNTY1MCwiYXZhdGFyIjoidXNlci9hdmF0YXIvZGVmYXVsdC5wbmciLCJyb2xlcyI6InVzZXIiLCJleHAiOjE3MTM5NDA0NTB9.YtNph3J4XPyADfFAgCpUvh5VE4RgSRC0FH1ZDcNtPhU',
{
maxAge: 7 * 24 * 60 * 60,
path: '/',
},
);
await getUserInfo(); await getUserInfo();
} }
return result; 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, getUserInfo,
}; };

@ -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;
};
Loading…
Cancel
Save