From e4da07b71dddb3b01b58ecaf21ae5b7052e98b7d Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期三, 26 八月 2020 16:01:01 +0800
Subject: [PATCH] 2020-08-26

---
 src/menu/datasourcecomponent/verifycard/customscript/index.scss |   34 
 src/menu/actioncomponent/dragaction/index.scss                  |    6 
 src/menu/actioncomponent/verifyexcelin/uniqueform/index.scss    |    0 
 src/menu/datasourcecomponent/verifycard/customscript/index.jsx  |  231 +
 src/tabviews/zshare/normalTable/index.jsx                       |    4 
 src/menu/actioncomponent/dragaction/index.jsx                   |  156 
 src/menu/actioncomponent/verifyexcelin/uniqueform/index.jsx     |  150 
 src/templates/sharecomponent/chartcomponent/index.jsx           |    5 
 src/menu/actioncomponent/verifyexcelin/customscript/index.jsx   |  325 +
 src/menu/components/chart/antv-bar/index.scss                   |  199 -
 src/menu/datasourcecomponent/verifycard/settingform/index.scss  |   24 
 src/templates/sharecomponent/tablecomponent/index.jsx           |    4 
 src/menu/actioncomponent/verifyprint/index.jsx                  |  449 ++
 src/menu/searchcomponent/index.jsx                              |  311 +
 src/menu/menushell/card.jsx                                     |    6 
 src/views/menudesign/index.jsx                                  |   58 
 src/menu/actioncomponent/verifyexcelin/index.jsx                |  947 +++++
 src/menu/actioncomponent/verifyexcelin/index.scss               |   86 
 src/locales/zh-CN/mob.js                                        |    1 
 src/menu/actioncomponent/dragaction/card.jsx                    |   56 
 src/menu/actioncomponent/actionform/index.scss                  |   33 
 src/menu/actioncomponent/verifyexcelout/columnform/index.jsx    |  116 
 src/menu/searchcomponent/dategroup/index.scss                   |   38 
 src/menu/searchcomponent/dragsearch/card.jsx                    |   98 
 src/menu/searchcomponent/dategroup/index.jsx                    |   32 
 src/menu/datasourcecomponent/verifycard/settingform/utils.jsx   |   84 
 src/menu/datasourcecomponent/verifycard/settingform/index.jsx   |  352 ++
 src/menu/actioncomponent/verifyexcelin/columnform/index.jsx     |  221 +
 src/menu/actioncomponent/verifyexcelout/index.scss              |   84 
 src/menu/menushell/index.scss                                   |   31 
 src/menu/datasourcecomponent/index.scss                         |   94 
 src/menu/searchcomponent/dragsearch/index.scss                  |    6 
 src/menu/searchcomponent/searchform/index.scss                  |   32 
 src/menu/searchcomponent/index.scss                             |   78 
 src/menu/actioncomponent/index.scss                             |   93 
 src/menu/searchcomponent/searcheditable/index.scss              |   43 
 src/menu/menuform/index.jsx                                     |    4 
 src/menu/actioncomponent/actionform/index.jsx                   |  848 +++++
 src/menu/actioncomponent/index.jsx                              |  969 +++++
 src/menu/components/chart/antv-bar/index.jsx                    |  695 +++-
 src/menu/searchcomponent/dragsearch/index.jsx                   |   96 
 src/menu/actioncomponent/verifyprint/editable/index.jsx         |  239 +
 src/menu/actioncomponent/verifyprint/index.scss                 |   68 
 src/menu/datasourcecomponent/index.jsx                          |   93 
 src/menu/actioncomponent/verifyprint/editable/index.scss        |   51 
 src/menu/searchcomponent/searchform/index.jsx                   |  602 +++
 src/menu/datasourcecomponent/verifycard/index.jsx               |  551 +++
 src/menu/datasourcecomponent/verifycard/index.scss              |   81 
 src/menu/actioncomponent/verifyexcelin/customscript/index.scss  |    0 
 src/menu/actioncomponent/verifyexcelout/columnform/index.scss   |    0 
 src/menu/actioncomponent/verifyexcelout/index.jsx               |  602 +++
 src/menu/actioncomponent/verifyexcelin/columnform/index.scss    |    0 
 src/menu/datasourcecomponent/verifycard/columnform/index.jsx    |  145 
 src/menu/datasourcecomponent/verifycard/columnform/index.scss   |    0 
 src/menu/datasourcecomponent/verifycard/utils.jsx               |  111 
 src/menu/menushell/index.jsx                                    |    3 
 src/menu/searchcomponent/searcheditable/index.jsx               |  307 +
 src/locales/en-US/mob.js                                        |    1 
 58 files changed, 9,561 insertions(+), 392 deletions(-)

diff --git a/src/locales/en-US/mob.js b/src/locales/en-US/mob.js
index 3b12865..ff4d6b0 100644
--- a/src/locales/en-US/mob.js
+++ b/src/locales/en-US/mob.js
@@ -10,6 +10,7 @@
   'mob.enable': '鍚�',
   'mob.disable': '鍋�',
   'mob.save': '淇濆瓨',
+  'mob.style': 'Style',
   'mob.menu': '鑿滃崟',
   'mob.menu.first': '涓�绾�',
   'mob.menu.second': '浜岀骇',
diff --git a/src/locales/zh-CN/mob.js b/src/locales/zh-CN/mob.js
index 3b12865..39f2fff 100644
--- a/src/locales/zh-CN/mob.js
+++ b/src/locales/zh-CN/mob.js
@@ -10,6 +10,7 @@
   'mob.enable': '鍚�',
   'mob.disable': '鍋�',
   'mob.save': '淇濆瓨',
+  'mob.style': '鏍峰紡',
   'mob.menu': '鑿滃崟',
   'mob.menu.first': '涓�绾�',
   'mob.menu.second': '浜岀骇',
