Browse Source

优化登录,退出功能

main
dark 5 months ago
parent
commit
f178bbf5dc
  1. 18
      src/App.tsx
  2. 15
      src/components/avatar/index.tsx
  3. 123
      src/pages/login/index.css
  4. 26
      src/pages/login/index.tsx
  5. 7
      src/request.ts
  6. 27
      src/routes.tsx

18
src/App.tsx

@ -1,37 +1,23 @@
import { AppContextProvider } from '@/context.ts'
import { initI18n } from '@/i18n.ts'
import { appAtom, appStore, changeLanguage } from '@/store/system.ts'
import { userMenuDataAtom } from '@/store/user.ts'
import { IAppData } from '@/global'
import { ConfigProvider } from '@/components/config-provider'
import { Provider, useAtom, useAtomValue } from 'jotai'
import { Provider, useAtom } from 'jotai'
import './App.css'
import { useEffect } from 'react'
import { RootProvider } from './routes.tsx'
import PageLoading from '@/components/page-loading'
function App() {
const [ appData, ] = useAtom(appAtom)
const { data = [], isLoading, isFetching, refetch } = useAtomValue(userMenuDataAtom)
useEffect(() => {
initI18n()
}, [])
useEffect(() => {
if (appData.token) {
refetch().then()
}
}, [ appData.token ])
if (isLoading || isFetching) {
return <PageLoading/>
}
return (
<ConfigProvider>
<AppContextProvider value={{
@ -41,7 +27,7 @@ function App() {
changeLanguage
}}>
<Provider store={appStore}>
<RootProvider context={{ menuData: data }}/>
<RootProvider context={{}}/>
</Provider>
</AppContextProvider>
</ConfigProvider>

15
src/components/avatar/index.tsx

@ -1,13 +1,16 @@
import Icon from '@/components/icon'
import { useTranslation } from '@/i18n.ts'
import { currentUserAtom } from '@/store/user.ts'
import { currentUserAtom, logoutAtom } from '@/store/user.ts'
import { Avatar as AntAvatar, Dropdown, Spin } from 'antd'
import { useAtomValue } from 'jotai'
import { useNavigate } from '@tanstack/react-router'
const Avatar = () => {
const { t } = useTranslation()
const { data, isLoading } = useAtomValue(currentUserAtom)
const { mutate: logout } = useAtomValue(logoutAtom)
const navigate = useNavigate()
return (
<div>
@ -25,6 +28,16 @@ const Avatar = () => {
}}>{t('app.header.logout')}</span>,
},
],
onClick: (e) => {
if (e.key === 'logout') {
logout()
navigate({
to: '/login', search: {
redirect: window.location.pathname
}
})
}
},
}}
>
<Spin spinning={isLoading}>

123
src/pages/login/index.css

@ -1,123 +0,0 @@
body {
margin: 0;
padding: 0;
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
overflow: hidden;
.login-container {
display: flex;
align-items: center;
height: 100vh;
background-image: url("@/assets/login.png");
background-repeat: no-repeat;
background-size: cover;
.language {
position: absolute;
top: 10px;
right: 10px;
color: #fff;
font-size: 14px;
cursor: pointer;
}
.loginBlock {
width: 100%;
height: 100%;
padding: 40px 0;
display: flex;
align-items: center;
justify-content: center;
}
.innerBlock {
width: 356px;
margin: 0 auto;
}
.logo {
height: 30px;
}
.infoLine {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0;
}
.infoLeft {
color: #666;
font-size: 14px;
}
.desc {
margin: 24px 0;
color: #999;
font-size: 16px;
cursor: pointer;
}
.active {
color: #333;
font-weight: bold;
font-size: 24px;
}
.line {
display: inline-block;
width: 1px;
height: 12px;
background: #999;
}
.innerBeforeInput {
margin-left: 10px;
color: #999;
}
.innerBeforeInput .line {
margin-left: 10px;
}
.innerAfterInput {
margin-right: 10px;
color: #999;
}
.innerAfterInput .line {
margin-right: 10px;
vertical-align: middle;
}
.sendCode {
max-width: 65px;
margin-right: 10px;
}
.otherLogin {
color: #666;
font-size: 14px;
}
.icon {
margin-left: 10px;
}
.link {
color: #5584ff;
font-size: 14px;
text-align: left;
}
.submitBtn {
width: 100%;
}
}
}

