From 0c86e5e2eaf907dfcb63aea13e6efac3ccc52cce Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期二, 25 二月 2020 11:06:20 +0800
Subject: [PATCH] 2020-02-25

---
 src/components/tabview/index.jsx                                  |    6 
 src/components/header/index.scss                                  |   27 
 src/templates/tableshare/verifycardexcelin/columnform/index.jsx   |   16 
 src/tabviews/managesubtable/index.jsx                             |  696 ++++++++++++++++++
 src/templates/tableshare/verifycardexcelin/customscript/index.jsx |   52 +
 src/components/header/index.jsx                                   |   30 
 src/templates/tableshare/verifycardexcelout/index.jsx             |    1 
 src/templates/formtabconfig/index.jsx                             |    2 
 src/tabviews/managetable/index.jsx                                | 1006 +++++++++++++++++++++++++++
 src/templates/comtableconfig/index.jsx                            |   12 
 src/templates/formtabconfig/actionform/index.jsx                  |    1 
 src/templates/subtableconfig/index.jsx                            |   13 
 src/tabviews/tableshare/actionList/index.jsx                      |   22 
 src/templates/modalconfig/index.jsx                               |   31 
 src/tabviews/managesubtable/index.scss                            |   37 +
 src/templates/formtabconfig/source.jsx                            |    4 
 src/tabviews/managetable/index.scss                               |  109 ++
 src/tabviews/subtable/index.jsx                                   |    9 
 src/components/sidemenu/index.jsx                                 |   29 
 src/templates/tableshare/verifycard/index.jsx                     |   22 
 src/templates/tableshare/verifycardexcelin/index.jsx              |   27 
 src/templates/tableshare/verifycardexcelout/columnform/index.jsx  |   14 
 src/utils/utils.js                                                |   24 
 23 files changed, 2,154 insertions(+), 36 deletions(-)

diff --git a/src/components/header/index.jsx b/src/components/header/index.jsx
index 079ead9..c629ec0 100644
--- a/src/components/header/index.jsx
+++ b/src/components/header/index.jsx
@@ -4,7 +4,7 @@
 import {connect} from 'react-redux'
 import { is, fromJS } from 'immutable'
 import moment from 'moment'
-import {Dropdown, Menu, Icon, Modal, Form, notification, Switch } from 'antd'
+import {Dropdown, Menu, Icon, Modal, Form, notification, Switch, Button } from 'antd'
 import asyncComponent from '@/utils/asyncComponent'
 import {
   toggleCollapse,
@@ -320,6 +320,26 @@
     // 杩涘叆缂栬緫鐘舵��
     this.props.resetEditLevel('level1')
   }
+
+  enterEditManage = () => {
+    const { editLevel } = this.props
+
+    if (editLevel === 'level4')  return
+
+    this.props.resetEditLevel('level4')
+    this.props.modifyMainMenu({
+      MenuID: 'systemManageView'
+    })
+  }
+
+  /**
+   * @description 閫�鍑虹鐞嗙晫闈㈣彍鍗�
+   */
+  exitManage = () => {
+    this.props.resetEditState(true)
+    this.props.resetEditLevel(false)
+    this.reload()
+  }
   
   exitEdit = () => {
     // 閫�鍑虹紪杈戠姸鎬�
@@ -378,7 +398,7 @@
         </div>
         {/* 姝e父鑿滃崟 */}
         {this.props.editLevel !== 'level1' && this.state.menulist &&
-        <ul className="header-menu">{
+        <ul className={'header-menu ' + this.props.editLevel}>{
           this.state.menulist.map(item => {
             return (
               <li key={item.MenuID} onClick={() => {this.changeMenu(item)}} className={this.props.selectmenu.MenuID === item.MenuID ? 'active' : ''}>
@@ -386,7 +406,13 @@
               </li>
             )
           })}
+          {this.props.editState && (!this.props.editLevel || this.props.editLevel === 'level4') ?
+            <li key="HS" onClick={this.enterEditManage} className={this.props.editLevel === 'level4' ? 'active' : ''}>
+              <span>HS</span>
+            </li> : null
+          }
         </ul>}
+        {this.props.editLevel === 'level4' ? <Button className="level4-close" type="primary" onClick={this.exitManage}>閫�鍑�</Button> : null}
         {/* 杩涘叆缂栬緫鎸夐挳 */}
         {this.props.editState && !this.props.editLevel && <Icon onClick={this.enterEdit} className="edit-check" type="edit" />}
         {/* 缂栬緫鑿滃崟 */}
diff --git a/src/components/header/index.scss b/src/components/header/index.scss
index e5c0df8..29ac023 100644
--- a/src/components/header/index.scss
+++ b/src/components/header/index.scss
@@ -74,6 +74,26 @@
       }
     }
   }
+
+  .header-menu.level4 {
+    li {
+      cursor: default;
+      &:hover {
+        span {
+          cursor: default;
+          color: rgba(255, 255, 255, 0.65);
+          border-bottom: none;
+        }
+      }
+      &.active {
+        span {
+          color: #ffffff;
+          border-bottom: 4px solid #1890ff;
+        }
+      }
+    }
+  }
+
   .header-setting {
     float: right;
     line-height: 48px;
@@ -103,6 +123,13 @@
     margin-left: 10px;
     cursor: pointer;
   }
+  .level4-close {
+    position: relative;
+    top: 13px;
+    left: 20px;
+    height: 26px;
+    padding: 0 10px;
+  }
 }
 .header-dropdown {
   li {
diff --git a/src/components/sidemenu/index.jsx b/src/components/sidemenu/index.jsx
index b5c33a2..f586415 100644
--- a/src/components/sidemenu/index.jsx
+++ b/src/components/sidemenu/index.jsx
@@ -8,6 +8,7 @@
 import {modifyTabview, resetEditLevel} from '@/store/action'
 import zhCN from '@/locales/zh-CN/header.js'
 import enUS from '@/locales/en-US/header.js'
+import Utils from '@/utils/utils.js'
 import Api from '@/api'
 import './index.scss'
 
@@ -167,8 +168,30 @@
     }
   }
 
+  enterManageView = () => {
+    let menulist = [{
+      MenuID: Utils.getuuid(),
+      text: '閰嶇疆',
+      PageParam: {Icon: 'folder'},
+      children: [{
+        src: '',
+        PageParam: {OpenType: 'newtab', Template: 'ManageTable'},
+        type: 'ManageTable',
+        MenuID: '1581067625930haged11ieaivpavv77k',
+        MenuNo: 'sDatasM',
+        MenuName: '鏁版嵁瀛楀吀',
+        text: '鏁版嵁瀛楀吀'
+      }]
+    }]
+    this.setState({
+      subMenulist: menulist,
+      rootSubmenuKeys: menulist.map(item => item.MenuID),
+      openKeys: this.props.collapse ? [] : [menulist[0].MenuID]
+    })
+  }
+
   changemenu(e) {
-    if (this.props.editState) {
+    if (this.props.editState && this.props.editLevel !== 'level4') {
       e.preventDefault()
       return
     }
@@ -194,7 +217,9 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    if (!is(fromJS(this.props.mainMenu), fromJS(nextProps.mainMenu))) {
+    if (nextProps.mainMenu && nextProps.mainMenu.MenuID === 'systemManageView') {
+      this.enterManageView()
+    } else if (!is(fromJS(this.props.mainMenu), fromJS(nextProps.mainMenu))) {
       // 涓昏彍鍗曞垏鎹紝璇锋眰2銆�3绾ц彍鍗曟暟鎹�
       this.loadsubmenu(nextProps.mainMenu)
     } else if (nextProps.collapse && this.props.collapse !== nextProps.collapse) {
diff --git a/src/components/tabview/index.jsx b/src/components/tabview/index.jsx
index ed5a8b2..25bef0f 100644
--- a/src/components/tabview/index.jsx
+++ b/src/components/tabview/index.jsx
@@ -80,6 +80,8 @@
       return (<Comps.Home MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
     } else if (view.type === 'CommonTable') {
       return (<Comps.CommonTable MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
+    } else if (view.type === 'ManageTable') {
+      return (<Comps.CommonTable MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
     } else if (view.type === 'DataManage') {
       return (<Comps.DataManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
     } else if (view.type === 'RolePermission') {
@@ -159,6 +161,8 @@
           Comps.Home = asyncComponent(() => import('@/tabviews/home'))
         } else if (!Comps.CommonTable && newtab.type === 'CommonTable') {
           Comps.CommonTable = asyncComponent(() => import('@/tabviews/commontable'))
+        } else if (!Comps.CommonTable && newtab.type === 'ManageTable') {
+          Comps.CommonTable = asyncComponent(() => import('@/tabviews/managetable'))
         } else if (!Comps.Iframe && newtab.type === 'iframe') {
           Comps.Iframe = asyncComponent(() => import('@/tabviews/iframe'))
         } else if (!Comps.DataManage && newtab.type === 'DataManage') {
@@ -215,7 +219,7 @@
                       key={view.MenuID}
                     >
                       {this.selectcomponent(view)}
-                      {view.type !== 'CommonTable' ?
+                      {view.type !== 'CommonTable' && view.type !== 'ManageTable' ?
                         <Button
                           icon="copy"
                           shape="circle"
diff --git a/src/tabviews/managesubtable/index.jsx b/src/tabviews/managesubtable/index.jsx
new file mode 100644
index 0000000..2f5ddc9
--- /dev/null
+++ b/src/tabviews/managesubtable/index.jsx
@@ -0,0 +1,696 @@
+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'
+import Api from '@/api'
+import SubTable from '@/tabviews/subtable/subTable'
+import SubAction from '@/tabviews/tableshare/actionList'
+import SubSearch from '@/tabviews/tableshare/topSearch'
+import asyncComponent from '@/utils/asyncLoadComponent'
+import NotFount from '@/components/404'
+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'))
+
+class SubTabViewTable extends Component {
+  static propTpyes = {
+    Tab: PropTypes.object,           // 鏍囩淇℃伅
+    BID: PropTypes.string,           // 涓婄骇鏁版嵁ID
+    BData: PropTypes.any,            // 涓婄骇鏁版嵁
+    MenuID: PropTypes.string,        // 鑿滃崟Id
+    SupMenuID: PropTypes.string,     // 涓婄骇鑿滃崟Id
+    ContainerId: PropTypes.any,      // 涓夌骇鑿滃崟Container(html) ID
+    handleTableId: PropTypes.func,   // 鎺у埗琛ㄦ牸鏁版嵁鍒囨崲鏃讹紝鏇存柊鍦ㄤ富琛ㄤ腑鐨刬d
+    handleMainTable: PropTypes.func, // 鍒锋柊涓昏〃
+    refreshtabs:PropTypes.any
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    loadingview: true,    // 椤甸潰鍔犺浇涓�
+    viewlost: false,      // 椤甸潰涓㈠け锛�1銆佹湭鑾峰彇鍒伴厤缃�-椤甸潰涓㈠け锛�2銆侀〉闈㈡湭鍚敤
+    lostmsg: '',          // 椤甸潰涓㈠け鏃剁殑鎻愮ず淇℃伅
+    config: null,         // 椤甸潰閰嶇疆淇℃伅锛屽寘鎷寜閽�佹悳绱€�佹樉绀哄垪銆佹爣绛剧瓑
+    searchlist: null,     // 鎼滅储鏉′欢
+    actions: null,        // 鎸夐挳闆�
+    columns: null,        // 鏄剧ず鍒�
+    logcolumns: null,     // 鏃ュ織涓樉绀虹殑鍒椾俊鎭� (澧炲姞鑷冲叏閮ㄥ垪锛岄櫎鍘诲悎骞跺垪)
+    arr_field: '',        // 浣跨敤 sPC_Get_TableData 鏃剁殑鏌ヨ瀛楁闆�
+    setting: null,        // 椤甸潰鍏ㄥ眬璁剧疆锛氭暟鎹簮銆佹寜閽強鏄剧ず鍒楀浐瀹氥�佷富閿瓑
+    data: null,           // 鍒楄〃鏁版嵁闆�
+    total: 0,             // 鎬绘暟
+    loading: false,       // 鍒楄〃鏁版嵁鍔犺浇涓�
+    pageIndex: 1,         // 椤电爜
+    pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
+    orderBy: '',          // 鎺掑簭
+    search: '',           // 鎼滅储鏉′欢鏁扮粍锛屼娇鐢ㄦ椂闇�鍒嗗満鏅鐞�
+    configMap: {},        // 椤甸潰閰嶇疆淇℃伅锛氫笅鎷夈�佹寜閽瓑
+    popAction: false,     // 寮规椤甸潰锛屾寜閽俊鎭�
+    popData: false,       // 寮规椤甸潰锛屾墍閫夌殑琛ㄦ牸鏁版嵁
+    visible: false        // 寮规鏄剧ず闅愯棌鎺у埗
+  }
+
+  /**
+   * @description 涓婄骇鑿滃崟id鍙樺寲鏃讹紝鍒锋柊鏁版嵁
+   */
+  UNSAFE_componentWillReceiveProps(nextProps) {
+    if (this.state.config && this.props.Tab.supMenu && !is(fromJS(this.props.BID), fromJS(nextProps.BID))) {
+      this.refs.subTable.resetTable()
+      this.loadmaindata(nextProps.BID, 'refresh')
+    } else if (this.state.config && nextProps.refreshtabs && nextProps.refreshtabs.includes(this.props.Tab.uuid)) {
+      this.reloadtable()
+    }
+  }
+
+  /**
+   * @description 鑾峰彇椤甸潰閰嶇疆淇℃伅
+   */
+  async loadconfig () {
+    const { Tab, BID } = 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 _logcolumns = []   // 鏃ュ織鏄剧ず鍒�
+      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) {
+          _arrField.push(col.field)
+
+          _logcolumns.push(col)
+        }
+        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
+        })
+      }
+
+      this.setState({
+        loadingview: false,
+        config: config,
+        setting: config.setting,
+        searchlist: config.search,
+        actions: _actions,
+        columns: _columns,
+        logcolumns: _logcolumns,
+        arr_field: _arrField.join(','),
+        search: Utils.initMainSearch(config.search) // 鎼滅储鏉′欢鍒濆鍖栵紙鍚湁鏃堕棿鏍煎紡锛岄渶瑕佽浆鍖栵級
+      }, () => {
+        this.improveSearch()
+
+        if (config.setting.onload !== 'false' && (!Tab.supMenu || BID)) { // 鍒濆鍖栧彲鍔犺浇
+          this.setState({
+            loading: true
+          })
+          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 _option = Utils.getSelectQueryOptions(item)
+        let _sql = Utils.formatOptions(_option.sql)
+        let isSSO = item.database === 'sso'
+
+        let param = {
+          func: 'sPC_Get_SelectedList',
+          LText: _sql,
+          obj_name: 'data',
+          arr_field: _option.field
+        }
+
+        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, isSSO).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 (bid, type) {
+    const { setting } = this.state
+    let param = ''
+    let _BID = this.props.BID
+    
+    if (type === 'refresh') {
+      _BID = bid
+      if (!bid) { // 涓昏〃ID涓嶅瓨鍦ㄦ椂锛屼笉鏌ヨ瀛愯〃
+        this.setState({
+          data: [],
+          total: 0,
+          loading: false
+        })
+
+        return
+      }
+    }
+
+    if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) {
+      param = this.getCustomParam(_BID)
+    } else {
+      param = this.getDefaultParam(_BID)
+    }
+
+    this.handleTableId()
+
+    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
+      })
+    } else {
+      this.setState({
+        loading: false
+      })
+      notification.error({
+        top: 92,
+        message: result.message,
+        duration: 15
+      })
+    }
+  }
+
+  /**
+   * @description 鑾峰彇鐢ㄦ埛鑷畾涔夊瓨鍌ㄨ繃绋嬩紶鍙�
+   */
+  getCustomParam = (BID) => {
+    const { pageIndex, pageSize, orderBy, search, setting } = this.state
+
+    let _search = Utils.formatCustomMainSearch(search)
+
+    let param = {
+      PageIndex: pageIndex,
+      PageSize: pageSize,
+      OrderCol: orderBy || setting.order,
+      BID: BID,
+      ..._search
+    }
+
+    if (setting.interType === 'inner') {
+      param.func = setting.innerFunc
+    } else {
+      if (setting.sysInterface === 'true') {
+        param.rduri = window.GLOB.mainSystemApi || window.GLOB.subSystemApi
+      } else {
+        param.rduri = setting.interface
+      }
+
+      param.appkey = window.GLOB.appkey || '' // 璋冪敤澶栭儴鎺ュ彛澧炲姞appkey
+
+      if (setting.outerFunc) {
+        param.func = setting.outerFunc
+      }
+    }
+
+    return param
+  }
+
+  /**
+   * @description 鑾峰彇绯荤粺瀛樺偍杩囩▼ sPC_Get_TableData 鐨勫弬鏁�
+   */
+  getDefaultParam = (BID) => {
+    const { arr_field, pageIndex, pageSize, orderBy, 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,
+      BID: BID,
+      appkey: window.GLOB.appkey || ''
+    }
+
+    let _orderBy = orderBy || setting.order
+    let _dataresource = setting.dataresource
+
+    if (/\s/.test(_dataresource)) {
+      _dataresource = '(' + _dataresource + ') tb'
+    }
+
+    if (setting.queryType === 'statistics') { // 缁熻鏁版嵁婧愶紝鍐呭鏇挎崲
+      let fieldmap = new Map()
+      let options = search.map(item => {
+        let _field = item.key
+
+        if (fieldmap.has(_field)) {
+          _field = _field + '1'
+        }
+
+        fieldmap.set(item.key, true)
+
+        return {
+          reg: new RegExp('@' + _field, 'ig'),
+          value: item.value
+        }
+      })
+
+      options.reverse()
+
+      options.forEach(item => {
+        _dataresource = _dataresource.replace(item.reg, `'${item.value}'`)
+      })
+
+      _search = ''
+    }
+
+    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) => {
+    this.refs.subTable.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,
+      orderBy: (sorter.field && sorter.order) ? `${sorter.field} ${sorter.order}` : ''
+    }, () => {
+      this.loadmaindata()
+    })
+  }
+
+  /**
+   * @description 琛ㄦ牸鍒锋柊
+   */
+  reloadtable = () => {
+    this.refs.subTable.resetTable()
+    this.setState({
+      loading: true,
+      pageIndex: 1
+    }, () => {
+      this.loadmaindata()
+    })
+  }
+
+  /**
+   * @description 椤甸潰鍒锋柊锛岄噸鏂拌幏鍙栭厤缃�
+   */
+  reloadview = () => {
+    this.setState({
+      loadingview: true,
+      viewlost: false,
+      lostmsg: '',
+      config: null,
+      searchlist: null,
+      actions: null,
+      columns: null,
+      arr_field: '',
+      setting: null,
+      data: null,
+      total: 0,
+      loading: false,
+      pageIndex: 1,
+      pageSize: 10,
+      orderBy: '',
+      search: '',
+      configMap: {}
+    }, () => {
+      this.loadconfig()
+    })
+  }
+
+  /**
+   * @description 鎸夐挳鎿嶄綔瀹屾垚鍚庯紙鎴愬姛鎴栧け璐ワ級锛岄〉闈㈠埛鏂帮紝閲嶇疆椤电爜鍙婇�夋嫨椤�
+   */
+  refreshbyaction = (btn, type) => {
+    if (btn.execSuccess === 'grid' && type === 'success') {
+      this.reloadtable()
+    } else if (btn.execError === 'grid' && type === 'error') {
+      this.reloadtable()
+    } else if (btn.execSuccess === 'view' && type === 'success') {
+      this.reloadview()
+    } else if (btn.execError === 'view' && type === 'error') {
+      this.reloadview()
+    } else if (btn.popClose === 'grid' && type === 'pop') {
+      this.reloadtable()
+    } else if (btn.popClose === 'view' && type === 'pop') {
+      this.reloadview()
+    } else if (btn.popClose === 'maingrid' && type === 'pop') {
+      this.props.handleMainTable('maingrid')
+    } else if (btn.popClose === 'equaltab' && type === 'pop') {
+      this.reloadtable()
+      this.props.handleMainTable('equaltab')
+    } else if (btn.execSuccess === 'maingrid' && type === 'success') {
+      this.props.handleMainTable('maingrid')
+    } else if (btn.execSuccess === 'equaltab' && type === 'success') {
+      this.reloadtable()
+      this.props.handleMainTable('equaltab')
+    }
+  }
+
+  /**
+   * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
+   */
+  getexceloutparam = () => {
+    const { Tab } = this.props
+    const { arr_field, orderBy, search, setting} = this.state
+
+    return {
+      arr_field: arr_field,
+      orderBy: orderBy || setting.order,
+      search: search,
+      menuName: Tab.label
+    }
+  }
+
+  /**
+   * @description 鑾峰彇琛ㄦ牸閫夋嫨椤�
+   */
+  gettableselected = () => {
+    let data = []
+    this.refs.subTable.state.selectedRowKeys.forEach(item => {
+      data.push(this.refs.subTable.props.data[item])
+    })
+    return data
+  }
+
+  /**
+   * @description 琛ㄦ牸涓紝鎸夐挳瑙﹀彂浜嬩欢浼犻��
+   */
+  buttonTrigger = (btn, record) => {
+    this.refs.subButton.actionTrigger(btn, record)
+  }
+
+  /**
+   * @description 琛ㄦ牸Id鍙樺寲
+   */
+  handleTableId = (id = '', data = '') => {
+    this.props.handleTableId(this.props.Tab.uuid, id, data)
+  }
+
+  /**
+   * @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 } = this.state
+
+    return (
+      <div className="subtable" id={'subtable' + this.props.MenuID}>
+        {loadingview && <Spin size="large" />}
+        {searchlist && searchlist.length > 0 ?
+          <SubSearch
+            refreshdata={this.refreshbysearch}
+            searchlist={searchlist}
+            dict={this.state.dict}
+          /> : null
+        }
+        {actions &&
+          <SubAction
+            ref="subButton"
+            type="sub"
+            setting={setting}
+            actions={actions}
+            Tab={this.props.Tab}
+            BID={this.props.BID}
+            BData={this.props.BData}
+            dict={this.state.dict}
+            MenuID={this.props.SupMenuID}
+            logcolumns={this.state.logcolumns}
+            ContainerId={this.props.ContainerId}
+            refreshdata={this.refreshbyaction}
+            triggerPopview={this.triggerPopview}
+            getexceloutparam={this.getexceloutparam}
+            gettableselected={this.gettableselected}
+          />
+        }
+        {columns &&
+          <SubTable
+            ref="subTable"
+            dict={this.state.dict}
+            MenuID={this.props.MenuID}
+            setting={setting}
+            columns={columns}
+            data={this.state.data}
+            total={this.state.total}
+            loading={this.state.loading}
+            refreshdata={this.refreshbytable}
+            buttonTrigger={this.buttonTrigger}
+            handleTableId={this.handleTableId}
+          />
+        }
+        <Modal
+          className="popview-modal"
+          title={this.state.popAction.label}
+          width={'80vw'}
+          maskClosable={false}
+          visible={this.state.visible}
+          onCancel={this.popclose}
+          footer={[
+            <Button key="close" onClick={this.popclose}>{this.state.dict['main.close']}</Button>
+          ]}
+          destroyOnClose
+        >
+          {<SubTabTable
+            BID={this.props.BID}
+            BData={this.props.BData}
+            SupMenuID={this.props.MenuID}
+            ContainerId={this.props.ContainerId}
+            MenuID={this.state.popAction.linkTab}
+            ID={this.state.popData ? this.state.popData[setting.primaryKey] : ''}
+            refreshSupView={this.reloadtable}
+          />}
+        </Modal>
+        {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
+      </div>
+    )
+  }
+}
+
+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/managesubtable/index.scss b/src/tabviews/managesubtable/index.scss
new file mode 100644
index 0000000..74096d3
--- /dev/null
+++ b/src/tabviews/managesubtable/index.scss
@@ -0,0 +1,37 @@
+.subtable {
+  position: relative;
+  min-height: 200px;
+  padding-top: 16px;
+  > .top-search {
+    padding: 0 0px 20px;
+  }
+  > .button-list {
+    padding: 10px 0px 5px;
+  }
+  .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: absolute;
+    left: calc(50% - 22px);
+    top: 100px;
+  }
+}
+.popview-modal {
+  .ant-modal-body {
+    min-height: 300px;
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/managetable/index.jsx b/src/tabviews/managetable/index.jsx
new file mode 100644
index 0000000..3e9a357
--- /dev/null
+++ b/src/tabviews/managetable/index.jsx
@@ -0,0 +1,1006 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import {connect} from 'react-redux'
+import { is, fromJS } from 'immutable'
+import { notification, Spin, Tabs, Icon, Switch, Modal, Button, message, Tree, Typography } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import zhCN from '@/locales/zh-CN/main.js'
+import enUS from '@/locales/en-US/main.js'
+import Utils from '@/utils/utils.js'
+import asyncComponent from '@/utils/asyncLoadComponent'
+import {refreshTabView, modifyTabview} from '@/store/action'
+
+import MainTable from '@/tabviews/commontable/mainTable'
+import MainAction from '@/tabviews/tableshare/actionList'
+import MainSearch from '@/tabviews/tableshare/topSearch'
+import SubTable from '@/tabviews/subtable'
+import NotFount from '@/components/404'
+import './index.scss'
+
+const SubTabTable = asyncComponent(() => import('@/tabviews/subtabtable'))
+const FormTab = asyncComponent(() => import('@/tabviews/formtab'))
+const { TabPane } = Tabs
+const { TreeNode } = Tree
+const { Paragraph } = Typography
+
+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,
+    ContainerId: Utils.getuuid(), // 鑿滃崟澶栧眰html Id
+    view: 'commontable',  // 褰撳墠椤甸潰榛樿涓轰富琛�
+    loadingview: true,    // 椤甸潰鍔犺浇涓�
+    viewlost: false,      // 椤甸潰涓㈠け锛�1銆佹湭鑾峰彇鍒伴厤缃�-椤甸潰涓㈠け锛�2銆侀〉闈㈡湭鍚敤
+    lostmsg: '',          // 椤甸潰涓㈠け鏃剁殑鎻愮ず淇℃伅
+    config: {},           // 椤甸潰閰嶇疆淇℃伅锛屽寘鎷寜閽�佹悳绱€�佹樉绀哄垪銆佹爣绛剧瓑
+    searchlist: null,     // 鎼滅储鏉′欢
+    actions: null,        // 鎸夐挳闆�
+    columns: null,        // 鏄剧ず鍒�
+    logcolumns: null,     // 鏃ュ織涓樉绀虹殑鍒椾俊鎭� (澧炲姞鑷冲叏閮ㄥ垪锛岄櫎鍘诲悎骞跺垪)
+    arr_field: '',        // 浣跨敤 sPC_Get_TableData 鏃剁殑鏌ヨ瀛楁闆�
+    setting: null,        // 椤甸潰鍏ㄥ眬璁剧疆锛氭暟鎹簮銆佹寜閽強鏄剧ず鍒楀浐瀹氥�佷富閿瓑
+    data: null,           // 鍒楄〃鏁版嵁闆�
+    total: 0,             // 鎬绘暟
+    loading: false,       // 鍒楄〃鏁版嵁鍔犺浇涓�
+    pageIndex: 1,         // 椤电爜
+    pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
+    orderBy: '',          // 鎺掑簭
+    search: '',           // 鎼滅储鏉′欢鏁扮粍锛屼娇鐢ㄦ椂闇�鍒嗗満鏅鐞�
+    BIDs: {},             // 涓婄骇琛╥d
+    setsingle: false,     // 涓昏〃鍗曢�夊閫夊垏鎹�
+    pickup: false,        // 涓昏〃鏁版嵁闅愯棌鏄剧ず鍒囨崲
+    isLinkMain: false,    // 鏄惁瀛樺湪涓庝富琛ㄥ叧鑱旂殑瀛愯〃
+    popAction: false,     // 寮规椤甸潰锛屾寜閽俊鎭�
+    popData: false,       // 寮规椤甸潰锛屾墍閫夌殑琛ㄦ牸鏁版嵁
+    visible: false,       // 寮规鏄剧ず闅愯棌鎺у埗
+    treevisible: false,   // 鑿滃崟缁撴瀯鏍戝脊妗嗘樉绀洪殣钘忔帶鍒�
+    tabBtn: null,         // 琛ㄥ崟鏍囩鎸夐挳
+    tabParam: null,       // 琛ㄥ崟鏍囩鍙傛暟
+    refreshtabs: null     // 闇�瑕佸埛鏂扮殑鏍囩闆�
+  }
+
+  /**
+   * @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 _logcolumns = []   // 鏃ュ織鏄剧ず鍒�
+      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)
+
+          _logcolumns.push(col)
+        }
+        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 // 妫�鏌ユ槸鍚︽湁涓庝富琛ㄥ叧鑱旂殑瀛愯〃
+      config.tabgroups.forEach(groupId => {
+        if (!config[groupId] || config[groupId].length === 0) return
+
+        config[groupId].forEach(tab => {
+          if (tab.supMenu === 'mainTable') {
+            _isLinkMain = true
+          }
+        })
+      })
+
+      this.setState({
+        loadingview: false,
+        config: config,
+        setting: config.setting,
+        searchlist: config.search,
+        actions: _actions,
+        columns: _columns,
+        logcolumns: _logcolumns,
+        isLinkMain: _isLinkMain,
+        arr_field: _arrField.join(','),
+        search: Utils.initMainSearch(config.search) // 鎼滅储鏉′欢鍒濆鍖栵紙鍚湁鏃堕棿鏍煎紡锛岄渶瑕佽浆鍖栵級
+      }, () => {
+        this.improveSearch()
+
+        if (config.setting.onload !== 'false') { // 鍒濆鍖栧彲鍔犺浇
+          this.setState({
+            loading: true
+          })
+          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 _option = Utils.getSelectQueryOptions(item)
+        let _sql = Utils.formatOptions(_option.sql)
+        let isSSO = item.database === 'sso'
+
+        let param = {
+          func: 'sPC_Get_SelectedList',
+          LText: _sql,
+          obj_name: 'data',
+          arr_field: _option.field
+        }
+
+        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, isSSO).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', '', '')
+
+    if (!param) { // 鏈幏鍙栧弬鏁版椂锛屼笉鍙戣姹�
+      return
+    }
+
+    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, orderBy, search, setting } = this.state
+
+    let _search = Utils.formatCustomMainSearch(search)
+
+    let param = {
+      PageIndex: pageIndex,
+      PageSize: pageSize,
+      OrderCol: orderBy || setting.order,
+      ..._search
+    }
+
+    if (setting.interType === 'inner') {
+      param.func = setting.innerFunc
+    } else {
+      if (setting.sysInterface === 'true') {
+        param.rduri = window.GLOB.mainSystemApi || window.GLOB.subSystemApi
+      } else {
+        param.rduri = setting.interface
+      }
+
+      param.appkey = window.GLOB.appkey || '' // 璋冪敤澶栭儴鎺ュ彛澧炲姞appkey
+
+      if (setting.outerFunc) {
+        param.func = setting.outerFunc
+      }
+    }
+
+    return param
+  }
+
+  /**
+   * @description 鑾峰彇绯荤粺瀛樺偍杩囩▼ sPC_Get_TableData 鐨勫弬鏁�
+   */
+  getDefaultParam = () => {
+    const { arr_field, pageIndex, pageSize, orderBy, search, setting } = this.state
+
+    if (!arr_field) {
+      notification.warning({
+        top: 92,
+        message: '鏈缃樉绀哄垪锛�',
+        duration: 10
+      })
+      return null
+    }
+
+    let _search = Utils.joinMainSearchkey(search)
+
+    _search = _search ? 'where ' + _search : ''
+    
+    let param = {
+      func: 'sPC_Get_TableData',
+      obj_name: 'data',
+      arr_field: arr_field,
+      appkey: window.GLOB.appkey || ''
+    }
+    
+    let _orderBy = orderBy || setting.order
+    let _dataresource = setting.dataresource
+
+    if (/\s/.test(_dataresource)) {
+      _dataresource = '(' + _dataresource + ') tb'
+    }
+
+    if (setting.queryType === 'statistics') { // 缁熻鏁版嵁婧愶紝鍐呭鏇挎崲
+      let fieldmap = new Map()
+      let options = search.map(item => {
+        let _field = item.key
+
+        if (fieldmap.has(_field)) {
+          _field = _field + '1'
+        }
+
+        fieldmap.set(item.key, true)
+
+        return {
+          reg: new RegExp('@' + _field, 'ig'),
+          value: item.value
+        }
+      })
+
+      options.reverse()
+
+      options.forEach(item => {
+        _dataresource = _dataresource.replace(item.reg, `'${item.value}'`)
+      })
+
+      _search = ''
+    }
+
+    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,
+      orderBy: (sorter.field && sorter.order) ? `${sorter.field} ${sorter.order}` : ''
+    }, () => {
+      this.loadmaindata()
+    })
+  }
+
+  /**
+   * @description 琛ㄦ牸鍒锋柊
+   */
+  reloadtable = () => {
+    this.refs.mainTable.resetTable()
+    this.setState({
+      loading: true,
+      pageIndex: 1
+    }, () => {
+      this.loadmaindata()
+    })
+  }
+
+  /**
+   * @description 椤甸潰鍒锋柊锛岄噸鏂拌幏鍙栭厤缃�
+   */
+  reloadview = () => {
+    this.setState({
+      view: 'commontable',
+      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,
+      orderBy: '',
+      search: '',
+      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.reloadtable()
+    } else if (btn.execSuccess === 'view' && type === 'success') {
+      this.reloadview()
+    } 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()
+    }
+  }
+
+  /**
+   * @description 琛ㄥ崟鎿嶄綔瀹屾垚鍚庡埛鏂颁富椤甸潰
+   */
+  refreshbyformtab = (type) => {
+    this.setState({
+      view: 'commontable',
+      tabBtn: null,
+      tabParam: null
+    }, () => {
+      if (type === 'grid') {
+        this.reloadtable()
+      } else if (type === 'view') {
+        this.reloadview()
+      }
+    })
+  }
+
+  /**
+   * @description 瀛愯〃鎿嶄綔瀹屾垚鍚庡埛鏂颁富琛�
+   */
+  handleMainTable = (type, tab) => {
+    if (type === 'maingrid' && tab.supMenu === 'mainTable') {
+      this.reloadtable()
+    } else if (type === 'maingrid' && tab.supMenu) {
+      this.setState({
+        refreshtabs: [tab.supMenu]
+      }, () => {
+        this.setState({
+          refreshtabs: null
+        })
+      })
+    } else if (type === 'equaltab' && tab.equalTab && tab.equalTab.length > 0) {
+      this.setState({
+        refreshtabs: tab.equalTab
+      }, () => {
+        this.setState({
+          refreshtabs: null
+        })
+      })
+    }
+  }
+
+  /**
+   * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
+   */
+  getexceloutparam = () => {
+    const { MenuName } = this.props
+    const { arr_field, orderBy, search, setting} = this.state
+
+    return {
+      arr_field: arr_field,
+      orderBy: orderBy || setting.order,
+      search: search,
+      menuName: MenuName
+    }
+  }
+
+  /**
+   * @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, data) => {
+    const { BIDs } = this.state
+
+    this.setState({
+      BIDs: {
+        ...BIDs,
+        [type]: id,
+        [type + 'data']: data
+      }
+    })
+  }
+
+  /**
+   * @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) => {
+    const { setting } = this.state
+
+    let _primaryId = ''
+
+    if (data && data[0] && setting.primaryKey) {
+      _primaryId = data[0][setting.primaryKey] || ''
+    }
+
+    if (btn.OpenType === 'popview') {
+      this.setState({
+        popAction: btn,
+        popData: 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: {
+          parentId: this.props.MenuID,
+          btn: btn,
+          data: data[0] || null,
+          primaryId: btn.Ot !== 'notRequired' ? _primaryId : '',
+          arr_field: this.state.arr_field
+        }
+      }
+
+      let index = 0
+      let isexit = false
+      let tabs = tabviews.map((tab, i) => {
+        tab.selected = false
+
+        if (tab.MenuID === MenuID) {
+          index = i
+        } else if (tab.MenuID === btn.uuid) {
+          tab.selected = true
+          isexit = true
+        }
+
+        return tab
+      })
+
+      if (!isexit) {
+        tabs.splice(index + 1, 0, newtab)
+      }
+
+      this.props.modifyTabview(tabs)
+    } else if (btn.OpenType === 'blank') {
+      this.setState({
+        view: 'formtab',
+        tabBtn: btn,
+        tabParam: {
+          btn: btn,
+          data: data[0] || null,
+          primaryId: btn.Ot !== 'notRequired' ? _primaryId : '',
+          arr_field: this.state.arr_field
+        }
+      })
+    }
+  }
+
+  popclose = () => {
+    this.setState({
+      visible: false
+    })
+    this.refreshbyaction(this.state.popAction, 'pop')
+  }
+
+  handleviewconfig = (e) => {
+    e.stopPropagation()
+
+    const { MenuNo } = this.props
+    const { config } = this.state
+
+    if (config && config.funcs && config.funcs.length > 0) {
+      this.setState({
+        treevisible: true
+      })
+    } else {
+      let oInput = document.createElement('input')
+      oInput.value = MenuNo || ''
+      document.body.appendChild(oInput)
+      oInput.select()
+      document.execCommand('Copy')
+      document.body.removeChild(oInput)
+      message.success(this.state.dict['main.copy.success'])
+    }
+  }
+
+  getTreeNode = (data) => {
+    let _type = {
+      view: '椤甸潰',
+      btn: '鎸夐挳',
+      tab: '鏍囩'
+    }
+
+    return data.map(item => {
+      let _title = _type[item.subtype]
+      let _others = []
+
+      _others.push(
+        (item.menuNo ? item.menuNo + '(鑿滃崟鍙傛暟)' : ''),
+        (item.tableName ? item.tableName + '(琛ㄥ悕) ' : ''),
+        (item.innerFunc ? item.innerFunc + '(鍐呴儴鍑芥暟) ' : ''),
+        (item.outerFunc ? item.outerFunc + '(澶栭儴鍑芥暟)' : '')
+      )
+      _others = _others.filter(Boolean)
+      _others = _others.join('銆�')
+
+      if (item.label) {
+        _title = _title + '(' + item.label + ')'
+      }
+      if (_others) {
+        _title = _title + ': ' + _others
+      }
+
+      if (item.subfuncs && item.subfuncs.length > 0) {
+        return (
+          <TreeNode title={_title} key={item.uuid} dataRef={item} selectable={false}>
+            {this.getTreeNode(item.subfuncs)}
+          </TreeNode>
+        )
+      }
+      return <TreeNode key={item.uuid} title={_title} isLeaf selectable={false} />
+    })
+  }
+
+  UNSAFE_componentWillMount () {
+    // 缁勪欢鍔犺浇鏃讹紝鑾峰彇鑿滃崟鏁版嵁
+    this.loadconfig()
+  }
+
+  UNSAFE_componentWillReceiveProps(nextProps) {
+    if (nextProps.refreshTab && nextProps.refreshTab.MenuID === this.props.MenuID) {
+      if (nextProps.refreshTab.position === 'grid') {
+        this.reloadtable()
+      } else if (nextProps.refreshTab.position === 'view') {
+        this.reloadview()
+      }
+      this.props.refreshTabView('')
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  render() {
+    const { view, setting, searchlist, actions, columns, loadingview, viewlost, setsingle, pickup, isLinkMain, config } = this.state
+
+    return (
+      <div>
+        {view === 'commontable' ? <div className={'commontable ' + (isLinkMain ? 'pick-control' : '')} id={this.state.ContainerId}>
+          {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}
+              logcolumns={this.state.logcolumns}
+              ContainerId={this.state.ContainerId}
+              refreshdata={this.refreshbyaction}
+              triggerPopview={this.triggerPopview}
+              getexceloutparam={this.getexceloutparam}
+              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 (
+                      <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}
+                            refreshtabs={this.state.refreshtabs}
+                            ContainerId={this.state.ContainerId}
+                            BID={this.state.BIDs[_tab.supMenu] || ''}
+                            BData={this.state.BIDs[_tab.supMenu + 'data'] || ''}
+                            handleTableId={this.handleTableId}
+                            handleMainTable={(type) => this.handleMainTable(type, _tab)}
+                          /> : null}
+                      </TabPane>
+                    )
+                  })}
+                </Tabs>
+              )
+            })
+          }
+          <Button
+            icon="copy"
+            shape="circle"
+            className="common-table-copy"
+            onClick={this.handleviewconfig}
+          />
+          <Modal
+            className="popview-modal"
+            title={this.state.popAction.label}
+            width={'80vw'}
+            maskClosable={false}
+            visible={this.state.visible}
+            onCancel={this.popclose}
+            footer={[
+              <Button key="close" onClick={this.popclose}>{this.state.dict['main.close']}</Button>
+            ]}
+            destroyOnClose
+          >
+            {<SubTabTable 
+              BID={''}
+              SupMenuID={this.props.MenuID}
+              MenuID={this.state.popAction.linkTab}
+              BData={this.state.BIDs['mainTabledata'] || ''}
+              ContainerId={this.state.ContainerId}
+              ID={this.state.popData ? this.state.popData[setting.primaryKey] : ''}
+              refreshSupView={this.reloadtable}
+            />}
+          </Modal>
+          <Modal
+            className="menu-tree-modal"
+            title={'鑿滃崟缁撴瀯鏍�'}
+            width={'650px'}
+            maskClosable={false}
+            visible={this.state.treevisible}
+            onCancel={() => this.setState({treevisible: false})}
+            footer={[
+              <Button key="close" onClick={() => this.setState({treevisible: false})}>{this.state.dict['main.close']}</Button>
+            ]}
+            destroyOnClose
+          >
+            <div className="menu-header">
+              <span>鑿滃崟鍚嶇О锛歿this.props.MenuName}</span>
+              <span>鑿滃崟鍙傛暟锛歿<Paragraph copyable>{this.props.MenuNo}</Paragraph>}</span>
+            </div>
+            {this.state.treevisible ? <Tree defaultExpandAll showLine={true}>
+              {this.getTreeNode(config.funcs)}
+            </Tree> : null}
+          </Modal>
+          {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
+        </div> : null}
+        {view === 'formtab' ? <FormTab MenuID={this.state.tabBtn.uuid} param={this.state.tabParam} refresh={this.refreshbyformtab}/> : null}
+      </div>
+    )
+  }
+}
+
+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/managetable/index.scss b/src/tabviews/managetable/index.scss
new file mode 100644
index 0000000..847136c
--- /dev/null
+++ b/src/tabviews/managetable/index.scss
@@ -0,0 +1,109 @@
+.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-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 {
+    padding: 0px 20px;
+    margin-bottom: 20px;
+    .ant-tabs-tab:not(.ant-tabs-tab-active) {
+      cursor: pointer;
+    }
+  }
+  .common-table-copy {
+    position: fixed;
+    z-index: 2;
+    bottom: 65px;
+    right: 30px;
+    width: 40px;
+    height: 40px;
+  }
+}
+.commontable.pick-control {
+  >.button-list {
+    padding-right: 140px;
+  }
+}
+.popview-modal {
+  .ant-modal-body {
+    min-height: 300px;
+  }
+}
+.menu-tree-modal {
+  .ant-modal-body {
+    min-height: 300px;
+    .menu-header {
+      text-align: center;
+      span {
+        font-weight: 600;
+        margin-right: 20px;
+      }
+      .ant-typography {
+        font-weight: 600;
+        display: inline-block;
+      }
+    }
+    .ant-tree li .ant-tree-node-content-wrapper {
+      cursor: default;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/subtable/index.jsx b/src/tabviews/subtable/index.jsx
index 0d982b0..a86dfc6 100644
--- a/src/tabviews/subtable/index.jsx
+++ b/src/tabviews/subtable/index.jsx
@@ -288,6 +288,15 @@
     
     if (type === 'refresh') {
       _BID = bid
+      if (!bid) { // 涓昏〃ID涓嶅瓨鍦ㄦ椂锛屼笉鏌ヨ瀛愯〃
+        this.setState({
+          data: [],
+          total: 0,
+          loading: false
+        })
+
+        return
+      }
     }
 
     if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) {
diff --git a/src/tabviews/tableshare/actionList/index.jsx b/src/tabviews/tableshare/actionList/index.jsx
index d8e49b4..8d12a45 100644
--- a/src/tabviews/tableshare/actionList/index.jsx
+++ b/src/tabviews/tableshare/actionList/index.jsx
@@ -247,7 +247,14 @@
             })
 
           } else if (btn.sql && btn.sqlType === 'insert') { // 绯荤粺鍑芥暟娣诲姞鏃讹紝鐢熸垚uuid
-            param.ID = Utils.getguid()
+            primaryId = ''
+            if (formdata && setting.primaryKey) { // 琛ㄥ崟涓瓨鍦ㄤ富閿瓧娈碉紝涓婚敭鍊间互琛ㄥ崟涓殑鍊间负鍑�
+              let _form = formdata.filter(_form => _form.key === setting.primaryKey)[0]
+              if (_form) {
+                primaryId = _form.value
+              }
+            }
+            param.ID = primaryId || Utils.getguid()
             param.LText = Utils.formatOptions(Utils.getSysDefaultSql(btn, setting, formdata, param, data[0], logcolumns)) // 鏁版嵁婧�
             param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
             param.secretkey = Utils.encrypt(param.LText, param.timestamp)
@@ -268,6 +275,14 @@
           _resolve()
         })
       } else if (btn.Ot === 'required' || (btn.Ot === 'requiredOnce' && btn.OpenType === 'pop')) {
+        let _formPrimaryId = ''
+        if (formdata && setting.primaryKey) { // 琛ㄥ崟涓瓨鍦ㄤ富閿瓧娈碉紝涓婚敭鍊间互琛ㄥ崟涓殑鍊间负鍑�
+          let _form = formdata.filter(_form => _form.key === setting.primaryKey)[0]
+          if (_form) {
+            _formPrimaryId = _form.value
+          }
+        }
+
         let _params = data.map((cell, index) => {
           let param = {
             func: 'sPC_TableData_InUpDe',
@@ -303,6 +318,11 @@
               if (setting.primaryKey) {
                 param[setting.primaryKey] = primaryId
               }
+            } else if (btn.sql && btn.sqlType === 'insert') { // 绯荤粺鍑芥暟娣诲姞鏃讹紝鐢熸垚uuid
+              param.ID = _formPrimaryId || Utils.getguid()
+              param.LText = Utils.formatOptions(Utils.getSysDefaultSql(btn, setting, formdata, param, cell, logcolumns)) // 鏁版嵁婧�
+              param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+              param.secretkey = Utils.encrypt(param.LText, param.timestamp)
             } else if (btn.sql) {
               if (index !== 0) {
                 formdata = formdata.map(_data => {
diff --git a/src/templates/comtableconfig/index.jsx b/src/templates/comtableconfig/index.jsx
index 5c221c9..fb223e3 100644
--- a/src/templates/comtableconfig/index.jsx
+++ b/src/templates/comtableconfig/index.jsx
@@ -1458,6 +1458,18 @@
           duration: 10
         })
         return
+      } else if (card.OpenType === 'excelOut') {
+        let _cols = _verify.columns.map(col => col.Column)
+        let _vcols = Array.from(new Set(_cols))
+        if (_cols.length > _vcols.length) {
+          notification.warning({
+            top: 92,
+            message: 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!',
+            duration: 10
+          })
+          
+          return
+        }
       }
 
       config.action = config.action.map(item => {
diff --git a/src/templates/formtabconfig/actionform/index.jsx b/src/templates/formtabconfig/actionform/index.jsx
index a87c475..bb9b201 100644
--- a/src/templates/formtabconfig/actionform/index.jsx
+++ b/src/templates/formtabconfig/actionform/index.jsx
@@ -388,7 +388,6 @@
     return new Promise((resolve, reject) => {
       this.props.form.validateFieldsAndScroll((err, values) => {
         if (!err) {
-          values.id = this.props.card.id
           values.uuid = this.props.card.uuid
           values.verify = this.props.card.verify || null
           values.btnType = this.props.card.btnType || 'tabFormBtn'
diff --git a/src/templates/formtabconfig/index.jsx b/src/templates/formtabconfig/index.jsx
index 27bb489..ebde15e 100644
--- a/src/templates/formtabconfig/index.jsx
+++ b/src/templates/formtabconfig/index.jsx
@@ -2229,7 +2229,7 @@
             </Card>
           </div>
         </DndProvider>
-        {/* 缂栬緫鎼滅储鏉′欢 */}
+        {/* 缂栬緫琛ㄥ崟 */}
         <Modal
           title={this.state.dict['header.modal.form.edit']}
           visible={modaltype === 'search'}
diff --git a/src/templates/formtabconfig/source.jsx b/src/templates/formtabconfig/source.jsx
index 568c66d..35f47b0 100644
--- a/src/templates/formtabconfig/source.jsx
+++ b/src/templates/formtabconfig/source.jsx
@@ -84,7 +84,7 @@
         errorTime: 15,
         OpenType: 'exec',
         icon: '',
-        class: 'green',
+        class: 'border-primary',
         verify: null
       }, {
         btnType: 'cancel',
@@ -97,7 +97,7 @@
         pageTemplate: '',
         url: '',
         icon: '',
-        class: 'danger'
+        class: 'border-danger'
       }
     ],
     tabs: [
diff --git a/src/templates/modalconfig/index.jsx b/src/templates/modalconfig/index.jsx
index f290ca9..716b5bc 100644
--- a/src/templates/modalconfig/index.jsx
+++ b/src/templates/modalconfig/index.jsx
@@ -971,6 +971,35 @@
     })
   }
 
+  editModalCancel = () => {
+    const { config, card } = this.state
+
+    if (card.focus) {
+      let _config = null
+      if (config.groups.length > 0) {
+        let _groups = config.groups.map(group => {
+          group.sublist = group.sublist.filter(item => item.uuid !== card.uuid)
+          return group
+        })
+        _config = {...config, groups: _groups}
+      } else {
+        let _fields = config.fields.filter(item => item.uuid !== card.uuid)
+        _config = {...config, fields: _fields}
+      }
+
+      this.setState({
+        card: null,
+        config: _config,
+        visible: false
+      })
+    } else {
+      this.setState({
+        card: null,
+        visible: false
+      })
+    }
+  }
+
   render () {
     const { config } = this.state
 
@@ -1098,7 +1127,7 @@
           title={this.state.dict['header.edit']}
           visible={this.state.visible}
           width={700}
-          onCancel={() => { this.setState({ visible: false }) }}
+          onCancel={this.editModalCancel}
           onOk={this.handleSubmit}
           destroyOnClose
         >
diff --git a/src/templates/subtableconfig/index.jsx b/src/templates/subtableconfig/index.jsx
index 1b37f90..c76954e 100644
--- a/src/templates/subtableconfig/index.jsx
+++ b/src/templates/subtableconfig/index.jsx
@@ -1213,6 +1213,18 @@
           duration: 10
         })
         return
