king
2021-09-01 31ec63f0419895876cbaba99637a884a32d33d0d
src/templates/sharecomponent/searchcomponent/searchform/index.jsx
@@ -1,12 +1,17 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Row, Col, Input, Select, Icon, Radio, notification, Tooltip, InputNumber, Checkbox, Cascader } from 'antd'
import { dateOptions, matchReg, formRule } from '@/utils/option.js'
import EditTable from '../searcheditable'
import Utils from '@/utils/utils.js'
import CodeMirror from '@/templates/zshare/codemirror'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const { TextArea } = Input
const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
const FieldsTable = asyncComponent(() => import('@/templates/zshare/modalform/fieldtable'))
const DataTable = asyncComponent(() => import('@/templates/zshare/modalform/datatable'))
const groupOptions = [
  {
@@ -81,11 +86,24 @@
  },
]
const searchTypeOptions = {
  text: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'inputType', 'advanced'],
  select: ['label', 'field', 'resourceType', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced', 'setAll'],
  multiselect: ['label', 'field', 'resourceType', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
  link: ['label', 'field', 'resourceType', 'initval', 'type', 'linkField', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced', 'setAll'],
  date: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
  checkcard: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'resourceType', 'display', 'width', 'multiple', 'borderColor', 'required', 'Hide', 'labelShow', 'advanced'],
  dateweek: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
  datemonth: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
  daterange: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
  group: ['label', 'type', 'field', 'datefield', 'initval', 'blacklist', 'ratio', 'items', 'required', 'labelShow'],
  range: ['label', 'type', 'field', 'initval', 'match', 'blacklist', 'Hide', 'required', 'maxValue', 'minValue', 'step', 'labelShow']
}
class MainSearch extends Component {
  static propTpyes = {
    dict: PropTypes.object,     // 字典项
    formlist: PropTypes.any,    // 表单
    optionLibs: PropTypes.any,  // 自定义下拉集
    card: PropTypes.object,     // 搜索条件信息
    inputSubmit: PropTypes.any  // 回车提交事件
  }
@@ -94,6 +112,8 @@
    openType: null,          // 搜索条件显示类型
    resourceType: null,      // 下拉搜索时,选项来源类型
    formlist: null,          // 表单
    display: null,
    cFields: [],
    textTooltip: '字段名可以使用逗号分隔,进行综合搜索',
  }
@@ -103,33 +123,39 @@
   * 2、下拉选择,根据数据源类型显示相关配置
   */
  UNSAFE_componentWillMount () {
    const { formlist, optionLibs, dict } = this.props
    const { formlist, dict } = this.props
    let type = formlist.filter(cell => cell.key === 'type')[0].initVal
    let _items = formlist.filter(cell => cell.key === 'items')[0].initVal
    let resourceType = formlist.filter(cell => cell.key === 'resourceType')[0].initVal
    let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required']                // 默认显示项
    let type = ''
    let _items = []
    let resourceType = ''
    let display = ''
    let cFields = []
    let multiple = 'false'
    if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '0') {        // 下拉选择类型、选项为自定义资源
      _options = [..._options, 'resourceType', 'options', 'display', 'quick']
    } else if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '1') { // 下拉选择类型、选项为后台数据源中获取
      _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database']
    } else if (type === 'group') {
      _options = ['label', 'type', 'field', 'datefield', 'initval', 'blacklist', 'ratio', 'items', 'required', 'transfer']
    }
    formlist.forEach(cell => {
      if (cell.key === 'type') {
        type = cell.initVal
      } else if (cell.key === 'items') {
        _items = cell.initVal
      } else if (cell.key === 'display') {
        display = cell.initVal
      } else if (cell.key === 'resourceType') {
        resourceType = cell.initVal
      } else if (cell.key === 'fields') {
        cFields = cell.initVal
      } else if (cell.key === 'multiple') {
        multiple = cell.initVal
      }
    })
    if (type === 'select' || type === 'link') {
      _options.push('setAll')
    }
    if (type === 'link') { // 关联类型、增加关联上级的字段名
      _options = [..._options, 'linkField']
    }
    let _options = this.getOptions(type, resourceType, display)
    
    this.setState({
      display,
      cFields,
      openType: type,
      items: _items,
      resourceType: resourceType,
      resourceType,
      formlist: formlist.map(form => {
        // 表单为初始值字段,且数据类型属于时间类型时,设置初始值为下拉选择,并重置选择项
        if (form.key === 'initval' && dateOptions.hasOwnProperty(type)) {
@@ -141,28 +167,22 @@
        } else if (form.key === 'match') { // 表单为匹配字段时,根据不同的类型,显示对应的匹配规则
          if (type === 'text') {
            form.options = matchReg.text
          } else if (type === 'multiselect') {
          } else if (type === 'multiselect' || (type === 'checkcard' && multiple === 'true')) {
            form.options = matchReg.multiselect
          } else if (type === 'select' || type === 'link') {
          } else if (type === 'select' || type === 'link' || type === 'checkcard') {
            form.options = matchReg.select
          } else if (type === 'date') {
            form.options = matchReg.date
          } else if (type === 'datemonth') {
            form.options = matchReg.datemonth
          } else if (type === 'dateweek' || type === 'daterange') {
          } else if (type === 'dateweek' || type === 'daterange' || type === 'range') {
            form.options = matchReg.daterange
          }
        } else if (form.key === 'quick') {
          form.options = [...optionLibs.values()].map(cell => {
            return {
              value: cell.uuid,
              text: cell.label + '(' + cell.parname + ')'
            }
          })
        } else if (form.key === 'field' && type === 'text') {
        } else if (form.key === 'field' && (type === 'text' || type === 'select')) {
          form.tooltip = this.state.textTooltip
        } else if (form.key === 'field' && type === 'group') {
          form.label = dict['header.form.type'] + dict['model.form.field']
          form.tooltip = '查询数据时(自定义脚本或统计数据源),类型字段将用作替换脚本中的 @字段@ ,类型字段对应值为 {"日": "day", "周": "week", "月": "month", "季": "quarter", "年": "year", "自定义": "customized"}。'
          form.label = dict['model.form.type'] + dict['model.form.field']
        }
        form.hidden = !_options.includes(form.key)
        return form
@@ -177,10 +197,36 @@
      try {
        let _form = document.getElementById('label')
        _form.select()
      } catch {
      } catch (e) {
        console.warn('表单focus失败!')
      }
    }
  }
  getOptions = (type, resourceType, display) => {
    let _options = fromJS(searchTypeOptions[type]).toJS() // 选项列表
    if (['multiselect', 'select', 'link'].includes(type) && resourceType === '0') {        // 下拉选择类型、选项为自定义资源
      _options.push('options')
    } else if (['multiselect', 'select', 'link'].includes(type) && resourceType === '1') { // 下拉选择类型、选项为后台数据源中获取
      _options.push('dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'database')
    } else if (type === 'checkcard') {
      if (display === 'picture') {
        if (resourceType === '0') {        // 自定义资源
          _options.push('options', 'picratio')
        } else if (resourceType === '1') { // 数据源
          _options.push('dataSource', 'cardValField', 'urlField', 'orderBy', 'orderType', 'database', 'picratio')
        }
      } else {
        if (resourceType === '0') {        // 自定义资源
          _options.push('options', 'fields', 'backgroundColor')
        } else if (resourceType === '1') { // 数据源
          _options.push('dataSource', 'cardValField', 'fields', 'orderBy', 'orderType', 'database', 'backgroundColor')
        }
      }
    }
    return _options
  }
  /**
@@ -188,27 +234,10 @@
   */
  openTypeChange = (key, value) => {
    const { dict } = this.props
    const { resourceType, items } = this.state
    const { resourceType, items, display } = this.state
    if (key === 'type') {
      let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required']
      if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '0') {        // 下拉选择类型、选项为自定义资源
        _options = [..._options, 'resourceType', 'options', 'display', 'quick']
      } else if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '1') { // 下拉选择类型、选项为后台数据源中获取
        _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database']
      } else if (value === 'group') {
        _options = ['label', 'type', 'field', 'datefield', 'initval', 'items', 'ratio', 'blacklist', 'required', 'transfer']
      }
      if (value === 'select' || value === 'link') {
        _options.push('setAll')
      }
      if (value === 'link') {
        _options = [..._options, 'linkField']
      }
      let _options = this.getOptions(value, resourceType, display)
      let matchs = []
      this.setState({
@@ -231,23 +260,24 @@
              form.options = matchReg.text
            } else if (value === 'multiselect') {
              form.options = matchReg.multiselect
            } else if (value === 'select' || value === 'link') {
            } else if (value === 'select' || value === 'link' || value === 'checkcard') {
              form.options = matchReg.select
            } else if (value === 'date') {
              form.options = matchReg.date
            } else if (value === 'datemonth') {
              form.options = matchReg.datemonth
            } else if (value === 'dateweek' || value === 'daterange') {
            } else if (value === 'dateweek' || value === 'daterange' || value === 'range') {
              form.options = matchReg.daterange
            }
            matchs = form.options
          } else if (form.key === 'field') {
            form.tooltip = ''
            form.label = dict['model.form.field']
            if (value === 'text') {
            if (value === 'text' || value === 'select') {
              form.tooltip = this.state.textTooltip
            } else if (value === 'group') {
              form.label = dict['header.form.type'] + dict['model.form.field']
              form.tooltip = '查询数据时(自定义脚本或统计数据源),类型字段将用作替换脚本中的 @字段@ ,类型字段对应值为 {"日": "day", "周": "week", "月": "month", "季": "quarter", "年": "year", "自定义": "customized"}。'
              form.label = dict['model.form.type'] + dict['model.form.field']
            }
          }
@@ -260,18 +290,9 @@
        if (this.props.form.getFieldValue('match') !== undefined) {
          this.props.form.setFieldsValue({match: matchs[0].value})
        }
      })
    } else if (key === 'quick') {
      let _option = this.props.optionLibs.get(value)
      this.setState({
        formlist: this.state.formlist.map(form => {
          if (form.key === 'options') {
            form.initVal = _option.options
          }
          return form
        })
        if (this.props.form.getFieldValue('multiple') !== undefined) {
          this.props.form.setFieldsValue({multiple: 'false'})
        }
      })
    }
  }
