cjd-parkball
Version:
> 中后台业务组件库,中后台就像公园,进入需要买门票(登录),所以以 Parkball(公园球) 命名,公园内必定捕获!作为一个组件库,提供使用方法文档,方便开发者的调用
506 lines (500 loc) • 13.3 kB
JavaScript
import { Button, Checkbox, Col, DatePicker, Form, Input, Pagination, Row, Select, message } from 'antd'
import classnames from 'classnames'
import PropTypes from 'prop-types'
import React, { isValidElement } from 'react'
import moment from 'moment'
import { request } from '../utilities'
import './index.scss'
const { Item: FormItem } = Form
const { Option } = Select
const { RangePicker } = DatePicker
message.config({
top: 99,
duration: 1,
maxCount: 1,
})
let timeout = null
function delay (c, ms) {
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(c, ms)
}
class FilterTable extends React.Component {
static propTypes = {
className: PropTypes.string,
size: PropTypes.string,
agile: PropTypes.bool,
handlers: PropTypes.arrayOf(PropTypes.oneOfType([
PropTypes.string,
PropTypes.element,
])),
showHandlers: PropTypes.bool,
onSearch: PropTypes.func,
onReset: PropTypes.func,
items: PropTypes.arrayOf(PropTypes.oneOfType([
PropTypes.string,
PropTypes.shape({
name: PropTypes.string,
label: PropTypes.string,
placeholder: PropTypes.string,
itemType: PropTypes.oneOf(['input', 'select', 'combobox', 'datePicker', 'checkbox']),
subType: PropTypes.oneOf(['time', 'date', 'week', 'month', 'range']),
selectOptions: PropTypes.arrayOf(PropTypes.shape({
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
label: PropTypes.string,
})),
buildOptions: PropTypes.func,
disabled: PropTypes.bool,
hidden: PropTypes.bool,
defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool, PropTypes.array]),
onChange: PropTypes.func,
valueFormat: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
nameFormat: PropTypes.func,
rules: PropTypes.arrayOf(PropTypes.object),
}),
])),
pagination: PropTypes.object,
}
static defaultProps = {
className: '',
size: 'medium',
agile: false,
handlers: ['重置', '搜索'],
showHandlers: true,
onReset: () => { console.log('default onReset handler') },
onSearch: () => { console.log('default onSearch handler') },
items: [],
pagination: {
total: 0,
pageNo: 1,
pageSize: 20,
},
}
constructor (props) {
super(props)
const { items, pagination } = props
this.state = {
items,
pagination: {
total: 0,
pageNo: 1,
pageSize: 20,
...pagination,
},
}
}
combineItems = (fresh) => {
const { getFieldError, setFields } = this.props.form
const { items: origin } = this.state
const combined = origin.map((o) => {
for (let i = 0; i < fresh.length; i += 1) {
const f = fresh[i]
if (f.name === o.name) {
if (getFieldError(o.name)) {
setFields({ [o.name]: { errors: null } })
}
return { ...o, ...f }
}
}
return o
})
this.setState({ items: combined })
}
onFieldsChange (field) {
const {
item, value, option, event,
} = field
const { type, onChange, onSelect } = item
const { agile } = this.props
if (agile) {
this.intendSearch()
}
switch (type) {
case 'select':
case 'combobox':
onSelect && onSelect({ value, option, combineItems: this.combineItems })
break
case 'picker':
onChange && onChange({ value, combineItems: this.combineItems })
break
default:
onChange && onChange({ value, event, combineItems: this.combineItems })
break
}
}
buildPagination () {
const { pagination } = this.state
const { pageNo, pageSize } = pagination
const { total } = this.props.pagination
return (
<Pagination
total={total}
current={pageNo}
pageSize={pageSize}
onChange={this.intendChangePage}
/>
)
}
buildSelect (item) {
const {
placeholder,
disabled,
url,
selectOptions,
buildOptions,
name,
} = item
if (!Array.isArray(selectOptions) && url && buildOptions) {
request(url)
.then((r) => {
this.combineItems([{ name, selectOptions: buildOptions(r) }])
})
}
const options = (selectOptions || []).map(o => <Option key={o.value}>{o.label}</Option>)
return (
<Select
disabled={!!disabled}
placeholder={placeholder || '请选择'}
onSelect={(value, option) => { this.onFieldsChange({ item, value, option }) }}
>
{options}
</Select>
)
}
buildCheckbox (item) {
const { disabled, defaultValue } = item
return (
<Checkbox
disabled={!!disabled}
onChange={(event) => { const { checked: value } = event.target; this.onFieldsChange({ item, value, event }) }}
defaultChecked={!!defaultValue}
/>
)
}
buildCombobox (item) {
const {
placeholder,
disabled,
onChange,
url,
selectOptions,
buildOptions,
name,
} = item
if (!Array.isArray(selectOptions) && url && buildOptions) {
request(url)
.then((r) => {
this.combineItems([{ name, selectOptions: buildOptions(r) }])
})
}
const options = (selectOptions || []).map(o => <Option key={o.value}>{o.label}</Option>)
return (
<Select
showSearch
disabled={!!disabled}
showArrow={false}
placeholder={placeholder || '请输入'}
filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
onSearch={(v, e) => {
if (url) {
delay(() => {
request(url + v)
.then((r) => {
onChange && onChange(v, r, e)
buildOptions && this.combineItems([{ name, selectOptions: buildOptions(r) }])
})
}, 500)
return
}
onChange && onChange(v, e)
}}
onSelect={(value, option) => { this.onFieldsChange({ item, value, option }) }}
>
{options}
</Select>
)
}
/* eslint-disable consistent-return */
buildDatePicker (item) {
const {
subType, disabled, placeholder,
} = item
if (subType === 'range') {
return (
<RangePicker
placeholder={placeholder || ['请选择', '请选择']}
disabled={!!disabled}
onChange={(moments, value) => { this.onFieldsChange({ item, value }) }}
/>
)
}
}
buildInput (item) {
const { placeholder, disabled } = item
return (
<Input
placeholder={placeholder || '请输入'}
disabled={!!disabled}
onChange={(event) => { const { value } = event.target; this.onFieldsChange({ item, value, event }) }}
/>
)
}
fieldMap (item) {
const { type } = item
switch (type) {
case 'select':
return this.buildSelect(item)
case 'combobox':
return this.buildCombobox(item)
case 'datePicker':
return this.buildDatePicker(item)
case 'checkbox':
return this.buildCheckbox(item)
default:
return this.buildInput(item)
}
}
/* eslint-disable class-methods-use-this */
getValueFromEvent (t) {
if (t === 'checkbox') {
return { getValueFromEvent (e) { return e.target.checked } }
}
}
buildItem (item) {
const { getFieldDecorator, fieldsNameFormat } = this.props.form
if (typeof item === 'object') {
const {
type, subType, name, label, defaultValue: initialValue, rules, nameFormat,
} = item
if (nameFormat) {
this.props.form.fieldsNameFormat = {
...fieldsNameFormat,
[name]: nameFormat,
}
}
return (
<FormItem
colon={false}
key={name}
label={label}
>
{
getFieldDecorator(name, {
initialValue,
rules,
...this.getValueFromEvent(type, subType),
})(this.fieldMap(item))
}
</FormItem>
)
}
}
buildItemCol () {
const { items } = this.state
const { showHandlers } = this.props
let span = 8
if (!showHandlers) {
span = 6
}
return items.map((item, i) => {
return (
<Col
key={i}
span={span}
className="item-col"
>
{this.buildItem(item)}
</Col>
)
})
}
buildItemRow () {
return (
<Row
type="flex"
justify="start"
className="items-row"
>
{this.buildItemCol()}
</Row>
)
}
/* eslint-disable class-methods-use-this, consistent-return */
buildHandler (handler, callback, type) {
if (typeof handler === 'string') {
return (
<Button
type={type}
onClick={callback}
>
{handler}
</Button>
)
}
if (isValidElement(handler)) {
return handler
}
}
valuesFormat (value, item) {
const { type, valueFormat } = item
if (valueFormat) {
return valueFormat(value)
}
if (type === 'datePicker') {
return value.map(v => moment(v).format('YYYY-MM-DD'))
}
}
validateItems () {
const { form } = this.props
const { fieldsNameFormat, validateFields } = form
const { items } = this.state
let values = null
validateFields({
first: true,
force: true,
}, (err, vals) => {
if (err) {
const info = Object.values(Object.values(err)[0])[0][0].message
message.error(info)
return
}
values = {}
Object.entries(vals).forEach((field) => {
const k = field[0]
const v = field[1]
if (v !== undefined && v !== null) {
if (fieldsNameFormat && fieldsNameFormat[k]) {
const item = items.filter(({ name }) => name === k)[0]
values = { ...values, ...fieldsNameFormat[k](this.valuesFormat(vals[k], item)) }
} else {
values[k] = v
}
}
})
})
return values
}
doReset = () => {
const { form, onReset } = this.props
const { resetFields, getFieldsValue } = form
const { pagination } = this.state
const { pageSize } = pagination
this.setState({ pagination: { ...pagination, pageNo: 1 } })
resetFields()
const params = { ...getFieldsValue(), pageNo: 1, pageSize }
onReset && onReset(params)
}
doSearch (params) {
const { onSearch } = this.props
onSearch && onSearch(params)
}
intendSearch = () => {
const vals = this.validateItems()
if (vals) {
const { pageNo, pageSize } = this.state.pagination
this.doSearch({ ...vals, pageNo, pageSize })
}
}
intendChangePage = (pageNo, pageSize) => {
const vals = this.validateItems()
if (vals) {
const { pagination } = this.state
this.doSearch({ ...vals, pageNo, pageSize })
this.setState({ pagination: { ...pagination, pageNo, pageSize } })
}
}
buildHandlerCol () {
const { handlers } = this.props
return handlers.map((handler, i) => {
let c = null
let t = 'default'
if (i === 0) {
c = this.doReset
}
if (i === 1) {
c = this.intendSearch
t = 'primary'
}
return (
<Col
key={i}
className="handler-col"
>
{this.buildHandler(handler, c, t)}
</Col>
)
})
}
buildHandlerRow () {
return (
<Row
type="flex"
justify="end"
className="handlers-row"
>
{this.buildHandlerCol()}
</Row>
)
}
buildForm () {
const { showHandlers } = this.props
if (!showHandlers) {
return (
<Form>
<Row>
<Col className="items-col">
{this.buildItemRow()}
</Col>
</Row>
</Form>
)
}
return (
<Form>
<Row>
<Col span={20} className="items-col">
{this.buildItemRow()}
</Col>
<Col span={4} className="handlers-col">
{this.buildHandlerRow()}
</Col>
</Row>
</Form>
)
}
// componentWillReceiveProps (nextProps) {
// const { pagination } = nextProps
// console.log(this.props.pagination)
// console.log(nextProps.pagination)
// }
render () {
const {
className, size, table, tableFooter,
} = this.props
return (
<div
className={classnames('parkball-filter-table', size, className)}
>
{this.buildForm()}
{table}
<div className="parkball-filter-table-footarea">
<div className="table-footer">
{tableFooter}
</div>
<div style={{ marginTop: '10px' }}>{this.buildPagination()}</div>
</div>
</div>
)
}
}
export default Form.create({
onFieldsChange (props, field, fields) {
// console.log(this)
// console.log(props, field, fields)
},
onValuesChange (props, field, fields) {
// console.log(this)
// console.log(props, field, fields)
},
})(FilterTable)