UNPKG

cjd-parkball

Version:

> 中后台业务组件库,中后台就像公园,进入需要买门票(登录),所以以 Parkball(公园球) 命名,公园内必定捕获!作为一个组件库,提供使用方法文档,方便开发者的调用

495 lines (464 loc) 14.9 kB
import React, { PureComponent } from 'react' import moment from 'moment' import get from 'lodash/get' import PropTypes from 'prop-types' import template from 'lodash/template' import { Input, InputNumber, Button, DatePicker, Select, Checkbox, Radio, Cascader, Upload, Form, Icon, SelectTable } from '../..' import { request, errorTip } from '../utilities' const { Item } = Form const { Option } = Select const { TextArea } = Input // eslint-disable-next-line no-eval export const urlFunc = (url, option = {}) => template(url)({ option }) const componentName = 'FormBuilder Field' export default class extends PureComponent { static defaultProps = { dataTransfer: options => (options.result ? options.result : options), } static propTypes = { dataTransfer: PropTypes.func, } state = { options: [], } componentWillReceiveProps (nextProps) { if (this.props.field.resetOptions !== nextProps.field.resetOptions) { this.props.form.resetFields([nextProps.field.name]) this.setState({ options: [], }) } } queryDynamic (url, query) { const { dataTransfer = this.props.dataTransfer } = this.props.field request(urlFunc(url, query)).then((options) => { let newOptions if (dataTransfer instanceof Function) { newOptions = dataTransfer(options) } else { newOptions = options } this.setState(() => ({ options: newOptions })) }) } renderHideItem (props) { const { getFieldProps } = this.props.form return props.hide.map((field, index) => { return (<Item key={`${field.name}-${index}`} className="form-hide-item"> <Input {...getFieldProps(field.name)} /> </Item>) }) } verifyParams = (fields) => { const { name } = fields if (!name) { errorTip(componentName, 'field.name 不能为空') return false } return true } handleChange = (value, selectedOptions) => { const { triggerConfig = {}, onChange } = this.props.field onChange && onChange(value, selectedOptions) if (triggerConfig.onChange) { this.batchHandleFun(triggerConfig.onChangeFunc, value, selectedOptions) } return true } batchHandleFun = (list, value, selectedOptions) => { list.forEach((item) => { item && item(value, selectedOptions) }) } handleSelect = (value, option, onSelectHandler = () => null) => { const { onSelect, triggerConfig = {} } = this.props.field if (onSelect) { onSelect(value, option) } else { this.setState({ selectOption: option.props.option }, () => { const { selectOption } = this.state const { setFieldsValue } = this.props.form const hideFields = this.props.field.hide || [] const fields = {} hideFields.forEach((item) => { fields[item.name] = item.get ? item.get(selectOption) : get(selectOption, item.valueKey || item.name) }) setFieldsValue(fields) }) onSelectHandler(value, option) } if (triggerConfig.onSelect) { this.batchHandleFun(triggerConfig.onSelectFunc, value, option) } } handleResult = (value) => { const { onChange } = this.props.field onChange && onChange(value.id) const { setFieldsValue } = this.props.form const hideFields = this.props.field.hide || [] const fields = { [this.props.field.name]: value.id } hideFields.forEach((item) => { fields[item.name] = value[item.get] }) setFieldsValue(fields) } render () { const { getFieldDecorator } = this.props.form const { // support: select, cascader // todo support: radio, checkbox hide, // 隐藏字段 valueKey = 'value', // 每一个选项的值 key labelKey = 'label', // 每一个选项的展示名 key initialValue, // 初始值 defaultData = [], // 级联选择器初始化数据 ...attrs } = this.props.field const { // 通用 label, // 字段名成 type, // 表单元素类型 placeholder, // 占位提示 name, // 表单元素字段key required = true, // 是否必填,默认必填 emptyMessage, // 为空时的提示信息 options, // 可选值 url, // 数据动态来源 validator = {}, // 自定义校验规则 setter = null, // 数据序列化输出 getter = null, // 输入数据序列化 // 下拉 optionChild, // 自定义下拉选项 // datepicker // format, // 格式化 // upload uploadText, // custom customNode, dataTransfer = this.props.dataTransfer, // 处理返回数据 } = this.props.field const onChange = this.handleChange // 值改变时的回调 const onSelect = this.handleSelect // 值选择的回调 const onResult = this.handleResult // 值选择的回调 // 对传入参数进行校验 if (!this.verifyParams(this.props.field)) { return null } switch (type) { case 'text': { return ( <Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: emptyMessage || `${label}不能为空`, }, ...validator], onChange, })(<Input {...attrs} placeholder={placeholder || '请输入'} />) } </Item> ) } case 'number': { return ( <Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: emptyMessage || `${label}不能为空`, }, ...validator], onChange, })(<InputNumber {...attrs} placeholder={placeholder || '请输入'} />) } </Item> ) } case 'radio': { return ( <Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: emptyMessage || `${label}不能为空`, }, ...validator], onChange, })(<Radio.Group> { options.map(option => <Radio key={option[valueKey]} value={option[valueKey]} disabled={option.disabled || false}>{option[labelKey]}</Radio>) } </Radio.Group>) } { hide && hide.length && this.renderHideItem({ hide }) } </Item> ) } case 'checkbox': { return ( <Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: emptyMessage || `${label}不能为空`, }, ...validator], onChange, })(<Checkbox.Group> { options.map(option => <Checkbox key={option[valueKey]} value={option[valueKey]} disabled={option.disabled || false}>{option[labelKey]}</Checkbox>) } </Checkbox.Group>) } { hide && hide.length && this.renderHideItem({ hide }) } </Item> ) } case 'selectTable': { return ( <Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: emptyMessage || `${label}不能为空`, }, ...validator], })(<SelectTable label={label} name={name} onResult={onResult} placeholder={placeholder || '请选择'} > </SelectTable>) } { hide && hide.length && this.renderHideItem({ hide }) } </Item> ) } case 'select': { if (options) { return ( <Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: `${label}不能为空`, }], })(<Select onSelect={onSelect} placeholder={placeholder || '请选择'} {...attrs} > { options.map((option) => { return optionChild ? React.cloneElement(optionChild, { ...this.props.field, option, }) : <Option key={option[valueKey]} value={option[valueKey]} option={option}>{option[labelKey]}</Option> }) } </Select>) } { hide && hide.length && this.renderHideItem({ hide }) } </Item> ) } return ( <Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: `${label}不能为空`, }], })(<Select showSearch onFocus={() => (this.state.options.length ? null : this.queryDynamic(url))} onSearch={value => this.queryDynamic(url, { [name]: value })} onSelect={onSelect} placeholder={placeholder || '请选择'} {...attrs} > { this.state.options.map((option) => { return optionChild ? React.cloneElement(optionChild, { ...this.props.field, key: option[valueKey], option, }) : <Option key={option[valueKey]} value={option[valueKey]} option={option}>{option[labelKey]}</Option> }) } </Select>) } { hide && hide.length && this.renderHideItem({ hide }) } </Item> ) } case 'cascader': { const loadData = (selectedOptions) => { const targetOption = selectedOptions[selectedOptions.length - 1] || { id: 0 } targetOption.loading = true request(urlFunc(url, targetOption)).then((optionItem) => { const optionChildren = dataTransfer(optionItem) targetOption.loading = false targetOption.children = optionChildren this.setState({ options: this.state.options.length ? [...this.state.options] : [...optionChildren], }) }) } if (options) { return ( <Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: `${label}不能为空`, }], })(<Cascader options={options} placeholder={placeholder || '请选择'} {...attrs} onChange={(value, selectedOptions) => onChange(value, selectedOptions)} />) } { hide && hide.length && this.renderHideItem({ hide }) } </Item> ) } return ( <Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: `${label}不能为空`, }], })(<Cascader options={this.state.options.length ? this.state.options : defaultData} onFocus={this.state.options.length ? null : loadData} loadData={loadData} fieldNames={{ label: labelKey, value: valueKey }} placeholder={placeholder || '请选择'} onChange={(value, selectedOptions) => onChange(value, selectedOptions)} {...attrs} />) } { hide && hide.length && this.renderHideItem({ hide }) } </Item> ) } case 'upload': { return ( <Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: `${label}不能为空`, }], })(<Upload {...attrs} action={url} defaultFileList={initialValue}> <Button> <Icon type="upload" /> {uploadText || '上传'} </Button> </Upload>) } { hide && hide.length && this.renderHideItem({ hide }) } </Item> ) } case 'date': { return (<Item label={label}> { getFieldDecorator(name, { initialValue: initialValue && moment(initialValue), rules: [{ required, message: `${label}不能为空`, }], })(<DatePicker placeholder={placeholder || '请选择'} {...attrs} />) } { hide && hide.length && this.renderHideItem({ hide }) } </Item>) } case 'textarea': { return (<Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: `${label}不能为空`, }], })(<TextArea placeholder={placeholder || '请选择'} {...attrs} />) } </Item>) } case 'custom': { const { field, form } = this.props return customNode({ form, field }) } case 'hidden': { return ( <Item className="form-hide-item"> { getFieldDecorator(name, { initialValue, })(<Input {...attrs} />) } </Item> ) } default: { return (<Item label={label}> { getFieldDecorator(name, { initialValue, rules: [{ required, message: emptyMessage || `${label}不能为空`, }], onChange, })(<Input placeholder={placeholder || '请输入'} {...attrs} />) } { hide && hide.length && this.renderHideItem({ hide }) } </Item>) } } } }