@@ -280,26 +301,12 @@
   * @description 数据源类型切换
   */
  onChange = (e, key) => {
    const { openType } = this.state
    const { openType, display, resourceType } = this.state
    let value = e.target.value
    if (key === 'resourceType') {
      let _options = ['label', 'field', 'initval', 'type', 'match', 'resourceType', 'display', 'ratio', 'blacklist', 'required']
      let _options = this.getOptions(openType, value, display)
      if (value === '0') {
        _options = [..._options, 'options', 'quick']
      } else if (value === '1') {
        _options = [..._options, 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'database']
      }
      if (openType === 'select' || openType === 'link') {
        _options.push('setAll')
      }
      if (openType === 'link') {
        _options = [..._options, 'linkField']
      }
      this.setState({
        resourceType: value,
        formlist: this.state.formlist.map(form => {
@@ -307,7 +314,49 @@
          return form
        })
      })
    } else if (key === 'display') {
      let _options = this.getOptions(openType, resourceType, value)
      this.setState({
        display: value,
        formlist: this.state.formlist.map(form => {
          form.hidden = !_options.includes(form.key)
          return form
        })
      })
    } else if (key === 'multiple') {
      let matchs = []
      this.setState({
        formlist: this.state.formlist.map(form => {
          if (form.key === 'match') {
            if (value === 'true') {
              form.options = matchReg.multiselect
            } else {
              form.options = matchReg.select
            }
            matchs = form.options
          }
          return form
        })
      }, () => {
        if (this.props.form.getFieldValue('match') !== undefined) {
          this.props.form.setFieldsValue({match: matchs[0].value})
        }
      })
    }
  }
  changeField = (data) => {
    this.setState({
      cFields: data,
      formlist: this.state.formlist.map(form => {
        if (form.key === 'fields') {
          form.initVal = data
        }
        return form
      })
    })
  }
  checkChange = (values, key) => {
@@ -345,13 +394,13 @@
    const { getFieldDecorator } = this.props.form
    const fields = []
    this.state.formlist.forEach((item, index) => {
      if (item.hidden) return
      if (item.hidden || item.forbid) return
      if (item.type === 'text') { // 文本搜索
        let rules = []
        if (item.key === 'field' || item.key === 'datefield') {
          rules = [{
            pattern: openType === 'text' ? formRule.field.multipattern : formRule.field.pattern,
            pattern: (openType === 'text' || openType === 'select') ? formRule.field.multipattern : formRule.field.pattern,
            message: formRule.field.message
          }, {
            max: formRule.field.max,
@@ -395,14 +444,17 @@
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || 6,
                initialValue: item.initVal,
                rules: [
                  {
                    required: item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(<InputNumber min={item.min} max={item.max} precision={0} />)}
              })(item.max ?
                  <InputNumber min={item.min} max={item.max} precision={0} onPressEnter={this.handleSubmit}/> :
                  <InputNumber onPressEnter={this.handleSubmit}/>
                )}
            </Form.Item>
          </Col>
        )
@@ -468,8 +520,8 @@
        )
      } else if (item.type === 'textarea') {
        fields.push(
          <Col span={20} offset={4} key={index}>
            <Form.Item className="text-area">
          <Col span={24} key={index}>
            <Form.Item className="text-area" label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
@@ -478,14 +530,40 @@
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(<TextArea rows={4} />)}
              })(<CodeMirror />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'options') {
        if (openType !== 'checkcard') {
          fields.push(
            <Col span={24} key={index}>
              <Form.Item label={item.label} className="text-area">
                {getFieldDecorator(item.key, {
                  initialValue: item.initVal
                })(<EditTable dict={this.props.dict} type={this.state.openType} data={item.initVal}/>)}
              </Form.Item>
            </Col>
          )
        } else {
          fields.push(
            <Col span={24} key={index}>
              <Form.Item label={item.label} className="text-area">
                {getFieldDecorator(item.key, {
                  initialValue: item.initVal
                })(<DataTable dict={this.props.dict} type={this.state.display} fields={this.state.cFields}/>)}
              </Form.Item>
            </Col>
          )
        }
      } else if (item.type === 'fields') {
        fields.push(
          <Col span={20} offset={4} key={index}>
            <EditTable data={item.initVal} type={this.state.openType} dict={this.props.dict} ref="editTable"/>
          <Col span={24} key={index}>
            <Form.Item label={item.label} className="text-area">
              {getFieldDecorator(item.key, {
                initialValue: item.initVal
              })(<FieldsTable dict={this.props.dict} onChange={this.changeField}/>)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'checkbox') {
@@ -538,6 +616,16 @@
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'color') {
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label} className="color-form-item">
              {getFieldDecorator(item.key, {
                initialValue: item.initVal
              })(<ColorSketch allowClear={true}/>)}
            </Form.Item>
          </Col>
        )
      }
    })
