mirror of
https://github.com/zuiidea/antd-admin
synced 2026-10-28 11:24:50 +00:00
Merge branch '4.2-dev'
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import styles from './FilterItem.less'
|
||||
|
||||
const FilterItem = ({
|
||||
label = '',
|
||||
children,
|
||||
}) => {
|
||||
const labelArray = label.split('')
|
||||
return (
|
||||
<div className={styles.filterItem}>
|
||||
{labelArray.length > 0
|
||||
? <div className={styles.labelWrap}>
|
||||
{labelArray.map((item, index) => <span className="labelText" key={index}>{item}</span>)}
|
||||
</div>
|
||||
: ''}
|
||||
<div className={styles.item}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
FilterItem.propTypes = {
|
||||
label: PropTypes.string,
|
||||
children: PropTypes.element.isRequired,
|
||||
}
|
||||
|
||||
export default FilterItem
|
||||
@@ -0,0 +1,17 @@
|
||||
.filterItem {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.labelWrap {
|
||||
width: 64px;
|
||||
line-height: 28px;
|
||||
margin-right: 12px;
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "FilterItem",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "./FilterItem.js"
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import styles from './Bread.less'
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
import { queryArray } from '../../utils'
|
||||
|
||||
const Bread = ({ location, menu }) => {
|
||||
const Bread = ({ menu }) => {
|
||||
// 匹配当前路由
|
||||
let pathArray = []
|
||||
let current
|
||||
@@ -17,19 +17,24 @@ const Bread = ({ location, menu }) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (!current) {
|
||||
return (<div className={styles.bread}>首页</div>)
|
||||
}
|
||||
|
||||
// 递归查找父级
|
||||
const getPathArray = (item) => {
|
||||
pathArray.unshift(item)
|
||||
if (item.bpid) {
|
||||
getPathArray(queryArray(menu, item.bpid, 'id'))
|
||||
}
|
||||
}
|
||||
getPathArray(current)
|
||||
|
||||
if (!current) {
|
||||
pathArray.push(menu[0])
|
||||
pathArray.push({
|
||||
id: 404,
|
||||
name: 'Not Found',
|
||||
})
|
||||
} else {
|
||||
getPathArray(current)
|
||||
}
|
||||
|
||||
// 递归查找父级
|
||||
const breads = pathArray.map((item, key) => {
|
||||
const content = (
|
||||
<span>{item.icon
|
||||
@@ -58,7 +63,6 @@ const Bread = ({ location, menu }) => {
|
||||
|
||||
Bread.propTypes = {
|
||||
menu: PropTypes.array,
|
||||
location: PropTypes.object,
|
||||
}
|
||||
|
||||
export default Bread
|
||||
|
||||
@@ -40,7 +40,7 @@ function Header ({ user, logout, switchSider, siderFold, isNavbar, menuPopoverVi
|
||||
{user.username} < /span>}
|
||||
>
|
||||
<Menu.Item key="logout">
|
||||
<a>注销</a>
|
||||
Sign out
|
||||
</Menu.Item>
|
||||
</SubMenu>
|
||||
</Menu>
|
||||
|
||||
@@ -90,7 +90,7 @@ const Menus = ({ siderFold, darkTheme, location, handleClickNavMenu, navOpenKeys
|
||||
const getPathArray = (array, current, pid, id) => {
|
||||
let result = [String(current[id])]
|
||||
const getPath = (item) => {
|
||||
if (item[pid]) {
|
||||
if (item && item[pid]) {
|
||||
result.unshift(String(item[pid]))
|
||||
getPath(queryArray(array, item[pid], id))
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ function Sider ({ siderFold, darkTheme, location, changeTheme, navOpenKeys, chan
|
||||
</div>
|
||||
<Menus {...menusProps} />
|
||||
{!siderFold ? <div className={styles.switchtheme}>
|
||||
<span><Icon type="bulb" />切换主题</span>
|
||||
<Switch onChange={changeTheme} defaultChecked={darkTheme} checkedChildren="黑" unCheckedChildren="白" />
|
||||
<span><Icon type="bulb" />Switch Theme</span>
|
||||
<Switch onChange={changeTheme} defaultChecked={darkTheme} checkedChildren="Dark" unCheckedChildren="Light" />
|
||||
</div> : ''}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@ import DropOption from './DropOption'
|
||||
import Iconfont from './Iconfont'
|
||||
import Search from './Search'
|
||||
import Editor from './Editor'
|
||||
import FilterItem from './FilterItem'
|
||||
import * as Layout from './Layout/index.js'
|
||||
|
||||
import layer from './layer'
|
||||
@@ -14,5 +15,6 @@ export {
|
||||
Iconfont,
|
||||
Search,
|
||||
Editor,
|
||||
FilterItem,
|
||||
layer,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
const qs = require('qs')
|
||||
const Mock = require('mockjs')
|
||||
const config = require('../utils/config')
|
||||
const { apiPrefix } = config
|
||||
|
||||
let usersListData = Mock.mock({
|
||||
'data|80-100': [
|
||||
{
|
||||
id: '@id',
|
||||
name: '@name',
|
||||
nickName: '@last',
|
||||
phone: /^1[34578]\d{9}$/,
|
||||
'age|11-99': 1,
|
||||
address: '@county(true)',
|
||||
isMale: '@boolean',
|
||||
email: '@email',
|
||||
createTime: '@datetime',
|
||||
avatar () {
|
||||
return Mock.Random.image('100x100', Mock.Random.color(), '#757575', 'png', this.nickName.substr(0, 1))
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
||||
let database = usersListData.data
|
||||
|
||||
const userPermission = {
|
||||
DEFAULT: [
|
||||
'dashboard', 'chart',
|
||||
],
|
||||
ADMIN: [
|
||||
'dashboard', 'users', 'UIElement', 'UIElementIconfont', 'chart',
|
||||
],
|
||||
DEVELOPER: ['dashboard', 'users', 'UIElement', 'UIElementIconfont', 'chart'],
|
||||
}
|
||||
|
||||
const adminUsers = [
|
||||
{
|
||||
id: 0,
|
||||
username: 'admin',
|
||||
password: 'admin',
|
||||
permissions: userPermission.ADMIN,
|
||||
}, {
|
||||
id: 1,
|
||||
username: 'guest',
|
||||
password: 'guest',
|
||||
permissions: userPermission.DEFAULT,
|
||||
}, {
|
||||
id: 2,
|
||||
username: '吴彦祖',
|
||||
password: '123456',
|
||||
permissions: userPermission.DEVELOPER,
|
||||
},
|
||||
]
|
||||
|
||||
const queryArray = (array, key, keyAlias = 'key') => {
|
||||
if (!(array instanceof Array)) {
|
||||
return null
|
||||
}
|
||||
let data
|
||||
|
||||
for (let item of array) {
|
||||
if (item[keyAlias] === key) {
|
||||
data = item
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (data) {
|
||||
return data
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const NOTFOUND = {
|
||||
message: 'Not Found',
|
||||
documentation_url: 'http://localhost:8000/request',
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
[`POST ${apiPrefix}/user/login`] (req, res) {
|
||||
const { username, password } = req.body
|
||||
const user = adminUsers.filter((item) => item.username === username)
|
||||
|
||||
if (user && user[0].password === password) {
|
||||
const now = new Date()
|
||||
now.setDate(now.getDate() + 1)
|
||||
res.cookie('token', JSON.stringify({ id: user[0].id, deadline: now.getTime() }), {
|
||||
maxAge: 900000,
|
||||
httpOnly: true,
|
||||
})
|
||||
res.json({ success: true, message: 'Ok' })
|
||||
} else {
|
||||
res.status(400).end()
|
||||
}
|
||||
},
|
||||
|
||||
[`GET ${apiPrefix}/user/logout`] (req, res) {
|
||||
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 = {}
|
||||
const user = {}
|
||||
if (!cookies.token) {
|
||||
res.status(200).send({ message: 'Not Login' })
|
||||
return
|
||||
}
|
||||
const token = JSON.parse(cookies.token)
|
||||
if (token) {
|
||||
response.success = token.deadline > new Date().getTime()
|
||||
}
|
||||
if (response.success) {
|
||||
const userItem = adminUsers.filter(_ => _.id === token.id)
|
||||
if (userItem.length > 0) {
|
||||
user.permissions = userItem[0].permissions
|
||||
user.username = userItem[0].username
|
||||
user.id = userItem[0].id
|
||||
}
|
||||
}
|
||||
response.user = user
|
||||
res.json(response)
|
||||
},
|
||||
|
||||
[`GET ${apiPrefix}/users`] (req, res) {
|
||||
const { query } = req
|
||||
let { pageSize, page, ...other } = query
|
||||
pageSize = pageSize || 10
|
||||
page = page || 1
|
||||
|
||||
let newData = database
|
||||
for (let key in other) {
|
||||
if ({}.hasOwnProperty.call(other, key)) {
|
||||
newData = newData.filter((item) => {
|
||||
if ({}.hasOwnProperty.call(item, key)) {
|
||||
if (key === 'address') {
|
||||
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()
|
||||
const now = new Date(item[key]).getTime()
|
||||
|
||||
if (start && end) {
|
||||
return now >= start && now <= end
|
||||
}
|
||||
return true
|
||||
}
|
||||
return String(item[key]).trim().indexOf(decodeURI(other[key]).trim()) > -1
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
data: newData.slice((page - 1) * pageSize, page * pageSize),
|
||||
total: newData.length,
|
||||
})
|
||||
},
|
||||
|
||||
[`POST ${apiPrefix}/user`] (req, res) {
|
||||
const newData = req.body
|
||||
newData.createTime = Mock.mock('@now')
|
||||
newData.avatar = newData.avatar || Mock.Random.image('100x100', Mock.Random.color(), '#757575', 'png', newData.nickName.substr(0, 1))
|
||||
newData.id = Mock.mock('@id')
|
||||
|
||||
database.unshift(newData)
|
||||
|
||||
res.status(200).end()
|
||||
},
|
||||
|
||||
[`GET ${apiPrefix}/user/:id`] (req, res) {
|
||||
const { id } = req.params
|
||||
const data = queryArray(database, id, 'id')
|
||||
if (data) {
|
||||
res.status(200).json(data)
|
||||
} else {
|
||||
res.status(404).json(NOTFOUND)
|
||||
}
|
||||
},
|
||||
|
||||
[`DELETE ${apiPrefix}/user/:id`] (req, res) {
|
||||
const { id } = req.params
|
||||
const data = queryArray(database, id, 'id')
|
||||
if (data) {
|
||||
database = database.filter((item) => item.id !== id)
|
||||
res.status(204).end()
|
||||
} else {
|
||||
res.status(404).json(NOTFOUND)
|
||||
}
|
||||
},
|
||||
|
||||
[`PATCH ${apiPrefix}/user/:id`] (req, res) {
|
||||
const { id } = req.params
|
||||
const editItem = req.body
|
||||
let isExist = false
|
||||
|
||||
database = database.map((item) => {
|
||||
if (item.id === id) {
|
||||
isExist = true
|
||||
return Object.assign({}, item, editItem)
|
||||
}
|
||||
return item
|
||||
})
|
||||
|
||||
if (isExist) {
|
||||
res.status(201).end()
|
||||
} else {
|
||||
res.status(404).json(NOTFOUND)
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
const qs = require('qs')
|
||||
const Mock = require('mockjs')
|
||||
const config = require('../utils/config')
|
||||
const { apiPrefix } = config
|
||||
|
||||
let usersListData = Mock.mock({
|
||||
'data|100': [
|
||||
{
|
||||
'id|+1': 1,
|
||||
name: '@cname',
|
||||
nickName: '@last',
|
||||
phone: /^1[34578]\d{9}$/,
|
||||
'age|11-99': 1,
|
||||
address: '@county(true)',
|
||||
isMale: '@boolean',
|
||||
email: '@email',
|
||||
createTime: '@datetime',
|
||||
avatar () {
|
||||
return Mock.Random.image('100x100', Mock.Random.color(), '#757575', 'png', this.nickName.substr(0, 1))
|
||||
},
|
||||
},
|
||||
],
|
||||
page: {
|
||||
total: 100,
|
||||
current: 1,
|
||||
},
|
||||
})
|
||||
|
||||
const userPermission = {
|
||||
DEFAULT: [
|
||||
'dashboard', 'chart',
|
||||
],
|
||||
ADMIN: [
|
||||
'dashboard', 'users', 'UIElement', 'UIElementIconfont', 'chart',
|
||||
],
|
||||
DEVELOPER: ['dashboard', 'users', 'UIElement', 'UIElementIconfont', 'chart'],
|
||||
}
|
||||
|
||||
const adminUsers = [
|
||||
{
|
||||
id: 0,
|
||||
username: 'admin',
|
||||
password: 'admin',
|
||||
permissions: userPermission.ADMIN,
|
||||
}, {
|
||||
id: 1,
|
||||
username: 'guest',
|
||||
password: 'guest',
|
||||
permissions: userPermission.DEFAULT,
|
||||
}, {
|
||||
id: 2,
|
||||
username: '吴彦祖',
|
||||
password: '123456',
|
||||
permissions: userPermission.DEVELOPER,
|
||||
},
|
||||
]
|
||||
|
||||
module.exports = {
|
||||
|
||||
[`POST ${apiPrefix}/user/login`] (req, res) {
|
||||
const { username, password } = req.body
|
||||
const user = adminUsers.filter((item) => item.username === username)
|
||||
|
||||
if (user[0] && user[0].password === password) {
|
||||
const now = new Date()
|
||||
now.setDate(now.getDate() + 1)
|
||||
res.cookie('token', JSON.stringify({ id: user[0].id, deadline: now.getTime() }), {
|
||||
maxAge: 900000,
|
||||
httpOnly: true,
|
||||
})
|
||||
res.json({ success: true, message: 'Ok' })
|
||||
} else {
|
||||
res.status(400).send({ message: 'Bad Request' })
|
||||
}
|
||||
},
|
||||
|
||||
[`GET ${apiPrefix}/user/logout`] (req, res) {
|
||||
res.clearCookie('token')
|
||||
res.status(200).send({ message: 'OK' })
|
||||
},
|
||||
|
||||
[`GET ${apiPrefix}/userInfo`] (req, res) {
|
||||
const cookie = req.headers.cookie || ''
|
||||
const cookies = qs.parse(cookie.replace(/\s/g, ''), { delimiter: ';' })
|
||||
const response = {}
|
||||
const user = {}
|
||||
if (!cookies.token) {
|
||||
res.status(200).send({ message: 'Not Login' })
|
||||
return
|
||||
}
|
||||
const token = JSON.parse(cookies.token)
|
||||
if (token) {
|
||||
response.success = token.deadline > new Date().getTime()
|
||||
}
|
||||
if (response.success) {
|
||||
const userItem = adminUsers.filter(_ => _.id === token.id)
|
||||
if (userItem.length > 0) {
|
||||
user.permissions = userItem[0].permissions
|
||||
user.username = userItem[0].username
|
||||
user.id = userItem[0].id
|
||||
}
|
||||
}
|
||||
response.user = user
|
||||
res.json(response)
|
||||
},
|
||||
|
||||
[`GET ${apiPrefix}/users`] (req, res) {
|
||||
const page = req.query
|
||||
const pageSize = page.pageSize || 10
|
||||
const currentPage = page.page || 1
|
||||
|
||||
let data
|
||||
let newPage
|
||||
|
||||
let newData = usersListData.data.concat()
|
||||
|
||||
if (page.field) {
|
||||
const d = newData.filter((item) => {
|
||||
return item[page.field].indexOf(decodeURI(page.keyword)) > -1
|
||||
})
|
||||
|
||||
data = d.slice((currentPage - 1) * pageSize, currentPage * pageSize)
|
||||
|
||||
newPage = {
|
||||
current: currentPage * 1,
|
||||
total: d.length,
|
||||
}
|
||||
} else {
|
||||
data = usersListData.data.slice((currentPage - 1) * pageSize, currentPage * pageSize)
|
||||
usersListData.page.current = currentPage * 1
|
||||
newPage = usersListData.page
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
data,
|
||||
page: {
|
||||
...newPage,
|
||||
pageSize: Number(pageSize),
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
[`POST ${apiPrefix}/users`] (req, res) {
|
||||
const newData = req.body
|
||||
newData.createTime = Mock.mock('@now')
|
||||
newData.avatar = Mock.Random.image('100x100', Mock.Random.color(), '#757575', 'png', newData.nickName.substr(0, 1))
|
||||
|
||||
newData.id = usersListData.data.length + 1
|
||||
usersListData.data.unshift(newData)
|
||||
|
||||
usersListData.page.total = usersListData.data.length
|
||||
usersListData.page.current = 1
|
||||
|
||||
res.json({ success: true, data: usersListData.data, page: usersListData.page })
|
||||
},
|
||||
|
||||
[`DELETE ${apiPrefix}/users`] (req, res) {
|
||||
const deleteItem = req.body
|
||||
|
||||
usersListData.data = usersListData.data.filter((item) => {
|
||||
if (item.id === deleteItem.id) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
usersListData.page.total = usersListData.data.length
|
||||
|
||||
res.json({ success: true, data: usersListData.data, page: usersListData.page })
|
||||
},
|
||||
|
||||
[`PUT ${apiPrefix}/users`] (req, res) {
|
||||
const editItem = req.body
|
||||
|
||||
editItem.createTime = Mock.mock('@now')
|
||||
editItem.avatar = Mock.Random.image('100x100', Mock.Random.color(), '#757575', 'png', editItem.nickName.substr(0, 1))
|
||||
|
||||
usersListData.data = usersListData.data.map((item) => {
|
||||
if (item.id === editItem.id) {
|
||||
return editItem
|
||||
}
|
||||
return item
|
||||
})
|
||||
|
||||
res.json({ success: true, data: usersListData.data, page: usersListData.page })
|
||||
},
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { getUserInfo, logout } from '../services/app'
|
||||
import { query, logout } from '../services/app'
|
||||
import { routerRedux } from 'dva/router'
|
||||
import { parse } from 'qs'
|
||||
import { config } from '../utils'
|
||||
@@ -27,7 +27,7 @@ export default {
|
||||
*queryUser ({
|
||||
payload,
|
||||
}, { call, put }) {
|
||||
const data = yield call(getUserInfo, parse(payload))
|
||||
const data = yield call(query, parse(payload))
|
||||
if (data.success && data.user) {
|
||||
yield put({
|
||||
type: 'queryUserSuccess',
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { create, remove, update, query } from '../services/users'
|
||||
import { create, remove, update } from '../services/user'
|
||||
import { query } from '../services/users'
|
||||
import { routerRedux } from 'dva/router'
|
||||
import { parse } from 'qs'
|
||||
|
||||
export default {
|
||||
|
||||
namespace: 'users',
|
||||
namespace: 'user',
|
||||
|
||||
state: {
|
||||
list: [],
|
||||
@@ -23,7 +25,7 @@ export default {
|
||||
subscriptions: {
|
||||
setup ({ dispatch, history }) {
|
||||
history.listen(location => {
|
||||
if (location.pathname === '/users') {
|
||||
if (location.pathname === '/user') {
|
||||
dispatch({
|
||||
type: 'query',
|
||||
payload: location.query,
|
||||
@@ -34,65 +36,54 @@ export default {
|
||||
},
|
||||
|
||||
effects: {
|
||||
*requery ({ payload }, { put }) {
|
||||
yield put(routerRedux.push({
|
||||
pathname: location.pathname,
|
||||
query: parse(location.search.substr(1)),
|
||||
}))
|
||||
},
|
||||
*query ({ payload }, { call, put }) {
|
||||
const data = yield call(query, parse(payload))
|
||||
const data = yield call(query, payload)
|
||||
if (data) {
|
||||
yield put({
|
||||
type: 'querySuccess',
|
||||
payload: {
|
||||
list: data.data,
|
||||
pagination: data.page,
|
||||
pagination: {
|
||||
current: Number(payload.page) || 1,
|
||||
pageSize: Number(payload.pageSize) || 10,
|
||||
total: data.total,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
*'delete' ({ payload }, { call, put }) {
|
||||
const data = yield call(remove, { id: payload })
|
||||
if (data && data.success) {
|
||||
yield put({
|
||||
type: 'querySuccess',
|
||||
payload: {
|
||||
list: data.data,
|
||||
pagination: {
|
||||
total: data.page.total,
|
||||
current: data.page.current,
|
||||
},
|
||||
},
|
||||
})
|
||||
if (data.success) {
|
||||
yield put({ type: 'requery' })
|
||||
} else {
|
||||
throw data
|
||||
}
|
||||
},
|
||||
*create ({ payload }, { call, put }) {
|
||||
yield put({ type: 'hideModal' })
|
||||
const data = yield call(create, payload)
|
||||
if (data && data.success) {
|
||||
yield put({
|
||||
type: 'querySuccess',
|
||||
payload: {
|
||||
list: data.data,
|
||||
pagination: {
|
||||
total: data.page.total,
|
||||
current: data.page.current,
|
||||
},
|
||||
},
|
||||
})
|
||||
if (data.success) {
|
||||
yield put({ type: 'requery' })
|
||||
} else {
|
||||
throw data
|
||||
}
|
||||
},
|
||||
*update ({ payload }, { select, call, put }) {
|
||||
yield put({ type: 'hideModal' })
|
||||
const id = yield select(({ users }) => users.currentItem.id)
|
||||
const id = yield select(({ user }) => user.currentItem.id)
|
||||
const newUser = { ...payload, id }
|
||||
const data = yield call(update, newUser)
|
||||
if (data && data.success) {
|
||||
yield put({
|
||||
type: 'querySuccess',
|
||||
payload: {
|
||||
list: data.data,
|
||||
pagination: {
|
||||
total: data.page.total,
|
||||
current: data.page.current,
|
||||
},
|
||||
},
|
||||
})
|
||||
if (data.success) {
|
||||
yield put({ type: 'requery' })
|
||||
} else {
|
||||
throw data
|
||||
}
|
||||
},
|
||||
*switchIsMotion ({
|
||||
@@ -0,0 +1,51 @@
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
import { query } from '../../services/user'
|
||||
|
||||
export default {
|
||||
|
||||
namespace: 'userDetail',
|
||||
|
||||
state: {
|
||||
data: {},
|
||||
},
|
||||
|
||||
subscriptions: {
|
||||
setup ({ dispatch, history }) {
|
||||
history.listen(() => {
|
||||
const match = pathToRegexp('/user/:id').exec(location.pathname)
|
||||
if (match) {
|
||||
dispatch({ type: 'query', payload: { id: match[1] } })
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
effects: {
|
||||
*query ({
|
||||
payload,
|
||||
}, { call, put }) {
|
||||
const data = yield call(query, payload)
|
||||
const { success, message, status, ...other } = data
|
||||
if (success) {
|
||||
yield put({
|
||||
type: 'querySuccess',
|
||||
payload: {
|
||||
data: other,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
throw data
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
reducers: {
|
||||
querySuccess (state, { payload }) {
|
||||
const { data } = payload
|
||||
return {
|
||||
...state,
|
||||
data,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
+12
-4
@@ -30,12 +30,20 @@ const Routers = function ({ history, app }) {
|
||||
}, 'dashboard')
|
||||
},
|
||||
}, {
|
||||
path: 'users',
|
||||
path: 'user',
|
||||
getComponent (nextState, cb) {
|
||||
require.ensure([], require => {
|
||||
registerModel(app, require('./models/users'))
|
||||
cb(null, require('./routes/users/'))
|
||||
}, 'users')
|
||||
registerModel(app, require('./models/user'))
|
||||
cb(null, require('./routes/user/'))
|
||||
}, 'user')
|
||||
},
|
||||
}, {
|
||||
path: 'user/:id',
|
||||
getComponent (nextState, cb) {
|
||||
require.ensure([], require => {
|
||||
registerModel(app, require('./models/user/detail'))
|
||||
cb(null, require('./routes/user/detail/'))
|
||||
}, 'user-detail')
|
||||
},
|
||||
}, {
|
||||
path: 'login',
|
||||
|
||||
@@ -38,28 +38,26 @@ const Login = ({
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写用户名',
|
||||
},
|
||||
],
|
||||
})(<Input size="large" onPressEnter={handleOk} placeholder="用户名" />)}
|
||||
})(<Input size="large" onPressEnter={handleOk} placeholder="Username" />)}
|
||||
</FormItem>
|
||||
<FormItem hasFeedback>
|
||||
{getFieldDecorator('password', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写密码',
|
||||
},
|
||||
],
|
||||
})(<Input size="large" type="password" onPressEnter={handleOk} placeholder="密码" />)}
|
||||
})(<Input size="large" type="password" onPressEnter={handleOk} placeholder="Password" />)}
|
||||
</FormItem>
|
||||
<Row>
|
||||
<Button type="primary" size="large" onClick={handleOk} loading={loginLoading}>
|
||||
登录
|
||||
Sign in
|
||||
</Button>
|
||||
<p>
|
||||
<span>账号:guest</span>
|
||||
<span>密码:guest</span>
|
||||
<span>Username:guest</span>
|
||||
<span>Password:guest</span>
|
||||
</p>
|
||||
</Row>
|
||||
|
||||
|
||||
+20
-25
@@ -11,36 +11,42 @@ import {
|
||||
Button,
|
||||
} from 'antd'
|
||||
const { api, baseURL } = config
|
||||
const { userInfo, dashboard, users, userLogin } = api
|
||||
const { dashboard, users, userLogin, user } = api
|
||||
|
||||
const requestOptions = [
|
||||
{
|
||||
url: baseURL + userInfo,
|
||||
url: baseURL + user.replace('/:id', ''),
|
||||
desc: 'intercept request by mock.js',
|
||||
},
|
||||
{
|
||||
url: baseURL + dashboard,
|
||||
desc: 'intercept request by mock.js',
|
||||
},
|
||||
{
|
||||
url: baseURL + users,
|
||||
desc: 'intercept request by mock.js',
|
||||
},
|
||||
{
|
||||
url: baseURL + userLogin,
|
||||
method: 'post',
|
||||
data: {
|
||||
username: 'admin',
|
||||
password: 'admin6',
|
||||
username: 'guest',
|
||||
password: 'guest',
|
||||
},
|
||||
desc: 'intercept request by mock.js',
|
||||
},
|
||||
{
|
||||
url: baseURL + users,
|
||||
desc: 'intercept request by mock.js',
|
||||
},
|
||||
{
|
||||
url: baseURL + user,
|
||||
desc: 'intercept request by mock.js',
|
||||
data: Mock.mock({
|
||||
id: '@id',
|
||||
}),
|
||||
},
|
||||
{
|
||||
url: baseURL + user.replace('/:id', ''),
|
||||
desc: 'intercept request by mock.js',
|
||||
method: 'post',
|
||||
data: Mock.mock({
|
||||
'id|+1': 1000,
|
||||
name: '@cname',
|
||||
nickName: '@last',
|
||||
phone: /^1[34578]\d{9}$/,
|
||||
@@ -48,37 +54,26 @@ const requestOptions = [
|
||||
address: '@county(true)',
|
||||
isMale: '@boolean',
|
||||
email: '@email',
|
||||
createTime: '@datetime',
|
||||
avatar () {
|
||||
return Mock.Random.image('100x100', Mock.Random.color(), '#757575', 'png', this.nickName.substr(0, 1))
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
url: baseURL + users,
|
||||
url: baseURL + user,
|
||||
desc: 'intercept request by mock.js',
|
||||
method: 'put',
|
||||
method: 'patch',
|
||||
data: Mock.mock({
|
||||
id: 1,
|
||||
id: '@id',
|
||||
name: '@cname',
|
||||
nickName: '@last',
|
||||
phone: /^1[34578]\d{9}$/,
|
||||
'age|11-99': 1,
|
||||
address: '@county(true)',
|
||||
isMale: '@boolean',
|
||||
email: '@email',
|
||||
createTime: '@datetime',
|
||||
avatar () {
|
||||
return Mock.Random.image('100x100', Mock.Random.color(), '#757575', 'png', this.nickName.substr(0, 1))
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
url: baseURL + users,
|
||||
url: baseURL + user,
|
||||
desc: 'intercept request by mock.js',
|
||||
method: 'delete',
|
||||
data: Mock.mock({
|
||||
id: 10,
|
||||
id: '@id',
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import moment from 'moment'
|
||||
import { FilterItem } from '../../components'
|
||||
import { Form, Button, Row, Col, DatePicker, Input, Cascader, Switch } from 'antd'
|
||||
import city from '../../utils/city'
|
||||
|
||||
const Search = Input.Search
|
||||
const { RangePicker } = DatePicker
|
||||
|
||||
const ColProps = {
|
||||
xs: 24,
|
||||
sm: 12,
|
||||
style: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
}
|
||||
|
||||
const TwoColProps = {
|
||||
...ColProps,
|
||||
xl: 96,
|
||||
}
|
||||
|
||||
const UserFilter = ({
|
||||
onAdd,
|
||||
isMotion,
|
||||
switchIsMotion,
|
||||
onFilterChange,
|
||||
filter,
|
||||
form: {
|
||||
getFieldDecorator,
|
||||
getFieldsValue,
|
||||
setFieldsValue,
|
||||
},
|
||||
}) => {
|
||||
const handleFields = (fields) => {
|
||||
const { createTime } = fields
|
||||
if (createTime.length) {
|
||||
fields.createTime = [createTime[0].format('YYYY-MM-DD'), createTime[1].format('YYYY-MM-DD')]
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
let fields = getFieldsValue()
|
||||
fields = handleFields(fields)
|
||||
console.log(fields)
|
||||
onFilterChange(fields)
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
const fields = getFieldsValue()
|
||||
for (let item in fields) {
|
||||
if ({}.hasOwnProperty.call(fields, item)) {
|
||||
if (fields[item] instanceof Array) {
|
||||
fields[item] = []
|
||||
} else {
|
||||
fields[item] = undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
setFieldsValue(fields)
|
||||
handleSubmit()
|
||||
}
|
||||
|
||||
const handleChange = (key, values) => {
|
||||
let fields = getFieldsValue()
|
||||
fields[key] = values
|
||||
fields = handleFields(fields)
|
||||
onFilterChange(fields)
|
||||
}
|
||||
const { name, address } = filter
|
||||
|
||||
let initialCreateTime = []
|
||||
if (filter.createTime && filter.createTime[0]) {
|
||||
initialCreateTime[0] = moment(filter.createTime[0])
|
||||
}
|
||||
if (filter.createTime && filter.createTime[1]) {
|
||||
initialCreateTime[1] = moment(filter.createTime[1])
|
||||
}
|
||||
|
||||
return (
|
||||
<Row gutter={24}>
|
||||
<Col {...ColProps} xl={{ span: 4 }} md={{ span: 8 }}>
|
||||
{getFieldDecorator('name', { initialValue: name })(<Search placeholder="Search Name" size="large" onSearch={handleSubmit} />)}
|
||||
</Col>
|
||||
<Col {...ColProps} xl={{ span: 4 }} md={{ span: 8 }}>
|
||||
{getFieldDecorator('address', { initialValue: address })(
|
||||
<Cascader
|
||||
size="large"
|
||||
style={{ width: '100%' }}
|
||||
options={city}
|
||||
placeholder="Please pick an address"
|
||||
onChange={handleChange.bind(null, 'address')}
|
||||
/>)}
|
||||
</Col>
|
||||
<Col {...ColProps} xl={{ span: 6 }} md={{ span: 8 }} sm={{ span: 12 }}>
|
||||
<FilterItem label="Createtime">
|
||||
{getFieldDecorator('createTime', { initialValue: initialCreateTime })(
|
||||
<RangePicker style={{ width: '100%' }} size="large" onChange={handleChange.bind(null, 'createTime')} />
|
||||
)}
|
||||
</FilterItem>
|
||||
</Col>
|
||||
<Col {...TwoColProps} xl={{ span: 10 }} md={{ span: 24 }} sm={{ span: 24 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<div >
|
||||
<Button type="primary" size="large" className="margin-right" onClick={handleSubmit}>Search</Button>
|
||||
<Button size="large" onClick={handleReset}>Reset</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Switch style={{ marginRight: 16 }} size="large" defaultChecked={isMotion} onChange={switchIsMotion} checkedChildren={'Motion'} unCheckedChildren={'Motion'} />
|
||||
<Button size="large" type="ghost" onClick={onAdd}>Create</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
UserFilter.propTypes = {
|
||||
onAdd: PropTypes.func,
|
||||
isMotion: PropTypes.bool,
|
||||
switchIsMotion: PropTypes.func,
|
||||
form: PropTypes.object,
|
||||
filter: PropTypes.object,
|
||||
onFilterChange: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Form.create()(UserFilter)
|
||||
@@ -5,7 +5,7 @@ import styles from './UserList.less'
|
||||
import classnames from 'classnames'
|
||||
import AnimTableBody from '../../components/DataTable/AnimTableBody'
|
||||
import { DropOption } from '../../components'
|
||||
|
||||
import { Link } from 'dva/router'
|
||||
|
||||
const confirm = Modal.confirm
|
||||
|
||||
@@ -15,7 +15,7 @@ function list ({ loading, dataSource, pagination, onPageChange, onDeleteItem, on
|
||||
onEditItem(record)
|
||||
} else if (e.key === '2') {
|
||||
confirm({
|
||||
title: '您确定要删除这条记录吗?',
|
||||
title: 'Are you sure delete this record?',
|
||||
onOk () {
|
||||
onDeleteItem(record.id)
|
||||
},
|
||||
@@ -25,50 +25,50 @@ function list ({ loading, dataSource, pagination, onPageChange, onDeleteItem, on
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '头像',
|
||||
title: 'Avatar',
|
||||
dataIndex: 'avatar',
|
||||
key: 'avatar',
|
||||
width: 64,
|
||||
className: styles.avatar,
|
||||
render: (text) => <img alt={'avatar'} width={24} src={text} />,
|
||||
}, {
|
||||
title: '姓名',
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
render: (text, record) => <Link to={`user/${record.id}`}>{text}</Link>,
|
||||
}, {
|
||||
title: '昵称',
|
||||
title: 'NickName',
|
||||
dataIndex: 'nickName',
|
||||
key: 'nickName',
|
||||
}, {
|
||||
title: '年龄',
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
render: (text) => <span>{text}岁</span>,
|
||||
}, {
|
||||
title: '性别',
|
||||
title: 'Gender',
|
||||
dataIndex: 'isMale',
|
||||
key: 'isMale',
|
||||
render: (text) => <span>{text
|
||||
? '男'
|
||||
: '女'}</span>,
|
||||
? 'Male'
|
||||
: 'Female'}</span>,
|
||||
}, {
|
||||
title: '电话',
|
||||
title: 'Phone',
|
||||
dataIndex: 'phone',
|
||||
key: 'phone',
|
||||
}, {
|
||||
title: '邮箱',
|
||||
title: 'Email',
|
||||
dataIndex: 'email',
|
||||
key: 'email',
|
||||
}, {
|
||||
title: '住址',
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
}, {
|
||||
title: '创建时间',
|
||||
title: 'CreateTime',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
}, {
|
||||
title: '操作',
|
||||
title: 'Operation',
|
||||
key: 'operation',
|
||||
width: 100,
|
||||
render: (text, record) => {
|
||||
@@ -1,6 +1,8 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Form, Input, InputNumber, Radio, Modal } from 'antd'
|
||||
import { Form, Input, InputNumber, Radio, Modal, Cascader } from 'antd'
|
||||
import city from '../../utils/city'
|
||||
|
||||
const FormItem = Form.Item
|
||||
|
||||
const formItemLayout = {
|
||||
@@ -33,12 +35,13 @@ const modal = ({
|
||||
...getFieldsValue(),
|
||||
key: item.key,
|
||||
}
|
||||
data.address = data.address.join(' ')
|
||||
onOk(data)
|
||||
})
|
||||
}
|
||||
|
||||
const modalOpts = {
|
||||
title: `${type === 'create' ? '新建用户' : '修改用户'}`,
|
||||
title: `${type === 'create' ? 'Create User' : 'Update User'}`,
|
||||
visible,
|
||||
onOk: handleOk,
|
||||
onCancel,
|
||||
@@ -48,89 +51,89 @@ const modal = ({
|
||||
return (
|
||||
<Modal {...modalOpts}>
|
||||
<Form layout="horizontal">
|
||||
<FormItem label="姓名:" hasFeedback {...formItemLayout}>
|
||||
<FormItem label="Name" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('name', {
|
||||
initialValue: item.name,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '姓名未填写',
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label="昵称:" hasFeedback {...formItemLayout}>
|
||||
<FormItem label="NickName" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('nickName', {
|
||||
initialValue: item.nickName,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '昵称未填写',
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label="性别" hasFeedback {...formItemLayout}>
|
||||
<FormItem label="Gender" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('isMale', {
|
||||
initialValue: item.isMale,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
type: 'boolean',
|
||||
message: '请选择性别',
|
||||
},
|
||||
],
|
||||
})(
|
||||
<Radio.Group>
|
||||
<Radio value>男</Radio>
|
||||
<Radio value={false}>女</Radio>
|
||||
<Radio value>Male</Radio>
|
||||
<Radio value={false}>Female</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="年龄:" hasFeedback {...formItemLayout}>
|
||||
<FormItem label="Age" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('age', {
|
||||
initialValue: item.age,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '年龄未填写',
|
||||
},
|
||||
],
|
||||
})(<InputNumber min={18} max={100} />)}
|
||||
</FormItem>
|
||||
<FormItem label="电话:" hasFeedback {...formItemLayout}>
|
||||
<FormItem label="Phone" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('phone', {
|
||||
initialValue: item.phone,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
pattern: /^1[34578]\d{9}$/,
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label="邮箱:" hasFeedback {...formItemLayout}>
|
||||
<FormItem label="Email" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('email', {
|
||||
initialValue: item.email,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label="住址:" hasFeedback {...formItemLayout}>
|
||||
<FormItem label="Address" hasFeedback {...formItemLayout}>
|
||||
{getFieldDecorator('address', {
|
||||
initialValue: item.address,
|
||||
initialValue: item.address && item.address.split(' '),
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
],
|
||||
})(<Input />)}
|
||||
})(<Cascader
|
||||
size="large"
|
||||
style={{ width: '100%' }}
|
||||
options={city}
|
||||
placeholder="Pick an address"
|
||||
/>)}
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
@@ -0,0 +1,29 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'dva'
|
||||
import styles from './index.less'
|
||||
|
||||
const Detail = ({ userDetail }) => {
|
||||
const { data } = userDetail
|
||||
const content = []
|
||||
for (let key in data) {
|
||||
if ({}.hasOwnProperty.call(data, key)) {
|
||||
content.push(<div key={key} className={styles.item}>
|
||||
<div>{key}</div>
|
||||
<div>{String(data[key])}</div>
|
||||
</div>)
|
||||
}
|
||||
}
|
||||
return (<div className="content-inner">
|
||||
<div className={styles.content}>
|
||||
{content}
|
||||
</div>
|
||||
</div>)
|
||||
}
|
||||
|
||||
Detail.propTypes = {
|
||||
userDetail: PropTypes.object,
|
||||
loading: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default connect(({ userDetail, loading }) => ({ userDetail, loading: loading.models.userDetail }))(Detail)
|
||||
@@ -0,0 +1,14 @@
|
||||
.content {
|
||||
line-height: 2.4;
|
||||
font-size: 13px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
|
||||
& > div {
|
||||
&:first-child {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@ import UserList from './UserList'
|
||||
import UserFilter from './UserFilter'
|
||||
import UserModal from './UserModal'
|
||||
|
||||
function Users ({ location, dispatch, users, loading }) {
|
||||
const { list, pagination, currentItem, modalVisible, modalType, isMotion } = users
|
||||
const { field, keyword } = location.query
|
||||
const User = ({ location, dispatch, user, loading }) => {
|
||||
const { list, pagination, currentItem, modalVisible, modalType, isMotion } = user
|
||||
const { pageSize } = pagination
|
||||
|
||||
const userModalProps = {
|
||||
item: modalType === 'create' ? {} : currentItem,
|
||||
@@ -16,13 +16,13 @@ function Users ({ location, dispatch, users, loading }) {
|
||||
visible: modalVisible,
|
||||
onOk (data) {
|
||||
dispatch({
|
||||
type: `users/${modalType}`,
|
||||
type: `user/${modalType}`,
|
||||
payload: data,
|
||||
})
|
||||
},
|
||||
onCancel () {
|
||||
dispatch({
|
||||
type: 'users/hideModal',
|
||||
type: 'user/hideModal',
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -46,13 +46,13 @@ function Users ({ location, dispatch, users, loading }) {
|
||||
},
|
||||
onDeleteItem (id) {
|
||||
dispatch({
|
||||
type: 'users/delete',
|
||||
type: 'user/delete',
|
||||
payload: id,
|
||||
})
|
||||
},
|
||||
onEditItem (item) {
|
||||
dispatch({
|
||||
type: 'users/showModal',
|
||||
type: 'user/showModal',
|
||||
payload: {
|
||||
modalType: 'update',
|
||||
currentItem: item,
|
||||
@@ -62,30 +62,41 @@ function Users ({ location, dispatch, users, loading }) {
|
||||
}
|
||||
|
||||
const userFilterProps = {
|
||||
field,
|
||||
keyword,
|
||||
isMotion,
|
||||
filter: {
|
||||
...location.query,
|
||||
},
|
||||
onFilterChange (value) {
|
||||
dispatch(routerRedux.push({
|
||||
pathname: location.pathname,
|
||||
query: {
|
||||
...value,
|
||||
page: 1,
|
||||
pageSize,
|
||||
},
|
||||
}))
|
||||
},
|
||||
onSearch (fieldsValue) {
|
||||
fieldsValue.keyword.length ? dispatch(routerRedux.push({
|
||||
pathname: '/users',
|
||||
pathname: '/user',
|
||||
query: {
|
||||
field: fieldsValue.field,
|
||||
keyword: fieldsValue.keyword,
|
||||
},
|
||||
})) : dispatch(routerRedux.push({
|
||||
pathname: '/users',
|
||||
pathname: '/user',
|
||||
}))
|
||||
},
|
||||
onAdd () {
|
||||
dispatch({
|
||||
type: 'users/showModal',
|
||||
type: 'user/showModal',
|
||||
payload: {
|
||||
modalType: 'create',
|
||||
},
|
||||
})
|
||||
},
|
||||
switchIsMotion () {
|
||||
dispatch({ type: 'users/switchIsMotion' })
|
||||
dispatch({ type: 'user/switchIsMotion' })
|
||||
},
|
||||
}
|
||||
|
||||
@@ -101,11 +112,11 @@ function Users ({ location, dispatch, users, loading }) {
|
||||
)
|
||||
}
|
||||
|
||||
Users.propTypes = {
|
||||
users: PropTypes.object,
|
||||
User.propTypes = {
|
||||
user: PropTypes.object,
|
||||
location: PropTypes.object,
|
||||
dispatch: PropTypes.func,
|
||||
loading: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default connect(({ users, loading }) => ({ users, loading: loading.models.users }))(Users)
|
||||
export default connect(({ user, loading }) => ({ user, loading: loading.models.user }))(User)
|
||||
@@ -1,50 +0,0 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Form, Button, Row, Col, Switch } from 'antd'
|
||||
import { Search } from '../../components'
|
||||
|
||||
const UserFilter = ({
|
||||
field,
|
||||
keyword,
|
||||
onSearch,
|
||||
onAdd,
|
||||
isMotion,
|
||||
switchIsMotion,
|
||||
}) => {
|
||||
const searchGroupProps = {
|
||||
field,
|
||||
keyword,
|
||||
size: 'large',
|
||||
select: true,
|
||||
selectOptions: [{ value: 'name', name: '姓名' }, { value: 'address', name: '地址' }],
|
||||
selectProps: {
|
||||
defaultValue: field || 'name',
|
||||
},
|
||||
onSearch: (value) => {
|
||||
onSearch(value)
|
||||
},
|
||||
}
|
||||
return (
|
||||
<Row gutter={24}>
|
||||
<Col lg={8} md={12} sm={16} xs={24} style={{ marginBottom: 16 }}>
|
||||
<Search {...searchGroupProps} />
|
||||
</Col>
|
||||
<Col lg={{ offset: 8, span: 8 }} md={12} sm={8} xs={24} style={{ marginBottom: 16, textAlign: 'right' }}>
|
||||
{/* <Switch style={{ marginRight: 16 }} defaultChecked={isMotion} onChange={switchIsMotion} checkedChildren={'动画开'} unCheckedChildren={'动画关'} /> */}
|
||||
<Button size="large" type="ghost" onClick={onAdd}>添加</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
UserFilter.propTypes = {
|
||||
form: PropTypes.object.isRequired,
|
||||
onSearch: PropTypes.func,
|
||||
onAdd: PropTypes.func,
|
||||
field: PropTypes.string,
|
||||
keyword: PropTypes.string,
|
||||
isMotion: PropTypes.bool,
|
||||
switchIsMotion: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Form.create()(UserFilter)
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
import { request, config } from '../utils'
|
||||
const { api } = config
|
||||
const { userInfo, userLogout, userLogin } = api
|
||||
const { user, userLogout, userLogin } = api
|
||||
|
||||
export async function login (params) {
|
||||
return request({
|
||||
@@ -18,9 +18,9 @@ export async function logout (params) {
|
||||
})
|
||||
}
|
||||
|
||||
export async function getUserInfo (params) {
|
||||
export async function query (params) {
|
||||
return request({
|
||||
url: userInfo,
|
||||
url: user.replace('/:id', ''),
|
||||
method: 'get',
|
||||
data: params,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { request, config } from '../utils'
|
||||
const { api } = config
|
||||
const { user } = api
|
||||
|
||||
export async function query (params) {
|
||||
return request({
|
||||
url: user,
|
||||
method: 'get',
|
||||
data: params,
|
||||
})
|
||||
}
|
||||
|
||||
export async function create (params) {
|
||||
return request({
|
||||
url: user.replace('/:id', ''),
|
||||
method: 'post',
|
||||
data: params,
|
||||
})
|
||||
}
|
||||
|
||||
export async function remove (params) {
|
||||
return request({
|
||||
url: user,
|
||||
method: 'delete',
|
||||
data: params,
|
||||
})
|
||||
}
|
||||
|
||||
export async function update (params) {
|
||||
return request({
|
||||
url: user,
|
||||
method: 'patch',
|
||||
data: params,
|
||||
})
|
||||
}
|
||||
@@ -9,27 +9,3 @@ export async function query (params) {
|
||||
data: params,
|
||||
})
|
||||
}
|
||||
|
||||
export async function create (params) {
|
||||
return request({
|
||||
url: users,
|
||||
method: 'post',
|
||||
data: params,
|
||||
})
|
||||
}
|
||||
|
||||
export async function remove (params) {
|
||||
return request({
|
||||
url: users,
|
||||
method: 'delete',
|
||||
data: params,
|
||||
})
|
||||
}
|
||||
|
||||
export async function update (params) {
|
||||
return request({
|
||||
url: users,
|
||||
method: 'put',
|
||||
data: params,
|
||||
})
|
||||
}
|
||||
|
||||
+7
-14
@@ -113,21 +113,14 @@ body {
|
||||
}
|
||||
}
|
||||
@media (min-width: 1600px) {
|
||||
.ant-col-xl-48 {
|
||||
width: 20%;
|
||||
}
|
||||
:global {
|
||||
.ant-col-xl-48 {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.ant-col-xl-96 {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1600px) {
|
||||
.ant-col-xl-48 {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.ant-col-xl-96 {
|
||||
width: 40%;
|
||||
.ant-col-xl-96 {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
|
||||
+4073
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -1,12 +1,12 @@
|
||||
module.exports = {
|
||||
name: 'AntD Admin',
|
||||
prefix: 'antdAdmin',
|
||||
footerText: 'Ant Design Admin 版权所有 © 2016 由 zuiidea 支持',
|
||||
footerText: 'Ant Design Admin © 2017 zuiidea',
|
||||
logo: 'https://t.alipayobjects.com/images/T1QUBfXo4fXXXXXXXX.png',
|
||||
iconFontUrl: '//at.alicdn.com/t/font_c4y7asse3q1cq5mi.js',
|
||||
baseURL: 'http://localhost:8000/api/v1',
|
||||
YQL: ['http://www.zuimeitianqi.com'],
|
||||
CORS: ['http://localhost:7001'],
|
||||
CORS: ['http://localhost:7001', 'http://192.168.1.110:8000'],
|
||||
openPages: ['/login'],
|
||||
apiPrefix: '/api/v1',
|
||||
api: {
|
||||
@@ -14,6 +14,7 @@ module.exports = {
|
||||
userLogout: '/user/logout',
|
||||
userInfo: '/userInfo',
|
||||
users: '/users',
|
||||
user: '/user/:id',
|
||||
dashboard: '/dashboard',
|
||||
},
|
||||
}
|
||||
|
||||
+8
-1
@@ -10,7 +10,14 @@ module.exports = [
|
||||
bpid: 1,
|
||||
name: 'User Manage',
|
||||
icon: 'user',
|
||||
router: '/users',
|
||||
router: '/user',
|
||||
},
|
||||
{
|
||||
id: 21,
|
||||
mpid: -1,
|
||||
bpid: 2,
|
||||
name: 'User Detail',
|
||||
router: '/user/:id',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
|
||||
+38
-13
@@ -3,10 +3,11 @@ import qs from 'qs'
|
||||
import { YQL, CORS, baseURL } from './config'
|
||||
import jsonp from 'jsonp'
|
||||
import lodash from 'lodash'
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
import { message } from 'antd'
|
||||
|
||||
axios.defaults.baseURL = baseURL
|
||||
|
||||
|
||||
const fetch = (options) => {
|
||||
let {
|
||||
method = 'get',
|
||||
@@ -15,6 +16,26 @@ const fetch = (options) => {
|
||||
url,
|
||||
} = options
|
||||
|
||||
const cloneData = lodash.cloneDeep(data)
|
||||
|
||||
try {
|
||||
let domin = ''
|
||||
if (url.match(/[a-zA-z]+:\/\/[^/]*/)) {
|
||||
domin = url.match(/[a-zA-z]+:\/\/[^/]*/)[0]
|
||||
url = url.slice(domin.length)
|
||||
}
|
||||
const match = pathToRegexp.parse(url)
|
||||
url = pathToRegexp.compile(url)(data)
|
||||
for (let item of match) {
|
||||
if (item instanceof Object && item.name in cloneData) {
|
||||
delete cloneData[item.name]
|
||||
}
|
||||
}
|
||||
url = domin + url
|
||||
} catch (e) {
|
||||
message.error(e.message)
|
||||
}
|
||||
|
||||
if (fetchType === 'JSONP') {
|
||||
return new Promise((resolve, reject) => {
|
||||
jsonp(url, {
|
||||
@@ -35,17 +56,19 @@ const fetch = (options) => {
|
||||
|
||||
switch (method.toLowerCase()) {
|
||||
case 'get':
|
||||
return axios.get(`${url}${!lodash.isEmpty(data) ? `?${qs.stringify(data)}` : ''}`)
|
||||
return axios.get(url, {
|
||||
params: cloneData,
|
||||
})
|
||||
case 'delete':
|
||||
return axios.delete(url, { data })
|
||||
case 'head':
|
||||
return axios.head(url, data)
|
||||
return axios.delete(url, {
|
||||
data: cloneData,
|
||||
})
|
||||
case 'post':
|
||||
return axios.post(url, data)
|
||||
return axios.post(url, cloneData)
|
||||
case 'put':
|
||||
return axios.put(url, data)
|
||||
return axios.put(url, cloneData)
|
||||
case 'patch':
|
||||
return axios.patch(url, data)
|
||||
return axios.patch(url, cloneData)
|
||||
default:
|
||||
return axios(options)
|
||||
}
|
||||
@@ -76,16 +99,18 @@ export default function request (options) {
|
||||
}
|
||||
}).catch((error) => {
|
||||
const { response } = error
|
||||
let message
|
||||
let msg
|
||||
let status
|
||||
let otherData = {}
|
||||
if (response) {
|
||||
status = response.status
|
||||
const { data, statusText } = response
|
||||
message = data.message || statusText
|
||||
otherData = data
|
||||
status = response.status
|
||||
msg = data.message || statusText
|
||||
} else {
|
||||
status = 600
|
||||
message = 'Network Error'
|
||||
msg = 'Network Error'
|
||||
}
|
||||
return { success: false, status, message }
|
||||
return { success: false, status, message: msg, ...otherData }
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user