king
2020-09-03 af02b8f3c3ec9e5684be1084904d673429421d2b
2020-09-03
39个文件已修改
6个文件已添加
2个文件已删除
4694 ■■■■■ 已修改文件
src/locales/en-US/model.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/model.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/actionform/index.jsx 204 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/dragaction/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/formconfig.jsx 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/index.scss 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/verifyexcelin/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/verifyexcelout/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/verifyprint/editable/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/chartcompile/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/index.jsx 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasourcecomponent/verifycard/index.jsx 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasourcecomponent/verifycard/settingform/index.jsx 87 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menushell/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menushell/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/searchcomponent/index.scss 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/searchcomponent/searcheditable/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 216 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar-line/asyncButtonComponent.jsx 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar-line/index.jsx 981 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar-line/index.scss 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar/index.jsx 583 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar/index.scss 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/searchLine/index.jsx 784 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/searchLine/index.scss 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 582 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/index.jsx 235 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtabtable/index.jsx 220 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/treepage/index.jsx 153 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/calendarconfig/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/columncomponent/markcolumn/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/searcheditable/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/modaleditable/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/option.js 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-datamanage.js 181 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.scss 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/model.js
@@ -210,12 +210,12 @@
  'header.form.database.local': '本地',
  'header.form.database.sso': '系统',
  'header.form.linkMain': '关联主表',
  'header.form.query.delete': '确定删除吗?',
  'model.query.delete': '确定删除吗?',
  'header.form.up': '上移',
  'header.form.down': '下移',
  'header.form.status.change': '状态切换',
  'header.form.status.forbidden': '禁用',
  'header.form.status.open': '启用',
  'model.status.forbidden': '禁用',
  'model.status.open': '启用',
  'header.form.readin': '自动填充',
  'header.form.readin.tooltip': '是否将表格选中的数据自动填充到表单(字段相同)',
  'header.form.afterExecSuccess': '成功后',
src/locales/zh-CN/model.js
@@ -210,12 +210,12 @@
  'header.form.database.local': '本地',
  'header.form.database.sso': '系统',
  'header.form.linkMain': '关联主表',
  'header.form.query.delete': '确定删除吗?',
  'model.query.delete': '确定删除吗?',
  'header.form.up': '上移',
  'header.form.down': '下移',
  'header.form.status.change': '状态切换',
  'header.form.status.forbidden': '禁用',
  'header.form.status.open': '启用',
  'model.status.forbidden': '禁用',
  'model.status.open': '启用',
  'header.form.readin': '自动填充',
  'header.form.readin.tooltip': '是否将表格选中的数据自动填充到表单(字段相同)',
  'header.form.afterExecSuccess': '成功后',
