dark
7 months ago
19 changed files with 319 additions and 77 deletions
-
2mock/menus.ts
-
2package.json
-
5src/App.tsx
-
11src/layout/EmptyLayout.tsx
-
15src/pages/login/index.tsx
-
5src/pages/system/departments/index.tsx
-
6src/pages/system/menus/index.tsx
-
5src/pages/system/roles/index.tsx
-
5src/pages/system/users/index.tsx
-
63src/request.ts
-
128src/routes.tsx
-
2src/service/base.ts
-
3src/service/system.ts
-
57src/store/system.ts
-
25src/types.d.ts
-
18src/types/menus.d.ts
-
26src/utils/index.ts
-
6tsconfig.json
-
8vite.config.ts
@ -1,10 +1,15 @@ |
|||||
import './App.css' |
import './App.css' |
||||
import { RootProvider } from './routes.tsx' |
import { RootProvider } from './routes.tsx' |
||||
|
import { Provider } from 'jotai' |
||||
|
import { appStore } from '@/store/system.ts' |
||||
|
|
||||
function App() { |
function App() { |
||||
|
|
||||
|
|
||||
return ( |
return ( |
||||
|
<Provider store={appStore}> |
||||
<RootProvider/> |
<RootProvider/> |
||||
|
</Provider> |
||||
) |
) |
||||
} |
} |
||||
|
|
||||
|
@ -0,0 +1,11 @@ |
|||||
|
import { Outlet } from '@tanstack/react-router' |
||||
|
|
||||
|
const EmptyLayout = () => { |
||||
|
return ( |
||||
|
<> |
||||
|
<Outlet/> |
||||
|
</> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
export default EmptyLayout |
@ -0,0 +1,15 @@ |
|||||
|
import { createFileRoute } from '@tanstack/react-router' |
||||
|
|
||||
|
const Login = () => { |
||||
|
return ( |
||||
|
<div> |
||||
|
Login |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
export const Route = createFileRoute("/login")({ |
||||
|
component: Login |
||||
|
}) |
||||
|
|
||||
|
export default Login |
@ -1,19 +1,76 @@ |
|||||
import axios, { AxiosRequestConfig } from 'axios' |
|
||||
|
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios' |
||||
|
import { message } from 'antd' |
||||
|
import { getToken, setToken } from '@/store/system.ts' |
||||
|
|
||||
|
|
||||
export type { AxiosRequestConfig } |
export type { AxiosRequestConfig } |
||||
|
|
||||
|
|
||||
export const request = axios.create({ |
export const request = axios.create({ |
||||
baseURL: '/api/v1', |
baseURL: '/api/v1', |
||||
timeout: 1000, |
|
||||
|
// timeout: 1000,
|
||||
headers: { |
headers: { |
||||
'Content-Type': 'application/json', |
'Content-Type': 'application/json', |
||||
}, |
}, |
||||
}) |
}) |
||||
|
|
||||
|
//拦截request,添加token
|
||||
|
request.interceptors.request.use((config) => { |
||||
|
|
||||
|
const token = getToken() |
||||
|
if (token) { |
||||
|
config.headers.Authorization = `Bearer ${token}` |
||||
|
} |
||||
|
|
||||
|
if (window.location.pathname === '/login') { |
||||
|
|
||||
|
throw new Error('login') |
||||
|
|
||||
|
} else { |
||||
|
const search = new URLSearchParams(window.location.search) |
||||
|
let url = `/login?redirect=${encodeURIComponent(window.location.pathname)}` |
||||
|
if (search.toString() !== '') { |
||||
|
url = `/login?redirect=${encodeURIComponent(window.location.pathname + '?=' + search.toString())}` |
||||
|
} |
||||
|
window.location.href = url |
||||
|
} |
||||
|
return config |
||||
|
}) |
||||
|
|
||||
|
|
||||
//拦截response,返回data
|
//拦截response,返回data
|
||||
request.interceptors.response.use((response) => { |
|
||||
|
request.interceptors.response.use((response: AxiosResponse) => { |
||||
// console.log('response', response.data)
|
// console.log('response', response.data)
|
||||
|
|
||||
|
message.destroy() |
||||
|
|
||||
|
switch (response.data.code) { |
||||
|
case 200: |
||||
|
//login
|
||||
|
if (response.config.url?.includes('/sys/login')) { |
||||
|
setToken(response.data.data.token) |
||||
|
} |
||||
return response.data |
return response.data |
||||
|
case 401: |
||||
|
// 401: 未登录
|
||||
|
message.error('登录失败,跳转重新登录') |
||||
|
// eslint-disable-next-line no-case-declarations
|
||||
|
const search = new URLSearchParams(window.location.search) |
||||
|
// eslint-disable-next-line no-case-declarations
|
||||
|
let redirect = window.location.pathname |
||||
|
if (search.toString() !== '') { |
||||
|
redirect = window.location.pathname + '?=' + search.toString() |
||||
|
} |
||||
|
window.location.href = `/login?redirect=${encodeURIComponent(redirect)}` |
||||
|
break |
||||
|
default: |
||||
|
message.error(response.data.message) |
||||
|
return Promise.reject(response) |
||||
|
} |
||||
|
|
||||
|
}, (error) => { |
||||
|
console.log('error', error) |
||||
|
return Promise.reject(error) |
||||
}) |
}) |
||||
|
|
||||
export default request |
export default request |
@ -0,0 +1,26 @@ |
|||||
|
import { IMenu } from '@/types/menus' |
||||
|
import { MenuItem } from '@/types' |
||||
|
import { getIcon } from '@/components/icon' |
||||
|
|
||||
|
|
||||
|
// 格式化菜单数据, 把children转换成routes
|
||||
|
export const formatMenuData = (data: IMenu[]) => { |
||||
|
const result: MenuItem[] = [] |
||||
|
for (const item of data) { |
||||
|
if (item.icon && typeof item.icon === 'string') { |
||||
|
item.icon = getIcon(item.icon as string, { size: '14', theme: 'filled' }) |
||||
|
} |
||||
|
if (!item.children || !item.children.length) { |
||||
|
result.push(item) |
||||
|
} else { |
||||
|
const { children, ...other } = item |
||||
|
result.push({ |
||||
|
...other, |
||||
|
children, |
||||
|
routes: formatMenuData(children), |
||||
|
}) |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
return result |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue