From 1a67732f77de8afd138b6e75235edcc4c0e9a166 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期四, 16 一月 2020 23:29:57 +0800
Subject: [PATCH] 2020-01-16

---
 src/components/tabview/index.jsx                   |   11 
 src/templates/tableshare/dragelform/index.scss     |   15 
 src/tabviews/formtab/index.jsx                     |  806 +++++++++++++
 src/templates/tableshare/tabform/index.scss        |    0 
 src/components/header/index.jsx                    |    2 
 src/templates/formtabconfig/index.jsx              | 1014 ++++------------
 src/templates/tableshare/dragelform/index.jsx      |  118 ++
 src/templates/comtableconfig/index.jsx             |   25 
 src/tabviews/tableshare/actionList/index.jsx       |    6 
 src/templates/formtabconfig/dragelement/index.jsx  |   30 
 src/templates/tableshare/tabdragelement/index.jsx  |    3 
 src/templates/formtabconfig/groupform/index.jsx    |    2 
 src/templates/tableshare/tabform/index.jsx         |    5 
 src/templates/formtabconfig/source.jsx             |   82 -
 src/tabviews/subtable/index.jsx                    |   38 
 src/templates/formtabconfig/dragelement/card.jsx   |   46 
 src/tabviews/subtabtable/index.jsx                 |   38 
 src/locales/zh-CN/comtable.js                      |    1 
 src/tabviews/commontable/index.jsx                 |   89 +
 src/templates/modalconfig/dragelement/card.jsx     |    2 
 src/templates/formtabconfig/index.scss             |   13 
 src/utils/utils.js                                 |    9 
 src/templates/subtableconfig/actionform/index.jsx  |   22 
 src/tabviews/formtab/index.scss                    |   88 +
 src/templates/formtabconfig/settingform/index.jsx  |   60 
 src/templates/tableshare/dragelement/index.jsx     |    1 
 src/templates/tableshare/dragelform/itemtypes.js   |    8 
 src/tabviews/formtab/mainTable/index.jsx           |  393 ++++++
 src/components/sidemenu/editthdmenu/index.jsx      |    2 
 src/templates/tableshare/dragelform/card.jsx       |  109 +
 src/templates/formtabconfig/actionform/index.jsx   |   15 
 src/templates/subtableconfig/index.jsx             |   31 
 src/templates/formtabconfig/modalform/index.jsx    |    5 
 /dev/null                                          |    7 
 src/templates/tableshare/colspanform/index.jsx     |    5 
 src/templates/tableshare/tabdragelement/index.scss |    0 
 src/templates/tableshare/tabdragelement/card.jsx   |    0 
 src/templates/tableshare/dragelform/source.jsx     |   13 
 src/tabviews/formtab/mainTable/index.scss          |  133 ++
 src/templates/tableshare/formconfig.js             |  289 ++++
 src/views/login/index.jsx                          |    2 
 41 files changed, 2,515 insertions(+), 1,023 deletions(-)

diff --git a/src/components/header/index.jsx b/src/components/header/index.jsx
index bd76670..298bdb9 100644
--- a/src/components/header/index.jsx
+++ b/src/components/header/index.jsx
@@ -182,7 +182,7 @@
           }
           return item
         }),
-        systems: result.Systems.filter(sys => sys.LinkUrl1)
+        systems: result.Systems.filter(sys => sys.LinkUrl1 && sys.AppKey !== window.GLOB.appkey)
       })
     } else {
       notification.error({
diff --git a/src/components/sidemenu/editthdmenu/index.jsx b/src/components/sidemenu/editthdmenu/index.jsx
index 721b40a..2af730f 100644
--- a/src/components/sidemenu/editthdmenu/index.jsx
+++ b/src/components/sidemenu/editthdmenu/index.jsx
@@ -486,7 +486,7 @@
       })
     } else if (type === 'tabview') { // 涓夌骇鑿滃崟涓嬶紝鎵撳紑鏂版爣绛鹃〉鎴栧綋鍓嶉〉璺宠浆锛岀被鍨嬬殑鎸夐挳閰嶇疆
       let pageParam = ''
-      if (config && config.type === 'formTab') {
+      if (config && config.type === 'FormTab') {
         pageParam = config
       }
 
diff --git a/src/components/tabview/index.jsx b/src/components/tabview/index.jsx
index 2a6a77e..b951d46 100644
--- a/src/components/tabview/index.jsx
+++ b/src/components/tabview/index.jsx
@@ -47,12 +47,9 @@
       } else {
         tab.selected = false
       }
-      if (menu.type === 'TabForm' || menu.type === 'iframe') {
-        return tab.MenuID !== menu.MenuID
-      } else {
-        return tab.MenuNo !== menu.MenuNo
-      }
+      return tab.MenuID !== menu.MenuID
     })
+    
     if (menu.MenuID === this.state.selectedTabId) {
       tabs[0] && (tabs[0].selected = true)
     }
@@ -90,6 +87,8 @@
       return (<Comps.RoleManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
     } else if (view.type === 'TabForm') {
       return (<Comps.TabForm MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>)
+    } else if (view.type === 'FormTab') {
+      return (<Comps.FormTab MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>)
     } else if (view.type === 'iframe') {
       return (<Comps.Iframe key={view.MenuID} title={view.MenuName} MenuName={view.MenuName} url={service + view.LinkUrl}/>)
     } else {
@@ -166,6 +165,8 @@
           Comps.RoleManage = asyncComponent(() => import('@/tabviews/rolemanage'))
         } else if (!Comps.TabForm && newtab.type === 'TabForm') {
           Comps.TabForm = asyncComponent(() => import('@/tabviews/tabform'))
+        } else if (!Comps.TabForm && newtab.type === 'FormTab') {
+          Comps.FormTab = asyncComponent(() => import('@/tabviews/formtab'))
         }
       }
 
diff --git a/src/locales/zh-CN/comtable.js b/src/locales/zh-CN/comtable.js
index 017eb3a..0ae9ee5 100644
--- a/src/locales/zh-CN/comtable.js
+++ b/src/locales/zh-CN/comtable.js
@@ -172,6 +172,7 @@
   'header.form.request.method': '璇锋眰鏂瑰紡',
   'header.form.readonly': '鏄惁鍙',
   'header.form.field.required': '鏄惁蹇呭~',
+  'header.modal.form.edit': '琛ㄥ崟-缂栬緫',
   'header.modal.search.edit': '鎼滅储鏉′欢-缂栬緫',
   'header.modal.action.edit': '鎸夐挳-缂栬緫',
   'header.modal.action.copy': '鎸夐挳-澶嶅埗',
diff --git a/src/tabviews/commontable/index.jsx b/src/tabviews/commontable/index.jsx
index b7e8f63..d099e40 100644
--- a/src/tabviews/commontable/index.jsx
+++ b/src/tabviews/commontable/index.jsx
@@ -1,5 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
+import {connect} from 'react-redux'
 import { is, fromJS } from 'immutable'
 import { BackTop, notification, Spin, Tabs, Icon, Switch, Modal, Button} from 'antd'
 import moment from 'moment'
@@ -10,6 +11,7 @@
 import SubTable from '@/tabviews/subtable'
 import NotFount from '@/components/404'
 import asyncComponent from '@/utils/asyncLoadComponent'
+import {refreshTabView, modifyTabview} from '@/store/action'
 import zhCN from '@/locales/zh-CN/main.js'
 import enUS from '@/locales/en-US/main.js'
 import Utils from '@/utils/utils.js'
@@ -18,7 +20,7 @@
 const SubTabTable = asyncComponent(() => import('@/tabviews/subtabtable'))
 const { TabPane } = Tabs
 