@@ -552,22 +640,63 @@
          let isvalid = true
          values.uuid = this.props.card.uuid
          // 下拉菜单或联动菜单
          if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '0') {
            values.options = this.refs.editTable.state.dataSource
          if (['multiselect', 'select', 'link', 'checkcard'].includes(values.type) && values.resourceType === '0') {
            values.options = values.options || []
            values.dataSource = ''
            let emptys = []
            if (values.type === 'multiselect' || values.type === 'select') {
            if (['multiselect', 'select'].includes(values.type)) {
              emptys = values.options.filter(op => !(op.Value && op.Text))
            } else {
            } else if (values.type === 'link') {
              emptys = values.options.filter(op => !(op.Value && op.Text && op.ParentID))
            }
            if (emptys.length > 0) {
              isvalid = false
            }
          } else if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '1') {
          } else if (['multiselect', 'select', 'link', 'checkcard'].includes(values.type) && values.resourceType === '1') {
            values.options = []
          }
          if (values.type === 'range') {
            let error = ''
            if (values.maxValue <= values.minValue) {
              error = '最大值必须大于最小值'
            } else if (values.step <= 0) {
              error = '步长必须大于0'
            } else {
              let s = (values.maxValue - values.minValue) / values.step
              if (s !== parseInt(s)) {
                error = '步长必须被 (max - min) 整除'
              }
            }
            if (!error && values.initval) {
              let vals = values.initval.split(',')
              if (vals.length !== 2) {
                error = '初始值设置错误!'
              } else if (isNaN(parseFloat(vals[0])) || isNaN(parseFloat(vals[1]))) {
                error = '初始值设置错误!'
              } else {
                let start = parseFloat(vals[0])
                let end = parseFloat(vals[1])
                let s = (values.maxValue - start) / values.step
                let e = (values.maxValue - end) / values.step
                if (start > end || start < values.minValue || end > values.maxValue) {
                  error = '初始值设置错误!'
                } else if (s !== parseInt(s) || e !== parseInt(e)) {
                  error = '初始值设置错误!'
                }
              }
            }
            if (error) {
              notification.warning({
                top: 92,
                message: error,
                duration: 5
              })
              return
            }
          }
          if (isvalid) {
            ['linkField', 'valueField', 'valueText', 'orderBy'].forEach(item => {
              if (values[item]) {