+      } else if (card.OpenType === 'excelOut') {
+        let _cols = _verify.columns.map(col => col.Column)
+        let _vcols = Array.from(new Set(_cols))
+        if (_cols.length > _vcols.length) {
+          notification.warning({
+            top: 92,
+            message: 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!',
+            duration: 10
+          })
+          
+          return
+        }
       }
 
       config.action = config.action.map(item => {
@@ -2248,6 +2260,7 @@
             dict={this.state.dict}
             card={this.state.card}
             formlist={this.state.formlist}
+            optionLibs={this.state.optionLibs}
             wrappedComponentRef={(inst) => this.searchFormRef = inst}
           />
         </Modal>
diff --git a/src/templates/tableshare/verifycard/index.jsx b/src/templates/tableshare/verifycard/index.jsx
index 358d8b4..ebc1365 100644
--- a/src/templates/tableshare/verifycard/index.jsx
+++ b/src/templates/tableshare/verifycard/index.jsx
@@ -303,14 +303,22 @@
         width: '13%',
         render: (text, record) => {
           let _text = ''
+
+          let _type = record.Type
+          if (_type && typeof(_type) === 'string') {
+            _type = parseInt(_type)
+          } else {
+            _type = 4
+          }
+
           if (record.TypeCharOne === 'n') {
-            _text = record.ModularDetailCode + Array(record.Type).join('0') + '1'
+            _text = record.ModularDetailCode + Array(_type).join('0') + '1'
           } else if (record.TypeCharOne === 'Y') {
-            _text = record.ModularDetailCode + moment().format('YYYYMMDD') + Array(record.Type).join('0') + '1'
+            _text = record.ModularDetailCode + moment().format('YYYYMMDD') + Array(_type).join('0') + '1'
           } else if (record.TypeCharOne === 'Lp') {
-            _text = Array(record.Type).join('0') + '10'
+            _text = Array(_type).join('0') + '10'
           } else if (record.TypeCharOne === 'BN') {
-            _text = moment().format('YYYYMMDD') + Array(record.Type).join('0') + '1'
+            _text = moment().format('YYYYMMDD') + Array(_type).join('0') + '1'
           }
           return _text
         }
@@ -434,14 +442,14 @@
             _fields = _LongParam.fields
           }
 
-          let _usefulfields = ['BID', 'ID', 'LoginUID', 'SessionUid', 'UserID', 'Appkey']
+          let _usefulfields = ['BID', 'ID', 'LoginUID', 'SessionUid', 'UserID', 'Appkey', 'UserName', 'FullName']
           let hasBid = false
 
           _fields.forEach(_f => {
             if (_f.field) {
               _usefulfields.push(_f.field)
             }
-            if (_f.field.toLowerCase() === 'bid') {
+            if (_f.field && _f.field.toLowerCase() === 'bid') {
               hasBid = true
             }
           })
@@ -480,7 +488,7 @@
         }
       })
     } else {
-      let _usefulfields = ['BID', 'ID', 'LoginUID', 'SessionUid', 'UserID', 'Appkey']
+      let _usefulfields = ['BID', 'ID', 'LoginUID', 'SessionUid', 'UserID', 'Appkey', 'UserName', 'FullName']
 
       if (columns && columns.length > 0 && this.props.card.Ot !== 'notRequired') {
         columns.forEach(_f => {
diff --git a/src/templates/tableshare/verifycardexcelin/columnform/index.jsx b/src/templates/tableshare/verifycardexcelin/columnform/index.jsx
index 3fc28f9..defe917 100644
--- a/src/templates/tableshare/verifycardexcelin/columnform/index.jsx
+++ b/src/templates/tableshare/verifycardexcelin/columnform/index.jsx
@@ -7,7 +7,7 @@
 class UniqueForm extends Component {
   static propTpyes = {
     dict: PropTypes.object,         // 瀛楀吀椤�
-    range: PropTypes.any,           // 瀛楀吀椤�
+    columns: PropTypes.array,       // 鍒楀悕闆嗗悎
     columnChange: PropTypes.func    // 淇敼鍑芥暟
   }
 
@@ -68,6 +68,7 @@
 
 
   handleConfirm = () => {
+    // const { columns } = this.props
     // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
     this.props.form.validateFieldsAndScroll((err, values) => {
       if (!err) {
@@ -81,10 +82,21 @@
           values.limit = ''
         }
 
+        // let _col = columns.filter(col => col.uuid !== values.uuid && col.Column === values.Column)
+        // if (_col.length > 0) {
+        //   notification.warning({
+        //     top: 92,
+        //     message: 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!',
+        //     duration: 10
+        //   })
+        //   return
+        // }
+
         this.props.columnChange(values)
         this.setState({
           editItem: null,
-          locked: false
+          locked: false,
+          type: 'Nvarchar(50)'
         })
         this.props.form.setFieldsValue({
           Column: '',
diff --git a/src/templates/tableshare/verifycardexcelin/customscript/index.jsx b/src/templates/tableshare/verifycardexcelin/customscript/index.jsx
index 599b1b7..7302369 100644
--- a/src/templates/tableshare/verifycardexcelin/customscript/index.jsx
+++ b/src/templates/tableshare/verifycardexcelin/customscript/index.jsx
@@ -8,12 +8,41 @@
 class CustomForm extends Component {
   static propTpyes = {
     dict: PropTypes.object,         // 瀛楀吀椤�
+    btn: PropTypes.object,          // 鎸夐挳淇℃伅
+    scripts: PropTypes.array,       // 鑷畾涔夎剼鏈垪琛�
+    isdefault: PropTypes.any,       // 鏄惁浣跨敤榛樿sql
     usefulfields: PropTypes.string, // 鍙敤瀛楁
     scriptsChange: PropTypes.func   // 琛ㄥ崟
   }
 
   state = {
-    editItem: null
+    editItem: null,
+    usefulfields: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const {usefulfields} = this.props
+
+    let fields = usefulfields.map(item => item.Column)
+    fields = ['BID', 'ID', ...fields]
+    fields = Array.from(new Set(fields))
+
+    this.setState({
+      usefulfields: fields.join(', ')
+    })
+  }
+
+  componentDidMount () {
+    const { btn, isdefault, usefulfields, scripts } = this.props
+
+    if (isdefault === 'false' && scripts.length === 0) {
+      let fields = usefulfields.map(col => col.Column).join(',')
+
+      this.props.form.setFieldsValue({
+        sql: `Insert into ${btn.sheet} (${fields},createuserid,createuser,createstaff,bid) 
+        Select ${fields},@userid,@username,@fullname,@BID From @${btn.sheet}`
+      })
+    }
   }
 
   edit = (record) => {
@@ -24,6 +53,19 @@
     this.props.form.setFieldsValue({
       sql: record.sql
     })
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { btn, usefulfields, scripts } = this.props
+
+    if (nextProps.isdefault ==='false' && this.props.isdefault !== nextProps.isdefault && scripts.length === 0) {
+      let fields = usefulfields.map(col => col.Column).join(',')
+
+      this.props.form.setFieldsValue({
+        sql: `Insert into ${btn.sheet} (${fields},createuserid,createuser,createstaff,bid) 
+        Select ${fields},@userid,@username,@fullname,@BID From @${btn.sheet}`
+      })
+    }
   }
 
 
@@ -76,7 +118,7 @@
   }
 
   render() {
-    const { usefulfields } = this.props
+    const { usefulfields } = this.state
     const { getFieldDecorator } = this.props.form
     const formItemLayout = {
       labelCol: {
@@ -89,14 +131,12 @@
       }
     }
 
-    let _fields = usefulfields.map(item => item.Column).join(', ')
-
     return (
       <Form {...formItemLayout} className="verify-form" id="verifycard2">
         <Row gutter={24}>
-          {_fields ? <Col span={21} className="sqlfield">
+          {usefulfields ? <Col span={21} className="sqlfield">
             <Form.Item label={'鍙敤瀛楁'}>
-              {_fields}
+              {usefulfields}
             </Form.Item>
           </Col> : null}
           <Col span={21} className="sql">
diff --git a/src/templates/tableshare/verifycardexcelin/index.jsx b/src/templates/tableshare/verifycardexcelin/index.jsx
index 5a5254a..e5b8a3e 100644
--- a/src/templates/tableshare/verifycardexcelin/index.jsx
+++ b/src/templates/tableshare/verifycardexcelin/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Tabs, Row, Col, Input, Button, Table, Popconfirm, Icon, notification, Modal, message, InputNumber } from 'antd'
+import { Form, Tabs, Row, Col, Input, Button, Table, Popconfirm, Icon, notification, Modal, message, InputNumber, Radio } from 'antd'
 
 import Utils from '@/utils/utils.js'
 
@@ -148,6 +148,7 @@
     this.setState({
       verify: {
         ..._verify,
+        default: _verify.default || 'true',
         sheet: _verify.sheet || 'Sheet1',
         range: _verify.range || 0,
         columns: _columns,
@@ -336,6 +337,15 @@
     })
   }
 
+  onOptionChange = (e, key) => {
+    const { verify } = this.state
+    let value = e.target.value
+
+    this.setState({
+      verify: {...verify, default: value}
+    })
+  }
+
   showError = (errorType) => {
     if (errorType === 'S') {
       notification.success({
@@ -413,13 +423,21 @@
                     })(<InputNumber min={0} max={100} precision={0} />)}
                   </Form.Item>
                 </Col>
+                <Col span={8}>
+                  <Form.Item label={'榛樿sql'}>
+                    <Radio.Group value={verify.default} onChange={this.onOptionChange}>
+                      <Radio value="true">鎵ц</Radio>
+                      <Radio value="false">涓嶆墽琛�</Radio>
+                    </Radio.Group>
+                  </Form.Item>
+                </Col>
               </Row>
             </Form>
           </TabPane>
           <TabPane tab="Excel鍒楄缃�" key="2x">
             <ColumnForm
               dict={this.props.dict}
-              range={verify.range}
+              columns={verify.columns}
               columnChange={this.columnChange}
               wrappedComponentRef={(inst) => this.columnForm = inst}
             />
@@ -434,8 +452,11 @@
           </TabPane>
           <TabPane tab="鑷畾涔夎剼鏈�" key="6">
             <CustomScript
-              usefulfields={verify.columns}
               dict={this.props.dict}
+              btn={this.props.card}
+              isdefault={verify.default}
+              usefulfields={verify.columns}
+              scripts={verify.scripts}
               scriptsChange={this.scriptsChange}
               wrappedComponentRef={(inst) => this.scriptsForm = inst}
             />
diff --git a/src/templates/tableshare/verifycardexcelout/columnform/index.jsx b/src/templates/tableshare/verifycardexcelout/columnform/index.jsx
index 5b89d76..94242e2 100644
--- a/src/templates/tableshare/verifycardexcelout/columnform/index.jsx
+++ b/src/templates/tableshare/verifycardexcelout/columnform/index.jsx
@@ -3,11 +3,10 @@
 import { Form, Row, Col, Button, Input, InputNumber } from 'antd'
 import './index.scss'
 
-
 class UniqueForm extends Component {
   static propTpyes = {
     dict: PropTypes.object,         // 瀛楀吀椤�
-    range: PropTypes.any,           // 瀛楀吀椤�
+    columns: PropTypes.array,       // 鍒楀悕闆嗗悎
     columnChange: PropTypes.func    // 淇敼鍑芥暟
   }
 
@@ -29,11 +28,22 @@
 
 
   handleConfirm = () => {
+    // const { columns } = this.props
     // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
     this.props.form.validateFieldsAndScroll((err, values) => {
       if (!err) {
         values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
 
+        // let _col = columns.filter(col => col.uuid !== values.uuid && col.Column === values.Column)
+        // if (_col.length > 0) {
+        //   notification.warning({
+        //     top: 92,
+        //     message: 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!',
+        //     duration: 10
+        //   })
+        //   return
+        // }
+
         this.props.columnChange(values)
         this.setState({
           editItem: null
diff --git a/src/templates/tableshare/verifycardexcelout/index.jsx b/src/templates/tableshare/verifycardexcelout/index.jsx
index 7362874..66a8e26 100644
--- a/src/templates/tableshare/verifycardexcelout/index.jsx
+++ b/src/templates/tableshare/verifycardexcelout/index.jsx
@@ -196,7 +196,6 @@
           <TabPane tab="Excel瀵煎嚭鍒�" key="1">
             <ColumnForm
               dict={this.props.dict}
-              range={verify.range}
               columnChange={this.columnChange}
               wrappedComponentRef={(inst) => this.columnForm = inst}
             />
diff --git a/src/utils/utils.js b/src/utils/utils.js
index ba0e8e1..2fa05f9 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -550,6 +550,25 @@
 
       fields = fields.join(',')
 
+      let _insert = ''
+
+      if (btn.default !== 'false') {
+        _insert = `
+        Insert into ${item.sheet} (${fields},createuserid,createuser,createstaff,bid) 
+        Select ${fields},@userid@,@username,@fullname,@BID@ From @${item.sheet}
+        `
+      }
+
+      if (btn.scripts && btn.scripts.length > 0) {
+        btn.scripts.forEach(script => {
+          if (script.status === 'false') return
+
+          _insert += `
+          ${script.sql}
+          `
+        })
+      }
+
       _sql = `declare @${item.sheet} table (${declarefields.join(',')},jskey nvarchar(50) )
       Declare @UserName nvarchar(50),@FullName nvarchar(50),@ErrorCode nvarchar(50),@retmsg nvarchar(4000)
 
@@ -559,10 +578,7 @@
       
       Insert into  @${item.sheet} (${fields},jskey)
       ${_Ltext}
-
-      Insert into ${item.sheet} (${fields},createuserid,createuser,createstaff,bid) 
-      Select ${fields},@userid@,@username,@fullname,@BID@ From @${item.sheet}
-
+      ${_insert}
       Delete @${item.sheet}
 
       aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`

--
Gitblit v1.8.0