src/menu/actioncomponent/actionform/index.jsx
@@ -1,5 +1,6 @@
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, Cascader } from 'antd'
import { btnIcons, btnClasses, formRule } from '@/utils/option.js'
@@ -9,6 +10,17 @@
import './index.scss'
const { TextArea } = Input
const actionTypeOptions = {
  pop: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError'],
  prompt: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError'],
  exec: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError'],
  excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'icon', 'class', 'sheet', 'execSuccess', 'execError'],
  excelOut: ['label', 'OpenType', 'intertype', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search'],
  popview: ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabType', 'linkTab', 'popClose'],
  tab: ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'linkmenu'],
  innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position'],
  funcbutton: ['label', 'OpenType', 'funcType', 'icon', 'class']
}
class MainSearch extends Component {
  static propTpyes = {
@@ -72,62 +84,22 @@
    const { card } = this.props
    let _menulist = this.props.formlist.filter(form => form.key === 'linkmenu')[0] || ''
    let _opentype = card.OpenType             // 打开方式
    let _options = null                       // 选项列表
    if (card.execMode) {           // 转换打印时打开方式
    let _opentype = card.OpenType                // 打开方式
    let _intertype = card.intertype || 'system'  // 接口类型
    let _funcType = card.funcType || 'print'     // 功能按钮默认类型
    if (card.execMode) {                         // 转换打印时打开方式
      _opentype = 'funcbutton'
    } else if (_opentype === 'outerpage') {
      card.pageTemplate = 'custom'
      _opentype = 'innerpage'
    }
    if (_opentype === 'innerpage') {                                     // 新页面,可选模板(自定义时,可填入外部链接)
      _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position']
      if (card.pageTemplate === 'custom') {
        _options.push('url', 'joint')
      }
    } else if (_opentype === 'blank' || _opentype === 'tab') {           // 新标签或当前页面替换
      _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabTemplate', 'linkmenu']
    } else if (_opentype === 'popview') {                                // 模态框标签页
      _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabType', 'linkTab', 'popClose']
    } else if (_opentype === 'excelOut') {    // 导入导出
      if (card.intertype === 'outer') {
        _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
      } else {
        _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
      }
    } else if (_opentype === 'excelIn') {    // 导入导出
      if (card.intertype === 'outer') {
        _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
      } else {
        _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
      }
    } else if (_opentype === 'funcbutton') {
      if (!card.funcType) {
        _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
      } else if (card.funcType === 'changeuser') {
        _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
      } else if (card.funcType === 'print') {
        if (card.intertype === 'outer') {
          _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
        } else {
          _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
        }
      }
    } else {
      if (card.intertype === 'outer') {
        _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
      } else {
        _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sql', 'sqlType']
      }
    }
    let _options = this.getOptions(_opentype, _intertype, _funcType, card.pageTemplate)
    this.setState({
      openType: _opentype,
      menulist: _menulist.options || [],
      interType: card.intertype || 'inner',
      interType: _intertype,
      position: card.position || 'toolbar',
      funcType: card.funcType,
      funcType: _funcType,
      formlist: this.props.formlist.map(item => {
        if (item.key === 'class') {
          item.options = btnClasses
@@ -167,6 +139,46 @@
    })
  }
  getOptions = (_opentype, _intertype, _funcType, _pageTemplate) => {
    let _options = fromJS(actionTypeOptions[_opentype]).toJS() // 选项列表
    if (_opentype === 'innerpage') {         // 新页面,可选模板(自定义时,可填入外部链接)
      if (_pageTemplate === 'custom') {
        _options.push('url', 'joint')
      }
    } else if (_opentype === 'excelOut') {    // 导入导出
      if (_intertype === 'outer') {
        _options.push('innerFunc', 'sysInterface', 'interface', 'outerFunc')
      } else if (_intertype === 'inner') {
        _options.push('innerFunc')
      }
    } else if (_opentype === 'excelIn') {    // 导入导出
      if (_intertype === 'outer') {
        _options.push('innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc')
      } else if (_intertype === 'inner') {
        _options.push('innerFunc')
      }
    } else if (_opentype === 'funcbutton') {
      if (_funcType === 'print') {
        if (_intertype === 'outer') {
          _options.push('execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'execSuccess', 'execError')
        } else if (_intertype === 'inner') {
          _options.push('execMode', 'intertype', 'innerFunc', 'Ot', 'execSuccess', 'execError')
        }
      }
    } else {
      if (_intertype === 'outer') {
        _options.push('innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc')
      } else if (_intertype === 'inner') {
        _options.push('innerFunc')
      } else {
        _options.push('sql', 'sqlType')
      }
    }
    return _options
  }
  componentDidMount () {
    const { card } = this.props
@@ -190,47 +202,7 @@
    const { card } = this.props
    if (key === 'OpenType') {
      let _options = null
      if (value === 'innerpage') {
        _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position']
        if (card.pageTemplate === 'custom') {
          _options.push('url', 'joint')
        }
      } else if (value === 'blank' || value === 'tab') {
        _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabTemplate', 'linkmenu']
      } else if (value === 'popview') {
        _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabType', 'linkTab', 'popClose']
      } else if (value === 'excelOut') {
        if (this.state.interType === 'outer') {
          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
        } else {
          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
        }
      } else if (value === 'excelIn') {
        if (this.state.interType === 'outer') {
          _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
        } else {
          _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
        }
      } else if (value === 'funcbutton') {
        if (!this.state.funcType) {
          _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
        } else if (this.state.funcType === 'changeuser') {
          _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
        } else if (this.state.funcType === 'print') {
          if (this.state.interType === 'outer') {
            _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
          } else {
            _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
          }
        }
      } else {
        if (this.state.interType === 'inner') {
          _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sql', 'sqlType']
        } else {
          _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc']
        }
      }
      let _options = this.getOptions(value, this.state.interType, this.state.funcType, card.pageTemplate)
      let _fieldval = {}
      
@@ -323,12 +295,8 @@
        this.props.form.setFieldsValue(_fieldval)
      })
    } else if (key === 'funcType') {
      let _options = null
      if (!value) {
        _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
      } else if (value === 'changeuser') {
        _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
      } else if (value === 'print') {
      let _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
      if (value === 'print') {
        if (this.state.interType === 'outer') {
          _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
        } else {
@@ -387,12 +355,10 @@
        this.props.form.setFieldsValue(_fieldval)
      })
    } else if (key === 'pageTemplate') {
      let _options = null
      let _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position']
      let _fieldval = {}
      if (value === 'custom') {
        _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'url', 'joint', 'icon', 'class', 'position']
      } else {
        _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position']
        _options.push('url', 'joint')
      }
      this.setState({
@@ -414,17 +380,6 @@
      }, () => {
        this.props.form.setFieldsValue(_fieldval)
      })
    } else if (key === 'tabTemplate') {
      let _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabTemplate', 'linkmenu']
      this.setState({
        openType: value,
        formlist: this.state.formlist.map(item => {
          item.hidden = !_options.includes(item.key)
          return item
        })
      })
    }
  }
@@ -433,32 +388,7 @@
    let value = e.target.value
    if (key === 'intertype') {
      let _options = null
      if (openType === 'excelOut') {
        if (value === 'outer') {
          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
        } else {
          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
        }
      } else if (openType === 'excelIn') {
        if (value === 'outer') {
          _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
        } else {
          _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
        }
      } else if (openType === 'funcbutton') {
        if (value === 'outer') {
          _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
        } else {
          _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
        }
      } else {
        if (value === 'inner') {
          _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sql', 'sqlType']
        } else {
          _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc']
        }
      }
      let _options = this.getOptions(openType, value, this.state.funcType)
      this.setState({
        interType: value,
src/menu/actioncomponent/dragaction/index.jsx
@@ -108,7 +108,7 @@
    newcard.OpenType = 'prompt'
    newcard.icon = ''
    newcard.class = 'default'
    newcard.intertype = 'inner'
    newcard.intertype = 'system'
    newcard.method = 'POST'
    newcard.position = 'toolbar'
    newcard.execSuccess = 'grid'
src/menu/actioncomponent/formconfig.jsx
@@ -43,6 +43,10 @@
    }
  ]
  if (card.intertype === 'inner' && !card.innerFunc) {
    card.intertype = 'system'
  }
  if (type === 'chart') {
    if (card.focus) {
      // 导入和导出excel,按钮名称直接为导入、导出
@@ -80,12 +84,9 @@
      type: 'select',
      key: 'funcType',
      label: Formdict['header.form.funcType'],
      initVal: card.funcType || '',
      initVal: card.funcType || 'print',
      required: true,
      options: [{
        value: 'changeuser',
        text: Formdict['header.form.func.changeuser']
      }, {
        value: 'print',
        text: Formdict['header.form.func.print']
      }]
@@ -111,9 +112,12 @@
      type: 'radio',
      key: 'intertype',
      label: Formdict['header.form.intertype'],
      initVal: card.intertype || 'inner',
      initVal: card.intertype || 'system',
      required: true,
      options: [{
        value: 'system',
        text: '系统'
      }, {
        value: 'inner',
        text: Formdict['header.form.interface.inner']
      }, {
src/menu/actioncomponent/index.scss
@@ -6,9 +6,10 @@
    top: 5px;
  }
  .ant-row .anticon-plus {
  .ant-row > .anticon-plus {
    color: #26C281;
    padding: 5px;
    cursor: pointer;
  }
  .page-card {
src/menu/actioncomponent/verifyexcelin/index.jsx
@@ -84,7 +84,7 @@
              <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'columns', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={this.props.dict['header.form.query.delete']}
                title={this.props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record, 'columns')
              }>
                <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
@@ -117,13 +117,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -141,7 +141,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'unique')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record, 'unique')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
@@ -181,13 +181,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -205,7 +205,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record, 'scripts')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
src/menu/actioncomponent/verifyexcelout/index.jsx
@@ -52,7 +52,7 @@
              <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'columns', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={this.props.dict['header.form.query.delete']}
                title={this.props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record)
              }>
                <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
src/menu/actioncomponent/verifyprint/editable/index.jsx
@@ -118,7 +118,7 @@
              <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={props.dict['header.form.query.delete']}
                title={props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record.key)
              }>
                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
src/menu/components/chart/antv-bar/chartcompile/index.scss
@@ -7,6 +7,7 @@
    color: #1890ff;
    font-size: 16px;
    margin-right: 5px;
    cursor: pointer;
  }
}
.menu-chart-edit-modal {
src/menu/components/chart/antv-bar/index.jsx
@@ -6,6 +6,7 @@
import asyncComponent from '@/utils/asyncComponent'
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import './index.scss'
@@ -32,7 +33,8 @@
  UNSAFE_componentWillMount () {
    const { card, config } = this.props
    // card.dataName = Utils.getdataName()
    // this.props.updateConfig(card)
    if (card.isNew) {
      let _plot = {
        chartType: card.type, // 图表类型
@@ -68,11 +70,22 @@
        i++
      }
      let dataName = ''
      while (!dataName) {
        let _dataName = Utils.getdataName()
        if (config.components.filter(com => com.dataName === _dataName).length === 0) {
          dataName = _dataName
        }
      }
      let _card = {
        uuid: card.uuid,
        type: card.type,
        format: 'array',
        dataName: dataName,
        subtype: card.subtype,
        setting: {span: 12, height: 400, name},
        setting: {span: 12, height: 400, interType: 'system', name},
        columns: [],
        scripts: [],
        search: [],
src/menu/datasourcecomponent/verifycard/index.jsx
@@ -78,15 +78,15 @@
      {
        title: 'SQL',
        dataIndex: 'sql',
        width: '60%',
        width: '65%',
        render: (text) => (
          <Paragraph copyable ellipsis={{ rows: 5, expandable: true }}>{text}</Paragraph>
          <Paragraph copyable ellipsis={{ rows: 4, expandable: true }}>{text}</Paragraph>
        )
      },
      {
        title: '状态',
        dataIndex: 'status',
        width: '20%',
        width: '15%',
        render: (text, record) => record.status === 'false' ?
          (
            <div>
@@ -335,16 +335,6 @@
        activeKey: val,
        loading: false
      })
      // this.sqlverify(() => { // 验证成功
      //   this.setState({
      //     activeKey: val,
      //     loading: false
      //   })
      // }, () => {             // 验证失败
      //   this.setState({
      //     loading: false
      //   })
      // }, true)
    } else if (activeKey === 'scripts') {
      let _loading = false
      if (this.scriptsForm && this.scriptsForm.state.editItem) {
@@ -491,6 +481,7 @@
            <SettingForm
              menuId={this.props.menuId}
              dict={this.props.dict}
              config={this.props.config}
              permFuncField={this.props.permFuncField}
              columns={columns}
              setting={setting}
src/menu/datasourcecomponent/verifycard/settingform/index.jsx
@@ -14,13 +14,14 @@
    dict: PropTypes.object,       // 字典项
    menuId: PropTypes.string,     // 菜单Id
    permFuncField: PropTypes.any, // 菜单Id
    config: PropTypes.object,     // 组件配置
    setting: PropTypes.object,    // 数据源配置
    columns: PropTypes.array,     // 列设置
    scripts: PropTypes.array,     // 自定义脚本
  }
  state = {
    interType: this.props.setting.interType || 'inner',
    interType: this.props.setting.interType || 'system',
  }
  handleConfirm = () => {
@@ -30,7 +31,7 @@
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          // 数据源前端验证
          if (values.interType === 'inner' && !values.innerFunc && values.execute !== 'false' && !values.dataresource) {
          if (values.interType === 'system' && values.execute !== 'false' && !values.dataresource) {
            notification.warning({
              top: 92,
              message: '请填写内部函数或数据源!',
@@ -38,7 +39,7 @@
            })
            reject()
            return
          } else if (values.interType === 'inner' && !values.innerFunc && values.execute !== 'false' && values.dataresource) {
          } else if (values.interType === 'system' && values.execute !== 'false' && values.dataresource) {
            let _quot = values.dataresource.match(/'{1}/g)
            let _lparen = values.dataresource.match(/\({1}/g)
            let _rparen = values.dataresource.match(/\){1}/g)
@@ -88,7 +89,7 @@
          // 数据源保存
          if (
            values.interType === 'inner' && !values.innerFunc && values.execute !== 'false' &&
            values.interType === 'system' && values.execute !== 'false' &&
            /[^\s]+\s+[^\s]+/ig.test(values.dataresource) && setting.dataresource !== values.dataresource
          ) {
            let param = {
@@ -123,7 +124,7 @@
  }
  render() {
    const { setting, permFuncField, columns } = this.props
    const { setting, permFuncField, columns, config } = this.props
    const { getFieldDecorator } = this.props.form
    const { interType } = this.state
@@ -224,6 +225,7 @@
                  ]
                })(
                <Radio.Group onChange={(e) => {this.onRadioChange(e, 'interType')}}>
                  <Radio value="system">系统</Radio>
                  <Radio value="inner">内部</Radio>
                  <Radio value="outer">外部</Radio>
                </Radio.Group>)}
@@ -238,7 +240,13 @@
              }>
                {getFieldDecorator('innerFunc', {
                  initialValue: setting.innerFunc || '',
                  rules: rules
                  rules: [
                    {
                      required: true,
                      message: this.props.dict['form.required.input'] + '内部函数!'
                    },
                    ...rules
                  ]
                })(<Input placeholder={''} autoComplete="off" />)}
              </Form.Item>
            </Col> : null}
@@ -250,7 +258,7 @@
                    {
                      required: true,
                      message: this.props.dict['form.required.input'] + '接口地址!'
                    },
                    }
                  ]
                })(<Input placeholder={''} autoComplete="off" />)}
              </Form.Item>
@@ -265,7 +273,7 @@
                })(<Input placeholder={''} autoComplete="off" />)}
              </Form.Item>
            </Col> : null}
            {interType === 'inner' ? <Col span={24} className="data-source" style={{paddingLeft: '7px'}}>
            {interType === 'system' ? <Col span={24} className="data-source" style={{paddingLeft: '7px'}}>
              <Form.Item labelCol={{xs: { span: 24 }, sm: { span: 2 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 22 }} } label={
                <Tooltip placement="topLeft" title={'使用系统函数时,需填写数据源。注:数据权限替换符 $@ -> /* 或 \'\'、 @$ -> */ 或 \'\''}>
                  <Icon type="question-circle" />
@@ -289,7 +297,7 @@
                })(<InputNumber min={150} max={1500} precision={0} />)}
              </Form.Item>
            </Col>
            {interType === 'inner' ? <Col span={8}>
            {interType === 'system' ? <Col span={8}>
              <Form.Item label={
                <Tooltip placement="topLeft" title={'查询时,搜索条件以where条件拼接进入sql,统计时,将数据源中以“@+搜索字段+@”的内容,以搜索条件中的值进行替换后,提交查询,注:查询类型仅在使用系统函数时有效。'}>
                  <Icon type="question-circle" />
@@ -320,7 +328,21 @@
                )}
              </Form.Item>
            </Col>
            {interType === 'inner' ? <Col span={8}>
            {/* 数组数据,需设置排序规则 */}
            {config.format === 'array' ? <Col span={8}>
              <Form.Item label="默认排序">
                {getFieldDecorator('order', {
                  initialValue: setting.order || '',
                  rules: [
                    {
                      required: true,
                      message: this.props.dict['form.required.input'] + '默认排序!'
                    }
                  ]
                })(<Input placeholder={'ID asc, UID desc'} autoComplete="off" />)}
              </Form.Item>
            </Col> : null}
            {interType === 'system' ? <Col span={8}>
              <Form.Item label="默认sql">
                {getFieldDecorator('execute', {
                  initialValue: setting.execute || 'true'
@@ -332,14 +354,49 @@
              </Form.Item>
            </Col> : null}
            <Col span={8}>
              <Form.Item label="初始化数据">
              <Form.Item label="初始化">
                {getFieldDecorator('onload', {
                  initialValue: setting.onload || 'true'
                })(
                <Radio.Group>
                  <Radio value="true">加载</Radio>
                  <Radio value="false">不加载</Radio>
                </Radio.Group>)}
                  <Radio.Group>
                    <Radio value="true">加载数据</Radio>
                    <Radio value="false">不加载数据</Radio>
                  </Radio.Group>
                )}
              </Form.Item>
            </Col>
            {!config.laypage ? <Col span={8}>
              <Form.Item label={
                <Tooltip placement="topLeft" title={'初始化加载时,是否与其他组件一同加载数据,注:仅在使用系统函数,且初始化加载数据时有效。'}>
                  <Icon type="question-circle" />
                  同步查询
                </Tooltip>
              }>
                {getFieldDecorator('sync', {
                  initialValue: setting.sync || 'true'
                })(
                  <Radio.Group>
                    <Radio value="true">是</Radio>
                    <Radio value="false">否</Radio>
                  </Radio.Group>
                )}
              </Form.Item>
            </Col> : null}
            <Col span={8}>
              <Form.Item label={
                <Tooltip placement="topLeft" title={'使用主搜索条件(存在时),主搜索条件与组件的搜索条件会一同用作数据过滤(组件的搜索条件优先)。'}>
                  <Icon type="question-circle" />
                  主搜索
                </Tooltip>
              }>
                {getFieldDecorator('useMSearch', {
                  initialValue: setting.useMSearch || 'false'
                })(
                  <Radio.Group>
                    <Radio value="true">使用</Radio>
                    <Radio value="false">不使用</Radio>
                  </Radio.Group>
                )}
              </Form.Item>
            </Col>
          </Row>
src/menu/menushell/index.jsx
@@ -2,7 +2,7 @@
import { useDrop } from 'react-dnd'
import { is, fromJS } from 'immutable'
import update from 'immutability-helper'
import { Empty } from 'antd'
import { Empty, notification } from 'antd'
import Utils from '@/utils/utils.js'
import Card from './card'
@@ -45,6 +45,17 @@
        return
      }
      if (item.component === 'search') { // 搜索组件不可重复添加
        if (cards.filter(card => card.type === 'search').length > 0) {
          notification.warning({
            top: 92,
            message: '搜索条件不可重复添加!',
            duration: 5
          })
          return
        }
      }
      let newcard = {
        uuid: Utils.getuuid(),
        type: item.component,
src/menu/menushell/index.scss
@@ -5,6 +5,9 @@
  >.ant-col {
    padding: 8px;
  }
  .anticon {
    cursor: unset;
  }
  .mk-component-card {
    position: relative;
@@ -40,6 +43,7 @@
    right: 0px;
    top: -30px;
    opacity: 0;
    cursor: pointer;
    transition: opacity 0.2s;
  }
}
src/menu/searchcomponent/index.scss
@@ -12,10 +12,11 @@
    padding: 0 6px;
    margin-top: 5px;
  }
  .ant-row .anticon-plus {
  .ant-row > .anticon-plus {
    color: #26C281;
    float: right;
    padding: 5px;
    cursor: pointer;
    margin-top: 7px;
  }
  .page-card {
src/menu/searchcomponent/searcheditable/index.jsx
@@ -117,7 +117,7 @@
              <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={props.dict['header.form.query.delete']}
                title={props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record.key)
              }>
                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
@@ -227,7 +227,7 @@
              <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={this.props.dict['header.form.query.delete']}
                title={this.props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record.key)
              }>
                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
src/tabviews/commontable/index.jsx
@@ -3,13 +3,13 @@
import {connect} from 'react-redux'
import { is, fromJS } from 'immutable'
import { notification, Spin, Tabs, Icon, Switch, Modal, Button, message, Tree, Typography, Row, Col } from 'antd'
import moment from 'moment'
import Api from '@/api'
import options from '@/store/options.js'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import Utils from '@/utils/utils.js'
import UtilsDM from '@/utils/utils-datamanage.js'
import asyncComponent from '@/utils/asyncComponent'
import asyncSpinComponent from '@/utils/asyncSpinComponent'
import { refreshTabView } from '@/store/action'
@@ -262,6 +262,30 @@
      // 标记主页面,用于按钮固定及表单挂载设置
      config.setting.tabType = 'main'
      // 数据源信息预处理
      config.setting.laypage = config.setting.laypage !== 'false'     // 是否分页,转为boolean 统一格式
      config.setting.execute = config.setting.default !== 'false'     // 默认sql是否执行,转为boolean 统一格式
      config.setting.customScript = config.setting.customScript || '' // 自定义脚本
      if (!config.setting.execute) { // 默认sql 不执行时 置空
        config.setting.dataresource = ''
      } else {
        config.setting.dataresource = config.setting.dataresource || ''
      }
      if (/\s/.test(config.setting.dataresource)) {
        config.setting.dataresource = '(' + config.setting.dataresource + ') tb'
      }
      if (this.props.dataManager) { // 数据权限
        config.setting.dataresource = config.setting.dataresource.replace(/\$@/ig, '/*')
        config.setting.dataresource = config.setting.dataresource.replace(/@\$/ig, '*/')
        config.setting.customScript = config.setting.customScript.replace(/\$@/ig, '/*')
        config.setting.customScript = config.setting.customScript.replace(/@\$/ig, '*/')
      } else {
        config.setting.dataresource = config.setting.dataresource.replace(/@\$|\$@/ig, '')
        config.setting.customScript = config.setting.customScript.replace(/@\$|\$@/ig, '')
      }
      if (_curUserConfig) {
        config.setting = {...config.setting, ..._curUserConfig.setting}
        config.easyCode = _curUserConfig.easyCode || config.easyCode || ''
@@ -388,8 +412,6 @@
          return pre.sort - next.sort
        })
      }
      console.log(_columns)
      this.setState({
        BID: param && param.BID ? param.BID : '',
@@ -524,8 +546,7 @@
   * @description 主表数据加载
   */ 
  async loadmaindata () {
    const { setting, BIDs, search, BID } = this.state
    let param = ''
    const { setting, arr_field, BIDs, search, orderBy, BID, pageIndex, pageSize } = this.state
    let requireFields = search.filter(item => item.required && (!item.value || item.value.length === 0))
    if (requireFields.length > 0) {
@@ -544,19 +565,8 @@
      loading: true
    })
    if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) {
      param = this.getCustomParam()
    } else {
      param = this.getDefaultParam()
    }
    if (BID) {
      param.BID = BID
    }
    // 数据管理权限
    if (this.props.dataManager) {
      param.dataM = 'Y'
    }
    let _orderBy = orderBy || setting.order
    let param = UtilsDM.getQueryDataParams(setting, setting.customScript, arr_field, search, _orderBy, pageIndex, pageSize, BID, this.props.menuType, this.props.dataManager)
    let result = await Api.genericInterface(param)
    if (result.status) {
@@ -584,176 +594,6 @@
        duration: 10
      })
    }
  }
  /**
   * @description 获取用户自定义存储过程传参
   */
  getCustomParam = () => {
    const { pageIndex, pageSize, orderBy, search, setting } = this.state
    let _search = Utils.formatCustomMainSearch(search)
    let param = {
      OrderCol: orderBy || setting.order,
      ..._search
    }
    if (setting.laypage !== 'false') {
      param.PageIndex = pageIndex
      param.PageSize = pageSize
    }
    if (setting.interType === 'inner') {
      param.func = setting.innerFunc
    } else {
      if (this.props.menuType === 'HS') {
        if (setting.sysInterface === 'true' && options.cloudServiceApi) {
          param.rduri = options.cloudServiceApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      } else {
        if (setting.sysInterface === 'true' && window.GLOB.mainSystemApi) {
          param.rduri = window.GLOB.mainSystemApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      }
      if (setting.outerFunc) {
        param.func = setting.outerFunc
      }
    }
    return param
  }
  /**
   * @description 获取系统存储过程 sPC_Get_TableData 的参数
   */
  getDefaultParam = () => {
    const { arr_field, pageIndex, pageSize, orderBy, search, setting } = this.state
    if (!arr_field) {
      notification.warning({
        top: 92,
        message: '未设置显示列!',
        duration: 5
      })
      return null
    }
    let _search = Utils.joinMainSearchkey(search)
    _search = _search ? 'where ' + _search : ''
    let param = {
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      arr_field: arr_field,
      custom_script: setting.customScript || '',
      default_sql: setting.default || 'true'
    }
    let _orderBy = orderBy || setting.order
    let _dataresource = setting.dataresource
    if (/\s/.test(_dataresource)) {
      _dataresource = '(' + _dataresource + ') tb'
    }
    if (this.props.dataManager) { // 数据权限
      _dataresource = _dataresource.replace(/\$@/ig, '/*')
      _dataresource = _dataresource.replace(/@\$/ig, '*/')
      param.custom_script = param.custom_script.replace(/\$@/ig, '/*')
      param.custom_script = param.custom_script.replace(/@\$/ig, '*/')
    } else {
      _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
      param.custom_script = param.custom_script.replace(/@\$|\$@/ig, '')
    }
    let regoptions = null
    if (setting.queryType === 'statistics' || param.custom_script) {
      let allSearch = Utils.getAllSearchOptions(search)
      regoptions = allSearch.map(item => {
        return {
          reg: new RegExp('@' + item.key + '@', 'ig'),
          value: `'${item.value}'`
        }
      })
    }
    if (setting.queryType === 'statistics' && setting.default !== 'false') { // 统计数据源,内容替换
      regoptions.forEach(item => {
        _dataresource = _dataresource.replace(item.reg, item.value)
      })
      _search = ''
    }
    let LText = ''
    let DateCount = ''
    if (setting.default !== 'false' && setting.laypage !== 'false') {
      LText = ` select top ${pageSize} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from ${_dataresource} ${_search}) tmptable where rows > ${pageSize * (pageIndex - 1)} order by tmptable.rows `
      DateCount = `select count(1) as total from ${_dataresource} ${_search}`
    } else if (setting.default !== 'false') {
      LText = ` select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
      DateCount = ''
    }
    if (param.custom_script) {
      regoptions.push({
        reg: new RegExp('@orderBy@', 'ig'),
        value: _orderBy
      })
      if (setting.laypage !== 'false') {
        regoptions.push({
          reg: new RegExp('@pageSize@', 'ig'),
          value: pageSize
        }, {
          reg: new RegExp('@pageIndex@', 'ig'),
          value: pageIndex
        })
      }
      regoptions.forEach(item => {
        param.custom_script = param.custom_script.replace(item.reg, item.value)
      })
      if (LText) {
        LText += `
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      } else {
        param.custom_script += `
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      }
    }
    // 测试系统打印查询语句
    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
      param.custom_script &&  console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${param.custom_script}`)
      LText &&  console.log(LText)
    }
    param.custom_script = Utils.formatOptions(param.custom_script)
    param.LText = Utils.formatOptions(LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.DateCount = Utils.formatOptions(DateCount)
    if (this.props.menuType === 'HS') { // 云端数据验证
      param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
    }
    return param
  }
  /**
src/tabviews/custom/components/chart/antv-bar-line/asyncButtonComponent.jsx
New file
@@ -0,0 +1,34 @@
import React, {Component} from 'react'
import { Button } from 'antd'
/**
 * @description 异步加载模块
 * @param {*} importComponent
 */
export default function asyncComponent(importComponent) {
  return class extends Component {
    constructor(props) {
      super(props)
      this.state = {
        component: null
      }
    }
    async componentDidMount() {
      const {default: component} = await importComponent()
      this.setState({component})
    }
    // <Button className="loading-skeleton" disabled={true}></Button> // 骨架按钮
    render() {
      const C = this.state.component
      const btn = this.props.btn || {}
      return C ?
        <C {...this.props} /> :
        <Button icon={btn.OpenType === 'excelOut' ? 'download' : 'upload'} disabled={true} title={btn.label} style={{border: 0, background: 'transparent'}}></Button>
    }
  }
}
src/tabviews/custom/components/chart/antv-bar-line/index.jsx
New file
@@ -0,0 +1,981 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Chart } from '@antv/g2'
import DataSet from '@antv/data-set'
import { Spin, Empty, Select } from 'antd'
import asyncComponent from './asyncButtonComponent'
// import searchLine from '../../share/searchLine'
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import './index.scss'
const ExcelOutButton = asyncComponent(() => import('@/tabviews/zshare/actionList/exceloutbutton'))
const ExcelInButton = asyncComponent(() => import('@/tabviews/zshare/actionList/excelInbutton'))
class LineChart extends Component {
  static propTpyes = {
    BID: PropTypes.any,              // 父级Id
    data: PropTypes.array,           // 统一查询数据
    config: PropTypes.object,        // 组件配置信息
    mainSearch: PropTypes.any,       // 全局搜索条件
    menuType: PropTypes.any,         // 菜单类型
    dataManager: PropTypes.any,      // 数据权限
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, // 字典
    empty: true,               // 图表数据为空
    chartId: Utils.getuuid(),  // 图表Id
    title: '',
    searchList: null,
    chartData: [],             // 图表数据
    chartFields: [],           // 统计图表生成字段集
    selectFields: [],          // 统计图表选择字段
    percentFields: []          // 设置为百分比的字段,tooltip时增加%
  }
  UNSAFE_componentWillMount () {
    // const { config, data, BID, mainSearch, menuType, dataManager } = this.props
    // this.setState({
    //   title: config.setting.title,
    //   searchList: Utils.initMainSearch(config.search)
    // })
  }
  /**
   * @description 校验图表的按钮组,如果为统计图表,计算图表字段
   */
  componentDidMount () {
    const { plot, data, config } = this.props
    let _state = {}
    let percentFields = []
    if (plot.datatype === 'statistics' && (plot.chartType === 'line' || plot.chartType === 'bar')) {
      let result = this.getStaticMsg(data)
      _state.chartData = result.data
      _state.chartFields = result.chartFields
      _state.selectFields = result.selectFields
      let _column = config.columns.filter(col => plot.InfoValue === col.field)[0]
      if (_column && _column.format === 'percent') {
        percentFields.push(plot.InfoValue)
        _state.percentFields = percentFields
      }
      this.setState(_state, () => {
        this.viewrender()
      })
    } else {
      if (plot.chartType === 'line' || plot.chartType === 'bar') {
        try {
          plot.Yaxis.forEach(yaxis => {
            let _column = config.columns.filter(col => yaxis === col.field)[0]
            if (_column && _column.format === 'percent') {
              percentFields.push(_column.label)
            }
          })
        } catch {
          console.warn('Incorrect percentage setting')
        }
      }
      this.setState({ percentFields }, () => {
        this.viewrender()
      })
    }
  }
  /**
   * @description 图表数据更新,刷新内容
   */
  UNSAFE_componentWillReceiveProps (nextProps) {
    const { plot } = this.props
    if (!is(fromJS(this.props.data), fromJS(nextProps.data))) {
      let _state = {}
      if (plot.datatype === 'statistics' && (plot.chartType === 'line' || plot.chartType === 'bar')) {
        let result = this.getStaticMsg(nextProps.data)
        _state.chartData = result.data
        _state.chartFields = result.chartFields
        _state.selectFields = result.selectFields
      }
      this.setState(_state, () => {
        let _element = document.getElementById(this.state.chartId)
        if (_element) {
          _element.innerHTML = ''
        }
        this.viewrender()
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 图表数据预处理
   * 1、通过显示列进行数据类型转换
   * 2、重复数据:取平均值、累计、去重
   * 3、柱状图数据补齐
   */
  getdata = () => {
    const { data, plot, config } = this.props
    let vFields = plot.Yaxis && typeof(plot.Yaxis) === 'string' ? [plot.Yaxis] : plot.Yaxis
    let _columns = config.columns.filter(col => vFields.includes(col.field))
    if (!data) {
      this.setState({empty: true})
      return []
    }
    let _data = []
    let _cdata = fromJS(data).toJS()
    if (plot.repeat === 'average') {
      let _mdata = new Map()
      _cdata.forEach(item => {
        _columns.forEach(col => {
          if (typeof(item[col.field]) !== 'number') {
            item[col.field] = parseFloat(item[col.field])
            if (isNaN(item[col.field])) {
              item[col.field] = 0
            }
          }
          if (col.format === 'percent') {
            item[col.field] = item[col.field] * 100
          }
        })
        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
          item.$count = 1
          _mdata.set(item[plot.Xaxis], item)
        } else if (item[plot.Xaxis]) {
          let _item = _mdata.get(item[plot.Xaxis])
          _item.$count++
          vFields.forEach(field => {
            _item[field] += item[field]
          })
          _mdata.set(item[plot.Xaxis], _item)
        }
      })
      _data = [..._mdata.values()]
      _data = _data.map(item => {
        _columns.forEach(col => {
          item[col.field] = item[col.field] / item.$count
          item[col.field] = item[col.field].toFixed(col.decimal)
          item[col.field] = +item[col.field]
        })
        return item
      })
    } else if (plot.repeat === 'cumsum') {
      let _mdata = new Map()
      _cdata.forEach(item => {
        _columns.forEach(col => {
          if (typeof(item[col.field]) !== 'number') {
            item[col.field] = parseFloat(item[col.field])
            if (isNaN(item[col.field])) {
              item[col.field] = 0
            }
          }
          if (col.format === 'percent') {
            item[col.field] = item[col.field] * 100
          }
        })
        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
          _mdata.set(item[plot.Xaxis], item)
        } else if (item[plot.Xaxis]) {
          let _item = _mdata.get(item[plot.Xaxis])
          vFields.forEach(field => {
            _item[field] += item[field]
          })
          _mdata.set(item[plot.Xaxis], _item)
        }
      })
      _data = [..._mdata.values()]
      _data = _data.map(item => {
        _columns.forEach(col => {
          item[col.field] = item[col.field].toFixed(col.decimal)
          item[col.field] = +item[col.field]
        })
        return item
      })
    } else { // plot.repeat === 'unrepeat'
      let _mdata = new Map()
      _cdata.forEach(item => {
        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
          _columns.forEach(col => {
            if (typeof(item[col.field]) !== 'number') {
              item[col.field] = parseFloat(item[col.field])
              if (isNaN(item[col.field])) {
                item[col.field] = 0
              }
            }
            if (col.format === 'percent') {
              item[col.field] = item[col.field] * 100
            }
            item[col.field] = item[col.field].toFixed(col.decimal)
            item[col.field] = +item[col.field]
          })
          _mdata.set(item[plot.Xaxis], item)
        }
      })
      _data = [..._mdata.values()]
    }
    if (plot.correction && plot.chartType === 'bar' && _data.length > 0 && _data.length < plot.correction) {
      if (plot.enabled !== 'true' || (plot.customs && plot.customs.filter(cell => cell.chartType !== 'bar').length === 0)) {
        let _num = plot.correction - _data.length
        for (let i = 0; i < _num; i++) {
          let _val = Array( i + 2 ).join(' ')
          let _cell = {}
          _cell[plot.Xaxis] = _val
          _columns.forEach(col => {
            _cell[col.field] = ''
          })
          _data.push(_cell)
        }
      }
    }
    this.setState({empty: _data.length === 0})
    return _data
  }
  /**
   * @description 统计数据预处理,动态生成统计字段并进行数据转换
   */
  getStaticMsg = (data) => {
    const { plot, config } = this.props
    let _column = config.columns.filter(col => plot.InfoValue === col.field)[0]
    let percent = false
    let decimal = 0
    if (_column && _column.format === 'percent') {
      percent = true
    }
    if (_column) {
      decimal = _column.decimal
    }
    if (!data) {
      this.setState({empty: true})
      return {data: [], chartFields: [], selectFields: []}
    }
    let _data = []
    let _cdata = fromJS(data).toJS()
    let _chartFields = []
    let _selectFields = []
    if (plot.repeat === 'average') {
      let _mdata = new Map()
      _cdata.forEach(item => {
        if (!item[plot.InfoType] || !item[plot.Xaxis]) return
        _chartFields.push(item[plot.InfoType])
        item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
        if (typeof(item[plot.InfoValue]) !== 'number') {
          item[plot.InfoValue] = parseFloat(item[plot.InfoValue])
          if (isNaN(item[plot.InfoValue])) {
            item[plot.InfoValue] = 0
          }
        }
        if (percent) {
          item[plot.InfoValue] = item[plot.InfoValue] * 100
        }
        if (!_mdata.has(item.$uuid)) {
          item.$count = 1
          _mdata.set(item.$uuid, item)
        } else {
          let _item = _mdata.get(item.$uuid)
          _item.$count++
          _item[plot.InfoValue] += item[plot.InfoValue]
          _mdata.set(item.$uuid, _item)
        }
      })
      _data = [..._mdata.values()]
      _data = _data.map(item => {
        item[plot.InfoValue] = item[plot.InfoValue] / item.$count
        item[plot.InfoValue] = item[plot.InfoValue].toFixed(decimal)
        item[plot.InfoValue] = +item[plot.InfoValue]
        return item
      })
    } else if (plot.repeat === 'cumsum') {
      let _mdata = new Map()
      _cdata.forEach(item => {
        if (!item[plot.InfoType] || !item[plot.Xaxis]) return
        _chartFields.push(item[plot.InfoType])
        item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
        if (typeof(item[plot.InfoValue]) !== 'number') {
          item[plot.InfoValue] = parseFloat(item[plot.InfoValue])
          if (isNaN(item[plot.InfoValue])) {
            item[plot.InfoValue] = 0
          }
        }
        if (percent) {
          item[plot.InfoValue] = item[plot.InfoValue] * 100
        }
        if (!_mdata.has(item.$uuid)) {
          _mdata.set(item.$uuid, item)
        } else {
          let _item = _mdata.get(item.$uuid)
          _item[plot.InfoValue] += item[plot.InfoValue]
          _mdata.set(item.$uuid, _item)
        }
      })
      _data = [..._mdata.values()]
      _data = _data.map(item => {
        item[plot.InfoValue] = item[plot.InfoValue].toFixed(decimal)
        item[plot.InfoValue] = +item[plot.InfoValue]
        return item
      })
    } else { // plot.repeat === 'unrepeat'
      let _mdata = new Map()
      _cdata.forEach(item => {
        if (!item[plot.InfoType] || !item[plot.Xaxis]) return
        _chartFields.push(item[plot.InfoType])
        item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
        if (!_mdata.has(item.$uuid)) {
          if (typeof(item[plot.InfoValue]) !== 'number') {
            item[plot.InfoValue] = parseFloat(item[plot.InfoValue])
            if (isNaN(item[plot.InfoValue])) {
              item[plot.InfoValue] = 0
            }
          }
          if (percent) {
            item[plot.InfoValue] = item[plot.InfoValue] * 100
          }
          item[plot.InfoValue] = item[plot.InfoValue].toFixed(decimal)
          item[plot.InfoValue] = +item[plot.InfoValue]
          _mdata.set(item.$uuid, item)
        }
      })
      _data = [..._mdata.values()]
    }
    _chartFields = Array.from(new Set(_chartFields))
    if (plot.InfoDefNumber >= _chartFields.length) {
      _selectFields = _chartFields
    } else {
      _selectFields = _chartFields.slice(0, plot.InfoDefNumber)
    }
    return {data: _data, chartFields: _chartFields, selectFields: _selectFields}
  }
  /**
   * @description 获取统计图表展示数据,通过选择类型筛选
   */
  getStaticData = () => {
    const { plot } = this.props
    const { chartData, chartFields, selectFields } = this.state
    let _data = []
    if (selectFields.length === chartFields.length) {
      _data = chartData
    } else {
      _data = chartData.filter(item => selectFields.includes(item[plot.InfoType]))
    }
    this.setState({empty: _data.length === 0})
    return _data
  }
  /**
   * @description 图表渲染分组
   */
  viewrender = () => {
    const { plot } = this.props
    if (plot.chartType === 'line') {
      this.linerender()
    } else if (plot.chartType === 'bar') {
      this.barrender()
    }
  }
  /**
   * @description 折线图渲染
   */
  linerender = () => {
    const { plot, config } = this.props
    const { percentFields } = this.state
    let _data = []
    let _valfield = 'value'
    let _typefield = 'key'
    let ispercent = false
    if (plot.datatype === 'statistics') {
      _valfield = plot.InfoValue
      _typefield = plot.InfoType
      if (percentFields.length > 0) {
        ispercent = true
      }
      _data = this.getStaticData()
    } else {
      let transfield = {}
      config.columns.forEach(col => {
        if (col.field) {
          transfield[col.field] = col.label
        }
      })
      let data = this.getdata()
      if (plot.enabled === 'true') {
        this.customrender(data, transfield)
        return
      }
      const ds = new DataSet()
      const dv = ds.createView().source(data)
      dv.transform({
        type: 'fold',
        fields: [...plot.Yaxis],
        key: 'key', // key字段
        value: _valfield, // value字段
        // retains: [], // 保留字段集,默认为除 fields 以外的所有字段
      })
      if (plot.Xaxis) {
        dv.transform({
          type: 'map',
          callback(row) {
            row.key = transfield[row.key]
            return row
          },
        })
      }
      _data = dv.rows
    }
    const chart = new Chart({
      container: this.state.chartId,
      autoFit: true,
      height: plot.height || 400
    })
    chart.data(_data)
    if (plot.coordinate !== 'polar') {
      chart.scale(plot.Xaxis, {
        range: [0, 1]
      })
    }
    chart.scale(_valfield, {
      nice: true,
      range: [0, 0.93]
    })
    // 坐标轴格式化
    chart.axis(plot.Xaxis, {
      label: {
        formatter: (val) => {
          if (!val || /^\s*$/.test(val)) return val
          let _val = `${val}`
          if (_val.length <= 10) return val
          return _val.substring(0, 7) + '...'
        }
      }
    })
    if (!plot.legend || plot.legend === 'hidden') {
      chart.legend(false)
    } else {
      chart.legend({
        position: plot.legend
      })
    }
    if (plot.tooltip !== 'true') {
      chart.tooltip(false)
    } else {
      chart.tooltip({
        shared: true
      })
    }
    if (plot.transpose === 'true') {
      chart.coordinate().transpose()
    }
    if (plot.coordinate === 'polar') {
      chart.coordinate('polar', {
        innerRadius: 0.1,
        radius: 0.8
      })
    }
    let _chart = chart
      .line()
      .position(`${plot.Xaxis}*${_valfield}`)
      .color(_typefield)
      .shape(plot.shape || 'smooth')
      .tooltip(`${plot.Xaxis}*${_valfield}*${_typefield}`, (name, value, type) => {
        return {
          name: type,
          value: percentFields.includes(type) || ispercent ? value + '%' : value
        }
      })
    if (plot.label === 'true') {
      _chart.label(_valfield)
    }
    if (plot.point === 'true') {
      chart
        .point()
        .position(`${plot.Xaxis}*${_valfield}`)
        .color(_typefield)
        .size(3)
        .shape('circle')
    }
    chart.render()
  }
  /**
   * @description 自定义渲染
   */
  customrender = (data, transfield) => {
    const { plot } = this.props
    const { percentFields } = this.state
    let barfields = []
    let fields = []
    let legends = []
    plot.customs.forEach(item => {
      item.name = transfield[item.field] || item.field
      if (item.axis === 'left') {
        item.index = 0
      } else if (item.axis === 'right') {
        item.index = 1
      } else {
        item.index = 2
      }
      if (item.chartType === 'bar') {
        barfields.push(item.field)
        fields.unshift(item)
      } else {
        fields.push(item)
      }
      legends.push({
        value: item.name,
        name: item.name,
        marker: { symbol: item.chartType === 'bar' ? 'square' : 'hyphen', style: { stroke: item.color,fill: item.color, r: 5, lineWidth: 2 } }
      })
    })
    fields.sort((a, b) => a.index - b.index)
    const ds = new DataSet()
    const dv = ds.createView().source(data)
    dv.transform({
      type: 'map',
      callback(row) {
        fields.forEach(line => {
          row[line.name] = row[line.field]
        })
        return row
      }
    })
    const chart = new Chart({
      container: this.state.chartId,
      autoFit: true,
      height: plot.height || 400
    })
    chart.data(dv.rows)
    if (plot.coordinate !== 'polar' && barfields.length === 0) {
      chart.scale(plot.Xaxis, {
        range: [0, 1]
      })
    } else {
      chart.scale(plot.Xaxis, {
        range: [0.05, 0.95]
      })
    }
    // 坐标轴格式化
    chart.axis(plot.Xaxis, {
      label: {
        formatter: (val) => {
          if (!val || /^\s*$/.test(val)) return val
          let _val = `${val}`
          if (_val.length <= 10) return val
          return _val.substring(0, 7) + '...'
        }
      }
    })
    if (!plot.legend || plot.legend === 'hidden') {
      chart.legend(false)
    } else {
      chart.legend({
        custom: true,
        position: plot.legend,
        items: legends,
      })
    }
    if (plot.tooltip !== 'true') {
      chart.tooltip(false)
    } else {
      chart.tooltip({
        shared: true
      })
    }
    if (plot.transpose === 'true') {
      chart.coordinate().transpose()
    }
    if (plot.coordinate === 'polar') {
      chart.coordinate('polar', {
        innerRadius: 0.1,
        radius: 0.8
      })
    }
    fields.forEach((item, i) => {
      if (i === 0) {
        chart.axis(item.name, {
          grid: {},
          title: {},
          label: {}
        })
      } else if (i === 1 && item.axis !== 'unset') {
        chart.axis(item.name, {
          grid: null,
          title: {},
          label: {}
        })
      } else {
        chart.axis(item.name, {
          grid: null,
          title: null,
          label: null
        })
      }
      if (item.chartType === 'bar') {
        let _chart = chart
          .interval()
          .position(`${plot.Xaxis}*${item.name}`)
          .color(item.color)
          .shape(item.shape)
          .tooltip(`${item.name}`, (value) => {
            return {
              name: item.name,
              value: percentFields.includes(item.name) ? value + '%' : value
            }
          })
        if (item.label === 'true') {
          _chart.label(item.name)
        }
      } else if (item.chartType === 'line') {
        let _chart = chart
          .line()
          .position(`${plot.Xaxis}*${item.name}`)
          .color(item.color)
          .shape(item.shape)
          .tooltip(`${item.name}`, (value) => {
            return {
              name: item.name,
              value: percentFields.includes(item.name) ? value + '%' : value
            }
          })
        if (item.label === 'true') {
          _chart.label(item.name)
        }
        if (plot.point === 'true') {
          chart
            .point()
            .position(`${plot.Xaxis}*${item.name}`)
            .color(item.color)
            .size(3)
            .shape('circle')
        }
      }
    })
    chart.render()
  }
  /**
   * @description 柱状图渲染
   */
  barrender = () => {
    const { plot, config } = this.props
    const { percentFields } = this.state
    let _data = []
    let _valfield = 'value'
    let _typefield = 'key'
    let ispercent = false
    if (plot.datatype === 'statistics') {
      _valfield = plot.InfoValue
      _typefield = plot.InfoType
      if (percentFields.length > 0) {
        ispercent = true
      }
      _data = this.getStaticData()
    } else {
      let transfield = {}
      config.columns.forEach(col => {
        if (col.field) {
          transfield[col.field] = col.label
        }
      })
      let data = this.getdata()
      if (plot.enabled === 'true') {
        this.customrender(data, transfield)
        return
      }
      const ds = new DataSet()
      const dv = ds.createView().source(data)
      dv.transform({
        type: 'fold',
        fields: [...plot.Yaxis],
        key: 'key',
        value: _valfield
      })
      if (plot.Xaxis) {
        dv.transform({
          type: 'map',
          callback(row) {
            row.key = transfield[row.key]
            return row
          },
        })
      }
      _data = dv.rows
    }
    const chart = new Chart({
      container: this.state.chartId,
      autoFit: true,
      height: plot.height || 400
    })
    // dodge is not support linear attribute, please use category attribute! 时间格式
    if (_data[0] && _data[0][plot.Xaxis] && /^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(_data[0][plot.Xaxis])) {
      _data[0][plot.Xaxis] += ' '
    }
    chart.data(_data)
    chart.scale(_valfield, {
      nice: true,
      range: [0, 0.93]
    })
    // 坐标轴格式化
    chart.axis(plot.Xaxis, {
      label: {
        formatter: (val) => {
          if (!val || /^\s*$/.test(val)) return val
          let _val = `${val}`
          if (_val.length <= 10) return val
          return _val.substring(0, 7) + '...'
        }
      }
    })
    if (!plot.legend || plot.legend === 'hidden') {
      chart.legend(false)
    } else {
      chart.legend({
        position: plot.legend
      })
    }
    if (plot.tooltip !== 'true') {
      chart.tooltip(false)
    } else {
      chart.tooltip({
        showMarkers: false,
        shared: true
      })
    }
    if (plot.transpose === 'true') {
      chart.coordinate().transpose()
    }
    if (plot.coordinate === 'polar') {
      chart.coordinate('polar', {
        innerRadius: 0.1,
        radius: 0.8
      })
    }
    if (plot.adjust !== 'stack') {
      let _chart = chart
        .interval()
        .position(`${plot.Xaxis}*${_valfield}`)
        .color(_typefield)
        .adjust([
          {
            type: 'dodge',
            marginRatio: 0
          }
        ])
        .shape(plot.shape || 'rect')
        .tooltip(`${plot.Xaxis}*${_valfield}*${_typefield}`, (name, value, type) => {
          return {
            name: type,
            value: percentFields.includes(type) || ispercent ? value + '%' : value
          }
        })
      if (plot.label === 'true') {
        _chart.label(_valfield)
      }
    } else if (plot.adjust === 'stack') {
      let _chart = chart
        .interval()
        .position(`${plot.Xaxis}*${_valfield}`)
        .color(_typefield)
        .adjust('stack')
        .shape(plot.shape || 'rect')
        .tooltip(`${plot.Xaxis}*${_valfield}*${_typefield}`, (name, value, type) => {
          return {
            name: type,
            value: percentFields.includes(type) || ispercent ? value + '%' : value
          }
        })
      if (plot.label === 'true') {
        _chart.label(_valfield)
      }
    }
    chart.render()
  }
  /**
   * @description 统计图表,统计类型切换
   */
  handleChange = (val) => {
    this.setState({selectFields: val}, () => {
      let _element = document.getElementById(this.state.chartId)
      if (_element) {
        _element.innerHTML = ''
      }
      this.viewrender()
    })
  }
  render() {
    const { plot, loading, config, BID, Tab } = this.props
    const { empty, chartFields, selectFields } = this.state
    return (
      <div className="custom-line-chart-plot-box">
        <searchLine />
        {plot.title ? <p className="chart-title">{plot.title}</p> : null}
        {loading ?
          <div className="loading-mask">
            <div className="ant-spin-blur"></div>
            <Spin />
          </div> : null
        }
        {plot.datatype === 'statistics' && chartFields.length > 0 ? <Select
          mode="multiple"
          showSearch
          showArrow={true}
          value={selectFields}
          onChange={this.handleChange}
          maxTagCount={0}
          maxTagPlaceholder={(option) => <div className="type-label">{option.join('、')}</div>}
        >
          {chartFields.map((item, i) => <Select.Option key={i} value={item}>{item}</Select.Option>)}
        </Select> : null}
        <div className="canvas-wrap">
          <div className={'chart-action ' + (plot.title ? 'with-title' : '')}>
            {config.action.map(item => {
              if (item.OpenType === 'excelOut') {
                return (
                  <ExcelOutButton
                    key={item.uuid}
                    BID={BID}
                    Tab={Tab}
                    btn={item}
                    show="icon"
                    setting={config.setting}
                    getexceloutparam={this.props.getexceloutparam}
                    updateStatus={() => {}}
                  />
                )
              } else {
                return (
                  <ExcelInButton
                    key={item.uuid}
                    BID={BID}
                    Tab={Tab}
                    btn={item}
                    show="icon"
                    setting={config.setting}
                    updateStatus={() => {}}
                  />
                )
              }
            })}
          </div>
          <div className={'canvas' + (empty ? ' empty' : '')} style={{minHeight: plot.height ? plot.height : 400}} id={this.state.chartId}></div>
        </div>
        {empty ? <Empty description={false}/> : null}
      </div>
    )
  }
}
export default LineChart
src/tabviews/custom/components/chart/antv-bar-line/index.scss
New file
@@ -0,0 +1,108 @@
.custom-line-chart-plot-box {
  margin-bottom: 30px;
  .canvas-wrap {
    margin: 0 0px;
    position: relative;
    border-top: 1px solid transparent;
    .chart-action {
      position: absolute;
      top: 2px;
      right: 5px;
      z-index: 1;
    }
    .chart-action.with-title {
      top: 35px;
    }
  }
  .canvas {
    margin: 0;
    border: 1px solid #e8e8e8;
    padding: 25px 15px;
  }
  .canvas.empty {
    div {
      opacity: 0;
    }
  }
  .ant-empty {
    position: absolute;
    top: calc(50% - 34px);
    left: calc(50% - 92px);
    .ant-empty-image {
      height: 60px;
    }
  }
  .loading-mask {
    position: absolute;
    left: 20px;
    top: 0;
    right: 20px;
    bottom: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: justify;
    z-index: 1;
    .ant-spin-blur {
      position: absolute;
      width: 100%;
      height: 100%;
      opacity: 0.5;
      background: #ffffff;
    }
  }
  .chart-title + .loading-mask {
    top: 40px;
  }
  > .ant-select {
    width: 150px;
    float: right;
    position: relative;
    z-index: 1;
    .ant-select-selection {
      min-height: 24px;
      height: 28px;
      li {
        background: unset;
        border: 0;
        width: 99%;
        padding: 0;
        margin-right: 0;
        cursor: pointer;
        .type-label {
          overflow: hidden;
          word-break: break-word;
          white-space: nowrap;
          text-overflow: ellipsis;
        }
      }
      li + li {
        margin-top: 0;
        width: 1%;
        opacity: 0;
      }
    }
  }
  > .ant-select.ant-select-focused {
    .ant-select-selection {
      li {
        width: 50%;
      }
      li + li {
        width: 49%;
        opacity: 1;
      }
    }
  }
  .g2-tooltip-list{
    display: none;
  }
  .g2-tooltip-title + .g2-tooltip-list{
    display: block;
  }
}
src/tabviews/custom/components/chart/antv-bar/index.jsx
File was deleted
src/tabviews/custom/components/chart/antv-bar/index.scss
File was deleted
src/tabviews/custom/components/share/searchLine/index.jsx
New file
@@ -0,0 +1,784 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Row, Col, Input, Button, Select, DatePicker, notification } from 'antd'
import moment from 'moment'
import Api from '@/api'
import options from '@/store/options.js'
import DateGroup from '@/tabviews/zshare/dategroup'
import Utils from '@/utils/utils.js'
import './index.scss'
const {MonthPicker, WeekPicker, RangePicker} = DatePicker
class MainSearch extends Component {
  static propTpyes = {
    BID: PropTypes.any,          // 父级Id,用于查询下拉选择项
    dataManager: PropTypes.any,  // 数据权限
    menuType: PropTypes.any,     // 菜单权限,是否为HS
    searchlist: PropTypes.array, // 搜索条件列表
    dict: PropTypes.object       // 字典项
  }
  state = {
    match: null,            // 搜索条件匹配规则
    style: null,            // 搜索条件类型
    label: null,            // 提示文字
    required: null,         // 是否必填
    searchlist: null,       // 搜索项
    groups: null,           // 组合搜索项
    formId: Utils.getuuid() // 搜索表单Id
  }
  UNSAFE_componentWillMount () {
    let searchlist = fromJS(this.props.searchlist).toJS()
    let match = {}
    let label = {}
    let style = {}
    let required = {}
    let _list = []
    let fieldMap = new Map()
    let mainItems = []  // 云端或单点数据
    let localItems = [] // 本地数据
    let deForms = []    // 测试系统,单个请求
    searchlist.forEach(item => {
      if (fieldMap.has(item.field)) {
        item.field = item.field + '@tail@'
      }
      fieldMap.set(item.field, true)
      match[item.field] = item.match
      label[item.field] = item.label
      style[item.field] = item.type
      required[item.field] = item.required === 'true'
      if (['select', 'link', 'multiselect'].includes(item.type)) {
        if (item.setAll === 'true' && item.type !== 'multiselect') {
          item.options.unshift({
            key: Utils.getuuid(),
            Value: '',
            Text: this.props.dict['main.all']
          })
        }
        // 数据源查询语句
        if (item.resourceType === '1' && item.dataSource) {
          let _option = Utils.getSelectQueryOptions(item)
          if (this.props.dataManager) { // 数据权限
            _option.sql = _option.sql.replace(/\$@/ig, '/*')
            _option.sql = _option.sql.replace(/@\$/ig, '*/')
          } else {
            _option.sql = _option.sql.replace(/@\$|\$@/ig, '')
          }
          // 测试系统单个请求
          if (this.props.menuType !== 'HS' && options.sysType === 'local' && !window.GLOB.systemType) {
            deForms.push({
              ...item,
              arr_field: _option.field,
              data_sql: Utils.formatOptions(_option.sql)
            })
          } else { // 合并请求,区分本地及系统
            if (item.database === 'sso') {
              mainItems.push(`select '${item.field}' as obj_name,'${_option.field}' as arr_field,'${window.btoa(window.encodeURIComponent(_option.sql))}' as LText`)
            } else {
              localItems.push(`select '${item.field}' as obj_name,'${_option.field}' as arr_field,'${window.btoa(window.encodeURIComponent(_option.sql))}' as LText`)
            }
          }
        }
        item.oriOptions = fromJS(item.options).toJS()
      }
      _list.push(item)
    })
    let _groups = []
    _list = _list.map(item => {
      if (item.type === 'link') {
        let supItem = _list.filter(form => form.field === item.linkField)[0]
        if (!supItem) {
          notification.warning({
            top: 92,
            message: '未查询到搜索条件《' + item.label + '》关联字段!',
            duration: 5
          })
          item.supInitVal = ''
        } else {
          item.supInitVal = supItem.initval
          item.options = item.oriOptions.filter(option => option.ParentID === supItem.initval)
        }
      } else if (item.type === 'group' && item.Hide !== 'true') {
        _groups.push(fromJS(item).toJS())
      }
      return item
    })
    this.setState({
      match: match,
      label: label,
      style: style,
      required: required,
      searchlist: _list,
      groups: _groups
    }, () => {
      if (this.props.menuType !== 'HS' && options.sysType === 'local' && !window.GLOB.systemType) {
        this.improveSimpleSearch(deForms)
      } else {
        this.improveSearch(mainItems, localItems)
      }
    })
  }
  // 查询下拉菜单
  improveSearch = (mainItems, localItems) => {
    const { menuType, BID } = this.props
    let deffers = []
    if (menuType !== 'HS' && window.GLOB.systemType !== 'production') {
      localItems = [...localItems, ...mainItems]
      mainItems = []
    }
    // 本地请求
    let param = {
      func: 'sPC_Get_SelectedList',
      LText: localItems.join(' union all '),
      obj_name: '',
      arr_field: '',
      table_type: 'Y'
    }
    if (BID) {
      param.BID = BID
    }
    if (param.LText) {
      param.LText = Utils.formatOptions(param.LText)
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      if (menuType === 'HS') { // 云端数据验证
        param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
      }
      deffers.push(
        new Promise(resolve => {
          Api.getSystemCacheConfig(param).then(res => {
            if (!res.status) {
              notification.warning({
                top: 92,
                message: res.message,
                duration: 5
              })
            }
            resolve(res)
          })
        })
      )
    }
    // 系统请求
    let mainparam = {
      func: 'sPC_Get_SelectedList',
      LText: mainItems.join(' union all '),
      obj_name: '',
      arr_field: '',
      table_type: 'Y'
    }
    if (BID) {
      mainparam.BID = BID
    }
    if (mainparam.LText) {
      mainparam.LText = Utils.formatOptions(mainparam.LText)
      mainparam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      mainparam.secretkey = Utils.encrypt(mainparam.LText, mainparam.timestamp)
      if (menuType === 'HS') { // 云端数据验证
        mainparam.open_key = Utils.encrypt(mainparam.secretkey, mainparam.timestamp, true)
        if (options.cloudServiceApi) {
          mainparam.rduri = options.cloudServiceApi
          mainparam.userid = sessionStorage.getItem('CloudUserID') || ''
          mainparam.LoginUID = sessionStorage.getItem('CloudLoginUID') || ''
        }
      } else if (window.GLOB.mainSystemApi) {
        mainparam.rduri = window.GLOB.mainSystemApi
      }
      deffers.push(
        new Promise(resolve => {
          Api.getSystemCacheConfig(mainparam).then(res => {
            if (!res.status) {
              notification.warning({
                top: 92,
                message: res.message,
                duration: 5
              })
            }
            resolve(res)
          })
        })
      )
    }
    Promise.all(deffers).then(response => {
      let result = {...response[0], ...(response[1] || {})}
      delete result.ErrCode
      delete result.ErrMesg
      delete result.message
      delete result.status
      let _searchlist = this.state.searchlist.map(item => {
        if (['select', 'link', 'multiselect'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
          let options = result[item.field].map(cell => {
            let _item = {
              key: Utils.getuuid(),
              Value: cell[item.valueField],
              Text: cell[item.valueText]
            }
            if (item.type === 'link') {
              _item.ParentID = cell[item.linkField]
            }
            return _item
          })
          item.oriOptions = [...item.oriOptions, ...options]
        }
        return item
      })
      this.setState({
        searchlist: _searchlist.map(item => {
          if (item.type === 'link') {
            if (item.supInitVal) {
              item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal)
            } else {
              item.options = item.oriOptions
            }
          } else if (item.type === 'select' || item.type === 'multiselect') {
            item.options = item.oriOptions
          }
          return item
        })
      })
    })
  }
  // 测试系统单个请求下拉选项
  improveSimpleSearch = (deForms) => {
    if (deForms.length === 0) return
    let deffers = deForms.map(item => {
      let param = {
        func: 'sPC_Get_SelectedList',
        LText: item.data_sql,
        obj_name: item.field,
        arr_field: item.arr_field
      }
      if (this.props.BID) {
        param.BID = this.props.BID
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      return (
        new Promise(resolve => {
          Api.getSystemCacheConfig(param).then(res => {
            if (!res.status) {
              notification.warning({
                top: 92,
                message: res.message,
                duration: 5
              })
            }
            resolve(res)
          })
        })
      )
    })
    Promise.all(deffers).then(response => {
      let result = {}
      response.forEach(res => {
        result = {...result, ...res}
      })
      delete result.ErrCode
      delete result.ErrMesg
      delete result.message
      delete result.status
      let _searchlist = this.state.searchlist.map(item => {
        if (['select', 'link', 'multiselect'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
          let options = result[item.field].map(cell => {
            let _item = {
              key: Utils.getuuid(),
              Value: cell[item.valueField],
              Text: cell[item.valueText]
            }
            if (item.type === 'link') {
              _item.ParentID = cell[item.linkField]
            }
            return _item
          })
          item.oriOptions = [...item.oriOptions, ...options]
        }
        return item
      })
      this.setState({
        searchlist: _searchlist.map(item => {
          if (item.type === 'link') {
            if (item.supInitVal) {
              item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal)
            } else {
              item.options = item.oriOptions
            }
          } else if (item.type === 'select' || item.type === 'multiselect') {
            item.options = item.oriOptions
          }
          return item
        })
      })
    })
  }
  resetform = (formlist, supfields, index, fieldsvalue) => {
    index++
    let subfields = []
    supfields.forEach(supfield => {
      formlist = formlist.map(item => {
        if (item.type === 'link' && item.linkField === supfield.field) {
          item.options = item.oriOptions.filter(option => option.ParentID === supfield.initval)
          item.initval = item.options[0] ? item.options[0].Value : ''
          if (this.props.form.getFieldValue(item.field) !== undefined) {
            fieldsvalue[item.field] = item.initval
          }
          subfields.push(item)
        }
        return item
      })
    })
    if (subfields.length === 0 || index > 6) {
      return formlist
    } else {
      return this.resetform(formlist, subfields, index, fieldsvalue)
    }
  }
  selectChange = (_field, value) => {
    let formlist = fromJS(this.state.searchlist).toJS()
    let subfields = []
    let fieldsvalue = {}
    formlist = formlist.map(item => {
      if (item.type === 'link' && item.linkField === _field.field) {
        item.options = item.oriOptions.filter(option => option.ParentID === value)
        item.initval = item.options[0] ? item.options[0].Value : ''
        if (this.props.form.getFieldValue(item.field) !== undefined) {
          fieldsvalue[item.field] = item.initval
        }
        subfields.push(item)
      }
      return item
    })
    if (subfields.length === 0) {
      this.searchChange()
      return
    }
    formlist = this.resetform(formlist, subfields, 0, fieldsvalue)
    if (Object.keys(fieldsvalue).length > 0) {
      this.props.form.setFieldsValue(fieldsvalue)
    }
    this.setState({
      searchlist: formlist
    }, () => {
      this.searchChange()
    })
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
    const fields = []
    this.state.searchlist.forEach((item, index) => {
      if (item.Hide === 'true') return
      if (item.type === 'text') { // 文本搜索
        fields.push(
          <Col span={item.ratio || 6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: item.initval,
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'select') { // 下拉搜索
        fields.push(
          <Col span={item.ratio || 6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: item.initval,
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Select
                  showSearch
                  onChange={(value) => {this.selectChange(item, value)}}
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  getPopupContainer={() => document.getElementById(this.state.formId)}
                >
                  {item.options.map((option, i) =>
                    <Select.Option id={`${i}`} title={option.Text} key={`${i}`} value={option.Value}>{option.Text}</Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'multiselect') { // 下拉多选
        let _initval = item.initval ? item.initval.split(',').filter(Boolean) : []
        fields.push(
          <Col span={item.ratio || 6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: _initval,
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Select
                  showSearch
                  mode="multiple"
                  onChange={this.searchChange}
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  getPopupContainer={() => document.getElementById(this.state.formId)}
                >
                  {item.options.map((option, i) =>
                    <Select.Option id={`${i}`} title={option.Text} key={`${i}`} value={option.Value}>{option.Text}</Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'date') { // 时间搜索
        fields.push(
          <Col span={item.ratio || 6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: item.initval ? moment().subtract(item.initval, 'days') : null,
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <DatePicker onChange={this.searchChange} getCalendarContainer={() => document.getElementById(this.state.formId)} />
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'datemonth') {
        fields.push(
          <Col span={item.ratio || 6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: item.initval ? moment().subtract(item.initval, 'month') : null,
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <MonthPicker onChange={this.searchChange} getCalendarContainer={() => document.getElementById(this.state.formId)} />
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'dateweek') {
        fields.push(
          <Col span={item.ratio || 6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: item.initval ? moment().subtract(item.initval * 7, 'days') : null,
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <WeekPicker onChange={this.searchChange} getCalendarContainer={() => document.getElementById(this.state.formId)} />
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'daterange') {
        let _defaultValue = [null, null]
        if (item.initval) {
          try {
            let _initval = JSON.parse(item.initval)
            _defaultValue = [moment().subtract(_initval[0], 'days'), moment().subtract(_initval[1], 'days')]
          } catch {
            _defaultValue = [null, null]
          }
        }
        fields.push(
          <Col className="daterange" span={item.ratio || 6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field,
                {
                  initialValue: _defaultValue,
                  rules: [
                    {
                      required: item.required === 'true',
                      message: this.props.dict['form.required.select'] + item.label + '!'
                    }
                  ]
                })(
                <RangePicker
                  placeholder={['开始日期', '结束日期']}
                  renderExtraFooter={() => 'extra footer'}
                  onChange={this.searchChange}
                  getCalendarContainer={() => document.getElementById(this.state.formId)}
                />
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'group') {
        fields.push(
          <Col span={item.ratio || 6} key={index}>
            <Form.Item label={item.label} className={item.required === 'true' ? 'group-required' : ''}>
              <DateGroup ref={item.uuid} position={index} card={item} onGroupChange={this.searchChange} />
            </Form.Item>
          </Col>
        )
      }
    })
    fields.push(
      <Col span={6} style={{ whiteSpace: 'nowrap' }} key="actions">
        <Form.Item label={' '} colon={false} style={{ minHeight: '40px' }}>
          <Button type="primary" htmlType="submit">
            {this.props.dict['main.search']}
          </Button>
          <Button style={{ marginLeft: 8 }} onClick={this.handleReset}>
            {this.props.dict['main.reset']}
          </Button>
        </Form.Item>
      </Col>
    )
    return fields
  }
  addHideFieldValue = (values) => {
    const { searchlist } = this.state
    let hideValue = {}
    searchlist.forEach(item => {
      if (item.Hide === 'true') {
        let value = ''
        if (item.type === 'multiselect') { // 下拉多选
          value = item.initval ? item.initval.split(',').filter(Boolean) : []
        } else if (item.type === 'date') { // 时间搜索
          value = item.initval ? moment().subtract(item.initval, 'days') : ''
        } else if (item.type === 'datemonth') {
          value = item.initval ? moment().subtract(item.initval, 'month') : ''
        } else if (item.type === 'dateweek') {
          value = item.initval ? moment().subtract(item.initval * 7, 'days') : ''
        } else if (item.type === 'daterange') {
          if (item.initval) {
            try {
              let _initval = JSON.parse(item.initval)
              value = [moment().subtract(_initval[0], 'days'), moment().subtract(_initval[1], 'days')]
            } catch {
              value = ''
            }
          }
        } else if (item.type !== 'group') {
          value = item.initval
        }
        hideValue[item.field] = value
      }
    })
    return {...hideValue, ...values}
  }
  handleSearch = (e) => {
    // 回车或点击搜索
    e.preventDefault()
    this.props.form.validateFields((err, values) => {
      if (!err) {
        values = this.addHideFieldValue(values)
        let searches = this.getFieldsValues(values)
        this.props.refreshdata(searches)
      }
    })
  }
  searchChange = () => {
    this.setState({}, () => {
      this.props.form.validateFields((err, values) => {
        if (!err) {
          values = this.addHideFieldValue(values)
          let searches = this.getFieldsValues(values)
          this.props.refreshdata(searches)
        }
      })
    })
  }
  /**
   * @description 搜索条件重置
   */
  handleReset = () => {
    const { groups } = this.state
    if (groups.length > 0) {
      groups.forEach(item => {
        this.refs[item.uuid].reset()
      })
    }
    let searchlist = this.state.searchlist.map(item => {
      item.initval = item.oriInitval
      return item
    })
    this.setState({searchlist}, () => {
      this.props.form.resetFields()
      this.props.form.validateFields((err, values) => {
        if (!err) {
          // 异步获取更新后的时间组
          this.setState({}, () => {
            values = this.addHideFieldValue(values)
            let searches = this.getFieldsValues(values)
            this.props.refreshdata(searches)
          })
        }
      })
    })
  }
  getFieldsValues = (values) => {
    const { groups } = this.state
    // 获取搜索条件值
    let search = []
    Object.keys(values).forEach(key => {
      let _value = ''
      if (this.state.style[key] === 'daterange') {
        if (values[key].length > 0 && values[key][0] && values[key][1]) {
          _value = [moment(values[key][0]).format('YYYY-MM-DD'), moment(values[key][1]).format('YYYY-MM-DD')]
        }
      } else if (this.state.style[key] === 'dateweek') {
        if (values[key]) {
          _value = [moment(values[key]).startOf('week').format('YYYY-MM-DD'), moment(values[key]).endOf('week').format('YYYY-MM-DD')]
        }
      } else if (this.state.style[key] === 'date') {
        if (values[key]) {
          _value = moment(values[key]).format('YYYY-MM-DD')
        }
      } else if (this.state.style[key] === 'datemonth') {
        if (values[key]) {
          _value = moment(values[key]).format('YYYY-MM')
        }
      } else if (this.state.style[key] === 'multiselect') {
        _value = values[key] || []
      } else {
        _value = (values[key] || values[key] === 0) ? values[key] : ''
        _value = _value.replace(/(^\s*|\s*$)/ig, '')
      }
      search.push({
        type: this.state.style[key],
        key: key.replace(/@tail@$/, ''),
        value: _value,
        label: this.state.label[key],
        match: this.state.match[key],
        required: this.state.required[key]
      })
    })
    if (groups.length > 0) {
      groups.forEach(item => {
        let items = this.refs[item.uuid].getSearchItems()
        search.push(...items)
      })
    }
    return search
  }
  render() {
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form top-search" id={this.state.formId} onSubmit={this.handleSearch}>
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/tabviews/custom/components/share/searchLine/index.scss
New file
@@ -0,0 +1,41 @@
.ant-advanced-search-form.top-search {
  padding: 0px 24px 10px;
  border-bottom: 1px solid #efefef;
  .ant-form-item {
    display: flex;
    margin-bottom: 0px;
    min-height: 60px;
    .ant-form-explain {
      white-space: nowrap;
    }
  }
  .ant-form-item-control-wrapper {
    flex: 1;
    width: calc(100% - 100px);
  }
  .ant-form-item-label {
    // width: 100px;
    text-overflow: ellipsis;
  }
  .daterange .ant-calendar-picker-input {
    padding: 4px 20px 4px 5px;
    font-size: 13px;
  }
  .ant-select-dropdown {
    z-index: 10 !important;
  }
  .ant-calendar-picker-container {
    z-index: 10 !important;
  }
  .group-required {
    label::before {
      display: inline-block;
      margin-right: 4px;
      color: #f5222d;
      font-size: 14px;
      font-family: SimSun, sans-serif;
      line-height: 1;
      content: '*';
    }
  }
}
src/tabviews/custom/index.jsx
@@ -2,7 +2,7 @@
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import { is, fromJS } from 'immutable'
import { notification, Spin, Modal, Button, message, Tree, Typography } from 'antd'
import { notification, Spin, Row, Col, Button, message } from 'antd'
import moment from 'moment'
import Api from '@/api'
@@ -13,16 +13,11 @@
import asyncSpinComponent from '@/utils/asyncSpinComponent'
import { refreshTabView } from '@/store/action'
import MainSearch from '@/tabviews/zshare/topSearch'
import NotFount from '@/components/404'
import './index.scss'
// 通用组件
const CalendarComponent = asyncSpinComponent(() => import('@/tabviews/zshare/calendar'))
const SubTabTable = asyncSpinComponent(() => import('@/tabviews/subtabtable'))
const { TreeNode } = Tree
const { Paragraph } = Typography
const AntvBarAndLine = asyncSpinComponent(() => import('./components/chart/antv-bar-line'))
class NormalTable extends Component {
  static propTpyes = {
@@ -39,18 +34,15 @@
    loadingview: true,    // 页面加载中
    viewlost: false,      // 页面丢失:1、未获取到配置-页面丢失;2、页面未启用
    lostmsg: '',          // 页面丢失时的提示信息
    config: {},           // 页面配置信息,包括按钮、搜索、显示列、标签等
    config: null,         // 页面配置信息,包括组件等
    mainSearch: null,
    userConfig: null,     // 用户自定义设置
    searchlist: null,     // 搜索条件
    arr_field: '',        // 使用 sPC_Get_TableData 时的查询字段集
    setting: null,        // 页面全局设置:数据源、按钮及显示列固定、主键等
    data: null,           // 列表数据集
    loading: false,       // 列表数据加载中
    search: '',           // 搜索条件数组,使用时需分场景处理
    visible: false,       // 标签页控制
    triggerTime: '',      // 点击时间
    treevisible: false,   // 菜单结构树弹框显示隐藏控制
    calendarYear: moment().format('YYYY') // 日历年份
  }
  /**
@@ -68,7 +60,6 @@
    if (result.status) {
      let config = ''
      let userConfig = null
      let _curUserConfig = ''
      try { // 配置信息解析
        config = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
@@ -81,7 +72,6 @@
      if (result.LongParamUser && this.props.menuType !== 'HS') {
        try { // 配置信息解析
          userConfig = JSON.parse(window.decodeURIComponent(window.atob(result.LongParamUser)))
          _curUserConfig = userConfig[this.props.MenuID]
        } catch (e) {
          console.warn('Parse Failure')
          userConfig = null
@@ -96,7 +86,7 @@
        })
        return
      }
      // 页面未启用时,显示未启用页面
      if (!config.enabled) {
        this.setState({
@@ -107,62 +97,103 @@
        return
      }
      // 获取主搜索条件
      let mainSearch = []
      config.components.forEach(component => {
        if (component.type === 'search') {
          component.search = component.search.map(item => {
            item.oriInitval = item.initval
            if (['text', 'select', 'link'].includes(item.type) && param) {
              if (param.searchkey === item.field) {
                item.initval = param.searchval
              } else if (param.BID && item.field.toLowerCase() === 'bid') {
                item.initval = param.BID
              } else if (param.data && param.data[item.field]) {
                item.initval = param.data[item.field]
              }
            }
            if (!item.blacklist || item.blacklist.length === 0) return item
            let _black = item.blacklist.filter(v => {
              return this.props.permRoles.indexOf(v) !== -1
            })
            if (_black.length > 0) {
              item.Hide = 'true'
            }
            return item
          })
          mainSearch = Utils.initMainSearch(component.search)
        }
      })
      // 权限过滤
      if (this.props.menuType !== 'HS') {
        if (config.tab && !permAction[config.tab.linkTab]) {
          config.tab = null
        }
        config.components.forEach(component => {
          if (component.action) {
            component.action = component.action.filter(item => permAction[item.uuid])
          }
        })
      }
      if (_curUserConfig) {
        config.setting = {...config.setting, ..._curUserConfig.setting}
        config.easyCode = _curUserConfig.easyCode || config.easyCode || ''
      }
      let params = []
      config.components.forEach(component => {
        let _customScript = ''
        component.scripts && component.scripts.forEach(script => {
          if (script.status !== 'false') {
            _customScript += `
            ${script.sql}
            `
          }
        })
      // 字段权限黑名单、必填、字段透视
      let valid = true
      config.search = config.search.map(item => {
        item.oriInitval = item.initval
        if (['text', 'select', 'link'].includes(item.type) && param) {
          if (param.searchkey === item.field) {
            item.initval = param.searchval
          } else if (param.BID && item.field.toLowerCase() === 'bid') {
            item.initval = param.BID
          } else if (param.data && param.data[item.field]) {
            item.initval = param.data[item.field]
        if (component.setting && component.setting.interType === 'system') { // 使用系统函数
          component.setting.execute = component.setting.execute !== 'false'  // 默认sql是否执行,转为boolean 统一格式
          component.setting.laypage = component.setting.laypage === 'true'   // 是否分页,转为boolean 统一格式
          if (!component.setting.execute) {
            component.setting.dataresource = ''
          }
          if (/\s/.test(component.setting.dataresource)) {
            component.setting.dataresource = '(' + component.setting.dataresource + ') tb'
          }
          if (this.props.dataManager) { // 数据权限
            component.setting.dataresource = component.setting.dataresource.replace(/\$@/ig, '/*')
            component.setting.dataresource = component.setting.dataresource.replace(/@\$/ig, '*/')
            _customScript = _customScript.replace(/\$@/ig, '/*')
            _customScript = _customScript.replace(/@\$/ig, '*/')
          } else {
            component.setting.dataresource = component.setting.dataresource.replace(/@\$|\$@/ig, '')
            _customScript = _customScript.replace(/@\$|\$@/ig, '')
          }
        }
        if (item.required === 'true' && !item.initval) {
          valid = false
        component.customScript = _customScript // 整理后自定义脚本
        // format   数据格式 array 或 object
        // dataName 系统生成的数据源名称
        // laypage  是否分页,组件属性,不分页的组件才可以统一查询
        if (component.format && component.dataName && !component.laypage && component.setting.interType === 'system' && component.setting.onload === 'true' && component.setting.sync === 'true') {
          let param = this.getDefaultParam(component, mainSearch)
          params.push(param)
        } else {
          component.setting.sync = 'false'
        }
        if (!item.blacklist || item.blacklist.length === 0) return item
        let _black = item.blacklist.filter(v => {
          return this.props.permRoles.indexOf(v) !== -1
        })
        if (_black.length > 0) {
          item.Hide = 'true'
        }
        return item
      })
      this.setState({
        BID: param && param.BID ? param.BID : '',
        loadingview: false,
        config: config,
        userConfig: userConfig,
        setting: config.setting,
        searchlist: config.search,
        arr_field: config.columns.map(item => item.field).join(','),
        search: Utils.initMainSearch(config.search) // 搜索条件初始化(含有时间格式,需要转化)
        config,
        mainSearch
      }, () => {
        if (config.setting.onload !== 'false' && valid) { // 初始化可加载
          this.loadmaindata()
        }
        this.loadmaindata(params)
      })
    } else {
      this.setState({
@@ -178,212 +209,139 @@
  }
  /**
   * @description 主表数据加载
   */
  async loadmaindata () {
    const { setting, search, BID } = this.state
    let param = ''
    let requireFields = search.filter(item => item.required && (!item.value || item.value.length === 0))
    if (requireFields.length > 0) {
      let labels = requireFields.map(item => item.label)
      labels = Array.from(new Set(labels))
      notification.warning({
        top: 92,
        message: this.state.dict['form.required.input'] + labels.join('、') + ' !',
        duration: 3
      })
      return
    }
    this.setState({
      loading: true
    })
    if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) {
      param = this.getCustomParam()
    } else {
      param = this.getDefaultParam()
    }
    if (BID) {
      param.BID = BID
    }
    // 数据管理权限
    if (this.props.dataManager) {
      param.dataM = 'Y'
    }
    let result = await Api.genericInterface(param)
    if (result.status) {
      this.setState({
        data: result.data.map((item, index) => {
          item.key = index
          return item
        }),
        loading: false
      })
    } else {
      this.setState({
        loading: false
      })
      notification.error({
        top: 92,
        message: result.message,
        duration: 10
      })
    }
  }
  /**
   * @description 获取用户自定义存储过程传参
   */
  getCustomParam = () => {
    const { search, setting, calendarYear, config } = this.state
    let _search = Utils.formatCustomMainSearch(search)
    let param = {
      ..._search
    }
    if (config.calendar.refresh === 'true') {
      param.calendarDate = calendarYear
    }
    if (setting.interType === 'inner') {
      param.func = setting.innerFunc
    } else {
      if (this.props.menuType === 'HS') {
        if (setting.sysInterface === 'true' && options.cloudServiceApi) {
          param.rduri = options.cloudServiceApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      } else {
        if (setting.sysInterface === 'true' && window.GLOB.mainSystemApi) {
          param.rduri = window.GLOB.mainSystemApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      }
      if (setting.outerFunc) {
        param.func = setting.outerFunc
      }
    }
    return param
  }
  /**
   * @description 获取系统存储过程 sPC_Get_TableData 的参数
   */
  getDefaultParam = () => {
    const { arr_field, search, setting, config, calendarYear } = this.state
    let _search = Utils.joinMainSearchkey(search)
    _search = _search ? 'where ' + _search : ''
  getDefaultParam = (component, mainSearch) => {
    const { columns, search, setting, dataName, format, customScript } = component
    
    let param = {
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      arr_field: arr_field,
      custom_script: setting.customScript || '',
      default_sql: setting.default || 'true'
    let searchlist = []
    if (search && search.length > 0) {
      searchlist = Utils.initMainSearch(search)
    }
    if (setting.useMSearch === 'true') {
      searchlist = [...mainSearch, ...searchlist]
    }
    let arr_field = columns.map(col => col.field)
    let _dataresource = setting.dataresource
    let _customScript = customScript
    if (/\s/.test(_dataresource)) {
      _dataresource = '(' + _dataresource + ') tb'
    }
    if (this.props.dataManager) { // 数据权限
      _dataresource = _dataresource.replace(/\$@/ig, '/*')
      _dataresource = _dataresource.replace(/@\$/ig, '*/')
      param.custom_script = param.custom_script.replace(/\$@/ig, '/*')
      param.custom_script = param.custom_script.replace(/@\$/ig, '*/')
    } else {
      _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
      param.custom_script = param.custom_script.replace(/@\$|\$@/ig, '')
    }
    let regoptions = null
    if (setting.queryType === 'statistics' || param.custom_script) {
      let allSearch = Utils.getAllSearchOptions(search)
      regoptions = allSearch.map(item => {
    if (setting.queryType === 'statistics' || _customScript) {
      let allSearch = Utils.getAllSearchOptions(searchlist)
      let regoptions = allSearch.map(item => {
        return {
          reg: new RegExp('@' + item.key + '@', 'ig'),
          value: `'${item.value}'`
        }
      })
    }
    if (config.calendar.refresh === 'true' && regoptions) {
      regoptions.push({
        reg: new RegExp('@calendarDate@', 'ig'),
        value: `${calendarYear}-01-01 00:00:00.000`
      })
      regoptions.push({
        reg: new RegExp('@calendarDate1@', 'ig'),
        value: `${calendarYear}-12-31 23:59:59.999`
      })
    }
    if (setting.queryType === 'statistics' && setting.default !== 'false') { // 统计数据源,内容替换
      regoptions.forEach(item => {
        _dataresource = _dataresource.replace(item.reg, item.value)
        if (_dataresource && setting.queryType === 'statistics') {
          _dataresource = _dataresource.replace(item.reg, item.value)
        }
        if (_customScript) {
          _customScript = _customScript.replace(item.reg, item.value)
        }
      })
      _search = ''
    }
    let LText = ''
    if (setting.default !== 'false') {
      LText = `select ${arr_field} from ${_dataresource} ${_search}`
    let _search = ''
    if (setting.queryType !== 'statistics' && _dataresource) {
      _search = Utils.joinMainSearchkey(searchlist)
      _search = _search ? 'where ' + _search : ''
    }
    if (param.custom_script) {
      regoptions.forEach(item => {
        param.custom_script = param.custom_script.replace(item.reg, item.value)
      })
      if (LText) {
        LText += `
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      } else {
        param.custom_script += `
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      }
    if (setting.order && _dataresource) {
      _dataresource = `select top 1000 ${arr_field.join(',')} from (select ${arr_field.join(',')} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
    } else if (_dataresource) {
      _dataresource = `select top 1000 ${arr_field.join(',')} from ${_dataresource} ${_search} `
    }
    // 测试系统打印查询语句
    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
      param.custom_script &&  console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${param.custom_script}`)
      LText &&  console.log(LText)
      _customScript &&  console.log(`${_dataresource ? '' : '/*不执行默认sql*/\n'}${_customScript}`)
      _dataresource &&  console.log(_dataresource)
    }
    return {
      name: dataName,
      columns: columns,
      par_tablename: '',
      type: format === 'array' ? format : '',
      primaryKey: setting.primaryKey || '',
      foreign_key: '',
      sql: _dataresource,
      script: _customScript
    }
  }
  /**
   * @description 主表数据加载
   */
  loadmaindata = (params) => {
    let LText_field = []
    let LText = params.map((item, index) => {
      let _sql = item.sql
      let _script = item.script
      // if (index === 0) {
      //   _script = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000) select @ErrorCode='',@retmsg =''
      //     ${_script}
      //   `
      // }
      // if (params.length === index + 1) {
      //   _sql = `${_sql}
      //     aaa:
      //       if @ErrorCode!=''
      //       begin
      //         insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
      //         goto bbb
      //       end
      //   `
      // }
      item.columns.forEach(cell => {
        LText_field.push(`Select '${item.name}' as tablename,'${cell.field}' as fieldname,'${cell.datatype}' as field_type`)
      })
      return `Select '${item.name}' as tablename,'${window.btoa(window.encodeURIComponent(_sql))}' as LText,'${window.btoa(window.encodeURIComponent(_script))}' as Lcustomize,'${item.type}' as table_type,'${item.primaryKey}' as primary_key,'${item.par_tablename}' as par_tablename,'${item.foreign_key}' as foreign_key,'${index}' as Sort`
      // return `Select '${item.name}' as tablename,'${_sql}' as LText,'${_script}' as Lcustomize,'${item.type}' as table_type,'${item.primaryKey}' as primary_key,'${item.par_tablename}' as par_tablename,'${item.foreign_key}' as foreign_key,'${index}' as Sort`
    })
    let param = {
      func: 'sPC_Get_structured_data',
      LText: LText.join(' union all '),
      LText_field: LText_field.join(' union all ')
    }
    
    param.custom_script = Utils.formatOptions(param.custom_script)
    param.LText = Utils.formatOptions(LText)
    param.LText = Utils.formatOptions(param.LText)
    param.LText_field = Utils.formatOptions(param.LText_field)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.DateCount = ''
    if (this.props.menuType === 'HS') { // 云端数据验证
      param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
    }
    Api.getLocalConfig(param).then(result => {
      if (result.status) {
        delete result.status
        delete result.message
        delete result.ErrMesg
        delete result.ErrCode
    return param
        this.setState({
          data: result,
          loading: false
        })
      } else {
        this.setState({
          data: '',
          loading: false
        })
        notification.error({
          top: 92,
          message: result.message,
          duration: 10
        })
      }
    })
  }
  /**
@@ -391,22 +349,9 @@
   * 含有初始不加载的页面,修改设置
   */
  refreshbysearch = (searches) => {
    const { setting } = this.state
    if (setting.onload === 'false') {
      this.setState({
        search: searches,
        setting: {...setting, onload: 'true'}
      }, () => {
        this.loadmaindata()
      })
    } else {
      this.setState({
        search: searches
      }, () => {
        this.loadmaindata()
      })
    }
    this.setState({
      mainSearch: searches
    })
  }
@@ -441,44 +386,6 @@
    }
  }
  getTreeNode = (data) => {
    let _type = {
      view: '页面',
      btn: '按钮',
      tab: '标签'
    }
    return data.map(item => {
      let _title = _type[item.subtype]
      let _others = []
      _others.push(
        (item.menuNo ? item.menuNo + '(菜单参数)' : ''),
        (item.tableName ? item.tableName + '(表名) ' : ''),
        (item.innerFunc ? item.innerFunc + '(内部函数) ' : ''),
        (item.outerFunc ? item.outerFunc + '(外部函数)' : '')
      )
      _others = _others.filter(Boolean)
      _others = _others.join('、')
      if (item.label) {
        _title = _title + '(' + item.label + ')'
      }
      if (_others) {
        _title = _title + ': ' + _others
      }
      if (item.subfuncs && item.subfuncs.length > 0) {
        return (
          <TreeNode title={_title} key={item.uuid} dataRef={item} selectable={false}>
            {this.getTreeNode(item.subfuncs)}
          </TreeNode>
        )
      }
      return <TreeNode key={item.uuid} title={_title} isLeaf selectable={false} />
    })
  }
  UNSAFE_componentWillMount () {
    // 组件加载时,获取菜单数据
    this.loadconfig()
@@ -486,20 +393,10 @@
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (nextProps.refreshTab && nextProps.refreshTab.MenuID === this.props.MenuID) {
      if (nextProps.refreshTab.position === 'grid') {
        this.loadmaindata()
      } else if (nextProps.refreshTab.position === 'view') {
      if (nextProps.refreshTab.position === 'view') {
        this.reloadview()
      }
      this.props.refreshTabView('')
    } else if (nextProps.param && !is(fromJS(this.props.param), fromJS(nextProps.param))) {
      let search = this.state.search.map(item => {
        if (item.type === 'text' && item.key === nextProps.param.searchkey) {
          item.value = nextProps.param.searchval
        }
        return item
      })
      this.refreshbysearch(search)
    }
  }
@@ -516,94 +413,39 @@
    }
  }
  changeDate = (value) => {
    this.setState({calendarYear: value}, () => {
      this.loadmaindata()
  getComponents = () => {
    const { menuType, dataManager } = this.props
    const { config, BID, data, mainSearch } = this.state
    if (!config || !config.components) return
    return config.components.map(item => {
      if (item.type === 'bar' || item.type === 'line') {
        return (
          <Col key={item.uuid}>
            <AntvBarAndLine config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
          </Col>
        )
      } else {
        return null
      }
    })
  }
  triggerDate = (item) => {
    const { config } = this.state
    if (!config.tab) return
    this.setState({
      visible: true,
      triggerTime: item.time.substr(0, 4) + '-' + item.time.substr(4, 2) + '-' + item.time.substr(6, 2)
    })
  }
  closeTab = () => {
    this.setState({
      visible: false,
      triggerTime: ''
    })
  }
  render() {
    const { BID, searchlist, loadingview, viewlost, config, loading, data, triggerTime } = this.state
    const { loadingview, viewlost } = this.state
    return (
      <div className="calendar-page" id={this.state.ContainerId}>
        {loadingview && <Spin size="large" />}
        {searchlist && searchlist.length > 0 ?
          <MainSearch
            BID={BID}
            dict={this.state.dict}
            searchlist={searchlist}
            menuType={this.props.menuType}
            dataManager={this.props.dataManager}
            refreshdata={this.refreshbysearch}
          /> : null
        }
        {config && config.calendar ? <CalendarComponent calendar={config.calendar} loading={loading} data={data} triggerDate={this.triggerDate} changeDate={this.changeDate}/> : null}
        <Row>{this.getComponents()}</Row>
        {options.sysType !== 'cloud' ? <Button
          icon="copy"
          shape="circle"
          className="common-table-copy"
          onClick={this.handleviewconfig}
        /> : null}
        <Modal
          className="menu-tree-modal"
          title={'菜单结构树'}
          width={'650px'}
          maskClosable={false}
          visible={this.state.treevisible}
          onCancel={() => this.setState({treevisible: false})}
          footer={[
            <Button key="close" onClick={() => this.setState({treevisible: false})}>{this.state.dict['main.close']}</Button>
          ]}
          destroyOnClose
        >
          <div className="menu-header">
            <span>菜单名称:{this.props.MenuName}</span>
            <span>菜单参数:{<Paragraph copyable>{this.props.MenuNo}</Paragraph>}</span>
          </div>
          {this.state.treevisible ? <Tree defaultExpandAll showLine={true}>
            {this.getTreeNode(config.funcs)}
          </Tree> : null}
        </Modal>
        <Modal
          title={config.tab ? config.tab.label : ''}
          width={'80vw'}
          maskClosable={false}
          visible={this.state.visible}
          onCancel={this.closeTab}
          footer={[
            <Button key="close" onClick={this.closeTab}>{this.state.dict['main.close']}</Button>
          ]}
          destroyOnClose
        >
          {config.tab ? <SubTabTable
            type="calendar"
            BID={triggerTime}
            Tab={config.tab}
            SupMenuID={this.props.MenuID}
            MenuID={config.tab.linkTab}
            refreshSupView={() => this.loadmaindata()}
            closeModalView={this.closeTab}
          /> : null}
        </Modal>
        {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
      </div>
    )
src/tabviews/subtable/index.jsx
@@ -3,13 +3,12 @@
import {connect} from 'react-redux'
import { is, fromJS } from 'immutable'
import { notification, Spin, Switch, Row, Col, Icon, Tabs} from 'antd'
import moment from 'moment'
import Api from '@/api'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import Utils from '@/utils/utils.js'
import options from '@/store/options.js'
import UtilsDM from '@/utils/utils-datamanage.js'
import { modifyTabview } from '@/store/action'
import SubSearch from '@/tabviews/zshare/topSearch'
@@ -346,6 +345,29 @@
      }
      config.setting.tabType = 'sub'
      // 数据源信息预处理
      config.setting.laypage = config.setting.laypage !== 'false'     // 是否分页,转为boolean 统一格式
      config.setting.execute = config.setting.default !== 'false'     // 默认sql是否执行,转为boolean 统一格式
      config.setting.customScript = config.setting.customScript || '' // 自定义脚本
      if (!config.setting.execute) { // 默认sql 不执行时 置空
        config.setting.dataresource = ''
      } else {
        config.setting.dataresource = config.setting.dataresource || ''
      }
      if (/\s/.test(config.setting.dataresource)) {
        config.setting.dataresource = '(' + config.setting.dataresource + ') tb'
      }
      if (this.props.dataManager) { // 数据权限
        config.setting.dataresource = config.setting.dataresource.replace(/\$@/ig, '/*')
        config.setting.dataresource = config.setting.dataresource.replace(/@\$/ig, '*/')
        config.setting.customScript = config.setting.customScript.replace(/\$@/ig, '/*')
        config.setting.customScript = config.setting.customScript.replace(/@\$/ig, '*/')
      } else {
        config.setting.dataresource = config.setting.dataresource.replace(/@\$|\$@/ig, '')
        config.setting.customScript = config.setting.customScript.replace(/@\$|\$@/ig, '')
      }
      this.setState({
        loadingview: false,
@@ -382,9 +404,14 @@
   * @description 子表数据加载
   */
  async loadmaindata (bid, type) {
    const { setting, search } = this.state
    let param = ''
    const { mainSearch } = this.props
    const { setting, arr_field, search, orderBy, pageIndex, pageSize } = this.state
    let _BID = this.props.BID
    let searches = fromJS(search).toJS()
    if (mainSearch && mainSearch.length > 0) { // 主表搜索条件
      searches = [...mainSearch, ...searches]
    }
    let requireFields = search.filter(item => item.required && (!item.value || item.value.length === 0))
    let prex = this.props.Tab && this.props.Tab.label ? this.props.Tab.label + '-' : ''
@@ -401,33 +428,23 @@
      return
    }
    this.setState({
      loading: true
    })
    if (type === 'refresh') {
      _BID = bid
      if (!bid) { // 主表ID不存在时,不查询子表
        this.setState({
          data: [],
          total: 0,
          loading: false
          total: 0
        })
        return
      } else {
        _BID = bid
      }
    }
    this.setState({
      loading: true
    })
    if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) {
      param = this.getCustomParam(_BID)
    } else {
      param = this.getDefaultParam(_BID)
    }
    // 数据管理权限
    if (this.props.dataManager) {
      param.dataM = 'Y'
    }
    let _orderBy = orderBy || setting.order
    let param = UtilsDM.getQueryDataParams(setting, setting.customScript, arr_field, searches, _orderBy, pageIndex, pageSize, _BID, this.props.menuType, this.props.dataManager)
    this.handleTableId()
@@ -453,180 +470,6 @@
        duration: 10
      })
    }
  }
  /**
   * @description 获取用户自定义存储过程传参
   */
  getCustomParam = (BID) => {
    const { mainSearch } = this.props
    const { pageIndex, pageSize, orderBy, search, setting } = this.state
    let searches = search
    if (mainSearch && mainSearch.length > 0) { // 主表搜索条件
      searches = [...mainSearch, ...search]
    }
    let _search = Utils.formatCustomMainSearch(searches)
    let param = {
      OrderCol: orderBy || setting.order,
      BID: BID,
      ..._search
    }
    if (setting.laypage !== 'false') {
      param.PageIndex = pageIndex
      param.PageSize = pageSize
    }
    if (setting.interType === 'inner') {
      param.func = setting.innerFunc
    } else {
      if (this.props.menuType === 'HS') {
        if (setting.sysInterface === 'true' && options.cloudServiceApi) {
          param.rduri = options.cloudServiceApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      } else {
        if (setting.sysInterface === 'true' && window.GLOB.mainSystemApi) {
          param.rduri = window.GLOB.mainSystemApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      }
      if (setting.outerFunc) {
        param.func = setting.outerFunc
      }
    }
    return param
  }
  /**
   * @description 获取系统存储过程 sPC_Get_TableData 的参数
   */
  getDefaultParam = (BID) => {
    const { mainSearch } = this.props
    const { arr_field, pageIndex, pageSize, orderBy, search, setting } = this.state
    let searches = search
    if (mainSearch && mainSearch.length > 0) { // 主表搜索条件
      searches = [...mainSearch, ...search]
    }
    let _search = Utils.joinMainSearchkey(searches)
    _search = _search ? 'where ' + _search : ''
    let param = {
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      arr_field: arr_field,
      BID: BID,
      custom_script: setting.customScript || '',
      default_sql: setting.default || 'true'
    }
    let _orderBy = orderBy || setting.order
    let _dataresource = setting.dataresource
    if (/\s/.test(_dataresource)) {
      _dataresource = '(' + _dataresource + ') tb'
    }
    if (this.props.dataManager) { // 数据权限
      _dataresource = _dataresource.replace(/\$@/ig, '/*')
      _dataresource = _dataresource.replace(/@\$/ig, '*/')
      param.custom_script = param.custom_script.replace(/\$@/ig, '/*')
      param.custom_script = param.custom_script.replace(/@\$/ig, '*/')
    } else {
      _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
      param.custom_script = param.custom_script.replace(/@\$|\$@/ig, '')
    }
    let regoptions = null
    if (setting.queryType === 'statistics' || param.custom_script) {
      let allSearch = Utils.getAllSearchOptions(searches)
      regoptions = allSearch.map(item => {
        return {
          reg: new RegExp('@' + item.key + '@', 'ig'),
          value: `'${item.value}'`
        }
      })
    }
    if (setting.queryType === 'statistics' && setting.default !== 'false') { // 统计数据源,内容替换
      regoptions.forEach(item => {
        _dataresource = _dataresource.replace(item.reg, item.value)
      })
      _search = ''
    }
    let LText = ''
    let DateCount = ''
    if (setting.default !== 'false' && setting.laypage !== 'false') {
      LText = ` select top ${pageSize} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from ${_dataresource} ${_search}) tmptable where rows > ${pageSize * (pageIndex - 1)} order by tmptable.rows `
      DateCount = `select count(1) as total from ${_dataresource} ${_search}`
    } else if (setting.default !== 'false') {
      LText = ` select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
      DateCount = ''
    }
    if (param.custom_script) {
      regoptions.push({
        reg: new RegExp('@orderBy@', 'ig'),
        value: _orderBy
      })
      if (setting.laypage !== 'false') {
        regoptions.push({
          reg: new RegExp('@pageSize@', 'ig'),
          value: pageSize
        }, {
          reg: new RegExp('@pageIndex@', 'ig'),
          value: pageIndex
        })
      }
      regoptions.forEach(item => {
        param.custom_script = param.custom_script.replace(item.reg, item.value)
      })
      if (LText) {
        LText += `
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      } else {
        param.custom_script += `
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      }
    }
    // 测试系统打印查询语句
    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
      param.custom_script &&  console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${param.custom_script}`)
      LText &&  console.log(LText)
    }
    param.custom_script = Utils.formatOptions(param.custom_script)
    param.LText = Utils.formatOptions(LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.DateCount = Utils.formatOptions(DateCount)
    if (this.props.menuType === 'HS') { // 云端数据验证
      param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
    }
    return param
  }
  /**
src/tabviews/subtabtable/index.jsx
@@ -3,13 +3,12 @@
import {connect} from 'react-redux'
import { is, fromJS } from 'immutable'
import { notification, Spin, Col, Row, Icon, Tabs} from 'antd'
import moment from 'moment'
import Api from '@/api'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import Utils from '@/utils/utils.js'
import options from '@/store/options.js'
import UtilsDM from '@/utils/utils-datamanage.js'
import asyncComponent from '@/utils/asyncComponent'
import asyncSpinComponent from '@/utils/asyncSpinComponent'
@@ -269,6 +268,29 @@
      })
      config.setting.tabType = 'subtab'
      // 数据源信息预处理
      config.setting.laypage = config.setting.laypage !== 'false'     // 是否分页,转为boolean 统一格式
      config.setting.execute = config.setting.default !== 'false'     // 默认sql是否执行,转为boolean 统一格式
      config.setting.customScript = config.setting.customScript || '' // 自定义脚本
      if (!config.setting.execute) { // 默认sql 不执行时 置空
        config.setting.dataresource = ''
      } else {
        config.setting.dataresource = config.setting.dataresource || ''
      }
      if (/\s/.test(config.setting.dataresource)) {
        config.setting.dataresource = '(' + config.setting.dataresource + ') tb'
      }
      if (this.props.dataManager) { // 数据权限
        config.setting.dataresource = config.setting.dataresource.replace(/\$@/ig, '/*')
        config.setting.dataresource = config.setting.dataresource.replace(/@\$/ig, '*/')
        config.setting.customScript = config.setting.customScript.replace(/\$@/ig, '/*')
        config.setting.customScript = config.setting.customScript.replace(/@\$/ig, '*/')
      } else {
        config.setting.dataresource = config.setting.dataresource.replace(/@\$|\$@/ig, '')
        config.setting.customScript = config.setting.customScript.replace(/@\$|\$@/ig, '')
      }
      this.setState({
        loadingview: false,
@@ -303,8 +325,13 @@
   * @description 子表数据加载
   */
  async loadmaindata () {
    const { setting, search } = this.state
    let param = ''
    const { mainSearch, BID } = this.props
    const { setting, arr_field, search, orderBy, pageIndex, pageSize } = this.state
    let searches = fromJS(search).toJS()
    if (mainSearch && mainSearch.length > 0) { // 主表搜索条件
      searches = [...mainSearch, ...searches]
    }
    let requireFields = search.filter(item => item.required && (!item.value || item.value.length === 0))
@@ -324,16 +351,8 @@
      loading: true
    })
    if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) {
      param = this.getCustomParam()
    } else {
      param = this.getDefaultParam()
    }
    // 数据管理权限
    if (this.props.dataManager) {
      param.dataM = 'Y'
    }
    let _orderBy = orderBy || setting.order
    let param = UtilsDM.getQueryDataParams(setting, setting.customScript, arr_field, searches, _orderBy, pageIndex, pageSize, BID, this.props.menuType, this.props.dataManager)
    let result = await Api.genericInterface(param)
    if (result.status) {
@@ -355,179 +374,6 @@
        duration: 10
      })
    }
  }
  /**
   * @description 获取用户自定义存储过程传参
   */
  getCustomParam = () => {
    const { mainSearch } = this.props
    const { pageIndex, pageSize, orderBy, search, setting } = this.state
    let searches = search
    if (mainSearch && mainSearch.length > 0) { // 主表搜索条件
      searches = [...mainSearch, ...search]
    }
    let _search = Utils.formatCustomMainSearch(searches)
    let param = {
      OrderCol: orderBy || setting.order,
      ..._search
    }
    if (setting.laypage !== 'false') {
      param.PageIndex = pageIndex
      param.PageSize = pageSize
    }
    if (setting.interType === 'inner') {
      param.func = setting.innerFunc
    } else {
      if (this.props.menuType === 'HS') {
        if (setting.sysInterface === 'true' && options.cloudServiceApi) {
          param.rduri = options.cloudServiceApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      } else {
        if (setting.sysInterface === 'true' && window.GLOB.mainSystemApi) {
          param.rduri = window.GLOB.mainSystemApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      }
      if (setting.outerFunc) {
        param.func = setting.outerFunc
      }
    }
    return param
  }
  /**
   * @description 获取系统存储过程 sPC_Get_TableData 的参数
   */
  getDefaultParam = () => {
    const { mainSearch } = this.props
    const { arr_field, pageIndex, pageSize, orderBy, search, setting } = this.state
    let searches = search
    if (mainSearch && mainSearch.length > 0) { // 主表搜索条件
      searches = [...mainSearch, ...search]
    }
    let _search = Utils.joinMainSearchkey(searches)
    _search = _search ? 'where ' + _search : ''
    let param = {
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      arr_field: arr_field,
      BID: this.props.BID,
      custom_script: setting.customScript || '',
      default_sql: setting.default || 'true'
    }
    let _orderBy = orderBy || setting.order
    let _dataresource = setting.dataresource
    if (/\s/.test(_dataresource)) {
      _dataresource = '(' + _dataresource + ') tb'
    }
    if (this.props.dataManager) { // 数据权限
      _dataresource = _dataresource.replace(/\$@/ig, '/*')
      _dataresource = _dataresource.replace(/@\$/ig, '*/')
      param.custom_script = param.custom_script.replace(/\$@/ig, '/*')
      param.custom_script = param.custom_script.replace(/@\$/ig, '*/')
    } else {
      _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
      param.custom_script = param.custom_script.replace(/@\$|\$@/ig, '')
    }
    let regoptions = null
    if (setting.queryType === 'statistics' || param.custom_script) {
      let allSearch = Utils.getAllSearchOptions(searches)
      regoptions = allSearch.map(item => {
        return {
          reg: new RegExp('@' + item.key + '@', 'ig'),
          value: `'${item.value}'`
        }
      })
    }
    if (setting.queryType === 'statistics' && setting.default !== 'false') { // 统计数据源,内容替换
      regoptions.forEach(item => {
        _dataresource = _dataresource.replace(item.reg, item.value)
      })
      _search = ''
    }
    let LText = ''
    let DateCount = ''
    if (setting.default !== 'false' && setting.laypage !== 'false') {
      LText = ` select top ${pageSize} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from ${_dataresource} ${_search}) tmptable where rows > ${pageSize * (pageIndex - 1)} order by tmptable.rows `
      DateCount = `select count(1) as total from ${_dataresource} ${_search}`
    } else if (setting.default !== 'false') {
      LText = ` select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
      DateCount = ''
    }
    if (param.custom_script) {
      regoptions.push({
        reg: new RegExp('@orderBy@', 'ig'),
        value: _orderBy
      })
      if (setting.laypage !== 'false') {
        regoptions.push({
          reg: new RegExp('@pageSize@', 'ig'),
          value: pageSize
        }, {
          reg: new RegExp('@pageIndex@', 'ig'),
          value: pageIndex
        })
      }
      regoptions.forEach(item => {
        param.custom_script = param.custom_script.replace(item.reg, item.value)
      })
      if (LText) {
        LText += `
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      } else {
        param.custom_script += `
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      }
    }
    // 测试系统打印查询语句
    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
      param.custom_script &&  console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${param.custom_script}`)
      LText &&  console.log(LText)
    }
    param.custom_script = Utils.formatOptions(param.custom_script)
    param.LText = Utils.formatOptions(LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.DateCount = Utils.formatOptions(DateCount)
    if (this.props.menuType === 'HS') { // 云端数据验证
      param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
    }
    return param
  }
  /**
src/tabviews/treepage/index.jsx
@@ -3,13 +3,13 @@
import {connect} from 'react-redux'
import { is, fromJS } from 'immutable'
import { notification, Spin, Tabs, Icon, Modal, Button, message, Tree, Typography, Row, Col, Card, Input, Empty } from 'antd'
import moment from 'moment'
import Api from '@/api'
import options from '@/store/options.js'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import Utils from '@/utils/utils.js'
import UtilsDM from '@/utils/utils-datamanage.js'
import asyncComponent from '@/utils/asyncComponent'
import asyncSpinComponent from '@/utils/asyncSpinComponent'
import {refreshTabView, modifyTabview} from '@/store/action'
@@ -141,6 +141,30 @@
        }
      })
      // 数据源信息预处理
      config.setting.laypage = false                                  // 是否分页,转为boolean 统一格式
      config.setting.execute = config.setting.default !== 'false'     // 默认sql是否执行,转为boolean 统一格式
      config.setting.customScript = config.setting.customScript || '' // 自定义脚本
      if (!config.setting.execute) { // 默认sql 不执行时 置空
        config.setting.dataresource = ''
      } else {
        config.setting.dataresource = config.setting.dataresource || ''
      }
      if (/\s/.test(config.setting.dataresource)) {
        config.setting.dataresource = '(' + config.setting.dataresource + ') tb'
      }
      if (this.props.dataManager) { // 数据权限
        config.setting.dataresource = config.setting.dataresource.replace(/\$@/ig, '/*')
        config.setting.dataresource = config.setting.dataresource.replace(/@\$/ig, '*/')
        config.setting.customScript = config.setting.customScript.replace(/\$@/ig, '/*')
        config.setting.customScript = config.setting.customScript.replace(/@\$/ig, '*/')
      } else {
        config.setting.dataresource = config.setting.dataresource.replace(/@\$|\$@/ig, '')
        config.setting.customScript = config.setting.customScript.replace(/@\$|\$@/ig, '')
      }
      this.setState({
        BID: param && param.BID ? param.BID : '',
        loadingview: false,
@@ -247,26 +271,13 @@
   */ 
  async loadmaindata () {
    const { setting, searchKey, BID } = this.state
    let param = ''
    this.setState({
      loading: true
    })
    if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) {
      param = this.getCustomParam()
    } else {
      param = this.getDefaultParam()
    }
    if (BID) {
      param.BID = BID
    }
    // 数据管理权限
    if (this.props.dataManager) {
      param.dataM = 'Y'
    }
    let arr_field = `${setting.valueField},${setting.labelField},${setting.parentField}`
    let param = UtilsDM.getQueryDataParams(setting, setting.customScript, arr_field, [], setting.order, '', '', BID, this.props.menuType, this.props.dataManager)
    let result = await Api.genericInterface(param)
    if (result.status) {
@@ -445,116 +456,6 @@
        selectedKeys: [_data.key]
      })
    }
  }
  /**
   * @description 获取用户自定义存储过程传参
   */
  getCustomParam = () => {
    const { setting } = this.state
    let param = {
      OrderCol: setting.order
    }
    if (setting.interType === 'inner') {
      param.func = setting.innerFunc
    } else {
      if (this.props.menuType === 'HS') {
        if (setting.sysInterface === 'true' && options.cloudServiceApi) {
          param.rduri = options.cloudServiceApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      } else {
        if (setting.sysInterface === 'true' && window.GLOB.mainSystemApi) {
          param.rduri = window.GLOB.mainSystemApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      }
      if (setting.outerFunc) {
        param.func = setting.outerFunc
      }
    }
    return param
  }
  /**
   * @description 获取系统存储过程 sPC_Get_TableData 的参数
   */
  getDefaultParam = () => {
    const { setting } = this.state
    let arr_field = `${setting.valueField},${setting.labelField},${setting.parentField}`
    let param = {
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      arr_field: arr_field,
      custom_script: setting.customScript || '',
      default_sql: setting.default || 'true'
    }
    let _dataresource = setting.dataresource
    if (/\s/.test(_dataresource)) {
      _dataresource = '(' + _dataresource + ') tb'
    }
    if (this.props.dataManager) { // 数据权限
      _dataresource = _dataresource.replace(/\$@/ig, '/*')
      _dataresource = _dataresource.replace(/@\$/ig, '*/')
      param.custom_script = param.custom_script.replace(/\$@/ig, '/*')
      param.custom_script = param.custom_script.replace(/@\$/ig, '*/')
    } else {
      _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
      param.custom_script = param.custom_script.replace(/@\$|\$@/ig, '')
    }
    let LText = ''
    if (setting.default !== 'false') {
      LText = ` select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource}) tmptable order by tmptable.rows `
    }
    if (param.custom_script) {
      param.custom_script = param.custom_script.replace(/@orderBy@/ig, setting.order)
      if (LText) {
        LText += `
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      } else {
        param.custom_script += `
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      }
    }
    // 测试系统打印查询语句
    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
      param.custom_script &&  console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${param.custom_script}`)
      LText &&  console.log(LText)
    }
    param.custom_script = Utils.formatOptions(param.custom_script)
    param.LText = Utils.formatOptions(LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.DateCount = ''
    if (this.props.menuType === 'HS') { // 云端数据验证
      param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
    }
    return param
  }
  /**
src/templates/calendarconfig/index.jsx
@@ -681,6 +681,8 @@
    if (config.setting.interType === 'inner' && !config.setting.innerFunc && config.setting.default !== 'false' && !config.setting.dataresource) {
      return '菜单尚未设置数据源,不可启用!'
    } else if (config.columns.length === 0) {
      return '菜单尚未设置数据字段,不可启用!'
    } else if (!calvaild) {
      return '日历关联字段未设置,不可启用!'
    } else {
src/templates/comtableconfig/index.jsx
@@ -1160,6 +1160,8 @@
      return '菜单尚未设置数据源,不可启用!'
    } else if (!config.setting.primaryKey) {
      return '菜单尚未设置主键,不可启用!'
    } else if (config.columns.length === 0) {
      return '菜单尚未设置显示列,不可启用!'
    } else if (!hasKey) {
      return '显示列中不存在主键字段,不可启用!'
    } else if (!tabinvalid) {
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
@@ -84,7 +84,7 @@
              <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'columns', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={this.props.dict['header.form.query.delete']}
                title={this.props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record, 'columns')
              }>
                <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
@@ -117,13 +117,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -141,7 +141,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'unique')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record, 'unique')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
@@ -181,13 +181,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -205,7 +205,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record, 'scripts')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -52,7 +52,7 @@
              <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'columns', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={this.props.dict['header.form.query.delete']}
                title={this.props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record, 'columns')
              }>
                <span style={{color: '#ff4d4f', cursor: 'pointer'}}><Icon type="delete" /></span>
src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.jsx
@@ -118,7 +118,7 @@
              <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={props.dict['header.form.query.delete']}
                title={props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record.key)
              }>
                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
src/templates/sharecomponent/columncomponent/markcolumn/index.jsx
@@ -118,7 +118,7 @@
              <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={this.props.dict['header.form.query.delete']}
                title={this.props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record)
              }>
                <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
src/templates/sharecomponent/searchcomponent/searcheditable/index.jsx
@@ -117,7 +117,7 @@
              <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={props.dict['header.form.query.delete']}
                title={props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record.key)
              }>
                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
@@ -227,7 +227,7 @@
              <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={this.props.dict['header.form.query.delete']}
                title={this.props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record.key)
              }>
                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
src/templates/sharecomponent/settingcomponent/settingform/index.jsx
@@ -53,13 +53,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -77,7 +77,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record)} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record)
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx
@@ -49,13 +49,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -73,7 +73,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record)} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record)
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
src/templates/subtableconfig/index.jsx
@@ -965,9 +965,11 @@
    })
    if (config.setting.interType === 'inner' && !config.setting.innerFunc && config.setting.default !== 'false' && !config.setting.dataresource) {
      return '菜单尚未设置数据源,不可启用!'
      return '尚未设置数据源,不可启用!'
    } else if (!config.setting.primaryKey) {
      return '菜单尚未设置主键,不可启用!'
      return '尚未设置主键,不可启用!'
    }  else if (config.columns.length === 0) {
      return '尚未设置显示列,不可启用!'
    } else if (!hasKey) {
      return '显示列中不存在主键字段,不可启用!'
    } else if (chartError) {
src/templates/zshare/modalform/modaleditable/index.jsx
@@ -158,7 +158,7 @@
              <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={props.dict['header.form.query.delete']}
                title={props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record.key)
              }>
                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
@@ -363,7 +363,7 @@
              <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={this.props.dict['header.form.query.delete']}
                title={this.props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record.key)
              }>
                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
src/templates/zshare/verifycard/index.jsx
@@ -65,13 +65,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -89,7 +89,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'unique')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record, 'unique')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
@@ -110,13 +110,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -134,7 +134,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'unique')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record, 'unique')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
@@ -175,13 +175,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -199,7 +199,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'contrast')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record, 'contrast')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
@@ -238,13 +238,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -262,7 +262,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'customverify')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record, 'customverify')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
@@ -300,13 +300,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -324,7 +324,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record, 'scripts')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
@@ -403,13 +403,13 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              {this.props.dict['model.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              {this.props.dict['model.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
@@ -427,7 +427,7 @@
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'ordercode')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title={this.props.dict['header.form.query.delete']}
              title={this.props.dict['model.query.delete']}
              onConfirm={() => this.handleDelete(record, 'ordercode')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
src/utils/option.js
@@ -4,7 +4,7 @@
import mainsubtable from '@/assets/img/mainsubtable.jpg'
import treepage from '@/assets/img/treepage.jpg'
import calendar from '@/assets/img/calendar.jpg'
import customImg from '@/assets/img/custom.jpg'
// import customImg from '@/assets/img/custom.jpg'
import rolemanage from '@/assets/img/rolemanage.jpg'
const _dict =  sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
@@ -78,13 +78,13 @@
    baseconfig: '',
    isSystem: true
  },
  {
    title: '自定义',
    type: 'CustomPage',
    url: customImg,
    baseconfig: '',
    isSystem: true
  },
  // {
  //   title: '自定义',
  //   type: 'CustomPage',
  //   url: customImg,
  //   baseconfig: '',
  //   isSystem: true
  // },
  {
    title: '角色权限分配',
    type: 'RolePermission',
src/utils/utils-datamanage.js
New file
@@ -0,0 +1,181 @@
import moment from 'moment'
import options from '@/store/options.js'
import Utils from './utils.js'
export default class DataUtils {
  /**
   * @description 数据源名称,用于统一查询
   * @param {Object}   setting      数据源设置
   * @param {String}   customScript 自定义脚本
   * @param {String}   arrFields    查询字段
   * @param {Array}    search       搜索条件
   * @param {String}   orderBy      排序方式
   * @param {Number}   pageIndex    页码
   * @param {Number}   pageSize     每页数量
   * @param {String}   BID          上级ID
   * @param {String}   menuType     菜单类型,普通菜单与HS
   * @param {Boolean}  dataManager  数据权限
   * @return {Object}  param
   */
  static getQueryDataParams (setting, customScript, arrFields, search = [], orderBy = '', pageIndex = 1, pageSize = 10, BID, menuType, dataManager) {
    let param = null
    if (setting.interType === 'system' || (setting.interType === 'inner' && !setting.innerFunc)) {
      param = this.getDefaultQueryParam(setting, customScript, arrFields, search, orderBy, pageIndex, pageSize, menuType)
    } else {
      param = this.getCustomQueryParam(setting, search, orderBy, pageIndex, pageSize, menuType)
    }
    if (BID) {
      param.BID = BID
    }
    // 数据管理权限
    if (dataManager) {
      param.dataM = 'Y'
    }
    return param
  }
  /**
   * @description 获取用户自定义存储过程传参
   */
  static getCustomQueryParam (setting, search, orderBy, pageIndex, pageSize, menuType) {
    let param = Utils.formatCustomMainSearch(search)
    if (orderBy) {
      param.OrderCol = orderBy
    }
    if (setting.laypage) {
      param.PageIndex = pageIndex
      param.PageSize = pageSize
    }
    if (setting.interType === 'inner') {
      param.func = setting.innerFunc
    } else {
      if (menuType === 'HS') {
        if (setting.sysInterface === 'true' && options.cloudServiceApi) {
          param.rduri = options.cloudServiceApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      } else {
        if (setting.sysInterface === 'true' && window.GLOB.mainSystemApi) {
          param.rduri = window.GLOB.mainSystemApi
        } else if (setting.sysInterface !== 'true') {
          param.rduri = setting.interface
        }
      }
      if (setting.outerFunc) {
        param.func = setting.outerFunc
      }
    }
    return param
  }
  /**
   * @description 获取系统存储过程 sPC_Get_TableData 的参数
   */
  static getDefaultQueryParam (setting, customScript, arrFields, search, orderBy, pageIndex, pageSize, menuType) {
    let param = {
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      arr_field: arrFields,
      default_sql: setting.execute ? 'true' : 'false'
    }
    let _dataresource = setting.dataresource
    let _customScript = customScript
    let regoptions = null
    if (setting.queryType === 'statistics' || _customScript) {
      let allSearch = Utils.getAllSearchOptions(search)
      regoptions = allSearch.map(item => {
        return {
          reg: new RegExp('@' + item.key + '@', 'ig'),
          value: `'${item.value}'`
        }
      })
      regoptions.push({
        reg: new RegExp('@orderBy@', 'ig'),
        value: orderBy
      }, {
        reg: new RegExp('@pageSize@', 'ig'),
        value: pageSize
      }, {
        reg: new RegExp('@pageIndex@', 'ig'),
        value: pageIndex
      })
    }
    let _search = ''
    if (setting.queryType === 'statistics' && _dataresource) { // 统计数据源,内容替换
      regoptions.forEach(item => {
        _dataresource = _dataresource.replace(item.reg, item.value)
      })
    } else if (_dataresource) {
      _search = Utils.joinMainSearchkey(search)
      if (_search) {
        _search = 'where ' + _search
      }
    }
    if (_customScript) {
      regoptions.forEach(item => {
        _customScript = _customScript.replace(item.reg, item.value)
      })
    }
    let LText = ''
    let DateCount = ''
    if (_dataresource && setting.laypage && orderBy) {
      LText = ` select top ${pageSize} ${arrFields} from (select ${arrFields} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${_dataresource} ${_search}) tmptable where rows > ${pageSize * (pageIndex - 1)} order by tmptable.rows `
      DateCount = `select count(1) as total from ${_dataresource} ${_search}`
    } else if (_dataresource && orderBy) {
      LText = ` select ${arrFields} from (select ${arrFields} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
    } else if (_dataresource) {
      LText = ` select ${arrFields} from ${_dataresource} ${_search}  `
    }
    if (_customScript) {
      if (LText) {
        LText = `${LText}
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      } else {
        _customScript = `${_customScript}
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      }
    }
    // 测试系统打印查询语句
    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
      _customScript &&  console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${_customScript}`)
      LText &&  console.log(LText)
    }
    param.custom_script = Utils.formatOptions(_customScript)
    param.LText = Utils.formatOptions(LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.DateCount = Utils.formatOptions(DateCount)
    if (menuType === 'HS') { // 云端数据验证
      param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
    }
    return param
  }
}
src/utils/utils.js
@@ -4,6 +4,19 @@
export default class Utils {
  /**
   * @description 数据源名称,用于统一查询
   * @return {String}  name
   */
  static getdataName () {
    let name = []
    let _options = 'abcdefghigklmnopqrstuvwxyz'
    for (let i = 0; i < 6; i++) {
      name.push(_options.substr(Math.floor(Math.random() * 26), 1))
    }
    return name.join('')
  }
  /**
   * @description 生成32位uuid string + 时间
   * @return {String}  uuid
   */
@@ -96,7 +109,8 @@
  /**
   * @description sql加密
   * @return {String}  value
   * @return {String}   value
   * @return {Boolean}  isUnFormat // 是否为解密
   */
  static formatOptions (value, isUnFormat = false) {
    if (!value) return ''
src/views/login/index.jsx
@@ -437,6 +437,7 @@
      <div className="login-container" style={bgImage ? {backgroundImage: 'url(' + bgImage + ')'} : {}}>
        <div className="logo" style={lineColor ? {borderColor: lineColor} : {}}>
          {loginlogo ? <img src={loginlogo} alt=""/> : null}
          {this.state.platName ? <p className="plat-name">{this.state.platName}</p> : null}
        </div>
        <div className="login-middle" style={lineColor ? {borderColor: lineColor} : {}}>
          {loginWays ? <LoginForm
src/views/login/index.scss
@@ -6,6 +6,7 @@
  background-repeat: no-repeat;
  background-position: center center;
  .logo {
    position: relative;
    height: 100px;
    padding-top: 30px;
    line-height: 80px;
@@ -13,6 +14,15 @@
    img {
      max-height: 100%;
    }
    .plat-name {
      position: absolute;
      color: #ffffff;
      line-height: 30px;
      font-size: 30px;
      font-weight: 600;
      padding-left: 20px;
      font-family: "黑体","宋体",sans-serif,"Arial","Microsoft YaHei";
    }
  }
  .ant-tabs.ant-tabs-card {
src/views/menudesign/index.jsx
@@ -310,8 +310,14 @@
    }
    config.components.forEach(item => {
      if (!error && (!item.setting || !item.setting.dataresource)) {
        error = `组件《${item.setting.name}》未设置数据源`
      if (!error && item.setting) {
        if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {
          error = `组件《${item.setting.name}》未设置数据源`
        } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
          error = `组件《${item.setting.name}》未设置数据源`
        } else if (item.setting.interType && !item.setting.primaryKey) {
          error = `组件《${item.setting.name}》未设置主键`
        }
      }
    })