diff --git a/config/config.ts b/config/config.ts
index 82e6426..653776c 100644
--- a/config/config.ts
+++ b/config/config.ts
@@ -25,6 +25,9 @@ const config: IConfig = {
type: 'none',
exclude: [],
},
+ mock: {
+ exclude: ['utils/index'],
+ },
extraBabelPresets: ['@lingui/babel-preset-react'],
extraBabelPlugins: [
'macros',
diff --git a/mock/dashboard.js b/mock/dashboard.ts
similarity index 97%
rename from mock/dashboard.js
rename to mock/dashboard.ts
index 8758594..8c37dd2 100644
--- a/mock/dashboard.js
+++ b/mock/dashboard.ts
@@ -1,4 +1,5 @@
-import { Mock, Constant } from './_utils'
+import Mock from 'mockjs'
+import { Constant } from './utils'
const { ApiPrefix, Color } = Constant
@@ -135,7 +136,7 @@ const Dashboard = Mock.mock({
],
})
-module.exports = {
+export default {
[`GET ${ApiPrefix}/dashboard`](req, res) {
res.json(Dashboard)
},
diff --git a/mock/index.d.ts b/mock/index.d.ts
new file mode 100644
index 0000000..ca310a9
--- /dev/null
+++ b/mock/index.d.ts
@@ -0,0 +1,2 @@
+declare module 'mockjs'
+declare module 'qs'
diff --git a/mock/route.js b/mock/route.ts
similarity index 97%
rename from mock/route.js
rename to mock/route.ts
index ad9c809..91a43e8 100644
--- a/mock/route.js
+++ b/mock/route.ts
@@ -1,4 +1,4 @@
-import { Constant } from './_utils'
+import { Constant } from './utils'
const { ApiPrefix } = Constant
const database = [
@@ -148,7 +148,7 @@ const database = [
},
]
-module.exports = {
+export default {
[`GET ${ApiPrefix}/routes`](req, res) {
res.status(200).json(database)
},
diff --git a/mock/user.js b/mock/user.ts
similarity index 73%
rename from mock/user.js
rename to mock/user.ts
index 4ffd4d3..76df5a2 100644
--- a/mock/user.js
+++ b/mock/user.ts
@@ -1,9 +1,10 @@
-import { Mock, Constant, randomAvatar } from './_utils'
+import Mock from 'mockjs'
import qs from 'qs'
+import { Constant, randomAvatar, waitTime } from './utils'
const { ApiPrefix } = Constant
-let usersListData = Mock.mock({
+const usersListData = Mock.mock({
'data|80-100': [
{
id: '@id',
@@ -91,10 +92,28 @@ const NOTFOUND = {
documentation_url: 'http://localhost:8000/request',
}
-module.exports = {
- [`POST ${ApiPrefix}/user/login`](req, res) {
+const authorized = (req, res) => {
+ const cookie = req.headers.cookie || ''
+ const cookies = qs.parse(cookie.replace(/\s/g, ''), { delimiter: ';' })
+ if (!cookies.token) {
+ res.status(401).send({ message: 'Not Login' })
+ return false
+ }
+
+ const token = JSON.parse(cookies.token)
+ if (cookies.token && token && token.deadline > new Date().getTime()) {
+ return token
+ }
+
+ res.status(401).send({ message: 'Not Login' })
+ return false
+}
+
+export default {
+ async [`POST ${ApiPrefix}/user/login`](req, res) {
+ await waitTime()
const { username, password } = req.body
- const user = adminUsers.filter(item => item.username === username)
+ const user = adminUsers.filter((item) => item.username === username)
if (user.length > 0 && user[0].password === password) {
const now = new Date()
@@ -113,33 +132,27 @@ module.exports = {
}
},
- [`GET ${ApiPrefix}/user/logout`](req, res) {
+ async [`GET ${ApiPrefix}/user/logout`](req, res) {
+ await waitTime()
res.clearCookie('token')
res.status(200).end()
},
- [`GET ${ApiPrefix}/user`](req, res) {
- const cookie = req.headers.cookie || ''
- const cookies = qs.parse(cookie.replace(/\s/g, ''), { delimiter: ';' })
- const response = {}
- let user = {}
- if (!cookies.token) {
- res.status(200).send({ message: 'Not Login' })
+ async [`GET ${ApiPrefix}/user`](req, res) {
+ await waitTime()
+
+ const token = authorized(req, res)
+ if (!token) {
return
}
- const token = JSON.parse(cookies.token)
- if (token) {
- response.success = token.deadline > new Date().getTime()
+
+ const userItem = adminUsers.find((_) => _.id === token.id)
+ if (userItem) {
+ const { password, ...rest } = userItem
+ res.json(rest)
+ } else {
+ res.status(401).send({ message: 'Not Login' })
}
- if (response.success) {
- const userItem = adminUsers.find(_ => _.id === token.id)
- if (userItem) {
- const { password, ...other } = userItem
- user = other
- }
- }
- response.user = user
- res.json(response)
},
[`GET ${ApiPrefix}/users`](req, res) {
@@ -151,10 +164,10 @@ module.exports = {
let newData = database
for (let key in other) {
if ({}.hasOwnProperty.call(other, key)) {
- newData = newData.filter(item => {
+ newData = newData.filter((item) => {
if ({}.hasOwnProperty.call(item, key)) {
if (key === 'address') {
- return other[key].every(iitem => item[key].indexOf(iitem) > -1)
+ return other[key].every((iitem) => item[key].indexOf(iitem) > -1)
} else if (key === 'createTime') {
const start = new Date(other[key][0]).getTime()
const end = new Date(other[key][1]).getTime()
@@ -166,9 +179,8 @@ module.exports = {
return true
}
return (
- String(item[key])
- .trim()
- .indexOf(decodeURI(other[key]).trim()) > -1
+ String(item[key]).trim().indexOf(decodeURI(other[key]).trim()) >
+ -1
)
}
return true
@@ -183,8 +195,8 @@ module.exports = {
},
[`POST ${ApiPrefix}/users/delete`](req, res) {
- const { ids=[] } = req.body
- database = database.filter(item => !ids.some(_ => _ === item.id))
+ const { ids = [] } = req.body
+ database = database.filter((item) => !ids.some((_) => _ === item.id))
res.status(204).end()
},
@@ -221,7 +233,7 @@ module.exports = {
const { id } = req.params
const data = queryArray(database, id, 'id')
if (data) {
- database = database.filter(item => item.id !== id)
+ database = database.filter((item) => item.id !== id)
res.status(204).end()
} else {
res.status(200).json(NOTFOUND)
@@ -233,7 +245,7 @@ module.exports = {
const editItem = req.body
let isExist = false
- database = database.map(item => {
+ database = database.map((item) => {
if (item.id === id) {
isExist = true
return Object.assign({}, item, editItem)
diff --git a/mock/_utils.js b/mock/utils/index.ts
similarity index 80%
rename from mock/_utils.js
rename to mock/utils/index.ts
index 2229c12..2bb1f38 100644
--- a/mock/_utils.js
+++ b/mock/utils/index.ts
@@ -9,7 +9,7 @@ export function queryArray(array, key, value) {
if (!Array.isArray(array)) {
return
}
- return array.filter(_ => _[key] === value)
+ return array.filter((_) => _[key] === value)
}
export function randomNumber(min, max) {
@@ -30,9 +30,19 @@ export function randomAvatar() {
'photo-1551438632-e8c7d9a5d1b7.jpeg',
'photo-1525879000488-bff3b1c387cf.jpeg',
'photo-1487412720507-e7ab37603c6f.jpeg',
- 'photo-1510227272981-87123e259b17.jpeg'
+ 'photo-1510227272981-87123e259b17.jpeg',
]
- return `//image.zuiidea.com/${avatarList[randomNumber(0, avatarList.length - 1)]}?imageView2/1/w/200/h/200/format/webp/q/75|imageslim`
+ return `//image.zuiidea.com/${
+ avatarList[randomNumber(0, avatarList.length - 1)]
+ }?imageView2/1/w/200/h/200/format/webp/q/75|imageslim`
+}
+
+export const waitTime = (time: number = 300) => {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(true)
+ }, time)
+ })
}
export const Constant = {
@@ -54,6 +64,3 @@ export const Constant = {
sky: '#c1e0fc',
},
}
-
-export Mock from 'mockjs'
-export qs from 'qs'
diff --git a/src/configs/default/index.ts b/src/configs/default/index.ts
index 63097b8..ba50812 100644
--- a/src/configs/default/index.ts
+++ b/src/configs/default/index.ts
@@ -20,6 +20,7 @@ export const config: IConfig = {
logo: 'logo.svg',
copyright: 'Ant Design Admin © 2021 zuiidea',
language: language as ISupportedLocales,
+ apiPrefix: '/api/v1',
/* Layout configuration, specify which layout to use for route. */
layouts: [
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index d9591b9..d576f0c 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -1,4 +1,12 @@
-import { useHistory, useLocation } from 'umi'
+import { useHistory, useLocation, useRequest, UseRequestProvider } from 'umi'
import useIntlProvider from './useIntlProvider'
+import useConfig from './useConfig'
-export { useIntlProvider, useHistory, useLocation }
+export {
+ useIntlProvider,
+ useHistory,
+ useLocation,
+ useRequest,
+ UseRequestProvider,
+ useConfig,
+}
diff --git a/src/hooks/useConfig.ts b/src/hooks/useConfig.ts
new file mode 100644
index 0000000..c19c396
--- /dev/null
+++ b/src/hooks/useConfig.ts
@@ -0,0 +1,8 @@
+import { useContext } from 'react'
+import { ConfigContext } from '@/utils/context'
+
+const useConfig = () => {
+ return useContext(ConfigContext)
+}
+
+export default useConfig
diff --git a/src/layouts/BaseLayout.tsx b/src/layouts/BaseLayout.tsx
index b98ae6e..f2a3c1b 100644
--- a/src/layouts/BaseLayout.tsx
+++ b/src/layouts/BaseLayout.tsx
@@ -3,7 +3,7 @@ import { useLocation } from '@/hooks'
import { queryLayout } from '@/utils'
import { config } from '@/configs'
import PublicLayout from './PublicLayout'
-import PrimaryLayout from './PrimaryLayout'
+import PrimaryLayout from './PrimaryLayout/index'
import './BaseLayout.less'
const LayoutMap = {
diff --git a/src/layouts/PrimaryLayout/HeaderRightContent.tsx b/src/layouts/PrimaryLayout/HeaderRightContent.tsx
new file mode 100644
index 0000000..0c80925
--- /dev/null
+++ b/src/layouts/PrimaryLayout/HeaderRightContent.tsx
@@ -0,0 +1,69 @@
+import React from 'react'
+import { Dropdown, Menu, Avatar } from 'antd'
+import { language, languages } from '@/configs'
+import { ISupportedLocales } from '@/typings'
+import { Trans } from '@lingui/macro'
+import { useRequest, useHistory, useConfig } from '@/hooks'
+import { logoutUser } from '@/services'
+import styles from './index.less'
+
+const { SubMenu } = Menu
+
+const NotFoundPage: React.FC = () => {
+ const { language: locale, setLanguage, userInfo } = useConfig()
+ const currentLanguage = language[locale]
+ const history = useHistory()
+ const { run: runLogoutUser } = useRequest(logoutUser, {
+ manual: true,
+ onSuccess: () => history.push('/login'),
+ })
+
+ return (
+ <>
+ {
+ setLanguage(data.key as ISupportedLocales)
+ }}
+ >
+ {languages.map((item) => (
+
+
+ {item.value}
+
+ ))}
+
+ }
+ >
+
+
+
+ >
+ )
+}
+
+export default NotFoundPage
diff --git a/src/layouts/PrimaryLayout.less b/src/layouts/PrimaryLayout/index.less
similarity index 91%
rename from src/layouts/PrimaryLayout.less
rename to src/layouts/PrimaryLayout/index.less
index 6ee60c9..d379e7a 100644
--- a/src/layouts/PrimaryLayout.less
+++ b/src/layouts/PrimaryLayout/index.less
@@ -1,5 +1,9 @@
-@import '~themes/vars.less';
-
+@import '~@/themes/vars.less';
+:global {
+ #root {
+ height: 100%;
+ }
+}
.backTop {
right: 50px;
diff --git a/src/layouts/PrimaryLayout.tsx b/src/layouts/PrimaryLayout/index.tsx
similarity index 64%
rename from src/layouts/PrimaryLayout.tsx
rename to src/layouts/PrimaryLayout/index.tsx
index ad41617..6e59ccb 100644
--- a/src/layouts/PrimaryLayout.tsx
+++ b/src/layouts/PrimaryLayout/index.tsx
@@ -1,24 +1,15 @@
-import React, {
- useState,
- useEffect,
- useMemo,
- useCallback,
- useContext,
-} from 'react'
+import React, { useState, useEffect, useMemo, useCallback } from 'react'
import ProBasicLayout, {
getMenuData,
MenuDataItem,
SettingDrawerProps,
} from '@ant-design/pro-layout'
import { Link } from 'umi'
-import { Dropdown, Menu, Avatar } from 'antd'
import { useLocation } from '@/hooks'
-import { ConfigContext } from '@/utils/context'
-import { menus, menuIcon, language, languages, config } from '@/configs'
+import { menus, menuIcon, config } from '@/configs'
import defaultSettings from '@/defaultSettings'
-import { ISupportedLocales } from '@/typings'
import type { MenuProps } from 'antd/es/menu'
-import styles from './index.less'
+import HeaderRightContent from './HeaderRightContent'
const renderMenuItem = (menus: MenuDataItem[]): MenuDataItem[] =>
menus.map(({ icon, children, ...item }) => ({
@@ -34,8 +25,6 @@ const PrimaryLayout: React.FC = (props) => {
const [selectedKeys, setSelectedKeys] = useState(['/'])
const { pathname } = location
const { breadcrumbMap, menuData } = useMemo(() => getMenuData(menus), [])
- const { language: locale, setLanguage } = useContext(ConfigContext)
- const currentLanguage = language[locale]
useEffect(() => {
const select = breadcrumbMap.get(pathname)
@@ -68,30 +57,6 @@ const PrimaryLayout: React.FC = (props) => {
[handleOnOpenChange, openKeys, selectedKeys]
)
- const rightContentRender = () => (
- {
- setLanguage(data.key as ISupportedLocales)
- }}
- >
- {languages.map((item) => (
-
-
- {item.value}
-
- ))}
-
- }
- >
-
-
- )
-
return (
<>
{
menuDataRender={menuDataRender}
menuItemRender={menuItemRender}
menuProps={menuProps}
- rightContentRender={rightContentRender}
+ rightContentRender={() => }
>
{props.children}
diff --git a/src/layouts/index.tsx b/src/layouts/index.tsx
index cfe4f61..e5830be 100644
--- a/src/layouts/index.tsx
+++ b/src/layouts/index.tsx
@@ -1,21 +1,55 @@
import React from 'react'
import { ConfigProvider } from 'antd'
import { I18nProvider } from '@lingui/react'
-import { useIntlProvider } from '@/hooks'
+import {
+ useIntlProvider,
+ useRequest,
+ UseRequestProvider,
+ useHistory,
+} from '@/hooks'
import { ConfigContext } from '@/utils/context'
+import request from '@/utils/request'
+import { queryUserInfo, IUserInfo } from '@/services'
import BaseLayout from './BaseLayout'
const Layout: React.FC = (props) => {
const { language, setLanguage, i18n, locale } = useIntlProvider()
+ const history = useHistory()
+
+ const {
+ data: userInfo,
+ run: runQueryUserInfo,
+ loading,
+ } = useRequest(queryUserInfo, {
+ onError: (data: any) => {
+ if (data.statusCode === 401) {
+ history.push('/login')
+ }
+ },
+ })
+
const globalConfig = {
language,
setLanguage,
+ userInfo: userInfo as IUserInfo,
+ queryUserInfo: runQueryUserInfo,
}
+
+ if (loading) {
+ return loading
+ }
+
return (
- {props.children}
+
+ {props.children}
+
diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx
index 8ba53ac..8ddfb2b 100644
--- a/src/pages/login/index.tsx
+++ b/src/pages/login/index.tsx
@@ -4,27 +4,37 @@ import { GithubOutlined } from '@ant-design/icons'
import { GlobalFooter } from '@/components'
import { Trans, t } from '@lingui/macro'
import { config, languages } from '@/configs'
+import { useRequest, useHistory, useConfig } from '@/hooks'
+import { loginUser, ILoginUserParams } from '@/services'
import styles from './index.less'
const FormItem = Form.Item
-const Login: React.FC = () => {
- const footerLinks = [
- {
- key: 'github',
- title: ,
- href: 'https://github.com/zuiidea/antd-admin',
- blankTarget: true,
- },
- ...languages.map((item) => ({
- key: item.key,
- title: {item.value},
- })),
- ]
+const footerLinks = [
+ {
+ key: 'github',
+ title: ,
+ href: 'https://github.com/zuiidea/antd-admin',
+ blankTarget: true,
+ },
+ ...languages.map((item) => ({
+ key: item.key,
+ title: {item.value},
+ })),
+]
- const handleFinish = (values) => {
- // eslint-disable-next-line no-console
- console.log(values)
+const Login: React.FC = () => {
+ const { run: runLogin, loading } = useRequest(loginUser, {
+ manual: true,
+ })
+ const history = useHistory()
+ const { queryUserInfo } = useConfig()
+
+ const handleFinish = (values: ILoginUserParams) => {
+ runLogin(values).then(() => {
+ queryUserInfo()
+ history.push('/dashborad')
+ })
}
return (
@@ -50,7 +60,12 @@ const Login: React.FC = () => {
-