26
src/pages/login/index.tsx

@ -1,22 +1,18 @@
import SelectLang from '@/components/select-lang'
import { createFileRoute, useSearch, useNavigate } from '@tanstack/react-router'
import { Button, Form, Input, message, Space } from 'antd'
import { useAtom } from 'jotai'
import { createFileRoute } from '@tanstack/react-router'
import { Button, Form, Input, Space } from 'antd'
import { useAtom, useAtomValue } from 'jotai'
import { useTranslation } from '@/i18n.ts'
import { loginAtom, loginFormAtom } from '@/store/user.ts'
import { memo, useEffect, useLayoutEffect } from 'react'
// import './index.css'
import { memo, useLayoutEffect } from 'react'
import { useStyles } from './style.ts'
const Login = memo(() => {
const { styles } = useStyles()
const navigator = useNavigate()
// @ts-ignore 从url中获取redirect参数
const search = useSearch({ form: '/login' })
const { t } = useTranslation()
const [ values, setValues ] = useAtom(loginFormAtom)
const [ { isPending, isSuccess, mutate } ] = useAtom(loginAtom)
const { isPending, mutate } = useAtomValue(loginAtom)
const [ form ] = Form.useForm()
const handleSubmit = () => {
@ -25,19 +21,11 @@ const Login = memo(() => {
})
}
useEffect(() => {
if (isSuccess) {
message.success(t('login.success'))
navigator({
to: search?.redirect ?? '/'
})
}
}, [ isSuccess ])
useLayoutEffect(()=>{
useLayoutEffect(() => {
document.body.className = 'login'
return ()=>{
return () => {
document.body.className = document.body.className.replace('login', '')
}

7
src/request.ts

@ -52,6 +52,12 @@ axiosInstance.interceptors.response.use(
//login
if (response.config.url?.includes('/sys/login')) {
setToken(result.data.token)
const search = new URLSearchParams(window.location.search)
// eslint-disable-next-line no-case-declarations
const redirect = search.get('redirect')
if (redirect) {
window.location.href = redirect
}
}
return response
case 401:
@ -60,7 +66,6 @@ axiosInstance.interceptors.response.use(
return Promise.reject(new Error('to login'))
}
// 401: 未登录
message.error('登录失败,跳转重新登录')
// eslint-disable-next-line no-case-declarations

27
src/routes.tsx

@ -22,10 +22,12 @@ import {
RouterProvider,
} from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
import { memo } from 'react'
import { memo, useEffect, useRef } from 'react'
import RootLayout from './layout/RootLayout'
import { IRootContext, MenuItem } from './global'
import { DevTools } from 'jotai-devtools'
import { useAtomValue } from 'jotai'
import { userMenuDataAtom } from '@/store/user.ts'
const PageRootLayout = () => {
return <PageStoreProvider>
@ -279,7 +281,25 @@ const routeTree = rootRoute.addChildren(
export const RootProvider = memo((props: { context: Partial<IRootContext> }) => {
generateDynamicRoutes(props.context.menuData ?? [], layoutAuthRoute)
const { data: menuData, isLoading, refetch } = useAtomValue(userMenuDataAtom)
const isFetchRef = useRef(false)
useEffect(() => {
if (isFetchRef.current) {
return
}
isFetchRef.current = true
refetch()
}, [])
if (isLoading) {
return <PageLoading/>
}
generateDynamicRoutes(menuData ?? [], layoutAuthRoute)
const router = createRouter({
routeTree,
@ -288,9 +308,10 @@ export const RootProvider = memo((props: { context: Partial<IRootContext> }) =>
defaultPendingComponent: () => <Loading loading={true} delay={300}/>
})
return (
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} context={{ ...props.context, queryClient }}/>
<RouterProvider router={router} context={{ ...props.context, menuData, queryClient }}/>
</QueryClientProvider>
)
})
Loading…
Cancel
Save