diff --git a/src/menu/actioncomponent/actionform/index.jsx b/src/menu/actioncomponent/actionform/index.jsx
new file mode 100644
index 0000000..e159cec
--- /dev/null
+++ b/src/menu/actioncomponent/actionform/index.jsx
@@ -0,0 +1,848 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Select, Icon, Radio, notification, Tooltip, InputNumber, Cascader } from 'antd'
+import { btnIcons, btnClasses, formRule } from '@/utils/option.js'
+
+import Api from '@/api'
+import options from '@/store/options.js'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const { TextArea } = Input
+
+class MainSearch extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,      // 瀛楀吀椤�
+    setting: PropTypes.object,   // 椤甸潰璁剧疆
+    formlist: PropTypes.any,     // 琛ㄥ崟淇℃伅
+    card: PropTypes.any,         // 鎸夐挳淇℃伅
+    tabs: PropTypes.array,       // 鎵�鏈夋爣绛鹃〉
+    inputSubmit: PropTypes.any   // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  state = {
+    formlist: null,  // 琛ㄥ崟淇℃伅
+    openType: null,  // 鎵撳紑鏂瑰紡
+    interType: null, // 鎺ュ彛绫诲瀷锛氬唴閮ㄣ�佸閮�
+    funcType: null,  // 鍔熻兘绫诲瀷
+    position: null,  // 鎸夐挳浣嶇疆
+    requireOptions: [{
+      value: 'notRequired',
+      text: this.props.dict['header.form.notRequired']
+    }, {
+      value: 'requiredSgl',
+      text: this.props.dict['header.form.requiredSgl']
+    }, {
+      value: 'required',
+      text: this.props.dict['header.form.required']
+    }, {
+      value: 'requiredOnce',
+      text: this.props.dict['header.form.requiredOnce']
+    }],
+    insertUpdateOptions: [{
+      value: '',
+      text: this.props.dict['model.empty']
+    }, {
+      value: 'insert',
+      text: this.props.dict['header.form.action.insert']
+    }, {
+      value: 'update',
+      text: this.props.dict['header.form.action.update']
+    }, {
+      value: 'audit',
+      text: this.props.dict['header.form.action.audit']
+    }],
+    deleteOptions: [{
+      value: '',
+      text: this.props.dict['model.empty']
+    }, {
+      value: 'LogicDelete',
+      text: this.props.dict['header.form.action.LogicDelete']
+    }, {
+      value: 'delete',
+      text: this.props.dict['header.form.action.delete']
+    }, {
+      value: 'custom',
+      text: this.props.dict['header.form.custom']
+    }]
+  }
+
+  
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    let _menulist = this.props.formlist.filter(form => form.key === 'linkmenu')[0] || ''
+    let _opentype = card.OpenType             // 鎵撳紑鏂瑰紡
+    let _tabType = card.tabType || 'SubTable' // 鎸夐挳涓哄脊绐楋紙鏍囩锛夋椂锛屾爣绛剧殑绫诲瀷
+    let _options = null                       // 閫夐」鍒楄〃
+
+    if (card.execMode) {           // 杞崲鎵撳嵃鏃舵墦寮�鏂瑰紡
+      _opentype = 'funcbutton'
+    } else if (_opentype === 'outerpage') {
+      card.pageTemplate = 'custom'
+      _opentype = 'innerpage'
+    }
+
+    let _tabs = this.props.tabs.filter(tab => tab.type === _tabType)
+
+    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']
+      if (card.tabTemplate === 'ThdMenu') {
+        _options.push('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']
+      }
+    }
+    this.setState({
+      openType: _opentype,
+      menulist: _menulist.options || [],
+      interType: card.intertype || 'inner',
+      position: card.position || 'toolbar',
+      funcType: card.funcType,
+      formlist: this.props.formlist.map(item => {
+        if (item.key === 'class') {
+          item.options = btnClasses
+        } else if (item.key === 'icon') {
+          item.options = btnIcons
+        } else if (item.key === 'Ot') {
+          if (card.position === 'grid' || card.pageTemplate === 'pay') { // 琛岀骇鎸夐挳銆佹敮浠樻寜閽紝鍙兘閫夊崟琛�
+            item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value))
+          } else if (['innerpage', 'blank', 'tab', 'popview', 'excelIn'].includes(_opentype)) {
+            item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
+          } else if (card.sqlType === 'insert') {
+            item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl', 'required'].includes(op.value))
+          } else {
+            item.options = this.state.requireOptions
+          }
+        } else if (item.key === 'sqlType') {
+          if (['prompt', 'exec'].includes(_opentype)) {
+            item.options = this.state.deleteOptions
+          } else {
+            item.options = this.state.insertUpdateOptions
+          }
+        } else if (item.key === 'linkTab') {
+          item.options = [
+            {
+              value: '',
+              text: '鏂板缓'
+            },
+            ..._tabs
+          ]
+        } else if (item.key === 'OpenType') {
+          item.initVal = _opentype
+        }
+
+        item.hidden = !_options.includes(item.key)
+        return item
+      })
+    })
+  }
+
+  componentDidMount () {
+    const { card } = this.props
+
+    if (card.focus) {
+      try {
+        let _form = document.getElementById('label')
+        _form.select()
+      } catch {
+        console.warn('琛ㄥ崟focus澶辫触锛�')
+      }
+    }
+  }
+
+  /**
+   * @description 涓嬫媺鍒囨崲
+   * 1銆佹墦寮�鏂瑰紡鍒囨崲锛岄噸缃彲瑙佽〃鍗曞拰琛ㄥ崟鍊�
+   * 2銆佹樉绀轰綅缃垏鎹紝閲嶇疆閫夋嫨琛�
+   * 3銆佸垏鎹㈡爣绛剧被鍨嬶紝閲嶇疆鍙�夋爣绛�
+   */
+  openTypeChange = (key, value) => {
+    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']
+        if (card.tabTemplate === 'ThdMenu') {
+          _options.push('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 _fieldval = {}
+      
+      let _formlist = this.state.formlist.map(item => {
+        item.hidden = !_options.includes(item.key)
+
+        if (item.hidden) return item
+
+        if (item.key === 'intertype') {
+          _fieldval.intertype = this.state.interType
+        } else if (item.key === 'Ot') {
+          if (this.state.position === 'grid') {
+            item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value))
+            _fieldval.Ot = 'requiredSgl'
+          } else if (['innerpage', 'blank', 'tab', 'popview'].includes(value)) {
+            item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
+            _fieldval.Ot = 'requiredSgl'
+          } else if (value === 'excelIn') {
+            item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
+            _fieldval.Ot = 'notRequired'
+          } else {
+            item.options = this.state.requireOptions
+          }
+        } else if (item.key === 'sqlType') {
+          if (['prompt', 'exec'].includes(value)) {
+            item.options = this.state.deleteOptions
+          } else {
+            item.options = this.state.insertUpdateOptions
+          }
+          _fieldval.sqlType = ''
+        }
+
+        return item
+      })
+
+      this.setState({
+        openType: value,
+        formlist: _formlist
+      }, () => {
+        if (value === 'excelIn') {
+          _fieldval.label = this.props.dict['model.form.excelIn']
+          _fieldval.class = 'border-dgreen'
+        } else if (value === 'excelOut') {
+          _fieldval.label = this.props.dict['model.form.excelOut']
+          _fieldval.class = 'dgreen'
+        }
+
+        this.props.form.setFieldsValue(_fieldval)
+      })
+    } else if (key === 'position') {
+      let _fieldval = {}
+
+      this.setState({
+        position: value,
+        formlist: this.state.formlist.map(item => {
+          if (item.key === 'Ot') {
+            if (value === 'grid') {
+              item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value))
+              _fieldval.Ot = 'requiredSgl'
+            } else if (['innerpage', 'blank', 'tab', 'popview'].includes(this.state.openType)) {
+              item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
+              _fieldval.Ot = 'requiredSgl'
+            } else {
+              item.options = this.state.requireOptions
+            }
+          }
+          return item
+        })
+      }, () => {
+        this.props.form.setFieldsValue(_fieldval)
+      })
+    } else if (key === 'tabType') {
+      let _tabs = this.props.tabs.filter(tab => tab.type === value)
+      let _fieldval = {}
+
+      this.setState({
+        formlist: this.state.formlist.map(item => {
+          if (item.key === 'linkTab') {
+            item.options = [
+              {
+                value: '',
+                text: '鏂板缓'
+              },
+              ..._tabs
+            ]
+          }
+          return item
+        })
+      }, () => {
+        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') {
+        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']
+        }
+      }
+      let _fieldval = {}
+
+      this.setState({
+        formlist: this.state.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
+
+          if (item.hidden) return item
+
+          if (item.key === 'intertype') {
+            _fieldval.intertype = this.state.interType
+          } else if (item.key === 'Ot' && value === 'print') {
+            item.options = this.state.requireOptions
+          }
+
+          return item
+        })
+      }, () => {
+        this.props.form.setFieldsValue(_fieldval)
+      })
+    } else if (key === 'sqlType') {
+      let _fieldval = {}
+      this.setState({
+        formlist: this.state.formlist.map(item => {
+          if (item.key === 'Ot' && value === 'insert') {
+            item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl', 'required'].includes(op.value))
+          } else if (item.key === 'Ot') {
+            item.options = this.state.requireOptions
+          }
+          return item
+        })
+      }, () => {
+        if (value === 'insert') {
+          _fieldval.label = '娣诲姞'
+          _fieldval.class = 'green'
+          _fieldval.Ot = 'notRequired'
+        } else if (value === 'update') {
+          _fieldval.label = '淇敼'
+          _fieldval.class = 'purple'
+          _fieldval.Ot = 'requiredSgl'
+        } else if (value === 'audit') {
+          _fieldval.label = '瀹℃牳'
+          _fieldval.class = 'purple'
+          _fieldval.Ot = 'requiredSgl'
+        } else if (value === 'LogicDelete' || value === 'delete') {
+          _fieldval.label = '鍒犻櫎'
+          _fieldval.class = 'danger'
+          _fieldval.Ot = 'required'
+        }
+
+        this.props.form.setFieldsValue(_fieldval)
+      })
+    } else if (key === 'pageTemplate') {
+      let _options = null
+      let _fieldval = {}
+      if (value === 'custom') {
+        _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'url', 'joint', 'icon', 'class', 'position']
+      } else {
+        _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position']
+      }
+
+      this.setState({
+        openType: value,
+        formlist: this.state.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
+
+          if (item.key === 'Ot') {
+            if (value === 'pay') {
+              item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value))
+              _fieldval.Ot = 'requiredSgl'
+            } else {
+              item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
+            }
+          }
+  
+          return item
+        })
+      }, () => {
+        this.props.form.setFieldsValue(_fieldval)
+      })
+    } else if (key === 'tabTemplate') {
+      let _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabTemplate']
+
+      if (value === 'ThdMenu') {
+        _options.push('linkmenu')
+      }
+
+      this.setState({
+        openType: value,
+        formlist: this.state.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
+  
+          return item
+        })
+      })
+    }
+  }
+
+  onChange = (e, key) => {
+    const { openType } = this.state
+    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']
+        }
+      }
+
+      this.setState({
+        interType: value,
+        formlist: this.state.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
+
+          if (item.key === 'interface') {
+            item.readonly = false
+          } else if (item.key === 'sysInterface') {
+            item.initVal = 'false'
+          } else if (item.key === 'Ot') {
+            item.options = this.state.requireOptions
+          }
+          return item
+        })
+      }, () => {
+        if (this.props.form.getFieldValue('sqlType') !== undefined) {
+          this.props.form.setFieldsValue({sqlType: ''})
+        }
+      })
+    } else if (key === 'sysInterface') {
+      if (value === 'true') {
+        this.props.form.setFieldsValue({
+          interface: window.GLOB.mainSystemApi || ''
+        })
+      }
+      this.setState({
+        formlist: this.state.formlist.map(item => {
+          if (item.key === 'interface' && value === 'true') {
+            item.readonly = true
+          } else if (item.key === 'interface') {
+            item.readonly = false
+          }
+
+          return item
+        })
+      })
+    }
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  getFields() {
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+
+    this.state.formlist.forEach((item, index) => {
+      if (item.hidden) return
+
+      if (item.type === 'text') { // 鏂囨湰鎼滅储
+        let _rules = []
+        if (item.key === 'innerFunc') {
+          let str = '^(' + item.fields.join('|') + ')'
+          let _patten = new RegExp(str + formRule.func.innerPattern + '$', 'g')
+          _rules = [{
+            pattern: _patten,
+            message: formRule.func.innerMessage
+          }, {
+            max: formRule.func.max,
+            message: formRule.func.maxMessage
+          }]
+        } else if (item.key === 'outerFunc' || item.key === 'callbackFunc') {
+          _rules = [{
+            pattern: formRule.func.pattern,
+            message: formRule.func.message
+          }, {
+            max: formRule.func.max,
+            message: formRule.func.maxMessage
+          }]
+        } else {
+          _rules = [{
+            max: formRule.input.max,
+            message: formRule.input.message
+          }]
+        }
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: item.readonly ? false : !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  },
+                  ..._rules
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: item.readonly ? false : !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={0} max={10000} precision={0} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select
+                  showSearch
+                  filterOption={(input, option) => option.props.children[2].toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  onChange={(value) => {this.openTypeChange(item.key, value)}}
+                  getPopupContainer={() => document.getElementById('winter')}
+                >
+                  {item.options.map((option, index) =>
+                    <Select.Option id={`${index}`} title={option.text} key={`${index}`} value={option.value}>
+                      {item.key === 'icon' && option.value && <Icon type={option.value} />} {option.text}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group onChange={(e) => {this.onChange(e, item.key)}} disabled={item.readonly}>
+                  {
+                    item.options.map(option => {
+                      return (
+                        <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                      )
+                    })
+                  }
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'textarea') {
+        fields.push(
+          <Col span={24} key={index}>
+            <Form.Item label={item.label} className="textarea">
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal
+              })(<TextArea rows={4} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'cascader') { // 澶氶��
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || [],
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Cascader
+                  options={this.state.menulist}
+                  loadData={this.loadData}
+                  placeholder=""
+                />
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    return fields
+  }
+
+  loadData = selectedOptions => {
+    const { MenuID } = this.props
+    const targetOption = selectedOptions[selectedOptions.length - 1]
+    targetOption.loading = true
+
+    let _param = {
+      func: 'sPC_Get_FunMenu',
+      ParentID: targetOption.value,
+      systemType: options.sysType,
+      debug: 'Y'
+    }
+
+    Api.getSystemConfig(_param).then(result => {
+      if (result.status) {
+        targetOption.loading = false
+        targetOption.children = result.data.map(item => {
+          let submenu = {
+            value: item.ParentID,
+            label: item.MenuNameP,
+            children: item.FunMenu.map(cell => {
+              return {
+                value: cell.MenuID,
+                label: cell.MenuName,
+                MenuID: cell.MenuID,
+                MenuName: cell.MenuName,
+                MenuNo: cell.MenuNo,
+                Ot: cell.Ot,
+                PageParam: cell.PageParam,
+                LinkUrl: cell.LinkUrl,
+                disabled: cell.MenuID === MenuID
+              }
+            })
+          }
+
+          return submenu
+        })
+
+        this.setState({
+          menulist: [...this.state.menulist]
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+        targetOption.loading = false
+      }
+    })
+  }
+
+  handleConfirm = () => {
+    const { setting } = this.props
+    const { menulist } = this.state
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          values.uuid = this.props.card.uuid
+          values.verify = this.props.card.verify || null
+
+          if (values.OpenType === 'excelIn') {
+            values.position = 'toolbar'
+          } else if (values.OpenType === 'excelOut') {
+            if (values.intertype === 'inner' && !values.innerFunc) {
+              if ((setting.interType === 'inner' && setting.innerFunc) || setting.interType === 'outer') {
+                notification.warning({
+                  top: 92,
+                  message: '琛ㄦ牸鏁版嵁鏌ヨ鏈娇鐢ㄦ暟鎹簮锛屽鍑篍xcel浣跨敤鍐呴儴鎺ュ彛鏃讹紝闇�鑷畾涔夊唴閮ㄥ嚱鏁帮紒',
+                  duration: 5
+                })
+                return
+              }
+            }
+            
+            values.position = 'toolbar'
+            values.Ot = 'notRequired'
+          } else if (values.OpenType === 'popview' && !values.linkTab) { // 娌℃湁鍏宠仈鏍囩锛堟柊寤烘椂锛夛紝鍒涘缓鏂版爣绛綢d
+            values.linkTab = Utils.getuuid()
+            values.createTab = true // 鐢ㄤ簬鏍囪鎸夐挳澶嶅埗鏃讹紝鏄惁澶嶅埗鍘熸湁鏍囩
+          } else if (values.OpenType === 'funcbutton') { // 杞崲鎵撳嵃鏃舵墦寮�鏂瑰紡
+            values.position = 'toolbar'
+            if (values.funcType === 'print') {
+              values.OpenType = values.execMode
+            }
+          } else if (['pop', 'prompt', 'exec'].includes(values.OpenType) && values.verify) {
+            if (values.Ot === 'requiredOnce' && ['notRequired', 'requiredSgl', 'required'].includes(this.props.card.Ot)) {
+              values.verify.uniques = []
+            } else if (this.props.card.Ot === 'requiredOnce' && ['notRequired', 'requiredSgl', 'required'].includes(values.Ot)) {
+              values.verify.uniques = []
+            }
+          }
+
+          // 鍏宠仈涓夌骇鑿滃崟
+          if (values.OpenType === 'tab' && values.linkmenu && values.linkmenu.length > 0) {
+            let linkThdMenu = ''
+            menulist.forEach(menu => {
+              if (menu.value === values.linkmenu[0]) {
+                menu.children.forEach(item => {
+                  if (item.value === values.linkmenu[1]) {
+                    item.children.forEach(cell => {
+                      if (cell.value === values.linkmenu[2]) {
+                        linkThdMenu = cell
+                      }
+                    })
+                  }
+                })
+              }
+            })
+            values.linkThdMenu = linkThdMenu
+          }
+
+          if (values.innerFunc === '' && values.sql === '') {
+            notification.warning({
+              top: 92,
+              message: this.props.dict['header.form.actionhelp.tablename'],
+              duration: 5
+            })
+          } else if (values.innerFunc === '' && values.sql !== '' && values.sqlType === '') {
+            notification.warning({
+              top: 92,
+              message: this.props.dict['header.form.actionhelp.sqlType'],
+              duration: 5
+            })
+          } else {
+            resolve(values)
+          }
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 7 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 17 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="ant-advanced-search-form commontable-action-form" id="winter">
+        <Row gutter={24}>{this.getFields()}</Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/menu/actioncomponent/actionform/index.scss b/src/menu/actioncomponent/actionform/index.scss
new file mode 100644
index 0000000..c25cef2
--- /dev/null
+++ b/src/menu/actioncomponent/actionform/index.scss
@@ -0,0 +1,33 @@
+.ant-advanced-search-form.commontable-action-form {
+  min-height: 190px;
+  .superconfig {
+    color: #1890ff;
+    cursor: pointer;
+  }
+  .textarea {
+    .ant-col-sm-7 {
+      width: 14%;
+    }
+    .ant-col-sm-17 {
+      width: 86%;
+    }
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+  .with-button {
+    .ant-form-item-control-wrapper {
+      padding-right: 63px;
+    }
+    .ant-btn {
+      position: absolute;
+      right: 12px;
+      top: 4.5px;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/actioncomponent/dragaction/card.jsx b/src/menu/actioncomponent/dragaction/card.jsx
new file mode 100644
index 0000000..670a8c5
--- /dev/null
+++ b/src/menu/actioncomponent/dragaction/card.jsx
@@ -0,0 +1,56 @@
+import React from 'react'
+import { useDrag, useDrop } from 'react-dnd'
+import { Icon, Button } from 'antd'
+import './index.scss'
+
+const Card = ({ id, card, moveCard, findCard, editCard, delCard, copyCard, profileCard, doubleClickCard }) => {
+  const originalIndex = findCard(id).index
+  const [{ isDragging }, drag] = useDrag({
+    item: { type: 'action', id, originalIndex },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  })
+  const [, drop] = useDrop({
+    accept: 'action',
+    canDrop: () => true,
+    drop: () => {},
+    hover({ id: draggedId }) {
+      if (!draggedId) return
+      if (draggedId !== id) {
+        const { index: overIndex } = findCard(id)
+        moveCard(draggedId, overIndex)
+      }
+    },
+  })
+  const opacity = isDragging ? 0 : 1
+
+  let hasProfile = false
+  if (['pop', 'prompt', 'exec'].includes(card.OpenType)) {
+    hasProfile = true
+  } else if (card.OpenType === 'excelIn' || card.OpenType === 'excelOut') {
+    hasProfile = true
+  } else if (card.funcType === 'print') {
+    hasProfile = true
+  }
+
+  return (
+    <div className="page-card" style={{ opacity: opacity}}>
+      <div ref={node => drag(drop(node))}>
+        <Button
+          className={'mk-btn mk-' + card.class}
+          icon={card.icon}
+          key={card.uuid}
+          onDoubleClick={() => doubleClickCard(id)}
+        >
+          {card.label}{card.position === 'grid' && <Icon type="table" />}
+        </Button>
+      </div>
+      <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} />
+      <Icon className="edit copy" title="copy" type="copy" onClick={() => copyCard(id)} />
+      <Icon className="edit close" title="close" type="close" onClick={() => delCard(id)} />
+      {hasProfile ? <Icon className="edit profile" title="setting" type="profile" onClick={() => profileCard(id)} /> : null}
+    </div>
+  )
+}
+export default Card
diff --git a/src/menu/actioncomponent/dragaction/index.jsx b/src/menu/actioncomponent/dragaction/index.jsx
new file mode 100644
index 0000000..5f310c0
--- /dev/null
+++ b/src/menu/actioncomponent/dragaction/index.jsx
@@ -0,0 +1,156 @@
+import React, { useState } from 'react'
+import { useDrop } from 'react-dnd'
+import { is, fromJS } from 'immutable'
+import update from 'immutability-helper'
+import { Icon } from 'antd'
+
+import Utils from '@/utils/utils.js'
+import Card from './card'
+import './index.scss'
+
+const Container = ({list, handleList, handleMenu, deleteMenu, profileMenu, doubleClickCard }) => {
+  const [cards, setCards] = useState(list)
+  const moveCard = (id, atIndex) => {
+    const { card, index } = findCard(id)
+    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
+    handleList(_cards)
+  }
+
+  if (!is(fromJS(cards), fromJS(list))) {
+    setCards(list)
+  }
+  
+  const findCard = id => {
+    const card = cards.filter(c => `${c.uuid}` === id)[0]
+    return {
+      card,
+      index: cards.indexOf(card),
+    }
+  }
+
+  const doubleClickBtn = id => {
+    const { card } = findCard(id)
+    doubleClickCard(card)
+  }
+
+  const editCard = id => {
+    const { card } = findCard(id)
+    handleMenu(card)
+  }
+  
+  const profileCard = id => {
+    const { card } = findCard(id)
+    profileMenu(card)
+  }
+
+  const delCard = id => {
+    const { card } = findCard(id)
+    deleteMenu(card)
+  }
+
+  const copyCard = id => {
+    const { card } = findCard(id)
+    let copycard = fromJS(card).toJS()
+
+    copycard.uuid = Utils.getuuid()
+    copycard.origin = false
+    copycard.copyType = 'action'
+    copycard.label = copycard.label + '(copy)'
+    copycard.focus = true
+
+    copycard.originCard = card
+
+    if (copycard.OpenType === 'popview') { // 寰呭畬鍠�
+      copycard.linkTab = ''
+    }
+
+    let _val = fromJS(copycard).toJS()
+
+    try {
+      _val.uuid = Utils.getuuid()
+      _val = window.btoa(window.encodeURIComponent(JSON.stringify(_val)))
+    } catch {
+      console.warn('Stringify Failure')
+      _val = ''
+    }
+
+    if (_val) {
+      let oInput = document.createElement('input')
+      oInput.value = _val
+      document.body.appendChild(oInput)
+      oInput.select()
+      document.execCommand('Copy')
+      document.body.removeChild(oInput)
+    }
+
+    const { index: overIndex } = findCard(id)
+
+    const _cards = update(cards, { $splice: [[overIndex + 1, 0, copycard]] })
+
+    handleList(_cards, copycard)
+  }
+
+  const [, drop] = useDrop({
+    accept: 'action',
+    drop(item) {
+      if (item.hasOwnProperty('originalIndex')) {
+        return
+      }
+    }
+  })
+
+  const addaction = () => {
+    let newcard = {}
+    newcard.uuid = Utils.getuuid()
+    newcard.focus = true
+    
+    newcard.label = 'button'
+    newcard.sqlType = ''
+    newcard.Ot = 'requiredSgl'
+    newcard.OpenType = 'excelIn'
+    newcard.tabType = 'SubTable'
+    newcard.icon = ''
+    newcard.class = 'default'
+    newcard.intertype = 'inner'
+    newcard.method = 'POST'
+    newcard.position = 'toolbar'
+    newcard.execSuccess = 'grid'
+    newcard.execError = 'never'
+    newcard.popClose = 'never'
+    newcard.errorTime = 10
+    newcard.verify = null
+    
+    let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
+
+    const { index: overIndex } = findCard(`${targetId}`)
+    let targetIndex = overIndex
+
+    targetIndex++
+
+    const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
+
+    handleList(_cards, newcard)
+  }
+
+  return (
+    <div ref={drop} className="ant-row">
+      {cards.map(card => (
+        <Card
+          id={card.uuid}
+          key={card.uuid}
+          card={card}
+          moveCard={moveCard}
+          copyCard={copyCard}
+          editCard={editCard}
+          delCard={delCard}
+          findCard={findCard}
+          profileCard={profileCard}
+          doubleClickCard={doubleClickBtn}
+        />
+      ))}
+      
+      <Icon type="plus" onClick={addaction}/>
+    </div>
+  )
+}
+export default Container
diff --git a/src/menu/actioncomponent/dragaction/index.scss b/src/menu/actioncomponent/dragaction/index.scss
new file mode 100644
index 0000000..369ae98
--- /dev/null
+++ b/src/menu/actioncomponent/dragaction/index.scss
@@ -0,0 +1,6 @@
+.common-drawarea-placeholder {
+  width: 100%;
+  line-height: 65px;
+  text-align: center;
+  color: #bcbcbc;
+}
\ No newline at end of file
diff --git a/src/menu/actioncomponent/index.jsx b/src/menu/actioncomponent/index.jsx
new file mode 100644
index 0000000..5776ff9
--- /dev/null
+++ b/src/menu/actioncomponent/index.jsx
@@ -0,0 +1,969 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Modal, notification, Button } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import options from '@/store/options.js'
+import Utils from '@/utils/utils.js'
+import DevUtils from '@/utils/devutils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import { getActionForm } from '@/templates/zshare/formconfig'
+
+import ActionForm from './actionform'
+import VerifyCard from '@/templates/zshare/verifycard'
+import CreateFunc from '@/templates/zshare/createfunc'
+import VerifyPrint from './verifyprint'
+import VerifyExcelIn from './verifyexcelin'
+import VerifyExcelOut from './verifyexcelout'
+import DragElement from './dragaction'
+import './index.scss'
+
+const { confirm } = Modal
+
+class ActionComponent extends Component {
+  static propTpyes = {
+    type: PropTypes.string,          // 鑿滃崟绫诲瀷锛屼富琛ㄦ垨瀛愯〃
+    menu: PropTypes.object,          // 鑿滃崟淇℃伅锛堣彍鍗昳d锛岃彍鍗曞弬鏁帮紝鑿滃崟鍚嶇О锛�
+    config: PropTypes.object,        // 鑿滃崟閰嶇疆淇℃伅
+    usefulFields: PropTypes.array,   // 鑷畾涔夊嚱鏁板彲鐢ㄥ瓧娈�
+    tabs: PropTypes.array,           // 鎵�鏈夋爣绛�
+    setSubConfig: PropTypes.func,    // 璁剧疆瀛愰厤缃俊鎭�
+    updateaction: PropTypes.func     // 鑿滃崟閰嶇疆鏇存柊
+  }
+
+  state = {
+    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,          // 缂栬緫涓厓绱�
+    formlist: null,      // 琛ㄥ崟淇℃伅
+    actionlist: null,    // 鎸夐挳缁�
+    copying: false,      // 鎸夐挳澶嶅埗涓�
+    visible: false,      // 妯℃�佹鎺у埗
+    profVisible: false   // 楠岃瘉淇℃伅妯℃�佹
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢鍒濆鍖�
+   */
+  UNSAFE_componentWillMount () {
+    this.setState({
+      actionlist: fromJS(this.props.config.action).toJS()
+    })
+  }
+
+  /**
+   * @description 鐩戝惉鍒版寜閽鍒舵椂锛岃Е鍙戞寜閽紪杈�
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { actionlist } = this.state
+
+    if (!is(fromJS(nextProps.config.action), fromJS(this.props.config.action)) && !is(fromJS(nextProps.config.action), fromJS(actionlist))) {
+      this.setState({actionlist: fromJS(nextProps.config.action).toJS()})
+    }
+  }
+
+  /**
+   * @description 鎸夐挳椤哄簭璋冩暣锛屾垨鎷栨嫿娣诲姞
+   */
+  handleList = (list, card) => {
+    const { config } = this.props
+
+    if (card) {
+      this.setState({actionlist: list})
+      this.handleAction(card)
+    } else {
+      this.setState({actionlist: list}, () => {
+        this.props.updateaction({...config, action: list})
+      })
+    }
+  }
+
+  /**
+   * @description 鎸夐挳缂栬緫锛岃幏鍙栨寜閽〃鍗曚俊鎭�
+   */
+  handleAction = (card) => {
+    const { menu } = this.props
+    let ableField = this.props.usefulFields.join(', ')
+    let functip = <div>
+      <p style={{marginBottom: '5px'}}>{this.state.dict['model.tooltip.func.innerface'].replace('@ableField', ableField)}</p>
+      <p>{this.state.dict['model.tooltip.func.outface']}</p>
+    </div>
+
+    let menulist = []
+    if (menu.fstMenuList) {
+      menulist = menu.fstMenuList.map(item => {
+        return {
+          value: item.MenuID,
+          label: item.text,
+          isLeaf: false
+        }
+      })
+    }
+
+    if (menu.fstMenuList && card.linkmenu && card.linkmenu.length > 0) {
+      let _param = {
+        func: 'sPC_Get_FunMenu',
+        ParentID: card.linkmenu[0],
+        systemType: options.sysType,
+        debug: 'Y'
+      }
+  
+      Api.getSystemConfig(_param).then(result => {
+        if (result.status) {
+          menulist = menulist.map(item => {
+            if (item.value === card.linkmenu[0]) {
+              item.children = result.data.map(item => {
+                let submenu = {
+                  value: item.ParentID,
+                  label: item.MenuNameP,
+                  children: item.FunMenu.map(cell => {
+                    return {
+                      value: cell.MenuID,
+                      label: cell.MenuName,
+                      MenuID: cell.MenuID,
+                      MenuName: cell.MenuName,
+                      MenuNo: cell.MenuNo,
+                      Ot: cell.Ot,
+                      PageParam: cell.PageParam,
+                      LinkUrl: cell.LinkUrl,
+                      disabled: cell.MenuID === menu.MenuID
+                    }
+                  })
+                }
+
+                return submenu
+              })
+            }
+            return item
+          })
+        } else {
+          notification.warning({
+            top: 92,
+            message: result.message,
+            duration: 5
+          })
+        }
+
+        this.setState({
+          visible: true,
+          card: card,
+          formlist: getActionForm(card, functip, this.props.config, this.props.usefulFields, this.props.type, menulist)
+        })
+      })
+    } else {
+      this.setState({
+        visible: true,
+        card: card,
+        formlist: getActionForm(card, functip, this.props.config, this.props.usefulFields, this.props.type, menulist)
+      })
+    }
+  }
+
+  /**
+   * @description 鍙栨秷淇濆瓨锛屽鏋滃厓绱犱负鏂版坊鍏冪礌锛屽垯浠庡簭鍒椾腑鍒犻櫎
+   */
+  editModalCancel = () => {
+    const { card } = this.state
+
+    if (card.focus) {
+      let actionlist = fromJS(this.state.actionlist).toJS()
+
+      actionlist = actionlist.filter(item => item.uuid !== card.uuid)
+
+      this.setState({
+        card: null,
+        actionlist: actionlist,
+        visible: false
+      })
+    } else {
+      this.setState({
+        card: null,
+        visible: false
+      })
+    }
+  }
+
+  /**
+   * @description 鎼滅储淇敼鍚庢彁浜や繚瀛�
+   * 1銆佸幓闄ょ郴缁熼粯璁ゆ悳绱㈡潯浠�
+   * 2銆佸瓧娈靛強鎻愮ず鏂囧瓧閲嶅鏍¢獙
+   * 3銆佹洿鏂颁笅鎷夎彍鍗曞彲閫夐泦鍚�
+   * 4銆佷笅鎷夎彍鍗曟暟鎹簮璇硶楠岃瘉
+   */
+  handleSubmit = () => {
+    const { config, menu } = this.props
+    const { card } = this.state
+    let _actionlist = fromJS(this.state.actionlist).toJS()
+
+    this.actionFormRef.handleConfirm().then(btn => {
+      _actionlist = _actionlist.filter(item => !item.origin || item.uuid === btn.uuid)
+
+      let labelrepet = false
+      _actionlist = _actionlist.map(item => {
+        if (item.uuid !== btn.uuid && item.label === btn.label) {
+          labelrepet = true
+        }
+
+        if (item.uuid === btn.uuid) {
+          return btn
+        } else {
+          return item
+        }
+      })
+
+      if (labelrepet) {
+        notification.warning({
+          top: 92,
+          message: this.state.dict['model.name.exist'] + ' !',
+          duration: 5
+        })
+        return
+      }
+
+      this.setState({
+        copying: true
+      })
+
+      let copyActionId = '' // 鎸夐挳涓哄鍒舵椂锛岃褰曞綋鍓嶆寜閽殑Id锛岃彍鍗曞彇娑堜繚瀛樻椂锛屽垹闄ゅ鍒舵寜閽厤缃俊鎭�
+
+      /**
+       * @description 鎸夐挳淇濆瓨鏍¢獙
+       * 1銆佹鏌ユ寜閽槸鍚︿负琛ㄥ崟鎴栬〃鍗曟爣绛鹃〉锛屽鍓嶅悗涓�鑷达紝鍒欏鍒跺叾鍐呭
+       * 2銆佹鏌ユ寜閽槸鍚︿负鏍囩椤碉紝濡傚墠鍚庝竴鑷达紝鍒欏鍒舵爣绛鹃〉
+       */
+      new Promise(resolve => {
+        if (
+          !card.originCard ||
+          (btn.OpenType === 'pop' && card.originCard.OpenType !== 'pop') ||
+          (['tab', 'blank'].includes(btn.OpenType) && !['tab', 'blank'].includes(card.originCard.OpenType)) ||
+          (btn.OpenType === 'popview' && (!btn.createTab || card.originCard.OpenType !== 'popview' || !card.originCard.linkTab))
+        ) { // 鎸夐挳涓嶆槸澶嶅埗锛屾垨鎸夐挳鍓嶅悗绫诲瀷涓嶄竴鑷存椂锛岀洿鎺ヤ繚瀛�
+          resolve('save')
+        } else if (btn.OpenType === 'pop' || btn.OpenType === 'tab' || btn.OpenType === 'blank') {
+          resolve('subconf')
+        } else if (btn.OpenType === 'popview') {
+          resolve('subtab')
+        } else {
+          resolve('save')
+        }
+      }).then(result => { // 鏌ヨ鍘熸寜閽厤缃俊鎭�
+        if (result === 'save' || result === 'subtab') return result
+
+        return Api.getSystemConfig({
+          func: 'sPC_Get_LongParam',
+          MenuID: card.originCard.uuid
+        })
+      }).then(result => { // 澶嶅埗鎸夐挳閰嶇疆淇℃伅锛屼繚瀛樿嚦鏂版坊鍔犳寜閽�
+        if (result === 'save' || result === 'subtab') return result
+
+        if (result.status && result.LongParam) {
+          let _LongParam = ''
+
+          // 瑙f瀽閰嶇疆
+          if (result.LongParam) {
+            try {
+              _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
+            } catch (e) {
+              console.warn('Parse Failure')
+              _LongParam = ''
+            }
+          }
+
+          let _temp = '' // 閰嶇疆淇℃伅绫诲瀷
+
+          // 淇敼妯℃�佹鏍囬鍚嶇О
+          if (btn.OpenType === 'pop' && _LongParam && _LongParam.type === 'Modal') {
+            try {
+              _LongParam.setting.title = btn.label
+              _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_LongParam)))
+              _temp = 'Modal'
+            } catch {
+              console.warn('Stringify Failure')
+              _LongParam = ''
+              _temp = ''
+            }
+          } else if (['tab', 'blank'].includes(btn.OpenType) && _LongParam && _LongParam.type === 'FormTab') {
+            try {
+              _LongParam.action = _LongParam.action.map(_btn => {
+                _btn.uuid = Utils.getuuid()
+
+                return _btn
+              })
+              _LongParam.tabgroups.forEach(_groupId => {
+                _LongParam[_groupId] = _LongParam[_groupId].map(_tab => {
+                  _tab.uuid = Utils.getuuid()
+
+                  return _tab
+                })
+              })
+              _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_LongParam)))
+              _temp = 'FormTab'
+            } catch {
+              console.warn('Stringify Failure')
+              _LongParam = ''
+              _temp = ''
+            }
+          }
+
+          if (!_temp) return 'save'
+
+          let param = {
+            func: 'sPC_ButtonParam_AddUpt',
+            ParentID: menu.MenuID,
+            MenuID: btn.uuid,
+            MenuNo: menu.MenuNo,
+            Template: _temp,
+            MenuName: btn.label,
+            PageParam: JSON.stringify({Template: _temp}),
+            LongParam: _LongParam
+          }
+
+          return Api.getSystemConfig(param)
+        } else {
+          if (!result.status) {
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+          }
+          return 'save'
+        }
+      }).then(result => {
+        if (result === 'save' || result === 'subtab') return result
+
+        if (!result.status) {
+          notification.warning({
+            top: 92,
+            message: result.message,
+            duration: 5
+          })
+        } else {
+          copyActionId = btn.uuid
+        }
+
+        return 'save'
+      }).then(result => { // 鏌ヨ鍘熸寜閽叧鑱旀爣绛句俊鎭�
+        if (result === 'save') return result
+
+        return Api.getSystemConfig({
+          func: 'sPC_Get_LongParam',
+          MenuID: card.originCard.linkTab
+        })
+      }).then(result => { // 鏍囩澶嶅埗
+        if (result === 'save') return result
+
+        let _LongParam = '' // 鏍囩閰嶇疆淇℃伅
+
+        if (!result.status) {
+          notification.warning({
+            top: 92,
+            message: result.message,
+            duration: 5
+          })
+        } else if (result.LongParam) {
+          // 瑙f瀽鏍囩閰嶇疆
+          try {
+            _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
+          } catch (e) {
+            console.warn('Parse Failure')
+            _LongParam = ''
+          }
+        }
+
+        if (!_LongParam) {
+          return 'save'
+        } else {
+          copyActionId = btn.linkTab
+
+          return new Promise(resolve => {
+            this.copytab(btn, _LongParam, resolve)
+          })
+        }
+      }).then(() => {
+        // 鍒ゆ柇鏄惁瀛樺湪鎿嶄綔鍒�
+        let _hasGridbtn = _actionlist.filter(act => act.position === 'grid').length > 0
+        let _gridBtn = config.gridBtn ? fromJS(config.gridBtn).toJS() : null
+
+        if (_gridBtn) {
+          _gridBtn.display = _hasGridbtn
+        } else {
+          _gridBtn = {
+            display: _hasGridbtn,
+            Align: 'center',
+            IsSort: 'false',
+            uuid: Utils.getuuid(),
+            label: this.state.dict['model.form.column.action'],
+            type: 'action',
+            style: 'button',
+            show: 'horizontal',
+            Width: 120
+          }
+        }
+
+        this.setState({
+          actionlist: _actionlist,
+          copying: false,
+          visible: false
+        }, () => {
+          this.props.updateaction({...config, action: _actionlist, gridBtn: _gridBtn}, copyActionId)
+        })
+      })
+    })
+  }
+
+  /**
+   * @description 鏍囩澶嶅埗
+   * 1銆佷繚瀛樻寜閽叧鑱旂殑鏂版爣绛�
+   * 2銆佷繚瀛樻爣绛炬寜閽俊鎭�
+   * 3銆佷繚瀛樻柊鏍囩涓寜閽殑瀛愰厤缃俊鎭�
+   */
+  copytab = (btn, _tab, _resolve) => {
+    let _LongParam = ''
+
+    _tab.uuid = btn.linkTab
+    _tab.tabName = _tab.tabName + moment().format('YYYY-MM-DD HH:mm:ss')
+    _tab.tabNo = _tab.tabNo + moment().format('YYYY-MM-DD HH:mm:ss')
+
+    let param = {
+      func: 'sPC_Tab_AddUpt',
+      MenuID: _tab.uuid,
+      MenuNo: _tab.tabNo,
+      Template: _tab.Template,
+      MenuName: _tab.tabName,
+      Remark: _tab.Remark,
+      PageParam: JSON.stringify({Template: _tab.Template}),
+      Sort: 0
+    }
+
+    let _oriActions = []
+
+    let btnParam = {
+      func: 'sPC_Button_AddUpt',
+      Type: 40,
+      ParentID: _tab.uuid,
+      MenuNo: _tab.tabNo,
+      Template: _tab.Template,
+      PageParam: '',
+      LongParam: '',
+      LText: ''
+    }
+
+    try {
+      let _linkchange = {}
+      btnParam.LText = []
+
+      _tab.action = _tab.action.map((item, index) => {
+        let uuid = Utils.getuuid()
+
+        if (item.OpenType === 'pop') {
+          _oriActions.push({
+            prebtn: JSON.parse(JSON.stringify(item)),
+            curuuid: uuid,
+            Template: 'Modal'
+          })
+        } else if (item.OpenType === 'popview') {
+          _linkchange[item.linkTab] = Utils.getuuid()
+
+          item.linkTab = _linkchange[item.linkTab]
+        }
+
+        item.uuid = uuid
+
+        btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${(index + 1) * 10}' as Sort`)
+
+        return item
+      })
+
+      if (_tab.funcs && _tab.funcs.length > 0) {
+        _tab.funcs = _tab.funcs.map(item => {
+          if (item.type === 'tab') {
+            item.linkTab = _linkchange[item.linkTab]
+            item.menuNo = ''
+            item.subfuncs = []
+          }
+
+          return item
+        })
+      }
+
+      btnParam.LText = btnParam.LText.join(' union all ')
+      btnParam.LText = Utils.formatOptions(btnParam.LText)
+      btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+      btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
+
+      _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_tab)))
+    } catch {
+      console.warn('Stringify Failure')
+      _LongParam = ''
+      _resolve('save')
+      return
+    }
+
+    param.LongParam = _LongParam
+
+    new Promise(resolve => {
+      Api.getSystemConfig(param).then(response => {
+        if (response.status) {
+          resolve(true)
+        } else {
+          notification.warning({
+            top: 92,
+            message: response.message,
+            duration: 5
+          })
+          resolve(false)
+        }
+      })
+    }).then(result => {
+      if (!result) return result
+      if (!btnParam.LText) return true
+
+      return Api.getSystemConfig(btnParam)
+    }).then(result => {
+      if (result === false || result === true) return result
+
+      if (result.status) {
+        return true
+      } else {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+        return false
+      }
+    }).then(result => {
+      if (!result) return result
+      if (_oriActions.length === 0) return true
+
+      let deffers = _oriActions.map(item => {
+        return new Promise(resolve => {
+          Api.getSystemConfig({
+            func: 'sPC_Get_LongParam',
+            MenuID: item.prebtn.uuid
+          }).then(response => {
+            if (!response.status || !response.LongParam) {
+              resolve(response)
+            } else {
+              let _param = {
+                func: 'sPC_ButtonParam_AddUpt',
+                ParentID: _tab.uuid,
+                MenuID: item.curuuid,
+                MenuNo: _tab.tabNo,
+                Template: item.Template,
+                MenuName: item.prebtn.label,
+                PageParam: JSON.stringify({Template: item.Template}),
+                LongParam: response.LongParam
+              }
+              Api.getSystemConfig(_param).then(resp => {
+                resolve(resp)
+              })
+            }
+          })
+        })
+      })
+
+      return Promise.all(deffers)
+    }).then(result => {
+      let error = ''
+
+      if (typeof(result) === 'object') {
+        result.forEach(resul => {
+          if (!resul.status && !error) {
+            error = resul
+          }
+        })
+      }
+      
+      if (error) {
+        notification.warning({
+          top: 92,
+          message: error.message,
+          duration: 5
+        })
+      }
+
+      _resolve('save')
+    })
+  }
+
+  /**
+   * @description 鎸夐挳鍒犻櫎
+   */
+  deleteElement = (card) => {
+    const { config } = this.props
+    const { dict } = this.state
+    let _this = this
+
+    confirm({
+      content: dict['model.confirm'] + dict['model.delete'] + ` - ${card.label} 锛焋,
+      okText: dict['model.confirm'],
+      cancelText: this.state.dict['model.cancel'],
+      onOk() {
+        let _actionlist = fromJS(_this.state.actionlist).toJS()
+
+        _actionlist = _actionlist.filter(item => item.uuid !== card.uuid)
+
+        let _hasGridbtn = _actionlist.filter(act => act.position === 'grid').length > 0
+        let _gridBtn = config.gridBtn ? fromJS(config.gridBtn).toJS() : null
+
+        if (_gridBtn) {
+          _gridBtn.display = _hasGridbtn
+        } else {
+          _gridBtn = {
+            display: _hasGridbtn,
+            Align: 'center',
+            IsSort: 'false',
+            uuid: Utils.getuuid(),
+            label: this.state.dict['model.form.column.action'],
+            type: 'action',
+            style: 'button',
+            show: 'horizontal',
+            Width: 120
+          }
+        }
+
+        let delcard = {
+          type: 'action',
+          card: card
+        }
+
+        _this.setState({
+          actionlist: _actionlist
+        }, () => {
+          _this.props.updateaction({...config, action: _actionlist, gridBtn: _gridBtn}, '', delcard)
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  /**
+   * @description 楠岃瘉淇℃伅閰嶇疆
+   */
+  profileAction = (element) => {
+    this.setState({
+      profVisible: true,
+      card: element
+    })
+  }
+
+  /**
+   * @description 楠岃瘉淇℃伅淇濆瓨
+   */
+  verifySubmit = () => {
+    const { config } = this.props
+    const { card } = this.state
+    
+    this.verifyRef.handleConfirm().then(res => {
+      let _actionlist = fromJS(this.state.actionlist).toJS()
+      _actionlist = _actionlist.filter(item => !item.origin || item.uuid === card.uuid)
+
+      _actionlist = _actionlist.map(item => {
+        if (item.uuid === card.uuid) {
+          item.verify = res
+        }
+  
+        return item
+      })
+
+      this.setState({
+        actionlist: _actionlist,
+        profVisible: false
+      }, () => {
+        this.props.updateaction({...config, action: _actionlist})
+      })
+    })
+  }
+
+  /**
+   * @description 鍒涘缓鎸夐挳瀛樺偍杩囩▼
+   */
+  creatFunc = () => {
+    const { config, menu } = this.props
+    let _config = fromJS(this.props.config).toJS()
+
+    this.actionFormRef.handleConfirm().then(res => {
+      let btn = res         // 鎸夐挳淇℃伅
+      let newLText = ''     // 鍒涘缓瀛樺偍杩囩▼sql
+      let DelText = ''      // 鍒犻櫎瀛樺偍杩囩▼sql
+
+      let _actionlist = fromJS(this.state.actionlist).toJS()
+
+      _actionlist = _actionlist.filter(item => !item.origin || item.uuid === btn.uuid)
+
+      let labelrepet = false
+      _actionlist = _actionlist.map(item => {
+        if (item.uuid !== btn.uuid && item.label === btn.label) {
+          labelrepet = true
+        }
+
+        if (item.uuid === btn.uuid) {
+          return btn
+        } else {
+          return item
+        }
+      })
+
+      if (labelrepet) {
+        notification.warning({
+          top: 92,
+          message: this.state.dict['model.name.exist'] + ' !',
+          duration: 5
+        })
+        return
+      }
+
+      // 鍒涘缓瀛樺偍杩囩▼锛屽繀椤诲~鍐欏唴閮ㄥ嚱鏁板悕
+      if (!btn.innerFunc) {
+        notification.warning({
+          top: 92,
+          message: '璇峰~鍐欏唴閮ㄥ嚱鏁帮紒',
+          duration: 5
+        })
+        return
+      }
+
+      new Promise(resolve => {
+        // 寮圭獥锛堣〃鍗曪級绫绘寜閽紝鍏堣幏鍙栨寜閽厤缃俊鎭紝濡傛灉灏氭湭閰嶇疆鎸夐挳鍒欎細鎶ラ敊骞剁粓姝€��
+        // 鑾峰彇淇℃伅鍚庣敓鎴愬垹闄ゅ拰鍒涘缓瀛樺偍杩囩▼鐨勮鍙�
+        if (btn.OpenType === 'pop') {
+          Api.getSystemConfig({
+            func: 'sPC_Get_LongParam',
+            MenuID: btn.uuid
+          }).then(res => {
+            let _LongParam = ''
+            if (res.status && res.LongParam) {
+              try {
+                _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
+              } catch (e) {
+                console.warn('Parse Failure')
+                _LongParam = ''
+              }
+            }
+
+            if (_LongParam) {
+              let fields = []
+              if (_LongParam.groups.length > 0) {
+                _LongParam.groups.forEach(group => {
+                  fields = [...fields, ...group.sublist]
+                })
+              } else {
+                fields = _LongParam.fields
+              }
+
+              let _param = {
+                funcName: btn.innerFunc,
+                name: _config.setting.tableName || '',
+                fields: fields,
+                menuNo: menu.MenuNo
+              }
+              newLText = Utils.formatOptions(DevUtils.getfunc(_param, btn, menu, _config))
+              DelText = Utils.formatOptions(DevUtils.dropfunc(btn.innerFunc))
+              resolve(true)
+            } else {
+              notification.warning({
+                top: 92,
+                message: '寮圭獥锛堣〃鍗曪級鎸夐挳锛岃鍏堥厤缃〃鍗曚俊鎭紒',
+                duration: 5
+              })
+              resolve(false)
+            }
+          })
+        } else if (btn.OpenType === 'excelIn') {
+          if (btn.verify && btn.verify.sheet && btn.verify.columns && btn.verify.columns.length > 0) {
+            let _param = {
+              funcName: btn.innerFunc,
+              menuNo: menu.MenuNo
+            }
+            newLText = Utils.formatOptions(DevUtils.getexcelInfunc(_param, btn, menu))
+            DelText = Utils.formatOptions(DevUtils.dropfunc(btn.innerFunc))
+            resolve(true)
+          } else {
+            notification.warning({
+              top: 92,
+              message: '璇峰畬鍠勫鍏xcel楠岃瘉淇℃伅锛�',
+              duration: 5
+            })
+            resolve(false)
+          }
+        } else if (btn.OpenType === 'excelOut') {
+          let _param = {
+            innerFunc: btn.innerFunc
+          }
+
+          newLText = Utils.formatOptions(DevUtils.getTableFunc(_param, menu, _config)) // 鍒涘缓瀛樺偍杩囩▼sql
+          DelText = Utils.formatOptions(DevUtils.dropfunc(btn.innerFunc))
+
+          resolve(true)
+        } else {
+          let _param = {
+            funcName: btn.innerFunc,
+            name: _config.setting.tableName || '',
+            fields: '',
+            menuNo: menu.MenuNo
+          }
+          newLText = Utils.formatOptions(DevUtils.getfunc(_param, btn, menu, _config))
+          DelText = Utils.formatOptions(DevUtils.dropfunc(btn.innerFunc))
+          resolve(true)
+        }
+      }).then(res => {
+        if (!res) return
+
+        this.refs.btnCreatFunc.exec(btn.innerFunc, newLText, DelText).then(result => {
+          if (result !== 'success') return
+
+          // 鍒ゆ柇鏄惁瀛樺湪鎿嶄綔鍒�
+          let _hasGridbtn = _actionlist.filter(act => act.position === 'grid').length > 0
+          let _gridBtn = config.gridBtn ? fromJS(config.gridBtn).toJS() : null
+
+          if (_gridBtn) {
+            _gridBtn.display = _hasGridbtn
+          } else {
+            _gridBtn = {
+              display: _hasGridbtn,
+              Align: 'center',
+              IsSort: 'false',
+              uuid: Utils.getuuid(),
+              label: this.state.dict['model.form.column.action'],
+              type: 'action',
+              style: 'button',
+              show: 'horizontal',
+              Width: 120
+            }
+          }
+
+          this.setState({
+            actionlist: _actionlist
+          }, () => {
+            this.props.updateaction({...config, action: _actionlist, gridBtn: _gridBtn})
+          })
+        })
+      })
+    })
+  }
+
+  /**
+   * @description 鎸夐挳鍙屽嚮瑙﹀彂瀛愰厤缃�
+   */
+  btnDoubleClick = (element) => {
+    if (!element.origin && (element.OpenType === 'pop' || element.OpenType === 'popview' || element.OpenType === 'blank' || element.OpenType === 'tab')) {
+      this.props.setSubConfig(element)
+    } else {
+      notification.warning({
+        top: 92,
+        message: '姝ゆ寜閽棤瀛愰厤缃」锛�',
+        duration: 5
+      })
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  render() {
+    const { config } = this.props
+    const { actionlist, visible, card, dict, copying, profVisible } = this.state
+
+    return (
+      <div className="model-custom-chart-action-list">
+        <DragElement
+          list={actionlist}
+          setting={this.props.config.setting}
+          handleList={this.handleList}
+          handleMenu={this.handleAction}
+          deleteMenu={this.deleteElement}
+          profileMenu={this.profileAction}
+          doubleClickCard={this.btnDoubleClick}
+        />
+        {/* 缂栬緫鎸夐挳锛氬鍒躲�佺紪杈� */}
+        <Modal
+          title={dict['model.action'] + '-' + (card && card.copyType === 'action' ? dict['model.copy'] : dict['model.edit'])}
+          visible={visible}
+          width={800}
+          maskClosable={false}
+          onCancel={this.editModalCancel}
+          footer={[
+            card && !card.copyType ? <CreateFunc key="create" dict={dict} ref="btnCreatFunc" trigger={this.creatFunc}/> : null,
+            <Button key="cancel" onClick={this.editModalCancel}>{dict['model.cancel']}</Button>,
+            <Button key="confirm" type="primary" loading={copying} onClick={this.handleSubmit}>{dict['model.confirm']}</Button>
+          ]}
+          destroyOnClose
+        >
+          <ActionForm
+            dict={dict}
+            card={card}
+            tabs={this.props.tabs}
+            formlist={this.state.formlist}
+            inputSubmit={this.handleSubmit}
+            setting={config.setting}
+            wrappedComponentRef={(inst) => this.actionFormRef = inst}
+          />
+        </Modal>
+        {/* 鎸夐挳浣跨敤绯荤粺瀛樺偍杩囩▼鏃讹紝楠岃瘉淇℃伅妯℃�佹 */}
+        <Modal
+          wrapClassName="model-table-action-verify-modal"
+          title={'楠岃瘉淇℃伅'}
+          visible={profVisible}
+          width={'75vw'}
+          maskClosable={false}
+          style={{minWidth: '900px', maxWidth: '1200px'}}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ profVisible: false }) }}
+          destroyOnClose
+        >
+          {card && !card.execMode && card.OpenType !== 'excelIn' && card.OpenType !== 'excelOut' ?
+            <VerifyCard
+              floor={this.props.type}
+              card={card}
+              dict={dict}
+              config={config}
+              columns={config.columns}
+              wrappedComponentRef={(inst) => this.verifyRef = inst}
+            /> : null
+          }
+          {card && card.execMode ?
+            <VerifyPrint
+              card={card}
+              dict={dict}
+              columns={config.columns}
+              wrappedComponentRef={(inst) => this.verifyRef = inst}
+            /> : null
+          }
+          {card && card.OpenType === 'excelIn' ?
+            <VerifyExcelIn
+              card={card}
+              dict={dict}
+              columns={config.columns}
+              wrappedComponentRef={(inst) => this.verifyRef = inst}
+            /> : null
+          }
+          {card && card.OpenType === 'excelOut' ?
+            <VerifyExcelOut
+              card={card}
+              dict={dict}
+              config={config}
+              wrappedComponentRef={(inst) => this.verifyRef = inst}
+            /> : null
+          }
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default ActionComponent
\ No newline at end of file
diff --git a/src/menu/actioncomponent/index.scss b/src/menu/actioncomponent/index.scss
new file mode 100644
index 0000000..d2e31fb
--- /dev/null
+++ b/src/menu/actioncomponent/index.scss
@@ -0,0 +1,93 @@
+.model-custom-chart-action-list {
+  position: absolute;
+  right: 0px;
+  z-index: 4;
+  
+  .anticon-question-circle {
+    color: #c49f47;
+    position: absolute;
+    left: 5px;
+    top: 5px;
+  }
+
+  .ant-row .anticon-plus {
+    color: #26C281;
+    float: right;
+    padding: 5px;
+    margin-top: 20px;
+  }
+
+  .page-card {
+    margin: 0px 0px 0px 0px;
+    padding: 15px 10px 0 0;
+    position: relative;
+    float: right;
+
+    div {
+      cursor: move;
+    }
+    .edit {
+      position: absolute;
+      left: 0;
+      top: 0px;
+      color: #1890ff;
+      cursor: pointer;
+      display: none;
+    }
+    .edit.copy {
+      left: 20px;
+      color: #26C281;
+    }
+    .edit.close {
+      left: 40px;
+      color: #ff4d4f;
+    }
+    .edit.profile {
+      left: 60px;
+      color: purple;
+    }
+    button {
+      min-width: 65px;
+      cursor: move;
+      .anticon-table {
+        font-size: 10px;
+        position: absolute;
+        right: 1px;
+        bottom: 0px;
+      }
+    }
+  }
+  .page-card:hover {
+    .edit {
+      display: inline-block;
+    }
+  }
+}
+
+.model-table-action-verify-modal {
+  .ant-modal {
+    top: 50px;
+    padding-bottom: 5px;
+    .ant-modal-body {
+      max-height: calc(100vh - 190px);
+      overflow-y: auto;
+      .ant-empty {
+        margin: 15vh 8px;
+      }
+    }
+    .ant-modal-body::-webkit-scrollbar {
+      width: 7px;
+    }
+    .ant-modal-body::-webkit-scrollbar-thumb {
+      border-radius: 5px;
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
+      background: rgba(0, 0, 0, 0.13);
+    }
+    .ant-modal-body::-webkit-scrollbar-track {
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
+      border-radius: 3px;
+      border: 1px solid rgba(0, 0, 0, 0.07);
+      background: rgba(0, 0, 0, 0);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/actioncomponent/verifyexcelin/columnform/index.jsx b/src/menu/actioncomponent/verifyexcelin/columnform/index.jsx
new file mode 100644
index 0000000..2cf05f4
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelin/columnform/index.jsx
@@ -0,0 +1,221 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Select, Button, Input, InputNumber, Radio } from 'antd'
+import './index.scss'
+
+class ExcelInColumn extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,         // 瀛楀吀椤�
+    columns: PropTypes.array,       // 鍒楀悕闆嗗悎
+    columnChange: PropTypes.func    // 淇敼鍑芥暟
+  }
+
+  state = {
+    editItem: null, // 缂栬緫鍏冪礌
+    type: 'Nvarchar(50)',
+    locked: false
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record,
+      type: record.type || 'Nvarchar(50)'
+    }, () => {
+      if (!/^Nvarchar/.test(record.type)) {
+        this.props.form.setFieldsValue({
+          min: record.min,
+          max: record.max
+        })
+      }
+    })
+
+    this.props.form.setFieldsValue({
+      Column: record.Column,
+      Text: record.Text,
+      required: record.required || 'true',
+      import: record.import || 'true',
+      type: record.type
+    })
+    if (record.type === 'Int' || /^Decimal/ig.test(record.type)) {
+      this.setState({
+        locked: true
+      })
+    } else {
+      this.setState({
+        locked: false
+      })
+    }
+  }
+
+  typeChange = (val) => {
+    this.setState({
+      type: val
+    }, () => {
+      if (val === 'Int' || /^Decimal/ig.test(val)) {
+        this.props.form.setFieldsValue({
+          required: 'true',
+        })
+        this.setState({
+          locked: true
+        })
+      } else {
+        this.setState({
+          locked: false
+        })
+      }
+    })
+  }
+
+
+  handleConfirm = () => {
+    // const { columns } = this.props
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
+
+        if (/^Nvarchar/ig.test(values.type)) {
+          values.limit = values.type.match(/\d+/) ? values.type.match(/\d+/)[0] : '20000'
+        } else if (/^Decimal/ig.test(values.type)) {
+          values.limit = values.type.match(/\d+/ig)[1]
+        } else {
+          values.limit = ''
+        }
+
+        this.props.columnChange(values)
+        this.setState({
+          editItem: null,
+          locked: false,
+          type: 'Nvarchar(50)'
+        })
+        this.props.form.setFieldsValue({
+          Column: '',
+          Text: '',
+          required: 'true',
+          import: 'true',
+          type: 'Nvarchar(50)'
+        })
+      }
+    })
+  }
+
+  render() {
+    const { dict } = this.props
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    let haslimit = !/^Nvarchar/.test(this.state.type)
+
+    return (
+      <Form {...formItemLayout} className="verify-form">
+        <Row gutter={24}>
+          <Col span={7}>
+            <Form.Item label={dict['model.form.field']}>
+              {getFieldDecorator('Column', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: dict['form.required.input'] + dict['model.form.field'] + '!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={dict['model.name']}>
+              {getFieldDecorator('Text', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + dict['model.name'] + '!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={dict['model.form.type']}>
+              {getFieldDecorator('type', {
+                initialValue: 'Nvarchar(50)'
+              })(
+                <Select onChange={this.typeChange}>
+                  <Select.Option value="Nvarchar(10)"> Nvarchar(10) </Select.Option>
+                  <Select.Option value="Nvarchar(20)"> Nvarchar(20) </Select.Option>
+                  <Select.Option value="Nvarchar(50)"> Nvarchar(50) </Select.Option>
+                  <Select.Option value="Nvarchar(100)"> Nvarchar(100) </Select.Option>
+                  <Select.Option value="Nvarchar(256)"> Nvarchar(256) </Select.Option>
+                  <Select.Option value="Nvarchar(512)"> Nvarchar(512) </Select.Option>
+                  <Select.Option value="Nvarchar(1024)"> Nvarchar(1024) </Select.Option>
+                  <Select.Option value="Nvarchar(2048)"> Nvarchar(2048) </Select.Option>
+                  <Select.Option value="Nvarchar(max)"> Nvarchar(max) </Select.Option>
+                  <Select.Option value="Int"> Int </Select.Option>
+                  <Select.Option value="Decimal(18,0)"> Decimal(18,0) </Select.Option>
+                  <Select.Option value="Decimal(18,2)"> Decimal(18,2) </Select.Option>
+                  <Select.Option value="Decimal(18,4)"> Decimal(18,4) </Select.Option>
+                  <Select.Option value="Decimal(18,6)"> Decimal(18,6) </Select.Option>
+                  <Select.Option value="date"> date </Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={3} className="add">
+            <Button onClick={this.handleConfirm} type="primary" className="mk-green">
+              {dict['model.save']}
+            </Button>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={dict['model.required']}>
+              {getFieldDecorator('required', {
+                initialValue: 'true'
+              })(
+                <Radio.Group disabled={this.state.locked}>
+                  <Radio value="true">{dict['model.true']}</Radio>
+                  <Radio value="false">{dict['model.false']}</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={dict['model.import']}>
+              {getFieldDecorator('import', {
+                initialValue: 'true'
+              })(
+                <Radio.Group>
+                  <Radio value="true">{dict['model.true']}</Radio>
+                  <Radio value="false">{dict['model.false']}</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          {haslimit ? <Col span={7}>
+            <Form.Item label={'鏈�灏忓��'}>
+              {getFieldDecorator('min', {
+                initialValue: ''
+              })(<InputNumber />)}
+            </Form.Item>
+          </Col> : null}
+          {haslimit ? <Col span={7}>
+            <Form.Item label={'鏈�澶у��'}>
+              {getFieldDecorator('max', {
+                initialValue: ''
+              })(<InputNumber />)}
+            </Form.Item>
+          </Col> : null}
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(ExcelInColumn)
\ No newline at end of file
diff --git a/src/menu/actioncomponent/verifyexcelin/columnform/index.scss b/src/menu/actioncomponent/verifyexcelin/columnform/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelin/columnform/index.scss
diff --git a/src/menu/actioncomponent/verifyexcelin/customscript/index.jsx b/src/menu/actioncomponent/verifyexcelin/customscript/index.jsx
new file mode 100644
index 0000000..9b8ecee
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelin/customscript/index.jsx
@@ -0,0 +1,325 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Form, Row, Col, Button, notification, Modal, Icon, Tooltip, Radio, Select } from 'antd'
+import moment from 'moment'
+
+import Utils from '@/utils/utils.js'
+import Api from '@/api'
+import CodeMirror from '@/templates/zshare/codemirror'
+import './index.scss'
+
+class CustomForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,         // 瀛楀吀椤�
+    btn: PropTypes.object,          // 鎸夐挳淇℃伅
+    scripts: PropTypes.array,       // 鑷畾涔夎剼鏈垪琛�
+    usefulfields: PropTypes.any,    // 鍙敤瀛楁
+    systemScripts: PropTypes.array, // 绯荤粺鑴氭湰
+    scriptsChange: PropTypes.func   // 琛ㄥ崟
+  }
+
+  state = {
+    editItem: null,
+    usefulfields: null,
+    loading: false,
+    verifySql: ''
+  }
+
+  UNSAFE_componentWillMount () {
+    const {usefulfields, btn} = this.props
+
+    let fields = usefulfields.map(item => item.Column)
+    if (!fields.includes('ID')) {
+      fields.unshift('ID')
+    }
+    if (!fields.includes('BID')) {
+      fields.unshift('BID')
+    }
+
+    let _sql = `Declare @${btn.sheet} table (${usefulfields.map(item => item.Column + ' ' + item.type).join(',')},jskey nvarchar(50) )
+      Declare @UserName nvarchar(50),@FullName nvarchar(50),@ErrorCode nvarchar(50), @retmsg nvarchar(4000),@tbid Nvarchar(512)
+      Select @ErrorCode='', @retmsg=''
+    `
+    
+    this.setState({
+      verifySql: _sql,
+      usefulfields: fields.join(', ')
+    })
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { btn } = this.props
+
+    if (nextProps.usefulfields && !is(fromJS(this.props.usefulfields), fromJS(nextProps.usefulfields))) {
+
+      let fields = nextProps.usefulfields.map(item => item.Column)
+      if (!fields.includes('ID')) {
+        fields.unshift('ID')
+      }
+      if (!fields.includes('BID')) {
+        fields.unshift('BID')
+      }
+
+      let _sql = `Declare @${btn.sheet} table (${nextProps.usefulfields.map(item => item.Column + ' ' + item.type).join(',')},jskey nvarchar(50) )
+        Declare @UserName nvarchar(50),@FullName nvarchar(50),@ErrorCode nvarchar(50), @retmsg nvarchar(4000),@tbid Nvarchar(512)
+        Select @ErrorCode='', @retmsg=''
+      `
+      
+      this.setState({
+        verifySql: _sql,
+        usefulfields: fields.join(', ')
+      })
+    }
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record
+    })
+
+    this.props.form.setFieldsValue({
+      sql: record.sql,
+      position: record.position || 'back'
+    })
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
+
+        let _quot = values.sql.match(/'{1}/g)
+        let _lparen = values.sql.match(/\({1}/g)
+        let _rparen = values.sql.match(/\){1}/g)
+
+        _quot = _quot ? _quot.length : 0
+        _lparen = _lparen ? _lparen.length : 0
+        _rparen = _rparen ? _rparen.length : 0
+
+        if (_quot % 2 !== 0) {
+          notification.warning({
+            top: 92,
+            message: 'sql涓璡'蹇呴』鎴愬鍑虹幇',
+            duration: 5
+          })
+          return
+        } else if (_lparen !== _rparen) {
+          notification.warning({
+            top: 92,
+            message: 'sql涓�()蹇呴』鎴愬鍑虹幇',
+            duration: 5
+          })
+          return
+        } else if (/--/ig.test(values.sql)) {
+          notification.warning({
+            top: 92,
+            message: '鑷畾涔塻ql璇彞涓紝涓嶅彲鍑虹幇瀛楃 -- 锛屾敞閲婅鐢� /*鍐呭*/',
+            duration: 5
+          })
+          return
+        }
+
+        let error = Utils.verifySql(values.sql, 'customscript')
+
+        if (error) {
+          notification.warning({
+            top: 92,
+            message: 'sql涓笉鍙娇鐢�' + error,
+            duration: 5
+          })
+          return
+        }
+
+        let tail = `
+          aaa:
+        `
+
+        let _initsql = ''
+        this.props.scripts.forEach(script => {
+          if (this.state.editItem && this.state.editItem.uuid === script.uuid) return
+          if (script.status === 'false' || script.position !== 'init') return
+
+          _initsql += `
+            ${script.sql}
+            `
+        })
+
+        let param = {
+          func: 's_debug_sql',
+          LText: this.state.verifySql + _initsql + values.sql + tail
+        }
+
+        param.LText = param.LText.replace(/@\$|\$@/ig, '')
+
+        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)
+        
+        this.setState({loading: true})
+        Api.getLocalConfig(param).then(res => {
+          if (res.status) {
+            this.setState({
+              loading: false,
+              editItem: null
+            }, () => {
+              this.props.scriptsChange(values)
+            })
+            this.props.form.setFieldsValue({
+              sql: ''
+            })
+          } else {
+            this.setState({loading: false})
+
+            Modal.error({
+              title: res.message
+            })
+          }
+        })
+      }
+    })
+  }
+
+  handleCancel = () => {
+    this.setState({
+      editItem: null
+    })
+    
+    this.props.form.setFieldsValue({
+      sql: ''
+    })
+  }
+
+  selectScript = (value, option) => {
+    const { usefulfields, btn } = this.props
+
+    let _value = ''
+    if (value === 'default') {
+      let fields = usefulfields.map(col => col.Column).join(',')
+      
+      if (fields) {
+        fields = fields + ','
+      }
+
+      _value = `Insert into ${btn.sheet} (${fields}createuserid,createuser,createstaff,bid)\nSelect ${fields}@userid@,@username,@fullname,@BID@ From @${btn.sheet}`
+    } else {
+      _value = value
+    }
+
+    let _sql = this.props.form.getFieldValue('sql')
+    if (_sql) {
+      _sql = _sql + ` 
+
+      `
+    }
+
+    _sql = _sql.replace(/\s{6}$/, '')
+    _sql = _sql + `/*${option.props.children}*/
+    `
+    _sql = _sql.replace(/\s{4}$/, '')
+    _sql = _sql + _value
+
+    this.props.form.setFieldsValue({
+      sql: _sql
+    })
+  }
+
+  render() {
+    const { systemScripts, btn } = this.props
+    const { usefulfields } = this.state
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="verify-form" id="verify-excelin-custom-scripts">
+        <Row gutter={24}>
+          {btn.sheet ? <Col span={8}>
+            <Form.Item label={'琛ㄥ悕'} style={{whiteSpace: 'nowrap', margin: 0}}>
+              {btn.sheet}
+            </Form.Item>
+          </Col> : null}
+          <Col span={16}>
+            <Form.Item label={'鎶ラ敊瀛楁'} style={{margin: 0}}>
+              ErrorCode, retmsg
+            </Form.Item>
+          </Col>
+          {usefulfields ? <Col span={24} className="sqlfield">
+            <Form.Item label={'鍙敤瀛楁'}>
+              {usefulfields}, jskey
+            </Form.Item>
+          </Col> : null}
+          <Col span={8} style={{whiteSpace: 'nowrap'}}>
+            <Form.Item style={{marginBottom: 0}} label={
+              <Tooltip placement="bottomLeft" title={'鑷畾涔夎剼鏈笌榛樿sql浣嶇疆鍏崇郴銆�'}>
+                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '5px'}} />
+                鎵ц浣嶇疆
+              </Tooltip>
+            }>
+              {getFieldDecorator('position', {
+                initialValue: 'front'
+              })(
+                <Radio.Group>
+                  <Radio value="init">鍒濆鍖�</Radio>
+                  <Radio value="front">sql鍓�</Radio>
+                  <Radio value="back">sql鍚�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={10}>
+            <Form.Item style={{marginBottom: 0}} label={'蹇嵎娣诲姞'}>
+              <Select
+                showSearch
+                filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                onChange={this.selectScript}
+                getPopupContainer={() => document.getElementById('verify-excelin-custom-scripts')}
+              >
+                <Select.Option key="default" value={'default'}>
+                  榛樿sql
+                </Select.Option>
+                {systemScripts.map((option, i) =>
+                  <Select.Option key={i} value={option.value}>
+                    {option.name}
+                  </Select.Option>
+                )}
+              </Select>
+            </Form.Item>
+          </Col>
+          <Col span={6} className="add">
+            <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginBottom: 15, marginLeft: 40}}>
+              淇濆瓨
+            </Button>
+            <Button onClick={this.handleCancel} style={{marginBottom: 15, marginLeft: 10}}>
+              鍙栨秷
+            </Button>
+          </Col>
+          <Col span={24} className="sql">
+            <Form.Item label={'sql'}>
+              {getFieldDecorator('sql', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + 'sql!'
+                  }
+                ]
+              })(<CodeMirror />)}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(CustomForm)
\ No newline at end of file
diff --git a/src/menu/actioncomponent/verifyexcelin/customscript/index.scss b/src/menu/actioncomponent/verifyexcelin/customscript/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelin/customscript/index.scss
diff --git a/src/menu/actioncomponent/verifyexcelin/index.jsx b/src/menu/actioncomponent/verifyexcelin/index.jsx
new file mode 100644
index 0000000..b511cc1
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelin/index.jsx
@@ -0,0 +1,947 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Form, Tabs, Row, Col, Input, Button, Table, Popconfirm, Icon, Tooltip, notification, Modal, message, InputNumber, Radio, Typography } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+
+import UniqueForm from './uniqueform'
+import ColumnForm from './columnform'
+import CustomScript from './customscript'
+import './index.scss'
+
+const { TabPane } = Tabs
+const { confirm } = Modal
+const { Paragraph } = Typography
+
+class VerifyCard extends Component {
+  static propTpyes = {
+    columns: PropTypes.array,  // 鏄剧ず鍒�
+    dict: PropTypes.object,    // 瀛楀吀椤�
+    card: PropTypes.object,
+  }
+
+  state = {
+    verify: {},
+    systemScripts: [],
+    activeKey: 'basemsg',
+    excelColumns: [
+      {
+        title: this.props.dict['model.form.field'],
+        dataIndex: 'Column',
+        width: '16%',
+        editable: true
+      },
+      {
+        title: this.props.dict['model.name'],
+        dataIndex: 'Text',
+        width: '15%',
+        editable: true
+      },
+      {
+        title: this.props.dict['model.form.type'],
+        dataIndex: 'type',
+        width: '12%',
+        editable: true
+      },
+      {
+        title: this.props.dict['model.required'],
+        dataIndex: 'required',
+        width: '10%',
+        editable: true,
+        render: (text, record) => record.required === 'true' ? this.props.dict['model.true'] : this.props.dict['model.false']
+      },
+      {
+        title: this.props.dict['model.import'],
+        dataIndex: 'import',
+        width: '10%',
+        editable: true,
+        render: (text, record) => record.import !== 'false' ? this.props.dict['model.true'] : this.props.dict['model.false']
+      },
+      {
+        title: '鏈�灏忓��',
+        dataIndex: 'min',
+        width: '10%',
+        editable: true
+      },
+      {
+        title: '鏈�澶у��',
+        dataIndex: 'max',
+        width: '10%',
+        editable: true
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          (
+            <div>
+              <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+              <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'columns', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+              <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
+                title={this.props.dict['header.form.query.delete']}
+                okText={this.props.dict['model.confirm']}
+                cancelText={this.props.dict['model.cancel']}
+                onConfirm={() => this.handleDelete(record, 'columns')
+              }>
+                <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
+              </Popconfirm>
+            </div>
+          )
+      }
+    ],
+    uniqueColumns: [
+      {
+        title: '瀛楁鍚�',
+        dataIndex: 'field',
+        width: '35%'
+      },
+      {
+        title: '鎶ラ敊缂栫爜',
+        dataIndex: 'errorCode',
+        width: '12%'
+      },
+      {
+        title: '楠岃瘉绫诲瀷',
+        dataIndex: 'verifyType',
+        width: '13%',
+        render: (text, record) => record.verifyType === 'logic' ? '閫昏緫楠岃瘉' : '鐗╃悊楠岃瘉'
+      },
+      {
+        title: '鐘舵��',
+        dataIndex: 'status',
+        width: '15%',
+        render: (text, record) => record.status === 'false' ?
+          (
+            <div>
+              {this.props.dict['header.form.status.forbidden']}
+              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
+            </div>
+          ) :
+          (
+            <div>
+              {this.props.dict['header.form.status.open']}
+              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
+            </div>
+          )
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        width: '25%',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          (<div>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'unique')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'unique', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+            <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'unique', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
+            <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
+              title={this.props.dict['header.form.query.delete']}
+              okText={this.props.dict['model.confirm']}
+              cancelText={this.props.dict['model.cancel']}
+              onConfirm={() => this.handleDelete(record, 'unique')
+            }>
+              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
+            </Popconfirm>
+          </div>)
+      }
+    ],
+    scriptsColumns: [
+      {
+        title: 'SQL',
+        dataIndex: 'sql',
+        width: '60%',
+        render: (text) => (
+          <Paragraph copyable ellipsis={{ rows: 5, expandable: true }}>{text}</Paragraph>
+        )
+      },
+      {
+        title: '鎵ц浣嶇疆',
+        dataIndex: 'position',
+        width: '10%',
+        render: (text, record) => {
+          let _text = ''
+          if (record.position === 'front') {
+            _text = 'sql鍓�'
+          } else if (record.position === 'init') {
+            _text = '鍒濆鍖�'
+          } else {
+            _text = 'sql鍚�'
+          }
+          return _text
+        }
+      },
+      {
+        title: '鐘舵��',
+        dataIndex: 'status',
+        width: '10%',
+        render: (text, record) => record.status === 'false' ?
+          (
+            <div>
+              {this.props.dict['header.form.status.forbidden']}
+              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
+            </div>
+          ) :
+          (
+            <div>
+              {this.props.dict['header.form.status.open']}
+              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
+            </div>
+          )
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        width: '20%',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          (<div>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'scripts', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+            <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'scripts', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
+            <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
+              title={this.props.dict['header.form.query.delete']}
+              okText={this.props.dict['model.confirm']}
+              cancelText={this.props.dict['model.cancel']}
+              onConfirm={() => this.handleDelete(record, 'scripts')
+            }>
+              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
+            </Popconfirm>
+          </div>)
+      }
+    ]
+  }
+
+  UNSAFE_componentWillMount() {
+    const { columns, card } = this.props
+    let _verify = fromJS(card.verify || {range: 1}).toJS()
+    let _columns = _verify.columns || []
+
+    // 鍚屾鏄剧ず鍒�
+    if (_columns.length === 0) {
+      columns.forEach(col => {
+        if (!col.field) return
+        let _type = 'Nvarchar(50)'
+        let _limit = '50'
+        if (col.type === 'number' && !col.decimal) {
+          _type = 'Int'
+          _limit = ''
+        } else if (col.type === 'number') {
+          _type = 'Decimal(18,' + col.decimal + ')'
+          _limit = col.decimal
+        }
+
+        let _cell = {
+          uuid: col.uuid,
+          Column: col.field,
+          Text: col.label,
+          type: _type,
+          limit: _limit,
+          import: 'true',
+          required: 'true'
+        }
+
+        if (_type !== 'Nvarchar(50)') {
+          _cell.min = 0
+          _cell.max = 999999
+        }
+
+        _columns.push(_cell)
+      })
+    } else {
+      // 鏃ф暟鎹吋瀹�
+      _columns = _columns.map(col => {
+        col.required = col.required || 'true'
+        col.type = col.type || 'Nvarchar(50)'
+        
+        if (/^Nvarchar/ig.test(col.type)) {
+          col.limit = col.type.match(/\d+/)[0]
+        } else if (/^Decimal/ig.test(col.type)) {
+          col.limit = col.type.match(/\d+/ig)[1]
+        } else {
+          col.limit = ''
+        }
+  
+        return col
+      })
+    }
+
+    this.setState({
+      verify: {
+        ..._verify,
+        default: _verify.default || 'true',
+        sheet: _verify.sheet || 'Sheet1',
+        range: _verify.range || 0,
+        columns: _columns,
+        scripts: _verify.scripts || [],
+        uniques: _verify.uniques || []
+      }
+    })
+  }
+
+  componentDidMount () {
+    let _scriptSql = `Select distinct func+Remark as funcname,longparam, s.Sort from聽 s_custom_script s inner join (select OpenID from sapp where ID=@Appkey@) p on s.openid = case when s.appkey='' then s.openid else p.OpenID end order by s.Sort`
+
+    _scriptSql = Utils.formatOptions(_scriptSql)
+
+    let _sParam = {
+      func: 'sPC_Get_SelectedList',
+      LText: _scriptSql,
+      obj_name: 'data',
+      arr_field: 'funcname,longparam'
+    }
+    
+    _sParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+    _sParam.secretkey = Utils.encrypt(_sParam.LText, _sParam.timestamp)
+
+    _sParam.open_key = Utils.encrypt(_sParam.secretkey, _sParam.timestamp, true) // 浜戠鏁版嵁楠岃瘉
+    
+    Api.getSystemConfig(_sParam).then(res => {
+      if (res.status) {
+        this.setState({
+          systemScripts: res.data.map(item => {
+            return {
+              name: item.funcname,
+              value: Utils.formatOptions(item.longparam, true)
+            }
+          })
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  columnFieldInput = () => {
+    const { columns } = this.props
+    const { verify } = this.state
+
+    let _columns = JSON.parse(JSON.stringify(verify.columns))
+
+    let _cols = _columns.map(col => col.Column )
+
+    columns.forEach(col => {
+      if (col.field && !_cols.includes(col.field)) {
+        let _type = 'Nvarchar(50)'
+        let _limit = '50'
+        if (col.type === 'number' && !col.decimal) {
+          _type = 'Int'
+          _limit = ''
+        } else if (col.type === 'number') {
+          _type = 'Decimal(18,' + col.decimal + ')'
+          _limit = col.decimal
+        }
+
+        let _cell = {
+          uuid: col.uuid,
+          Column: col.field,
+          Text: col.label,
+          type: _type,
+          limit: _limit,
+          import: 'true',
+          required: 'true'
+        }
+
+        if (_type !== 'Nvarchar(50)') {
+          _cell.min = 0
+          _cell.max = 999999
+        }
+
+        _columns.push(_cell)
+      }
+    })
+
+    this.setState({
+      verify: {
+        ...verify,
+        columns: _columns
+      }
+    })
+  }
+
+  clearField = () => {
+    const { verify } = this.state
+    const _this = this
+
+    confirm({
+      content: `纭畾娓呯┖Excel鍒楀悧锛焋,
+      okText: this.props.dict['model.confirm'],
+      cancelText: this.props.dict['model.cancel'],
+      onOk() {
+        _this.setState({
+          verify: {
+            ...verify,
+            columns: []
+          }
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  columnChange = (values) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+
+    if (values.uuid) {
+      verify.columns = verify.columns.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      values.uuid = Utils.getuuid()
+      verify.columns.push(values)
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  uniqueChange = (values) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+
+    if (values.uuid) {
+      verify.uniques = verify.uniques.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      values.uuid = Utils.getuuid()
+      verify.uniques.push(values)
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  scriptsChange = (values) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+
+    if (values.uuid) {
+      verify.scripts = verify.scripts.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      values.uuid = Utils.getuuid()
+      verify.scripts.push(values)
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  handleDelete = (record, type) => {
+    const { verify } = this.state
+
+    if (type === 'columns') {
+      verify.columns = verify.columns.filter(item => item.uuid !== record.uuid)
+    } else if (type === 'scripts') {
+      verify.scripts = verify.scripts.filter(item => item.uuid !== record.uuid)
+    } else if (type === 'unique') {
+      verify.uniques = verify.uniques.filter(item => item.uuid !== record.uuid)
+    }
+
+    this.setState({ verify: verify })
+  }
+
+  handleEdit = (record, type) => {
+    if (type === 'columns') {
+      this.columnForm.edit(record)
+    } else if (type === 'scripts') {
+      this.scriptsForm.edit(record)
+    } else if (type === 'unique') {
+      this.uniqueForm.edit(record)
+    }
+
+    let node = document.getElementById('verify-excel-box-tab').parentNode
+
+    if (node && node.scrollTop) {
+      let inter = Math.ceil(node.scrollTop / 10)
+
+      let timer = setInterval(() => {
+        if (node.scrollTop - inter > 0) {
+          node.scrollTop = node.scrollTop - inter
+        } else {
+          node.scrollTop = 0
+          clearInterval(timer)
+        }
+      }, 10)
+    }
+  }
+
+  handleStatus = (record, type) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+    record.status = record.status === 'false' ? 'true' : 'false'
+
+    if (type === 'scripts') {
+      verify.scripts = verify.scripts.map(item => {
+        if (item.uuid === record.uuid) {
+          return record
+        } else {
+          return item
+        }
+      })
+    } else if (type === 'unique') {
+      verify.uniques = verify.uniques.map(item => {
+        if (item.uuid === record.uuid) {
+          return record
+        } else {
+          return item
+        }
+      })
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  handleUpDown = (record, type, direction) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+    let index = 0
+
+    if (type === 'columns') {
+      verify.columns = verify.columns.filter((item, i) => {
+        if (item.uuid === record.uuid) {
+          index = i
+        }
+
+        return item.uuid !== record.uuid
+      })
+      if ((index === 0 && direction === 'up') || (index === verify.columns.length && direction === 'down')) {
+        return
+      }
+
+      if (direction === 'up') {
+        verify.columns.splice(index - 1, 0, record)
+      } else {
+        verify.columns.splice(index + 1, 0, record)
+      }
+    } else if (type === 'unique') {
+      verify.uniques = verify.uniques.filter((item, i) => {
+        if (item.uuid === record.uuid) {
+          index = i
+        }
+
+        return item.uuid !== record.uuid
+      })
+      if ((index === 0 && direction === 'up') || (index === verify.uniques.length && direction === 'down')) {
+        return
+      }
+
+      if (direction === 'up') {
+        verify.uniques.splice(index - 1, 0, record)
+      } else {
+        verify.uniques.splice(index + 1, 0, record)
+      }
+    } else if (type === 'scripts') {
+      verify.scripts = verify.scripts.filter((item, i) => {
+        if (item.uuid === record.uuid) {
+          index = i
+        }
+
+        return item.uuid !== record.uuid
+      })
+      if ((index === 0 && direction === 'up') || (index === verify.scripts.length && direction === 'down')) {
+        return
+      }
+
+      if (direction === 'up') {
+        verify.scripts.splice(index - 1, 0, record)
+      } else {
+        verify.scripts.splice(index + 1, 0, record)
+      }
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  handleConfirm = () => {
+    const { verify } = this.state
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let _verify = {...verify, ...values}
+
+          let cols = _verify.columns.map(col => col.Column)
+          cols = Array.from(new Set(cols))
+
+          if (_verify.columns.length === 0) {
+            notification.warning({
+              top: 92,
+              message: '璇疯缃瓻xcel鍒楀瓧娈�!',
+              duration: 5
+            })
+            return
+          } else if (_verify.columns.length > cols.length) {
+            notification.warning({
+              top: 92,
+              message: 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!',
+              duration: 5
+            })
+            return
+          } else if (_verify.range === 1) {
+            let tEmptys = _verify.columns.filter(op => !op.Text)
+            if (tEmptys.length > 0) {
+              notification.warning({
+                top: 92,
+                message: '蹇界暐棣栬鏃讹紝浼氫娇鐢═ext鍊兼牎楠孍xcel棣栬鍐呭锛孴ext鍊间笌Excel琛ㄩ琛屽唴瀹圭浉鍚岋紝涓斿潎涓嶅彲涓虹┖锛�',
+                duration: 5
+              })
+              return
+            }
+          }
+
+          let _loading = false
+          if (this.columnForm && this.columnForm.state.editItem) {
+            _loading = true
+            this.setState({activeKey: 'excelcolumn'})
+          } else if (this.scriptsForm && this.scriptsForm.state.editItem) {
+            _loading = true
+            this.setState({activeKey: 'scripts'})
+          } else if (this.uniqueForm && this.uniqueForm.state.editItem) {
+            _loading = true
+            this.setState({activeKey: 'unique'})
+          }
+
+          if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) {
+            _loading = true
+            this.setState({activeKey: 'scripts'})
+          }
+
+          if (_loading) {
+            confirm({
+              content: `瀛樺湪鏈繚瀛橀」锛岀‘瀹氭彁浜ゅ悧锛焋,
+              okText: this.props.dict['model.confirm'],
+              cancelText: this.props.dict['model.cancel'],
+              onOk() {
+                resolve(_verify)
+              },
+              onCancel() {}
+            })
+          } else {
+            resolve(_verify)
+          }
+        } else {
+          notification.warning({
+            top: 92,
+            message: '璇疯缃瓻xcel琛ㄥ悕!',
+            duration: 5
+          })
+        }
+      })
+    })
+  }
+
+  onOptionChange = (e, key) => {
+    const { verify } = this.state
+    let value = e.target.value
+
+    this.setState({
+      verify: {...verify, default: value}
+    })
+  }
+
+  showError = (errorType) => {
+    if (errorType === 'S') {
+      notification.success({
+        top: 92,
+        message: '鎵ц鎴愬姛锛�',
+        duration: 2
+      })
+    } else if (errorType === 'Y') {
+      Modal.success({
+        title: '鎵ц鎴愬姛锛�'
+      })
+    } else if (errorType === 'F') {
+      notification.error({
+        className: 'notification-custom-error',
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'N') {
+      notification.error({
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'E') {
+      Modal.error({
+        title: '鎵ц澶辫触锛�'
+      })
+    } else if (errorType === 'NM') {
+      message.error('鎵ц澶辫触锛�')
+    }
+  }
+
+  timeChange = (val, type) => {
+    const { verify } = this.state
+
+    this.setState({
+      verify: {...verify, [type]: val}
+    })
+  }
+
+  tabchange = (val) => {
+    const { activeKey } = this.state
+
+    if (activeKey === 'basemsg') {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          this.setState({activeKey: val})
+        }
+      })
+    } else {
+      this.setState({activeKey: val})
+    }
+  }
+
+  render() {
+    const { card } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { verify, excelColumns, scriptsColumns, uniqueColumns, activeKey } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div id="verify-excel-box-tab">
+        <Tabs activeKey={activeKey} className="verify-card-box" onChange={this.tabchange}>
+          <TabPane tab="鍩虹楠岃瘉" key="basemsg">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col span={8}>
+                  <Form.Item label={this.props.dict['model.form.tablename']}>
+                    {getFieldDecorator('sheet', {
+                      initialValue: verify.sheet || '',
+                      rules: [
+                        {
+                          required: true,
+                          message: this.props.dict['form.required.input'] + this.props.dict['model.form.tablename'] + '!'
+                        }
+                      ]
+                    })(<Input placeholder="" autoComplete="off" />)}
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={
+                    <Tooltip placement="bottomLeft" title="蹇界暐棣栬鏃讹紝浼氭牎楠宔xcel涓〃澶村悕绉颁笌excel鍒楄缃槸鍚︿竴鑷淬��">
+                      <Icon type="question-circle" style={{color: '#c49f47', marginRight: '5px'}}/>
+                      蹇界暐琛�
+                    </Tooltip>
+                  }>
+                    {getFieldDecorator('range', {
+                      initialValue: verify.range || 0
+                    })(<InputNumber min={0} max={100} precision={0} />)}
+                  </Form.Item>
+                </Col>
+                {card.intertype === 'inner' && !card.innerFunc ? <Col span={8}>
+                  <Form.Item label={'榛樿sql'}>
+                    <Radio.Group value={verify.default} onChange={this.onOptionChange}>
+                      <Radio value="true">鎵ц</Radio>
+                      <Radio value="false">涓嶆墽琛�</Radio>
+                    </Radio.Group>
+                  </Form.Item>
+                </Col> : null}
+              </Row>
+            </Form>
+          </TabPane>
+          <TabPane tab={
+            <span>
+              Excel鍒楄缃�
+              {verify.columns.length ? <span className="count-tip">{verify.columns.length}</span> : null}
+            </span>
+          } key="excelcolumn">
+            <ColumnForm
+              dict={this.props.dict}
+              columns={verify.columns}
+              columnChange={this.columnChange}
+              wrappedComponentRef={(inst) => this.columnForm = inst}
+            />
+            <Button className="excel-col-add mk-green" title="娣诲姞鏄剧ず鍒楀瓧娈�" onClick={this.columnFieldInput}>
+              鍚屾鏄剧ず鍒�
+            </Button>
+            <Button className="excel-col-add mk-red" title="娓呯┖Excel鍒�" onClick={this.clearField}>
+              娓呯┖Excel鍒�
+            </Button>
+            <Table
+              bordered
+              rowKey="uuid"
+              className="custom-table excel-custom-table"
+              dataSource={verify.columns}
+              columns={excelColumns}
+              pagination={false}
+            />
+          </TabPane>
+          {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab={
+            <span>
+              鍞竴鎬ч獙璇�
+              {verify.uniques.length ? <span className="count-tip">{verify.uniques.length}</span> : null}
+            </span>
+          } key="unique">
+            <UniqueForm
+              fields={verify.columns}
+              dict={this.props.dict}
+              uniqueChange={this.uniqueChange}
+              wrappedComponentRef={(inst) => this.uniqueForm = inst}
+            />
+            <Table
+              bordered
+              rowKey="uuid"
+              className="custom-table"
+              dataSource={verify.uniques}
+              columns={uniqueColumns}
+              pagination={false}
+            />
+          </TabPane> : null}
+          {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab={
+            <span>
+              鑷畾涔夎剼鏈�
+              {verify.scripts.length ? <span className="count-tip">{verify.scripts.length}</span> : null}
+            </span>
+          } key="scripts">
+            <CustomScript
+              dict={this.props.dict}
+              btn={this.props.card}
+              usefulfields={verify.columns}
+              scripts={verify.scripts}
+              systemScripts={this.state.systemScripts}
+              scriptsChange={this.scriptsChange}
+              wrappedComponentRef={(inst) => this.scriptsForm = inst}
+            />
+            <Table
+              bordered
+              rowKey="uuid"
+              className="custom-table"
+              dataSource={verify.scripts}
+              columns={scriptsColumns}
+              pagination={false}
+            />
+          </TabPane> : null}
+          <TabPane tab="淇℃伅鎻愮ず" key="tip">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> S </span>
+                    <Button onClick={() => {this.showError('S')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.stime || 2} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'stime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> Y </span>
+                    <Button onClick={() => {this.showError('Y')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> N </span>
+                    <Button onClick={() => {this.showError('N')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ntime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ntime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> F </span>
+                    <Button onClick={() => {this.showError('F')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ftime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ftime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> E </span>
+                    <Button onClick={() => {this.showError('E')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> NM </span>
+                    <Button onClick={() => {this.showError('NM')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> -1 </span>
+                    涓嶆彁绀�
+                  </Form.Item>
+                </Col>
+              </Row>
+            </Form>
+          </TabPane>
+        </Tabs>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(VerifyCard)
\ No newline at end of file
diff --git a/src/menu/actioncomponent/verifyexcelin/index.scss b/src/menu/actioncomponent/verifyexcelin/index.scss
new file mode 100644
index 0000000..00808ca
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelin/index.scss
@@ -0,0 +1,86 @@
+.verify-card-box {
+  .ant-tabs-nav-scroll {
+    text-align: center;
+  }
+  .ant-tabs-content {
+    min-height: 40vh;
+  }
+  table tr td {
+    word-wrap: break-word;
+    word-break: break-word;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .count-tip {
+    position: absolute;
+    top: 0px;
+    color: #1890ff;
+    font-size: 12px;
+  }
+  .verify-form {
+    .sql {
+      .ant-col-sm-8 {
+        width: 10.5%;
+      }
+      .ant-col-sm-16 {
+        width: 89.5%;
+        padding-top: 4px;
+      }
+      .CodeMirror {
+        height: 350px;
+      }
+    }
+    .sqlfield {
+      .ant-form-item {
+        margin-bottom: 5px;
+      }
+      .ant-form-item-control {
+        line-height: 24px;
+      }
+      .ant-form-item-label {
+        line-height: 25px;
+      }
+      .ant-form-item-children {
+        line-height: 22px;
+      }
+      .ant-col-sm-8 {
+        width: 10.5%;
+      }
+      .ant-col-sm-16 {
+        width: 89.5%;
+      }
+    }
+    .add {
+      padding-top: 4px;
+    }
+  }
+  .custom-table .ant-empty {
+    margin: 20px 8px!important;
+  }
+  .excel-custom-table {
+    position: relative;
+    top: -25px;
+  }
+  .errorval {
+    display: inline-block;
+    width: 30px;
+  }
+  .operation-btn {
+    display: inline-block;
+    font-size: 16px;
+    padding: 0 5px;
+    cursor: pointer;
+  }
+  .ant-tabs-tabpane {
+    position: relative;
+    .excel-col-add {
+      position: relative;
+      float: right;
+      right: -9px;
+      margin-right: 10px;
+      top: -40px;
+      z-index: 1;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/actioncomponent/verifyexcelin/uniqueform/index.jsx b/src/menu/actioncomponent/verifyexcelin/uniqueform/index.jsx
new file mode 100644
index 0000000..221bf91
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelin/uniqueform/index.jsx
@@ -0,0 +1,150 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Select, Button } from 'antd'
+import './index.scss'
+
+
+class UniqueForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,       // 瀛楀吀椤�
+    fields: PropTypes.array,      // 琛ㄥ崟瀛楁
+    uniqueChange: PropTypes.func  // 淇敼鍑芥暟
+  }
+
+  state = {
+    editItem: null // 缂栬緫鍏冪礌
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record
+    })
+
+    this.props.form.setFieldsValue({
+      field: record.field.split(','),
+      errorCode: record.errorCode,
+      verifyType: record.verifyType || 'physical'
+    })
+  }
+
+
+  handleConfirm = () => {
+    const { fields } = this.props
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
+        values.fieldlabel = values.field.map(field => {
+          let item = fields.filter(cell => cell.Column === field)[0]
+          let label = ''
+          if (item) {
+            label = item.Text
+          }
+          return label
+        })
+
+        values.fieldlabel = values.fieldlabel.join(',')
+        values.field = values.field.join(',')
+
+        this.setState({
+          editItem: null
+        }, () => {
+          this.props.uniqueChange(values)
+        })
+        this.props.form.setFieldsValue({
+          field: [],
+        })
+      }
+    })
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+    const { fields } = this.props
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="verify-form" id="verifycard1">
+        <Row gutter={24}>
+          <Col span={8}>
+            <Form.Item label={'鍒楀悕'}>
+              {getFieldDecorator('field', {
+                initialValue: [],
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.select'] + '鍒楀悕!'
+                  }
+                ]
+              })(
+                <Select
+                  mode="multiple"
+                >
+                  <Select.Option key="bid" value="BID">BID</Select.Option>
+                  {fields.map(item => (
+                    <Select.Option key={item.uuid} value={item.Column}>{item.Text}</Select.Option>
+                  ))}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={6}>
+            <Form.Item label={'鎶ラ敊缂栫爜'}>
+              {getFieldDecorator('errorCode', {
+                initialValue: 'E',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.select'] + '鎶ラ敊缂栫爜!'
+                  }
+                ]
+              })(
+                <Select>
+                  <Select.Option value="E"> E </Select.Option>
+                  <Select.Option value="N"> N </Select.Option>
+                  <Select.Option value="F"> F </Select.Option>
+                  <Select.Option value="NM"> NM </Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={6}>
+            <Form.Item label={'楠岃瘉绫诲瀷'}>
+              {getFieldDecorator('verifyType', {
+                initialValue: 'physical',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.select'] + '楠岃瘉绫诲瀷!'
+                  }
+                ]
+              })(
+                <Select>
+                  <Select.Option value="physical"> 鐗╃悊楠岃瘉 </Select.Option>
+                  <Select.Option value="logic"> 閫昏緫楠岃瘉 </Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={4} className="add">
+            <Button onClick={this.handleConfirm} className="mk-green">
+              淇濆瓨
+            </Button>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(UniqueForm)
\ No newline at end of file
diff --git a/src/menu/actioncomponent/verifyexcelin/uniqueform/index.scss b/src/menu/actioncomponent/verifyexcelin/uniqueform/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelin/uniqueform/index.scss
diff --git a/src/menu/actioncomponent/verifyexcelout/columnform/index.jsx b/src/menu/actioncomponent/verifyexcelout/columnform/index.jsx
new file mode 100644
index 0000000..56f31eb
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelout/columnform/index.jsx
@@ -0,0 +1,116 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Button, Input, InputNumber } from 'antd'
+import './index.scss'
+
+class ExcelOutColumn extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,         // 瀛楀吀椤�
+    columns: PropTypes.array,       // 鍒楀悕闆嗗悎
+    columnChange: PropTypes.func    // 淇敼鍑芥暟
+  }
+
+  state = {
+    editItem: null // 缂栬緫鍏冪礌
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record
+    })
+
+    this.props.form.setFieldsValue({
+      Column: record.Column,
+      Text: record.Text,
+      Width: record.Width
+    })
+  }
+
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
+
+        this.props.columnChange(values)
+        this.setState({
+          editItem: null
+        })
+        this.props.form.setFieldsValue({
+          Column: '',
+          Text: '',
+          Width: 20
+        })
+      }
+    })
+  }
+
+  render() {
+    const { dict } = this.props
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="verify-form">
+        <Row gutter={24}>
+          <Col span={7}>
+            <Form.Item label={dict['model.form.field']}>
+              {getFieldDecorator('Column', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: dict['form.required.input'] + dict['model.form.field'] + '!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={dict['model.name']}>
+              {getFieldDecorator('Text', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: dict['form.required.input'] + dict['model.name'] + '!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={dict['model.form.columnWidth']}>
+              {getFieldDecorator('Width', {
+                initialValue: 20,
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + dict['model.form.columnWidth'] + '!'
+                  }
+                ]
+              })(<InputNumber min={5} max={200} precision={0} />)}
+            </Form.Item>
+          </Col>
+          <Col span={3} className="add">
+            <Button onClick={this.handleConfirm} type="primary" className="mk-green">
+              淇濆瓨
+            </Button>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(ExcelOutColumn)
\ No newline at end of file
diff --git a/src/menu/actioncomponent/verifyexcelout/columnform/index.scss b/src/menu/actioncomponent/verifyexcelout/columnform/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelout/columnform/index.scss
diff --git a/src/menu/actioncomponent/verifyexcelout/index.jsx b/src/menu/actioncomponent/verifyexcelout/index.jsx
new file mode 100644
index 0000000..a2fd460
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelout/index.jsx
@@ -0,0 +1,602 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Form, Tabs, Row, Col, Button, Table, Popconfirm, Icon, notification, Modal, message, InputNumber, Radio } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+
+import ColumnForm from './columnform'
+import CodeMirror from '@/templates/zshare/codemirror'
+import './index.scss'
+
+const { TabPane } = Tabs
+const { confirm } = Modal
+
+class VerifyCard extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,    // 瀛楀吀椤�
+    config: PropTypes.object,
+    card: PropTypes.object,
+  }
+
+  state = {
+    verify: {},
+    defaultscript: '', // 鑷畾涔夎剼鏈�
+    excelColumns: [
+      {
+        title: this.props.dict['model.form.field'],
+        dataIndex: 'Column',
+        width: '25%'
+      },
+      {
+        title: this.props.dict['model.name'],
+        dataIndex: 'Text',
+        width: '25%'
+      },
+      {
+        title: this.props.dict['model.form.columnWidth'],
+        dataIndex: 'Width',
+        width: '25%'
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          (
+            <div>
+              <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+              <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'columns', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+              <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
+                title={this.props.dict['header.form.query.delete']}
+                okText={this.props.dict['model.confirm']}
+                cancelText={this.props.dict['model.cancel']}
+                onConfirm={() => this.handleDelete(record, 'columns')
+              }>
+                <span style={{color: '#ff4d4f', cursor: 'pointer'}}><Icon type="delete" /></span>
+              </Popconfirm>
+            </div>
+          )
+      }
+    ]
+  }
+
+  UNSAFE_componentWillMount() {
+    const { config, card } = this.props
+    let _verify = {}
+
+    if (card.verify) {
+      _verify = fromJS(card.verify).toJS()
+    }
+
+    _verify.enable = _verify.enable || 'false'
+
+    // 鍚屾鏄剧ず鍒�
+    if (!_verify.columns || _verify.columns.length === 0) {
+      _verify.columns = []
+      config.columns.forEach(item => {
+        if (!item.field) return
+  
+        _verify.columns.push({
+          Column: item.field,
+          Text: item.label,
+          Width: 20,
+          uuid: Utils.getuuid()
+        })
+      })
+    }
+
+    if (card.intertype !== 'inner' || card.innerFunc) {
+      _verify.enable = 'false'
+    }
+
+    let defaultscript = ''
+    if (!_verify.script && card.intertype === 'inner' && !card.innerFunc) {
+      let search = this.formatSearch(config.search)
+      search = Utils.joinMainSearchkey(search)
+      search = search ? 'where ' + search : ''
+      
+      defaultscript = `update ${config.setting.tableName || ''} set idefine5= idefine5+1 ,modifydate=getdate(),cdefine5='宸插鍑�',modifyuserid=@userid@ ${search}`
+    }
+
+
+    this.setState({
+      verify: _verify,
+      defaultscript: defaultscript
+    })
+  }
+
+  /**
+   * @description 鑾峰彇鍏ㄩ儴鎼滅储鏉′欢
+   * @param {Array} searches 鎼滅储鏉′欢鏁扮粍
+   */
+  formatSearch (searches) {
+    if (!searches || searches.length === 0) return []
+
+    let newsearches = []
+    searches.forEach(search => {
+      let item = {
+        key: search.field,
+        match: search.match,
+        type: search.type,
+        label: search.label,
+        value: `@${search.field}@`,
+        required: search.required === 'true'
+      }
+      if (item.type === 'group') {
+        let copy = fromJS(item).toJS()
+        copy.key = search.datefield
+
+        item.value = `@${search.field}@`
+        item.match = '='
+        
+        copy.type = 'daterange'
+        copy.match = 'between'
+        copy.value = [`@${search.datefield}@`, `@${search.datefield}1@`]
+
+        if (search.transfer === 'true') {
+          newsearches.push(item)
+        }
+        newsearches.push(copy)
+        return
+      } else if (item.type === 'dateweek') {
+        item.value = [`@${search.field}@`, `@${search.field}1@`]
+      } else if (item.type === 'daterange') {
+        item.value = [`@${search.field}@`, `@${search.field}1@`]
+      } else if (item.type === 'multiselect') {
+        item.value = [`@${search.field}@`]
+      }
+      newsearches.push(item)
+    })
+    
+    return newsearches
+  }
+
+  columnChange = (values) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+
+    if (values.uuid) {
+      verify.columns = verify.columns.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      let fields = verify.columns.map(item => item.Column)
+      if (fields.includes(values.Column)) {
+        notification.warning({
+          top: 92,
+          message: values.Column + '瀛楁宸插瓨鍦紒',
+          duration: 5
+        })
+        return
+      }
+      values.uuid = Utils.getuuid()
+      verify.columns.push(values)
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  handleDelete = (record, type) => {
+    const { verify } = this.state
+
+    verify.columns = verify.columns.filter(item => item.uuid !== record.uuid)
+
+    this.setState({ verify: verify })
+  }
+
+  handleEdit = (record, type) => {
+    this.columnForm.edit(record)
+
+    let node = document.getElementById('verify-excelout-box-tab').parentNode
+
+    if (node && node.scrollTop) {
+      let inter = Math.ceil(node.scrollTop / 10)
+
+      let timer = setInterval(() => {
+        if (node.scrollTop - inter > 0) {
+          node.scrollTop = node.scrollTop - inter
+        } else {
+          node.scrollTop = 0
+          clearInterval(timer)
+        }
+      }, 10)
+    }
+  }
+
+  handleUpDown = (record, type, direction) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+    let index = 0
+
+    verify.columns = verify.columns.filter((item, i) => {
+      if (item.uuid === record.uuid) {
+        index = i
+      }
+
+      return item.uuid !== record.uuid
+    })
+    if ((index === 0 && direction === 'up') || (index === verify.columns.length && direction === 'down')) {
+      return
+    }
+
+    if (direction === 'up') {
+      verify.columns.splice(index - 1, 0, record)
+    } else {
+      verify.columns.splice(index + 1, 0, record)
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  showError = (errorType) => {
+    if (errorType === 'S') {
+      notification.success({
+        top: 92,
+        message: '鎵ц鎴愬姛锛�',
+        duration: 2
+      })
+    } else if (errorType === 'Y') {
+      Modal.success({
+        title: '鎵ц鎴愬姛锛�'
+      })
+    } else if (errorType === 'F') {
+      notification.error({
+        className: 'notification-custom-error',
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'N') {
+      notification.error({
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'E') {
+      Modal.error({
+        title: '鎵ц澶辫触锛�'
+      })
+    } else if (errorType === 'NM') {
+      message.error('鎵ц澶辫触锛�')
+    }
+  }
+
+  timeChange = (val, type) => {
+    const { verify } = this.state
+
+    this.setState({
+      verify: {...verify, [type]: val}
+    })
+  }
+
+  handleConfirm = () => {
+    let verify = fromJS(this.state.verify).toJS()
+    
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      let _cols = verify.columns.map(col => col.Column)
+      let _vcols = Array.from(new Set(_cols))
+
+      if (_cols.length > _vcols.length) {
+        notification.warning({
+          top: 92,
+          message: 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!',
+          duration: 5
+        })
+        
+        return
+      }
+
+      if (verify.enable === 'true') {
+        this.props.form.validateFieldsAndScroll((err, values) => {
+          if (!err) {
+            values.sql = values.sql || ''
+
+            let _quot = values.sql.match(/'{1}/g)
+            let _lparen = values.sql.match(/\({1}/g)
+            let _rparen = values.sql.match(/\){1}/g)
+    
+            _quot = _quot ? _quot.length : 0
+            _lparen = _lparen ? _lparen.length : 0
+            _rparen = _rparen ? _rparen.length : 0
+    
+            if (_quot % 2 !== 0) {
+              notification.warning({
+                top: 92,
+                message: 'sql涓璡'蹇呴』鎴愬鍑虹幇',
+                duration: 5
+              })
+              return
+            } else if (_lparen !== _rparen) {
+              notification.warning({
+                top: 92,
+                message: 'sql涓�()蹇呴』鎴愬鍑虹幇',
+                duration: 5
+              })
+              return
+            } else if (/--/ig.test(values.sql)) {
+              notification.warning({
+                top: 92,
+                message: '鑷畾涔塻ql璇彞涓紝涓嶅彲鍑虹幇瀛楃 -- 锛屾敞閲婅鐢� /*鍐呭*/',
+                duration: 5
+              })
+              return
+            }
+    
+            let error = Utils.verifySql(values.sql, 'customscript')
+    
+            if (error) {
+              notification.warning({
+                top: 92,
+                message: 'sql涓笉鍙娇鐢�' + error,
+                duration: 5
+              })
+              return
+            }
+    
+            let param = {
+              func: 's_debug_sql',
+              LText: values.sql
+            }
+    
+            param.LText = param.LText.replace(/@\$|\$@/ig, '')
+    
+            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)
+            
+            Api.getLocalConfig(param).then(res => {
+              if (res.status) {
+                resolve({...verify, script: values.sql})
+              } else {
+                Modal.error({
+                  title: res.message
+                })
+              }
+            })
+          } else {
+            notification.warning({
+              top: 92,
+              message: '鑷畾涔夎剼鏈笉鍙负绌猴紒',
+              duration: 5
+            })
+          }
+        })
+      } else {
+        resolve(verify)
+      }
+    })
+  }
+
+  changeEnable = (e) => {
+    const { verify } = this.state
+
+    this.setState({
+      verify: {...verify, enable: e.target.value}
+    })
+  }
+
+  columnFieldInput = () => {
+    const { config } = this.props
+    const { verify } = this.state
+
+    let columns = fromJS(verify.columns).toJS()
+    let fields = columns.map(item => item.Column)
+
+    config.columns.forEach(item => {
+      if (fields.includes(item.field) || !item.field) return
+      fields.push(item.field)
+
+      columns.push({
+        Column: item.field,
+        Text: item.label,
+        Width: 20,
+        uuid: Utils.getuuid()
+      })
+    })
+
+    this.setState({
+      verify: {...verify, columns: columns}
+    })
+  }
+
+  clearField = () => {
+    const { verify } = this.state
+    const _this = this
+
+    confirm({
+      content: `纭畾娓呯┖Excel鍒楀悧锛焋,
+      okText: this.props.dict['model.confirm'],
+      cancelText: this.props.dict['model.cancel'],
+      onOk() {
+        _this.setState({
+          verify: {
+            ...verify,
+            columns: []
+          }
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  render() {
+    const { card } = this.props
+    const { verify, excelColumns, defaultscript } = this.state
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div id="verify-excelout-box-tab">
+        <Tabs defaultActiveKey="1" className="verify-card-box" onChange={this.tabchange}>
+          <TabPane tab={
+            <span>
+              Excel瀵煎嚭鍒�
+              {verify.columns.length ? <span className="count-tip">{verify.columns.length}</span> : null}
+            </span>
+          } key="1">
+            <ColumnForm
+              dict={this.props.dict}
+              columnChange={this.columnChange}
+              wrappedComponentRef={(inst) => this.columnForm = inst}
+            />
+            <Button className="excel-col-add mk-green" title="娣诲姞鏄剧ず鍒楀瓧娈�" onClick={this.columnFieldInput}>
+              鍚屾鏄剧ず鍒�
+            </Button>
+            <Button className="excel-col-add mk-red" title="娓呯┖Excel鍒�" onClick={this.clearField}>
+              娓呯┖Excel鍒�
+            </Button>
+            <Table
+              bordered
+              rowKey="uuid"
+              className="custom-table"
+              dataSource={verify.columns}
+              columns={excelColumns}
+              pagination={false}
+            />
+          </TabPane>
+          {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab={
+            <span>
+              鑷畾涔夎剼鏈�
+              {verify.enable === 'true' ? <span className="count-tip">1</span> : null}
+            </span>
+          } key="6">
+            <Form {...formItemLayout} className="verify-form">
+              <Row gutter={24}>
+                <Col span={8}>
+                  <Form.Item style={{marginBottom: 10}} label={'鍚敤'}>
+                    <Radio.Group defaultValue={verify.enable || 'false'} onChange={this.changeEnable}>
+                      <Radio value="true">鏄�</Radio>
+                      <Radio value="false">鍚�</Radio>
+                    </Radio.Group>
+                  </Form.Item>
+                </Col>
+                <Col span={24} className="sql">
+                  <Form.Item label={'sql'}>
+                    {getFieldDecorator('sql', {
+                      initialValue: verify.script || defaultscript,
+                      rules: [
+                        {
+                          required: true,
+                          message: this.props.dict['form.required.input'] + 'sql!'
+                        }
+                      ]
+                    })(<CodeMirror />)}
+                  </Form.Item>
+                </Col>
+              </Row>
+            </Form>
+          </TabPane> : null}
+          <TabPane tab="淇℃伅鎻愮ず" key="7">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> S </span>
+                    <Button onClick={() => {this.showError('S')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.stime || 2} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'stime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> Y </span>
+                    <Button onClick={() => {this.showError('Y')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> N </span>
+                    <Button onClick={() => {this.showError('N')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ntime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ntime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> F </span>
+                    <Button onClick={() => {this.showError('F')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ftime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ftime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> E </span>
+                    <Button onClick={() => {this.showError('E')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> NM </span>
+                    <Button onClick={() => {this.showError('NM')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> -1 </span>
+                    涓嶆彁绀�
+                  </Form.Item>
+                </Col>
+              </Row>
+            </Form>
+          </TabPane>
+        </Tabs>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(VerifyCard)
\ No newline at end of file
diff --git a/src/menu/actioncomponent/verifyexcelout/index.scss b/src/menu/actioncomponent/verifyexcelout/index.scss
new file mode 100644
index 0000000..94b67c9
--- /dev/null
+++ b/src/menu/actioncomponent/verifyexcelout/index.scss
@@ -0,0 +1,84 @@
+.verify-card-box {
+  .ant-tabs-nav-scroll {
+    text-align: center;
+  }
+  .ant-tabs-content {
+    min-height: 40vh;
+  }
+  table tr td {
+    word-wrap: break-word;
+    word-break: break-word;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .count-tip {
+    position: absolute;
+    top: 0px;
+    color: #1890ff;
+    font-size: 12px;
+  }
+  .verify-form {
+    .sql {
+      .ant-col-sm-8 {
+        width: 10.5%;
+      }
+      .ant-col-sm-16 {
+        width: 89.5%;
+        padding-top: 4px;
+      }
+      .CodeMirror {
+        height: 350px;
+      }
+    }
+    .sqlfield {
+      .ant-form-item {
+        margin-bottom: 5px;
+      }
+      .ant-form-item-control {
+        line-height: 24px;
+      }
+      .ant-form-item-label {
+        line-height: 25px;
+      }
+      .ant-form-item-children {
+        line-height: 22px;
+      }
+      .ant-col-sm-8 {
+        width: 10.5%;
+      }
+      .ant-col-sm-16 {
+        width: 89.5%;
+      }
+    }
+    .add {
+      padding-top: 4px;
+    }
+  }
+  .custom-table .ant-empty {
+    margin: 20px 8px!important;
+  }
+  .errorval {
+    display: inline-block;
+    width: 30px;
+  }
+  .operation-btn {
+    display: inline-block;
+    font-size: 16px;
+    padding: 0 5px;
+    cursor: pointer;
+  }
+}
+#verify-excelout-box-tab {
+  .ant-tabs-tabpane {
+    position: relative;
+    .excel-col-add {
+      position: relative;
+      float: right;
+      right: -9px;
+      margin-right: 10px;
+      top: -5px;
+      z-index: 1;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/actioncomponent/verifyprint/editable/index.jsx b/src/menu/actioncomponent/verifyprint/editable/index.jsx
new file mode 100644
index 0000000..cafd233
--- /dev/null
+++ b/src/menu/actioncomponent/verifyprint/editable/index.jsx
@@ -0,0 +1,239 @@
+import React, {Component} from 'react'
+import { Table, Input, Popconfirm, Form, Icon } from 'antd'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const EditableContext = React.createContext()
+
+const EditableRow = ({ form, index, ...props }) => (
+  <EditableContext.Provider value={form}>
+    <tr {...props} />
+  </EditableContext.Provider>
+)
+
+const EditableFormRow = Form.create()(EditableRow)
+
+class EditableCell extends Component {
+  state = {
+    editing: false
+  }
+
+  toggleEdit = () => {
+    const editing = !this.state.editing
+    this.setState({ editing }, () => {
+      if (editing && this.input && this.input.select) {
+        this.input.select()
+      } else if (editing && this.input && this.input.focus) {
+        this.input.focus()
+      }
+    })
+  }
+
+  save = e => {
+    const { record, handleSave } = this.props
+    this.form.validateFields((error, values) => {
+      handleSave({ ...record, ...values })
+      if (error && error[e.currentTarget.id]) {
+        return
+      }
+      this.toggleEdit()
+    })
+  }
+
+  renderCell = form => {
+    this.form = form
+    const { children, dataIndex, record } = this.props
+    const { editing } = this.state
+
+    return editing ? (
+      <Form.Item style={{ margin: 0 }}>
+        {form.getFieldDecorator(dataIndex, {
+          rules: [
+            {
+              required: true,
+              message: 'NOT NULL.',
+            },
+          ],
+          initialValue: record[dataIndex]
+        })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)}
+      </Form.Item>
+    ) : (
+      <div
+        className="editable-cell-value-wrap"
+        onClick={this.toggleEdit}
+      >
+        {children}
+      </div>
+    )
+  }
+
+  render() {
+    const {
+      editable,
+      dataIndex,
+      title,
+      record,
+      index,
+      handleSave,
+      children,
+      ...restProps
+    } = this.props
+    return (
+      <td {...restProps}>
+        {editable ? (
+          <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer>
+        ) : (
+          children
+        )}
+      </td>
+    )
+  }
+}
+
+class EditTable extends Component {
+  constructor(props) {
+    super(props)
+
+    let columns = [
+      {
+        title: 'Value',
+        dataIndex: 'Value',
+        width: '40%',
+        editable: true
+      },
+      {
+        title: 'Text',
+        dataIndex: 'Text',
+        width: '40%',
+        editable: true
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          this.state.dataSource.length >= 1 ? (
+            <div>
+              <span className="operation-btn" title={props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+              <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
+              <Popconfirm
+                title={props.dict['header.form.query.delete']}
+                okText={props.dict['model.confirm']}
+                cancelText={props.dict['model.cancel']}
+                onConfirm={() => this.handleDelete(record.key)
+              }>
+                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
+              </Popconfirm>
+            </div>
+          ) : null,
+      }
+    ]
+
+    this.state = {
+      columns: columns,
+      dataSource: props.data,
+      count: props.data.length,
+      linkSubFields: props.linkSubFields
+    }
+  }
+
+  handleUpDown = (record, direction) => {
+    const { dataSource } = this.state
+    let index = 0
+
+    let _data = dataSource.filter((item, i) => {
+      if (item.key === record.key) {
+        index = i
+      }
+
+      return item.key !== record.key
+    })
+    if ((index === 0 && direction === 'up') || (index === dataSource.length - 1 && direction === 'down')) {
+      return
+    }
+
+    if (direction === 'up') {
+      _data.splice(index - 1, 0, record)
+    } else {
+      _data.splice(index + 1, 0, record)
+    }
+
+    this.setState({
+      dataSource: _data
+    })
+  }
+
+  handleDelete = key => {
+    const dataSource = [...this.state.dataSource]
+    this.setState({ dataSource: dataSource.filter(item => item.key !== key) })
+  }
+
+  handleAdd = () => {
+    const { count, dataSource } = this.state
+    const newData = {
+      key: Utils.getuuid(),
+      Value: `${count}`,
+      Text: `${count}`
+    }
+
+    this.setState({
+      dataSource: [...dataSource, newData],
+      count: count + 1
+    })
+  }
+
+  handleSave = row => {
+    const newData = [...this.state.dataSource]
+    const index = newData.findIndex(item => row.key === item.key)
+    const item = newData[index]
+    newData.splice(index, 1, {
+      ...item,
+      ...row
+    })
+    this.setState({ dataSource: newData })
+  }
+
+  UNSAFE_componentWillReceiveProps () {
+    
+  }
+
+  render() {
+    const { dataSource } = this.state
+    const components = {
+      body: {
+        row: EditableFormRow,
+        cell: EditableCell
+      }
+    }
+    const columns = this.state.columns.map(col => {
+      if (!col.editable) {
+        return col
+      }
+      return {
+        ...col,
+        onCell: record => ({
+          record,
+          editable: col.editable,
+          dataIndex: col.dataIndex,
+          title: col.title,
+          handleSave: this.handleSave,
+        })
+      }
+    })
+    return (
+      <div className="print-verify-edit-table">
+        <Icon className="add-row" type="plus" onClick={this.handleAdd} />
+        <Table
+          components={components}
+          rowClassName={() => 'editable-row'}
+          bordered
+          dataSource={dataSource}
+          columns={columns}
+          pagination={false}
+        />
+      </div>
+    )
+  }
+}
+
+export default EditTable
\ No newline at end of file
diff --git a/src/menu/actioncomponent/verifyprint/editable/index.scss b/src/menu/actioncomponent/verifyprint/editable/index.scss
new file mode 100644
index 0000000..e353a37
--- /dev/null
+++ b/src/menu/actioncomponent/verifyprint/editable/index.scss
@@ -0,0 +1,51 @@
+.print-verify-edit-table {
+  margin: 10px 20px;
+  .add-row {
+    position: absolute;
+    z-index: 1;
+    right: 35px;
+    top: -30px;
+    padding: 10px;
+    font-size: 20px;
+    color: #26C281;
+  }
+  .ant-table-thead > tr > th {
+    padding: 10px 16px;
+  }
+  .ant-table-tbody > tr > td {
+    padding: 0px 16px;
+  }
+  .editable-cell-value-wrap {
+    cursor: pointer;
+    height: 40px;
+    width: 500px;
+    display: table-cell;
+    vertical-align: middle;
+    word-wrap: break-word;
+    word-break: break-word;
+    .ant-input {
+      height: 30px;
+      padding: 0 11px;
+    }
+  }
+  .ant-form-item-control-wrapper {
+    width: 100%;
+  }
+  .ant-table-placeholder {
+    padding: 5px 16px;
+    .ant-empty-normal {
+      margin: 0;
+    }
+  }
+  .operation-btn {
+    margin-right: 10px;
+    cursor: pointer;
+  }
+  .ant-table-content {
+    .ant-table-placeholder {
+      .ant-empty.ant-empty-normal {
+        margin: 50px 8px;
+      }
+    }
+  }
+}
diff --git a/src/menu/actioncomponent/verifyprint/index.jsx b/src/menu/actioncomponent/verifyprint/index.jsx
new file mode 100644
index 0000000..23e1582
--- /dev/null
+++ b/src/menu/actioncomponent/verifyprint/index.jsx
@@ -0,0 +1,449 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Tabs, Row, Col, Button, notification, Modal, message, InputNumber, Input, Select, Radio } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import CodeMirror from '@/templates/zshare/codemirror'
+import EditTable from './editable'
+
+import './index.scss'
+
+const { TabPane } = Tabs
+
+class VerifyCard extends Component {
+  static propTpyes = {
+    floor: PropTypes.any,      // 鏄惁涓哄瓙琛�
+    btnTab: PropTypes.any,     // 琛ㄥ崟鏍囩椤碉紙鎸夐挳锛夊弬鏁�
+    config: PropTypes.any,     // 琛ㄥ崟鏍囩椤靛弬鏁�
+    dict: PropTypes.object,    // 瀛楀吀椤�
+    card: PropTypes.object,
+    columns: PropTypes.array
+  }
+
+  state = {
+    verify: {},
+    templates: [],
+    selectimg: '',
+    printMode: 'normal'
+  }
+
+  UNSAFE_componentWillMount() {
+    let _verify = this.props.card.verify || {}
+
+    _verify.Template = _verify.Template || ''
+    _verify.printerTypeList = _verify.printerTypeList || []
+    _verify.linkType = _verify.linkType || 'system'
+    _verify.printMode = _verify.printMode || 'normal'
+
+    this.setState({
+      verify: _verify,
+      linkType: _verify.linkType,
+      printMode: _verify.printMode,
+      printFunc: _verify.printFunc || '// Function(data, form, printer, notification) data-鎵撳嵃鏁版嵁鍒楄〃锛宖orm-琛ㄥ崟淇℃伅锛堜笉瀛樺湪鏃朵负{}锛夛紝printer-鎵撳嵃璁剧疆锛宯otification-淇℃伅鎻愮ず鎺т欢'
+    })
+  }
+
+  componentDidMount() {
+    let _sql = `select PrintTempNO,Images,PrintTempNO+PrintTempName as PN from sPrintTemplate 
+    where appkey= @appkey@ and Deleted=0 
+    union select ID,Images,a.PrintTempNO+PrintTempName as PN 
+    from (select * from sPrintTemplate where appkey= '' and Deleted=0 ) a 
+    left join (select PrintTempNO from sPrintTemplate where appkey= @appkey@ and Deleted=0 ) b 
+    on a.PrintTempNO=b.PrintTempNO 
+    left join (select Srcid from sPrintTemplate_Log where appkey='' and apicode= @appkey@ and Deleted=0 ) c 
+    on a.ID=c.Srcid where b.PrintTempNO is null and c.Srcid is null`
+
+    let param = {
+      func: 'sPC_Get_SelectedList',
+      LText: Utils.formatOptions(_sql),
+      obj_name: 'data',
+      arr_field: 'PN,PrintTempNO,Images'
+    }
+
+    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+
+    param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true) // 浜戠鏁版嵁楠岃瘉
+
+    Api.getSystemConfig(param).then(res => {
+      if (res.status) {
+        let temps = res.data.map(temp => {
+          return {
+            value: temp.PrintTempNO,
+            text: temp.PN,
+            img: temp.Images
+          }
+        })
+
+        let Template = this.state.verify.Template
+        let selectimg = ''
+        let selectTemp = temps.filter(temp => temp.value === Template)[0]
+
+        if (!selectTemp) {
+          Template = ''
+        } else {
+          selectimg = selectTemp.img
+        }
+
+        this.setState({
+          selectimg: selectimg,
+          templates: temps,
+          verify: {
+            ...this.state.verify,
+            Template: Template
+          }
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  showError = (errorType) => {
+    if (errorType === 'S') {
+      notification.success({
+        top: 92,
+        message: '鎵ц鎴愬姛锛�',
+        duration: 2
+      })
+    } else if (errorType === 'Y') {
+      Modal.success({
+        title: '鎵ц鎴愬姛锛�'
+      })
+    } else if (errorType === 'F') {
+      notification.error({
+        className: 'notification-custom-error',
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'N') {
+      notification.error({
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'E') {
+      Modal.error({
+        title: '鎵ц澶辫触锛�'
+      })
+    } else if (errorType === 'NM') {
+      message.error('鎵ц澶辫触锛�')
+    }
+  }
+
+  timeChange = (val, type) => {
+    const { verify } = this.state
+
+    this.setState({
+      verify: {...verify, [type]: val}
+    })
+  }
+
+  changeTemplate = (val) => {
+    const { templates } = this.state
+
+    let temp = templates.filter(temp => temp.value === val)[0]
+
+    this.setState({
+      selectimg: temp.img
+    })
+  }
+
+  handleConfirm = () => {
+    const { verify } = this.state
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let _verify = {...verify, ...values}
+
+          if (this.refs.editTable && this.refs.editTable.state) {
+            let printTypes = this.refs.editTable.state.dataSource
+  
+            let emptys = printTypes.filter(item => !item.Value || !item.Text)
+            let valMap = new Map()
+            let isvalid = true
+  
+            printTypes.forEach(item => {
+              if (valMap.has(item.Value)) {
+                isvalid = false
+              } else {
+                valMap.set(item.Value, item.Text)
+              }
+            })
+  
+            if (emptys.length > 0) {
+              notification.warning({
+                top: 92,
+                message: '鎵撳嵃绫诲瀷琛ㄦ牸涓璙alue銆乀ext瀛楁涓嶅彲涓虹┖!',
+                duration: 5
+              })
+              return
+            } else if (!isvalid) {
+              notification.warning({
+                top: 92,
+                message: '鎵撳嵃绫诲瀷琛ㄦ牸涓璙alue瀛楁涓嶅彲閲嶅!',
+                duration: 5
+              })
+              return
+            }
+  
+            _verify.printerTypeList = printTypes
+          }
+
+          resolve(_verify)
+        } else {
+          notification.warning({
+            top: 92,
+            message: '閾炬帴鍦板潃涓庢墦鍗版ā鏉夸笉鍙负绌�!',
+            duration: 5
+          })
+        }
+      })
+    })
+  }
+
+  changePrintMode = (e) => {
+    let value = e.target.value
+
+    this.setState({
+      printMode: value
+    })
+  }
+
+  changeLinkType = (e) => {
+    let value = e.target.value
+
+    this.setState({
+      linkType: value
+    }, () => {
+      if (value === 'system') {
+        this.props.form.setFieldsValue({
+          linkUrl: '127.0.0.1:13529'
+        })
+      }
+    })
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+
+    const { verify, linkType, printMode, printFunc } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div id="verify-card-box-tab">
+        <Tabs defaultActiveKey="1" className="verify-card-print-box" onChange={this.tabchange}>
+          <TabPane tab="鎵撳嵃楠岃瘉" key="1">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col span={8}>
+                  <Form.Item label={'鎵撳嵃妯″紡'}>
+                    {getFieldDecorator('printMode', {
+                      initialValue: printMode || 'normal'
+                    })(
+                      <Radio.Group onChange={this.changePrintMode}>
+                        <Radio value="normal">鏍囧噯</Radio>
+                        <Radio value="custom">鑷畾涔�</Radio>
+                      </Radio.Group>
+                    )}
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'閾炬帴绫诲瀷'}>
+                    {getFieldDecorator('linkType', {
+                      initialValue: linkType || 'system'
+                    })(
+                      <Radio.Group onChange={this.changeLinkType}>
+                        <Radio value="system">绯荤粺</Radio>
+                        <Radio value="custom">鑷畾涔�</Radio>
+                      </Radio.Group>
+                    )}
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'閾炬帴鍦板潃'}>
+                    {getFieldDecorator('linkUrl', {
+                      initialValue: verify.linkUrl || '127.0.0.1:13529',
+                      rules: [
+                        {
+                          required: true,
+                          message: this.props.dict['form.required.input'] + '閾炬帴鍦板潃!'
+                        }
+                      ]
+                    })(<Input placeholder="" autoComplete="off" disabled={linkType === 'system'} />)}
+                  </Form.Item>
+                </Col>
+                {printMode === 'custom' ? <Col span={24}>
+                  <Form.Item label={'澶勭悊鍑芥暟'} className="printFunc">
+                    {getFieldDecorator('printFunc', {
+                      initialValue: printFunc || '',
+                      rules: [
+                        {
+                          required: true,
+                          message: this.props.dict['form.required.input'] + '澶勭悊鍑芥暟!'
+                        }
+                      ]
+                    })(
+                      <CodeMirror mode="text/javascript"/>
+                    )} 
+                  </Form.Item>
+                </Col> : null}
+                {printMode === 'normal' ? <Col span={8}>
+                  <Form.Item label={'鎵撳嵃妯℃澘'}>
+                    {getFieldDecorator('Template', {
+                      initialValue: verify.Template || '',
+                      rules: [
+                        {
+                          required: true,
+                          message: this.props.dict['form.required.select'] + '鎵撳嵃妯℃澘!'
+                        }
+                      ]
+                    })(
+                      <Select dropdownClassName="print-template-setting" onChange={this.changeTemplate}>
+                        {this.state.templates.map((option, key) =>
+                          <Select.Option id={key} key={key} value={option.value}>
+                            {option.text}
+                          </Select.Option>
+                        )}
+                      </Select>
+                    )}
+                  </Form.Item>
+                </Col> : null }
+                {printMode === 'normal' ? <Col span={8} offset={8}>
+                  <img className="legend" src={this.state.selectimg} alt=""/>
+                </Col> : null }
+              </Row>
+            </Form>
+          </TabPane>
+          <TabPane tab={
+            <span>
+              鎵撳嵃绫诲瀷
+              {verify.printerTypeList.length ? <span className="count-tip">{verify.printerTypeList.length}</span> : null}
+            </span>
+          } key="2">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col span={24} className="print-tip">
+                  <Form.Item label={'鎻愮ず'}>
+                    濡傛灉姝ゆ寜閽秹鍙婂绉嶆暟鎹被鍨嬬殑鎵撳嵃锛岄渶瑕佽缃笉鍚岀殑鎵撳嵃鏈烘椂锛岃娣诲姞鎵撳嵃绫诲瀷鎺у埗淇℃伅锛岀敤鎴峰湪鑷畾涔夎缃腑锛屽彲鏍规嵁鎵撳嵃绫诲瀷璁剧疆瀵瑰簲鐨勬墦鍗版満銆�
+                    鎵撳嵃鏃讹紝鏁版嵁鐨勬墦鍗扮被鍨嬪彇鍐充簬杩斿洖鍊硷紙鍐呴儴鎴栧閮ㄦ帴鍙o級涓殑 printType 瀛楁銆�
+                    娉細杩斿洖鍊间腑鐨� printCount銆乼emplateID 瀛楁锛屽彲鍒嗗埆鎺у埗鎵撳嵃鏁伴噺鍜屾墦鍗版ā鏉裤��
+                  </Form.Item>
+                </Col>
+                <Col span={24}>
+                  <EditTable data={verify.printerTypeList} dict={this.props.dict} ref="editTable"/>
+                </Col>
+              </Row>
+            </Form>
+          </TabPane>
+          <TabPane tab="淇℃伅鎻愮ず" key="7">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> S </span>
+                    <Button onClick={() => {this.showError('S')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.stime || 2} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'stime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> Y </span>
+                    <Button onClick={() => {this.showError('Y')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> N </span>
+                    <Button onClick={() => {this.showError('N')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ntime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ntime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> F </span>
+                    <Button onClick={() => {this.showError('F')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ftime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ftime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> E </span>
+                    <Button onClick={() => {this.showError('E')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> NM </span>
+                    <Button onClick={() => {this.showError('NM')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> -1 </span>
+                    涓嶆彁绀�
+                  </Form.Item>
+                </Col>
+              </Row>
+            </Form>
+          </TabPane>
+        </Tabs>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(VerifyCard)
\ No newline at end of file
diff --git a/src/menu/actioncomponent/verifyprint/index.scss b/src/menu/actioncomponent/verifyprint/index.scss
new file mode 100644
index 0000000..1da8ed1
--- /dev/null
+++ b/src/menu/actioncomponent/verifyprint/index.scss
@@ -0,0 +1,68 @@
+.verify-card-print-box {
+  .ant-tabs-nav-scroll {
+    text-align: center;
+  }
+  .ant-tabs-content {
+    min-height: 40vh;
+    .ant-form-item {
+      margin-bottom: 10px;
+    }
+  }
+  .ant-input-disabled {
+    color: rgba(0, 0, 0, 0.65);
+    cursor: default;
+  }
+  .errorval {
+    display: inline-block;
+    width: 30px;
+  }
+  .operation-btn {
+    display: inline-block;
+    font-size: 16px;
+    padding: 0 5px;
+    cursor: pointer;
+  }
+  .legend {
+    width: 100%;
+    margin-bottom: 25px;
+    margin-left: -2px;
+    box-shadow: 0px 0px 2px #bcbcbc;
+  }
+  .printFunc {
+    .ant-form-item-label {
+      width: 10.7%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 89.3%;
+    }
+  }
+  .code-mirror-area {
+    .CodeMirror {
+      height: calc(100vh - 360px);
+    }
+  }
+  .print-tip {
+    margin-bottom: 25px;
+    .ant-form-item-label {
+      width: 8.5%;
+      line-height: 25px;
+    }
+    .ant-form-item-control-wrapper {
+      width: 91.5%;
+      .ant-form-item-children {
+        line-height: 25px;
+      }
+    }
+  }
+  .count-tip {
+    position: absolute;
+    top: 0px;
+    color: #1890ff;
+    font-size: 12px;
+  }
+}
+.print-template-setting {
+  .ant-select-dropdown-menu-item {
+    white-space: normal;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/chart/antv-bar/index.jsx b/src/menu/components/chart/antv-bar/index.jsx
index 88bbd27..cf3b9d1 100644
--- a/src/menu/components/chart/antv-bar/index.jsx
+++ b/src/menu/components/chart/antv-bar/index.jsx
@@ -1,227 +1,552 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { InputItem, Icon, Checkbox, List, Button } from 'antd-mobile'
-// import { createForm } from 'rc-form'
+import { Chart } from '@antv/g2'
+import DataSet from '@antv/data-set'
+
+import asyncComponent from '@/utils/asyncComponent'
 
 import zhCN from '@/locales/zh-CN/mob.js'
 import enUS from '@/locales/en-US/mob.js'
-import Utils from '@/utils/utils.js'
-import ContentUpdate from '@/mob/contupdate'
-import mklogo from '@/assets/mobimg/mklogo.png'
+// import ChartCompileForm from './chartcompile'
 import './index.scss'
 
-const CheckboxItem = Checkbox.CheckboxItem
+const SettingComponent = asyncComponent(() => import('@/menu/datasourcecomponent'))
+const SearchComponent = asyncComponent(() => import('@/menu/searchcomponent'))
+const ActionComponent = asyncComponent(() => import('@/menu/actioncomponent'))
 
-class MobLogin extends Component {
+class antvBarLineChart extends Component {
   static propTpyes = {
+    config: PropTypes.object,
     card: PropTypes.object,
     editId: PropTypes.any,
     triggerEdit: PropTypes.func,
     updateConfig: PropTypes.func,
-    onDoubleClick: PropTypes.func
   }
 
   state = {
     dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    rember: true,
-    param: {
-      type: 'login',
-      subtype: 'mob-login-1',
-      box: { uuid: Utils.getuuid(), eleType: 'box', style: {color: '#ffffff', backgroundImage: 'linear-gradient(#378DBE, #46C29E, #48A9D6)'}},
-      logo: { uuid: Utils.getuuid(), eleType: 'img', content: mklogo, style: {marginTop: '17vh', marginBottom: '15px'} },
-      title: { uuid: Utils.getuuid(), eleType: 'text', content: '鏄庣鍟嗕笟鏅鸿兘寮�鏀惧钩鍙�', style: {fontSize: '20px', fontWeight: 'bold', color: '#ffffff', textAlign: 'center', marginTop: '15px', marginBottom: '30px'}},
-      login: { uuid: Utils.getuuid(), eleType: 'button', content: '鐧诲綍', style: {fontSize: '18px', color: '#ffffff', textAlign: 'center', lineHeight: 2.4, borderRadius: '25px', marginBottom: '15vh'}},
-      copyright: { uuid: Utils.getuuid(), eleType: 'textarea', content: 'Copyright漏2017  鎵�鏈夌浉鍏崇増鏉冨綊  鍖椾含鏄庣鏅崕淇℃伅鎶�鏈湁闄愬叕鍙�', style: {fontSize: '12px', color: '#ffffff', textAlign: 'center'} }
-    }
+    card: null,
+    visible: true
   }
 
   UNSAFE_componentWillMount () {
-    const { card } = this.props
+    const { card, config } = this.props
 
+    console.log(config)
     if (card.isNew) {
-      // this.props.updateConfig({...param, ...card})
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        subtype: card.subtype,
+        setting: {span: 12, height: 400},
+        columns: [],
+        scripts: [],
+        search: [],
+        action: [],
+        plot: {type: card.type, Xaxis: '', Yaxis: null}
+      }
+      this.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
     }
+  }
+
+  componentDidMount () {
+    this.viewrender()
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    if (!is(fromJS(this.props.plot), fromJS(nextProps.plot))) {
+      this.setState({}, () => {
+        this.viewrender()
+      })
+    }
+  }
+
+  getdata = (X_axis, Y_axis) => {
+    let data = []
+    let xdata = ['鍛ㄤ竴', '鍛ㄤ簩', '鍛ㄤ笁', '鍛ㄥ洓', '鍛ㄤ簲', '鍛ㄥ叚', '鍛ㄦ棩']
+    let point = 7
+
+    for (let i = 0; i < point; i++) {
+      let item = {}
+
+      item[X_axis] = xdata[i]
+
+      if (typeof(Y_axis) === 'string') {
+        item[Y_axis] = Math.floor(Math.random() * 5 * (i + 1)) + i
+      } else {
+        Y_axis.forEach(y => {
+          item[y] = Math.floor(Math.random() * 5 * (i + 1)) + i
+        })
+      }
+
+      data.push(item)
+    }
+
+    return data
+  }
+
+  viewrender = () => {
+    const { card } = this.state
+
+    if (card.plot.type === 'line') {
+      this.linerender()
+    } else if (card.plot.type === 'bar') {
+      this.barrender()
+    }
+  }
+
+  linerender = () => {
+    const { plot, config } = this.props
+
+    let transfield = {}
+    config.columns.forEach(col => {
+      if (col.field) {
+        transfield[col.field] = col.label
+      }
+    })
+
+    let X_axis = plot.Xaxis || 'x'
+    let Y_axis = plot.Yaxis || ['y']
+
+    let data = this.getdata(X_axis, Y_axis)
+
+    if (plot.enabled !== 'true') {
+      const ds = new DataSet()
+      const dv = ds.createView().source(data)
+
+      dv.transform({
+        type: 'fold',
+        fields: [...Y_axis],
+        key: 'key',
+        value: 'value'
+      })
+
+      if (plot.Xaxis) {
+        dv.transform({
+          type: 'map',
+          callback(row) {
+            row.key = transfield[row.key]
+            return row
+          },
+        })
+      }
+
+      const chart = new Chart({
+        container: plot.uuid,
+        autoFit: true,
+        height: plot.height || 400
+      })
+  
+      chart.data(dv.rows)
+  
+      if (plot.coordinate !== 'polar') {
+        chart.scale(X_axis, {
+          range: [0, 1]
+        })
+      }
+      chart.scale('value', {
+        nice: true
+      })
+  
+      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(`${X_axis}*value`)
+        .color('key')
+        .shape(plot.shape || 'smooth')
+  
+      if (plot.label === 'true') {
+        _chart.label('value')
+      }
+
+      if (plot.point === 'true') {
+        chart
+          .point()
+          .position(`${X_axis}*value`)
+          .color('key')
+          .size(3)
+          .shape('circle')
+      }
+      chart.render()
+    } else {
+      this.customrender(data, transfield)
+    }
+  }
+
+  customrender = (data, transfield) => {
+    const { plot } = this.props
+
+    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: plot.uuid,
+      autoFit: true,
+      height: plot.height || 400
+    })
+
+    chart.data(dv.rows)
+
+    if (plot.coordinate !== 'polar' && barfields.length === 0) {
+      chart.scale(plot.Xaxis, {
+        range: [0, 1]
+      })
+    }
+
+    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
+      })
+    }
+
+    chart.scale({
+      nice: true
+    })
+
+    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)
+
+        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)
+
+        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()
+  }
+
+  barrender = () => {
+    const { card } = this.state
+
+    let plot = {...card.plot, height: card.setting.height - 70}
+
+    let transfield = {}
+    card.columns.forEach(col => {
+      if (col.field) {
+        transfield[col.field] = col.label
+      }
+    })
+    let X_axis = plot.Xaxis || 'x'
+    let Y_axis = plot.Yaxis || ['y']
+
+    let data = this.getdata(X_axis, Y_axis)
+    console.log(plot)
+    console.log(data)
+    
+    if (plot.enabled !== 'true') {
+      const ds = new DataSet()
+      const dv = ds.createView().source(data)
+  
+      dv.transform({
+        type: 'fold',
+        fields: [...Y_axis],
+        key: 'key',
+        value: 'value'
+      })
+  
+      if (plot.Xaxis) {
+        dv.transform({
+          type: 'map',
+          callback(row) {
+            row.key = transfield[row.key]
+            return row
+          },
+        })
+      }
+      
+      const chart = new Chart({
+        container: card.uuid,
+        autoFit: true,
+        height: plot.height || 400
+      })
+  
+      console.log(dv.rows)
+      chart.data(dv.rows)
+  
+      chart.scale('value', {
+        nice: true
+      })
+  
+      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
+        })
+      }
+  
+      if (plot.adjust !== 'stack') {
+        let _chart = chart
+          .interval()
+          .position(`${X_axis}*value`)
+          .color('key')
+          .adjust([
+            {
+              type: 'dodge',
+              marginRatio: 0
+            }
+          ])
+          .shape(plot.shape || 'rect')
+  
+        if (plot.label === 'true') {
+          _chart.label('value')
+        }
+      } else if (plot.adjust === 'stack') {
+        let _chart = chart
+          .interval()
+          .position(`${X_axis}*value`)
+          .color('key')
+          .adjust('stack')
+          .shape(plot.shape || 'rect')
+  
+        if (plot.label === 'true') {
+          _chart.label('value')
+        }
+      }
+  
+      chart.render()
+    } else {
+      this.customrender(data, transfield)
+    }
+  }
+
+  plotChange = (_plot) => {
+    const { config } = this.props
+
+    if (_plot.datatype === 'statistics') {
+      _plot.Yaxis = [_plot.InfoValue]
+    }
+    
+    let _charts = fromJS(config.charts).toJS()
+
+    _charts = _charts.map(item => {
+      if (item.uuid === _plot.uuid) {
+        if (!is(fromJS(item), fromJS(_plot))) {
+          let _element = document.getElementById(_plot.uuid)
+          if (_element) {
+            _element.innerHTML = ''
+          }
+        }
+        return _plot
+      }
+      return item
+    })
+
+    this.props.plotchange({...config, charts: _charts})
   }
 
   shouldComponentUpdate (nextProps, nextState) {
     return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
   }
 
-  onChange = (e) => {
-    const { rember } = this.state
-    e.stopPropagation()
-
+  updateComponent = (component) => {
     this.setState({
-      rember: !rember
+      card: component
     })
+    this.props.updateConfig(component)
   }
 
-  onChangeLang = (value) => {
-    this.setState({
-      lang: value
-    })
-  }
-
-  editLogo = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.logo.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.logo.uuid,
-      items: ['margin']
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editTitle = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.title.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.title.uuid,
-      items: ['font', 'margin'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editMsg = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.copyright.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.copyright.uuid,
-      items: ['font'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editLogin = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.login.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.login.uuid,
-      items: ['font', 'background', 'border', 'margin']
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editBox = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.box.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.box.uuid,
-      items: ['font', 'padding', 'background'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  updateContent = (card) => {
-    Object.keys(card).forEach(key => {
-      if (card[key] === null) {
-        delete card[key]
-      }
-    })
-    this.props.updateConfig(card)
-  }
-
-  render () {
-    const { card, editId } = this.props
-    // const { getFieldProps } = this.props.form
-    const { rember } = this.state
-
-    if (!card.box) return null
-
-    let logoStyle = card.logo && card.logo.style ? fromJS(card.logo.style).toJS() : null
-    if (logoStyle && logoStyle.marginTop && /vh$/ig.test(logoStyle.marginTop)) {
-      let percent = parseInt(logoStyle.marginTop)
-      logoStyle.marginTop = `calc(${(percent / 100) * 615}px)`
-    }
-    if (logoStyle && logoStyle.marginBottom && /vh$/ig.test(logoStyle.marginBottom)) {
-      let percent = parseInt(logoStyle.marginBottom)
-      logoStyle.marginBottom = `calc(${(percent / 100) * 625}px)`
-    }
-
-    let titleStyle = card.title && card.title.style ? fromJS(card.title.style).toJS() : null
-    if (titleStyle && titleStyle.marginTop && /vh$/ig.test(titleStyle.marginTop)) {
-      let percent = parseInt(titleStyle.marginTop)
-      titleStyle.marginTop = `calc(${(percent / 100) * 615}px)`
-    }
-    if (titleStyle && titleStyle.marginBottom && /vh$/ig.test(titleStyle.marginBottom)) {
-      let percent = parseInt(titleStyle.marginBottom)
-      titleStyle.marginBottom = `calc(${(percent / 100) * 615}px)`
-    }
-    
-    let loginStyle = fromJS(card.login.style).toJS()
-    if (loginStyle.marginTop && /vh$/ig.test(loginStyle.marginTop)) {
-      let percent = parseInt(loginStyle.marginTop)
-      loginStyle.marginTop = `calc(${(percent / 100) * 615}px)`
-    }
-    if (loginStyle.marginBottom && /vh$/ig.test(loginStyle.marginBottom)) {
-      let percent = parseInt(loginStyle.marginBottom)
-      loginStyle.marginBottom = `calc(${(percent / 100) * 615}px)`
-    }
+  render() {
+    const { card } = this.state
+    const { config } = this.props
 
     return (
-      <div className="mob-login-1" onClick={this.editBox} style={card.box.style}>
-        {card.logo ? <div className={'logo ' + (editId === card.logo.uuid ? 'editing' : '')} style={logoStyle} onClick={this.editLogo}>
-          <ContentUpdate element={card.logo} updateContent={(ele) => this.updateContent({...card, logo: ele})}/>
-          <img src={card.logo.content} alt=""/>
-        </div> : null}
-        {card.title ? <div className={'plat-name ' + (editId === card.title.uuid ? 'editing' : '')} style={titleStyle} onClick={this.editTitle}>
-          <ContentUpdate element={card.title} updateContent={(ele) => this.updateContent({...card, title: ele})}/>
-          {card.title.content}
-        </div> : null}
-        <InputItem
-          placeholder={"UserName"}
-          prefixListCls="mk-login-item am-list"
-          disabled={true}
-        >
-          <Icon type="check-circle-o" />
-        </InputItem>
-        <InputItem
-          placeholder="Password"
-          prefixListCls="mk-login-item am-list"
-          type={'password'}
-          disabled={true}
-        >
-          <Icon type="check-circle" />
-        </InputItem>
-        <div className="other-setting">
-          <CheckboxItem checked={rember} onChange={this.onChange}>
-            <span onClick={this.onChange}>璁颁綇瀵嗙爜</span>
-          </CheckboxItem>
-          {/* <Picker data={langs} value={lang} cols={1} onChange={this.onChangeLang} className="forss">
-            <List.Item>{lang}</List.Item>
-          </Picker> */}
-          <List.Item className="lang">涓枃绠�浣�</List.Item>
-          <div className="clear-both"></div>
+      <div className="line-chart-edit-box" style={{height: card.setting.height || 400}}>
+        <SettingComponent
+          config={{...card, tables: config.tables}}
+          MenuID={config.uuid}
+          tableFields={config.tableFields || []}
+          permFuncField={config.permFuncField || []}
+          updateConfig={this.updateComponent}
+        />
+        <div className="chart-header">
+          <span className="chart-title">{card.setting.title || ''}</span>
+          <SearchComponent
+            menu={{MenuID: config.uuid, MenuName: config.MenuName}}
+            config={card}
+            sysRoles={config.sysRoles}
+            optionLibs={null}
+            updatesearch={this.updateComponent}
+          />
         </div>
-        <Button 
-          type="primary"
-          className={'login ' + (editId === card.login.uuid ? 'editing' : '')} 
-          onDoubleClick={() => this.props.doubleClickCard(card.login)}
-          style={loginStyle}
-          onClick={this.editLogin}
-        >
-          <ContentUpdate element={card.login} deletable={false} updateContent={(ele) => this.updateContent({...card, login: ele})}/>
-          {card.login.content}
-        </Button>
-        {card.copyright ? <div className={'company-msg ' + (editId === card.copyright.uuid ? 'editing' : '')} style={card.copyright.style} onClick={this.editMsg}>
-          <ContentUpdate element={card.copyright} updateContent={(ele) => this.updateContent({...card, copyright: ele})}/>
-          {card.copyright.content}
-        </div> : null}
+        <ActionComponent
+          menu={{ MenuID: config.uuid, MenuName: config.MenuName, MenuNo: config.MenuNo, fstMenuList: config.fstMenuList }}
+          config={card}
+          tabs={[]}
+          usefulFields={config.permFuncField || []}
+          // setSubConfig={(_btn) => this.setSubConfig(_btn, 'button')}
+          updateaction={this.updateComponent}
+        />
+        <div className="canvas" id={card.uuid}></div>
+        {/* <ChartCompileForm
+          plot={plot}
+          type={plot.chartType}
+          config={this.props.config}
+          dict={this.state.dict}
+          plotchange={this.plotChange}
+        /> */}
       </div>
     )
   }
 }
 
-// export default createForm()(MobLogin)
-export default MobLogin
\ No newline at end of file
+export default antvBarLineChart
\ No newline at end of file
diff --git a/src/menu/components/chart/antv-bar/index.scss b/src/menu/components/chart/antv-bar/index.scss
index 4ce0042..33e95af 100644
--- a/src/menu/components/chart/antv-bar/index.scss
+++ b/src/menu/components/chart/antv-bar/index.scss
@@ -1,192 +1,23 @@
-.mob-login-1 {
+.line-chart-edit-box {
   position: relative;
-  width: 100%;
-  min-height: 100%;
-  overflow-x: hidden;
-  background-repeat: no-repeat;
-  background-size: cover;
-  background-position: center center;
-  border-top: 1px solid transparent;
-
-  .logo {
-    position: relative;
-    font-size: 14px;
-    max-width: 280px;
-    min-height: 10px;
-    margin: 0 auto;
-    text-align: center;
-    line-height: 1.5;
-    border: 1px dotted transparent;
-    img {
-      max-width: 100%;
-    }
-  }
-  .logo.editing {
-    border: 1px solid #1890ff;
-    box-shadow: 0px 0px 2px #1890ff;
-  }
-  .logo:not(.editing):hover {
-    border-color: #535353;
+  margin-bottom: 30px;
+  border: 1px solid #e8e8e8;
+  
+  .canvas {
+    margin: 0px;
+    padding: 10px 15px;
   }
 
-  .plat-name {
-    position: relative;
-    max-width: 280px;
-    min-height: 10px;
-    margin: 0 auto;
-    margin-top: 15px;
-    margin-bottom: 30px;
-    text-align: center;
-    line-height: 1.5;
-    font-size: 20px;
-    color: #ffffff;
-    font-weight: bold;
-    letter-spacing: 0px;
-    border: 1px dotted transparent;
-  }
-  .plat-name.editing {
-    border: 1px solid #1890ff;
-    box-shadow: 0px 0px 2px #1890ff;
-  }
-  .plat-name:not(.editing):hover {
-    border-color: #535353;
-  }
+  .chart-header {
+    height: 50px;
+    border-bottom: 1px solid #e8e8e8;
+    overflow: hidden;
 
-  .mk-login-item.am-list-item {
-    position: relative;
-    z-index: 1;
-    width: 245px;
-    font-size: 14px;
-    max-width: 270px;
-    line-height: 1.5;
-    margin: 0 auto;
-    margin-bottom: 10px;
-    border-radius: 30px;
-    background-color: rgba(255, 255, 255, 0.3);
-    .am-input-label {
-      width: 30px;
-      color: inherit;
-      padding-top: 10px;
-    }
-    input {
-      color: inherit;
-    }
-    input::-webkit-input-placeholder {
-      color: inherit;
-    }
-    input:-moz-placeholder {
-      color: inherit;
-    }
-    input::-moz-placeholder {
-      color: inherit;
-    }
-    input:-ms-input-placeholder {
-      color: inherit;
-    }
-
-    .am-input-control input:disabled {
-      background-color: transparent;
-    }
-  }
-  .am-list-item:not(:last-child) .am-list-line {
-    border: none;
-  }
-  .other-setting {
-    position: relative;
-    z-index: 1;
-    font-size: 14px;
-    width: 245px;
-    max-width: 270px;
-    line-height: 1.5;
-    margin: 0 auto;
-    margin-bottom: 10px;
-    .am-list-item {
+    .chart-title {
+      font-size: 16px;
       float: left;
-      background: transparent;
-      width: 50%;
-      padding: 0;
-      .am-list-thumb:first-child {
-        margin-right: 5px;
-        cursor: pointer;
-
-        .am-checkbox-inner {
-          width: 18px;
-          height: 18px;
-        }
-        .am-checkbox-inner:after {
-          width: 5px;
-          height: 9px;
-        }
-      }
-      .am-list-line .am-list-content {
-        font-size: 14px;
-        color: inherit;
-        cursor: pointer;
-      }
-      .am-list-extra {
-        display: none;
-      }
+      line-height: 50px;
+      margin-left: 10px;
     }
-    
-    .am-list-item.lang {
-      float: right;
-      .am-list-line {
-        padding-right: 10px;
-        .am-list-content {
-          text-align: right;
-          cursor: default;
-        }
-      }
-    }
-  }
-  .am-button {
-    position: relative;
-    z-index: 1;
-    width: 245px;
-    max-width: 270px;
-    margin: 0 auto;
-    border: 1px dotted transparent;
-    overflow: visible;
-    letter-spacing: 0px;
-    background-repeat: no-repeat;
-    background-size: cover;
-    background-position: center center;
-    
-    span {
-      font-style: inherit;
-      font-weight: inherit;
-    }
-  }
-  .am-button:hover {
-    color: #fff;
-    border-color: #535353;
-  }
-  .company-msg {
-    max-width: 280px;
-    min-height: 10px;
-    margin: 0 auto;
-    font-size: 12px;
-    color: #fafafa;
-    text-align: center;
-    line-height: 1.5;
-    letter-spacing: 0px;
-    border: 1px dotted transparent;
-  }
-  .company-msg.editing {
-    border: 1px solid #1890ff;
-    box-shadow: 0px 0px 2px #1890ff;
-  }
-  .company-msg:not(.editing):hover {
-    border-color: #535353;
   }
 }
-.am-picker-popup-wrap {
-  left: calc(50vw - 305px);
-  right: calc(50vw - 45px);
-  bottom: 54px;
-  overflow: hidden;
-}
-.clear-both {
-  float: none!important;
-  clear: both;
-}
\ No newline at end of file
diff --git a/src/menu/datasourcecomponent/index.jsx b/src/menu/datasourcecomponent/index.jsx
new file mode 100644
index 0000000..4c285ae
--- /dev/null
+++ b/src/menu/datasourcecomponent/index.jsx
@@ -0,0 +1,93 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal } from 'antd'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import VerifyCard from './verifycard'
+import './index.scss'
+
+class DataSource extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    MenuID: PropTypes.string,
+    tableFields: PropTypes.any,
+    permFuncField: PropTypes.any,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    sourcelist: [],
+    visible: false,
+    loading: false,
+    setting: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    this.setState({setting: fromJS(config.setting).toJS()})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  editDataSource = () => {
+    this.setState({
+      visible: true
+    })
+  }
+
+  verifySubmit = () => {
+    const { config } = this.props
+
+    this.setState({loading: true})
+    this.verifyRef.submitDataSource().then(res => {
+
+      this.setState({loading: false, visible: false})
+      this.props.updateConfig({...config, ...res})
+    }, () => {
+      this.setState({loading: false})
+    })
+  }
+
+  render () {
+    const { config } = this.props
+    const { visible, dict, loading } = this.state
+
+    return (
+      <div className="model-datasource">
+        <Icon type="setting" onClick={() => this.editDataSource()} />
+        <Modal
+          wrapClassName="model-datasource-verify-modal popview-modal"
+          title={'鏁版嵁婧愰厤缃�'}
+          visible={visible}
+          width={'75vw'}
+          maskClosable={false}
+          style={{minWidth: '900px', maxWidth: '1200px'}}
+          okText={dict['model.submit']}
+          cancelText={dict['model.cancel']}
+          onOk={this.verifySubmit}
+          confirmLoading={loading}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <VerifyCard
+            dict={dict}
+            config={config}
+            tableFields={this.props.tableFields}
+            permFuncField={this.props.permFuncField}
+            menuId={this.props.config.uuid}
+            searches={config.search}
+            wrappedComponentRef={(inst) => this.verifyRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default DataSource
\ No newline at end of file
diff --git a/src/menu/datasourcecomponent/index.scss b/src/menu/datasourcecomponent/index.scss
new file mode 100644
index 0000000..c994031
--- /dev/null
+++ b/src/menu/datasourcecomponent/index.scss
@@ -0,0 +1,94 @@
+.model-datasource {
+  position: absolute;
+  right: 7px;
+  top: 5px;
+  z-index: 1;
+
+  >.anticon-setting {
+    font-size: 18px;
+    padding: 10px;
+  }
+
+  .model-input-group-wrapper {
+    padding: 0 20px;
+    display: inline-block;
+    width: 100%;
+    text-align: start;
+    vertical-align: top;
+    margin-bottom: 15px;
+
+    .model-input-wrapper {
+      position: relative;
+      display: table;
+      width: 100%;
+      border-collapse: separate;
+      border-spacing: 0;
+
+      .model-input-value {
+        display: table-cell;
+        width: 100%;
+        border: 1px solid #d9d9d9;
+        border-radius: 4px 0px 0px 4px;
+        overflow: hidden;
+        text-overflow:ellipsis;
+        white-space: nowrap;
+        padding: 2px 10px;
+        color: #ffffff;
+      }
+
+      .model-input-group-addon {
+        display: table-cell;
+        width: 1px;
+        position: relative;
+        padding: 0 11px;
+        color: rgba(0, 0, 0, 0.65);
+        font-weight: normal;
+        font-size: 14px;
+        line-height: 1;
+        text-align: center;
+        background-color: #fafafa;
+        border: 1px solid #d9d9d9;
+        border-radius: 0px 4px 4px 0px;
+        white-space: nowrap;
+      }
+
+      .model-input-insert {
+        display: table-cell;
+        width: 100%;
+        border: 1px dotted #d9d9d9;
+        border-radius: 4px;
+        text-align: center;
+        cursor: pointer;
+
+        .anticon-plus {
+          padding: 6px;
+          font-size: 16px;
+          color: rgb(38, 194, 129);
+        }
+      }
+    }
+    .anticon-setting {
+      margin-right: 5px;
+      padding: 6px;
+      cursor: pointer;
+    }
+    .anticon-setting:hover {
+      color: #1890ff;
+    }
+    .anticon-close {
+      padding: 6px;
+      cursor: pointer;
+    }
+    .anticon-close:hover {
+      color: #ff4d4f;
+    }
+  }
+}
+.model-datasource-verify-modal {
+  .ant-modal {
+    top: 50px;
+    .ant-modal-body {
+      max-height: calc(100vh - 190px);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/datasourcecomponent/verifycard/columnform/index.jsx b/src/menu/datasourcecomponent/verifycard/columnform/index.jsx
new file mode 100644
index 0000000..c8ef7bb
--- /dev/null
+++ b/src/menu/datasourcecomponent/verifycard/columnform/index.jsx
@@ -0,0 +1,145 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Select, Button, Input } from 'antd'
+import './index.scss'
+
+
+class UniqueForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,       // 瀛楀吀椤�
+    columnChange: PropTypes.func  // 淇敼鍑芥暟
+  }
+
+  state = {
+    editItem: null // 缂栬緫鍏冪礌
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record
+    })
+
+    this.props.form.setFieldsValue({
+      label: record.label,
+      field: record.field,
+      datatype: record.datatype
+    })
+  }
+
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
+
+        this.setState({
+          editItem: null
+        }, () => {
+          this.props.columnChange(values)
+        })
+        this.props.form.setFieldsValue({
+          label: '',
+          field: ''
+        })
+      }
+    })
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="verify-form" id="verifycard1">
+        <Row gutter={24}>
+          <Col span={7}>
+            <Form.Item label={'鍚嶇О'}>
+              {getFieldDecorator('label', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + '鍚嶇О!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={'瀛楁'}>
+              {getFieldDecorator('field', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + '瀛楁!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={'鏁版嵁绫诲瀷'}>
+              {getFieldDecorator('datatype', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.select'] + '鏁版嵁绫诲瀷!'
+                  }
+                ]
+              })(
+                <Select>
+                  <Select.Option value="Nvarchar(50)"> Nvarchar(50) </Select.Option>
+                  <Select.Option value="Nvarchar(100)"> Nvarchar(100) </Select.Option>
+                  <Select.Option value="Nvarchar(512)"> Nvarchar(512) </Select.Option>
+                  <Select.Option value="Nvarchar(1024)"> Nvarchar(1024) </Select.Option>
+                  <Select.Option value="Nvarchar(2048)"> Nvarchar(2048) </Select.Option>
+                  <Select.Option value="Nvarchar(max)"> Nvarchar(max) </Select.Option>
+                  <Select.Option value="Int"> Int </Select.Option>
+                  <Select.Option value="Decimal(18,0)"> Decimal(18,0) </Select.Option>
+                  <Select.Option value="Decimal(18,1)"> Decimal(18,1) </Select.Option>
+                  <Select.Option value="Decimal(18,2)"> Decimal(18,2) </Select.Option>
+                  <Select.Option value="Decimal(18,3)"> Decimal(18,3) </Select.Option>
+                  <Select.Option value="Decimal(18,4)"> Decimal(18,4) </Select.Option>
+                  <Select.Option value="Decimal(18,5)"> Decimal(18,5) </Select.Option>
+                  <Select.Option value="Decimal(18,6)"> Decimal(18,6) </Select.Option>
+                  <Select.Option value="Decimal(18,7)"> Decimal(18,7) </Select.Option>
+                  <Select.Option value="Decimal(18,8)"> Decimal(18,8) </Select.Option>
+                  <Select.Option value="Decimal(18,9)"> Decimal(18,9) </Select.Option>
+                  <Select.Option value="Decimal(18,10)"> Decimal(18,10) </Select.Option>
+                  <Select.Option value="Decimal(18,11)"> Decimal(18,11) </Select.Option>
+                  <Select.Option value="Decimal(18,12)"> Decimal(18,12) </Select.Option>
+                  <Select.Option value="Decimal(18,13)"> Decimal(18,13) </Select.Option>
+                  <Select.Option value="Decimal(18,14)"> Decimal(18,14) </Select.Option>
+                  <Select.Option value="Decimal(18,15)"> Decimal(18,15) </Select.Option>
+                  <Select.Option value="Decimal(18,16)"> Decimal(18,16) </Select.Option>
+                  <Select.Option value="Decimal(18,17)"> Decimal(18,17) </Select.Option>
+                  <Select.Option value="Decimal(18,18)"> Decimal(18,18) </Select.Option>
+                  {/* <Select.Option value="date"> date </Select.Option> */}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={3} className="add">
+            <Button onClick={this.handleConfirm} type="primary" className="mk-green">
+              淇濆瓨
+            </Button>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(UniqueForm)
\ No newline at end of file
diff --git a/src/menu/datasourcecomponent/verifycard/columnform/index.scss b/src/menu/datasourcecomponent/verifycard/columnform/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/menu/datasourcecomponent/verifycard/columnform/index.scss
diff --git a/src/menu/datasourcecomponent/verifycard/customscript/index.jsx b/src/menu/datasourcecomponent/verifycard/customscript/index.jsx
new file mode 100644
index 0000000..996e2ff
--- /dev/null
+++ b/src/menu/datasourcecomponent/verifycard/customscript/index.jsx
@@ -0,0 +1,231 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Button, notification, Select } from 'antd'
+
+import Utils from '@/utils/utils.js'
+import CodeMirror from '@/templates/zshare/codemirror'
+import './index.scss'
+
+class CustomForm extends Component {
+  static propTpyes = {
+    type: PropTypes.string,         // 鑿滃崟绫诲瀷
+    dict: PropTypes.object,         // 瀛楀吀椤�
+    setting: PropTypes.object,      // 璁剧疆
+    searches: PropTypes.array,      // 鎼滅储鏉′欢
+    swhere: PropTypes.string,       // where鏉′欢
+    arr_field: PropTypes.string,    // 鍒楀瓧娈�
+    regoptions: PropTypes.array,    // 姝e垯鏇挎崲
+    systemScripts: PropTypes.array, // 绯荤粺鑴氭湰
+    scriptSubmit: PropTypes.func,   // 鑴氭湰楠岃瘉鍚庢彁浜�
+    scriptsChange: PropTypes.func   // 鑴氭湰楠岃瘉
+  }
+
+  state = {
+    editItem: null,
+    loading: false,
+    usefulFields: ''
+  }
+
+  UNSAFE_componentWillMount() {
+    const { searches } = this.props
+
+    let _usefulFields = []
+    searches.forEach(item => {
+      if (!item.field) return
+
+      if (item.type === 'group') {
+        if (item.transfer === 'true') {
+          _usefulFields.push(item.field)
+        }
+        _usefulFields.push(item.datefield)
+        _usefulFields.push(item.datefield + '1')
+      } else if (['dateweek', 'datemonth', 'daterange'].includes(item.type)) {
+        _usefulFields.push(item.field)
+        _usefulFields.push(item.field + '1')
+      } else if (_usefulFields.includes(item.field)) {
+        _usefulFields.push(item.field + '1')
+      } else {
+        _usefulFields.push(item.field)
+      }
+    })
+
+    this.setState({
+      usefulFields: _usefulFields.join(', ')
+    })
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record
+    })
+
+    this.props.form.setFieldsValue({
+      sql: record.sql
+    })
+  }
+
+  handleCancel = () => {
+    this.setState({
+      editItem: null
+    })
+    this.props.form.setFieldsValue({
+      sql: ''
+    })
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
+
+        let _quot = values.sql.match(/'{1}/g)
+        let _lparen = values.sql.match(/\({1}/g)
+        let _rparen = values.sql.match(/\){1}/g)
+
+        _quot = _quot ? _quot.length : 0
+        _lparen = _lparen ? _lparen.length : 0
+        _rparen = _rparen ? _rparen.length : 0
+
+        if (_quot % 2 !== 0) {
+          notification.warning({
+            top: 92,
+            message: 'sql涓璡'蹇呴』鎴愬鍑虹幇',
+            duration: 5
+          })
+          return
+        } else if (_lparen !== _rparen) {
+          notification.warning({
+            top: 92,
+            message: 'sql涓�()蹇呴』鎴愬鍑虹幇',
+            duration: 5
+          })
+          return
+        } else if (/--/ig.test(values.sql)) {
+          notification.warning({
+            top: 92,
+            message: '鑷畾涔塻ql璇彞涓紝涓嶅彲鍑虹幇瀛楃 -- 锛屾敞閲婅鐢� /*鍐呭*/',
+            duration: 5
+          })
+          return
+        }
+
+        let error = Utils.verifySql(values.sql, 'customscript')
+
+        if (error) {
+          notification.warning({
+            top: 92,
+            message: 'sql涓笉鍙娇鐢�' + error,
+            duration: 5
+          })
+          return
+        }
+
+        this.setState({loading: true})
+        this.props.scriptsChange(values).then(() => {
+          this.setState({
+            editItem: null,
+            loading: false
+          })
+          this.props.form.setFieldsValue({
+            sql: ''
+          })
+          this.props.scriptSubmit(values)
+        })
+      }
+    })
+  }
+
+  selectScript = (value, option) => {
+    let _sql = this.props.form.getFieldValue('sql')
+    if (_sql) {
+      _sql = _sql + ` 
+
+      `
+    }
+
+    _sql = _sql.replace(/\s{6}$/, '')
+    _sql = _sql + `/*${option.props.children}*/
+    `
+    _sql = _sql.replace(/\s{4}$/, '')
+    _sql = _sql + value
+
+    this.props.form.setFieldsValue({
+      sql: _sql
+    })
+  }
+
+  render() {
+    const { systemScripts, setting } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { usefulFields } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="modal-menu-setting-script">
+        <Row gutter={24}>
+          {setting.tableName ? <Col span={8}>
+            <Form.Item label={'琛ㄥ悕'} style={{whiteSpace: 'nowrap', margin: 0}}>
+              {setting.tableName}
+            </Form.Item>
+          </Col> : null}
+          <Col span={16}>
+            <Form.Item label={'鎶ラ敊瀛楁'} style={{margin: 0}}>
+              ErrorCode, retmsg
+            </Form.Item>
+          </Col>
+          <Col span={24} className="sqlfield">
+            <Form.Item label={'鍙敤瀛楁'}>
+              id, bid, loginuid, sessionuid, userid, appkey, time_id, calendarDate, calendarDate1{usefulFields ? ', ' + usefulFields : ''}
+            </Form.Item>
+          </Col>
+          <Col span={10}>
+            <Form.Item label={'蹇嵎娣诲姞'} style={{marginBottom: 0}}>
+              <Select
+                showSearch
+                filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                onChange={this.selectScript}
+              >
+                {systemScripts.map((option, i) =>
+                  <Select.Option style={{whiteSpace: 'normal'}} key={i} value={option.value}>{option.name}</Select.Option>
+                )}
+              </Select>
+            </Form.Item>
+          </Col>
+          <Col span={6} className="add">
+            <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginTop: 5, marginBottom: 15, marginLeft: 30}}>
+              淇濆瓨
+            </Button>
+            <Button onClick={this.handleCancel} style={{marginTop: 5, marginBottom: 15, marginLeft: 10}}>
+              鍙栨秷
+            </Button>
+          </Col>
+          <Col span={24} className="sql">
+            <Form.Item label={'sql'}>
+              {getFieldDecorator('sql', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + 'sql!'
+                  }
+                ]
+              })(<CodeMirror />)}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(CustomForm)
\ No newline at end of file
diff --git a/src/menu/datasourcecomponent/verifycard/customscript/index.scss b/src/menu/datasourcecomponent/verifycard/customscript/index.scss
new file mode 100644
index 0000000..2a1d2d8
--- /dev/null
+++ b/src/menu/datasourcecomponent/verifycard/customscript/index.scss
@@ -0,0 +1,34 @@
+.modal-menu-setting-script {
+  .sqlfield {
+    .ant-form-item {
+      margin-bottom: 5px;
+    }
+    .ant-form-item-control {
+      line-height: 24px;
+    }
+    .ant-form-item-label {
+      line-height: 25px;
+    }
+    .ant-form-item-children {
+      line-height: 22px;
+    }
+    .ant-col-sm-8 {
+      width: 10.5%;
+    }
+    .ant-col-sm-16 {
+      width: 89.5%;
+    }
+  }
+  .sql {
+    .ant-col-sm-8 {
+      width: 10.5%;
+    }
+    .ant-col-sm-16 {
+      width: 89.5%;
+      padding-top: 4px;
+    }
+    .CodeMirror {
+      height: 350px;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/datasourcecomponent/verifycard/index.jsx b/src/menu/datasourcecomponent/verifycard/index.jsx
new file mode 100644
index 0000000..19276e6
--- /dev/null
+++ b/src/menu/datasourcecomponent/verifycard/index.jsx
@@ -0,0 +1,551 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Form, Tabs, Table, Popconfirm, Icon, notification, Modal, Typography, Spin } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+
+import asyncComponent from '@/utils/asyncComponent'
+import ColForm from './columnform'
+import CustomScriptsForm from './customscript'
+import SettingForm from './settingform'
+import SettingUtils from './utils'
+import './index.scss'
+
+const { TabPane } = Tabs
+const { Paragraph } = Typography
+
+const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
+
+class VerifyCard extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,          // 瀛楀吀椤�
+    tableFields: PropTypes.any,      // 鏁版嵁婧愪俊鎭�
+    permFuncField: PropTypes.any,    // 鏁版嵁婧愪俊鎭�
+    config: PropTypes.object,        // 鏁版嵁婧愪俊鎭�
+    menuId: PropTypes.string,        // 鑿滃崟Id
+    searches: PropTypes.array,       // 鎼滅储鏉′欢
+  }
+
+  state = {
+    columns: [],
+    activeKey: 'setting',
+    loading: false,
+    initsql: '',          // sql楠岃瘉鏃跺彉閲忓0鏄庡強璧嬪��
+    usefulfields: '',
+    defaultsql: '',         // 榛樿Sql
+    systemScripts: [{
+      name: '榛樿sql',
+      value: ''
+    }],
+    colColumns: [
+      {
+        title: '鍚嶇О',
+        dataIndex: 'label',
+        width: '25%'
+      },
+      {
+        title: '瀛楁',
+        dataIndex: 'field',
+        width: '25%'
+      },
+      {
+        title: '鏁版嵁绫诲瀷',
+        dataIndex: 'datatype',
+        width: '25%',
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        width: '25%',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          (<div>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <Popconfirm
+              title={this.props.dict['model.query.delete']}
+              okText={this.props.dict['model.confirm']}
+              cancelText={this.props.dict['model.cancel']}
+              onConfirm={() => this.deleteColumn(record)
+            }>
+              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
+            </Popconfirm>
+          </div>)
+      }
+    ],
+    scriptsColumns: [
+      {
+        title: 'SQL',
+        dataIndex: 'sql',
+        width: '60%',
+        render: (text) => (
+          <Paragraph copyable ellipsis={{ rows: 5, expandable: true }}>{text}</Paragraph>
+        )
+      },
+      {
+        title: '鐘舵��',
+        dataIndex: 'status',
+        width: '20%',
+        render: (text, record) => record.status === 'false' ?
+          (
+            <div>
+              {this.props.dict['model.status.forbidden']}
+              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
+            </div>
+          ) :
+          (
+            <div>
+              {this.props.dict['model.status.open']}
+              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
+            </div>
+          )
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        width: '20%',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          (<div>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+            <span className="operation-btn" onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
+            <span className="operation-btn" title={this.props.dict['model.status.change']} onClick={() => this.handleStatus(record)} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
+            <Popconfirm
+              title={this.props.dict['model.query.delete']}
+              okText={this.props.dict['model.confirm']}
+              cancelText={this.props.dict['model.cancel']}
+              onConfirm={() => this.deleteScript(record)
+            }>
+              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
+            </Popconfirm>
+          </div>)
+      }
+    ]
+  }
+
+  UNSAFE_componentWillMount() {
+    const { config } = this.props
+
+    this.setState({
+      columns: fromJS(config.columns).toJS(),
+      setting: fromJS(config.setting).toJS(),
+      scripts: fromJS(config.scripts).toJS()
+    })
+
+    this.getsysScript()
+  }
+
+  getsysScript = () => {
+    let _scriptSql = `Select distinct func+Remark as funcname,longparam, s.Sort from聽 s_custom_script s inner join (select OpenID from sapp where ID=@Appkey@) p on s.openid = case when s.appkey='' then s.openid else p.OpenID end order by s.Sort`
+
+    _scriptSql = Utils.formatOptions(_scriptSql)
+
+    let _sParam = {
+      func: 'sPC_Get_SelectedList',
+      LText: _scriptSql,
+      obj_name: 'data',
+      arr_field: 'funcname,longparam'
+    }
+    
+    _sParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+    _sParam.secretkey = Utils.encrypt(_sParam.LText, _sParam.timestamp)
+
+    _sParam.open_key = Utils.encrypt(_sParam.secretkey, _sParam.timestamp, true) // 浜戠鏁版嵁楠岃瘉
+    
+    Api.getSystemConfig(_sParam).then(res => {
+      if (res.status) {
+        let _scripts = []
+
+        res.data.forEach(item => {
+          let _item = {
+            name: item.funcname,
+            value: Utils.formatOptions(item.longparam, true)
+          }
+
+          _scripts.push(_item)
+        })
+
+        this.setState({
+          systemScripts: [...this.state.systemScripts, ..._scripts]
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  columnChange = (values) => {
+    let columns = fromJS(this.state.columns).toJS()
+
+    if (values.uuid) {
+      columns = columns.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      values.uuid = Utils.getuuid()
+      columns.push(values)
+    }
+
+    this.setState({ columns })
+  }
+
+  deleteColumn = (record) => {
+    this.setState({ columns: this.state.columns.filter(item => item.uuid !== record.uuid) })
+  }
+
+  deleteScript = (record) => {
+    this.setState({ scripts: this.state.scripts.filter(item => item.uuid !== record.uuid) })
+  }
+
+  handleEdit = (record, type) => {
+    if (type === 'scripts') {
+      this.scriptsForm.edit(record)
+    } else if (type === 'columns') {
+      this.contrastForm.edit(record)
+    }
+
+    let node = document.getElementById('model-verify-card-box-tab').parentNode
+
+    if (node && node.scrollTop) {
+      let inter = Math.ceil(node.scrollTop / 10)
+
+      let timer = setInterval(() => {
+        if (node.scrollTop - inter > 0) {
+          node.scrollTop = node.scrollTop - inter
+        } else {
+          node.scrollTop = 0
+          clearInterval(timer)
+        }
+      }, 10)
+    }
+  }
+
+  handleStatus = (record) => {
+    let scripts = fromJS(this.state.scripts).toJS()
+    record.status = record.status === 'false' ? 'true' : 'false'
+
+    scripts = scripts.map(item => {
+      if (item.uuid === record.uuid) {
+        return record
+      } else {
+        return item
+      }
+    })
+
+    this.setState({ scripts })
+  }
+
+  handleUpDown = (record, direction) => {
+    let scripts = fromJS(this.state.scripts).toJS()
+    let index = 0
+
+    scripts = scripts.filter((item, i) => {
+      if (item.uuid === record.uuid) {
+        index = i
+      }
+
+      return item.uuid !== record.uuid
+    })
+    if ((index === 0 && direction === 'up') || (index === scripts.length && direction === 'down')) {
+      return
+    }
+
+    if (direction === 'up') {
+      scripts.splice(index - 1, 0, record)
+    } else {
+      scripts.splice(index + 1, 0, record)
+    }
+
+    this.setState({ scripts })
+  }
+
+  scriptsChange = (values) => {
+    let scripts = fromJS(this.state.scripts).toJS()
+
+    if (values.uuid) {
+      scripts = scripts.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      scripts.push(values)
+    }
+
+    return new Promise((resolve, reject) => {
+      this.sqlverify(resolve, reject, false, scripts)
+    })
+  }
+
+  scriptSubmit = (values) => {
+    let scripts = fromJS(this.state.scripts).toJS()
+
+    if (values.uuid) {
+      scripts = scripts.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      values.uuid = Utils.getuuid()
+      scripts.push(values)
+    }
+
+    this.setState({ scripts })
+  }
+
+  changeTab = (val) => {
+    const { activeKey } = this.state
+
+    this.setState({loading: true})
+    if (activeKey === 'setting') {
+      this.settingForm.handleConfirm().then(res => {
+        this.setState({
+          setting: res
+        }, () => {
+          this.sqlverify(() => { // 楠岃瘉鎴愬姛
+            this.setState({
+              activeKey: val,
+              loading: false
+            })
+          }, () => {             // 楠岃瘉澶辫触
+            this.setState({
+              loading: false
+            })
+          }, true)
+        })
+      }, () => {
+        this.setState({loading: false})
+      })
+    } else if (activeKey === 'columns') {
+      this.setState({
+        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) {
+        _loading = true
+      } else if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) {
+        _loading = true
+      }
+
+      if (_loading) {
+        notification.warning({
+          top: 92,
+          message: '瀛樺湪鏈繚瀛樿剼鏈紝璇风偣鍑荤‘瀹氫繚瀛橈紝鎴栫偣鍑诲彇娑堟斁寮冧慨鏀癸紒',
+          duration: 5
+        })
+        this.setState({
+          loading: false
+        })
+        return
+      }
+
+      this.setState({
+        activeKey: val,
+        loading: false
+      })
+
+      // this.sqlverify(() => { // 楠岃瘉鎴愬姛
+      //   this.setState({
+      //     activeKey: val,
+      //     loading: false
+      //   })
+      // }, () => {             // 楠岃瘉澶辫触
+      //   this.setState({
+      //     loading: false
+      //   })
+      // }, true)
+    }
+  }
+
+  submitDataSource = () => {
+    const { activeKey, setting, columns, scripts } = this.state
+
+    return new Promise((resolve, reject) => {
+      if (activeKey === 'setting') {
+        this.settingForm.handleConfirm().then(res => {
+          this.setState({
+            setting: res
+          }, () => {
+            this.sqlverify(() => { resolve({setting: res, columns, scripts }) }, reject, false)
+          })
+        }, () => {
+          reject()
+        })
+      } else if (activeKey === 'columns') {
+        this.sqlverify(() => { resolve({setting, columns, scripts }) }, reject, false)
+      } else if (activeKey === 'scripts') {
+        let _loading = false
+        if (this.scriptsForm && this.scriptsForm.state.editItem) {
+          _loading = true
+        } else if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) {
+          _loading = true
+        }
+
+        if (_loading) {
+          notification.warning({
+            top: 92,
+            message: '瀛樺湪鏈繚瀛樿剼鏈紝璇风偣鍑荤‘瀹氫繚瀛橈紝鎴栫偣鍑诲彇娑堟斁寮冧慨鏀癸紒',
+            duration: 5
+          })
+          reject()
+          return
+        }
+
+        this.sqlverify(() => { resolve({setting, columns, scripts }) }, reject, false)
+      }
+    })
+  }
+
+  sqlverify = (resolve, reject, change = false, testScripts) => {
+    const { searches } = this.props
+    const { columns, setting, scripts } = this.state
+
+    let _scripts = scripts.filter(item => item.status !== 'false')
+
+    if (testScripts) {
+      _scripts = testScripts.filter(item => item.status !== 'false')
+    }
+    if (!change && setting.interType === 'inner' && !setting.innerFunc && setting.execute === 'false' && _scripts.length === 0) {
+      notification.warning({
+        top: 92,
+        message: '涓嶆墽琛岄粯璁ql鏃讹紝璇锋坊鍔犺嚜瀹氫箟鑴氭湰锛�',
+        duration: 5
+      })
+      reject()
+      return
+    }
+
+    if ((setting.interType === 'inner' && !setting.innerFunc && setting.execute !== 'false') || _scripts.length > 0) {
+      let param = {
+        func: 's_debug_sql',
+        LText: SettingUtils.getDebugSql(setting, _scripts, columns, searches)
+      }
+      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)
+      
+      Api.getLocalConfig(param).then(result => {
+        if (result.status) {
+          resolve()
+        } else {
+          reject()
+          Modal.error({
+            title: result.message
+          })
+        }
+      })
+    } else {
+      resolve()
+    }
+  }
+
+  updatefields = (columns) => {
+    this.setState({
+      columns: columns
+    })
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  render() {
+    const { columns, setting, scripts, colColumns, scriptsColumns, activeKey, loading } = this.state
+
+    return (
+      <div id="model-verify-card-box-tab">
+        {loading && <Spin size="large" />}
+        <Tabs activeKey={activeKey} className="verify-card-box" onChange={this.changeTab}>
+          <TabPane tab="鏁版嵁婧�" key="setting">
+            <SettingForm
+              menuId={this.props.menuId}
+              dict={this.props.dict}
+              permFuncField={this.props.permFuncField}
+              columns={columns}
+              setting={setting}
+              scripts={scripts}
+              wrappedComponentRef={(inst) => this.settingForm = inst}
+            />
+          </TabPane>
+          <TabPane tab="瀛楁闆�" key="columns">
+            <ColForm
+              dict={this.props.dict}
+              columnChange={this.columnChange}
+              wrappedComponentRef={(inst) => this.contrastForm = inst}
+            />
+            <FieldsComponent
+              config={{...this.props.config, columns}}
+              type="fields"
+              tableFields={this.props.tableFields}
+              updatefield={this.updatefields}
+            />
+            <Table
+              bordered
+              rowKey="uuid"
+              className="custom-table"
+              dataSource={columns}
+              columns={colColumns}
+              pagination={false}
+            />
+          </TabPane>
+          <TabPane tab="鑷畾涔夎剼鏈�" key="scripts">
+            <CustomScriptsForm
+              setting={setting}
+              searches={this.props.searches}
+              initsql={this.state.initsql}
+              dict={this.props.dict}
+              customScripts={scripts}
+              systemScripts={this.state.systemScripts}
+              scriptsChange={this.scriptsChange}
+              scriptSubmit={this.scriptSubmit}
+              wrappedComponentRef={(inst) => this.scriptsForm = inst}
+            />
+            <Table
+              bordered
+              rowKey="uuid"
+              className="custom-table"
+              dataSource={scripts}
+              columns={scriptsColumns}
+              pagination={false}
+            />
+          </TabPane>
+        </Tabs>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(VerifyCard)
\ No newline at end of file
diff --git a/src/menu/datasourcecomponent/verifycard/index.scss b/src/menu/datasourcecomponent/verifycard/index.scss
new file mode 100644
index 0000000..31e4d0a
--- /dev/null
+++ b/src/menu/datasourcecomponent/verifycard/index.scss
@@ -0,0 +1,81 @@
+#model-verify-card-box-tab {
+  .ant-spin {
+    position: absolute;
+    left: calc(50% - 16px);
+    top: 220px;
+    z-index: 1;
+  }
+  .verify-card-box {
+    .ant-tabs-nav-scroll {
+      text-align: center;
+    }
+    .ant-tabs-content {
+      min-height: 40vh;
+    }
+    table tr td {
+      word-wrap: break-word;
+      word-break: break-word;
+    }
+    .quickly-add {
+      position: relative;
+      width: 100px;
+      float: right;
+      top: -5px;
+      z-index: 2;
+    }
+    .verify-form {
+      .ant-input-number {
+        width: 100%;
+      }
+      .sql {
+        .ant-col-sm-8 {
+          width: 10.5%;
+        }
+        .ant-col-sm-16 {
+          width: 89.5%;
+          padding-top: 4px;
+        }
+      }
+      .sqlfield {
+        .ant-form-item {
+          margin-bottom: 5px;
+        }
+        .ant-form-item-control {
+          line-height: 24px;
+        }
+        .ant-form-item-label {
+          line-height: 25px;
+        }
+        .ant-form-item-children {
+          line-height: 22px;
+        }
+        .ant-col-sm-8 {
+          width: 10.5%;
+        }
+        .ant-col-sm-16 {
+          width: 89.5%;
+        }
+      }
+      .add {
+        padding-top: 4px;
+      }
+      .anticon-question-circle {
+        color: #c49f47;
+        margin-right: 3px;
+      }
+    }
+    .custom-table .ant-empty {
+      margin: 20px 8px!important;
+    }
+    .errorval {
+      display: inline-block;
+      width: 30px;
+    }
+    .operation-btn {
+      display: inline-block;
+      font-size: 16px;
+      padding: 0 5px;
+      cursor: pointer;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/datasourcecomponent/verifycard/settingform/index.jsx b/src/menu/datasourcecomponent/verifycard/settingform/index.jsx
new file mode 100644
index 0000000..2cbec37
--- /dev/null
+++ b/src/menu/datasourcecomponent/verifycard/settingform/index.jsx
@@ -0,0 +1,352 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Radio, Tooltip, Icon, notification, InputNumber, Select } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import { formRule } from '@/utils/option.js'
+import Utils from '@/utils/utils.js'
+import CodeMirror from '@/templates/zshare/codemirror'
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,       // 瀛楀吀椤�
+    menuId: PropTypes.string,     // 鑿滃崟Id
+    permFuncField: PropTypes.any, // 鑿滃崟Id
+    setting: PropTypes.object,    // 鏁版嵁婧愰厤缃�
+    columns: PropTypes.array,     // 鍒楄缃�
+    scripts: PropTypes.array,     // 鑷畾涔夎剼鏈�
+  }
+
+  state = {
+    interType: this.props.setting.interType || 'inner',
+  }
+
+  handleConfirm = () => {
+    const { setting } = this.props
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          // 鏁版嵁婧愬墠绔獙璇�
+          if (values.interType === 'inner' && !values.innerFunc && values.execute !== 'false' && !values.dataresource) {
+            notification.warning({
+              top: 92,
+              message: '璇峰~鍐欏唴閮ㄥ嚱鏁版垨鏁版嵁婧愶紒',
+              duration: 5
+            })
+            reject()
+            return
+          } else if (values.interType === 'inner' && !values.innerFunc && 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)
+
+            _quot = _quot ? _quot.length : 0
+            _lparen = _lparen ? _lparen.length : 0
+            _rparen = _rparen ? _rparen.length : 0
+
+            if (_quot % 2 !== 0) {
+              notification.warning({
+                top: 92,
+                message: '鏁版嵁婧愪腑\'蹇呴』鎴愬鍑虹幇',
+                duration: 5
+              })
+              reject()
+              return
+            } else if (_lparen !== _rparen) {
+              notification.warning({
+                top: 92,
+                message: '鏁版嵁婧愪腑()蹇呴』鎴愬鍑虹幇',
+                duration: 5
+              })
+              reject()
+              return
+            } else if (/--/ig.test(values.dataresource)) {
+              notification.warning({
+                top: 92,
+                message: '鏁版嵁婧愪腑锛屼笉鍙嚭鐜板瓧绗� -- 锛屾敞閲婅鐢� /*鍐呭*/',
+                duration: 5
+              })
+              reject()
+              return
+            }
+
+            let error = Utils.verifySql(values.dataresource)
+
+            if (error) {
+              notification.warning({
+                top: 92,
+                message: '鏁版嵁婧愪腑涓嶅彲浣跨敤' + error,
+                duration: 5
+              })
+              reject()
+              return
+            }
+          }
+
+          // 鏁版嵁婧愪繚瀛�
+          if (
+            values.interType === 'inner' && !values.innerFunc && values.execute !== 'false' &&
+            /[^\s]+\s+[^\s]+/ig.test(values.dataresource) && setting.dataresource !== values.dataresource
+          ) {
+            let param = {
+              func: 's_DataSrc_Save',
+              LText: values.dataresource,
+              MenuID: this.props.menuId
+            }
+    
+            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)
+    
+            Api.getLocalConfig(param)
+          }
+
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  onRadioChange = (e, key) => {
+    let value = e.target.value
+
+    if (key === 'interType') {
+      this.setState({
+        interType: value
+      })
+    }
+  }
+
+  render() {
+    const { setting, permFuncField, columns } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { interType } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    let tooltip = null
+    let rules = []
+
+    if (permFuncField && permFuncField.length > 0) {
+      tooltip = '寮�澶村彲鐢ㄥ瓧绗︼細' + permFuncField.join(', ')
+      let str = '^(' + permFuncField.join('|') + ')'
+      let _patten = new RegExp(str + formRule.func.innerPattern + '$', 'g')
+
+      rules.push({
+        pattern: _patten,
+        message: formRule.func.innerMessage
+      })
+    }
+
+    return (
+      <div className="model-datasource-setting-form-box">
+        <Form {...formItemLayout} className="model-setting-form">
+          <Row gutter={24}>
+            <Col span={8}>
+              <Form.Item label="鏍囬">
+                {getFieldDecorator('title', {
+                  initialValue: setting.title
+                })(<Input placeholder={''} autoComplete="off" />)}
+              </Form.Item>
+            </Col>
+            <Col span={8}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�">
+                  <Icon type="question-circle" />
+                  缁勪欢鍚嶇О
+                </Tooltip>
+              }>
+                {getFieldDecorator('name', {
+                  initialValue: setting.name,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '缁勪欢鍚嶇О!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" />)}
+              </Form.Item>
+            </Col>
+            <Col span={8}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒�24浠姐��">
+                  <Icon type="question-circle" />
+                  瀹藉害
+                </Tooltip>
+              }>
+                {getFieldDecorator('span', {
+                  initialValue: setting.span || 12,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '瀹藉害!'
+                    }
+                  ]
+                })(<InputNumber min={1} max={24} precision={0} />)}
+              </Form.Item>
+            </Col>
+            <Col span={8}>
+              <Form.Item label="琛ㄥ悕">
+                {getFieldDecorator('tableName', {
+                  initialValue: setting.tableName,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '琛ㄥ悕!'
+                    },
+                  ]
+                })(<Input placeholder={''} autoComplete="off" />)}
+              </Form.Item>
+            </Col>
+            <Col span={8}>
+              <Form.Item label="鎺ュ彛绫诲瀷">
+                {getFieldDecorator('interType', {
+                  initialValue: interType,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '鎺ュ彛绫诲瀷!'
+                    },
+                  ]
+                })(
+                <Radio.Group onChange={(e) => {this.onRadioChange(e, 'interType')}}>
+                  <Radio value="inner">鍐呴儴</Radio>
+                  <Radio value="outer">澶栭儴</Radio>
+                </Radio.Group>)}
+              </Form.Item>
+            </Col>
+            {interType === 'inner' ? <Col span={8}>
+              <Form.Item label={tooltip ?
+                <Tooltip placement="topLeft" title={tooltip}>
+                  <Icon type="question-circle" />
+                  鍐呴儴鍑芥暟
+                </Tooltip> : '鍐呴儴鍑芥暟'
+              }>
+                {getFieldDecorator('innerFunc', {
+                  initialValue: setting.innerFunc || '',
+                  rules: rules
+                })(<Input placeholder={''} autoComplete="off" />)}
+              </Form.Item>
+            </Col> : null}
+            {interType === 'outer' ? <Col span={8}>
+              <Form.Item label="鎺ュ彛鍦板潃">
+                {getFieldDecorator('interface', {
+                  initialValue: setting.interface || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '鎺ュ彛鍦板潃!'
+                    },
+                  ]
+                })(<Input placeholder={''} autoComplete="off" />)}
+              </Form.Item>
+            </Col> : null}
+            {interType === 'outer' ? <Col span={8}>
+              <Form.Item label="澶栭儴鍑芥暟">
+                {getFieldDecorator('outerFunc', {
+                  initialValue: setting.outerFunc || '',
+                  rules: [
+
+                  ]
+                })(<Input placeholder={''} autoComplete="off" />)}
+              </Form.Item>
+            </Col> : null}
+            {interType === 'inner' ? <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" />
+                  鏁版嵁婧�
+                </Tooltip>
+              }>
+                {getFieldDecorator('dataresource', {
+                  initialValue: setting.dataresource || ''
+                })(<CodeMirror />)}
+              </Form.Item>
+            </Col> : null}
+            <Col span={8}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="楂樺害涓虹┖鏃讹紝浣跨敤绯荤粺鑷�傚簲璁剧疆銆�">
+                  <Icon type="question-circle" />
+                  楂樺害
+                </Tooltip>
+              }>
+                {getFieldDecorator('height', {
+                  initialValue: setting.height || 400
+                })(<InputNumber min={100} max={1500} precision={0} />)}
+              </Form.Item>
+            </Col>
+            {interType === 'inner' ? <Col span={8}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title={'鏌ヨ鏃讹紝鎼滅储鏉′欢浠here鏉′欢鎷兼帴杩涘叆sql锛岀粺璁℃椂锛屽皢鏁版嵁婧愪腑浠モ�淍+鎼滅储瀛楁+@鈥濈殑鍐呭锛屼互鎼滅储鏉′欢涓殑鍊艰繘琛屾浛鎹㈠悗锛屾彁浜ゆ煡璇紝娉細鏌ヨ绫诲瀷浠呭湪浣跨敤绯荤粺鍑芥暟鏃舵湁鏁堛��'}>
+                  <Icon type="question-circle" />
+                  鏌ヨ绫诲瀷
+                </Tooltip>
+              }>
+                {getFieldDecorator('queryType', {
+                  initialValue: setting.queryType || 'query'
+                })(
+                <Radio.Group>
+                  <Radio value="query">鏌ヨ</Radio>
+                  <Radio value="statistics">缁熻</Radio>
+                </Radio.Group>)}
+              </Form.Item>
+            </Col> : null}
+            <Col span={8}>
+              <Form.Item label="涓婚敭">
+                {getFieldDecorator('primaryKey', {
+                  initialValue: setting.primaryKey || ''
+                })(
+                  <Select>
+                    {columns.map((option, i) =>
+                      <Select.Option key={i} value={option.field}>
+                        {option.label}
+                      </Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col>
+            {interType === 'inner' ? <Col span={8}>
+              <Form.Item label="榛樿sql">
+                {getFieldDecorator('execute', {
+                  initialValue: setting.execute || 'true'
+                })(
+                <Radio.Group>
+                  <Radio value="true">鎵ц</Radio>
+                  <Radio value="false">涓嶆墽琛�</Radio>
+                </Radio.Group>)}
+              </Form.Item>
+            </Col> : null}
+            <Col span={8}>
+              <Form.Item label="鍒濆鍖栨暟鎹�">
+                {getFieldDecorator('onload', {
+                  initialValue: setting.onload || 'true'
+                })(
+                <Radio.Group>
+                  <Radio value="true">鍔犺浇</Radio>
+                  <Radio value="false">涓嶅姞杞�</Radio>
+                </Radio.Group>)}
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/menu/datasourcecomponent/verifycard/settingform/index.scss b/src/menu/datasourcecomponent/verifycard/settingform/index.scss
new file mode 100644
index 0000000..d24bedd
--- /dev/null
+++ b/src/menu/datasourcecomponent/verifycard/settingform/index.scss
@@ -0,0 +1,24 @@
+.model-datasource-setting-form-box {
+  position: relative;
+
+  .model-setting-form {
+    .data-source {
+      .ant-form-item-label {
+        width: 11%;
+      }
+      .ant-form-item-control-wrapper {
+        width: 89%;
+      }
+      .CodeMirror {
+        height: 150px;
+      }
+    }
+    .anticon-question-circle {
+      color: #c49f47;
+      margin-right: 3px;
+    }
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/datasourcecomponent/verifycard/settingform/utils.jsx b/src/menu/datasourcecomponent/verifycard/settingform/utils.jsx
new file mode 100644
index 0000000..ebd508d
--- /dev/null
+++ b/src/menu/datasourcecomponent/verifycard/settingform/utils.jsx
@@ -0,0 +1,84 @@
+
+export default class SettingUtils {
+  /**
+   * @description 鐢熸垚椤甸潰鏌ヨ璇彞
+   * @return {String}  arr_field     鏄剧ず鍒楀瓧娈�
+   * @return {String}  search        鎼滅储鏉′欢
+   * @return {Object}  setting       椤甸潰璁剧疆
+   * @return {Array}   regoptions    鎼滅储鏉′欢姝e垯鏇挎崲
+   */
+  static getDebugSql (setting, arr_field, regoptions, search) {
+    let sql = ''
+    let _dataresource = setting.dataresource
+    let _customScript = setting.customScript
+
+    if (setting.interType === 'inner' && !setting.innerFunc && setting.default === 'false') {
+      _dataresource = ''
+    }
+    
+    if (_dataresource) {
+      _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
+    }
+    if (_customScript) {
+      _customScript = _customScript.replace(/@\$|\$@/ig, '')
+    }
+    
+    // 姝e垯鏇挎崲
+    let _regoptions = regoptions.map(item => {
+      return {
+        reg: new RegExp('@' + item.key + '@', 'ig'),
+        value: `'${item.value}'`
+      }
+    })
+    let _search = search
+
+    if (setting.queryType === 'statistics' && _dataresource) {
+      _regoptions.forEach(item => {
+        _dataresource = _dataresource.replace(item.reg, item.value)
+      })
+
+      _search = ''
+    }
+
+    if (_customScript) {
+      _regoptions.push({
+        reg: new RegExp('@orderBy@', 'ig'),
+        value: setting.order
+      })
+      if (setting.laypage !== 'false') {
+        _regoptions.push({
+          reg: new RegExp('@pageSize@', 'ig'),
+          value: 10
+        }, {
+          reg: new RegExp('@pageIndex@', 'ig'),
+          value: 1
+        })
+      }
+      _regoptions.forEach(item => {
+        _customScript = _customScript.replace(item.reg, item.value)
+      })
+    }
+
+    // 鏁版嵁婧愬鐞�, 瀛樺湪鏄剧ず鍒楁椂 
+    if (arr_field && _dataresource) {
+      if (/\s/.test(_dataresource)) {
+        _dataresource = '(' + _dataresource + ') tb'
+      }
+
+      _dataresource = `select ${setting.laypage !== 'false' ?  'top 10' : ''} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable ${setting.laypage !== 'false' ?  'where rows > 0' : ''} order by tmptable.rows`
+    }
+
+    if (_customScript) {
+      sql = `${_customScript}
+        ${_dataresource}
+        aaa:
+        if @ErrorCode!=''
+          insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
+      `
+    } else {
+      sql = _dataresource
+    }
+    
+    return sql
+  }
+}
\ No newline at end of file
diff --git a/src/menu/datasourcecomponent/verifycard/utils.jsx b/src/menu/datasourcecomponent/verifycard/utils.jsx
new file mode 100644
index 0000000..8d04983
--- /dev/null
+++ b/src/menu/datasourcecomponent/verifycard/utils.jsx
@@ -0,0 +1,111 @@
+
+export default class SettingUtils {
+  /**
+   * @description 鐢熸垚椤甸潰鏌ヨ璇彞
+   * @return {String}  scripts       鑷畾涔夎剼鏈�
+   * @return {String}  searches      鎼滅储鏉′欢
+   * @return {Object}  setting       椤甸潰璁剧疆
+   * @return {Array}   columns       鏄剧ず瀛楁
+   */
+  static getDebugSql (setting, scripts, columns, searches) {
+    let sql = ''
+    let _dataresource = ''
+    let _customScript = ''
+    let arr_field = columns.map(item => item.field).join(',')
+
+    if (scripts.length > 0) {
+      scripts.forEach(item => {
+        _customScript += `
+          ${item.sql}
+        `
+      })
+    }
+
+    if (_customScript) {
+      _customScript = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000) select @ErrorCode='',@retmsg =''
+        ${_customScript}
+      `
+    }
+
+    if (setting.interType === 'inner' && !setting.innerFunc && setting.execute !== 'false') {
+      _dataresource = setting.dataresource
+    }
+    
+    if (_dataresource) {
+      _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
+    }
+    if (_customScript) {
+      _customScript = _customScript.replace(/@\$|\$@/ig, '')
+    }
+    
+    // 姝e垯鏇挎崲
+    let _regoptions = searches.map(item => {
+      return {
+        reg: new RegExp('@' + item.key + '@', 'ig'),
+        value: `'${item.value}'`
+      }
+    })
+    let _search = ''
+
+    // 鏃ュ巻涓殑骞翠唤鏇挎崲
+    if (setting.queryType === 'statistics' || _customScript) {
+      _regoptions.push({
+        reg: new RegExp('@calendarDate@', 'ig'),
+        value: `1970-01-01 00:00:00.000`
+      })
+      _regoptions.push({
+        reg: new RegExp('@calendarDate1@', 'ig'),
+        value: `2030-12-31 23:59:59.999`
+      })
+    }
+
+    if (setting.queryType === 'statistics' && _dataresource) {
+      _regoptions.forEach(item => {
+        _dataresource = _dataresource.replace(item.reg, item.value)
+      })
+
+      _search = ''
+    }
+
+    if (_customScript) {
+      _regoptions.push({
+        reg: new RegExp('@orderBy@', 'ig'),
+        value: setting.order
+      })
+      if (setting.laypage !== 'false') {
+        _regoptions.push({
+          reg: new RegExp('@pageSize@', 'ig'),
+          value: 10
+        }, {
+          reg: new RegExp('@pageIndex@', 'ig'),
+          value: 1
+        })
+      }
+      _regoptions.forEach(item => {
+        _customScript = _customScript.replace(item.reg, item.value)
+      })
+    }
+
+    // 鏁版嵁婧愬鐞�, 瀛樺湪鏄剧ず鍒楁椂 
+    if (arr_field && _dataresource) {
+      if (/\s/.test(_dataresource)) {
+        _dataresource = '(' + _dataresource + ') tb'
+      }
+
+      _dataresource = `select ${setting.laypage !== 'false' ?  'top 10' : ''} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable ${setting.laypage !== 'false' ?  'where rows > 0' : ''} order by tmptable.rows`
+    }
+
+    if (_customScript) {
+      sql = `${_customScript}
+        ${_dataresource}
+        aaa:
+        if @ErrorCode!=''
+          insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
+      `
+    } else {
+      sql = _dataresource
+    }
+    
+    return sql
+  }
+}
\ No newline at end of file
diff --git a/src/menu/menuform/index.jsx b/src/menu/menuform/index.jsx
index 9f714ff..16bbb7e 100644
--- a/src/menu/menuform/index.jsx
+++ b/src/menu/menuform/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, notification } from 'antd'
 
 import Api from '@/api'
@@ -14,6 +15,7 @@
     MenuName: PropTypes.string,
     MenuNo: PropTypes.string,
     parentId: PropTypes.string,
+    initMenuList: PropTypes.func,
     updateConfig: PropTypes.func
   }
 
@@ -56,6 +58,8 @@
           }
         })
 
+        this.props.initMenuList(fromJS(menulist).toJS())
+
         this.setState({
           fstMenuId: result.FstIDSeleted,
           menulist,
diff --git a/src/menu/menushell/card.jsx b/src/menu/menushell/card.jsx
index cc2146d..ac08014 100644
--- a/src/menu/menushell/card.jsx
+++ b/src/menu/menushell/card.jsx
@@ -7,7 +7,7 @@
 
 const AntvBar = asyncComponent(() => import('@/menu/components/chart/antv-bar'))
 
-const Card = ({ id, card, moveCard, findCard, editId, editCard, delCard, hasDrop, doubleClickCard, updateConfig }) => {
+const Card = ({ id, config, card, moveCard, findCard, editId, editCard, delCard, hasDrop, doubleClickCard, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'menu', id, originalIndex },
@@ -39,12 +39,12 @@
 
   const getCardComponent = () => {
     if (card.type === 'bar') {
-      return (<AntvBar card={card} triggerEdit={editCard} editId={editId} onDoubleClick={doubleClickCard} updateConfig={updateConfig} />)
+      return (<AntvBar config={config} card={card} triggerEdit={editCard} editId={editId} updateConfig={updateConfig} />)
     }
   }
 
   return (
-    <div className="mk-component-card" ref={node => drag(drop(node))} style={style}>
+    <div className={'ant-col mk-component-card ant-col-' + (card.setting ? card.setting.span : 12)} ref={node => drag(drop(node))} style={style}>
       {getCardComponent()}
       <Icon className="remove-component" title="delete" type="delete" onClick={() => delCard(id)} />
     </div>
diff --git a/src/menu/menushell/index.jsx b/src/menu/menushell/index.jsx
index baa9e5e..c2827ec 100644
--- a/src/menu/menushell/index.jsx
+++ b/src/menu/menushell/index.jsx
@@ -70,11 +70,12 @@
   })
 
   return (
-    <div ref={drop} className="menu-shell-inner">
+    <div ref={drop} className="ant-row menu-shell-inner">
       {cards.map(card => (
         <Card
           id={card.uuid}
           key={card.uuid}
+          config={config}
           card={card}
           editId={editId}
           moveCard={moveCard}
diff --git a/src/menu/menushell/index.scss b/src/menu/menushell/index.scss
index 26d5c35..fd9cc3f 100644
--- a/src/menu/menushell/index.scss
+++ b/src/menu/menushell/index.scss
@@ -1,25 +1,42 @@
 .menu-shell-inner {
   min-height: calc(100vh - 150px);
+  margin: -8px;
+
+  >.ant-col {
+    padding: 8px;
+  }
+
   .mk-component-card {
     position: relative;
     .remove-component {
       position: absolute;
-      right: 2px;
-      top: 50%;
-      background: #ff4d4f;
+      right: 40px;
+      top: -13px;
+      color: #ff4d4f;
       border-radius: 2px;
-      padding: 4px;
-      color: #ffffff;
+      padding: 5px;
       cursor: pointer;
-      display: none;
+      opacity: 0;
     }
   }
   .mk-component-card:hover {
     .remove-component {
-      display: inline-block;
+      opacity: 1;
+    }
+    .model-datasource > .anticon-setting {
+      opacity: 1;
     }
   }
   >.ant-empty {
     padding-top: 150px;
   }
+
+  .model-datasource > .anticon-setting {
+    font-size: 16px;
+    padding: 5px;
+    position: absolute;
+    right: 0px;
+    top: -19px;
+    opacity: 0;
+  }
 }
\ No newline at end of file
diff --git a/src/menu/searchcomponent/dategroup/index.jsx b/src/menu/searchcomponent/dategroup/index.jsx
new file mode 100644
index 0000000..37b8769
--- /dev/null
+++ b/src/menu/searchcomponent/dategroup/index.jsx
@@ -0,0 +1,32 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Tag } from 'antd'
+import './index.scss'
+
+const { CheckableTag } = Tag
+
+class DateGroup extends Component {
+  static propTpyes = {
+    card: PropTypes.object    // 瀛楀吀椤�
+  }
+
+  render() {
+    const { card } = this.props
+    let tabs = {day: '鏃�', week: '鍛�', month: '鏈�', quarter: '瀛�', year: '骞�', customized: '鑷畾涔�'}
+
+    return (
+      <div className="model-date-group">
+        {card.items.map(tab => (
+          <CheckableTag
+            key={tab}
+            checked={card.initval && card.initval.includes(tab)}
+          >
+            {tabs[tab]}
+          </CheckableTag>
+        ))}
+      </div>
+    )
+  }
+}
+
+export default DateGroup
\ No newline at end of file
diff --git a/src/menu/searchcomponent/dategroup/index.scss b/src/menu/searchcomponent/dategroup/index.scss
new file mode 100644
index 0000000..6782732
--- /dev/null
+++ b/src/menu/searchcomponent/dategroup/index.scss
@@ -0,0 +1,38 @@
+.model-date-group {
+  white-space: nowrap;
+  line-height: 40px;
+  position: relative;
+  z-index: 1;
+
+  .ant-tag-checkable {
+    border-color: #d1d5d9;
+    border-radius: 2px;
+    margin-right: 2px;
+    padding: 2px 6px;
+  }
+  .ant-tag-checkable-checked {
+    border-color: #1890ff;
+  }
+}
+
+@media screen and (min-width: 1440px) {
+  .model-date-group {
+    .ant-tag-checkable {
+      padding: 2px 7px;
+    }
+  }
+}
+@media screen and (min-width: 1600px) {
+  .model-date-group {
+    .ant-tag-checkable {
+      padding: 2px 9px;
+    }
+  }
+}
+@media screen and (min-width: 1920px) {
+  .model-date-group {
+    .ant-tag-checkable {
+      padding: 2px 11px;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/searchcomponent/dragsearch/card.jsx b/src/menu/searchcomponent/dragsearch/card.jsx
new file mode 100644
index 0000000..b8d4a54
--- /dev/null
+++ b/src/menu/searchcomponent/dragsearch/card.jsx
@@ -0,0 +1,98 @@
+import React from 'react'
+import { useDrag, useDrop } from 'react-dnd'
+import { Icon, Select, DatePicker, Input } from 'antd'
+import moment from 'moment'
+
+import DateGroup from '../dategroup'
+import './index.scss'
+
+const { MonthPicker, WeekPicker, RangePicker } = DatePicker
+
+const Card = ({ id, card, moveCard, findCard, editCard, delCard }) => {
+  const originalIndex = findCard(id).index
+  const [{ isDragging }, drag] = useDrag({
+    item: { type: 'search', id, originalIndex },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  })
+  const [, drop] = useDrop({
+    accept: 'search',
+    canDrop: () => true,
+    drop: (item) => {
+      if (!item.hasOwnProperty('originalIndex')) {
+
+      }
+    },
+    hover({ id: draggedId }) {
+      if (!draggedId) return
+      if (draggedId !== id) {
+        const { index: overIndex } = findCard(id)
+        moveCard(draggedId, overIndex)
+      }
+    },
+  })
+  const opacity = isDragging ? 0 : 1
+
+  let _defaultValue = '' // 涓嬫媺鎼滅储銆佹椂闂磋寖鍥寸被鍨嬶紝鍒濆鍊奸渶瑕侀澶勭悊
+
+  if (card.type === 'multiselect' || card.type === 'select' || card.type === 'link') {
+    if (card.initval) {
+      let _option = card.options.filter(option => option.Value === card.initval)[0]
+      if (_option) {
+        _defaultValue = _option.Text || ''
+      } else {
+        _defaultValue = ''
+      }
+    } else if (card.setAll === 'true') {
+      _defaultValue = 'All'
+    }
+  } else if (card.type === 'daterange') {
+    _defaultValue = [null, null]
+    if (card.initval) {
+      try {
+        let _initval = JSON.parse(card.initval)
+        _defaultValue = [moment().subtract(_initval[0], 'days'), moment().subtract(_initval[1], 'days')]
+      } catch {
+        _defaultValue = [null, null]
+      }
+    }
+  }
+
+  return (
+    <div className="page-card" style={{ opacity: opacity}}>
+      <div ref={node => drag(drop(node))}>
+        <div className="ant-form-item">
+          {card.type === 'text' ?
+            <Input placeholder={card.label} style={{marginTop: '4px'}} value={card.initval} /> : null
+          }
+          {(card.type === 'multiselect' || card.type === 'select' || card.type === 'link') ?
+            <Select placeholder={card.label} value={_defaultValue}></Select> : null
+          }
+          {card.type === 'date' ?
+            <DatePicker placeholder={card.label} value={card.initval ? moment().subtract(card.initval, 'days') : null} /> : null
+          }
+          {card.type === 'dateweek' ?
+            <WeekPicker placeholder={card.label} value={card.initval ? moment().subtract(card.initval * 7, 'days') : null} /> : null
+          }
+          {card.type === 'datemonth' ?
+            <MonthPicker placeholder={card.label} value={card.initval ? moment().subtract(card.initval, 'month') : null} /> : null
+          }
+          {card.type === 'daterange' ?
+            <RangePicker
+              className="data-range"
+              placeholder={['BeginTime', 'EndTime']}
+              renderExtraFooter={() => 'extra footer'}
+              value={_defaultValue}
+            /> : null
+          }
+          {card.type === 'group' ? <DateGroup card={card} /> : null }
+          <div className="input-mask"></div>
+        </div>
+      </div>
+      <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} />
+      <Icon className="edit close" title="delete" type="close" onClick={() => delCard(id)} />
+    </div>
+  )
+}
+export default Card
diff --git a/src/menu/searchcomponent/dragsearch/index.jsx b/src/menu/searchcomponent/dragsearch/index.jsx
new file mode 100644
index 0000000..c7f08e5
--- /dev/null
+++ b/src/menu/searchcomponent/dragsearch/index.jsx
@@ -0,0 +1,96 @@
+import React, { useState } from 'react'
+import { useDrop } from 'react-dnd'
+import { is, fromJS } from 'immutable'
+import update from 'immutability-helper'
+import { Col, Icon } from 'antd'
+import Utils from '@/utils/utils.js'
+import Card from './card'
+import './index.scss'
+
+const Container = ({list, handleList, handleMenu, deleteMenu }) => {
+  const [cards, setCards] = useState(list)
+  const moveCard = (id, atIndex) => {
+    const { card, index } = findCard(id)
+    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
+    handleList(_cards)
+  }
+
+  if (!is(fromJS(cards), fromJS(list))) {
+    setCards(list)
+  }
+  
+  const findCard = id => {
+    const card = cards.filter(c => `${c.uuid}` === id)[0]
+    return {
+      card,
+      index: cards.indexOf(card),
+    }
+  }
+
+  const editCard = id => {
+    const { card } = findCard(id)
+    handleMenu(card)
+  }
+
+  const delCard = id => {
+    const { card } = findCard(id)
+    deleteMenu(card)
+  }
+
+  const [, drop] = useDrop({
+    accept: 'search',
+    drop(item) {
+      if (item.hasOwnProperty('originalIndex')) {
+        return
+      }
+    }
+  })
+
+  const addsearch = (e) => {
+    e.stopPropagation()
+
+    let newcard = {}
+    newcard.uuid = Utils.getuuid()
+    newcard.focus = true
+
+    newcard.label = 'label'
+    newcard.initval = ''
+    newcard.type = 'select'
+    newcard.resourceType = '0'
+    newcard.options = []
+    newcard.setAll = 'false'
+    newcard.orderType = 'asc'
+    newcard.display = 'dropdown'
+    newcard.match = '='
+    
+    let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
+
+    const { index: overIndex } = findCard(`${targetId}`)
+    let targetIndex = overIndex
+
+    targetIndex++
+
+    const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
+
+    handleList(_cards, newcard)
+  }
+
+  return (
+    <div ref={drop} className="ant-row">
+      {cards.map(card => (
+        <Col key={card.uuid} span={card.ratio || 6}>
+          <Card
+            id={`${card.uuid}`}
+            card={card}
+            moveCard={moveCard}
+            editCard={editCard}
+            delCard={delCard}
+            findCard={findCard}
+          />
+        </Col>
+      ))}
+      <Icon type="plus" onClick={addsearch}/>
+    </div>
+  )
+}
+export default Container
diff --git a/src/menu/searchcomponent/dragsearch/index.scss b/src/menu/searchcomponent/dragsearch/index.scss
new file mode 100644
index 0000000..369ae98
--- /dev/null
+++ b/src/menu/searchcomponent/dragsearch/index.scss
@@ -0,0 +1,6 @@
+.common-drawarea-placeholder {
+  width: 100%;
+  line-height: 65px;
+  text-align: center;
+  color: #bcbcbc;
+}
\ No newline at end of file
diff --git a/src/menu/searchcomponent/index.jsx b/src/menu/searchcomponent/index.jsx
new file mode 100644
index 0000000..e8e7ab4
--- /dev/null
+++ b/src/menu/searchcomponent/index.jsx
@@ -0,0 +1,311 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Modal, notification } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import { getSearchForm } from '@/templates/zshare/formconfig'
+
+import SearchForm from './searchform'
+import DragElement from './dragsearch'
+import './index.scss'
+
+const { confirm } = Modal
+
+class SearchComponent extends Component {
+  static propTpyes = {
+    config: PropTypes.object,        // 閰嶇疆淇℃伅
+    sysRoles: PropTypes.array,       // 瑙掕壊鍒楄〃锛岄粦鍚嶅崟
+    updatesearch: PropTypes.func     // 鏇存柊
+  }
+
+  state = {
+    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    searchlist: null,    // 鎼滅储鏉′欢闆�
+    sqlVerifing: false,  // sql楠岃瘉涓�
+    visible: false,      // 妯℃�佹鎺у埗
+    card: null           // 缂栬緫涓厓绱�
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢鍒濆鍖�
+   */
+  UNSAFE_componentWillMount () {
+    this.setState({
+      searchlist: fromJS(this.props.config.search).toJS()
+    })
+  }
+
+  /**
+   * @description 鐩戝惉鍒版悳绱㈡潯浠跺鍒舵椂锛岃Е鍙戞悳绱㈡潯浠剁紪杈�
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { searchlist } = this.state
+
+    if (!is(fromJS(nextProps.config.search), fromJS(this.props.config.search)) && !is(fromJS(nextProps.config.search), fromJS(searchlist))) {
+      this.setState({searchlist: fromJS(nextProps.config.search).toJS()})
+    }
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢椤哄簭璋冩暣锛屾垨鎷栨嫿娣诲姞
+   */
+  handleList = (list, card) => {
+    const { config } = this.props
+
+    if (card) {
+      this.setState({searchlist: list})
+      this.handleSearch(card)
+    } else {
+      this.setState({searchlist: list}, ()=> {  
+        this.props.updatesearch({...config, search: list})
+      })
+    }
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢缂栬緫锛岃幏鍙栨悳绱㈡潯浠惰〃鍗曚俊鎭�
+   */
+  handleSearch = (card) => {
+    const { searchlist } = this.state
+    let linkableFields = []
+
+    searchlist.forEach(item => {
+      if (item.uuid !== card.uuid && (item.type === 'select' || item.type === 'link')) {
+        linkableFields.push({
+          value: item.field,
+          text: item.label
+        })
+      }
+    })
+
+    this.setState({
+      visible: true,
+      card: card,
+      formlist: getSearchForm(card, this.props.sysRoles, linkableFields)
+    })
+  }
+
+  /**
+   * @description 鍙栨秷淇濆瓨锛屽鏋滃厓绱犱负鏂版坊鍏冪礌锛屽垯浠庡簭鍒椾腑鍒犻櫎
+   */
+  editModalCancel = () => {
+    const { card } = this.state
+
+    if (card.focus) {
+      let searchlist = fromJS(this.state.searchlist).toJS()
+
+      searchlist = searchlist.filter(item => item.uuid !== card.uuid)
+
+      this.setState({
+        card: null,
+        searchlist: searchlist,
+        visible: false
+      })
+    } else {
+      this.setState({
+        card: null,
+        visible: false
+      })
+    }
+  }
+
+  /**
+   * @description 鎼滅储淇敼鍚庢彁浜や繚瀛�
+   * 1銆佸幓闄ょ郴缁熼粯璁ゆ悳绱㈡潯浠�
+   * 2銆佸瓧娈靛強鎻愮ず鏂囧瓧閲嶅鏍¢獙
+   * 3銆佹洿鏂颁笅鎷夎彍鍗曞彲閫夐泦鍚�
+   * 4銆佷笅鎷夎彍鍗曟暟鎹簮璇硶楠岃瘉
+   */
+  handleSubmit = () => {
+    const { config } = this.props
+    let _searchlist = fromJS(this.state.searchlist).toJS()
+
+    this.searchFormRef.handleConfirm().then(res => {
+      let fieldrepet = false // 瀛楁閲嶅
+      let labelrepet = false // 鎻愮ず鏂囧瓧閲嶅
+
+      _searchlist = _searchlist.filter(item => !item.origin || item.uuid === res.uuid) // 鍘婚櫎绯荤粺椤�
+
+      _searchlist = _searchlist.map(item => { // 鏁版嵁鏇存柊鍙婇噸澶嶆娴�
+        if (item.uuid !== res.uuid && res.field && item.field) {
+          let itemFields = []
+          if (item.type === 'text') {
+            itemFields = item.field.split(',')
+          } else if (item.type === 'group') {
+            itemFields = [item.field, item.datefield]
+          } else {
+            itemFields = [item.field]
+          }
+
+          let resFields = []
+          if (res.type === 'text') {
+            resFields = res.field.split(',')
+          } else if (res.type === 'group') {
+            resFields = [res.field, res.datefield]
+          } else {
+            resFields = [res.field]
+          }
+
+          let setFields = Array.from(new Set([...itemFields, ...resFields]))
+
+          if (setFields.length < itemFields.length + resFields.length && (res.type !== 'date' || item.type !== 'date')) {
+            fieldrepet = true
+          } else if (item.label === res.label) {
+            labelrepet = true
+          }
+        }
+
+        if (item.uuid === res.uuid) {
+          return res
+        } else {
+          return item
+        }
+      })
+
+      if (fieldrepet) {
+        notification.warning({
+          top: 92,
+          message: this.state.dict['model.field.exist'] + ' !',
+          duration: 5
+        })
+        return
+      } else if (labelrepet) {
+        notification.warning({
+          top: 92,
+          message: this.state.dict['model.name.exist'] + ' !',
+          duration: 5
+        })
+        return
+      }
+
+      if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
+        this.setState({
+          sqlVerifing: true
+        })
+
+        let param = {
+          func: 's_debug_sql',
+          LText: res.dataSource
+        }
+
+        param.LText = param.LText.replace(/@\$|\$@/ig, '')
+        
+        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 (window.GLOB.mainSystemApi && res.database === 'sso') {
+          param.rduri = window.GLOB.mainSystemApi
+        }
+        
+        Api.getLocalConfig(param).then(result => {
+          if (result.status) {
+            this.setState({
+              sqlVerifing: false,
+              searchlist: _searchlist,
+              visible: false
+            }, ()=> {
+              this.props.updatesearch({...config, search: _searchlist})
+            })
+          } else {
+            this.setState({sqlVerifing: false})
+            
+            Modal.error({
+              title: result.message
+            })
+          }
+        })
+      } else {
+        this.setState({
+          searchlist: _searchlist,
+          visible: false
+        }, ()=> { 
+          this.props.updatesearch({...config, search: _searchlist})
+        })
+      }
+    })
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢鍒犻櫎
+   */
+  deleteElement = (card) => {
+    const { config } = this.props
+    const { dict } = this.state
+    let _this = this
+
+    confirm({
+      content: dict['model.confirm'] + dict['model.delete'] + ` - ${card.label} 锛焋,
+      okText: dict['model.confirm'],
+      cancelText: dict['model.cancel'],
+      onOk() {
+        let _searchlist = fromJS(_this.state.searchlist).toJS()
+
+        _searchlist = _searchlist.filter(item => item.uuid !== card.uuid)
+
+        _this.setState({
+          searchlist: _searchlist
+        }, () => {
+          _this.props.updatesearch({...config, search: _searchlist})
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  render() {
+    const { dict, searchlist, visible, sqlVerifing } = this.state
+
+    return (
+      <div className="model-custom-search-list">
+        <DragElement
+          list={searchlist}
+          handleList={this.handleList}
+          handleMenu={this.handleSearch}
+          deleteMenu={this.deleteElement}
+        />
+        {/* 缂栬緫鎼滅储鏉′欢 */}
+        <Modal
+          title={dict['model.searchCriteria'] + '-' + dict['model.edit']}
+          visible={visible}
+          width={850}
+          maskClosable={false}
+          onOk={this.handleSubmit}
+          okText={dict['model.confirm']}
+          cancelText={dict['model.cancel']}
+          confirmLoading={sqlVerifing}
+          onCancel={this.editModalCancel}
+          destroyOnClose
+        >
+          <SearchForm
+            dict={dict}
+            card={this.state.card}
+            formlist={this.state.formlist}
+            inputSubmit={this.handleSubmit}
+            wrappedComponentRef={(inst) => this.searchFormRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default SearchComponent
\ No newline at end of file
diff --git a/src/menu/searchcomponent/index.scss b/src/menu/searchcomponent/index.scss
new file mode 100644
index 0000000..dbed81b
--- /dev/null
+++ b/src/menu/searchcomponent/index.scss
@@ -0,0 +1,78 @@
+.model-custom-search-list {
+  padding: 0px;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -15px;
+    top: 5px;
+  }
+  .ant-row .ant-col {
+    float: right;
+    padding: 0 6px;
+    margin-top: 5px;
+  }
+  .ant-row .anticon-plus {
+    color: #26C281;
+    float: right;
+    padding: 5px;
+    margin-top: 11px;
+  }
+  .page-card {
+    position: relative;
+    background: #ffffff;
+    border-radius: 2px;
+    .ant-form-item {
+      cursor: move;
+      display: flex;
+      margin-bottom: 0px;
+
+      .ant-select {
+        width: 100%;
+        margin-top: 4px;
+      }
+      .ant-calendar-picker {
+        margin-top: 4px;
+      }
+      .input-mask {
+        position: absolute;
+        top: 0;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        opacity: 0;
+        z-index: 2;
+      }
+      .data-range .ant-calendar-picker-input {
+        padding: 4px 20px 4px 5px;
+        font-size: 13px;
+      }
+    }
+    .edit {
+      position: absolute;
+      left: 5px;
+      top: 5px;
+      color: #1890ff;
+      cursor: pointer;
+      display: none;
+      z-index: 3;
+    }
+    .edit.copy {
+      left: 20px;
+      color: #26C281;
+    }
+    .edit.close {
+      left: 30px;
+      color: #ff4d4f;
+    }
+  }
+  .page-card:hover {
+    .edit {
+      display: inline-block;
+    }
+  }
+  .ant-calendar-picker {
+    min-width: 100px!important;
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/searchcomponent/searcheditable/index.jsx b/src/menu/searchcomponent/searcheditable/index.jsx
new file mode 100644
index 0000000..4a560c4
--- /dev/null
+++ b/src/menu/searchcomponent/searcheditable/index.jsx
@@ -0,0 +1,307 @@
+import React, {Component} from 'react'
+import { is, fromJS } from 'immutable'
+import { Table, Input, Popconfirm, Form, Icon } from 'antd'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const EditableContext = React.createContext()
+
+const EditableRow = ({ form, index, ...props }) => (
+  <EditableContext.Provider value={form}>
+    <tr {...props} />
+  </EditableContext.Provider>
+)
+
+const EditableFormRow = Form.create()(EditableRow)
+
+class EditableCell extends Component {
+  state = {
+    editing: false
+  }
+
+  toggleEdit = () => {
+    const editing = !this.state.editing
+    this.setState({ editing }, () => {
+      if (editing && this.input && this.input.select) {
+        this.input.select()
+      } else if (editing && this.input && this.input.focus) {
+        this.input.focus()
+      }
+    })
+  }
+
+  save = e => {
+    const { record, handleSave } = this.props
+    this.form.validateFields((error, values) => {
+      handleSave({ ...record, ...values })
+      if (error && error[e.currentTarget.id]) {
+        return
+      }
+      this.toggleEdit()
+    })
+  }
+
+  renderCell = form => {
+    this.form = form
+    const { children, dataIndex, record } = this.props
+    const { editing } = this.state
+    return editing ? (
+      <Form.Item style={{ margin: 0 }}>
+        {form.getFieldDecorator(dataIndex, {
+          rules: [
+            {
+              required: true,
+              message: 'NOT NULL.',
+            },
+          ],
+          initialValue: record[dataIndex]
+        })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)}
+      </Form.Item>
+    ) : (
+      <div
+        className="editable-cell-value-wrap"
+        onClick={this.toggleEdit}
+      >
+        {children}
+      </div>
+    )
+  }
+
+  render() {
+    const {
+      editable,
+      dataIndex,
+      title,
+      record,
+      index,
+      handleSave,
+      children,
+      ...restProps
+    } = this.props
+    return (
+      <td {...restProps}>
+        {editable ? (
+          <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer>
+        ) : (
+          children
+        )}
+      </td>
+    )
+  }
+}
+
+class EditTable extends Component {
+  constructor(props) {
+    super(props)
+    let columns = [
+      {
+        title: 'Value',
+        dataIndex: 'Value',
+        width: props.type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Text',
+        dataIndex: 'Text',
+        width: props.type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Action',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          this.state.dataSource.length >= 1 ? (
+            <div>
+              <span className="operation-btn" title={props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+              <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
+              <Popconfirm
+                title={props.dict['header.form.query.delete']}
+                okText={props.dict['model.confirm']}
+                cancelText={props.dict['model.cancel']}
+                onConfirm={() => this.handleDelete(record.key)
+              }>
+                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
+              </Popconfirm>
+            </div>
+          ) : null,
+      }
+    ]
+
+    if (props.type === 'link') {
+      columns.unshift({
+        title: 'ParentID',
+        dataIndex: 'ParentID',
+        width: '27%',
+        editable: true
+      })
+    }
+
+    this.state = {
+      columns: columns,
+      dataSource: props.data,
+      count: props.data.length,
+      type: props.type
+    }
+  }
+
+  handleUpDown = (record, direction) => {
+    const { dataSource } = this.state
+    let index = 0
+
+    let _data = dataSource.filter((item, i) => {
+      if (item.key === record.key) {
+        index = i
+      }
+
+      return item.key !== record.key
+    })
+    if ((index === 0 && direction === 'up') || (index === dataSource.length - 1 && direction === 'down')) {
+      return
+    }
+
+    if (direction === 'up') {
+      _data.splice(index - 1, 0, record)
+    } else {
+      _data.splice(index + 1, 0, record)
+    }
+
+    this.setState({
+      dataSource: _data
+    })
+  }
+
+  handleDelete = key => {
+    const dataSource = [...this.state.dataSource]
+    this.setState({ dataSource: dataSource.filter(item => item.key !== key) })
+  }
+
+  handleAdd = () => {
+    const { type, count, dataSource } = this.state
+    const newData = {
+      key: Utils.getuuid(),
+      Value: `${count}`,
+      Text: `${count}`
+    }
+    if (type === 'link') {
+      newData.ParentID = `${count}`
+    }
+    this.setState({
+      dataSource: [...dataSource, newData],
+      count: count + 1
+    })
+  }
+
+  handleSave = row => {
+    const newData = [...this.state.dataSource]
+    const index = newData.findIndex(item => row.key === item.key)
+    const item = newData[index]
+    newData.splice(index, 1, {
+      ...item,
+      ...row
+    })
+    this.setState({ dataSource: newData })
+  }
+
+  resetColumn = (type) => {
+    let columns = [
+      {
+        title: 'Value',
+        dataIndex: 'Value',
+        width: type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Text',
+        dataIndex: 'Text',
+        width: type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Action',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          this.state.dataSource.length >= 1 ? (
+            <div>
+              <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+              <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
+                title={this.props.dict['header.form.query.delete']}
+                okText={this.props.dict['model.confirm']}
+                cancelText={this.props.dict['model.cancel']}
+                onConfirm={() => this.handleDelete(record.key)
+              }>
+                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
+              </Popconfirm>
+            </div>
+          ) : null,
+      }
+    ]
+
+    if (type === 'link') {
+      columns.unshift({
+        title: 'ParentID',
+        dataIndex: 'ParentID',
+        width: '27%',
+        editable: true
+      })
+    }
+
+    this.setState({
+      columns: columns,
+      type: type
+    })
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    if (this.props.type !== nextProps.type) {
+      this.resetColumn(nextProps.type)
+    } else if (!is(fromJS(this.props.data), fromJS(nextProps.data))) {
+      this.setState({
+        dataSource: nextProps.data,
+        count: nextProps.data.length
+      })
+    }
+  }
+
+  render() {
+    const { dataSource } = this.state
+    const components = {
+      body: {
+        row: EditableFormRow,
+        cell: EditableCell
+      }
+    }
+    const columns = this.state.columns.map(col => {
+      if (!col.editable) {
+        return col
+      }
+      return {
+        ...col,
+        onCell: record => ({
+          record,
+          editable: col.editable,
+          dataIndex: col.dataIndex,
+          title: col.title,
+          handleSave: this.handleSave,
+        })
+      }
+    })
+    return (
+      <div className="model-search-edit-table">
+        <Icon className="add-row" type="plus" onClick={this.handleAdd} />
+        <Table
+          components={components}
+          rowClassName={() => 'editable-row'}
+          bordered
+          dataSource={dataSource}
+          columns={columns}
+          pagination={false}
+        />
+      </div>
+    )
+  }
+}
+
+export default EditTable
\ No newline at end of file
diff --git a/src/menu/searchcomponent/searcheditable/index.scss b/src/menu/searchcomponent/searcheditable/index.scss
new file mode 100644
index 0000000..ae28ba2
--- /dev/null
+++ b/src/menu/searchcomponent/searcheditable/index.scss
@@ -0,0 +1,43 @@
+.model-search-edit-table {
+  .add-row {
+    position: absolute;
+    z-index: 1;
+    right: 20px;
+    top: -30px;
+    padding: 5px;
+    font-size: 18px;
+    color: #26C281;
+  }
+  .ant-table-thead > tr > th {
+    padding: 10px 16px;
+  }
+  .ant-table-tbody > tr > td {
+    padding: 0px 16px;
+  }
+  .editable-cell-value-wrap {
+    cursor: pointer;
+    height: 40px;
+    width: 100px;
+    display: table-cell;
+    vertical-align: middle;
+    word-wrap: break-word;
+    word-break: break-word;
+    .ant-input {
+      height: 30px;
+      padding: 0 11px;
+    }
+  }
+  .ant-form-item-control-wrapper {
+    width: 100%;
+  }
+  .ant-table-placeholder {
+    padding: 5px 16px;
+    .ant-empty-normal {
+      margin: 0;
+    }
+  }
+  .operation-btn {
+    margin-right: 10px;
+    cursor: pointer;
+  }
+}
diff --git a/src/menu/searchcomponent/searchform/index.jsx b/src/menu/searchcomponent/searchform/index.jsx
new file mode 100644
index 0000000..48acf2d
--- /dev/null
+++ b/src/menu/searchcomponent/searchform/index.jsx
@@ -0,0 +1,602 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Select, Icon, Radio, notification, Tooltip, InputNumber, Checkbox, Cascader } from 'antd'
+import { dateOptions, matchReg, formRule } from '@/utils/option.js'
+import EditTable from '../searcheditable'
+import Utils from '@/utils/utils.js'
+import CodeMirror from '@/templates/zshare/codemirror'
+import './index.scss'
+
+const groupOptions = [
+  {
+    value: 'day',
+    label: '鏃�',
+    children: [
+      {value: '0', label: '褰撳ぉ'},
+      {value: 1, label: '鏄ㄥぉ'},
+      {value: 2, label: '鍓嶅ぉ'},
+      {value: 3, label: '鍓嶄笁澶�'},
+      {value: 7, label: '鍓嶄竷澶�'},
+      {value: 30, label: '鍓�30澶�'},
+      {value: -1, label: '鏄庡ぉ'},
+      {value: -2, label: '鍚庡ぉ'}
+    ]
+  },
+  {
+    value: 'week',
+    label: '鍛�',
+    children: [
+      {value: '0', label: '鏈懆'},
+      {value: 1, label: '涓婂懆'},
+      {value: 3, label: '鍓嶄笁鍛�'},
+      {value: 7, label: '鍓嶄竷鍛�'},
+      {value: -1, label: '涓嬪懆'}
+    ]
+  },
+  {
+    value: 'month',
+    label: '鏈�',
+    children: [
+      {value: '0', label: '鏈湀'},
+      {value: 1, label: '涓婃湀'},
+      {value: 3, label: '鍓嶄笁鏈�'},
+      {value: 7, label: '鍓嶄竷鏈�'},
+      {value: -1, label: '涓嬫湀'}
+    ]
+  },
+  {
+    value: 'quarter',
+    label: '瀛�',
+    children: [
+      {value: '0', label: '鏈搴�'},
+      {value: 1, label: '涓婂搴�'},
+      {value: -1, label: '涓嬪搴�'}
+    ]
+  },
+  {
+    value: 'year',
+    label: '骞�',
+    children: [
+      {value: '0', label: '鏈勾'},
+      {value: 1, label: '鍘诲勾'},
+      {value: -1, label: '鏄庡勾'}
+    ]
+  },
+  {
+    value: 'customized',
+    label: '鑷畾涔�',
+    children: [
+      {value: '[0, 0]', label: '浠婂ぉ'},
+      {value: '[1, 1]', label: '鏄ㄥぉ'},
+      {value: '[3, 0]', label: '杩戜笁澶�'},
+      {value: '[7, 0]', label: '杩戜竷澶�'},
+      {value: '[30, 0]', label: '杩�30澶�'},
+      {value: '[7, -7]', label: '鍓嶅悗涓冨ぉ'},
+      {value: '[30, -30]', label: '鍓嶅悗30澶�'},
+      {value: '[90, -90]', label: '鍓嶅悗90澶�'},
+      {value: '[-1, -1]', label: '鏄庡ぉ'},
+      {value: '[-2, -2]', label: '鍚庡ぉ'}
+    ]
+  },
+]
+
+class MainSearch extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,     // 瀛楀吀椤�
+    formlist: PropTypes.any,    // 琛ㄥ崟
+    card: PropTypes.object,     // 鎼滅储鏉′欢淇℃伅
+    inputSubmit: PropTypes.any  // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  state = {
+    openType: null,          // 鎼滅储鏉′欢鏄剧ず绫诲瀷
+    resourceType: null,      // 涓嬫媺鎼滅储鏃讹紝閫夐」鏉ユ簮绫诲瀷
+    formlist: null,          // 琛ㄥ崟
+    textTooltip: '瀛楁鍚嶅彲浠ヤ娇鐢ㄩ�楀彿鍒嗛殧锛岃繘琛岀患鍚堟悳绱�',
+  }
+
+  /**
+   * @description 琛ㄥ崟棰勫鐞�
+   * 1銆佹牴鎹〃鍗曠被鍨嬶紝鏄剧ず琛ㄥ崟鍙紪杈戦」
+   * 2銆佷笅鎷夐�夋嫨锛屾牴鎹暟鎹簮绫诲瀷鏄剧ず鐩稿叧閰嶇疆
+   */
+  UNSAFE_componentWillMount () {
+    const { formlist, dict } = this.props
+
+    let type = formlist.filter(cell => cell.key === 'type')[0].initVal
+    let _items = formlist.filter(cell => cell.key === 'items')[0].initVal
+    let resourceType = formlist.filter(cell => cell.key === 'resourceType')[0].initVal
+    let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide']                // 榛樿鏄剧ず椤�
+
+    if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '0') {        // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓鸿嚜瀹氫箟璧勬簮
+      _options = [..._options, 'resourceType', 'options', 'display', 'quick']
+    } else if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '1') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓哄悗鍙版暟鎹簮涓幏鍙�
+      _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database']
+    } else if (type === 'group') {
+      _options = ['label', 'type', 'field', 'datefield', 'initval', 'blacklist', 'ratio', 'items', 'required', 'transfer']
+    }
+
+    if (type === 'select' || type === 'link') {
+      _options.push('setAll')
+    }
+
+    if (type === 'link') { // 鍏宠仈绫诲瀷銆佸鍔犲叧鑱斾笂绾х殑瀛楁鍚�
+      _options = [..._options, 'linkField']
+    }
+    
+    this.setState({
+      openType: type,
+      items: _items,
+      resourceType: resourceType,
+      formlist: formlist.map(form => {
+        // 琛ㄥ崟涓哄垵濮嬪�煎瓧娈碉紝涓旀暟鎹被鍨嬪睘浜庢椂闂寸被鍨嬫椂锛岃缃垵濮嬪�间负涓嬫媺閫夋嫨锛屽苟閲嶇疆閫夋嫨椤�
+        if (form.key === 'initval' && dateOptions.hasOwnProperty(type)) {
+          form.options = dateOptions[type]
+          form.type = 'select'
+        } else if (form.key === 'initval' && type === 'group') {
+          form.options = groupOptions.filter(op => _items.includes(op.value))
+          form.type = 'cascader'
+        } else if (form.key === 'match') { // 琛ㄥ崟涓哄尮閰嶅瓧娈垫椂锛屾牴鎹笉鍚岀殑绫诲瀷锛屾樉绀哄搴旂殑鍖归厤瑙勫垯
+          if (type === 'text') {
+            form.options = matchReg.text
+          } else if (type === 'multiselect') {
+            form.options = matchReg.multiselect
+          } else if (type === 'select' || type === 'link') {
+            form.options = matchReg.select
+          } else if (type === 'date') {
+            form.options = matchReg.date
+          } else if (type === 'datemonth') {
+            form.options = matchReg.datemonth
+          } else if (type === 'dateweek' || type === 'daterange') {
+            form.options = matchReg.daterange
+          }
+        } else if (form.key === 'field' && type === 'text') {
+          form.tooltip = this.state.textTooltip
+        } else if (form.key === 'field' && type === 'group') {
+          form.label = dict['model.form.type'] + dict['model.form.field']
+        }
+        form.hidden = !_options.includes(form.key)
+        return form
+      })
+    })
+  }
+
+  componentDidMount () {
+    const { card } = this.props
+
+    if (card.focus) {
+      try {
+        let _form = document.getElementById('label')
+        _form.select()
+      } catch {
+        console.warn('琛ㄥ崟focus澶辫触锛�')
+      }
+    }
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢绫诲瀷鍒囨崲
+   */
+  openTypeChange = (key, value) => {
+    const { dict } = this.props
+    const { resourceType, items } = this.state
+
+    if (key === 'type') {
+      let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide']
+
+      if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '0') {        // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓鸿嚜瀹氫箟璧勬簮
+        _options = [..._options, 'resourceType', 'options', 'display', 'quick']
+      } else if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '1') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓哄悗鍙版暟鎹簮涓幏鍙�
+        _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database']
+      } else if (value === 'group') {
+        _options = ['label', 'type', 'field', 'datefield', 'initval', 'items', 'ratio', 'blacklist', 'required', 'transfer']
+      }
+
+      if (value === 'select' || value === 'link') {
+        _options.push('setAll')
+      }
+      
+      if (value === 'link') {
+        _options = [..._options, 'linkField']
+      }
+
+      let matchs = []
+
+      this.setState({
+        openType: value,
+        formlist: this.state.formlist.map(form => {
+          form.hidden = !_options.includes(form.key)            // 闅愯棌琛ㄥ崟
+
+          if (form.key === 'initval') {
+            if (dateOptions.hasOwnProperty(value)) { // 鏍规嵁鎼滅储鏉′欢绫诲瀷锛岄�夋嫨鍒濆鍊肩殑绫诲瀷鍙婃暟鎹�
+              form.options = dateOptions[value]
+              form.type = 'select'
+            } else if (value === 'group') {
+              form.options = groupOptions.filter(op => items.includes(op.value))
+              form.type = 'cascader'
+            } else {
+              form.type = 'text'
+            }
+          } else if (form.key === 'match') {                     // 鎼滅储鏉′欢绫诲瀷鍒囨崲鏃讹紝鍖归厤瑙勫垯绫诲瀷瀵瑰簲鍒囨崲
+            if (value === 'text') {
+              form.options = matchReg.text
+            } else if (value === 'multiselect') {
+              form.options = matchReg.multiselect
+            } else if (value === 'select' || value === 'link') {
+              form.options = matchReg.select
+            } else if (value === 'date') {
+              form.options = matchReg.date
+            } else if (value === 'datemonth') {
+              form.options = matchReg.datemonth
+            } else if (value === 'dateweek' || value === 'daterange') {
+              form.options = matchReg.daterange
+            }
+            matchs = form.options
+          } else if (form.key === 'field') {
+            form.tooltip = ''
+            form.label = dict['model.form.field']
+            if (value === 'text') {
+              form.tooltip = this.state.textTooltip
+            } else if (value === 'group') {
+              form.label = dict['model.form.type'] + dict['model.form.field']
+            }
+          }
+
+          return form
+        })
+      }, () => {
+        if (this.props.form.getFieldValue('initval') !== undefined) {
+          this.props.form.setFieldsValue({initval: ''})
+        }
+        if (this.props.form.getFieldValue('match') !== undefined) {
+          this.props.form.setFieldsValue({match: matchs[0].value})
+        }
+      })
+    }
+  }
+
+  /**
+   * @description 鏁版嵁婧愮被鍨嬪垏鎹�
+   */
+  onChange = (e, key) => {
+    const { openType } = this.state
+    let value = e.target.value
+
+    if (key === 'resourceType') {
+      let _options = ['label', 'field', 'initval', 'type', 'match', 'resourceType', 'display', 'ratio', 'blacklist', 'required', 'Hide']
+
+      if (value === '0') {
+        _options = [..._options, 'options', 'quick']
+      } else if (value === '1') {
+        _options = [..._options, 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'database']
+      }
+
+      if (openType === 'select' || openType === 'link') {
+        _options.push('setAll')
+      }
+      
+      if (openType === 'link') {
+        _options = [..._options, 'linkField']
+      }
+      
+      this.setState({
+        resourceType: value,
+        formlist: this.state.formlist.map(form => {
+          form.hidden = !_options.includes(form.key)
+          return form
+        })
+      })
+    }
+  }
+
+  checkChange = (values, key) => {
+    const { openType, formlist } = this.state
+
+    if (key === 'items') {
+      this.setState({
+        items: values,
+        formlist: formlist.map(form => {
+          if (form.key === 'initval' && openType === 'group') {
+            form.options = groupOptions.filter(op => values.includes(op.value))
+          }
+
+          return form
+        })
+      })
+
+      let _initval = this.props.form.getFieldValue('initval')
+      if (_initval && !values.includes(_initval[0])) {
+        this.props.form.setFieldsValue({initval: ''})
+      }
+    }
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  getFields() {
+    const { openType } = this.state
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+    this.state.formlist.forEach((item, index) => {
+      if (item.hidden) return
+
+      if (item.type === 'text') { // 鏂囨湰鎼滅储
+        let rules = []
+        if (item.key === 'field' || item.key === 'datefield') {
+          rules = [{
+            pattern: openType === 'text' ? formRule.field.multipattern : formRule.field.pattern,
+            message: formRule.field.message
+          }, {
+            max: formRule.field.max,
+            message: formRule.field.maxMessage
+          }]
+        } else {
+          rules = [{
+            max: formRule.input.max,
+            message: formRule.input.message
+          }]
+        }
+        
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  },
+                  ...rules
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || 6,
+                rules: [
+                  {
+                    required: item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={item.min} max={item.max} precision={0} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select
+                  showSearch
+                  filterOption={(input, option) => option.props.children[2].toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  onChange={(value) => {this.openTypeChange(item.key, value)}}
+                  getPopupContainer={() => document.getElementById('commontable-search-form-box')}
+                >
+                  {item.options.map(option =>
+                    <Select.Option id={option.value} title={option.text} key={option.value} value={option.value}>
+                      {item.key === 'icon' && <Icon type={option.text} />} {option.text}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group onChange={(e) => {this.onChange(e, item.key)}}>
+                  {
+                    item.options.map(option => {
+                      return (
+                        <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                      )
+                    })
+                  }
+                </Radio.Group>,
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'textarea') {
+        fields.push(
+          <Col span={20} offset={4} key={index}>
+            <Form.Item className="text-area">
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<CodeMirror />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'options') {
+        fields.push(
+          <Col span={20} offset={4} key={index}>
+            <EditTable data={item.initVal} type={this.state.openType} dict={this.props.dict} ref="editTable"/>
+          </Col>
+        )
+      } else if (item.type === 'checkbox') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Checkbox.Group style={{width: '105%'}} options={item.options} onChange={(values) => this.checkChange(values, item.key)}/>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'multiselect') { // 澶氶��
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || []
+              })(
+                <Select
+                  showSearch
+                  mode="multiple"
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                >
+                  {item.options.map((option, i) =>
+                    <Select.Option id={i} key={i} value={option.value}>{option.text}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'cascader') { // 澶氶��
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal
+              })(
+                <Cascader options={item.options} placeholder="" />
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+
+    return fields
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let isvalid = true
+          values.uuid = this.props.card.uuid
+          // 涓嬫媺鑿滃崟鎴栬仈鍔ㄨ彍鍗�
+          if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '0') {
+            values.options = this.refs.editTable.state.dataSource
+            values.dataSource = ''
+            let emptys = []
+            if (values.type === 'multiselect' || values.type === 'select') {
+              emptys = values.options.filter(op => !(op.Value && op.Text))
+            } else {
+              emptys = values.options.filter(op => !(op.Value && op.Text && op.ParentID))
+            }
+            if (emptys.length > 0) {
+              isvalid = false
+            }
+          } else if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '1') {
+            values.options = []
+          }
+
+          if (isvalid) {
+            ['linkField', 'valueField', 'valueText', 'orderBy'].forEach(item => {
+              if (values[item]) {
+                values[item] = values[item].replace(/\s* | \t* | \v* | \r*/ig, '')
+              }
+            })
+
+            let error = Utils.verifySql(values.dataSource)
+
+            if (error) {
+              notification.warning({
+                top: 92,
+                message: '鏁版嵁婧愪腑涓嶅彲浣跨敤' + error,
+                duration: 5
+              })
+              return
+            }
+
+            resolve(values)
+          } else {
+            notification.warning({
+              top: 92,
+              message: this.props.dict['model.form.selectItem.error'],
+              duration: 5
+            })
+          }
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="model-search-edit-form" id="commontable-search-form-box">
+        <Row gutter={24}>{this.getFields()}</Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/menu/searchcomponent/searchform/index.scss b/src/menu/searchcomponent/searchform/index.scss
new file mode 100644
index 0000000..cc9c99c
--- /dev/null
+++ b/src/menu/searchcomponent/searchform/index.scss
@@ -0,0 +1,32 @@
+.model-search-edit-form {
+  min-height: 180px;
+  .ant-col-offset-4 {
+    padding-left: 6px!important;
+    padding-bottom: 20px;
+  }
+  .ant-form-item.text-area {
+    margin-bottom: 0px;
+    .ant-form-item-control-wrapper {
+      width: 100%;
+    }
+    .CodeMirror {
+      height: 150px;
+    }
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .ant-checkbox-group {
+    .ant-checkbox-group-item {
+      .ant-checkbox + span {
+        padding-left: 4px;
+        padding-right: 4px;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/zshare/normalTable/index.jsx b/src/tabviews/zshare/normalTable/index.jsx
index cddb597..5eb8327 100644
--- a/src/tabviews/zshare/normalTable/index.jsx
+++ b/src/tabviews/zshare/normalTable/index.jsx
@@ -670,8 +670,8 @@
         return (<p key={index} style={{textAlign: cont.align}}>{cont.content}</p>)
       })
     } else if (type === 'horizontal') {
-      return contents.map((content, index) => {
-        return (<span key={index}>{content}</span>)
+      return contents.map((cont, index) => {
+        return (<span key={index}>{cont.content}</span>)
       })
     } else if (type === 'vertical2') {
       return (
diff --git a/src/templates/sharecomponent/chartcomponent/index.jsx b/src/templates/sharecomponent/chartcomponent/index.jsx
index b4eed38..c9b6726 100644
--- a/src/templates/sharecomponent/chartcomponent/index.jsx
+++ b/src/templates/sharecomponent/chartcomponent/index.jsx
@@ -531,11 +531,6 @@
             type: 'overlap'
           }
           setting.offset = 0
-          // setting.style = {
-          //   textAlign: 'center',
-          //   fontSize: 12,
-          //   fill: '#535353'
-          // }
         }
 
         _chart.label('percent', setting)
diff --git a/src/templates/sharecomponent/tablecomponent/index.jsx b/src/templates/sharecomponent/tablecomponent/index.jsx
index 05bcaa8..543f4ee 100644
--- a/src/templates/sharecomponent/tablecomponent/index.jsx
+++ b/src/templates/sharecomponent/tablecomponent/index.jsx
@@ -165,11 +165,11 @@
       })
 
       let _config = {...config, tables: [...selectedTables, _table]}
-
+      
       Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: value}).then(res => {
         if (res.status) {
           let tabmsg = {
-            tableName: _table.name,
+            tableName: _table.TbName,
             columns: res.FDName.map(item => {
               let _type = item.FieldType.toLowerCase()
               let _decimal = 0
diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx
index 79bd9e8..e78a014 100644
--- a/src/views/menudesign/index.jsx
+++ b/src/views/menudesign/index.jsx
@@ -22,6 +22,7 @@
 const MenuForm = asyncComponent(() => import('@/menu/menuform'))
 const SourceWrap = asyncComponent(() => import('@/menu/modelsource'))
 const MenuShell = asyncComponent(() => import('@/menu/menushell'))
+// const Controller = asyncComponent(() => import('@/mob/controller'))
 // const DataSource = asyncComponent(() => import('@/mob/datasource'))
 const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
 
@@ -39,6 +40,7 @@
   }
 
   UNSAFE_componentWillMount() {
+    
     this.getMenuParam()
     // this.testFunc()
   }
@@ -50,6 +52,10 @@
     this.setState = () => {
       return
     }
+  }
+
+  reloadTab = () => {
+    
   }
 
   closeView = () => {
@@ -155,6 +161,8 @@
           config: fromJS(config).toJS(),
           openEdition: result.open_edition || '',
         })
+
+        this.getRoleFields()
       } else {
         notification.warning({
           top: 92,
@@ -162,6 +170,44 @@
           duration: 5
         })
       }
+    })
+  }
+
+  getRoleFields = () => {
+    Api.getSystemConfig({func: 'sPC_Get_Roles_sModular'}).then(res => {
+      if (res.status) {
+        let _permFuncField = []
+        let _sysRoles = []
+
+        if (res.Roles && res.Roles.length > 0) {
+          _sysRoles = res.Roles.map(role => {
+            return {
+              uuid: Utils.getuuid(),
+              value: role.RoleID,
+              text: role.RoleName
+            }
+          })
+        }
+
+        if (res.sModular && res.sModular.length > 0) {
+          res.sModular.forEach(field => {
+            if (field.ModularNo) {
+              _permFuncField.push(field.ModularNo)
+            }
+          })
+          _permFuncField = _permFuncField.sort()
+        }
+
+        this.setState({
+          config: {...this.state.config, sysRoles: _sysRoles, permFuncField: _permFuncField}
+        })
+      }
+    })
+  }
+
+  initMenuList = (list) => {
+    this.setState({
+      config: {...this.state.config, fstMenuList: list}
     })
   }
 
@@ -212,6 +258,8 @@
   updatetable = (config, fields) => {
     const { tableFields } = this.state
 
+    config.tableFields = fields ? fields : tableFields
+
     this.setState({
       config: config,
       tableFields: fields ? fields : tableFields
@@ -240,22 +288,26 @@
                     parentId={this.props.match.params.ParentId}
                     MenuName={this.props.match.params.MenuName}
                     MenuNo={this.props.match.params.MenuNo}
+                    initMenuList={this.initMenuList}
                     updateConfig={this.updateConfig}
                   />
                   {/* 琛ㄥ悕娣诲姞 */}
-                  {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null}
+                  {config ? <TableComponent config={config} updatetable={this.updatetable}/> : null}
                 </Panel>
                 {/* 缁勪欢娣诲姞 */}
                 <Panel header={dict['mob.component']} key="component">
                   <SourceWrap />
                 </Panel>
+                {/* <Panel header={dict['mob.style']} key="style">
+                  <Controller />
+                </Panel> */}
               </Collapse>
             </div>
             <div className="menu-view">
               <Card title={
                 <div>
                   {config && config.MenuName} 
-                  <Icon type="redo" style={{marginLeft: '10px'}} title="鍒锋柊鏍囩鍒楄〃" onClick={() => this.reloadTab(true)} />
+                  <Icon type="redo" style={{marginLeft: '10px'}} title="鍒锋柊鏍囩鍒楄〃" onClick={() => this.reloadTab()} />
                 </div>
               } bordered={false} extra={
                 <div>
@@ -263,7 +315,7 @@
                   <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{dict['mob.save']}</Button>
                 </div>
               } style={{ width: '100%' }}>
-                {config ? <MenuShell config={config} handleList={this.updateConfig} /> : null}
+                {config ? <MenuShell config={config} handleList={this.updateConfig} deleteCard={this.deleteCard} /> : null}
               </Card>
             </div>
           </div>

--
Gitblit v1.8.0