Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15b62e302d | ||
|
|
9d5ec20f20 | ||
|
|
c878425fd0 | ||
|
|
90e80dda64 | ||
|
|
1db5bfeab5 | ||
|
|
b2b3fcd4a3 | ||
|
|
9cf97375c7 | ||
|
|
7839b6affb | ||
|
|
597064a07d | ||
|
|
0ea57d14c9 | ||
|
|
afd736d615 | ||
|
|
ce9b8c376f | ||
|
|
79776e6752 | ||
|
|
a2432022a1 | ||
|
|
ea5ee96bdc | ||
|
|
fe954092a4 | ||
|
|
5e148fec92 | ||
|
|
5daa2a9548 | ||
|
|
f1913f7b18 | ||
|
|
65a453553e | ||
|
|
29da8f24da | ||
|
|
3443ad9968 | ||
|
|
838dc93eff | ||
|
|
07ef68ec1f | ||
|
|
3cb7f86086 | ||
|
|
fc9565c157 |
@@ -60,9 +60,9 @@ export default {
|
||||
},
|
||||
pwa: {
|
||||
manifestOptions: {
|
||||
srcPath: 'manifest.json'
|
||||
srcPath: 'manifest.json',
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
|
||||
@@ -4,10 +4,33 @@
|
||||
"display": "standalone",
|
||||
"background_color": "#fff",
|
||||
"description": "A front-end solution for enterprise applications built upon Ant Design and UmiJS",
|
||||
"icons": [
|
||||
"icons": [{
|
||||
"src": "logo/logo@96.png",
|
||||
"sizes": "72x72"
|
||||
},
|
||||
{
|
||||
"src": "logo.svg",
|
||||
"sizes": "72x72 96x96 128x128 144x144 152x152 192x192 384x384 512x512"
|
||||
"src": "logo/logo@128.png",
|
||||
"sizes": "128x128"
|
||||
},
|
||||
{
|
||||
"src": "logo/logo@144.png",
|
||||
"sizes": "144x144"
|
||||
},
|
||||
{
|
||||
"src": "logo/logo@152.png",
|
||||
"sizes": "152x152"
|
||||
},
|
||||
{
|
||||
"src": "logo/logo@192.png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo/logo@384.png",
|
||||
"sizes": "384x384"
|
||||
},
|
||||
{
|
||||
"src": "logo/logo@512.png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -17,25 +17,22 @@ export function randomNumber(min, max) {
|
||||
}
|
||||
|
||||
export function randomAvatar() {
|
||||
// https://uifaces.co
|
||||
const avatarList = [
|
||||
'https://randomuser.me/api/portraits/men/32.jpg',
|
||||
'https://images.pexels.com/photos/415829/pexels-photo-415829.jpeg?h=350&auto=compress&cs=tinysrgb',
|
||||
'https://d3iw72m71ie81c.cloudfront.net/female-17.jpg',
|
||||
'https://randomuser.me/api/portraits/men/35.jpg',
|
||||
'https://pbs.twimg.com/profile_images/835224725815246848/jdMBCxHS.jpg',
|
||||
'https://pbs.twimg.com/profile_images/584098247641300992/N25WgvW_.png',
|
||||
'https://d3iw72m71ie81c.cloudfront.net/male-5.jpg',
|
||||
'https://images.pexels.com/photos/413723/pexels-photo-413723.jpeg?h=350&auto=compress&cs=tinysrgb',
|
||||
'https://randomuser.me/api/portraits/women/44.jpg',
|
||||
'https://randomuser.me/api/portraits/women/68.jpg',
|
||||
'https://randomuser.me/api/portraits/women/65.jpg',
|
||||
'https://randomuser.me/api/portraits/men/43.jpg',
|
||||
'https://tinyfac.es/data/avatars/475605E3-69C5-4D2B-8727-61B7BB8C4699-500w.jpeg',
|
||||
'https://pbs.twimg.com/profile_images/943227488292962306/teiNNAiy.jpg',
|
||||
'https://randomuser.me/api/portraits/men/46.jpg'
|
||||
'photo-1549492864-2ec7d66ffb04.jpeg',
|
||||
'photo-1480535339474-e083439a320d.jpeg',
|
||||
'photo-1523419409543-a5e549c1faa8.jpeg',
|
||||
'photo-1519648023493-d82b5f8d7b8a.jpeg',
|
||||
'photo-1523307730650-594bc63f9d67.jpeg',
|
||||
'photo-1522962506050-a2f0267e4895.jpeg',
|
||||
'photo-1489779162738-f81aed9b0a25.jpeg',
|
||||
'photo-1534308143481-c55f00be8bd7.jpeg',
|
||||
'photo-1519336555923-59661f41bb45.jpeg',
|
||||
'photo-1551438632-e8c7d9a5d1b7.jpeg',
|
||||
'photo-1525879000488-bff3b1c387cf.jpeg',
|
||||
'photo-1487412720507-e7ab37603c6f.jpeg',
|
||||
'photo-1510227272981-87123e259b17.jpeg'
|
||||
]
|
||||
return avatarList[randomNumber(0, avatarList.length - 1)]
|
||||
return `//image.zuiidea.com/${avatarList[randomNumber(0, avatarList.length - 1)]}?imageView2/1/w/200/h/200/format/webp/q/75|imageslim`
|
||||
}
|
||||
|
||||
export const Constant = {
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
{
|
||||
"name": "antd-admin",
|
||||
"version": "5.1.0",
|
||||
"version": "5.1.3",
|
||||
"license": "MIT",
|
||||
"description": "An admin dashboard application demo built upon Ant Design and UmiJS",
|
||||
"dependencies": {
|
||||
"@lingui/react": "^2.8.0",
|
||||
"ant-design-pro": "^2.3.0",
|
||||
"antd": "^3.19.0",
|
||||
"antd": "^3.24.0",
|
||||
"axios": "^0.19.0",
|
||||
"classnames": "^2.2.6",
|
||||
"d3-shape": "^1.3.0",
|
||||
"draftjs-to-html": "^0.8.4",
|
||||
"draftjs-to-markdown": "^0.5.1",
|
||||
"dva": "2.4.1",
|
||||
"dva-model-extend": "^0.1.2",
|
||||
"echarts": "^4.2.0",
|
||||
"echarts-for-react": "^2.0.15-beta.0",
|
||||
"echarts": "^4.4.0",
|
||||
"echarts-for-react": "^2.0.15-beta.1",
|
||||
"echarts-gl": "^1.1.1",
|
||||
"echarts-liquidfill": "^2.0.2",
|
||||
"enquire-js": "^0.2.1",
|
||||
@@ -24,16 +25,16 @@
|
||||
"lodash": "^4.17.11",
|
||||
"md5": "^2.2.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"path-to-regexp": "^3.0.0",
|
||||
"path-to-regexp": "^3.1.0",
|
||||
"prop-types": "^15.7.0",
|
||||
"qs": "^6.7.0",
|
||||
"qs": "^6.9.0",
|
||||
"react-adsense": "^0.1.0",
|
||||
"react-countup": "^4.1.0",
|
||||
"react-countup": "^4.2.0",
|
||||
"react-draft-wysiwyg": "^1.13.0",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-highcharts": "^16.0.2",
|
||||
"react-highcharts": "^16.1.0",
|
||||
"react-perfect-scrollbar": "^1.5.0",
|
||||
"recharts": "^1.6.0",
|
||||
"recharts": "^1.8.0",
|
||||
"store": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -44,27 +45,27 @@
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-plugin-dev-expression": "^0.2.1",
|
||||
"babel-plugin-import": "^1.12.0",
|
||||
"babel-plugin-macros": "^2.5.0",
|
||||
"babel-plugin-macros": "^2.6.0",
|
||||
"babel-plugin-module-resolver": "^3.2.0",
|
||||
"cross-env": "^5.2.0",
|
||||
"cross-env": "^6.0.0",
|
||||
"eslint": "^5.15.0",
|
||||
"eslint-config-react-app": "^4.0.0",
|
||||
"eslint-plugin-flowtype": "^3.4.0",
|
||||
"eslint-plugin-import": "^2.17.0",
|
||||
"eslint-plugin-flowtype": "^3.11.0",
|
||||
"eslint-plugin-import": "^2.18.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.1",
|
||||
"eslint-plugin-react": "^7.13.0",
|
||||
"eslint-plugin-react": "^7.14.0",
|
||||
"eslint-plugin-react-hooks": "^1.6.0",
|
||||
"husky": "^2.3.0",
|
||||
"husky": "^2.7.0",
|
||||
"less-vars-to-js": "^1.3.0",
|
||||
"lint-staged": "^8.1.0",
|
||||
"mockjs": "^1.0.1-beta3",
|
||||
"module": "^1.2.5",
|
||||
"prettier": "^1.16.0",
|
||||
"prettier": "^1.18.0",
|
||||
"stylelint": "^10.0.0",
|
||||
"stylelint-config-prettier": "^5.2.0",
|
||||
"stylelint-config-standard": "^18.3.0",
|
||||
"umi": "^2.8.1",
|
||||
"umi-plugin-react": "^1.9.1"
|
||||
"umi": "^2.10.0",
|
||||
"umi-plugin-react": "^1.12.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"src/**/*.js": [
|
||||
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<rect style="fill:#D80027;" width="512" height="512"/>
|
||||
<polygon style="fill:#6DA544;" points="196.641,0 196.641,264.348 196.641,512 0,512 0,0 "/>
|
||||
<circle style="fill:#FFDA44;" cx="196.641" cy="256" r="96"/>
|
||||
<path style="fill:#D80027;" d="M142.638,208v60c0,29.823,24.178,54,54,54s54-24.178,54-54v-60H142.638z"/>
|
||||
<path style="fill:#F0F0F0;" d="M196.638,286c-9.925,0-18-8.075-18-18v-24.001h36V268C214.638,277.925,206.563,286,196.638,286z"/>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 973 B |
@@ -6,7 +6,7 @@ const FilterItem = ({ label = '', children }) => {
|
||||
const labelArray = label.split('')
|
||||
return (
|
||||
<div className={styles.filterItem}>
|
||||
{labelArray.length > 0 ? (
|
||||
{labelArray.length > 0 && (
|
||||
<div className={styles.labelWrap}>
|
||||
{labelArray.map((item, index) => (
|
||||
<span className="labelText" key={index}>
|
||||
@@ -14,8 +14,6 @@ const FilterItem = ({ label = '', children }) => {
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
<div className={styles.item}>{children}</div>
|
||||
</div>
|
||||
|
||||
@@ -14,9 +14,7 @@ class Bread extends PureComponent {
|
||||
return paths.map((item, key) => {
|
||||
const content = item && (
|
||||
<Fragment>
|
||||
{item.icon ? (
|
||||
<Icon type={item.icon} style={{ marginRight: 4 }} />
|
||||
) : null}
|
||||
{item.icon && <Icon type={item.icon} style={{ marginRight: 4 }} />}
|
||||
{item.name}
|
||||
</Fragment>
|
||||
)
|
||||
|
||||
@@ -85,7 +85,7 @@ class Header extends PureComponent {
|
||||
trigger="click"
|
||||
key="notifications"
|
||||
overlayClassName={styles.notificationPopover}
|
||||
getPopupContainer={() => document.querySelector('#layoutHeader')}
|
||||
getPopupContainer={() => document.querySelector('#primaryLayout')}
|
||||
content={
|
||||
<div className={styles.notification}>
|
||||
<List
|
||||
|
||||
@@ -28,13 +28,13 @@ class Sider extends PureComponent {
|
||||
trigger={null}
|
||||
collapsible
|
||||
collapsed={collapsed}
|
||||
onBreakpoint={isMobile ? null : onCollapseChange}
|
||||
onBreakpoint={!isMobile && onCollapseChange}
|
||||
className={styles.sider}
|
||||
>
|
||||
<div className={styles.brand}>
|
||||
<div className={styles.logo}>
|
||||
<img alt="logo" src={config.logoPath} />
|
||||
{collapsed ? null : <h1>{config.siteName}</h1>}
|
||||
{!collapsed && <h1>{config.siteName}</h1>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -49,11 +49,12 @@ class Sider extends PureComponent {
|
||||
menus={menus}
|
||||
theme={theme}
|
||||
isMobile={isMobile}
|
||||
collapsed={collapsed}
|
||||
onCollapseChange={onCollapseChange}
|
||||
/>
|
||||
</ScrollBar>
|
||||
</div>
|
||||
{collapsed ? null : (
|
||||
{!collapsed && (
|
||||
<div className={styles.switchTheme}>
|
||||
<span>
|
||||
<Icon type="bulb" />
|
||||
|
||||
@@ -5,12 +5,14 @@ import { I18nProvider } from '@lingui/react'
|
||||
import { langFromPath, defaultLanguage } from 'utils'
|
||||
import zh_CN from 'antd/lib/locale-provider/zh_CN'
|
||||
import en_US from 'antd/lib/locale-provider/en_US'
|
||||
import pt_BR from 'antd/lib/locale-provider/pt_BR'
|
||||
|
||||
import BaseLayout from './BaseLayout'
|
||||
|
||||
const languages = {
|
||||
zh: zh_CN,
|
||||
en: en_US,
|
||||
'pt-br': pt_BR,
|
||||
}
|
||||
|
||||
@withRouter
|
||||
@@ -24,7 +26,7 @@ class Layout extends Component {
|
||||
componentDidMount() {
|
||||
const language = langFromPath(this.props.location.pathname)
|
||||
this.language = language
|
||||
this.loadCatalog(language)
|
||||
language && this.loadCatalog(language)
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
@@ -33,7 +35,7 @@ class Layout extends Component {
|
||||
const { catalogs } = nextState
|
||||
|
||||
if (preLanguage !== language && !catalogs[language]) {
|
||||
this.loadCatalog(language)
|
||||
language && this.loadCatalog(language)
|
||||
this.language = language
|
||||
return false
|
||||
}
|
||||
@@ -43,8 +45,10 @@ class Layout extends Component {
|
||||
}
|
||||
|
||||
loadCatalog = async language => {
|
||||
const catalog = await import(/* webpackMode: "lazy", webpackChunkName: "i18n-[index]" */
|
||||
`@lingui/loader!../locales/${language}/messages.json`)
|
||||
const catalog = await import(
|
||||
/* webpackMode: "lazy", webpackChunkName: "i18n-[index]" */
|
||||
`@lingui/loader!../locales/${language}/messages.json`
|
||||
)
|
||||
|
||||
this.setState(state => ({
|
||||
catalogs: {
|
||||
|
||||
@@ -11,6 +11,14 @@ import config from 'config'
|
||||
|
||||
const { queryRouteList, logoutUser, queryUserInfo } = api
|
||||
|
||||
const goDashboard = () => {
|
||||
if (pathMatchRegexp(['/', '/login'], window.location.pathname)) {
|
||||
router.push({
|
||||
pathname: '/dashboard',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
namespace: 'app',
|
||||
state: {
|
||||
@@ -69,9 +77,14 @@ export default {
|
||||
},
|
||||
effects: {
|
||||
*query({ payload }, { call, put, select }) {
|
||||
const { success, user } = yield call(queryUserInfo, payload)
|
||||
// store isInit to prevent query trigger by refresh
|
||||
const isInit = store.get('isInit')
|
||||
if (isInit) {
|
||||
goDashboard()
|
||||
return
|
||||
}
|
||||
const { locationPathname } = yield select(_ => _.app)
|
||||
|
||||
const { success, user } = yield call(queryUserInfo, payload)
|
||||
if (success && user) {
|
||||
const { list } = yield call(queryRouteList)
|
||||
const { permissions } = user
|
||||
@@ -96,11 +109,8 @@ export default {
|
||||
store.set('routeList', routeList)
|
||||
store.set('permissions', permissions)
|
||||
store.set('user', user)
|
||||
if (pathMatchRegexp(['/', '/login'], window.location.pathname)) {
|
||||
router.push({
|
||||
pathname: '/dashboard',
|
||||
})
|
||||
}
|
||||
store.set('isInit', true)
|
||||
goDashboard()
|
||||
} else if (queryLayout(config.layouts, locationPathname) !== 'public') {
|
||||
router.push({
|
||||
pathname: '/login',
|
||||
@@ -117,6 +127,7 @@ export default {
|
||||
store.set('routeList', [])
|
||||
store.set('permissions', { visit: [] })
|
||||
store.set('user', {})
|
||||
store.set('isInit', false)
|
||||
yield put({ type: 'query' })
|
||||
} else {
|
||||
throw data
|
||||
|
||||
@@ -73,7 +73,7 @@ function Completed({ data }) {
|
||||
return (
|
||||
<div className={styles.tooltip}>
|
||||
<p className={styles.tiptitle}>{content.label}</p>
|
||||
<ul>{list}</ul>
|
||||
{content.payload && <ul>{list}</ul>}
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -22,7 +22,7 @@ function NumberCard({ icon, color, title, number, countUp }) {
|
||||
useEasing
|
||||
useGrouping
|
||||
separator=","
|
||||
{...countUp || {}}
|
||||
{...(countUp || {})}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -73,7 +73,7 @@ function Sales({ data }) {
|
||||
return (
|
||||
<div className={styles.tooltip}>
|
||||
<p className={styles.tiptitle}>{content.label}</p>
|
||||
<ul>{list}</ul>
|
||||
{content.payload && <ul>{list}</ul>}
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -16,7 +16,7 @@ export default {
|
||||
const { from } = locationQuery
|
||||
yield put({ type: 'app/query' })
|
||||
if (!pathMatchRegexp('/login', from)) {
|
||||
if (from === '/') router.push('/dashboard')
|
||||
if (['', '/'].includes(from)) router.push('/dashboard')
|
||||
else router.push(from)
|
||||
} else {
|
||||
router.push('/dashboard')
|
||||
|
||||
@@ -18,12 +18,23 @@ const EnumPostStatus = {
|
||||
@withI18n()
|
||||
@connect(({ post, loading }) => ({ post, loading }))
|
||||
class Post extends PureComponent {
|
||||
render() {
|
||||
const { post, loading, location, i18n } = this.props
|
||||
handleTabClick = key => {
|
||||
const { pathname } = this.props.location
|
||||
|
||||
router.push({
|
||||
pathname,
|
||||
search: stringify({
|
||||
status: key,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
get listProps() {
|
||||
const { post, loading, location } = this.props
|
||||
const { list, pagination } = post
|
||||
const { query, pathname } = location
|
||||
|
||||
const listProps = {
|
||||
return {
|
||||
pagination,
|
||||
dataSource: list,
|
||||
loading: loading.effects['post/query'],
|
||||
@@ -38,15 +49,11 @@ class Post extends PureComponent {
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const handleTabClick = key => {
|
||||
router.push({
|
||||
pathname,
|
||||
search: stringify({
|
||||
status: key,
|
||||
}),
|
||||
})
|
||||
}
|
||||
render() {
|
||||
const { location, i18n } = this.props
|
||||
const { query } = location
|
||||
|
||||
return (
|
||||
<Page inner>
|
||||
@@ -56,19 +63,19 @@ class Post extends PureComponent {
|
||||
? String(EnumPostStatus.UNPUBLISH)
|
||||
: String(EnumPostStatus.PUBLISHED)
|
||||
}
|
||||
onTabClick={handleTabClick}
|
||||
onTabClick={this.handleTabClick}
|
||||
>
|
||||
<TabPane
|
||||
tab={i18n.t`Publised`}
|
||||
key={String(EnumPostStatus.PUBLISHED)}
|
||||
>
|
||||
<List {...listProps} />
|
||||
<List {...this.listProps} />
|
||||
</TabPane>
|
||||
<TabPane
|
||||
tab={i18n.t`Unpublished`}
|
||||
key={String(EnumPostStatus.UNPUBLISH)}
|
||||
>
|
||||
<List {...listProps} />
|
||||
<List {...this.listProps} />
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</Page>
|
||||
|
||||
@@ -13,40 +13,46 @@ import Modal from './components/Modal'
|
||||
@withI18n()
|
||||
@connect(({ user, loading }) => ({ user, loading }))
|
||||
class User extends PureComponent {
|
||||
componentDidMount() {
|
||||
this.handleRefresh({ page: 1, pageSize: 10 })
|
||||
}
|
||||
|
||||
handleRefresh = newQuery => {
|
||||
const { location, dispatch } = this.props
|
||||
const { location } = this.props
|
||||
const { query, pathname } = location
|
||||
const payload = {
|
||||
...query,
|
||||
...newQuery,
|
||||
}
|
||||
dispatch({
|
||||
type: 'user/query',
|
||||
payload,
|
||||
})
|
||||
|
||||
router.push({
|
||||
pathname,
|
||||
search: stringify(payload, { arrayFormat: 'repeat' }),
|
||||
search: stringify(
|
||||
{
|
||||
...query,
|
||||
...newQuery,
|
||||
},
|
||||
{ arrayFormat: 'repeat' }
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { location, dispatch, user, loading, i18n } = this.props
|
||||
const { query } = location
|
||||
const {
|
||||
list,
|
||||
pagination,
|
||||
currentItem,
|
||||
modalVisible,
|
||||
modalType,
|
||||
selectedRowKeys,
|
||||
} = user
|
||||
handleDeleteItems = () => {
|
||||
const { dispatch, user } = this.props
|
||||
const { list, pagination, selectedRowKeys } = user
|
||||
|
||||
const modalProps = {
|
||||
dispatch({
|
||||
type: 'user/multiDelete',
|
||||
payload: {
|
||||
ids: selectedRowKeys,
|
||||
},
|
||||
}).then(() => {
|
||||
this.handleRefresh({
|
||||
page:
|
||||
list.length === selectedRowKeys.length && pagination.current > 1
|
||||
? pagination.current - 1
|
||||
: pagination.current,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
get modalProps() {
|
||||
const { dispatch, user, loading, i18n } = this.props
|
||||
const { currentItem, modalVisible, modalType } = user
|
||||
|
||||
return {
|
||||
item: modalType === 'create' ? {} : currentItem,
|
||||
visible: modalVisible,
|
||||
destroyOnClose: true,
|
||||
@@ -56,7 +62,7 @@ class User extends PureComponent {
|
||||
modalType === 'create' ? i18n.t`Create User` : i18n.t`Update User`
|
||||
}`,
|
||||
centered: true,
|
||||
onOk(data) {
|
||||
onOk: data => {
|
||||
dispatch({
|
||||
type: `user/${modalType}`,
|
||||
payload: data,
|
||||
@@ -70,8 +76,13 @@ class User extends PureComponent {
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const listProps = {
|
||||
get listProps() {
|
||||
const { dispatch, user, loading } = this.props
|
||||
const { list, pagination, selectedRowKeys } = user
|
||||
|
||||
return {
|
||||
dataSource: list,
|
||||
loading: loading.effects['user/query'],
|
||||
pagination,
|
||||
@@ -81,7 +92,7 @@ class User extends PureComponent {
|
||||
pageSize: page.pageSize,
|
||||
})
|
||||
},
|
||||
onDeleteItem(id) {
|
||||
onDeleteItem: id => {
|
||||
dispatch({
|
||||
type: 'user/delete',
|
||||
payload: id,
|
||||
@@ -115,8 +126,13 @@ class User extends PureComponent {
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const filterProps = {
|
||||
get filterProps() {
|
||||
const { location, dispatch } = this.props
|
||||
const { query } = location
|
||||
|
||||
return {
|
||||
filter: {
|
||||
...query,
|
||||
},
|
||||
@@ -134,26 +150,15 @@ class User extends PureComponent {
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteItems = () => {
|
||||
dispatch({
|
||||
type: 'user/multiDelete',
|
||||
payload: {
|
||||
ids: selectedRowKeys,
|
||||
},
|
||||
}).then(() => {
|
||||
this.handleRefresh({
|
||||
page:
|
||||
list.length === selectedRowKeys.length && pagination.current > 1
|
||||
? pagination.current - 1
|
||||
: pagination.current,
|
||||
})
|
||||
})
|
||||
}
|
||||
render() {
|
||||
const { user } = this.props
|
||||
const { selectedRowKeys } = user
|
||||
|
||||
return (
|
||||
<Page inner>
|
||||
<Filter {...filterProps} />
|
||||
<Filter {...this.filterProps} />
|
||||
{selectedRowKeys.length > 0 && (
|
||||
<Row style={{ marginBottom: 24, textAlign: 'right', fontSize: 13 }}>
|
||||
<Col>
|
||||
@@ -161,7 +166,7 @@ class User extends PureComponent {
|
||||
<Popconfirm
|
||||
title="Are you sure delete these items?"
|
||||
placement="left"
|
||||
onConfirm={handleDeleteItems}
|
||||
onConfirm={this.handleDeleteItems}
|
||||
>
|
||||
<Button type="primary" style={{ marginLeft: 8 }}>
|
||||
Remove
|
||||
@@ -170,8 +175,8 @@ class User extends PureComponent {
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
<List {...listProps} />
|
||||
<Modal {...modalProps} />
|
||||
<List {...this.listProps} />
|
||||
<Modal {...this.modalProps} />
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* global window */
|
||||
import modelExtend from 'dva-model-extend'
|
||||
import { pathMatchRegexp } from 'utils'
|
||||
import api from 'api'
|
||||
@@ -22,6 +21,20 @@ export default modelExtend(pageModel, {
|
||||
selectedRowKeys: [],
|
||||
},
|
||||
|
||||
subscriptions: {
|
||||
setup({ dispatch, history }) {
|
||||
history.listen(location => {
|
||||
if (pathMatchRegexp('/user', location.pathname)) {
|
||||
const payload = location.query || { page: 1, pageSize: 10 }
|
||||
dispatch({
|
||||
type: 'query',
|
||||
payload,
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
effects: {
|
||||
*query({ payload = {} }, { call, put }) {
|
||||
const data = yield call(queryUserList, payload)
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { message } from 'antd'
|
||||
|
||||
export default {
|
||||
onError(e) {
|
||||
onError(e, a) {
|
||||
e.preventDefault()
|
||||
message.error(e.message)
|
||||
if (e.message) {
|
||||
message.error(e.message)
|
||||
} else {
|
||||
/* eslint-disable */
|
||||
console.error(e)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -86,6 +86,10 @@ body {
|
||||
a:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.ant-table-layout-fixed table {
|
||||
table-layout: auto;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1600px) {
|
||||
:global {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module.exports = {
|
||||
siteName: 'AntD Admin',
|
||||
copyright: 'Ant Design Admin © 2018 zuiidea',
|
||||
copyright: 'Ant Design Admin ©2019 zuiidea',
|
||||
logoPath: '/logo.svg',
|
||||
apiPrefix: '/api/v1',
|
||||
fixedHeader: true, // sticky primary layout header
|
||||
@@ -21,7 +21,7 @@ module.exports = {
|
||||
{
|
||||
key: 'pt-br',
|
||||
title: 'Português',
|
||||
flag: '/brazil.svg',
|
||||
flag: '/portugal.svg',
|
||||
},
|
||||
{
|
||||
key: 'en',
|
||||
|
||||
@@ -2,14 +2,18 @@ import { cloneDeep, isString, flow, curry } from 'lodash'
|
||||
import umiRouter from 'umi/router'
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
import { i18n } from './config'
|
||||
import moment from 'moment'
|
||||
import 'moment/locale/zh-cn'
|
||||
|
||||
export classnames from 'classnames'
|
||||
export config from './config'
|
||||
export request from './request'
|
||||
export { Color } from './theme'
|
||||
|
||||
export const { defaultLanguage } = i18n
|
||||
export const languages = i18n.languages.map(item => item.key)
|
||||
// export const { defaultLanguage } = i18n
|
||||
// export const languages = i18n.languages.map(item => item.key)
|
||||
export const languages = i18n ? i18n.languages.map(item => item.key) : []
|
||||
export const defaultLanguage = i18n ? i18n.defaultLanguage : ''
|
||||
|
||||
/**
|
||||
* Query objects that specify keys and values in an array where all values are objects.
|
||||
@@ -59,23 +63,32 @@ export function arrayToTree(
|
||||
return result
|
||||
}
|
||||
|
||||
export const langFromPath = curry(
|
||||
/**
|
||||
* Query language from pathname.
|
||||
* @param {array} languages Specify which languages are currently available.
|
||||
* @param {string} defaultLanguage Specify the default language.
|
||||
* @param {string} pathname Pathname to be queried.
|
||||
* @return {string} Return the queryed language.
|
||||
*/
|
||||
(languages, defaultLanguage, pathname) => {
|
||||
for (const item of languages) {
|
||||
if (pathname.startsWith(`/${item}/`)) {
|
||||
return item
|
||||
}
|
||||
// export const langFromPath = curry(
|
||||
// /**
|
||||
// * Query language from pathname.
|
||||
// * @param {array} languages Specify which languages are currently available.
|
||||
// * @param {string} defaultLanguage Specify the default language.
|
||||
// * @param {string} pathname Pathname to be queried.
|
||||
// * @return {string} Return the queryed language.
|
||||
// */
|
||||
// (languages, defaultLanguage, pathname) => {
|
||||
// for (const item of languages) {
|
||||
// if (pathname.startsWith(`/${item}/`)) {
|
||||
// return item
|
||||
// }
|
||||
// }
|
||||
// return defaultLanguage
|
||||
// }
|
||||
// )(languages)(defaultLanguage)
|
||||
|
||||
export const langFromPath = pathname => {
|
||||
for (const item of languages) {
|
||||
if (pathname.startsWith(`/${item}/`)) {
|
||||
return item
|
||||
}
|
||||
return defaultLanguage
|
||||
}
|
||||
)(languages)(defaultLanguage)
|
||||
return defaultLanguage
|
||||
}
|
||||
|
||||
export const deLangPrefix = curry(
|
||||
/**
|
||||
@@ -104,11 +117,18 @@ export const deLangPrefix = curry(
|
||||
* @return {string} Return the pathname after adding the language prefix.
|
||||
*/
|
||||
export function addLangPrefix(pathname) {
|
||||
if (!i18n) {
|
||||
return pathname
|
||||
}
|
||||
|
||||
const prefix = langFromPath(window.location.pathname)
|
||||
return `/${prefix}${deLangPrefix(pathname)}`
|
||||
}
|
||||
|
||||
const routerAddLangPrefix = params => {
|
||||
if (!i18n) {
|
||||
return params
|
||||
}
|
||||
if (isString(params)) {
|
||||
params = addLangPrefix(params)
|
||||
} else {
|
||||
@@ -245,6 +265,7 @@ export function getLocale() {
|
||||
|
||||
export function setLocale(language) {
|
||||
if (getLocale() !== language) {
|
||||
moment.locale(language === 'zh' ? 'zh-cn' : language)
|
||||
umiRouter.push({
|
||||
pathname: `/${language}${deLangPrefix(window.location.pathname)}`,
|
||||
search: window.location.search,
|
||||
|
||||