diff --git a/.gitignore b/.gitignore index f3f09f2..d6be306 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ npm-debug.log yarn-error.log yarn.lock package-lock.json +pnpm-lock.yaml # ide .idea diff --git a/.umirc b/.umirc new file mode 100644 index 0000000..3da267f --- /dev/null +++ b/.umirc @@ -0,0 +1,5 @@ +import routes from './config/routes' + +export default { + routes +} \ No newline at end of file diff --git a/config/config.prod.ts b/config/config.prod.ts index 3878130..4fde2e2 100644 --- a/config/config.prod.ts +++ b/config/config.prod.ts @@ -1,6 +1,4 @@ -import type { IConfig } from 'umi' - -const config: IConfig = { +const config = { publicPath: 'https://cdn.antd-admin.zuiidea.com/', } diff --git a/config/config.ts b/config/config.ts index eccf876..c3a2d79 100644 --- a/config/config.ts +++ b/config/config.ts @@ -1,30 +1,22 @@ /** * see more, https://umijs.org/config */ -import type { IConfig } from 'umi' import lessToJs from 'less-vars-to-js' import fs from 'fs' import path from 'path' -import routes from './routes' import proxy from './proxy' const theme = lessToJs( fs.readFileSync(path.join(__dirname, '../src/themes/default.less'), 'utf8') ) -const config: IConfig = { +const config = { hash: true, ignoreMomentLocale: true, targets: { ie: 11 }, - dynamicImport: {}, theme, proxy, - routes, devtool: 'eval', - nodeModulesTransform: { - type: 'none', - exclude: [], - }, mock: { exclude: ['utils/index'], }, @@ -62,8 +54,6 @@ const config: IConfig = { chainWebpack: (memo) => { memo.module.rule('po').test(/\.po$/).use('po').loader('@lingui/loader') }, - fastRefresh: {}, - esbuild: {}, } export default config diff --git a/config/routes.ts b/config/routes.ts index 063ecd0..c890a50 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -1,10 +1,8 @@ -import type { IRoute } from 'umi' - -const routes: IRoute[] = [ +const routes = [ { exact: false, path: '/', - component: '@/layouts', + component: '@/layouts/index', routes: [ { exact: true, path: '/login', component: '@/pages/login' }, { exact: true, path: '/user', component: '@/pages/user' }, diff --git a/package.json b/package.json index 0bf83e5..55e917f 100644 --- a/package.json +++ b/package.json @@ -1,74 +1,73 @@ { "name": "antd-admin", - "version": "5.3.0", + "version": "6.0.0-a.1", "license": "MIT", "description": "An admin dashboard application demo built upon Ant Design and UmiJS", "dependencies": { - "@ant-design/icons": "^4.6.2", - "@ant-design/pro-layout": "^6.16.0", - "@lingui/core": "^3.8.2", - "@lingui/detect-locale": "^3.8.2", - "@lingui/react": "^3.8.2", - "antd": "^4.15.0", - "axios": "^0.21.0", - "classnames": "^2.2.6", + "@ant-design/icons": "^4.7.0", + "@ant-design/pro-layout": "^6.35.0", + "@lingui/core": "^3.13.3", + "@lingui/detect-locale": "^3.13.3", + "@lingui/react": "^3.13.3", + "antd": "^4.20.1", + "axios": "^0.27.2", + "classnames": "^2.3.1", "dva-model-extend": "^0.1.2", - "echarts": "^5.0.0", - "echarts-for-react": "^3.0.0", - "echarts-gl": "^2.0.2", - "echarts-liquidfill": "^3.0.0", + "echarts": "^5.3.2", + "echarts-for-react": "^3.0.2", + "echarts-gl": "^2.0.9", + "echarts-liquidfill": "^3.1.0", "json-format": "^1.0.1", - "lodash": "^4.17.11", - "md5": "^2.2.1", + "lodash": "^4.17.21", + "make-plural": "^7.1.0", + "md5": "^2.3.0", "nprogress": "^0.2.0", - "path-to-regexp": "^6.1.0", - "prop-types": "^15.7.0", - "qs": "^6.10.0", - "react": "^17.0.2", - "react-countup": "^4.2.0", - "react-dom": "^17.0.2", - "react-helmet": "^6.0.0", + "path-to-regexp": "^6.2.0", + "prop-types": "^15.8.1", + "qs": "^6.10.3", + "react": "^18.1.0", + "react-countup": "^6.2.0", + "react-dom": "^18.1.0", + "react-helmet": "^6.1.0", "react-highcharts": "^16.1.0", - "react-perfect-scrollbar": "^1.5.0", - "recharts": "^2.0.0", - "store": "^2.0.0" + "react-perfect-scrollbar": "^1.5.8", + "react-router-dom": "^6.3.0", + "recharts": "^2.1.9", + "store": "^2.0.12" }, "devDependencies": { - "@babel/preset-react": "^7.12.13", + "@babel/preset-react": "^7.16.7", "@lingui/babel-preset-react": "^2.9.2", - "@lingui/cli": "^3.8.2", - "@lingui/loader": "^3.8.2", - "@lingui/macro": "^3.8.2", - "@typescript-eslint/eslint-plugin": "^4.20.0", - "@typescript-eslint/parser": "^4.20.0", - "@umijs/plugin-esbuild": "^1.2.0", - "@umijs/preset-react": "^1.8.0", - "babel-eslint": "^10.0.0", - "babel-plugin-dev-expression": "^0.2.1", - "babel-plugin-import": "^1.10.0", - "babel-plugin-macros": "^3.0.1", - "babel-plugin-module-resolver": "^3.1.1", - "cross-env": "^7.0.0", - "eslint": "^7.23.0", - "eslint-config-prettier": "^8.1.0", - "eslint-config-react-app": "^6.0.0", + "@lingui/cli": "^3.13.3", + "@lingui/loader": "^3.13.3", + "@lingui/macro": "^3.13.3", + "@typescript-eslint/eslint-plugin": "^5.21.0", + "@typescript-eslint/parser": "^5.21.0", + "babel-plugin-dev-expression": "^0.2.3", + "babel-plugin-import": "^1.13.5", + "babel-plugin-macros": "^3.1.0", + "babel-plugin-module-resolver": "^4.1.0", + "cross-env": "^7.0.3", + "eslint": "^8.14.0", + "eslint-config-prettier": "^8.5.0", + "eslint-config-react-app": "^7.0.1", "eslint-plugin-babel": "^5.3.1", - "eslint-plugin-flowtype": "^5.4.0", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-prettier": "^3.3.1", - "eslint-plugin-react": "^7.23.1", - "eslint-plugin-react-hooks": "^4.2.0", - "husky": "^6.0.0", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-react": "^7.29.4", + "eslint-plugin-react-hooks": "^4.5.0", + "husky": "^7.0.4", "less-vars-to-js": "^1.3.0", - "lint-staged": "^10.0.0", + "lint-staged": "^12.4.1", "mockjs": "^1.1.0", - "prettier": "^2.0.0", - "stylelint": "^13.2.0", - "stylelint-config-prettier": "^8.0.0", - "stylelint-config-standard": "^21.0.0", - "typescript": "^4.2.3", - "umi": "^3.4.25" + "prettier": "^2.6.2", + "stylelint": "^14.8.0", + "stylelint-config-prettier": "^9.0.3", + "stylelint-config-standard": "^25.0.0", + "typescript": "^4.6.3", + "umi": "4.0.0-canary.20220428.1" }, "engines": { "node": ">= 10.0.0" @@ -84,31 +83,18 @@ ] }, "lingui": { - "fallbackLocales": { - "default": "en" - }, + "fallbackLocales": { "default": "en" }, "sourceLocale": "en", - "locales": [ - "en", - "zh", - "pt-br" - ], + "locales": [ "en", "zh", "pt-br"], "catalogs": [ { "path": "src/locales/{locale}/messages", - "include": [ - "src/pages" - ], - "exclude": [ - "**/node_modules/**" - ] + "include": ["src"], + "exclude": ["**/node_modules/**"] } ], - "orderBy": "origin", - "runtimeConfigModule": [ - "@/i18n", - "i18n" - ] + "format": "minimal", + "runtimeConfigModule": ["@/hooks/useIntlProvider", "i18n"] }, "scripts": { "start": "umi dev", diff --git a/src/hooks/index.ts b/src/hooks/index.ts index ded67ae..e487280 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1,13 +1,16 @@ -import { useHistory, useLocation, UseRequestProvider } from 'umi' -import useIntlProvider from './useIntlProvider' +import { useNavigate, useLocation } from 'react-router-dom'; +import { useLingui } from '@lingui/react'; import useConfig from './useConfig' -import useRequest from './useRequest' +import useIntlProvider from './useIntlProvider' +import useLocalStorage from './useLocalStorage'; +import useRequest from './useRequest'; export { - useIntlProvider, - useHistory, + useConfig, + useNavigate, useLocation, useRequest, - UseRequestProvider, - useConfig, + useLocalStorage, + useIntlProvider, + useLingui, } diff --git a/src/hooks/useIntlProvider.ts b/src/hooks/useIntlProvider.ts index df069fb..1df3e9b 100644 --- a/src/hooks/useIntlProvider.ts +++ b/src/hooks/useIntlProvider.ts @@ -1,42 +1,47 @@ -import { useEffect, useContext, useState, useCallback } from 'react' -import { ConfigContext } from '@/utils/context' -import { LOCALE_LANGUAGE } from '@/configs' -import { ISupportedLocales } from '@/typings' -import { ConfigProviderProps } from 'antd/lib/config-provider' -import { antdI18nMap } from '@/configs' -import { i18n } from '@/i18n' -import zh_CN from 'antd/lib/locale/zh_CN' -import en_US from 'antd/lib/locale/en_US' -import pt_BR from 'antd/lib/locale/pt_BR' +import { useEffect, useContext, useState } from 'react'; +import { setupI18n } from '@lingui/core'; +import { LOCALE_LANGUAGE } from '@/configs/constants'; +import { ConfigContext } from '@/utils/context'; +import { useLocalStorage } from '@/hooks'; +import { antdI18nMap } from '@/configs'; +import { SupportedLocales } from '@/typings'; +import { ConfigProviderProps } from 'antd/lib/config-provider'; +import { en, zh } from 'make-plural/plurals'; -const antdLocaleMap = { - zh_CN, - en_US, - pt_BR -} +export const i18n = setupI18n({ + localeData: { + en: { plurals: en }, + zh: { plurals: zh }, + }, +}); const useIntlProvider = () => { - const { language } = useContext(ConfigContext) - const [locale, setLocale] = useState() + const { language: defaultLocale } = useContext(ConfigContext); + const [language, setLanguage] = useLocalStorage( + LOCALE_LANGUAGE, + defaultLocale + ); + + const [locale, setLocale] = useState(); useEffect(() => { - setLocale(antdLocaleMap[antdI18nMap[language]]) - localStorage.setItem(LOCALE_LANGUAGE, language) - }, [language]) + import(`@/locales/${language}/messages.json`).then(data => { + i18n.load(language, data.default); + i18n.activate(language); + }); - const setLanguage = useCallback((language: ISupportedLocales) => { - if (language !== i18n.locale) { - localStorage.setItem(LOCALE_LANGUAGE, language) - window.location.reload() - } - }, []) + const path = antdI18nMap[language]; + import(`antd/lib/locale/${path}.js`).then(data => { + setLocale(data.default); + }); + }, [language]); return { language, setLanguage, locale, i18n, - } -} + }; +}; -export default useIntlProvider +export default useIntlProvider; diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts new file mode 100644 index 0000000..ee49f12 --- /dev/null +++ b/src/hooks/useLocalStorage.ts @@ -0,0 +1,29 @@ +import { useState } from 'react'; + +const useLocalStorage = ( + key: string, + initialValue?: T +): [T, (value: T) => void] => { + let defaultValue = initialValue; + try { + const item = window.localStorage.getItem(key); + defaultValue = item ? JSON.parse(item) : initialValue; + } catch (error) { + defaultValue = initialValue; + } + + const [state, setState] = useState(defaultValue as T); + const setValue = (value: T) => { + try { + const valueToStore = value instanceof Function ? value(state) : value; + setState(valueToStore); + window.localStorage.setItem(key, JSON.stringify(valueToStore)); + } catch (error) { + console.log(error); + } + }; + + return [state, setValue]; +}; + +export default useLocalStorage; diff --git a/src/layouts/PrimaryLayout/HeaderRightContent.tsx b/src/layouts/PrimaryLayout/HeaderRightContent.tsx index 0c80925..b8641dc 100644 --- a/src/layouts/PrimaryLayout/HeaderRightContent.tsx +++ b/src/layouts/PrimaryLayout/HeaderRightContent.tsx @@ -3,7 +3,8 @@ 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 { history } from 'umi' +import { useRequest, useConfig } from '@/hooks' import { logoutUser } from '@/services' import styles from './index.less' @@ -12,7 +13,6 @@ 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'), diff --git a/src/layouts/index.tsx b/src/layouts/index.tsx index e5830be..02d5c7b 100644 --- a/src/layouts/index.tsx +++ b/src/layouts/index.tsx @@ -1,12 +1,13 @@ import React from 'react' +import { history } from 'umi' import { ConfigProvider } from 'antd' import { I18nProvider } from '@lingui/react' import { useIntlProvider, useRequest, - UseRequestProvider, - useHistory, } from '@/hooks' +// @ts-ignore +import { Outlet } from 'umi' import { ConfigContext } from '@/utils/context' import request from '@/utils/request' import { queryUserInfo, IUserInfo } from '@/services' @@ -14,7 +15,6 @@ import BaseLayout from './BaseLayout' const Layout: React.FC = (props) => { const { language, setLanguage, i18n, locale } = useIntlProvider() - const history = useHistory() const { data: userInfo, @@ -43,13 +43,7 @@ const Layout: React.FC = (props) => { - - {props.children} - + diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 5657612..a5628e6 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { Redirect } from 'umi' +import { Navigate } from 'react-router-dom' -const Index: React.FC = () => +const Index: React.FC = () => export default Index diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index 8ddfb2b..bf5965f 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -1,10 +1,11 @@ import React from 'react' +import { history } from 'umi' import { Button, Row, Input, Form } from 'antd' 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 { useRequest, useConfig } from '@/hooks' import { loginUser, ILoginUserParams } from '@/services' import styles from './index.less' @@ -27,7 +28,7 @@ const Login: React.FC = () => { const { run: runLogin, loading } = useRequest(loginUser, { manual: true, }) - const history = useHistory() + const { queryUserInfo } = useConfig() const handleFinish = (values: ILoginUserParams) => { diff --git a/src/pages/user/index.tsx b/src/pages/user/index.tsx index f49a335..08e755b 100644 --- a/src/pages/user/index.tsx +++ b/src/pages/user/index.tsx @@ -54,11 +54,13 @@ const columns: ColumnType[] = [ { title: Email, dataIndex: 'email', + ellipsis: true, key: 'email', }, { title: Address, dataIndex: 'address', + ellipsis: true, key: 'address', }, {