-export default class NormalTable extends Component {
+class NormalTable extends Component {
   static propTpyes = {
     MenuNo: PropTypes.string,    // 鑿滃崟鍙傛暟
     MenuName: PropTypes.string,  // 鑿滃崟鍙傛暟
@@ -58,6 +60,8 @@
    * @description 鑾峰彇椤甸潰閰嶇疆淇℃伅
    */
   async loadconfig () {
+    const { permAction } = this.props
+
     let param = {
       func: 'sPC_Get_LongParam',
       MenuID: this.props.MenuID
@@ -97,6 +101,13 @@
       let _hideCol = []      // 闅愯棌鍙婂悎骞跺垪涓瓧娈电殑uuid闆�
       let colMap = new Map()
 
+      // 鏉冮檺杩囨护
+      config.action = config.action.filter(item => permAction[item.uuid])
+      // config.tabgroups.forEach(group => {
+      //   if (!config[group]) return
+      //   config[group] = config[group].filter(tab => permAction[tab.uuid])
+      // })
+
       // 1銆佺瓫閫夊瓧娈甸泦锛�2銆佽繃婊ら殣钘忓垪鍙婂悎骞跺垪涓殑瀛楁uuid
       config.columns.forEach(col => {
         if (col.field) {
@@ -129,16 +140,18 @@
         }
       })
 
-      // 娣诲姞鎿嶄綔鍒楋紙瀛樺湪鏃讹級锛堟湭缁忚繃鏉冮檺杩囨护锛�
-      if (config.gridBtn && config.gridBtn.display) {
+      let _actions = config.action.filter(item => item.position === 'toolbar') // 杩囨护宸ュ叿鏍忔寜閽�
+      let _operations = config.action.filter(item => item.position === 'grid') // 娣诲姞鎿嶄綔鍒楋紙瀛樺湪鏃讹級
+
+      if (config.gridBtn && config.gridBtn.display && _operations.length > 0) {
         _columns.push({
           ...config.gridBtn,
-          operations: config.action.filter(item => item.position === 'grid')
+          operations: _operations
         })
       }
 
-      let _actions = config.action.filter(item => item.position === 'toolbar') // 杩囨护宸ュ叿鏍忔寜閽紙鏈粡杩囨潈闄愯繃婊わ級
-      let _isLinkMain = false        // 妫�鏌ユ槸鍚︽湁涓庝富琛ㄥ叧鑱旂殑瀛愯〃
+      
+      let _isLinkMain = false // 妫�鏌ユ槸鍚︽湁涓庝富琛ㄥ叧鑱旂殑瀛愯〃
       let supmenus = {}
       config.tabgroups.forEach(group => {
         if (config[group] && config[group].length > 0) {
@@ -209,6 +222,11 @@
 
       if (item.resourceType === '1' && item.dataSource) {
         let arrfield = item.valueField + ',' + item.valueText
+
+        if (item.valueField === item.valueText) { // value 涓� text 瀛楁鐩稿悓鏃�
+          arrfield = item.valueField
+        }
+
         if (item.type === 'link') {
           arrfield = arrfield + ',' + item.linkField
         }
@@ -630,11 +648,41 @@
    * @description 瑙﹀彂鎸夐挳寮圭獥锛堟爣绛鹃〉锛�
    */
   triggerPopview = (btn, data) => {
-    this.setState({
-      popAction: btn,
-      popData: data[0] ? data[0] : null,
-      visible: true
-    })
+    console.log(btn)
+    if (btn.OpenType === 'popview') {
+      this.setState({
+        popAction: btn,
+        popData: data[0] ? data[0] : null,
+        visible: true
+      })
+    } else if (btn.OpenType === 'tab') {
+      // const { tabviews, MenuNo, MenuID } = this.props
+      // let newtab = {
+      //   MenuNo: MenuNo,
+      //   MenuID: btn.uuid,
+      //   MenuName: btn.label,
+      //   type: btn.tabTemplate,
+      //   selected: true,
+      //   param: {
+      //     btn: btn,
+      //     data: data
+      //   }
+      // }
+
+      // let index = 0
+      // let tabs = tabviews.map((tab, i) => {
+      //   if (tab.MenuID === MenuID) {
+      //     index = i
+      //   }
+      //   tab.selected = false
+
+      //   return tab
+      // })
+
+      // tabs.splice(index + 1, 0, newtab)
+      
+      // this.props.modifyTabview(tabs)
+    }
   }
 
   popclose = () => {
@@ -770,4 +818,21 @@
       </div>
     )
   }
-}
\ No newline at end of file
+}
+
+const mapStateToProps = (state) => {
+  return {
+    tabviews: state.tabviews,
+    refreshTab: state.refreshTab,
+    permAction: state.permAction
+  }
+}
+
+const mapDispatchToProps = (dispatch) => {
+  return {
+    refreshTabView: (refreshTab) => dispatch(refreshTabView(refreshTab)),
+    modifyTabview: (tabviews) => dispatch(modifyTabview(tabviews))
+  }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(NormalTable)
\ No newline at end of file
diff --git a/src/tabviews/formtab/index.jsx b/src/tabviews/formtab/index.jsx
new file mode 100644
index 0000000..5220a23
--- /dev/null
+++ b/src/tabviews/formtab/index.jsx
@@ -0,0 +1,806 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import {connect} from 'react-redux'
+import { is, fromJS } from 'immutable'
+import { BackTop, notification, Spin, Tabs, Icon, Switch, Modal, Button} from 'antd'
+import moment from 'moment'
+import Api from '@/api'
+import MainTable from './mainTable'
+import MainAction from '@/tabviews/tableshare/actionList'
+import MainSearch from '@/tabviews/tableshare/topSearch'
+import SubTable from '@/tabviews/subtable'
+import NotFount from '@/components/404'
+import asyncComponent from '@/utils/asyncLoadComponent'
+import {refreshTabView} from '@/store/action'
+import zhCN from '@/locales/zh-CN/main.js'
+import enUS from '@/locales/en-US/main.js'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const SubTabTable = asyncComponent(() => import('@/tabviews/subtabtable'))
+const { TabPane } = Tabs
+
+class NormalTable extends Component {
+  static propTpyes = {
+    MenuNo: PropTypes.string,    // 鑿滃崟鍙傛暟
+    MenuName: PropTypes.string,  // 鑿滃崟鍙傛暟
+    MenuID: PropTypes.string     // 鑿滃崟Id
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    loadingview: true,    // 椤甸潰鍔犺浇涓�
+    viewlost: false,      // 椤甸潰涓㈠け锛�1銆佹湭鑾峰彇鍒伴厤缃�-椤甸潰涓㈠け锛�2銆侀〉闈㈡湭鍚敤
+    lostmsg: '',          // 椤甸潰涓㈠け鏃剁殑鎻愮ず淇℃伅
+    config: {},           // 椤甸潰閰嶇疆淇℃伅锛屽寘鎷寜閽�佹悳绱€�佹樉绀哄垪銆佹爣绛剧瓑
+    searchlist: null,     // 鎼滅储鏉′欢
+    actions: null,        // 鎸夐挳闆�
+    columns: null,        // 鏄剧ず鍒�
+    arr_field: '',        // 浣跨敤 sPC_Get_TableData 鏃剁殑鏌ヨ瀛楁闆�
+    setting: null,        // 椤甸潰鍏ㄥ眬璁剧疆锛氭暟鎹簮銆佹寜閽強鏄剧ず鍒楀浐瀹氥�佷富閿瓑
+    data: null,           // 鍒楄〃鏁版嵁闆�
+    total: 0,             // 鎬绘暟
+    loading: false,       // 鍒楄〃鏁版嵁鍔犺浇涓�
+    pageIndex: 1,         // 椤电爜
+    pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
+    orderColumn: '',      // 鎺掑簭瀛楁
+    orderType: 'asc',     // 鎺掑簭鏂瑰紡
+    search: '',           // 鎼滅储鏉′欢鏁扮粍锛屼娇鐢ㄦ椂闇�鍒嗗満鏅鐞�
+    configMap: {},        // 椤甸潰閰嶇疆淇℃伅锛氫笅鎷夈�佹寜閽瓑
+    BIDs: {},             // 涓婄骇琛╥d
+    setsingle: false,     // 涓昏〃鍗曢�夊閫夊垏鎹�
+    pickup: false,        // 涓昏〃鏁版嵁闅愯棌鏄剧ず鍒囨崲
+    isLinkMain: false,    // 鏄惁瀛樺湪涓庝富琛ㄥ叧鑱旂殑瀛愯〃
+    popAction: false,     // 寮规椤甸潰锛屾寜閽俊鎭�
+    popData: false,       // 寮规椤甸潰锛屾墍閫夌殑琛ㄦ牸鏁版嵁
+    visible: false        // 寮规鏄剧ず闅愯棌鎺у埗
+  }
+
+  /**
+   * @description 鑾峰彇椤甸潰閰嶇疆淇℃伅
+   */
+  async loadconfig () {
+    const { permAction } = this.props
+
+    let param = {
+      func: 'sPC_Get_LongParam',
+      MenuID: this.props.MenuID
+    }
+    let result = await Api.getSystemCacheConfig(param)
+    if (result.status) {
+      let config = ''
+
+      try { // 閰嶇疆淇℃伅瑙f瀽
+        config = window.decodeURIComponent(window.atob(result.LongParam))
+        config = JSON.parse(config)
+      } catch (e) {
+        config = ''
+      }
+
+      // 椤甸潰閰嶇疆瑙f瀽閿欒鏃舵彁绀�
+      if (!config) {
+        this.setState({
+          loadingview: false,
+          viewlost: true
+        })
+        return
+      }
+
+      // 椤甸潰鏈惎鐢ㄦ椂锛屾樉绀烘湭鍚敤椤甸潰
+      if (!config.enabled) {
+        this.setState({
+          loadingview: false,
+          viewlost: true,
+          lostmsg: this.state.dict['main.view.unenabled']
+        })
+        return
+      }
+
+      let _arrField = []     // 瀛楁闆�
+      let _columns = []      // 鏄剧ず鍒�
+      let _hideCol = []      // 闅愯棌鍙婂悎骞跺垪涓瓧娈电殑uuid闆�
+      let colMap = new Map()
+
+      // 鏉冮檺杩囨护
+      config.action = config.action.filter(item => permAction[item.uuid])
+      // config.tabgroups.forEach(group => {
+      //   if (!config[group]) return
+      //   config[group] = config[group].filter(tab => permAction[tab.uuid])
+      // })
+
+      // 1銆佺瓫閫夊瓧娈甸泦锛�2銆佽繃婊ら殣钘忓垪鍙婂悎骞跺垪涓殑瀛楁uuid
+      config.columns.forEach(col => {
+        if (col.field) {
+          _arrField.push(col.field)
+        }
+        if (col.type === 'colspan' && col.sublist) { // 绛涢�夐殣钘忓垪
+          _hideCol = _hideCol.concat(col.sublist)
+        } else if (col.Hide === 'true') {
+          _hideCol.push(col.uuid)
+        }
+        colMap.set(col.uuid, col)
+      })
+
+      // 鐢熸垚鏄剧ず鍒楋紝澶勭悊鍚堝苟鍒椾腑鐨勫瓧娈�
+      config.columns.forEach(col => {
+        if (_hideCol.includes(col.uuid)) return
+
+        if (col.type === 'colspan' && col.sublist) {
+          let _col = JSON.parse(JSON.stringify(col))
+          let subColumn = []
+          _col.sublist.forEach(sub => {
+            if (colMap.has(sub)) {
+              subColumn.push(colMap.get(sub))
+            }
+          })
+          _col.subColumn = subColumn
+          _columns.push(_col)
+        } else {
+          _columns.push(col)
+        }
+      })
+
+      let _actions = config.action.filter(item => item.position === 'toolbar') // 杩囨护宸ュ叿鏍忔寜閽�
+      let _operations = config.action.filter(item => item.position === 'grid') // 娣诲姞鎿嶄綔鍒楋紙瀛樺湪鏃讹級
+
+      if (config.gridBtn && config.gridBtn.display && _operations.length > 0) {
+        _columns.push({
+          ...config.gridBtn,
+          operations: _operations
+        })
+      }
+
+      
+      let _isLinkMain = false // 妫�鏌ユ槸鍚︽湁涓庝富琛ㄥ叧鑱旂殑瀛愯〃
+      let supmenus = {}
+      config.tabgroups.forEach(group => {
+        if (config[group] && config[group].length > 0) {
+          config[group] = config[group].map(tab => {
+            if (tab.subtabs && tab.subtabs.length > 0) {
+              tab.subtabs.forEach(id => {
+                supmenus[id] = tab.uuid
+              })
+            }
+            if (config.setting.subtabs.includes(tab.uuid)) {
+              tab.supMenu = 'mainTable'
+              _isLinkMain = true
+            } else if (supmenus[tab.uuid]) {
+              tab.supMenu = supmenus[tab.uuid]
+            }
+
+            return tab
+          })
+        }
+      })
+
+      this.setState({
+        loadingview: false,
+        config: config,
+        setting: config.setting,
+        searchlist: config.search,
+        actions: _actions,
+        columns: _columns,
+        isLinkMain: _isLinkMain,
+        arr_field: _arrField.join(','),
+        search: Utils.initMainSearch(config.search), // 鎼滅储鏉′欢鍒濆鍖栵紙鍚湁鏃堕棿鏍煎紡锛岄渶瑕佽浆鍖栵級
+        loading: true
+      }, () => {
+        this.improveSearch()
+
+        if (config.setting.onload !== 'false') {
+          this.loadmaindata()
+        }
+      })
+    } else {
+      this.setState({
+        loadingview: false,
+        viewlost: true
+      })
+      notification.warning({
+        top: 92,
+        message: result.message,
+        duration: 10
+      })
+    }
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢涓嬫媺閫夐」棰勫姞杞�
+   */
+  improveSearch = () => {
+    let searchlist = JSON.parse(JSON.stringify(this.state.searchlist))
+    let deffers = []
+    searchlist.forEach(item => {
+      if (item.type !== 'multiselect' && item.type !== 'select' && item.type !== 'link') return
+      if (item.setAll === 'true') {
+        item.options.unshift({
+          key: Utils.getuuid(),
+          Value: '',
+          Text: this.state.dict['main.all']
+        })
+      }
+
+      if (item.resourceType === '1' && item.dataSource) {
+        let arrfield = item.valueField + ',' + item.valueText
+
+        if (item.valueField === item.valueText) { // value 涓� text 瀛楁鐩稿悓鏃�
+          arrfield = item.valueField
+        }
+
+        if (item.type === 'link') {
+          arrfield = arrfield + ',' + item.linkField
+        }
+
+        let _sql = Utils.getSelectQuerySql(item)
+        _sql = Utils.formatOptions(_sql)
+
+        let param = {
+          func: 'sPC_Get_SelectedList',
+          LText: _sql,
+          obj_name: 'data',
+          arr_field: arrfield
+        }
+
+        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+
+        let defer = new Promise(resolve => {
+          Api.getSystemCacheConfig(param).then(res => {
+            res.search = item
+            resolve(res)
+          })
+        })
+        deffers.push(defer)
+      } else if (item.resourceType === '1' && !item.dataSource) {
+        notification.warning({
+          top: 92,
+          message: item.label + ': ' + this.state.dict['main.datasource.settingerror'],
+          duration: 10
+        })
+      }
+    })
+
+    if (deffers.length === 0) {
+      this.setState({searchlist: JSON.parse(JSON.stringify(searchlist))})
+      return
+    }
+
+    Promise.all(deffers).then(result => {
+      result.forEach(res => {
+        if (res.status) {
+          searchlist = searchlist.map(item => {
+            if (item.uuid === res.search.uuid) {
+              res.data.forEach(cell => {
+                let _item = {
+                  key: Utils.getuuid(),
+                  Value: cell[res.search.valueField],
+                  Text: cell[res.search.valueText]
+                }
+
+                if (res.search.type === 'link') {
+                  _item.parentId = cell[res.search.linkField]
+                }
+
+                item.options.push(_item)
+              })
+            }
+            return item
+          })
+        } else {
+          notification.warning({
+            top: 92,
+            message: res.search.label + ':' + res.message,
+            duration: 10
+          })
+        }
+      })
+
+      this.setState({searchlist})
+    })
+  }
+
+  /**
+   * @description 涓昏〃鏁版嵁鍔犺浇
+   */ 
+  async loadmaindata () {
+    const { setting, BIDs } = this.state
+    let param = ''
+
+    if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) {
+      param = this.getCustomParam()
+    } else {
+      param = this.getDefaultParam()
+    }
+
+    this.setState({
+      pickup: false
+    })
+
+    this.handleTableId('mainTable', '')
+
+    let result = await Api.genericInterface(param)
+    if (result.status) {
+      this.setState({
+        data: result.data.map((item, index) => {
+          item.key = index
+          return item
+        }),
+        total: result.total,
+        loading: false,
+        BIDs: {
+          ...BIDs,
+          mainTable: ''
+        }
+      })
+    } else {
+      this.setState({
+        loading: false
+      })
+      notification.error({
+        top: 92,
+        message: result.message,
+        duration: 15
+      })
+    }
+  }
+
+  /**
+   * @description 鑾峰彇鐢ㄦ埛鑷畾涔夊瓨鍌ㄨ繃绋嬩紶鍙�
+   */
+  getCustomParam = () => {
+    const { pageIndex, pageSize, orderColumn, orderType, search, setting } = this.state
+
+    let _search = Utils.formatCustomMainSearch(search)
+
+    let param = {
+      PageIndex: pageIndex,
+      PageSize: pageSize,
+      OrderCol: orderColumn,
+      OrderType: orderType,
+      ..._search
+    }
+
+    if (setting.interType === 'inner') {
+      param.func = setting.innerFunc
+    } else {
+      param.rduri = setting.interface
+      if (setting.outerFunc) {
+        param.func = setting.outerFunc
+      }
+    }
+
+    return param
+  }
+
+  /**
+   * @description 鑾峰彇绯荤粺瀛樺偍杩囩▼ sPC_Get_TableData 鐨勫弬鏁�
+   */
+  getDefaultParam = () => {
+    const { arr_field, pageIndex, pageSize, orderColumn, orderType, search, setting } = this.state
+
+    let _search = Utils.joinMainSearchkey(search)
+
+    _search = _search ? 'where ' + _search : ''
+    
+    let param = {
+      func: 'sPC_Get_TableData',
+      obj_name: 'data',
+      arr_field: arr_field
+    }
+    
+    let orderBy = orderColumn ? (orderColumn + ' ' + orderType) : setting.order
+    let _dataresource = setting.dataresource
+
+    if (/\s/.test(_dataresource)) {
+      _dataresource = '(' + _dataresource + ') tb'
+    }
+
+    let LText = `select top ${pageSize} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${_dataresource} ${_search}) tmptable where rows > ${pageSize * (pageIndex - 1)} order by tmptable.rows`
+    let DateCount = `select count(1) as total from ${_dataresource} ${_search}`
+
+    param.LText = Utils.formatOptions(LText)
+    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+    param.DateCount = Utils.formatOptions(DateCount)
+
+    return param
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢鏀瑰彉鏃讹紝閲嶇疆琛ㄦ牸鏁版嵁
+   * 鍚湁鍒濆涓嶅姞杞界殑椤甸潰锛屼慨鏀硅缃�
+   */
+  refreshbysearch = (searches) => {
+    const { setting } = this.state
+
+    if (setting.onload === 'false') {
+      this.setState({
+        loading: true,
+        pageIndex: 1,
+        search: searches,
+        setting: {...setting, onload: 'true'}
+      }, () => {
+        this.loadmaindata()
+      })
+    } else {
+      this.refs.mainTable.resetTable()
+
+      this.setState({
+        loading: true,
+        pageIndex: 1,
+        search: searches
+      }, () => {
+        this.loadmaindata()
+      })
+    }
+  }
+
+  /**
+   * @description 琛ㄦ牸鏉′欢鏀瑰彉鏃堕噸缃暟鎹紙鍒嗛〉鎴栨帓搴忥級
+   */
+  refreshbytable = (pagination, filters, sorter) => {
+    if (sorter.order) {
+      let _chg = {
+        ascend: 'asc',
+        descend: 'desc'
+      }
+      sorter.order = _chg[sorter.order]
+    }
+
+    this.setState({
+      loading: true,
+      pageIndex: pagination.current,
+      pageSize: pagination.pageSize,
+      orderColumn: sorter.field || this.state.setting.orderColumn,
+      orderType: sorter.order || 'asc'
+    }, () => {
+      this.loadmaindata()
+    })
+  }
+
+  /**
+   * @description 琛ㄦ牸鍒锋柊
+   */
+  reloadtable = () => {
+    this.refs.mainTable.resetTable()
+    this.setState({
+      loading: true,
+      pageIndex: 1
+    }, () => {
+      this.loadmaindata()
+    })
+  }
+
+  /**
+   * @description 椤甸潰鍒锋柊锛岄噸鏂拌幏鍙栭厤缃�
+   */
+  reloadview = () => {
+    this.setState({
+      loadingview: true,
+      viewlost: false,
+      lostmsg: '',
+      config: {},
+      searchlist: null,
+      actions: null,
+      columns: null,
+      arr_field: '',
+      setting: null,
+      data: null,
+      total: 0,
+      loading: false,
+      pageIndex: 1,
+      pageSize: 10,
+      orderColumn: '',
+      orderType: 'asc',
+      search: '',
+      configMap: {},
+      BIDs: {},
+      setsingle: false,
+      pickup: false,
+      isLinkMain: false
+    }, () => {
+      this.loadconfig()
+    })
+  }
+
+  /**
+   * @description 鎸夐挳鎿嶄綔瀹屾垚鍚庯紙鎴愬姛鎴栧け璐ワ級锛岄〉闈㈠埛鏂帮紝閲嶇疆椤电爜鍙婇�夋嫨椤�
+   */
+  refreshbyaction = (btn, type) => {
+    if (btn.execSuccess === 'grid' && type === 'success') {
+      this.reloadtable()
+    } else if (btn.execError === 'grid' && type === 'error') {
+      this.reloadview()
+    } else if (btn.execSuccess === 'view' && type === 'success') {
+      this.reloadtable()
+    } else if (btn.execError === 'view' && type === 'error') {
+      this.reloadview()
+    } else if (btn.popClose === 'view' && type === 'pop') {
+      this.reloadview()
+    } else if (btn.popClose === 'grid' && type === 'pop') {
+      this.reloadtable()
+    } else if (type === 'excelOut') {
+      this.handleDefaultExcelout(btn)
+    }
+  }
+
+  /**
+   * @description 瀛愯〃鎿嶄綔瀹屾垚鍚庡埛鏂颁富琛�
+   */
+  handleMainTable = () => {
+    this.reloadtable()
+  }
+
+  /**
+   * @description 浣跨敤榛樿瀛樺偍杩囩▼ sPC_Get_TableData 瀵煎嚭excel琛ㄦ牸
+   */
+  handleDefaultExcelout = (btn) => {
+    const { MenuName } = this.props
+    const { arr_field, orderColumn, orderType, search, setting, config } = this.state
+
+    let _arr_labels = []      // 鍒楀悕绉伴泦
+    let _arr_label_field = [] // 鍒楀悕绉板瓧娈甸泦
+
+    config.columns.forEach(col => {
+      if (col.field) {
+        _arr_labels.push(col.label)
+        _arr_label_field.push(`${col.field} as ${col.label}`)
+      }
+    })
+
+    _arr_labels = _arr_labels.join(',')
+    _arr_label_field = _arr_label_field.join(',')
+
+    let _search = Utils.joinMainSearchkey(search)
+    _search = _search ? 'where ' + _search : ''
+
+    // 鑾峰彇excel鏁版嵁锛屼笌鑾峰彇鍒楄〃鏁版嵁涓嶅悓涓烘湭璁剧疆椤电爜绛夊弬鏁�
+    let param = {
+      func: 'sPC_Get_TableData',
+      obj_name: 'data',
+      arr_field: _arr_labels
+    }
+
+    let orderBy = orderColumn ? (orderColumn + ' ' + orderType) : setting.order
+    let _dataresource = setting.dataresource
+
+    if (/\s/.test(_dataresource)) {
+      _dataresource = '(' + _dataresource + ') tb'
+    }
+
+    let LText = `select ${_arr_label_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows`
+
+    param.LText = Utils.formatOptions(LText)
+    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+    param.DateCount = ''
+
+    let name = `${MenuName}${moment().format('YYYYMMDDHHmmss')}.xlsx`
+
+    Api.getExcelOut(param, name).then(res => {
+      if (res && res.status === false) {
+        this.refs.mainButton.execError(res, btn)
+      } else {
+        this.refs.mainButton.execSuccess(btn)
+      }
+    })
+  }
+
+  /**
+   * @description 鑾峰彇琛ㄦ牸閫夋嫨椤�
+   */
+  gettableselected = () => {
+    let data = []
+    this.refs.mainTable.state.selectedRowKeys.forEach(item => {
+      data.push(this.refs.mainTable.props.data[item])
+    })
+    return data
+  }
+
+  /**
+   * @description 琛ㄦ牸涓紝鎸夐挳瑙﹀彂浜嬩欢浼犻��
+   */
+  buttonTrigger = (btn, record) => {
+    this.refs.mainButton.actionTrigger(btn, record)
+  }
+
+  /**
+   * @description 琛ㄦ牸Id鍙樺寲
+   */
+  handleTableId = (type, id) => {
+    const { BIDs } = this.state
+
+    this.setState({
+      BIDs: {
+        ...BIDs,
+        [type]: id
+      }
+    })
+  }
+
+  /**
+   * @description 琛ㄦ牸鍗曢�夊閫夊垏鎹�
+   */
+  checkChange = () => {
+    const { setsingle, BIDs } = this.state
+
+    let _BIDs = JSON.parse(JSON.stringify(BIDs))
+    _BIDs.mainTable = ''
+
+    this.setState({
+      setsingle: !setsingle,
+      pickup: false,
+      BIDs: _BIDs
+    })
+  }
+  
+  /**
+   * @description 鏁版嵁灞曞紑鍚堝苟鍒囨崲
+   */
+  pickupChange = () => {
+    const { pickup } = this.state
+    this.setState({
+      pickup: !pickup
+    })
+  }
+
+  /**
+   * @description 瑙﹀彂鎸夐挳寮圭獥锛堟爣绛鹃〉锛�
+   */
+  triggerPopview = (btn, data) => {
+    this.setState({
+      popAction: btn,
+      popData: data[0] ? data[0] : null,
+      visible: true
+    })
+  }
+
+  popclose = () => {
+    this.setState({
+      visible: false
+    })
+    this.refreshbyaction(this.state.popAction, 'pop')
+  }
+
+  UNSAFE_componentWillMount () {
+    // 缁勪欢鍔犺浇鏃讹紝鑾峰彇鑿滃崟鏁版嵁
+    this.loadconfig()
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  render() {
+    const { setting, searchlist, actions, columns, loadingview, viewlost, setsingle, pickup, isLinkMain, config } = this.state
+
+    return (
+      <div className={'commontable ' + (isLinkMain ? 'pick-control' : '')} id={'commontable' + this.props.MenuID}>
+        {loadingview && <Spin size="large" />}
+        {searchlist && searchlist.length > 0 ?
+          <MainSearch
+            dict={this.state.dict}
+            searchlist={searchlist}
+            refreshdata={this.refreshbysearch}
+          /> : null
+        }
+        {actions && setting.onload !== 'false' ?
+          <MainAction
+            ref="mainButton"
+            BID=""
+            type="main"
+            setting={setting}
+            actions={actions}
+            dict={this.state.dict}
+            MenuID={this.props.MenuID}
+            refreshdata={this.refreshbyaction}
+            triggerPopview={this.triggerPopview}
+            gettableselected={this.gettableselected}
+          /> : null
+        }
+        {columns && setting.onload !== 'false' ?
+          <div className="main-table-box">
+            {isLinkMain ?
+              <div className="pickchange">
+                {setting.tableType === 'checkbox' ? <Switch title="鍗曢�夊垏鎹�" checkedChildren="鍗�" unCheckedChildren="澶�" defaultChecked={setsingle} onChange={this.checkChange} /> : null}
+                {this.state.BIDs.mainTable && (setting.tableType === 'radio' || setsingle) ? <Switch title="鏀惰捣" checkedChildren="寮�" unCheckedChildren="鍏�" defaultChecked={pickup} onChange={this.pickupChange} /> : null}
+              </div> : null
+            }
+            <MainTable
+              ref="mainTable"
+              pickup={pickup}
+              setting={setting}
+              columns={columns}
+              setsingle={setsingle}
+              dict={this.state.dict}
+              data={this.state.data}
+              total={this.state.total}
+              MenuID={this.props.MenuID}
+              loading={this.state.loading}
+              refreshdata={this.refreshbytable}
+              buttonTrigger={this.buttonTrigger}
+              handleTableId={this.handleTableId}
+            />
+          </div> : null
+        }
+        {setting && setting.onload !== 'false' &&
+          config.tabgroups.map(group => {
+            if (config[group].length === 0) return null
+
+            return (
+              <Tabs defaultActiveKey="0" key={group}>
+                {config[group].map((_tab, index) => {
+                  // return !_tab.supMenu || (_tab.supMenu && this.state.BIDs[_tab.supMenu]) ?
+                  return (
+                    <TabPane tab={
+                      <span>
+                        {_tab.icon ? <Icon type={_tab.icon} /> : null}
+                        {_tab.label}
+                      </span>
+                    } key={`${index}`}>
+                      {_tab.type === 'SubTable' ?
+                        <SubTable
+                          Tab={_tab}
+                          MenuID={_tab.linkTab}
+                          SupMenuID={this.props.MenuID}
+                          BID={this.state.BIDs[_tab.supMenu] || ''}
+                          handleTableId={this.handleTableId}
+                          handleMainTable={this.handleMainTable}
+                        /> : null}
+                    </TabPane>
+                  )
+                })}
+              </Tabs>
+            )
+          })
+        }
+        <Modal
+          className="popview-modal"
+          title={this.state.popAction.label}
+          width={'80vw'}
+          maskClosable={false}
+          visible={this.state.visible}
+          onCancel={this.popclose}
+          footer={[
+            <Button key="cancel" onClick={this.popclose}>{this.state.dict['main.close']}</Button>
+          ]}
+          destroyOnClose
+        >
+          {<SubTabTable SupMenuID={this.props.MenuID} MenuID={this.state.popAction.linkTab} BID={''} ID={this.state.popData ? this.state.popData[setting.primaryKey] : ''} />}
+        </Modal>
+        <BackTop>
+          <div className="ant-back-top">
+            <div className="ant-back-top-content">
+              <div className="ant-back-top-icon"></div>
+            </div>
+          </div>
+        </BackTop>
+        {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
+      </div>
+    )
+  }
+}
+
+const mapStateToProps = (state) => {
+  return {
+    refreshTab: state.refreshTab,
+    permAction: state.permAction
+  }
+}
+
+const mapDispatchToProps = (dispatch) => {
+  return {
+    refreshTabView: (refreshTab) => dispatch(refreshTabView(refreshTab))
+  }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(NormalTable)
\ No newline at end of file
diff --git a/src/tabviews/formtab/index.scss b/src/tabviews/formtab/index.scss
new file mode 100644
index 0000000..ef364c5
--- /dev/null
+++ b/src/tabviews/formtab/index.scss
@@ -0,0 +1,88 @@
+.commontable {
+  position: relative;
+  min-height: calc(100vh - 94px);
+  padding-top: 16px;
+  padding-bottom: 80px;
+  .box404 {
+    padding-top: 30px;
+  }
+  .ant-modal-mask {
+    position: absolute;
+  }
+  .ant-modal-wrap {
+    position: absolute;
+  }
+  .action-modal .ant-modal {
+    top: 40px;
+    max-width: 95%;
+    .ant-modal-body {
+      max-height: calc(100vh - 265px);
+    }
+  }
+  > .ant-spin {
+    position: fixed;
+    left: calc(50vw - 22px);
+    top: calc(50vh - 70px);
+  }
+  > .ant-tabs {
+    padding: 0px 20px;
+    .ant-tabs-tab:not(.ant-tabs-tab-active) {
+      cursor: pointer;
+    }
+  }
+  > .ant-card {
+    margin: 0 20px 20px;
+    > .ant-card-head {
+      border: 0;
+      padding: 0;
+      min-height: 30px;
+      .ant-card-head-title {
+        padding: 10px 0 0;
+        span {
+          color: #1890ff;
+          display: inline-block;
+          padding: 0 10px;
+          font-size: 15px;
+          border-bottom: 1px solid #1890ff;
+          i {
+            margin-right: 10px;
+          }
+        }
+      }
+    }
+    > .ant-card-body {
+      padding: 0;
+    }
+  }
+  .main-table-box {
+    position: relative;
+    .pickchange {
+      position: absolute;
+      right: 0px;
+      top: -25px;
+      .ant-switch {
+        z-index: 1;
+        float: right;
+        margin-right: 20px;
+        margin-bottom: 5px;
+      }
+    }
+  }
+  .ant-tabs + .ant-tabs {
+    margin-top: 20px;
+  }
+}
+.commontable.pick-control {
+  >.button-list {
+    padding-right: 140px;
+  }
+}
+.ant-back-top {
+  bottom: 30px;
+  right: 30px;
+}
+.popview-modal {
+  .ant-modal-body {
+    min-height: 300px;
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/formtab/mainTable/index.jsx b/src/tabviews/formtab/mainTable/index.jsx
new file mode 100644
index 0000000..b2223cd
--- /dev/null
+++ b/src/tabviews/formtab/mainTable/index.jsx
@@ -0,0 +1,393 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Table, message, Affix, Button, Typography } from 'antd'
+import './index.scss'
+
+const { Paragraph } = Typography
+
+export default class MainTable extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,        // 瀛楀吀椤�
+    MenuID: PropTypes.string,      // 鑿滃崟Id
+    setting: PropTypes.object,     // 琛ㄦ牸鍏ㄥ眬璁剧疆锛歵ableType锛堣〃鏍兼槸鍚﹀彲閫夈�佸崟閫夈�佸閫夛級銆乧olumnfixed锛堝垪鍥哄畾锛夈�乤ctionfixed锛堟寜閽浐瀹氾級
+    pickup: PropTypes.any,         // 鏁版嵁鏀惰捣
+    setsingle: PropTypes.any,      // 璁剧疆鍗曢�夊閫�
+    columns: PropTypes.array,      // 琛ㄦ牸鍒�
+    data: PropTypes.any,           // 琛ㄦ牸鏁版嵁
+    total: PropTypes.number,       // 鎬绘暟
+    loading: PropTypes.bool,       // 琛ㄦ牸鍔犺浇涓�
+    refreshdata: PropTypes.func,   // 琛ㄦ牸涓帓搴忓垪銆侀〉鐮佺殑鍙樺寲鏃跺埛鏂�
+    buttonTrigger: PropTypes.func, // 琛ㄦ牸涓寜閽Е鍙戞搷浣�
+    handleTableId: PropTypes.func  // 鏁版嵁鍒囨崲
+  }
+
+  state = {
+    selectedRowKeys: [],  // 琛ㄦ牸涓�変腑琛�
+    pageIndex: 1,         // 鍒濆椤甸潰绱㈠紩
+    pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
+    columns: null,        // 鏄剧ず鍒�
+    selectId: '',
+    isSingleSelect: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { columns, setting } = this.props
+    let _columns = []
+    
+    columns.forEach(item => {
+      let cell = {
+        align: item.Align,
+        dataIndex: item.field || item.uuid,
+        title: item.label,
+        sorter: item.field && item.IsSort === 'true',
+        width: item.Width || 120,
+        render: (text, record) => {
+          return this.getContent(item, record)
+        }
+      }
+      _columns.push(cell)
+    })
+
+    this.setState({
+      columns: _columns,
+      isSingleSelect: setting.tableType === 'radio'
+    })
+  }
+
+  UNSAFE_componentWillReceiveProps(nextProps) {
+    if (!is(fromJS(this.props.setsingle), fromJS(nextProps.setsingle))) {
+      this.setState({
+        isSingleSelect: nextProps.setsingle,
+        selectedRowKeys: [],
+        selectId: ''
+      })
+    }
+  }
+
+  getContent = (item, record) => {
+    if (item.type === 'text') {
+      let content = ''
+      let match = false
+      if (item.field && record.hasOwnProperty(item.field)) {
+        content = `${record[item.field]}`
+      }
+
+      if (content && item.matchVal && content.indexOf(item.matchVal) > 0) {
+        match = true
+      }
+
+      content = (item.prefix || '') + content + (item.postfix || '')
+
+      return (
+        <div className={match ? item.color : ''}>
+          <div className="background"></div>
+          <div className="content" style={{ minWidth: (item.Width || 120) + 'px' }}>
+            {content}
+          </div>
+        </div>
+      )
+    } else if (item.type === 'number') {
+      let content = ''
+      let match = false
+      if (item.field && record.hasOwnProperty(item.field)) {
+        content = +record[item.field]
+      }
+
+      if (content && item.match && item.matchVal) {
+        if (item.match === '>') {
+          if (content > item.matchVal) {
+            match = true
+          }
+        } else if (item.match === '<') {
+          if (content < item.matchVal) {
+            match = true
+          }
+        } else if (item.match === '>=') {
+          if (content >= item.matchVal) {
+            match = true
+          }
+        } else if (item.match === '<=') {
+          if (content <= item.matchVal) {
+            match = true
+          }
+        }
+      }
+
+      if (content && item.format === 'thdSeparator') {
+        content = `${content}`
+        content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
+      }
+
+      content = (item.prefix || '') + content + (item.postfix || '')
+
+      return (
+        <div className={match ? item.color : ''}>
+          <div className={'background'}></div>
+          <div className="content" style={{ minWidth: (item.Width || 120) + 'px' }}>
+            {content}
+          </div>
+        </div>
+      )
+    } else if (item.type === 'picture') {
+      let photos = ''
+      if (item.field && record.hasOwnProperty(item.field)) {
+        photos = record[item.field].split(',')
+      } else {
+        photos = ''
+      }
+      return (
+        <div className="picture-col" style={{ minWidth: (item.Width || 120) + 'px' }}>
+          {photos && photos.map((url, i) => {
+            return <img key={`${i}`} src={url} alt=""/>
+          })}
+        </div>
+      )
+    } else if (item.type === 'textarea') {
+      let content = ''
+      let match = false
+      if (item.field && record.hasOwnProperty(item.field)) {
+        content = `${record[item.field]}`
+      }
+
+      if (content && item.matchVal && content.indexOf(item.matchVal) > 0) {
+        match = true
+      }
+
+      content = (item.prefix || '') + content + (item.postfix || '')
+
+      return (
+        <div className={match ? item.color : ''}>
+          <div className="background"></div>
+          <div className="content" style={{ minWidth: (item.Width || 120) + 'px' }}>
+            <Paragraph copyable ellipsis={{ rows: 3, expandable: true }}>{content}</Paragraph>
+          </div>
+        </div>
+      )
+    } else if (item.type === 'action') {
+      return (
+        <div className={item.style} style={{ minWidth: (item.Width || 120) + 'px' }}>
+          {item.operations.map(btn => {
+            return <Button
+              className={'mk-btn mk-' + btn.class}
+              icon={btn.icon}
+              key={btn.uuid}
+              onClick={(e) => {this.actionTrigger(e, btn, record)}}
+            >{btn.label}</Button>
+          })}
+        </div>
+      )
+    } else if (item.type === 'colspan') {
+      let contents = ''
+      if (item.subColumn.length > 0) {
+        contents = item.subColumn.map(col => {
+          let content = ''
+          if (col.type === 'text' || col.type === 'textarea') {
+            if (col.field && record.hasOwnProperty(col.field)) {
+              content = `${record[col.field]}`
+            }
+
+            content = (col.prefix || '') + content + (col.postfix || '')
+          } else if (col.type === 'number') {
+            if (col.field && record.hasOwnProperty(col.field)) {
+              content = +record[col.field]
+            }
+            if (content && col.format === 'thdSeparator') {
+              content = `${content}`
+              content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
+            }
+            content = (col.prefix || '') + content + (col.postfix || '')
+          }
+          return content
+        })
+      }
+
+      if (contents && item.order === 'vertical2') {
+        let _contents = []
+        for(let i = 0; i < contents.length; i += 2) {
+          _contents.push(contents.slice(i, i + 2).join(' '))
+        }
+        contents = _contents
+      }
+
+      return (
+        <div>
+          <div className="content" style={{ minWidth: (item.Width || 120) + 'px' }}>
+            {contents && item.order === 'vertical' && contents.map((content, index) => {
+              return (<p key={index}>{content}</p>)
+            })}
+            {contents && item.order === 'vertical2' && contents.map((content, index) => {
+              return (<p key={index}>{content}</p>)
+            })}
+            {contents && item.order === 'horizontal' && contents.map((content, index) => {
+              return (<span key={index}>{content}</span>)
+            })}
+          </div>
+        </div>
+      )
+    }
+  }
+
+  actionTrigger = (e, btn, record) => {
+    e.stopPropagation()
+    this.props.buttonTrigger(btn, record)
+  }
+
+  copycontent = (e, content) => {
+    // 琛ㄦ牸涓唴瀹瑰鍒�
+    e.stopPropagation()
+    let oInput = document.createElement('input')
+    oInput.value = content
+    document.body.appendChild(oInput)
+    oInput.select()
+    document.execCommand('Copy')
+    oInput.className = 'oInput'
+    oInput.style.display='none'
+    message.success(this.props.dict['main.copy.success'])
+  }
+
+  onSelectChange = selectedRowKeys => {
+    if (this.props.pickup) return
+
+    let index = ''
+    if (selectedRowKeys.length > 0) {
+      index = selectedRowKeys[selectedRowKeys.length - 1]
+    }
+
+    this.changedata(index)
+
+    this.setState({ selectedRowKeys })
+  }
+
+  changeRow = (record, index) => {
+    // 鐐瑰嚮鏁磋锛岃Е鍙戝垏鎹紝鍒ゆ柇鏄惁鍙�夛紝鍗曢�夋垨澶氶�夛紝杩涜瀵瑰簲鎿嶄綔
+    if (!this.props.setting.tableType || this.props.pickup) return
+    
+    let newkeys = JSON.parse(JSON.stringify(this.state.selectedRowKeys))
+    let _re = newkeys.includes(index)
+
+    if (this.props.setting.tableType === 'radio' || this.state.isSingleSelect) {
+      this.changedata(index)
+      this.setState({ selectedRowKeys: [index] })
+    } else {
+      if (_re) {
+        newkeys = newkeys.filter(item => item !== index)
+        this.changedata('')
+      } else {
+        newkeys.push(index)
+        this.changedata(index)
+      }
+
+      this.setState({ selectedRowKeys: newkeys })
+    }
+  }
+
+  changeTable = (pagination, filters, sorter) => {
+    this.setState({
+      pageIndex: pagination.current,
+      pageSize: pagination.pageSize,
+      selectedRowKeys: []
+    })
+    this.props.refreshdata(pagination, filters, sorter)
+  }
+
+  changedata = (index) => {
+    const { data, setting } = this.props
+    let _id = ''
+
+    if (data && data.length > 0 && index !== '') {
+      _id = data[index][setting.primaryKey] || ''
+    }
+
+    this.setState({
+      selectId: _id
+    })
+
+    this.props.handleTableId('mainTable', _id)
+  }
+
+  resetTable = () => {
+    this.setState({
+      pageIndex: 1,
+      selectId: '',
+      selectedRowKeys: []
+    })
+  }
+
+  render() {
+    const { setting, pickup } = this.props
+    let { selectedRowKeys, isSingleSelect, selectId } = this.state
+
+    let rowSelection = null
+    if (setting.tableType) {
+      rowSelection = {
+        selectedRowKeys,
+        type: (setting.tableType === 'radio' || isSingleSelect) ? 'radio' : 'checkbox',
+        onChange: this.onSelectChange
+      }
+    }
+    let offset = null
+    if (setting.columnfixed) {
+      // 琛ㄦ牸澶撮儴鍥哄畾浜庨《閮ㄦ椂锛屽垽鏂窛椤堕儴楂樺害
+      if (!setting.actionfixed) {
+        offset = 48
+      } else {
+        let box = document.getElementById(this.props.MenuID + 'mainaction')
+        if (box) {
+          offset = 48 + box.offsetHeight
+        } else {
+          offset = 105
+        }
+      }
+    }
+
+    let _data = this.props.data ? this.props.data : []
+
+    if (selectId && pickup && isSingleSelect) {
+      _data = _data.filter(item => item[setting.primaryKey] === selectId)
+    }
+
+    return (
+      <div className="main-table">
+        {setting.columnfixed && <Affix offsetTop={offset} className="fix-header">
+          <Table
+            size="middle"
+            bordered={true}
+            rowSelection={rowSelection}
+            columns={this.state.columns.map(column => {
+              return {
+                align: column.align,
+                dataIndex: column.dataIndex,
+                title: column.title,
+                width: column.width
+              }
+            })}
+          />
+        </Affix>}
+        <Table
+          size="middle"
+          bordered={true}
+          rowSelection={rowSelection}
+          columns={this.state.columns}
+          dataSource={_data}
+          loading={this.props.loading}
+          scroll={{ x: '100%', y: false }}
+          onRow={(record, index) => {
+            return {
+              onClick: () => {this.changeRow(record, index)}
+            }
+          }}
+          onChange={this.changeTable}
+          pagination={{
+            current: this.state.pageIndex,
+            pageSize: this.state.pageSize,
+            pageSizeOptions: ['10', '25', '50', '100', '500', '1000'],
+            showSizeChanger: true,
+            total: this.props.total,
+            showTotal: (total, range) => `${range[0]}-${range[1]} ${this.props.dict['main.pagination.of']} ${total} ${this.props.dict['main.pagination.items']}`
+          }}
+        />
+      </div>
+    )
+  }
+}
diff --git a/src/tabviews/formtab/mainTable/index.scss b/src/tabviews/formtab/mainTable/index.scss
new file mode 100644
index 0000000..93f37b9
--- /dev/null
+++ b/src/tabviews/formtab/mainTable/index.scss
@@ -0,0 +1,133 @@
+.main-table {
+  padding: 0 20px 30px;
+  table {
+    max-width: 100%;
+    width: 100%;
+    .ant-table-column-title {
+      white-space: nowrap;
+    }
+    .ant-table-selection-column {
+      width: 60px;
+      min-width: 60px;
+      max-width: 60px;
+    }
+    // .ant-table-tbody > tr td:not(.ant-table-selection-column) {
+    //   padding: 0!important;
+    // }
+    // .ant-table-tbody > tr td .content {
+    //   padding: 12px 8px;
+    //   height: 100%;
+    //   background: lightblue;
+    // }
+    .ant-table-tbody > tr.ant-table-row-selected td {
+      background-color: #c4ebfd;
+    }
+    .ant-table-tbody > tr.ant-table-row-selected:hover .ant-table-column-sort {
+      background-color: #c4ebfd;
+    }
+  }
+  .ant-table-body {
+    overflow-x: auto!important;
+    min-height: 90px;
+    border: 1px solid #e8e8e8;
+    border-radius: 4px;
+    border-top: none;
+    border-bottom: none;
+    table {
+      border-left: 0;
+      .ant-table-thead > tr > th:last-child {
+        border-right: 0;
+      }
+      .ant-table-tbody > tr > td:last-child {
+        border-right: 0;
+      }
+      .ant-table-tbody > tr > td {
+        vertical-align: top;
+        .content {
+          position: relative;
+          z-index: 1;
+          word-wrap: break-word;
+          word-break: break-word;
+        }
+        .picture-col {
+          img {
+            max-width: 100%;
+          }
+        }
+      }
+      .ant-table-tbody > tr > td.ant-table-column-has-actions {
+        position: relative;
+        .background {
+          position: absolute;
+          top: 0px;
+          left: 0px;
+          right: 0px;
+          bottom: 0px;
+        }
+        
+        .content {
+          position: relative;
+          z-index: 1;
+          word-wrap: break-word;
+          word-break: break-word;
+        }
+        .red {
+          .content {
+            color: red;
+          }
+        }
+        .redbg {
+          .background {
+            background: lightcoral;
+          }
+        }
+      }
+      .ant-table-tbody > tr > td .content {
+        p {
+          margin-bottom: 5px;
+        }
+        span {
+          display: inline-block;
+          margin-right: 5px;
+        }
+      }
+      .ant-table-tbody > tr > td .button {
+        .ant-btn {
+          margin-bottom: 10px;
+        }
+      }
+    }
+  }
+  .ant-table-body::-webkit-scrollbar {
+    width: 8px;
+    height: 10px;
+  }
+  ::-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);
+  }
+  ::-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);
+  }
+  .fix-header {
+    .ant-table-body {
+      min-height: unset
+    }
+    .ant-table-placeholder {
+      display: none;
+    }
+    .ant-table-wrapper {
+      display: none;
+    }
+    .ant-affix .ant-table-wrapper {
+      display: block;
+    }
+    // .ant-table-column-sorter, .anticon-filter {
+    //   display: none;
+    // }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/subtable/index.jsx b/src/tabviews/subtable/index.jsx
index 03dd628..aed40e9 100644
--- a/src/tabviews/subtable/index.jsx
+++ b/src/tabviews/subtable/index.jsx
@@ -1,5 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
+import {connect} from 'react-redux'
 import { is, fromJS } from 'immutable'
 import { notification, Spin, Modal, Button} from 'antd'
 import moment from 'moment'
@@ -16,7 +17,7 @@
 
 const SubTabTable = asyncComponent(() => import('@/tabviews/subtabtable'))
 
-export default class SubTabViewTable extends Component {
+class SubTabViewTable extends Component {
   static propTpyes = {
     Tab: PropTypes.object,           // 鏍囩淇℃伅
     BID: PropTypes.string,           // 涓婄骇鏁版嵁ID
@@ -64,6 +65,8 @@
    * @description 鑾峰彇椤甸潰閰嶇疆淇℃伅
    */
   async loadconfig () {
+    const { permAction } = this.props
+    console.log(permAction)
     let param = {
       func: 'sPC_Get_LongParam',
       MenuID: this.props.MenuID
@@ -103,6 +106,9 @@
       let _hideCol = []      // 闅愯棌鍙婂悎骞跺垪涓瓧娈电殑uuid闆�
       let colMap = new Map()
 
+      // 鏉冮檺杩囨护
+      config.action = config.action.filter(item => permAction[item.uuid])
+
       // 1銆佺瓫閫夊瓧娈甸泦锛�2銆佽繃婊ら殣钘忓垪鍙婂悎骞跺垪涓殑瀛楁uuid
       config.columns.forEach(col => {
         if (col.field) {
@@ -135,16 +141,15 @@
         }
       })
 
-      // 娣诲姞鎿嶄綔鍒楋紙瀛樺湪鏃讹級锛堟湭缁忚繃鏉冮檺杩囨护锛�
-      if (config.gridBtn && config.gridBtn.display) {
+      let _actions = config.action.filter(item => item.position === 'toolbar') // 杩囨护宸ュ叿鏍忔寜閽�
+      let _operations = config.action.filter(item => item.position === 'grid')  // 娣诲姞鎿嶄綔鍒楋紙瀛樺湪鏃讹級
+
+      if (config.gridBtn && config.gridBtn.display && _operations.length > 0) {
         _columns.push({
           ...config.gridBtn,
-          operations: config.action.filter(item => item.position === 'grid')
+          operations: _operations
         })
       }
-
-      // 杩囨护宸ュ叿鏍忔寜閽紙鏈粡杩囨潈闄愯繃婊わ級
-      let _actions = config.action.filter(item => item.position === 'toolbar')
 
       this.setState({
         loadingview: false,
@@ -191,6 +196,11 @@
 
       if (item.resourceType === '1' && item.dataSource) {
         let arrfield = item.valueField + ',' + item.valueText
+
+        if (item.valueField === item.valueText) { // value 涓� text 瀛楁鐩稿悓鏃�
+          arrfield = item.valueField
+        }
+
         if (item.type === 'link') {
           arrfield = arrfield + ',' + item.linkField
         }
@@ -643,4 +653,16 @@
       </div>
     )
   }
-}
\ No newline at end of file
+}
+
+const mapStateToProps = (state) => {
+  return {
+    permAction: state.permAction
+  }
+}
+
+const mapDispatchToProps = () => {
+  return {}
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(SubTabViewTable)
\ No newline at end of file
diff --git a/src/tabviews/subtabtable/index.jsx b/src/tabviews/subtabtable/index.jsx
index 45d97cd..ebc4cf5 100644
--- a/src/tabviews/subtabtable/index.jsx
+++ b/src/tabviews/subtabtable/index.jsx
@@ -1,5 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
+import {connect} from 'react-redux'
 import { is, fromJS } from 'immutable'
 import { notification, Spin} from 'antd'
 import moment from 'moment'
@@ -13,7 +14,7 @@
 import Utils from '@/utils/utils.js'
 import './index.scss'
 
-export default class NormalTable extends Component {
+class SubTabModalTable extends Component {
   static propTpyes = {
     BID: PropTypes.string,         // 涓婄骇鏁版嵁ID
     MenuID: PropTypes.string,      // 鑿滃崟Id
@@ -46,6 +47,8 @@
    * @description 鑾峰彇椤甸潰閰嶇疆淇℃伅
    */
   async loadconfig () {
+    const { permAction } = this.props
+
     let param = {
       func: 'sPC_Get_LongParam',
       MenuID: this.props.MenuID
@@ -85,6 +88,9 @@
       let _hideCol = []      // 闅愯棌鍙婂悎骞跺垪涓瓧娈电殑uuid闆�
       let colMap = new Map()
 
+      // 鏉冮檺杩囨护
+      config.action = config.action.filter(item => permAction[item.uuid])
+
       // 1銆佺瓫閫夊瓧娈甸泦锛�2銆佽繃婊ら殣钘忓垪鍙婂悎骞跺垪涓殑瀛楁uuid
       config.columns.forEach(col => {
         if (col.field) {
@@ -117,16 +123,15 @@
         }
       })
 
-      // 娣诲姞鎿嶄綔鍒楋紙瀛樺湪鏃讹級锛堟湭缁忚繃鏉冮檺杩囨护锛�
-      if (config.gridBtn && config.gridBtn.display) {
+      let _actions = config.action.filter(item => item.position === 'toolbar') // 杩囨护宸ュ叿鏍忔寜閽�
+      let _operations = config.action.filter(item => item.position === 'grid')  // 娣诲姞鎿嶄綔鍒楋紙瀛樺湪鏃讹級
+
+      if (config.gridBtn && config.gridBtn.display && _operations.length > 0) {
         _columns.push({
           ...config.gridBtn,
-          operations: config.action.filter(item => item.position === 'grid')
+          operations: _operations
         })
       }
-
-      // 杩囨护宸ュ叿鏍忔寜閽紙鏈粡杩囨潈闄愯繃婊わ級
-      let _actions = config.action.filter(item => item.position === 'toolbar')
 
       this.setState({
         loadingview: false,
@@ -173,6 +178,11 @@
 
       if (item.resourceType === '1' && item.dataSource) {
         let arrfield = item.valueField + ',' + item.valueText
+
+        if (item.valueField === item.valueText) { // value 涓� text 瀛楁鐩稿悓鏃�
+          arrfield = item.valueField
+        }
+        
         if (item.type === 'link') {
           arrfield = arrfield + ',' + item.linkField
         }
@@ -571,4 +581,16 @@
       </div>
     )
   }
-}
\ No newline at end of file
+}
+
+const mapStateToProps = (state) => {
+  return {
+    permAction: state.permAction
+  }
+}
+
+const mapDispatchToProps = () => {
+  return {}
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(SubTabModalTable)
\ No newline at end of file
diff --git a/src/tabviews/tableshare/actionList/index.jsx b/src/tabviews/tableshare/actionList/index.jsx
index ecab41d..5fb6b00 100644
--- a/src/tabviews/tableshare/actionList/index.jsx
+++ b/src/tabviews/tableshare/actionList/index.jsx
@@ -117,6 +117,8 @@
         url = url + '?ID=' + ids
       }
       window.open(url)
+    } else if (item.OpenType === 'tab' || item.OpenType === 'blank') {
+      this.props.triggerPopview(item, data)
     } else {
       notification.warning({
         top: 92,
@@ -743,6 +745,10 @@
     let deffers = subfields.map(item => {
       let arrfield = item.valueField + ',' + item.valueText
 
+      if (item.valueField === item.valueText) { // value 涓� text 瀛楁鐩稿悓鏃�
+        arrfield = item.valueField
+      }
+
       if (item.type === 'link') {
         arrfield = arrfield + ',' + item.linkField
       } else if (item.type === 'select' && item.linkSubField && item.linkSubField.length > 0) {
diff --git a/src/templates/comtableconfig/index.jsx b/src/templates/comtableconfig/index.jsx
index 5fcbc29..9977ac4 100644
--- a/src/templates/comtableconfig/index.jsx
+++ b/src/templates/comtableconfig/index.jsx
@@ -15,8 +15,7 @@
 
 import ActionForm from './actionform'
 import SettingForm from './settingform'
-import TabForm from './tabform'
-import TabDragElement from './tabdragelement'
+import TabForm from '@/templates/tableshare/tabform'
 import SearchForm from '@/templates/tableshare/searchform'
 import ColumnForm from '@/templates/tableshare/columnform'
 import DragElement from '@/templates/tableshare/dragelement'
@@ -25,6 +24,7 @@
 import EditCard from '@/templates/tableshare/editcard'
 import VerifyCard from '@/templates/tableshare/verifycard'
 import MenuForm from '@/templates/tableshare/menuform'
+import TabDragElement from '@/templates/tableshare/tabdragelement'
 import SourceElement from '@/templates/tableshare/dragelement/source'
 import Source from './source'
 import './index.scss'
@@ -347,7 +347,7 @@
     this.setState({
       modaltype: type === 'copy' ? 'actionCopy' : 'actionEdit',
       card: card,
-      formlist: getActionForm(card, functip, this.state.config, this.props.permFuncField, 'main')
+      formlist: getActionForm(card, functip, this.state.config, this.props.permFuncField)
     })
   }
 
@@ -612,9 +612,9 @@
       })
     } else if (modaltype === 'tabs') {
       this.tabsFormRef.handleConfirm().then(res => {
-        let _tabgroup = config[res.values.groupId].map(item => {
-          if (item.uuid === res.values.uuid) {
-            return res.values
+        let _tabgroup = config[res.groupId].map(item => {
+          if (item.uuid === res.uuid) {
+            return res
           } else {
             return item
           }
@@ -622,7 +622,7 @@
         _tabgroup = _tabgroup.filter(item => !item.origin)
 
         this.setState({
-          config: {...config, [res.values.groupId]: _tabgroup},
+          config: {...config, [res.groupId]: _tabgroup},
           modaltype: ''
         })
       })
@@ -1219,9 +1219,15 @@
           }
         }
 
+        // 鍒犻櫎鎸夐挳鍏冪礌
+        let _delActions = _this.state.delActions
+        if (element.type === 'action') {
+          _delActions.push(element.card.uuid)
+        }
+
         _this.setState({
           config: _config,
-          delActions: [..._this.state.delActions, element.card.uuid]
+          delActions: _delActions
         })
       },
       onCancel() {}
@@ -2162,8 +2168,7 @@
   render () {
     const { modaltype } = this.state
     const configAction = this.state.config.action.filter(_action =>
-      !_action.origin && (_action.OpenType === 'pop' || _action.OpenType === 'popview')
-      // !_action.origin && (_action.OpenType === 'pop' || _action.OpenType === 'popview' || _action.OpenType === 'blank' || _action.OpenType === 'tab')
+      !_action.origin && (_action.OpenType === 'pop' || _action.OpenType === 'popview' || _action.OpenType === 'blank' || _action.OpenType === 'tab')
     )
 
     let configTabs = []
diff --git a/src/templates/comtableconfig/tabdragelement/card.jsx b/src/templates/comtableconfig/tabdragelement/card.jsx
deleted file mode 100644
index 2437661..0000000
--- a/src/templates/comtableconfig/tabdragelement/card.jsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from 'react'
-import { useDrag, useDrop } from 'react-dnd'
-import { Icon } from 'antd'
-import './index.scss'
-
-const Card = ({ id, type, card, moveCard, findCard, editCard, delCard, hasDrop }) => {
-  const originalIndex = findCard(id).index
-  const [{ isDragging }, drag] = useDrag({
-    item: { type: type, id, originalIndex },
-    collect: monitor => ({
-      isDragging: monitor.isDragging(),
-    }),
-  })
-  const [, drop] = useDrop({
-    accept: type,
-    canDrop: () => true,
-    drop: (item) => {
-      if (!item.hasOwnProperty('originalIndex')) {
-        hasDrop(card)
-      }
-    },
-    hover({ id: draggedId }) {
-      if (!draggedId) return
-      if (draggedId !== id) {
-        const { index: overIndex } = findCard(id)
-        moveCard(draggedId, overIndex)
-      }
-    },
-  })
-  const opacity = isDragging ? 0 : 1
-
-  return (
-    <div className="page-card" style={{ opacity: opacity}}>
-      <div ref={node => drag(drop(node))}>
-        {card.icon ? <Icon type={card.icon} /> : null}
-        {card.label}
-      </div>
-    </div>
-  )
-}
-export default Card
diff --git a/src/templates/comtableconfig/tabdragelement/index.scss b/src/templates/comtableconfig/tabdragelement/index.scss
deleted file mode 100644
index 56fbd3b..0000000
--- a/src/templates/comtableconfig/tabdragelement/index.scss
+++ /dev/null
@@ -1,21 +0,0 @@
-.common-source-item {
-  display: block;
-  box-shadow: 0px 0px 2px #bcbcbc;
-  padding: 0.4rem 0.7rem;
-  background-color: white;
-  margin: 0px 0px 10px;
-  cursor: move;
-  border-radius: 4px;
-}
-.maintable-tab-list {
-  .ant-tabs-content {
-    text-align: center;
-    color: #bcbcbc;
-  }
-  .commontab-drawarea-placeholder {
-    position: absolute;
-    top: 25px;
-    left: calc(50% - 50px);
-    color: #bcbcbc;
-  }
-}
\ No newline at end of file
diff --git a/src/templates/formtabconfig/actionform/index.jsx b/src/templates/formtabconfig/actionform/index.jsx
index f768035..48c63df 100644
--- a/src/templates/formtabconfig/actionform/index.jsx
+++ b/src/templates/formtabconfig/actionform/index.jsx
@@ -81,6 +81,16 @@
           item.options = btnIcons
         } else if (item.key === 'sqlType') {
           item.options = this.state.insertUpdateOptions
+        } else if (item.key === 'OpenType') {
+          item.options = [
+            {
+              value: 'prompt',
+              text: this.props.dict['header.form.prompt']
+            }, {
+              value: 'exec',
+              text: this.props.dict['header.form.exec']
+            }
+          ]
         }
         item.hidden = !_options.includes(item.key)
         return item
@@ -292,10 +302,7 @@
               duration: 10
             })
           } else {
-            resolve({
-              type: 'action',
-              values
-            })
+            resolve(values)
           }
         } else {
           reject(err)
diff --git a/src/templates/formtabconfig/dragelement/card.jsx b/src/templates/formtabconfig/dragelement/card.jsx
index 09159fd..07b96ca 100644
--- a/src/templates/formtabconfig/dragelement/card.jsx
+++ b/src/templates/formtabconfig/dragelement/card.jsx
@@ -1,13 +1,14 @@
 import React from 'react'
 import { useDrag, useDrop } from 'react-dnd'
-import { Icon, Button, Select, DatePicker, Input } from 'antd'
+import { Icon, Button, Select, DatePicker, Input, InputNumber } from 'antd'
 import moment from 'moment'
 import ItemTypes from './itemtypes'
 import './index.scss'
 
-const { MonthPicker, WeekPicker, RangePicker } = DatePicker
+const { MonthPicker } = DatePicker
+const { TextArea } = Input
 
-const Card = ({ id, type, card, moveCard, findCard, editCard, delCard, copyCard, profileCard, hasDrop }) => {
+const Card = ({ id, type, cols, card, moveCard, findCard, editCard, delCard, copyCard, profileCard, hasDrop }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: ItemTypes[type], id, originalIndex },
@@ -74,17 +75,32 @@
     }
   }
 
+  let labelCol = 'ant-col-sm-8'
+  let wrapCol = 'ant-col-sm-16'
+  if (card.type === 'textarea') {
+    if (cols === '2') {
+      labelCol = 'ant-col-sm-4'
+      wrapCol = 'ant-col-sm-20'
+    } else if (cols === '3') {
+      labelCol = 'ant-col-cuslabel'
+      wrapCol = 'ant-col-cuswrap'
+    }
+  }
+
   return (
     <div className="page-card" style={{ opacity: opacity}}>
       <div ref={node => drag(drop(node))}>
         {type === 'search' ?
           <div className="ant-row ant-form-item">
-            <div className="ant-col ant-form-item-label ant-col-xs-24 ant-col-sm-8">
+            <div className={'ant-col ant-form-item-label ant-col-xs-24 ' + labelCol}>
               <label title={card.label}>{card.label}</label>
             </div>
-            <div className="ant-col ant-form-item-control-wrapper ant-col-xs-24 ant-col-sm-16">
+            <div className={'ant-col ant-form-item-control-wrapper ant-col-xs-24 ' + wrapCol}>
               {card.type === 'text' ?
                 <Input style={{marginTop: '4px'}} defaultValue={card.initval} /> : null
+              }
+              {card.type === 'number' ?
+                <InputNumber defaultValue={card.initval} precision={card.decimal} /> : null
               }
               {(card.type === 'multiselect' || card.type === 'select' || card.type === 'link') ?
                 <Select defaultValue={_defaultValue}></Select> : null
@@ -92,19 +108,19 @@
               {card.type === 'date' ?
                 <DatePicker defaultValue={card.initval ? moment().subtract(card.initval, 'days') : null} /> : null
               }
-              {card.type === 'dateweek' ?
-                <WeekPicker defaultValue={card.initval ? moment().subtract(card.initval * 7, 'days') : null} /> : null
-              }
               {card.type === 'datemonth' ?
                 <MonthPicker defaultValue={card.initval ? moment().subtract(card.initval, 'month') : null} /> : null
               }
-              {card.type === 'daterange' ?
-                <RangePicker
-                  className="data-range"
-                  placeholder={['寮�濮嬫棩鏈�', '缁撴潫鏃ユ湡']}
-                  renderExtraFooter={() => 'extra footer'}
-                  defaultValue={_defaultValue}
-                /> : null
+              {card.type === 'datetime' ?
+                <DatePicker showTime defaultValue={card.initval ? moment().subtract(card.initval, 'days') : null} /> : null
+              }
+              {card.type === 'textarea' ?
+                <TextArea defaultValue={card.initval} autosize={{ minRows: 2, maxRows: 6 }} /> : null
+              }
+              {card.type === 'fileupload' ?
+                <Button>
+                  <Icon type="upload" /> 鐐瑰嚮涓婁紶
+                </Button> : null
               }
               <div className="input-mask"></div>
             </div>
diff --git a/src/templates/formtabconfig/dragelement/index.jsx b/src/templates/formtabconfig/dragelement/index.jsx
index 83ca042..4912156 100644
--- a/src/templates/formtabconfig/dragelement/index.jsx
+++ b/src/templates/formtabconfig/dragelement/index.jsx
@@ -1,6 +1,7 @@
 import React, { useState } from 'react'
 import { useDrop } from 'react-dnd'
 import update from 'immutability-helper'
+import { is, fromJS } from 'immutable'
 import { Col } from 'antd'
 import Utils from '@/utils/utils.js'
 import Card from './card'
@@ -12,13 +13,19 @@
   const [cards, setCards] = useState(list)
   const moveCard = (id, atIndex) => {
     const { card, index } = findCard(id)
+
+    if (!card) return
+
     const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
-    setCards(_cards)
     if (type === 'action') {
       handleList(type, _cards)
     } else {
       handleList(type, _cards, null, groupId)
     }
+  }
+
+  if (!is(fromJS(cards), fromJS(list))) {
+    setCards(list)
   }
 
   const findCard = id => {
@@ -50,8 +57,7 @@
     copycard.uuid = Utils.getuuid()
     copycard.origin = false
     copycard.label = copycard.label + '(copy)'
-
-    copycard.originCard = card
+    copycard.focus = true
 
     copyElement(copycard)
   }
@@ -95,38 +101,24 @@
         newcard.type = item.subType
         newcard.resourceType = '0'
         newcard.options = []
-        newcard.dataSource = ''
         newcard.setAll = 'false'
-        newcard.linkField = ''
-        newcard.valueField = ''
-        newcard.valueText = ''
-        newcard.orderBy = ''
         newcard.orderType = 'asc'
         newcard.match = _match
         newcard.display = 'dropdown'
       } else if (item.type === 'action') {
         newcard.label = 'button'
-        newcard.innerFunc = ''
-        newcard.outerFunc = ''
-        newcard.sql = ''
-        newcard.sqlType = ''
         newcard.Ot = 'requiredSgl'
         newcard.OpenType = item.subType
         newcard.tabType = 'SubTable'
         newcard.linkTab = ''
-        newcard.icon = ''
         newcard.class = 'default'
         newcard.intertype = 'inner'
-        newcard.interface = ''
         newcard.method = 'POST'
         newcard.position = 'toolbar'
         newcard.execSuccess = 'grid'
         newcard.execError = 'never'
         newcard.popClose = 'never'
         newcard.errorTime = 15
-        newcard.callbackFunc = ''
-        newcard.pageTemplate = ''
-        newcard.url = ''
         newcard.verify = null
       }
       
@@ -141,7 +133,6 @@
       targetIndex++
 
       const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
-      setCards(_cards)
       handleList(type, _cards, newcard, groupId)
       target = null
     }
@@ -165,12 +156,13 @@
         />
       ))}
       {type === 'search' && cards.map(card => (
-        <Col key={card.uuid} span={24 / setting.cols}>
+        <Col key={card.uuid} span={card.type !== 'textarea' ? 24 / setting.cols : 24}>
           <Card
             id={card.uuid}
             key={card.uuid}
             type={type}
             card={card}
+            cols={setting.cols}
             moveCard={moveCard}
             editCard={editCard}
             delCard={delCard}
diff --git a/src/templates/formtabconfig/groupform/index.jsx b/src/templates/formtabconfig/groupform/index.jsx
index ee1c03c..139ba52 100644
--- a/src/templates/formtabconfig/groupform/index.jsx
+++ b/src/templates/formtabconfig/groupform/index.jsx
@@ -45,6 +45,8 @@
 
           if (group.isDefault) {
             values.isDefault = true
+            values.sublist = group.sublist
+            
             resolve(values)
           } else {
             let targetKeys = this.refs['fields-transfer'].state.targetKeys
diff --git a/src/templates/formtabconfig/index.jsx b/src/templates/formtabconfig/index.jsx
index b0db875..5771fba 100644
--- a/src/templates/formtabconfig/index.jsx
+++ b/src/templates/formtabconfig/index.jsx
@@ -4,23 +4,26 @@
 import { is, fromJS } from 'immutable'
 import { DndProvider } from 'react-dnd'
 import HTML5Backend from 'react-dnd-html5-backend'
-import { Button, Card, Modal, Collapse, notification, Spin, Select, List, Icon, Empty, Switch, Tooltip } from 'antd'
 import moment from 'moment'
-import ActionForm from './actionform'
-import SettingForm from './settingform'
-import TabForm from './tabform'
-import TabDragElement from './tabdragelement'
+import { Button, Card, Modal, Collapse, notification, Spin, Select, List, Icon, Empty, Switch, Tooltip } from 'antd'
+
 import Api from '@/api'
-import SearchForm from './modalform'
-import DragElement from './dragelement'
-import GroupForm from './groupform'
-import EditCard from '@/templates/tableshare/editcard'
-import VerifyCard from '@/templates/tableshare/verifycard'
-import MenuForm from '@/templates/tableshare/menuform'
-import SourceElement from '@/templates/tableshare/dragelement/source'
 import zhCN from '@/locales/zh-CN/comtable.js'
 import enUS from '@/locales/en-US/comtable.js'
 import Utils from '@/utils/utils.js'
+import { getModalForm, getActionForm } from '@/templates/tableshare/formconfig'
+
+import ActionForm from './actionform'
+import SettingForm from './settingform'
+import ModalForm from './modalform'
+import DragElement from './dragelement'
+import GroupForm from './groupform'
+import TabForm from '@/templates/tableshare/tabform'
+import EditCard from '@/templates/tableshare/editcard'
+import VerifyCard from '@/templates/tableshare/verifycard'
+import MenuForm from '@/templates/tableshare/menuform'
+import TabDragElement from '@/templates/tableshare/tabdragelement'
+import SourceElement from '@/templates/tableshare/dragelement/source'
 import Source from './source'
 import './index.scss'
 
@@ -41,18 +44,13 @@
   state = {
     dict: CommonDict,        // 瀛楀吀
     config: null,            // 椤甸潰閰嶇疆
-    visible: false,          // 鎼滅储鏉′欢銆佹寜閽�佹樉绀哄垪锛屾ā鎬佹鏄剧ず鎺у埗
-    modalTitle: '',          // 妯℃�佹鐨勬爣棰�
+    modaltype: '',           // 妯℃�佹绫诲瀷锛屾帶鍒舵ā鎬佹鏄剧ず
     tableVisible: false,     // 鏁版嵁琛ㄥ瓧娈垫ā鎬佹
     tableColumns: [],        // 琛ㄦ牸鏄剧ず鍒�
     fields: null,            // 鎼滅储鏉′欢鍙婃樉绀哄垪锛屽彲閫夊瓧娈�
     menuformlist: null,      // 鍩烘湰淇℃伅琛ㄥ崟瀛楁
     formlist: null,          // 鎼滅储鏉′欢銆佹寜閽�佹樉绀哄垪琛ㄥ崟瀛楁
-    formtemp: '',            // 琛ㄥ崟绫诲瀷锛屾樉绀哄垪銆佹寜閽�佹悳绱㈡潯浠�
     card: null,              // 缂栬緫鍏冪礌
-    searchloading: false,    // 鎼滅储鏉′欢鍔犺浇涓�
-    actionloading: false,    // 鎸夐挳鍔犺浇涓�
-    tabloading: false,       // 鏍囩椤靛姞杞戒腑
     menuloading: false,      // 鑿滃崟淇濆瓨涓�
     menucloseloading: false, // 鑿滃崟鍏抽棴鏃讹紝閫夋嫨淇濆瓨
     loading: false,          // 鍔犺浇涓紝椤甸潰spin
@@ -78,21 +76,18 @@
     const { menu, editAction, config } = this.props
     console.log(menu)
     let _config = ''
+    let _originMenu = ''
 
     if (!config) {
       _config = JSON.parse(JSON.stringify(Source.baseConfig))
     } else {
       _config = config
+      _originMenu = JSON.parse(JSON.stringify(_config))
     }
-    
-    // _config.action = _config.action.map(item => {
-    //   item.uuid = Utils.getuuid()
-    //   return item
-    // })
 
     this.setState({
       config: _config,
-      originMenu: JSON.parse(JSON.stringify(menu)),
+      originMenu: _originMenu,
       selectedTables: _config.tables,
       menuformlist: [
         {
@@ -239,92 +234,79 @@
   }
 
   handleList = (type, list, card, groupId, elementId) => {
-    let config = JSON.parse(JSON.stringify(this.state.config))
+    const { config } = this.state
 
     if (type === 'tabs') { // 鏍囩椤佃皟鏁撮『搴忔垨娣诲姞鍏冪礌
       if (list.length > config[card.groupId].length) {
         list = list.filter(item => !item.origin)
-  
-        this.setState({
-          tabloading: true,
-          config: {...config, [card.groupId]: list }
-        }, () => {
-          // 鍒锋柊瀵瑰簲鐨勯厤缃俊鎭�
-          this.setState({
-            tabloading: false
-          })
-          this.handleTab(card)
-        })
-      } else {
-        this.setState({config: {...config, [card.groupId]: list}})
+
+        this.handleTab(card)
       }
+
+      this.setState({config: {...config, [card.groupId]: list}})
     } else if (type === 'action') {
       if (list.length > config.action.length) {
         list = list.filter(item => !item.origin)
   
-        this.setState({
-          actionloading: true,
-          config: {...config, action: list }
-        }, () => {
-          // 鍒锋柊瀵瑰簲鐨勯厤缃俊鎭�
-          this.setState({
-            actionloading: false
-          })
-  
-          this.handleAction(card)
-        })
-      } else {
-        this.setState({config: {...config, action: list}})
+        this.handleAction(card)
       }
-    } else if (type === 'search') {
-      let _group = config.groups.filter(group => group.uuid === groupId)[0]
-      let isChange = elementId && list.length > _group.sublist.length
-      let isAdd = !elementId && list.length > _group.sublist.length
 
-      if (isAdd) {
-        _group.sublist = list.filter(item => !item.origin)
-        this.handleSearch(card)
-      } else if (isChange) {
-        // 淇敼宸叉湁鍏冪礌鐨勫垎缁�
-        let element = null
-        config.groups.forEach(item => {
-          item.sublist = item.sublist.filter(cell => {
-            if (cell.uuid !== elementId) {
-              return true
+      this.setState({config: {...config, action: list}})
+    } else if (type === 'search') {
+      let _groups = null
+
+      if (card) {
+        // 鍏冪礌娣诲姞
+        if (config.groups.length === 1) {
+          _groups = config.groups.map(group => {
+            let _list = list.filter(item => !item.origin)
+            return {...group, sublist: _list}
+          })
+        } else {
+          _groups = config.groups.map(group => {
+            if (group.uuid === groupId) {
+              return {...group, sublist: list}
             } else {
-              element = cell
-              return false
+              return group
             }
           })
-        })
-        _group.sublist.push(element)
-      } else {
-        _group.sublist = list
-      }
-
-      config.groups = config.groups.map(item => {
-        if (item.uuid === _group.uuid) {
-          return _group
-        } else {
-          return item
         }
-      })
-
-      if (isChange) {
-        this.setState({
-          searchloading: true,
-          config: config
-        }, () => {
-          // 鍒锋柊瀵瑰簲鐨勯厤缃俊鎭�
-          this.setState({
-            searchloading: false
+        this.handleSearch(card)
+      } else if (elementId) {
+        // 淇敼宸叉湁鍏冪礌鐨勫垎缁�
+        let element = null
+        _groups = config.groups.map(group => {
+          group.sublist = group.sublist.filter(item => {
+            if (item.uuid === elementId) {
+              element = item
+              return false
+            } else {
+              return true
+            }
           })
+          return group
+        })
+
+        _groups = _groups.map(group => {
+          if (group.uuid === groupId) {
+            group.sublist.push(element)
+          }
+          return group
         })
       } else {
-        this.setState({
-          config: config
+        // 鍏冪礌绉诲姩
+        _groups = config.groups.map(group => {
+          if (group.uuid === groupId) {
+            return {...group, sublist: list}
+          } else {
+            return group
+          }
         })
       }
+
+      this.setState({
+        config: {...config, groups: _groups}
+      })
     }
   }
 
@@ -344,399 +326,23 @@
     }
 
     this.setState({
-      visible: true,
-      formtemp: 'search',
-      modalTitle: '缂栬緫-琛ㄥ崟',
+      modaltype: 'search',
       card: card,
-      formlist: [
-        {
-          type: 'text',
-          key: 'label',
-          label: this.state.dict['header.form.name'],
-          initVal: card.label,
-          required: true,
-          readonly: false
-        },
-        {
-          type: 'text',
-          key: 'field',
-          label: this.state.dict['header.form.field'],
-          initVal: card.field,
-          required: true,
-          readonly: false
-        },
-        {
-          type: 'select',
-          key: 'type',
-          label: this.state.dict['header.form.type'],
-          initVal: card.type,
-          required: true,
-          options: [{
-            value: 'text',
-            text: this.state.dict['header.form.text']
-          }, {
-            value: 'number',
-            text: this.state.dict['header.form.number']
-          }, {
-            value: 'select',
-            text: this.state.dict['header.form.select']
-          }, {
-            value: 'multiselect',
-            text: this.state.dict['header.form.multiselect']
-          }, {
-            value: 'link',
-            text: this.state.dict['header.form.link']
-          }, {
-            value: 'fileupload',
-            text: this.state.dict['header.form.fileupload']
-          }, {
-            value: 'date',
-            text: this.state.dict['header.form.dateday']
-          }, {
-            value: 'datemonth',
-            text: this.state.dict['header.form.datemonth']
-          }, {
-            value: 'datetime',
-            text: this.state.dict['header.form.datetime']
-          }, {
-            value: 'textarea',
-            text: this.state.dict['header.form.textarea']
-          }]
-        },
-        {
-          type: 'text',
-          key: 'initval',
-          label: this.state.dict['header.form.initval'],
-          initVal: card.initval,
-          required: false
-        },
-        {
-          type: 'radio',
-          key: 'resourceType',
-          label: this.state.dict['header.form.resourceType'],
-          initVal: card.resourceType || '0',
-          required: true,
-          options: [{
-            value: '0',
-            text: this.state.dict['header.form.custom']
-          }, {
-            value: '1',
-            text: this.state.dict['header.form.datasource']
-          }]
-        },
-        {
-          type: 'radio',
-          key: 'setAll',
-          label: this.state.dict['header.form.setAll'],
-          initVal: card.setAll || 'false',
-          options: [{
-            value: 'true',
-            text: this.state.dict['header.form.true']
-          }, {
-            value: 'false',
-            text: this.state.dict['header.form.false']
-          }]
-        },
-        {
-          type: 'textarea',
-          key: 'dataSource',
-          label: this.state.dict['header.form.datasource'],
-          initVal: card.dataSource || '',
-          required: true,
-          readonly: false
-        },
-        {
-          type: 'options',
-          key: 'options',
-          label: '',
-          initVal: card.options || [],
-          required: true,
-          readonly: false
-        },
-        {
-          type: 'text',
-          key: 'linkField',
-          label: this.state.dict['header.form.linkField'],
-          initVal: card.linkField || '',
-          required: true,
-          readonly: false
-        },
-        {
-          type: 'text',
-          key: 'valueField',
-          label: this.state.dict['header.form.valueField'],
-          initVal: card.valueField || '',
-          required: true,
-          readonly: false
-        },
-        {
-          type: 'text',
-          key: 'valueText',
-          label: this.state.dict['header.form.valueText'],
-          initVal: card.valueText || '',
-          required: true,
-          readonly: false
-        },
-        {
-          type: 'text',
-          key: 'orderBy',
-          label: this.state.dict['header.form.orderBy'],
-          initVal: card.orderBy || '',
-          required: false,
-          readonly: false
-        },
-        {
-          type: 'select',
-          key: 'orderType',
-          label: this.state.dict['header.form.orderType'],
-          initVal: card.orderType || 'asc',
-          options: [{
-            value: 'asc',
-            text: this.state.dict['header.form.asc']
-          }, {
-            value: 'desc',
-            text: this.state.dict['header.form.desc']
-          }]
-        },
-        {
-          type: 'number',
-          key: 'decimal',
-          label: this.state.dict['header.form.decimal'],
-          initVal: card.decimal || 0,
-          required: false
-        },
-        {
-          type: 'number',
-          key: 'min',
-          label: '鏈�灏忓��',
-          initVal: card.min || '',
-          required: false
-        },
-        {
-          type: 'number',
-          key: 'max',
-          label: '鏈�澶у��',
-          initVal: card.max || '',
-          required: false
-        },
-        {
-          type: 'radio',
-          key: 'readonly',
-          label: this.state.dict['header.form.readonly'],
-          initVal: card.readonly || 'false',
-          options: [{
-            value: 'true',
-            text: this.state.dict['header.form.true']
-          }, {
-            value: 'false',
-            text: this.state.dict['header.form.false']
-          }]
-        },
-        {
-          type: 'radio',
-          key: 'required',
-          label: this.state.dict['header.form.field.required'],
-          initVal: card.required || 'false',
-          options: [{
-            value: 'true',
-            text: this.state.dict['header.form.true']
-          }, {
-            value: 'false',
-            text: this.state.dict['header.form.false']
-          }]
-        },
-        {
-          type: 'multiselect',
-          key: 'linkSubField',
-          label: this.state.dict['header.form.linkForm'],
-          initVal: card.linkSubField || [],
-          options: _inputfields
-        }
-      ]
+      formlist: getModalForm(card, _inputfields)
     })
   }
 
   handleAction = (card, type) => {
     let ableField = this.props.permFuncField.join(', ')
+    let functip = <div>
+      <p style={{marginBottom: '5px'}}>{this.state.dict['header.modal.func.innerface'].replace('@ableField', ableField)}</p>
+      <p>{this.state.dict['header.modal.func.outface']}</p>
+    </div>
+
     this.setState({
-      visible: true,
-      formtemp: 'action',
-      modalTitle: type === 'copy' ? '澶嶅埗-鎸夐挳' : '缂栬緫-鎸夐挳',
+      modaltype: type === 'copy' ? 'actionCopy' : 'actionEdit',
       card: card,
-      formlist: [
-        {
-          type: 'text',
-          key: 'label',
-          label: this.state.dict['header.form.name'],
-          initVal: card.label,
-          required: true,
-          readonly: false
-        },
-        {
-          type: 'select',
-          key: 'OpenType',
-          label: this.state.dict['header.form.openType'],
-          initVal: card.OpenType,
-          required: true,
-          options: [{
-            value: 'prompt',
-            text: this.state.dict['header.form.prompt']
-          }, {
-            value: 'exec',
-            text: this.state.dict['header.form.exec']
-          }]
-        },
-        {
-          type: 'radio',
-          key: 'intertype',
-          label: this.state.dict['header.form.intertype'],
-          initVal: card.intertype || 'inner',
-          required: true,
-          options: [{
-            value: 'inner',
-            text: this.state.dict['header.form.interface.inner']
-          }, {
-            value: 'outer',
-            text: this.state.dict['header.form.interface.outer']
-          }]
-        },
-        {
-          type: 'text',
-          key: 'innerFunc',
-          label: this.state.dict['header.form.innerFunc'],
-          initVal: card.innerFunc,
-          tooltip: <div>
-            <p>鍐呴儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屽嚱鏁板悕绉伴渶浠ableField}绛夊瓧绗﹀紑濮嬶紱鏈缃椂浼氳皟鐢ㄧ郴缁熷嚱鏁帮紝浣跨敤绯荤粺鍑芥暟闇�瀹屽杽鏁版嵁婧愬強鎿嶄綔绫诲瀷;</p>
-            <p>澶栭儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屾彁浜ゆ暟鎹粡杩囧唴閮ㄥ嚱鏁板鐞嗗悗锛屼紶鍏ュ閮ㄦ帴鍙o紝鏈缃椂锛屾暟鎹細鐩存帴浼犲叆澶栭儴鎺ュ彛銆�</p>
-          </div>,
-          fields: this.props.permFuncField,
-          tooltipClass: 'middle',
-          required: false,
-          readonly: false
-        },
-        {
-          type: 'radio',
-          key: 'sysInterface',
-          label: this.state.dict['header.form.sysInterface'],
-          initVal: card.sysInterface || 'false',
-          required: true,
-          options: [{
-            value: 'true',
-            text: this.state.dict['header.form.true']
-          }, {
-            value: 'false',
-            text: this.state.dict['header.form.false']
-          }]
-        },
-        {
-          type: 'text',
-          key: 'outerFunc',
-          label: this.state.dict['header.form.outerFunc'],
-          initVal: card.outerFunc,
-          required: false,
-          readonly: false
-        },
-        {
-          type: 'text',
-          key: 'interface',
-          label: this.state.dict['header.form.interface'],
-          initVal: card.sysInterface === 'true' ? (window.GLOB.mainSystemApi || window.GLOB.subSystemApi) : card.interface,
-          required: true,
-          readonly: card.sysInterface === 'true'
-        },
-        {
-          type: 'text',
-          key: 'callbackFunc',
-          label: this.state.dict['header.form.callbackFunc'],
-          initVal: card.callbackFunc,
-          required: false,
-          readonly: false
-        },
-        {
-          type: 'select',
-          key: 'execSuccess',
-          label: this.state.dict['header.form.execSuccess'],
-          initVal: card.execSuccess || 'never',
-          required: true,
-          options: [{
-            value: 'never',
-            text: this.state.dict['header.form.refresh.never']
-          }, {
-            value: 'grid',
-            text: this.state.dict['header.form.refresh.grid']
-          }, {
-            value: 'view',
-            text: this.state.dict['header.form.refresh.view']
-          }]
-        },
-        {
-          type: 'select',
-          key: 'execError',
-          label: this.state.dict['header.form.execError'],
-          initVal: card.execError || 'never',
-          required: true,
-          options: [{
-            value: 'never',
-            text: this.state.dict['header.form.refresh.never']
-          }, {
-            value: 'grid',
-            text: this.state.dict['header.form.refresh.grid']
-          }, {
-            value: 'view',
-            text: this.state.dict['header.form.refresh.view']
-          }]
-        },
-        {
-          type: 'select',
-          key: 'popClose',
-          label: this.state.dict['header.form.popClose'],
-          initVal: card.popClose || 'never',
-          required: true,
-          options: [{
-            value: 'never',
-            text: this.state.dict['header.form.refresh.never']
-          }, {
-            value: 'grid',
-            text: this.state.dict['header.form.refresh.grid']
-          }, {
-            value: 'view',
-            text: this.state.dict['header.form.refresh.view']
-          }]
-        },
-        {
-          type: 'select',
-          key: 'icon',
-          label: this.state.dict['header.form.icon'],
-          initVal: card.icon,
-          required: false,
-          options: []
-        },
-        {
-          type: 'select',
-          key: 'class',
-          label: this.state.dict['header.form.class'],
-          initVal: card.class,
-          required: false,
-          options: []
-        },
-        {
-          type: 'text',
-          key: 'sql',
-          label: this.state.dict['header.form.datasource'],
-          initVal: card.sql || this.state.config.setting.tableName || '',
-          tooltip: this.state.dict['header.form.actionhelp.datasource'],
-          required: false
-        },
-        {
-          type: 'select',
-          key: 'sqlType',
-          label: this.state.dict['header.form.action.type'],
-          initVal: card.sqlType || '',
-          tooltip: this.state.dict['header.form.actionhelp.sqlType'],
-          required: false,
-          options: []
-        }
-      ]
+      formlist: getActionForm(card, functip, this.state.config, this.props.permFuncField)
     })
   }
 
@@ -782,9 +388,7 @@
     }
 
     this.setState({
-      visible: true,
-      formtemp: 'tabs',
-      modalTitle: '缂栬緫-鏍囩椤�',
+      modaltype: 'tabs',
       card: card,
       formlist: [
         {
@@ -855,101 +459,100 @@
    * 3銆佹坊鍔犳垨缂栬緫鍒楋紝淇濆瓨鏃讹紝濡傛寜閽綅缃缃负琛ㄦ牸锛屽垯淇敼鎿嶄綔鍒楁樉绀虹姸鎬�
    */
   handleSubmit = () => {
-    const { menu } = this.props
-    const { card } = this.state
-    let _config = JSON.parse(JSON.stringify(this.state.config))
+    const { config, modaltype } = this.state
 
-    this.formRef.handleConfirm().then(res => {
-      let isupdate = false
-
-      if (res.type === 'action' && card.originCard && res.values.OpenType === 'pop') {
-        Api.getSystemConfig({
-          func: 'sPC_Get_LongParam',
-          MenuID: card.originCard.uuid
-        }).then(result => {
-          if (result.status && result.LongParam) {
-            let param = {
-              func: 'sPC_ButtonParam_AddUpt',
-              ParentID: menu.MenuID,
-              MenuID: res.values.uuid,
-              MenuNo: menu.MenuNo,
-              Template: 'Modal',
-              MenuName: res.values.label,
-              PageParam: JSON.stringify({Template: 'Modal'}),
-              LongParam: result.LongParam
-            }
-            Api.getSystemConfig(param).then(response => {
-              if (!response.status) {
-                notification.warning({
-                  top: 92,
-                  message: response.message,
-                  duration: 10
-                })
-              }
-            })
-          }
-        })
-      }
-
-      
-      if (res.type === 'action') {
-        _config.action = _config.action.map(item => {
-          if (item.uuid === res.values.uuid) {
-            isupdate = true
-            return res.values
-          } else {
-            return item
-          }
-        })
-        _config.action = _config.action.filter(item => !item.origin)
-  
-        if (!isupdate) { // 鎿嶄綔涓嶆槸淇敼锛屾坊鍔犲厓绱犺嚦鍒楄〃
-          _config.action.push(res.values)
-        }
-      } else if (res.type === 'search') {
-        _config.groups = _config.groups.map(item => {
-          item.sublist = item.sublist.map(cell => {
-            if (cell.uuid === res.values.uuid) {
-              return res.values
+    if (modaltype === 'search') {
+      this.modalFormRef.handleConfirm().then(res => {
+        let _groups = config.groups.map(group => {
+          group.sublist = group.sublist.map(item => {
+            if (item.uuid === res.uuid) {
+              return res
             } else {
-              return cell
+              return item
             }
           })
-          if (item.isDefault) {
-            item.sublist = item.sublist.filter(cell => !cell.origin)
+          if (group.isDefault) {
+            group.sublist = group.sublist.filter(item => !item.origin)
           }
-          return item
+          return group
         })
-      } else { // 鏍囩椤电殑娣诲姞涓庝慨鏀�
-        _config[res.values.groupId] = _config[res.values.groupId].map(item => {
-          if (item.uuid === res.values.uuid) {
-            isupdate = true
-            return res.values
+
+        this.setState({
+          config: {...config, groups: _groups},
+          modaltype: ''
+        })
+      })
+    } else if (modaltype === 'actionEdit' || modaltype === 'actionCopy') {
+      this.actionFormRef.handleConfirm().then(res => {
+        let _action = config.action.map(item => {
+          if (item.uuid === res.uuid) {
+            return res
           } else {
             return item
           }
         })
-        _config[res.values.groupId] = _config[res.values.groupId].filter(item => !item.origin)
-  
-        if (!isupdate) { // 鎿嶄綔涓嶆槸淇敼锛屾坊鍔犲厓绱犺嚦鍒楄〃
-          _config[res.values.groupId].push(res.values)
+        _action = _action.filter(item => !item.origin)
+
+        if (modaltype === 'actionCopy') {
+          _action.push(res)
         }
+
+        this.setState({
+          config: {...config, action: _action},
+          modaltype: ''
+        })
+      })
+    } else if (modaltype === 'tabs') {
+      this.tabsFormRef.handleConfirm().then(res => {
+        let _tabgroup = config[res.groupId].map(item => {
+          if (item.uuid === res.uuid) {
+            return res
+          } else {
+            return item
+          }
+        })
+        _tabgroup = _tabgroup.filter(item => !item.origin)
+
+        this.setState({
+          config: {...config, [res.groupId]: _tabgroup},
+          modaltype: ''
+        })
+      })
+    }
+  }
+
+  editModalCancel = () => {
+    const { config, card, modaltype } = this.state
+
+    if (card.focus) {
+      let _config = null
+      if (modaltype === 'search') {
+        let _groups = config.groups.map(group => {
+          group.sublist = group.sublist.filter(item => item.uuid !== card.uuid)
+          return group
+        })
+        _config = {...config, groups: _groups}
+      } else if (modaltype === 'actionEdit') {
+        let _action = config.action.filter(item => item.uuid !== card.uuid)
+        _config = {...config, action: _action}
+      } else if (modaltype === 'tabs') {
+        let _tabgroup = config[card.groupId].filter(item => item.uuid !== card.uuid)
+        _config = {...config, [card.groupId]: _tabgroup}
+      } else {
+        _config = config
       }
 
       this.setState({
+        card: null,
         config: _config,
-        searchloading: true,
-        actionloading: true,
-        tabloading: true,
-        visible: false
-      }, () => {
-        this.setState({
-          searchloading: false,
-          actionloading: false,
-          tabloading: false
-        })
+        modaltype: ''
       })
-    })
+    } else {
+      this.setState({
+        card: null,
+        modaltype: ''
+      })
+    }
   }
 
   /**
@@ -1228,12 +831,7 @@
 
         this.setState({
           config: _config,
-          actionloading: true,
           funcLoading: false
-        }, () => {
-          this.setState({
-            actionloading: false
-          })
         })
       })
     })
@@ -1468,6 +1066,7 @@
       cancelText: this.state.dict['header.cancel'],
       onOk() {
         let _config = JSON.parse(JSON.stringify(_this.state.config))
+        let _delActions = _this.state.delActions
 
         if (element.type === 'tabs') {
           _config[element.card.groupId] = _config[element.card.groupId].filter(item => {
@@ -1477,6 +1076,11 @@
               return true
             }
           })
+        } else if (element.type === 'search') {
+          _config.groups = _config.groups.map(group => {
+            group.sublist = group.sublist.filter(item => item.uuid !== element.card.uuid)
+            return group
+          })
         } else {
           _config[element.type] = _config[element.type].filter(item => {
             if (item.uuid === element.card.uuid) {
@@ -1485,22 +1089,12 @@
               return true
             }
           })
-        }
-
-        let refreshtype = element.type + 'loading'
-
-        if (/^tab/.test(refreshtype)) {
-          refreshtype = 'tabloading'
+          _delActions.push(element.card.uuid)
         }
 
         _this.setState({
           config: _config,
-          delActions: [..._this.state.delActions, element.card.uuid],
-          [refreshtype]: true
-        }, () => {
-          _this.setState({
-            [refreshtype]: false
-          })
+          delActions: _delActions
         })
       },
       onCancel() {}
@@ -1537,27 +1131,21 @@
       profileVisible: false,
       config: config,
       card: '',
-      actionloading: true
-    }, () => {
-      this.setState({
-        actionloading: false
-      })
     })
   }
 
   /**
-   * @description 涓夌骇鑿滃崟淇濆瓨
+   * @description 鑿滃崟淇濆瓨
    */
   submitConfig = () => {
-    const { menu } = this.props
-    const { originMenu } = this.state
+    const { menu, editAction } = this.props
 
     let config = JSON.parse(JSON.stringify(this.state.config))
 
     this.menuformRef.handleConfirm().then(res => {
 
-      if (config.search[0] && config.search[0].origin) {
-        config.search = config.search.filter(item => !item.origin)
+      if (config.groups[0] && config.groups[0].sublist[0] && config.groups[0].sublist[0].origin) {
+        config.groups[0].sublist = config.groups[0].sublist.filter(item => !item.origin)
       }
       if (config.action[0] && config.action[0].origin) {
         config.action = config.action.filter(item => !item.origin)
@@ -1568,21 +1156,15 @@
 
       let _LongParam = ''
       let _config = {...config, tables: this.state.selectedTables}
-      let _pageParam = {...menu.PageParam, OpenType: res.opentype}
 
-      // 鏈缃暟鎹簮鎴栨爣绛句笉鍚堟硶鏃讹紝鍚敤鐘舵�佷负false
-      if (_config.setting.interType === 'inner' && !_config.setting.innerFunc && !_config.setting.dataresource) {
-        _config.enabled = false
-      } else if (_config.tabgroups.length > 1) {
+      // 鏍囩涓嶅悎娉曟椂锛屽惎鐢ㄧ姸鎬佷负false
+      if (_config.tabgroups.length > 1) {
         _config.tabgroups.forEach(group => {
           if (_config[group].length === 0) {
             _config.enabled = false
           }
         })
       }
-
-      // 淇濆瓨鏃跺垹闄ら厤缃被鍨嬶紝system 銆乽ser
-      delete _config.type
 
       try {
         _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
@@ -1597,7 +1179,7 @@
 
       let btnParam = { // 娣诲姞鑿滃崟鎸夐挳
         func: 'sPC_Button_AddUpt',
-        Type: 60, // 娣诲姞鎸夐挳琛ㄥ崟椤典笅鐨勬寜閽�
+        Type: 60,      // 娣诲姞鎸夐挳琛ㄥ崟椤典笅鐨勬寜閽�
         ParentID: menu.MenuID,
         MenuNo: res.menuNo,
         Template: menu.PageParam.Template || '',
@@ -1615,9 +1197,9 @@
       
       let tabParam = { // 娣诲姞鑿滃崟tab椤�
         func: 'sPC_sMenusTab_AddUpt',
-        MenuID: menu.MenuID,
+        MenuID: editAction.uuid,
         LText: config.tabs.map((item, index) => {
-          return `select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${(index + 1) * 10}' as Sort`
+          return `select '${editAction.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${(index + 1) * 10}' as Sort`
         })
       }
       tabParam.LText = tabParam.LText.join(' union all ')
@@ -1626,14 +1208,13 @@
       tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
 
       let param = {
-        func: 'sPC_TrdMenu_AddUpt',
-        ParentID: res.parentId,
-        MenuID: menu.MenuID,
-        MenuNo: res.menuNo,
-        Template: menu.PageParam.Template || '',
-        MenuName: res.menuName,
-        Sort: (this.props.supMenuList.length + 1) * 10,
-        PageParam: JSON.stringify(_pageParam),
+        func: 'sPC_ButtonParam_AddUpt',
+        ParentID: menu.MenuID,
+        MenuID: editAction.uuid,
+        MenuNo: menu.MenuNo,
+        Template: 'FormTab',
+        MenuName: editAction.label,
+        PageParam: JSON.stringify({Template: 'FormTab'}),
         LongParam: _LongParam
       }
       
@@ -1651,25 +1232,9 @@
         if (response.status) {
           this.setState({
             config: _config,
-            originMenu: {
-              ...originMenu,
-              LongParam: _config,
-              PageParam: _pageParam,
-              MenuName: res.menuName,
-              MenuNo: res.menuNo,
-              ParentID: res.parentId
-            },
-            searchloading: true,
-            actionloading: true
-          }, () => {
-            this.setState({
-              searchloading: false,
-              actionloading: false
-            })
+            originMenu: _config
           })
 
-          this.props.reloadmenu()
-          
           this.submitAction(btnParam, tabParam)
         } else {
           this.setState({
@@ -1792,23 +1357,13 @@
   }
 
   cancelConfig = () => {
-    const { menu } = this.props
     const { config, originMenu } = this.state
 
     let _this = this
-    let isAdd = false
 
-    if (
-      (config.search[0] && config.search[0].origin) ||
-      (config.action[0] && config.action[0].origin) ||
-      (config.tabs[0] && config.tabs[0].origin)
-    ) {
-      isAdd = true
-    }
-
-    if (isAdd) {
+    if (!originMenu) {
       confirm({
-        content: '鑿滃崟灏氭湭鎻愪氦锛岀‘瀹氭斁寮冧繚瀛樺悧锛�',
+        content: '鎸夐挳閰嶇疆灏氭湭鎻愪氦锛岀‘瀹氭斁寮冧繚瀛樺悧锛�',
         okText: this.state.dict['header.confirm'],
         cancelText: this.state.dict['header.cancel'],
         onOk() {
@@ -1817,30 +1372,15 @@
         onCancel() {}
       })
     } else {
-      this.menuformRef.handleConfirm().then(res => {
-        let _config = {...config, tables: this.state.selectedTables}
-        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
-        let _originMenu = {
-          ...originMenu,
-          LongParam: _config,
-          PageParam: _pageParam,
-          MenuName: res.menuName,
-          MenuNo: res.menuNo,
-          ParentID: res.parentId
-        }
+      let _config = {...config, tables: this.state.selectedTables}
 
-        if (!is(fromJS(originMenu), fromJS(_originMenu))) {
-          this.setState({
-            closeVisible: true
-          })
-        } else {
-          this.props.handleConfig('')
-        }
-      }, () => {
+      if (!is(fromJS(_config), fromJS(originMenu))) {
         this.setState({
           closeVisible: true
         })
-      })
+      } else {
+        this.props.handleConfig('')
+      }
     }
   }
 
@@ -1899,7 +1439,6 @@
       columnsMap.set(card.field, card)
     })
 
-    console.log(cards)
     let groups = config.groups.map(group => {
       group.sublist = group.sublist.map(item => {
         if (columnsMap.has(item.field)) {
@@ -1941,17 +1480,12 @@
     })
 
     this.setState({
-      searchloading: true,
       config: {...config, groups: groups}
-    }, () => {
-      notification.success({
-        top: 92,
-        message: '鎿嶄綔鎴愬姛',
-        duration: 2
-      })
-      this.setState({
-        searchloading: false
-      })
+    })
+    notification.success({
+      top: 92,
+      message: '鎿嶄綔鎴愬姛',
+      duration: 2
     })
   }
 
@@ -2052,20 +1586,14 @@
       this.setState({
         config: {...config, setting: res},
         settingVisible: false,
-        tabloading: true
-      }, () => {
-        this.setState({
-          tabloading: false
-        })
       })
     })
   }
 
   /**
-   * @description 璁剧疆鍙厤缃寜閽�
+   * @description 璁剧疆鍙厤缃爣绛�
    */
   setSubConfig = (btn, type) => {
-    const { menu } = this.props
     const { config, originMenu } = this.state
 
     let isAdd = false
@@ -2087,17 +1615,8 @@
     } else {
       this.menuformRef.handleConfirm().then(res => {
         let _config = {...config, tables: this.state.selectedTables}
-        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
-        let _originMenu = {
-          ...originMenu,
-          LongParam: _config,
-          PageParam: _pageParam,
-          MenuName: res.menuName,
-          MenuNo: res.menuNo,
-          ParentID: res.parentId
-        }
 
-        if (!is(fromJS(originMenu), fromJS(_originMenu))) {
+        if (!is(fromJS(originMenu), fromJS(_config))) {
           notification.warning({
             top: 92,
             message: '鑿滃崟閰嶇疆宸蹭慨鏀癸紝璇蜂繚瀛橈紒',
@@ -2169,7 +1688,7 @@
     }
   }
 
-  onEnabledChange = (val, e) => {
+  onEnabledChange = () => {
     const { config } = this.state
 
     let tabinvalid = true
@@ -2216,11 +1735,6 @@
 
         _this.setState({
           config: _config,
-          tabloading: true
-        }, () => {
-          _this.setState({
-            tabloading: false
-          })
         })
       },
       onCancel() {}
@@ -2241,12 +1755,7 @@
         delete _config[groupId]
 
         _this.setState({
-          config: _config,
-          tabloading: true
-        }, () => {
-          _this.setState({
-            tabloading: false
-          })
+          config: _config
         })
       },
       onCancel() {}
@@ -2291,11 +1800,6 @@
 
         _this.setState({
           config: {...config, groups: groups},
-          searchloading: true
-        }, () => {
-          _this.setState({
-            searchloading: false
-          })
         })
       },
       onCancel() {}
@@ -2316,22 +1820,17 @@
       groups = groups.sort((a, b) => {
         return a.sort - b.sort
       })
-      
+
       this.setState({
         config: {...config, groups: groups},
         editgroup: '',
         groupVisible: false,
-        searchloading: true
-      }, () => {
-        this.setState({
-          searchloading: false
-        })
       })
     })
   }
 
   render () {
-    const { config } = this.state
+    const { config, modaltype } = this.state
     let _length = config.groups.length
 
     let configTabs = []
@@ -2454,7 +1953,7 @@
                 activeKey={config.groups.map(group => group.uuid)}
                 expandIconPosition={'right'}
               >
-                {!this.state.searchloading && config.groups.map((group, index) => (
+                {config.groups.map((group, index) => (
                   <Panel showArrow={false} header={group.label} key={group.uuid} extra={(
                     <span>
                       {index === _length - 1 ? <Icon
@@ -2488,21 +1987,19 @@
                 <Tooltip placement="bottomLeft" overlayClassName="middle" title="鍦ㄥ乏渚у伐鍏锋爮銆婃寜閽�嬩腑锛岄�夋嫨瀵瑰簲绫诲瀷鐨勬寜閽嫋鑷虫澶勬坊鍔狅紝濡傞�夋嫨鎸夐挳绫诲瀷涓鸿〃鍗曘�佹柊鏍囩椤电瓑鍚湁閰嶇疆椤甸潰鐨勬寜閽紝鍙湪宸︿晶宸ュ叿鏍�-鎸夐挳-鍙厤缃寜閽锛岀偣鍑绘寜閽畬鎴愮浉鍏抽厤缃�傛敞锛氬綋璁剧疆鎸夐挳鏄剧ず浣嶇疆涓鸿〃鏍兼椂锛屾樉绀哄垪浼氬鍔犳搷浣滃垪銆�">
                   <Icon type="question-circle" />
                 </Tooltip>
-                {!this.state.actionloading ?
-                  <DragElement
-                    type="action"
-                    list={this.state.config.action}
-                    handleList={this.handleList}
-                    handleMenu={this.handleAction}
-                    copyElement={(val) => this.handleAction(val, 'copy')}
-                    deleteMenu={this.deleteElement}
-                    profileMenu={this.profileAction}
-                    placeholder={this.state.dict['header.form.action.placeholder']}
-                  /> : null
-                }
+                <DragElement
+                  type="action"
+                  list={this.state.config.action}
+                  handleList={this.handleList}
+                  handleMenu={this.handleAction}
+                  copyElement={(val) => this.handleAction(val, 'copy')}
+                  deleteMenu={this.deleteElement}
+                  profileMenu={this.profileAction}
+                  placeholder={this.state.dict['header.form.action.placeholder']}
+                />
               </div>
               {/* 鏍囩缁� */}
-              {!this.state.tabloading && this.state.config.tabgroups.map((groupId, index) => {
+              {this.state.config.tabgroups.map((groupId, index) => {
                 return (
                   <div key={index} className="tab-list">
                     {index === 0 ? <Tooltip placement="bottomLeft" overlayClassName="middle" title="鍦ㄥ乏渚у伐鍏锋爮銆婃爣绛鹃〉銆嬩腑锛岄�夋嫨瀵瑰簲绫诲瀷鐨勬爣绛鹃〉鎷栬嚦姝ゅ娣诲姞銆�">
@@ -2524,47 +2021,60 @@
             </Card>
           </div>
         </DndProvider>
-        {/* 缂栬緫鎼滅储鏉′欢銆佹寜閽�佹樉绀哄垪 */}
+        {/* 缂栬緫鎼滅储鏉′欢 */}
         <Modal
-          title={this.state.modalTitle}
-          visible={this.state.visible}
+          title={this.state.dict['header.modal.form.edit']}
+          visible={modaltype === 'search'}
           width={700}
-          onCancel={() => { this.setState({ visible: false }) }}
+          onOk={this.handleSubmit}
+          onCancel={this.editModalCancel}
+          destroyOnClose
+        >
+          <ModalForm
+            dict={this.state.dict}
+            card={this.state.card}
+            formlist={this.state.formlist}
+            wrappedComponentRef={(inst) => this.modalFormRef = inst}
+          />
+        </Modal>
+        {/* 缂栬緫鎸夐挳锛氬鍒躲�佺紪杈� */}
+        <Modal
+          title={modaltype === 'actionEdit' ? this.state.dict['header.modal.action.edit'] : this.state.dict['header.modal.action.copy']}
+          visible={modaltype === 'actionEdit' || modaltype === 'actionCopy'}
+          width={700}
+          onCancel={this.editModalCancel}
           footer={[
-            this.state.formtemp === 'action' ?
-            <Button key="delete" className="mk-btn mk-purple" onClick={this.creatFunc} loading={this.state.funcLoading}>{this.state.dict['header.menu.func.create']}</Button> : null,
-            <Button key="cancel" onClick={() => { this.setState({ visible: false }) }}>{this.state.dict['header.cancel']}</Button>,
+            modaltype === 'actionEdit' ? <Button key="delete" className="mk-btn mk-purple" onClick={this.creatFunc} loading={this.state.funcLoading}>{this.state.dict['header.menu.func.create']}</Button> : null,
+            <Button key="cancel" onClick={this.editModalCancel}>{this.state.dict['header.cancel']}</Button>,
             <Button key="confirm" type="primary" onClick={this.handleSubmit}>{this.state.dict['header.confirm']}</Button>
           ]}
           destroyOnClose
         >
-          {this.state.formtemp === 'search' ?
-            <SearchForm
-              dict={this.state.dict}
-              formlist={this.state.formlist}
-              card={this.state.card}
-              wrappedComponentRef={(inst) => this.formRef = inst}
-            /> : null
-          }
-          {this.state.formtemp === 'action' ?
-            <ActionForm
-              dict={this.state.dict}
-              card={this.state.card}
-              tabs={this.state.tabviews}
-              formlist={this.state.formlist}
-              wrappedComponentRef={(inst) => this.formRef = inst}
-            /> : null
-          }
-          {this.state.formtemp === 'tabs' ?
-            <TabForm
-              type="tabs"
-              tabs={this.state.tabviews}
-              dict={this.state.dict}
-              card={this.state.card}
-              formlist={this.state.formlist}
-              wrappedComponentRef={(inst) => this.formRef = inst}
-            /> : null
-          }
+          <ActionForm
+            dict={this.state.dict}
+            card={this.state.card}
+            tabs={this.state.tabviews}
+            formlist={this.state.formlist}
+            wrappedComponentRef={(inst) => this.actionFormRef = inst}
+          />
+        </Modal>
+        {/* 鏍囩缂栬緫 */}
+        <Modal
+          title={this.state.dict['header.modal.tabs.edit']}
+          visible={modaltype === 'tabs'}
+          width={700}
+          onOk={this.handleSubmit}
+          onCancel={this.editModalCancel}
+          destroyOnClose
+        >
+          <TabForm
+            type="tabs"
+            dict={this.state.dict}
+            card={this.state.card}
+            tabs={this.state.tabviews}
+            formlist={this.state.formlist}
+            wrappedComponentRef={(inst) => this.tabsFormRef = inst}
+          />
         </Modal>
         {/* 鏍规嵁瀛楁鍚嶆坊鍔犳樉绀哄垪鍙婃悳绱㈡潯浠� */}
         <Modal
diff --git a/src/templates/formtabconfig/index.scss b/src/templates/formtabconfig/index.scss
index cafce11..9e65f71 100644
--- a/src/templates/formtabconfig/index.scss
+++ b/src/templates/formtabconfig/index.scss
@@ -216,7 +216,17 @@
                     white-space: nowrap;
                   }
                 }
+                .ant-form-item-label.ant-col-cuslabel {
+                  width: 11%;
+                }
+                .ant-form-item-control-wrapper.ant-col-cuswrap {
+                  width: 89%;
+                }
                 .ant-form-item-control-wrapper {
+                  .ant-input-number {
+                    width: 100%;
+                    margin-top: 4px;
+                  }
                   .ant-select {
                     width: 100%;
                     margin-top: 4px;
@@ -224,6 +234,9 @@
                   .ant-calendar-picker {
                     margin-top: 4px;
                   }
+                  .ant-btn {
+                    margin-top: 4px;
+                  }
                   .input-mask {
                     position: absolute;
                     top: 0;
diff --git a/src/templates/formtabconfig/modalform/index.jsx b/src/templates/formtabconfig/modalform/index.jsx
index 6a8c3b3..ff106e1 100644
--- a/src/templates/formtabconfig/modalform/index.jsx
+++ b/src/templates/formtabconfig/modalform/index.jsx
@@ -377,10 +377,7 @@
           }
 
           if (isvalid) {
-            resolve({
-              type: 'search',
-              values
-            })
+            resolve(values)
           }
         } else {
           reject(err)
diff --git a/src/templates/formtabconfig/settingform/index.jsx b/src/templates/formtabconfig/settingform/index.jsx
index adbd0b7..b6b8b60 100644
--- a/src/templates/formtabconfig/settingform/index.jsx
+++ b/src/templates/formtabconfig/settingform/index.jsx
@@ -23,8 +23,7 @@
 
   UNSAFE_componentWillMount() {
     const { config, menu } = this.props
-    console.log(menu)
-    console.log(config)
+
     let _tabs = []
     let _select = []
     let _tabMap = new Map()
@@ -34,12 +33,24 @@
 
     try {
       _columns = menu.LongParam.columns.filter(item => item.field && item.type !== 'colspan')
-      // config.groups.forEach(group => {
-      //   if (group.isDefault) {
-      //     _columns.push()
-      //   }
-      //   group.sublist
-      // })
+      config.groups.forEach(group => {
+        if (group.isDefault) {
+          let list = group.sublist.filter(item => !item.origin)
+          _columns = [..._columns, ...list]
+        } else {
+          _columns = [..._columns, ...group.sublist]
+        }
+      })
+
+      let _colMap = new Map()
+      _columns = _columns.filter(item => {
+        if (_colMap.has(item.field)) {
+          return false
+        } else {
+          _colMap.set(item.field, true)
+          return true
+        }
+      })
       _interType = menu.LongParam.setting.interType
     } catch {
       notification.warning({
@@ -78,18 +89,7 @@
     return new Promise((resolve, reject) => {
       this.props.form.validateFieldsAndScroll((err, values) => {
         if (!err) {
-          values.actionfixed = values.actionfixed === 'true'
-          values.columnfixed = values.columnfixed === 'true'
-
-          if (values.interType === 'inner' && !values.innerFunc && !values.dataresource) {
-            notification.warning({
-              top: 92,
-              message: '璇疯嚜瀹氫箟鍑芥暟鎴栧~鍐欐暟鎹簮锛�',
-              duration: 10
-            })
-          } else {
-            resolve(values)
-          }
+          resolve(values)
         } else {
           reject(err)
         }
@@ -100,12 +100,6 @@
   onChange = (e) => {
     this.setState({
       interType: e.target.value
-    })
-  }
-
-  selectChange = (val) => {
-    this.props.form.setFieldsValue({
-      order: `${val} desc`
     })
   }
 
@@ -157,6 +151,19 @@
                   }
                 ]
               })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label="鍒楁暟">
+              {getFieldDecorator('cols', {
+                initialValue: setting.cols || '2'
+              })(
+                <Select>
+                  <Select.Option value="1">1鍒�</Select.Option>
+                  <Select.Option value="2">2鍒�</Select.Option>
+                  <Select.Option value="3">3鍒�</Select.Option>
+                </Select>
+              )}
             </Form.Item>
           </Col>
           <Col span={12}>
@@ -245,7 +252,6 @@
               })(
                 <Select
                   getPopupContainer={() => document.getElementById('commontable-setting-form')}
-                  onChange={this.selectChange}
                 >
                   <Select.Option key='unset' value="">涓嶈缃�</Select.Option>
                   {columns.length === 0 ?
diff --git a/src/templates/formtabconfig/source.jsx b/src/templates/formtabconfig/source.jsx
index 1ee4c76..a64d2df 100644
--- a/src/templates/formtabconfig/source.jsx
+++ b/src/templates/formtabconfig/source.jsx
@@ -6,7 +6,7 @@
 
 class CommonTableBaseData {
   baseConfig = {
-    type: 'formTab',
+    type: 'FormTab',
     enabled: false,
     setting: {
       tableName: '',
@@ -16,7 +16,7 @@
       innerFunc: '',
       interface: '',
       outerFunc: '',
-      cols: 2,
+      cols: '2',
       subtabs: []
     },
     tables: [],
@@ -37,13 +37,7 @@
             resourceType: '0',
             setAll: 'false',
             options: [],
-            dataSource: '',
-            linkField: '',
-            valueField: '',
-            valueText: '',
-            orderBy: '',
-            orderType: 'asc',
-            match: 'like'
+            orderType: 'asc'
           }, {
             origin: true,
             uuid: Utils.getuuid(),
@@ -54,13 +48,7 @@
             resourceType: '0',
             setAll: 'false',
             options: [],
-            dataSource: '',
-            linkField: '',
-            valueField: '',
-            valueText: '',
-            orderBy: '',
-            orderType: 'asc',
-            match: 'equal'
+            orderType: 'asc'
           }, {
             origin: true,
             uuid: Utils.getuuid(),
@@ -71,69 +59,9 @@
             resourceType: '0',
             setAll: 'false',
             options: [],
-            dataSource: '',
-            linkField: '',
-            valueField: '',
-            valueText: '',
-            orderBy: '',
-            orderType: 'asc',
-            match: 'greater'
+            orderType: 'asc'
           }
         ]
-      }
-    ],
-    search: [
-      {
-        origin: true,
-        uuid: Utils.getuuid(),
-        label: 'label',
-        field: '',
-        initval: '',
-        type: 'text',
-        resourceType: '0',
-        setAll: 'false',
-        options: [],
-        dataSource: '',
-        linkField: '',
-        valueField: '',
-        valueText: '',
-        orderBy: '',
-        orderType: 'asc',
-        match: 'like'
-      }, {
-        origin: true,
-        uuid: Utils.getuuid(),
-        label: 'label',
-        field: '',
-        initval: '',
-        type: 'select',
-        resourceType: '0',
-        setAll: 'false',
-        options: [],
-        dataSource: '',
-        linkField: '',
-        valueField: '',
-        valueText: '',
-        orderBy: '',
-        orderType: 'asc',
-        match: 'equal'
-      }, {
-        origin: true,
-        uuid: Utils.getuuid(),
-        label: 'label',
-        field: '',
-        initval: '',
-        type: 'date',
-        resourceType: '0',
-        setAll: 'false',
-        options: [],
-        dataSource: '',
-        linkField: '',
-        valueField: '',
-        valueText: '',
-        orderBy: '',
-        orderType: 'asc',
-        match: 'greater'
       }
     ],
     action: [
diff --git a/src/templates/formtabconfig/tabdragelement/index.jsx b/src/templates/formtabconfig/tabdragelement/index.jsx
deleted file mode 100644
index 5f50bde..0000000
--- a/src/templates/formtabconfig/tabdragelement/index.jsx
+++ /dev/null
@@ -1,114 +0,0 @@
-import React, { useState } from 'react'
-import { useDrop } from 'react-dnd'
-import update from 'immutability-helper'
-import { Tabs, Icon } from 'antd'
-import Utils from '@/utils/utils.js'
-import Card from './card'
-import './index.scss'
-
-const { TabPane } = Tabs
-
-const Container = ({list, type, groupId, placeholder, handleList, handleMenu, deleteMenu }) => {
-  let target = null
-  const [cards, setCards] = useState(list)
-  const moveCard = (id, atIndex) => {
-    const { card, index } = findCard(id)
-
-    if (!card) return
-
-    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
-    setCards(_cards)
-    handleList(type, _cards)
-  }
-
-  const findCard = id => {
-    const card = cards.filter(c => `${c.uuid}` === id)[0]
-    return {
-      card,
-      index: cards.indexOf(card),
-    }
-  }
-
-  const hasDrop = (item) => {
-    target = item
-  }
-
-  const [, drop] = useDrop({
-    accept: type,
-    drop(item) {
-      if (item.hasOwnProperty('originalIndex')) {
-        return
-      }
-
-      let newcard = {}
-      
-      newcard.uuid = Utils.getuuid()
-      newcard.label = 'tab'
-      newcard.icon = ''
-      newcard.type = item.subType
-      newcard.linkTab = Utils.getuuid()
-      newcard.subtabs = []
-      newcard.supMenu = ''
-      newcard.groupId = groupId
-      
-      let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
-      if (target) {
-        targetId = target.uuid
-      }
-
-      const { index: overIndex } = findCard(`${targetId}`)
-      let targetIndex = overIndex
-      // if (!target) {
-      targetIndex++
-      // }
-      // if (targetIndex < 0) {
-      //   targetIndex = 0
-      // }
-
-      const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
-      setCards(_cards)
-      handleList(type, _cards, newcard)
-      target = null
-    }
-  })
-  
-  const edit = (card) => {
-    handleMenu(card)
-  }
-  
-  const del = (card) => {
-    deleteMenu({card: card, type: type})
-  }
-
-  return (
-    <div ref={drop} className="ant-row maintable-tab-list">
-      <Tabs defaultActiveKey="0">
-        {cards.map((card, index) => (
-          <TabPane tab={
-            <div key={card.uuid}>
-              <Card
-                key={card.uuid}
-                id={`${card.uuid}`}
-                type={type}
-                card={card}
-                moveCard={moveCard}
-                findCard={findCard}
-                hasDrop={hasDrop}
-              />
-              <Icon className="edit" type="edit" onClick={() => edit(card)} />
-              <Icon className="edit close" type="close" onClick={() => del(card)} />
-            </div>
-          } key={`${index}`}>
-            銆妠card.label}銆嬫爣绛惧唴瀹�
-          </TabPane>
-        ))}
-      </Tabs>
-      {cards.length === 0 ?
-        <div className="commontab-drawarea-placeholder">
-          {placeholder}
-        </div> : null
-      }
-    </div>
-  )
-}
-export default Container
diff --git a/src/templates/formtabconfig/tabform/index.jsx b/src/templates/formtabconfig/tabform/index.jsx
deleted file mode 100644
index c585f69..0000000
--- a/src/templates/formtabconfig/tabform/index.jsx
+++ /dev/null
@@ -1,220 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { Form, Row, Col, Input, Select, Icon, Tooltip } from 'antd'
-import { formRule } from '@/utils/option.js'
-import Utils from '@/utils/utils.js'
-import './index.scss'
-
-
-class MainTab extends Component {
-  static propTpyes = {
-    tabs: PropTypes.array,   // 绫诲瀷
-    type: PropTypes.string,  // 绫诲瀷
-    dict: PropTypes.object,  // 瀛楀吀椤�
-    formlist: PropTypes.any, // 琛ㄥ崟
-    card: PropTypes.object   // 鏍囩椤典俊鎭�
-  }
-
-  state = {
-    formlist: null // 琛ㄥ崟
-  }
-
-  /**
-   * @description 琛ㄥ崟棰勫鐞�
-   */
-  UNSAFE_componentWillMount () {
-    const { formlist } = this.props
-
-    let type = formlist.filter(cell => cell.key === 'type')[0].initVal
-    let _initval = formlist.filter(cell => cell.key === 'linkTab')[0].initVal
-
-    let _tabs = this.props.tabs.filter(tab => tab.type === type)
-    let initTab = _tabs.filter(tab => tab.uuid === _initval)[0]
-
-    this.setState({
-      formlist: formlist.map(item => {
-        if (item.key === 'linkTab') {
-          item.options = [
-            {
-              value: '',
-              text: '鏂板缓'
-            },
-            ..._tabs
-          ]
-          if (!initTab) {
-            item.initVal = ''
-          }
-        }
-
-        return item
-      })
-    })
-  }
-
-  /**
-   * @description 鏍囩椤电被鍨嬪垏鎹�
-   */
-  openTypeChange = (key, value) => {
-    const { formlist } = this.state
-
-    if (key === 'type') {
-      let _tabs = this.props.tabs.filter(tab => tab.type === value)
-
-      this.setState({
-        formlist: formlist.map(item => {
-          if (item.key === 'linkTab') {
-            item.options = [
-              {
-                value: '',
-                text: '鏂板缓'
-              },
-              ..._tabs
-            ]
-            item.initVal = ''
-            item.hidden = true
-          }
-          return item
-        })
-      }, () => {
-        this.setState({
-          formlist: this.state.formlist.map(item => {
-            if (item.key === 'linkTab') {
-              item.hidden = false
-            }
-            return item
-          })
-        })
-      })
-    }
-  }
-
-  getFields() {
-    const { getFieldDecorator } = this.props.form
-    const fields = []
-    
-    this.state.formlist.forEach((item, index) => {
-      if (item.hidden) return
-
-      if (item.type === 'text') { // 鏂囨湰鎼滅储
-        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.input'] + item.label + '!'
-                  },
-                  {
-                    max: formRule.input.max,
-                    message: formRule.input.message
-                  }
-                ]
-              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} />)}
-            </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.toLowerCase().indexOf(input.toLowerCase()) >= 0}
-                  onChange={(value) => {this.openTypeChange(item.key, value)}}
-                >
-                  {item.options.map((option, i) =>
-                    <Select.Option id={'mk' + i} title={option.text} key={'mk' + i} value={option.value}>
-                      {item.key === 'icon' && i !== 0 ? <Icon type={option.text} /> : option.text}
-                    </Select.Option>
-                  )}
-                </Select>
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'mutilselect') {
-        fields.push(
-          <Col span={12} key={index}>
-            <Form.Item label={
-              <Tooltip placement="topLeft" title="鏍囩鍙叧鑱斾笅绾ф爣绛撅紝涓嬬骇鏍囩鍙�夎寖鍥达細鐩搁偦鐨勪笅渚ф爣绛剧粍涓湭琚悓绾ф垨涓昏〃鍏宠仈鐨勬爣绛俱��">
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip>
-            }>
-              {getFieldDecorator(item.key, {
-                initialValue: item.initVal
-              })(
-                <Select
-                  mode="multiple"
-                  style={{ width: '100%' }}
-                  placeholder="Please select"
-                >
-                  {item.options.map((option, index) =>
-                    <Select.Option id={option.uuid} title={option.label} key={index} value={option.uuid}>{option.label}</Select.Option>
-                  )}
-                </Select>
-              )}
-            </Form.Item>
-          </Col>
-        )
-      }
-    })
-
-    return fields
-  }
-
-  handleConfirm = () => {
-    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
-    return new Promise((resolve, reject) => {
-      this.props.form.validateFieldsAndScroll((err, values) => {
-        if (!err) {
-
-          values.uuid = this.props.card.uuid
-          values.groupId = this.props.card.groupId
-
-          if (!values.linkTab) { // 娌℃湁鍏宠仈鏍囩锛堟柊寤烘椂锛夛紝鍒涘缓鏂版爣绛綢d
-            values.linkTab = Utils.getuuid()
-          }
-
-          resolve({
-            type: this.props.type,
-            values
-          })
-        } else {
-          reject(err)
-        }
-      })
-    })
-  }
-
-  render() {
-    const formItemLayout = {
-      labelCol: {
-        xs: { span: 24 },
-        sm: { span: 8 }
-      },
-      wrapperCol: {
-        xs: { span: 24 },
-        sm: { span: 16 }
-      }
-    }
-    return (
-      <Form {...formItemLayout} className="ant-advanced-search-form commontable-tab-form">
-        <Row gutter={24}>{this.getFields()}</Row>
-      </Form>
-    )
-  }
-}
-
-export default Form.create()(MainTab)
\ No newline at end of file
diff --git a/src/templates/formtabconfig/tabform/index.scss b/src/templates/formtabconfig/tabform/index.scss
deleted file mode 100644
index 930f1a5..0000000
--- a/src/templates/formtabconfig/tabform/index.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-.ant-advanced-search-form.commontable-tab-form {
-  min-height: 180px;
-  .anticon-question-circle {
-    color: #c49f47;
-    margin-right: 3px;
-  }
-}
\ No newline at end of file
diff --git a/src/templates/modalconfig/dragelement/card.jsx b/src/templates/modalconfig/dragelement/card.jsx
index d1fda91..208a850 100644
--- a/src/templates/modalconfig/dragelement/card.jsx
+++ b/src/templates/modalconfig/dragelement/card.jsx
@@ -94,7 +94,7 @@
               <DatePicker showTime defaultValue={card.initval ? moment().subtract(card.initval, 'days') : null} />
             }
             {card.type === 'textarea' &&
-              <TextArea autosize={{ minRows: 2, maxRows: 6 }} />
+              <TextArea defaultValue={card.initval} autosize={{ minRows: 2, maxRows: 6 }} />
             }
             {card.type === 'fileupload' &&
               <Button>
diff --git a/src/templates/subtableconfig/actionform/index.jsx b/src/templates/subtableconfig/actionform/index.jsx
index 71162c6..767f8bd 100644
--- a/src/templates/subtableconfig/actionform/index.jsx
+++ b/src/templates/subtableconfig/actionform/index.jsx
@@ -127,6 +127,28 @@
           if (!initTab) {
             item.initVal = ''
           }
+        } else if (item.key === 'OpenType') {
+          item.options = [
+            {
+              value: 'pop',
+              text: this.props.dict['header.form.popform']
+            }, {
+              value: 'prompt',
+              text: this.props.dict['header.form.prompt']
+            }, {
+              value: 'exec',
+              text: this.props.dict['header.form.exec']
+            }, {
+              value: 'excelIn',
+              text: this.props.dict['header.form.excelIn']
+            }, {
+              value: 'excelOut',
+              text: this.props.dict['header.form.excelOut']
+            }, {
+              value: 'popview',
+              text: this.props.dict['header.form.popview']
+            }
+          ]
         }
         item.hidden = !_options.includes(item.key)
         return item
diff --git a/src/templates/subtableconfig/index.jsx b/src/templates/subtableconfig/index.jsx
index e2196ff..c3fe1aa 100644
--- a/src/templates/subtableconfig/index.jsx
+++ b/src/templates/subtableconfig/index.jsx
@@ -314,7 +314,7 @@
     this.setState({
       modaltype: type === 'copy' ? 'actionCopy' : 'actionEdit',
       card: card,
-      formlist: getActionForm(card, functip, this.state.config, this.props.permFuncField, 'subtable')
+      formlist: getActionForm(card, functip, this.state.config, this.props.permFuncField)
     })
   }
 
@@ -1033,16 +1033,15 @@
           }
         })
 
-        let refreshtype = element.type + 'loading'
+        // 鍒犻櫎鎸夐挳鍏冪礌
+        let _delActions = _this.state.delActions
+        if (element.type === 'action') {
+          _delActions.push(element.card.uuid)
+        }
 
         _this.setState({
           config: _config,
-          delActions: [..._this.state.delActions, element.card.uuid],
-          [refreshtype]: true
-        }, () => {
-          _this.setState({
-            [refreshtype]: false
-          })
+          delActions: _delActions
         })
       },
       onCancel() {}
@@ -1564,17 +1563,13 @@
     }
 
     this.setState({
-      [addType + 'loading']: true,
       config: {...config, [addType]: items}
-    }, () => {
-      notification.success({
-        top: 92,
-        message: '鎿嶄綔鎴愬姛',
-        duration: 2
-      })
-      this.setState({
-        [addType + 'loading']: false
-      })
+    })
+
+    notification.success({
+      top: 92,
+      message: '鎿嶄綔鎴愬姛',
+      duration: 2
     })
   }
 
diff --git a/src/templates/tableshare/colspanform/index.jsx b/src/templates/tableshare/colspanform/index.jsx
index c91c6b0..11a6ed7 100644
--- a/src/templates/tableshare/colspanform/index.jsx
+++ b/src/templates/tableshare/colspanform/index.jsx
@@ -48,10 +48,7 @@
 
           let _card = {...this.props.card, ...values, sublist: targetKeys, subfield: subfield}
 
-          resolve({
-            type: 'columns',
-            values: _card
-          })
+          resolve(_card)
         } else {
           reject(err)
         }
diff --git a/src/templates/tableshare/dragelement/index.jsx b/src/templates/tableshare/dragelement/index.jsx
index 31ed8ae..5c3a12a 100644
--- a/src/templates/tableshare/dragelement/index.jsx
+++ b/src/templates/tableshare/dragelement/index.jsx
@@ -21,6 +21,7 @@
   if (!is(fromJS(cards), fromJS(list))) {
     setCards(list)
   }
+  
   const findCard = id => {
     const card = cards.filter(c => `${c.uuid}` === id)[0]
     return {
diff --git a/src/templates/tableshare/dragelform/card.jsx b/src/templates/tableshare/dragelform/card.jsx
new file mode 100644
index 0000000..8e31f09
--- /dev/null
+++ b/src/templates/tableshare/dragelform/card.jsx
@@ -0,0 +1,109 @@
+import React from 'react'
+import { useDrag, useDrop } from 'react-dnd'
+import { Icon, Select, DatePicker, Input } from 'antd'
+import moment from 'moment'
+import ItemTypes from './itemtypes'
+import './index.scss'
+
+const { MonthPicker, WeekPicker, RangePicker } = DatePicker
+
+const Card = ({ id, type, card, moveCard, findCard, editCard, delCard, hasDrop }) => {
+  const originalIndex = findCard(id).index
+  const [{ isDragging }, drag] = useDrag({
+    item: { type: ItemTypes[type], id, originalIndex },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  })
+  const [, drop] = useDrop({
+    accept: ItemTypes[type],
+    canDrop: () => true,
+    drop: (item) => {
+      if (!item.hasOwnProperty('originalIndex')) {
+        hasDrop(card)
+      }
+    },
+    hover({ id: draggedId }) {
+      if (!draggedId) return
+      if (draggedId !== id) {
+        const { index: overIndex } = findCard(id)
+        moveCard(draggedId, overIndex)
+      }
+    },
+  })
+  const opacity = isDragging ? 0 : 1
+
+  const edit = () => {
+    editCard(id)
+  }
+  
+  const del = () => {
+    delCard(id)
+  }
+
+  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 = '鍏ㄩ儴'
+    }
+  } 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-row ant-form-item">
+          <div className="ant-col ant-form-item-label">
+            <label title={card.label}>{card.label}</label>
+          </div>
+          <div className="ant-col ant-form-item-control-wrapper">
+            {card.type === 'text' ?
+              <Input style={{marginTop: '4px'}} defaultValue={card.initval} /> : null
+            }
+            {(card.type === 'multiselect' || card.type === 'select' || card.type === 'link') ?
+              <Select defaultValue={_defaultValue}></Select> : null
+            }
+            {card.type === 'date' ?
+              <DatePicker defaultValue={card.initval ? moment().subtract(card.initval, 'days') : null} /> : null
+            }
+            {card.type === 'dateweek' ?
+              <WeekPicker defaultValue={card.initval ? moment().subtract(card.initval * 7, 'days') : null} /> : null
+            }
+            {card.type === 'datemonth' ?
+              <MonthPicker defaultValue={card.initval ? moment().subtract(card.initval, 'month') : null} /> : null
+            }
+            {card.type === 'daterange' ?
+              <RangePicker
+                className="data-range"
+                placeholder={['寮�濮嬫棩鏈�', '缁撴潫鏃ユ湡']}
+                renderExtraFooter={() => 'extra footer'}
+                defaultValue={_defaultValue}
+              /> : null
+            }
+            <div className="input-mask"></div>
+          </div>
+        </div>
+      </div>
+      <Icon className="edit" title="缂栬緫" type="edit" onClick={edit} />
+      <Icon className="edit close" title="鍒犻櫎" type="close" onClick={del} />
+    </div>
+  )
+}
+export default Card
diff --git a/src/templates/tableshare/dragelform/index.jsx b/src/templates/tableshare/dragelform/index.jsx
new file mode 100644
index 0000000..88958aa
--- /dev/null
+++ b/src/templates/tableshare/dragelform/index.jsx
@@ -0,0 +1,118 @@
+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 ItemTypes from './itemtypes'
+import './index.scss'
+
+const Container = ({list, type, placeholder, handleList, handleMenu, deleteMenu }) => {
+  let target = null
+  
+  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(type, _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: card, type: type})
+  }
+
+  const hasDrop = (item) => {
+    target = item
+  }
+
+  const [, drop] = useDrop({
+    accept: ItemTypes[type],
+    drop(item) {
+      if (item.hasOwnProperty('originalIndex')) {
+        return
+      }
+
+      let newcard = {}
+      newcard.uuid = Utils.getuuid()
+      newcard.focus = true
+      
+      let _match = 'like'
+      if (item.subType === 'select' || item.subType === 'link') {
+        _match = '='
+      } else if (item.subType === 'date' || item.subType === 'datemonth') {
+        _match = '>='
+      } else if (item.subType === 'dateweek' || item.subType === 'daterange') {
+        _match = 'between'
+      }
+      
+      newcard.label = 'label'
+      newcard.initval = ''
+      newcard.type = item.subType
+      newcard.resourceType = '0'
+      newcard.options = []
+      newcard.setAll = 'false'
+      newcard.orderType = 'asc'
+      newcard.match = _match
+      newcard.display = 'dropdown'
+      
+      let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
+      if (target) {
+        targetId = target.uuid
+      }
+
+      const { index: overIndex } = findCard(`${targetId}`)
+      let targetIndex = overIndex
+
+      targetIndex++
+
+      const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
+
+      handleList(type, _cards, newcard)
+      target = null
+    }
+  })
+
+  return (
+    <div ref={drop} className="ant-row">
+      {cards.map(card => (
+        <Col key={card.uuid} span={6}>
+          <Card
+            id={`${card.uuid}`}
+            type={type}
+            card={card}
+            moveCard={moveCard}
+            editCard={editCard}
+            delCard={delCard}
+            findCard={findCard}
+            hasDrop={hasDrop}
+          />
+        </Col>
+      ))}
+      {cards.length === 0 &&
+        <div className="common-drawarea-placeholder">
+          {placeholder}
+        </div>
+      }
+    </div>
+  )
+}
+export default Container
diff --git a/src/templates/tableshare/dragelform/index.scss b/src/templates/tableshare/dragelform/index.scss
new file mode 100644
index 0000000..38776f9
--- /dev/null
+++ b/src/templates/tableshare/dragelform/index.scss
@@ -0,0 +1,15 @@
+.common-source-item {
+  display: block;
+  box-shadow: 0px 0px 2px #bcbcbc;
+  padding: 0.4rem 0.7rem;
+  background-color: white;
+  margin: 0px 0px 10px;
+  cursor: move;
+  border-radius: 4px;
+}
+.common-drawarea-placeholder {
+  width: 100%;
+  line-height: 65px;
+  text-align: center;
+  color: #bcbcbc;
+}
\ No newline at end of file
diff --git a/src/templates/tableshare/dragelform/itemtypes.js b/src/templates/tableshare/dragelform/itemtypes.js
new file mode 100644
index 0000000..9ea1f2c
--- /dev/null
+++ b/src/templates/tableshare/dragelform/itemtypes.js
@@ -0,0 +1,8 @@
+export default {
+  CARD: 'card',
+  form: 'form',
+  search: 'search',
+  action: 'action',
+  columns: 'columns',
+  tab: 'tab'
+}
diff --git a/src/templates/tableshare/dragelform/source.jsx b/src/templates/tableshare/dragelform/source.jsx
new file mode 100644
index 0000000..ab22158
--- /dev/null
+++ b/src/templates/tableshare/dragelform/source.jsx
@@ -0,0 +1,13 @@
+import React from 'react'
+import { useDrag } from 'react-dnd'
+import './index.scss'
+
+const SourceElement = ({content}) => {
+  const [, drag] = useDrag({ item: content })
+  return (
+    <div ref={drag} className="common-source-item">
+      {content.label}
+    </div>
+  )
+}
+export default SourceElement
\ No newline at end of file
diff --git a/src/templates/tableshare/formconfig.js b/src/templates/tableshare/formconfig.js
index e3df2fb..38c3fc0 100644
--- a/src/templates/tableshare/formconfig.js
+++ b/src/templates/tableshare/formconfig.js
@@ -201,45 +201,7 @@
  * @param {*} config         椤甸潰閰嶇疆
  * @param {*} permFuncField  瀛樺偍杩囩▼鍙敤鐨勫紑濮嬪瓧娈�
  */
-export function getActionForm (card, functip, config, permFuncField, type) {
-  let openTypeOptions = [{
-    value: 'pop',
-    text: Formdict['header.form.popform']
-  }, {
-    value: 'prompt',
-    text: Formdict['header.form.prompt']
-  }, {
-    value: 'exec',
-    text: Formdict['header.form.exec']
-  }, {
-    value: 'excelIn',
-    text: Formdict['header.form.excelIn']
-  }, {
-    value: 'excelOut',
-    text: Formdict['header.form.excelOut']
-  }, {
-    value: 'popview',
-    text: Formdict['header.form.popview']
-  }]
-
-  if (type === 'main') {
-    openTypeOptions = [
-      ...openTypeOptions,
-      {
-        value: 'tab',
-        text: Formdict['header.form.tab']
-      }, {
-        value: 'blank',
-        text: Formdict['header.form.blank']
-      }, {
-        value: 'innerpage',
-        text: Formdict['header.form.newpage.inner']
-      }, {
-        value: 'outerpage',
-        text: Formdict['header.form.newpage.outer']
-      }
-    ]
-  }
+export function getActionForm (card, functip, config, permFuncField) {
   return [
     {
       type: 'text',
@@ -255,7 +217,37 @@
       label: Formdict['header.form.openType'],
       initVal: card.OpenType,
       required: true,
-      options: openTypeOptions
+      options: [{
+        value: 'pop',
+        text: Formdict['header.form.popform']
+      }, {
+        value: 'prompt',
+        text: Formdict['header.form.prompt']
+      }, {
+        value: 'exec',
+        text: Formdict['header.form.exec']
+      }, {
+        value: 'excelIn',
+        text: Formdict['header.form.excelIn']
+      }, {
+        value: 'excelOut',
+        text: Formdict['header.form.excelOut']
+      }, {
+        value: 'popview',
+        text: Formdict['header.form.popview']
+      }, {
+        value: 'tab',
+        text: Formdict['header.form.tab']
+      }, {
+        value: 'blank',
+        text: Formdict['header.form.blank']
+      }, {
+        value: 'innerpage',
+        text: Formdict['header.form.newpage.inner']
+      }, {
+        value: 'outerpage',
+        text: Formdict['header.form.newpage.outer']
+      }]
     }, {
       type: 'select',
       key: 'tabType',
@@ -379,10 +371,10 @@
       type: 'select',
       key: 'tabTemplate',
       label: '鏍囩妯℃澘',
-      initVal: card.tabTemplate || 'formTab',
+      initVal: card.tabTemplate || 'FormTab',
       required: true,
       options: [{
-        value: 'formTab',
+        value: 'FormTab',
         text: '甯︽爣绛捐〃鍗�'
       }]
     },
@@ -674,4 +666,217 @@
       required: false
     }
   ]
+}
+
+/**
+ * @description 鑾峰彇琛ㄥ崟閰嶇疆淇℃伅
+ * @param {*} card 
+ * @param {*} inputfields 
+ */
+export function getModalForm (card, inputfields) {
+  return [
+    {
+      type: 'text',
+      key: 'label',
+      label: Formdict['header.form.name'],
+      initVal: card.label,
+      required: true,
+      readonly: false
+    },
+    {
+      type: 'text',
+      key: 'field',
+      label: Formdict['header.form.field'],
+      initVal: card.field,
+      required: true,
+      readonly: false
+    },
+    {
+      type: 'select',
+      key: 'type',
+      label: Formdict['header.form.type'],
+      initVal: card.type,
+      required: true,
+      options: [{
+        value: 'text',
+        text: Formdict['header.form.text']
+      }, {
+        value: 'number',
+        text: Formdict['header.form.number']
+      }, {
+        value: 'select',
+        text: Formdict['header.form.select']
+      }, {
+        value: 'multiselect',
+        text: Formdict['header.form.multiselect']
+      }, {
+        value: 'link',
+        text: Formdict['header.form.link']
+      }, {
+        value: 'fileupload',
+        text: Formdict['header.form.fileupload']
+      }, {
+        value: 'date',
+        text: Formdict['header.form.dateday']
+      }, {
+        value: 'datemonth',
+        text: Formdict['header.form.datemonth']
+      }, {
+        value: 'datetime',
+        text: Formdict['header.form.datetime']
+      }, {
+        value: 'textarea',
+        text: Formdict['header.form.textarea']
+      }]
+    },
+    {
+      type: 'text',
+      key: 'initval',
+      label: Formdict['header.form.initval'],
+      initVal: card.initval,
+      required: false
+    },
+    {
+      type: 'radio',
+      key: 'resourceType',
+      label: Formdict['header.form.resourceType'],
+      initVal: card.resourceType || '0',
+      required: true,
+      options: [{
+        value: '0',
+        text: Formdict['header.form.custom']
+      }, {
+        value: '1',
+        text: Formdict['header.form.datasource']
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'setAll',
+      label: Formdict['header.form.setAll'],
+      initVal: card.setAll || 'false',
+      options: [{
+        value: 'true',
+        text: Formdict['header.form.true']
+      }, {
+        value: 'false',
+        text: Formdict['header.form.false']
+      }]
+    },
+    {
+      type: 'textarea',
+      key: 'dataSource',
+      label: Formdict['header.form.datasource'],
+      initVal: card.dataSource || '',
+      required: true,
+      readonly: false
+    },
+    {
+      type: 'options',
+      key: 'options',
+      label: '',
+      initVal: card.options || [],
+      required: true,
+      readonly: false
+    },
+    {
+      type: 'text',
+      key: 'linkField',
+      label: Formdict['header.form.linkField'],
+      initVal: card.linkField || '',
+      required: true,
+      readonly: false
+    },
+    {
+      type: 'text',
+      key: 'valueField',
+      label: Formdict['header.form.valueField'],
+      initVal: card.valueField || '',
+      required: true,
+      readonly: false
+    },
+    {
+      type: 'text',
+      key: 'valueText',
+      label: Formdict['header.form.valueText'],
+      initVal: card.valueText || '',
+      required: true,
+      readonly: false
+    },
+    {
+      type: 'text',
+      key: 'orderBy',
+      label: Formdict['header.form.orderBy'],
+      initVal: card.orderBy || '',
+      required: false,
+      readonly: false
+    },
+    {
+      type: 'select',
+      key: 'orderType',
+      label: Formdict['header.form.orderType'],
+      initVal: card.orderType || 'asc',
+      options: [{
+        value: 'asc',
+        text: Formdict['header.form.asc']
+      }, {
+        value: 'desc',
+        text: Formdict['header.form.desc']
+      }]
+    },
+    {
+      type: 'number',
+      key: 'decimal',
+      label: Formdict['header.form.decimal'],
+      initVal: card.decimal || 0,
+      required: false
+    },
+    {
+      type: 'number',
+      key: 'min',
+      label: '鏈�灏忓��',
+      initVal: card.min || '',
+      required: false
+    },
+    {
+      type: 'number',
+      key: 'max',
+      label: '鏈�澶у��',
+      initVal: card.max || '',
+      required: false
+    },
+    {
+      type: 'radio',
+      key: 'readonly',
+      label: Formdict['header.form.readonly'],
+      initVal: card.readonly || 'false',
+      options: [{
+        value: 'true',
+        text: Formdict['header.form.true']
+      }, {
+        value: 'false',
+        text: Formdict['header.form.false']
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'required',
+      label: Formdict['header.form.field.required'],
+      initVal: card.required || 'false',
+      options: [{
+        value: 'true',
+        text: Formdict['header.form.true']
+      }, {
+        value: 'false',
+        text: Formdict['header.form.false']
+      }]
+    },
+    {
+      type: 'multiselect',
+      key: 'linkSubField',
+      label: Formdict['header.form.linkForm'],
+      initVal: card.linkSubField || [],
+      options: inputfields
+    }
+  ]
 }
\ No newline at end of file
diff --git a/src/templates/formtabconfig/tabdragelement/card.jsx b/src/templates/tableshare/tabdragelement/card.jsx
similarity index 100%
rename from src/templates/formtabconfig/tabdragelement/card.jsx
rename to src/templates/tableshare/tabdragelement/card.jsx
diff --git a/src/templates/comtableconfig/tabdragelement/index.jsx b/src/templates/tableshare/tabdragelement/index.jsx
similarity index 98%
rename from src/templates/comtableconfig/tabdragelement/index.jsx
rename to src/templates/tableshare/tabdragelement/index.jsx
index b5156e3..a6a9328 100644
--- a/src/templates/comtableconfig/tabdragelement/index.jsx
+++ b/src/templates/tableshare/tabdragelement/index.jsx
@@ -15,8 +15,9 @@
   const moveCard = (id, atIndex) => {
     const { card, index } = findCard(id)
     if (!card) return
+    
     const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
-    handleList(type, _cards)
+    handleList(type, _cards, card)
   }
 
   if (!is(fromJS(cards), fromJS(list))) {
diff --git a/src/templates/formtabconfig/tabdragelement/index.scss b/src/templates/tableshare/tabdragelement/index.scss
similarity index 100%
rename from src/templates/formtabconfig/tabdragelement/index.scss
rename to src/templates/tableshare/tabdragelement/index.scss
diff --git a/src/templates/comtableconfig/tabform/index.jsx b/src/templates/tableshare/tabform/index.jsx
similarity index 98%
rename from src/templates/comtableconfig/tabform/index.jsx
rename to src/templates/tableshare/tabform/index.jsx
index bc53aa2..d9372f7 100644
--- a/src/templates/comtableconfig/tabform/index.jsx
+++ b/src/templates/tableshare/tabform/index.jsx
@@ -200,10 +200,7 @@
             values.linkTab = Utils.getuuid()
           }
 
-          resolve({
-            type: this.props.type,
-            values
-          })
+          resolve(values)
         } else {
           reject(err)
         }
diff --git a/src/templates/comtableconfig/tabform/index.scss b/src/templates/tableshare/tabform/index.scss
similarity index 100%
rename from src/templates/comtableconfig/tabform/index.scss
rename to src/templates/tableshare/tabform/index.scss
diff --git a/src/utils/utils.js b/src/utils/utils.js
index ff237b6..50e592c 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -425,19 +425,24 @@
   static getSelectQuerySql (item) {
     let _datasource = item.dataSource
     let sql = ''
+    let _field = item.valueField + ',' + item.valueText
+
+    if (item.valueField === item.valueText) {
+      _field = item.valueField
+    }
 
     if (/\s/.test(_datasource)) { // 鎷兼帴鍒悕
       _datasource = '(' + _datasource + ') tb'
     }
 
     if (item.type === 'link') {
-      sql = 'select ' + item.valueField + ',' + item.valueText + ',' + item.linkField + ' from ' + _datasource
+      sql = 'select ' + _field + ',' + item.linkField + ' from ' + _datasource
     } else {
       let _linkSubField = '' // 涓嬫媺鑿滃崟鍏宠仈琛ㄥ崟
       if (item.linkSubField && item.linkSubField.length > 0) {
         _linkSubField = ',' + item.linkSubField.join(',')
       }
-      sql = 'select ' + item.valueField + ',' + item.valueText + _linkSubField + ' from ' + _datasource
+      sql = 'select ' + _field + _linkSubField + ' from ' + _datasource
     }
 
     if (item.orderBy) {
diff --git a/src/views/login/index.jsx b/src/views/login/index.jsx
index 61672db..c36e6b2 100644
--- a/src/views/login/index.jsx
+++ b/src/views/login/index.jsx
@@ -64,7 +64,7 @@
           sessionStorage.setItem('SessionUid', Utils.getuuid())
           sessionStorage.setItem('LoginUID', res.LoginUID)
           sessionStorage.setItem('User_Name', res.UserName)
-          sessionStorage.setItem('avatar', res.icon)
+          sessionStorage.setItem('avatar', res.icon || '')
           
           localStorage.setItem('lang', param.lang)
 

--
Gitblit v1.8.0