mirror of
https://github.com/zuiidea/antd-admin
synced 2026-10-28 19:55:23 +00:00
filters
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"
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ const config = require('../utils/config')
|
||||
const { apiPrefix } = config
|
||||
|
||||
let usersListData = Mock.mock({
|
||||
'data|100': [
|
||||
'data|80-100': [
|
||||
{
|
||||
id: '@id',
|
||||
name: '@cname',
|
||||
name: '@name',
|
||||
nickName: '@last',
|
||||
phone: /^1[34578]\d{9}$/,
|
||||
'age|11-99': 1,
|
||||
@@ -54,7 +54,6 @@ const adminUsers = [
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
const queryArray = (array, key, keyAlias = 'key') => {
|
||||
if (!(array instanceof Array)) {
|
||||
return null
|
||||
@@ -94,16 +93,16 @@ module.exports = {
|
||||
})
|
||||
res.json({ success: true, message: 'Ok' })
|
||||
} else {
|
||||
res.status(400).send({ message: 'Bad Request' })
|
||||
res.status(400).end()
|
||||
}
|
||||
},
|
||||
|
||||
[`GET ${apiPrefix}/user/logout`] (req, res) {
|
||||
res.clearCookie('token')
|
||||
res.status(200).send({ message: 'OK' })
|
||||
res.status(200).end()
|
||||
},
|
||||
|
||||
[`GET ${apiPrefix}/userInfo`] (req, res) {
|
||||
[`GET ${apiPrefix}/user`] (req, res) {
|
||||
const cookie = req.headers.cookie || ''
|
||||
const cookies = qs.parse(cookie.replace(/\s/g, ''), { delimiter: ';' })
|
||||
const response = {}
|
||||
@@ -174,11 +173,13 @@ module.exports = {
|
||||
|
||||
[`DELETE ${apiPrefix}/user/:id`] (req, res) {
|
||||
const { id } = req.params
|
||||
if (!id) {
|
||||
res.status(400).end()
|
||||
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)
|
||||
}
|
||||
database = database.filter((item) => item.id !== id)
|
||||
res.status(204).end()
|
||||
},
|
||||
|
||||
[`PATCH ${apiPrefix}/user/:id`] (req, res) {
|
||||
+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',
|
||||
|
||||
@@ -11,11 +11,11 @@ import {
|
||||
Button,
|
||||
} from 'antd'
|
||||
const { api, baseURL } = config
|
||||
const { userInfo, dashboard, users, userLogin, user } = api
|
||||
const { dashboard, users, userLogin, user } = api
|
||||
|
||||
const requestOptions = [
|
||||
{
|
||||
url: baseURL + userInfo,
|
||||
url: baseURL + user.replace('/:id', ''),
|
||||
desc: 'intercept request by mock.js',
|
||||
},
|
||||
{
|
||||
|
||||
+108
-26
@@ -1,50 +1,132 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Form, Button, Row, Col, Switch } from 'antd'
|
||||
import { Search } from '../../components'
|
||||
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,
|
||||
md: 8,
|
||||
lg: 6,
|
||||
xl: 48,
|
||||
style: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
}
|
||||
|
||||
const TwoColProps = {
|
||||
...ColProps,
|
||||
xl: 96,
|
||||
}
|
||||
|
||||
const UserFilter = ({
|
||||
field,
|
||||
keyword,
|
||||
onSearch,
|
||||
onAdd,
|
||||
isMotion,
|
||||
switchIsMotion,
|
||||
onFilterChange,
|
||||
filter,
|
||||
form: {
|
||||
getFieldDecorator,
|
||||
getFieldsValue,
|
||||
setFieldsValue,
|
||||
},
|
||||
}) => {
|
||||
const searchGroupProps = {
|
||||
field,
|
||||
keyword,
|
||||
size: 'large',
|
||||
select: true,
|
||||
selectOptions: [{ value: 'name', name: '姓名' }, { value: 'address', name: '地址' }],
|
||||
selectProps: {
|
||||
defaultValue: field || 'name',
|
||||
},
|
||||
onSearch: (value) => {
|
||||
onSearch(value)
|
||||
},
|
||||
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 lg={8} md={12} sm={16} xs={24} style={{ marginBottom: 16 }}>
|
||||
<Search {...searchGroupProps} />
|
||||
<Col {...ColProps}>
|
||||
{getFieldDecorator('name', { initialValue: name })(<Search placeholder="Search Name" size="large" onSearch={handleSubmit} />)}
|
||||
</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 {...ColProps}>
|
||||
{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}>
|
||||
<FilterItem label="Createtime">
|
||||
{getFieldDecorator('createTime', { initialValue: initialCreateTime })(
|
||||
<RangePicker style={{ width: '100%' }} size="large" onChange={handleChange.bind(null, 'createTime')} />
|
||||
)}
|
||||
</FilterItem>
|
||||
</Col>
|
||||
<Col {...TwoColProps}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<div >
|
||||
<Button type="primary" size="large" className="margin-right" onClick={handleSubmit}>Search</Button>
|
||||
<Button size="large" className="margin-right" onClick={handleReset}>Reset</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Switch style={{ marginRight: 16 }} defaultChecked={isMotion} onChange={switchIsMotion} checkedChildren={'动画开'} unCheckedChildren={'动画关'} />
|
||||
<Button size="large" type="ghost" onClick={onAdd}>Create</Button>
|
||||
</div>
|
||||
</div>
|
||||
</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,
|
||||
form: PropTypes.object,
|
||||
filter: PropTypes.object,
|
||||
onFilterChange: PropTypes.func,
|
||||
}
|
||||
|
||||
export default Form.create()(UserFilter)
|
||||
|
||||
+13
-14
@@ -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,51 +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,91 +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>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.content {
|
||||
line-height: 2.4;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
|
||||
@@ -8,7 +8,7 @@ import UserModal from './UserModal'
|
||||
|
||||
const User = ({ location, dispatch, user, loading }) => {
|
||||
const { list, pagination, currentItem, modalVisible, modalType, isMotion } = user
|
||||
const { field, keyword } = location.query
|
||||
const { current, pageSize } = pagination
|
||||
|
||||
const userModalProps = {
|
||||
item: modalType === 'create' ? {} : currentItem,
|
||||
@@ -62,9 +62,20 @@ const User = ({ location, dispatch, user, loading }) => {
|
||||
}
|
||||
|
||||
const userFilterProps = {
|
||||
field,
|
||||
keyword,
|
||||
isMotion,
|
||||
filter: {
|
||||
...location.query,
|
||||
},
|
||||
onFilterChange (value) {
|
||||
dispatch(routerRedux.push({
|
||||
pathname: location.pathname,
|
||||
query: {
|
||||
...value,
|
||||
page: current,
|
||||
pageSize,
|
||||
},
|
||||
}))
|
||||
},
|
||||
onSearch (fieldsValue) {
|
||||
fieldsValue.keyword.length ? dispatch(routerRedux.push({
|
||||
pathname: '/user',
|
||||
|
||||
+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,
|
||||
})
|
||||
|
||||
+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
@@ -101,14 +101,16 @@ export default function request (options) {
|
||||
const { response } = error
|
||||
let msg
|
||||
let status
|
||||
let otherData = {}
|
||||
if (response) {
|
||||
status = response.status
|
||||
const { data, statusText } = response
|
||||
otherData = data
|
||||
status = response.status
|
||||
msg = data.message || statusText
|
||||
} else {
|
||||
status = 600
|
||||
msg = 'Network Error'
|
||||
}
|
||||
return { success: false, status, message: msg }
|
||||
return { success: false, status, message: msg, ...otherData }
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user