From 24bba05db141f358bf1a8bb7213a2432c9de355e Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期五, 08 十月 2021 19:14:22 +0800
Subject: [PATCH] 2021-10-08

---
 src/index.js                                                           |   10 
 src/tabviews/custom/components/share/tabtransfer/index.jsx             |    7 
 src/menu/components/share/actioncomponent/formconfig.jsx               |   12 
 src/tabviews/custom/components/group/normal-group/index.jsx            |    7 
 src/templates/sharecomponent/actioncomponent/actionform/index.jsx      |    4 
 src/tabviews/custom/components/table/normal-table/index.jsx            |    4 
 src/tabviews/custom/components/table/edit-table/normalTable/index.jsx  |  553 ++++++++++++++++
 src/tabviews/custom/components/table/edit-table/normalTable/index.scss |  294 ++++++++
 src/tabviews/custom/components/table/edit-table/index.jsx              |  508 +++++++++++++++
 src/menu/components/share/actioncomponent/actionform/index.jsx         |    4 
 src/menu/components/table/edit-table/options.jsx                       |   55 -
 src/menu/components/table/edit-table/columns/index.scss                |   17 
 src/tabviews/custom/index.jsx                                          |   11 
 src/menu/components/table/edit-table/columns/editColumn/index.jsx      |   53 +
 src/menu/components/table/edit-table/index.jsx                         |   93 --
 src/menu/modulesource/option.jsx                                       |    2 
 src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx |   94 ++
 src/menu/components/table/edit-table/columns/index.jsx                 |  117 +--
 src/tabviews/custom/components/table/edit-table/index.scss             |   96 ++
 19 files changed, 1,712 insertions(+), 229 deletions(-)

diff --git a/src/index.js b/src/index.js
index 49328bb..3f455ef 100644
--- a/src/index.js
+++ b/src/index.js
@@ -110,9 +110,15 @@
       if (config.mainSystemApi) {
         let systemApi = config.mainSystemApi
         // 涓氬姟绯荤粺涓嶅厑璁歌繛鎺ヤ簯绔紝涓氬姟绯荤粺杩炴帴sso.mk9h.cn鏃讹紝鏁版嵁铏氬寲澶勭悊
-        if (systemApi && systemApi.indexOf('cloud.mk9h.cn') > -1) {
+        if (systemApi.indexOf('cloud.mk9h.cn') > -1) {
           systemApi = ''
-        } else if (systemApi && systemApi.indexOf('sso.mk9h.cn') > -1 && process.env.NODE_ENV === 'production') {
+        } else if (/index.html/ig.test(systemApi)) {
+          systemApi = systemApi.replace(/index.html.*/ig, 'webapi/dostars')
+        } else if (!/webapi\/dostars$/ig.test(systemApi)) {
+          systemApi = systemApi.replace(/\/?$/, '/webapi/dostars')
+        }
+
+        if (systemApi.indexOf('sso.mk9h.cn') > -1 && process.env.NODE_ENV === 'production') {
           GLOB.dataFormat = true
         }
       
diff --git a/src/menu/components/share/actioncomponent/actionform/index.jsx b/src/menu/components/share/actioncomponent/actionform/index.jsx
index 0d5c1a6..5213db6 100644
--- a/src/menu/components/share/actioncomponent/actionform/index.jsx
+++ b/src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -124,7 +124,7 @@
           } else if (['innerpage', 'tab', 'popview', 'excelIn'].includes(_opentype)) {
             item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
           } else if (card.sqlType === 'insert') {
-            item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl', 'required'].includes(op.value))
+            item.options = this.state.requireOptions.filter(op => ['notRequired'].includes(op.value))
           } else {
             item.options = this.state.requireOptions
           }
@@ -328,7 +328,7 @@
           if (item.key === 'Ot' && type === 'card') {
             item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
           } else if (item.key === 'Ot' && value === 'insert') {
-            item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl', 'required'].includes(op.value))
+            item.options = this.state.requireOptions.filter(op => ['notRequired'].includes(op.value))
           } else if (item.key === 'Ot') {
             item.options = this.state.requireOptions
           }
diff --git a/src/menu/components/share/actioncomponent/formconfig.jsx b/src/menu/components/share/actioncomponent/formconfig.jsx
index 109194f..00361d1 100644
--- a/src/menu/components/share/actioncomponent/formconfig.jsx
+++ b/src/menu/components/share/actioncomponent/formconfig.jsx
@@ -60,6 +60,18 @@
     })
   }
 
+  if (type === 'editable') {
+    opentypes = [
+      {
+        value: 'excelIn',
+        text: Formdict['model.form.excelIn']
+      }, {
+        value: 'excelOut',
+        text: Formdict['model.form.excelOut']
+      }
+    ]
+  }
+
   let tabs = getTabs(JSON.parse(JSON.stringify(modules)))
 
   let pageTemps = [
diff --git a/src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx b/src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
index 28c9fc9..c345c81 100644
--- a/src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
+++ b/src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
@@ -7,7 +7,7 @@
  * @description 鑾峰彇鏄剧ず鍒楄〃鍗曢厤缃俊鎭�
  * @param {object} card       // 鎼滅储鏉′欢瀵硅薄
  */
-export function getColumnForm (card, fields = []) {
+export function getColumnForm (card, fields = [], columns = []) {
   let roleList = sessionStorage.getItem('sysRoles')
   if (roleList) {
     try {
@@ -42,6 +42,21 @@
     value: 'index',
     text: '搴忓彿'
   }]
+
+  let editCols = [
+    {
+      field: '$next',
+      label: '涓嬩竴琛�'
+    }
+  ]
+  columns.forEach(col => {
+    if (col.editable === 'true' && col.uuid !== card.uuid) {
+      editCols.push({
+        field: col.uuid,
+        label: col.label
+      })
+    }
+  })
 
   return [
     {
@@ -125,6 +140,21 @@
     },
     {
       type: 'radio',
+      key: 'sum',
+      label: '鏄剧ず鍚堣',
+      initVal: card.sum || 'false',
+      tooltip: '鍚堣淇℃伅鍙湪浣跨敤绯荤粺鏁版嵁婧愭椂鏈夋晥銆�',
+      required: false,
+      options: [{
+        value: 'true',
+        text: Formdict['model.true']
+      }, {
+        value: 'false',
+        text: Formdict['model.false']
+      }]
+    },
+    {
+      type: 'radio',
       key: 'editable',
       label: '鍙紪杈�',
       initVal: card.editable || 'false',
@@ -138,6 +168,52 @@
       }]
     },
     {
+      type: 'radio',
+      key: 'required',
+      label: '蹇呭~',
+      initVal: card.required || 'false',
+      required: false,
+      options: [{
+        value: 'false',
+        text: '鍚�'
+      }, {
+        value: 'true',
+        text: '鏄�'
+      }]
+    },
+    {
+      type: 'text',
+      key: 'initval',
+      label: '榛樿鍊�',
+      initVal: card.initval,
+      tooltip: '浣跨敤$copy鏃讹紝琛ㄧず鏂板鏃跺鍒朵笂涓�琛屼俊鎭��',
+      required: false
+    },
+    {
+      type: 'select',
+      key: 'enter',
+      label: '鍥炶溅鍒囨崲',
+      initVal: card.enter || '$next',
+      options: editCols
+    },
+    {
+      type: 'radio',
+      key: 'footEnter',
+      label: '鏈鍥炶溅',
+      initVal: card.footEnter || 'false',
+      tooltip: '鏂板鍔熻兘浠呭湪琛ㄦ牸鍙柊澧炴椂鏈夋晥銆�',
+      options: [{
+        value: 'sub',
+        text: '鎻愪氦'
+      }, {
+        value: 'add',
+        text: '鏂板'
+      }, {
+        value: 'false',
+        text: '鏃犲姩浣�'
+      }]
+    },
+    {
       type: 'number',
       key: 'decimal',
       min: 0,
@@ -148,6 +224,22 @@
       required: true
     },
     {
+      type: 'number',
+      key: 'max',
+      label: '鏈�澶у��',
+      initVal: card.max,
+      unlimit: true,
+      required: false
+    },
+    {
+      type: 'number',
+      key: 'min',
+      label: '鏈�灏忓��',
+      initVal: card.min,
+      unlimit: true,
+      required: false
+    },
+    {
       type: 'select',
       key: 'format',
       label: Formdict['header.form.format'],
diff --git a/src/menu/components/table/edit-table/columns/editColumn/index.jsx b/src/menu/components/table/edit-table/columns/editColumn/index.jsx
index 10a6f8c..17cfbda 100644
--- a/src/menu/components/table/edit-table/columns/editColumn/index.jsx
+++ b/src/menu/components/table/edit-table/columns/editColumn/index.jsx
@@ -9,7 +9,7 @@
 
 const columnTypeOptions = {
   text: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'textFormat', 'editable', 'blacklist'],
-  number: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'decimal', 'format', 'prefix', 'postfix', 'editable', 'blacklist'],
+  number: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'decimal', 'format', 'prefix', 'postfix', 'editable', 'sum', 'blacklist'],
   textarea: ['label', 'field', 'type', 'Align', 'Hide', 'Width', 'prefix', 'postfix', 'blacklist'],
   custom: ['label', 'type', 'Align', 'Hide', 'Width', 'blacklist'],
   action: ['label', 'type', 'Align', 'Width'],
@@ -21,6 +21,7 @@
     dict: PropTypes.object,     // 瀛楀吀椤�
     visible: PropTypes.bool,
     column: PropTypes.object,
+    columns: PropTypes.array,
     fields: PropTypes.array,
     submitCol: PropTypes.func,  // 鎻愪氦浜嬩欢
     cancelCol: PropTypes.func   // 鍙栨秷鏃跺垹闄や簨浠�
@@ -38,8 +39,16 @@
   }
 
   editColumn = (column) => {
-    let formlist = getColumnForm(column, this.props.fields)
+    let formlist = getColumnForm(column, this.props.fields, this.props.columns)
     let _options = fromJS(columnTypeOptions[column.type]).toJS()
+
+    if (column.editable === 'true') {
+      if (column.type === 'text') {
+        _options.push('required', 'initval', 'enter', 'footEnter')
+      } else if (column.type === 'number') {
+        _options.push('max', 'min', 'initval', 'enter', 'footEnter')
+      }
+    }
 
     this.setState({
       visible: true,
@@ -63,12 +72,24 @@
   }
 
   typeChange = (key, value, option) => {
+    const { editable, type } = this.state
     if (key === 'type') {
       let _options = fromJS(columnTypeOptions[value]).toJS()
+
+      if (editable === 'true') {
+        if (value === 'text') {
+          _options.push('required', 'initval', 'enter', 'footEnter')
+        } else if (value === 'number') {
+          _options.push('max', 'min', 'initval', 'enter', 'footEnter')
+        }
+      }
 
       this.setState({
         type: value,
         formlist: this.state.formlist.map(item => {
+          if (item.key === 'editable') {
+            item.initVal = editable
+          }
           item.hidden = !_options.includes(item.key)
 
           return item
@@ -94,9 +115,20 @@
       if (values.type !== this.state.type) {
         let _options = fromJS(columnTypeOptions[values.type]).toJS()
 
+        if (editable === 'true') {
+          if (values.type === 'text') {
+            _options.push('required', 'initval', 'enter', 'footEnter')
+          } else if (values.type === 'number') {
+            _options.push('max', 'min', 'initval', 'enter', 'footEnter')
+          }
+        }
+
         this.setState({
           type: values.type,
           formlist: this.state.formlist.map(item => {
+            if (item.key === 'editable') {
+              item.initVal = editable
+            }
             item.hidden = !_options.includes(item.key)
 
             return item
@@ -110,7 +142,24 @@
     } else if (key === 'format' && value === 'percent') {
       this.props.form.setFieldsValue({postfix: '%'})
     } else if (key === 'editable') {
+      let _options = fromJS(columnTypeOptions[type]).toJS()
 
+      if (value === 'true') {
+        if (type === 'text') {
+          _options.push('required', 'initval', 'enter', 'footEnter')
+        } else if (type === 'number') {
+          _options.push('max', 'min', 'initval', 'enter', 'footEnter')
+        }
+      }
+
+      this.setState({
+        editable: value,
+        formlist: this.state.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
+
+          return item
+        })
+      })
     }
   }
 
diff --git a/src/menu/components/table/edit-table/columns/index.jsx b/src/menu/components/table/edit-table/columns/index.jsx
index 05b9c7b..639a389 100644
--- a/src/menu/components/table/edit-table/columns/index.jsx
+++ b/src/menu/components/table/edit-table/columns/index.jsx
@@ -51,44 +51,23 @@
   render() {
     const { connectDragSource, connectDropTarget, moveCol, addElement, updateCol, editColumn, changeStyle, deleteCol, index, column, align, fields, children, ...restProps } = this.props
 
-    if (index !== undefined) {
-      return connectDragSource(
-        connectDropTarget(<th {...restProps} index={index} style={{ cursor: 'move', textAlign: align }} onDoubleClick={() => column && this.props.editColumn(column)}>
-          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
-            <div className="mk-popover-control">
-              {column && ['custom', 'action'].includes(column.type) ?
-                <Icon className="plus" title="娣诲姞" type="plus" onClick={() => this.props.addElement(column)} /> : null
-              }
-              <Icon className="edit" title="缂栬緫" type="edit" onClick={() => this.props.editColumn(column)} />
-              {column && column.type === 'custom' ? <Icon className="style" title="璋冩暣鏍峰紡" onClick={() => this.props.changeStyle(column)} type="font-colors" /> : null}
-              <Icon className="close" title="鍒犻櫎" type="delete" onClick={this.deleteCol} />
-              {column && ['text', 'number'].includes(column.type) ? <MarkColumn columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
-            </div>
-          } trigger="hover">
-            {children}
-          </Popover>
-        </th>),
-      )
-    } else if (column) {
-      return (
-        <th {...restProps} key={column.uuid} onDoubleClick={() => this.props.editColumn(column)}>
-          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
-            <div className="mk-popover-control">
-              {column && ['custom'].includes(column.type) ?
-                <Icon className="plus" title="娣诲姞" type="plus" onClick={() => this.props.addElement(column)} /> : null
-              }
-              <Icon className="edit" title="缂栬緫" type="edit" onClick={() => this.props.editColumn(column)} />
-              <Icon className="close" title="鍒犻櫎" type="delete" onClick={this.deleteCol} />
-              {column && ['text', 'number'].includes(column.type) ? <MarkColumn columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
-            </div>
-          } trigger="hover">
-            {children}
-          </Popover>
-        </th>
-      )
-    } else {
-      return (<th {...restProps}>{children}</th>)
-    }
+    return connectDragSource(
+      connectDropTarget(<th {...restProps} index={index} style={{ cursor: 'move', textAlign: align }} onDoubleClick={() => column && this.props.editColumn(column)}>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            {column && ['custom', 'action'].includes(column.type) ?
+              <Icon className="plus" title="娣诲姞" type="plus" onClick={() => this.props.addElement(column)} /> : null
+            }
+            <Icon className="edit" title="缂栬緫" type="edit" onClick={() => this.props.editColumn(column)} />
+            {column && column.type === 'custom' ? <Icon className="style" title="璋冩暣鏍峰紡" onClick={() => this.props.changeStyle(column)} type="font-colors" /> : null}
+            <Icon className="close" title="鍒犻櫎" type="delete" onClick={this.deleteCol} />
+            {column && ['text', 'number'].includes(column.type) ? <MarkColumn columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
+          </div>
+        } trigger="hover">
+          {children}
+        </Popover>
+      </th>),
+    )
   }
 }
 
@@ -416,36 +395,6 @@
     document.body.removeChild(oInput)
   }
 
-  handlecolumns = (columns, fields, config, isSub) => {
-    return columns.map((col, index) => {
-      return {
-        title: col.label,
-        dataIndex: col.uuid,
-        align: col.Align,
-        sorter: !isSub && col.IsSort === 'true',
-        onCell: () => ({
-          column: col,
-          width: col.Width,
-          config: config,
-          upComponent: this.updateCol
-        }),
-        onHeaderCell: () => ({
-          index: isSub ? undefined : index,
-          column: col,
-          fields: fields,
-          align: col.Align,
-          moveCol: this.moveCol,
-          updateCol: this.updateCol,
-          addElement: this.addElement,
-          editColumn: this.editColumn,
-          changeStyle: this.changeStyle,
-          deleteCol: this.deleteCol,
-        }),
-        children: col.subcols && col.subcols.length ? this.handlecolumns(col.subcols, fields, config, true) : null,
-      }
-    })
-  }
-
   syncfield = () => {
     const { fields } = this.state
     let columns = fromJS(this.state.columns).toJS()
@@ -526,7 +475,32 @@
       }
     }
 
-    const columns = this.handlecolumns(this.state.columns, fields, config)
+    const columns = this.state.columns.map((col, index) => {
+      return {
+        title: col.label,
+        dataIndex: col.uuid,
+        align: col.Align,
+        sorter: col.IsSort === 'true',
+        onCell: () => ({
+          column: col,
+          width: col.Width,
+          config: config,
+          upComponent: this.updateCol
+        }),
+        onHeaderCell: () => ({
+          index,
+          column: col,
+          fields: fields,
+          align: col.Align,
+          moveCol: this.moveCol,
+          updateCol: this.updateCol,
+          addElement: this.addElement,
+          editColumn: this.editColumn,
+          changeStyle: this.changeStyle,
+          deleteCol: this.deleteCol,
+        }),
+      }
+    })
 
     let style = {}
     if (config.wrap.color) {
@@ -537,7 +511,7 @@
     }
 
     return (
-      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''}`} id={tableId}>
+      <div className={`edit-table-columns ${config.setting.laypage} ${config.wrap.mode || ''}`} id={tableId}>
         <div className="col-control">
           <Icon title="澶嶅埗鏄剧ず鍒�" type="copy" onClick={this.copycolumn} />
           <MarkColumn columns={fields} type="line" marks={lineMarks} onSubmit={this.updateLineMarks} />
@@ -553,7 +527,6 @@
             bordered={config.wrap.bordered !== 'false'}
             components={components}
             dataSource={this.state.data}
-            rowSelection={config.wrap.tableType ? { type: 'radio' } : null}
             columns={columns}
             pagination={{
               current: 1,
@@ -565,7 +538,7 @@
             }}
           />
         </DndProvider>
-        <EditColumn column={card} dict={dict} fields={fields} submitCol={this.submitCol} cancelCol={this.cancelCol}/>
+        <EditColumn column={card} dict={dict} columns={this.state.columns} fields={fields} submitCol={this.submitCol} cancelCol={this.cancelCol}/>
       </div>
     )
   }
diff --git a/src/menu/components/table/edit-table/columns/index.scss b/src/menu/components/table/edit-table/columns/index.scss
index f376b55..87fdab7 100644
--- a/src/menu/components/table/edit-table/columns/index.scss
+++ b/src/menu/components/table/edit-table/columns/index.scss
@@ -1,4 +1,4 @@
-.normal-table-columns {
+.edit-table-columns {
   position: relative;
   .ant-table {
     color: inherit;
@@ -80,24 +80,13 @@
     margin: 0;
   }
 }
-.normal-table-columns.false {
+.edit-table-columns.false {
   .ant-pagination {
     display: none;
   }
 }
-.normal-table-columns.checkbox {
-  .ant-radio-inner {
-    border-radius: 0;
-  }
-  .ant-radio-inner::after {
-    border-radius: 0;
-  }
-  .ant-radio-checked::after {
-    border-radius: 0;
-  }
-}
 
-.normal-table-columns.ghost {
+.edit-table-columns.ghost {
   .ant-table-thead > tr {
     > th {
       color: inherit;
diff --git a/src/menu/components/table/edit-table/index.jsx b/src/menu/components/table/edit-table/index.jsx
index 00d7aac..4a6b04d 100644
--- a/src/menu/components/table/edit-table/index.jsx
+++ b/src/menu/components/table/edit-table/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Icon, Popover, notification } from 'antd'
+import { Icon, Popover } from 'antd'
 
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
@@ -22,7 +22,6 @@
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
 const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
 const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
-const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
 const ColumnComponent = asyncComponent(() => import('./columns'))
 
 class TableCardEditComponent extends Component {
@@ -51,15 +50,15 @@
         parentId: card.parentId || '',
         format: 'array',    // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
         pageable: true,     // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
-        switchable: true,   // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        switchable: false,  // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
         dataName: card.dataName || '',
         width: card.width || 24,
         search: [],
         action: [],
         name: card.name,
         subtype: card.subtype,
-        setting: { interType: 'system' },
-        wrap: { name: card.name, width: card.width || 24, bordered: 'true', tableType: 'checkbox', show: 'true' },
+        setting: { interType: 'system', laypage: 'false' },
+        wrap: { name: card.name, width: card.width || 24, bordered: 'true', show: 'true' },
         style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px' },
         headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
         columns: [],
@@ -94,9 +93,7 @@
         })
         _card.cols = config.cols.map(col => {
           col.uuid = Utils.getuuid()
-          if (col.type === 'colspan' && col.subcols) {
-            col = this.loopCol(col)
-          } else if (col.type === 'custom' && col.elements) {
+          if (col.type === 'custom' && col.elements) {
             col.elements = col.elements.map(cell => {
               cell.uuid = Utils.getuuid()
               return cell
@@ -130,7 +127,6 @@
   componentDidMount () {
     MKEmitter.addListener('submitStyle', this.getStyle)
     MKEmitter.addListener('submitModal', this.handleSave)
-    MKEmitter.addListener('logButton', this.logButton)
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -146,31 +142,11 @@
     }
     MKEmitter.removeListener('submitStyle', this.getStyle)
     MKEmitter.removeListener('submitModal', this.handleSave)
-    MKEmitter.removeListener('logButton', this.logButton)
-  }
-
-  loopCol = (col) => {
-    col.subcols = col.subcols.map(c => {
-      c.uuid = Utils.getuuid()
-      if (c.type === 'colspan' && c.subcols) {
-        c = this.loopCol(c)
-      } else if (c.type === 'custom' && c.elements) {
-        c.elements = c.elements.map(cell => {
-          cell.uuid = Utils.getuuid()
-          return cell
-        })
-      }
-      return c
-    })
-
-    return col
   }
 
   filterOrigin = (component) => {
     if (component.isNew) {
       let item = fromJS(component).toJS()
-      item.search = item.search.filter(a => !a.origin)
-      item.action = item.action.filter(a => !a.origin)
       item.cols = item.cols.filter(a => !a.origin)
 
       delete item.isNew
@@ -193,20 +169,6 @@
     component.name = component.wrap.name
 
     this.filterOrigin(component)
-  }
-
-  logButton = (id, item) => {
-    const { card } = this.state
-
-    if (id !== card.uuid) return
-
-    let btnlog = card.btnlog || []
-    btnlog.push(item)
-
-    this.setState({
-      card: {...card, btnlog}
-    })
-    this.filterOrigin({...card, btnlog})
   }
 
   changeStyle = () => {
@@ -260,7 +222,7 @@
     newcard.label = 'label'
     newcard.sqlType = ''
     newcard.Ot = 'requiredSgl'
-    newcard.OpenType = 'pop'
+    newcard.OpenType = 'excelIn'
     newcard.icon = ''
     newcard.class = 'green'
     newcard.intertype = card.setting.interType || 'system'
@@ -328,46 +290,6 @@
     this.filterOrigin(card)
   }
 
-  handleLog = (type, logs, item) => {
-    let card = fromJS(this.state.card).toJS()
-
-    if (type === 'revert') {
-      let done = false
-      if (item.$parentId) {
-        card.cols.forEach(col => {
-          if (col.type !== 'action') return
-          if (item.$parentId === col.uuid) {
-            col.elements = col.elements ? [...col.elements, item] : [item]
-            done = true
-          }
-        })
-      }
-
-      if (!done) {
-        card.action = card.action ? [...card.action, item] : [item]
-      }
-
-      card.btnlog = logs
-
-      this.setState({ card })
-      this.filterOrigin(card)
-      notification.success({
-        top: 92,
-        message: '鎭㈠鎴愬姛锛�',
-        duration: 2
-      })
-    } else {
-      card.btnlog = logs
-      this.setState({ card })
-      this.filterOrigin(card)
-      notification.success({
-        top: 92,
-        message: '娓呴櫎鎴愬姛锛�',
-        duration: 2
-      })
-    }
-  }
-
   getWrapForms = () => {
     const { wrap, action } = this.state.card
 
@@ -403,7 +325,6 @@
             <CopyComponent type="normaltable" card={card}/>
             <PasteComponent config={card} options={['action', 'search', 'form', 'cols']} updateConfig={this.updateComponent} />
             <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
-            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
             <UserComponent config={card}/>
             <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
             <SettingComponent config={card} updateConfig={this.updateComponent} />
@@ -412,7 +333,7 @@
           <Icon type="tool" />
         </Popover>
         <SearchComponent config={card} updatesearch={this.updateconfig}/>
-        <ActionComponent config={card} setSubConfig={this.setSubConfig} updateaction={this.updateComponent}/>
+        <ActionComponent type="editable" config={card} setSubConfig={this.setSubConfig} updateaction={this.updateComponent}/>
         <ColumnComponent config={card} updatecolumn={this.updateconfig}/>
       </div>
     )
diff --git a/src/menu/components/table/edit-table/options.jsx b/src/menu/components/table/edit-table/options.jsx
index acfc1be..69d7d70 100644
--- a/src/menu/components/table/edit-table/options.jsx
+++ b/src/menu/components/table/edit-table/options.jsx
@@ -33,21 +33,6 @@
     },
     {
       type: 'radio',
-      field: 'tableType',
-      label: '琛ㄦ牸灞炴��',
-      initval: wrap.tableType,
-      required: false,
-      options: [
-        {value: '', label: '涓嶅彲閫�'},
-        {value: 'radio', label: '鍗曢��'},
-        {value: 'checkbox', label: '澶氶��'},
-      ],
-      controlFields: [
-        {field: 'selected', values: ['radio', 'checkbox']},
-      ]
-    },
-    {
-      type: 'radio',
       field: 'bordered',
       label: '杈规',
       initval: wrap.bordered || 'true',
@@ -95,18 +80,6 @@
     },
     {
       type: 'radio',
-      field: 'selected',
-      label: '棣栬閫変腑',
-      initval: wrap.selected || 'false',
-      required: false,
-      options: [
-        {value: 'false', label: '鏃�'},
-        {value: 'init', label: '鍒濆鍖�'},
-        {value: 'always', label: '鏁版嵁鍔犺浇'},
-      ]
-    },
-    {
-      type: 'radio',
       field: 'show',
       label: '鎼滅储鎸夐挳',
       initval: wrap.show || 'true',
@@ -115,6 +88,17 @@
       options: [
         {value: 'true', label: '鏄剧ず'},
         {value: 'false', label: '闅愯棌'},
+      ]
+    },
+    {
+      type: 'radio',
+      field: 'addable',
+      label: '鍙柊澧�',
+      initval: wrap.addable || 'false',
+      required: false,
+      options: [
+        {value: 'true', label: '鏄�'},
+        {value: 'false', label: '鍚�'},
       ]
     },
     {
@@ -163,8 +147,7 @@
       min: 10,
       max: 3000,
       precision: 0,
-      required: false,
-      forbid: appType === 'mob'
+      required: false
     },
     {
       type: 'number',
@@ -175,19 +158,7 @@
       min: 10,
       max: 3000,
       precision: 0,
-      required: false,
-      forbid: appType === 'mob'
-    },
-    {
-      type: 'select',
-      field: 'doubleClick',
-      label: '鍙屽嚮浜嬩欢',
-      initval: wrap.doubleClick || '',
-      tooltip: '鍙屽嚮琛ㄦ牸涓锛岃Е鍙戠殑鎸夐挳銆�',
-      required: false,
-      allowClear: true,
-      options: action.map(item => ({value: item.uuid, label: item.label})),
-      forbid: appType === 'mob'
+      required: false
     },
     {
       type: 'multiselect',
diff --git a/src/menu/modulesource/option.jsx b/src/menu/modulesource/option.jsx
index 55bebce..3bfa429 100644
--- a/src/menu/modulesource/option.jsx
+++ b/src/menu/modulesource/option.jsx
@@ -36,7 +36,7 @@
   { type: 'menu', url: Carousel, component: 'carousel', subtype: 'datacard', title: '杞挱-鍔ㄦ�佹暟鎹�', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: Carousel1, component: 'carousel', subtype: 'propcard', title: '杞挱-闈欐�佹暟鎹�', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '甯哥敤琛�', width: 24 },
-  // { type: 'menu', url: NormalTable, component: 'table', subtype: 'editable', title: '琛ㄦ牸锛堝彲缂栬緫锛�', width: 24 },
+  { type: 'menu', url: NormalTable, component: 'table', subtype: 'editable', title: '琛ㄦ牸锛堝彲缂栬緫锛�', width: 24 },
   { type: 'menu', url: TableCard, component: 'table', subtype: 'tablecard', title: '琛ㄦ牸锛堝崱鐗囷級', width: 12 },
   { type: 'menu', url: tree, component: 'tree', subtype: 'normaltree', title: '鏍戝舰鍒楄〃', width: 12 },
   { type: 'menu', url: line, component: 'line', subtype: 'line', title: '鎶樼嚎鍥�', width: 24 },
diff --git a/src/tabviews/custom/components/group/normal-group/index.jsx b/src/tabviews/custom/components/group/normal-group/index.jsx
index 63406b5..0840e45 100644
--- a/src/tabviews/custom/components/group/normal-group/index.jsx
+++ b/src/tabviews/custom/components/group/normal-group/index.jsx
@@ -21,6 +21,7 @@
 const DataCard = asyncComponent(() => import('@/tabviews/custom/components/card/data-card'))
 const TableCard = asyncComponent(() => import('@/tabviews/custom/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/tabviews/custom/components/table/normal-table'))
+const EditTable = asyncComponent(() => import('@/tabviews/custom/components/table/edit-table'))
 const PropCard = asyncComponent(() => import('@/tabviews/custom/components/card/prop-card'))
 const BraftEditor = asyncComponent(() => import('@/tabviews/custom/components/editor/braft-editor'))
 const SandBox = asyncComponent(() => import('@/tabviews/custom/components/code/sand-box'))
@@ -213,6 +214,12 @@
             <NormalTable config={item} data={data} BID={_bid} BData={BData} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'table' && item.subtype === 'editable') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <EditTable config={item} data={data} BID={_bid} BData={BData} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else if (item.type === 'tree') {
         return (
           <Col span={item.width} key={item.uuid}>
diff --git a/src/tabviews/custom/components/share/tabtransfer/index.jsx b/src/tabviews/custom/components/share/tabtransfer/index.jsx
index b74700f..24afb5d 100644
--- a/src/tabviews/custom/components/share/tabtransfer/index.jsx
+++ b/src/tabviews/custom/components/share/tabtransfer/index.jsx
@@ -23,6 +23,7 @@
 const AntvScatter = asyncComponent(() => import('@/tabviews/custom/components/chart/antv-scatter'))
 const TableCard = asyncComponent(() => import('@/tabviews/custom/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/tabviews/custom/components/table/normal-table'))
+const EditTable = asyncComponent(() => import('@/tabviews/custom/components/table/edit-table'))
 const PropCard = asyncComponent(() => import('@/tabviews/custom/components/card/prop-card'))
 const NormalGroup = asyncComponent(() => import('@/tabviews/custom/components/group/normal-group'))
 const BraftEditor = asyncComponent(() => import('@/tabviews/custom/components/editor/braft-editor'))
@@ -235,6 +236,12 @@
             <NormalTable config={item} data={data} BID={BID} BData={BData} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'table' && item.subtype === 'editable') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <EditTable config={item} data={data} BID={BID} BData={BData} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else if (item.type === 'group' && item.subtype === 'normalgroup') {
         return (
           <Col span={item.width} key={item.uuid}>
diff --git a/src/tabviews/custom/components/table/edit-table/index.jsx b/src/tabviews/custom/components/table/edit-table/index.jsx
new file mode 100644
index 0000000..8080bbc
--- /dev/null
+++ b/src/tabviews/custom/components/table/edit-table/index.jsx
@@ -0,0 +1,508 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import {connect} from 'react-redux'
+import { is, fromJS } from 'immutable'
+import { notification } from 'antd'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/main.js'
+import enUS from '@/locales/en-US/main.js'
+import UtilsDM from '@/utils/utils-datamanage.js'
+import asyncComponent from '@/utils/asyncComponent'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+// 閫氱敤缁勪欢
+const MainSearch = asyncComponent(() => import('@/tabviews/zshare/topSearch'))
+const MainAction = asyncComponent(() => import('@/tabviews/zshare/actionList'))
+const MainTable = asyncComponent(() => import('./normalTable'))
+const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader'))
+
+class EditableTable extends Component {
+  static propTpyes = {
+    BID: PropTypes.any,              // 鐖剁骇Id
+    data: PropTypes.array,           // 缁熶竴鏌ヨ鏁版嵁
+    config: PropTypes.object,        // 缁勪欢閰嶇疆淇℃伅
+    mainSearch: PropTypes.any,       // 澶栧眰鎼滅储鏉′欢
+    menuType: PropTypes.any,         // 鑿滃崟绫诲瀷
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    BID: '',              // 涓婄骇ID
+    BData: '',            // 涓婄骇缁勪欢琛屾暟鎹�
+    config: {},           // 椤甸潰閰嶇疆淇℃伅锛屽寘鎷寜閽�佹悳绱€�佹樉绀哄垪銆佹爣绛剧瓑
+    searchlist: null,     // 鎼滅储鏉′欢
+    actions: null,        // 鎸夐挳闆�
+    columns: null,        // 鏄剧ず鍒�
+    arr_field: '',        // 浣跨敤 sPC_Get_TableData 鏃剁殑鏌ヨ瀛楁闆�
+    setting: null,        // 椤甸潰鍏ㄥ眬璁剧疆锛氭暟鎹簮銆佹寜閽強鏄剧ず鍒楀浐瀹氥�佷富閿瓑
+    data: [],             // 鍒楄〃鏁版嵁闆�
+    total: 0,             // 鎬绘暟
+    loading: false,       // 鍒楄〃鏁版嵁鍔犺浇涓�
+    pageIndex: 1,         // 椤电爜
+    pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
+    orderBy: '',          // 鎺掑簭
+    search: '',           // 鎼滅储鏉′欢鏁扮粍锛屼娇鐢ㄦ椂闇�鍒嗗満鏅鐞�
+    statFValue: []        // 鍚堣鍊�
+  }
+
+  /**
+   * @description 鍒濆鍖栧鐞�
+   * 1銆� initdata 涓烘墦鍗版椂浣跨敤鐨勬暟鎹泦
+   */
+  UNSAFE_componentWillMount () {
+    const { data, initdata, BID, BData } = this.props
+    let _config = fromJS(this.props.config).toJS()
+    let _cols = new Map()
+    let _data = null
+    let _sync = _config.setting.sync === 'true'
+    let setting = {..._config.setting, ..._config.wrap, style: {}}
+
+    if (_config.setting.sync === 'true' && data) {
+      _data = data[_config.dataName] || []
+      _sync = false
+    } else if (_config.setting.sync === 'true' && initdata) {
+      _data = initdata || []
+      _sync = false
+    }
+
+    if (_data) {
+      _data = _data.map((item, index) => {
+        item.key = index
+        item.$$uuid = item[_config.setting.primaryKey] || ''
+        item.$$BID = BID || ''
+        item.$$BData = BData || ''
+        item.$Index = index + 1 + ''
+        return item
+      })
+    }
+
+    _config.columns.forEach(item => {
+      _cols.set(item.field, item)
+    })
+
+    _config.cols.forEach(column => {
+      if (column.type === 'custom') {
+        column.elements = column.elements.map(item => {
+          if (item.field && _cols.has(item.field)) {
+            item.col = _cols.get(item.field)
+          }
+          return item
+        })
+      } else if (column.type === 'action') {
+        column.operations = column.elements
+      }
+    })
+
+    if (setting.color) {
+      setting.style.color = setting.color
+    }
+    if (setting.fontSize) {
+      setting.style.fontSize = setting.fontSize
+    }
+
+    if (!_config.lineMarks || _config.lineMarks.length === 0) {
+      _config.lineMarks = null
+    }
+
+    this.setState({
+      BID: BID || '',
+      BData: BData || '',
+      title: _config.wrap.title,
+      sync: _sync,
+      data: _data,
+      config: _config,
+      setting: setting,
+      searchlist: _config.search,
+      actions: _config.action,
+      columns: _config.cols,
+      arr_field: _config.columns.map(col => col.field).join(','),
+      search: Utils.initMainSearch(_config.search) // 鎼滅储鏉′欢鍒濆鍖栵紙鍚湁鏃堕棿鏍煎紡锛岄渶瑕佽浆鍖栵級
+    }, () => {
+      if (_config.setting.sync !== 'true' && _config.setting.onload === 'true') {
+        this.loadmaindata()
+        this.getStatFieldsValue()
+      } else if (_config.setting.onload === 'true') {
+        this.getStatFieldsValue()
+      }
+    })
+  }
+
+  /**
+   * @description 涓昏〃鏁版嵁鍔犺浇
+   * @param { Boolean } reset  琛ㄦ牸鏄惁閲嶇疆
+   * @param { String }  repage 琛ㄦ牸鏄惁閲嶇疆椤电爜
+   */
+  async loadmaindata (reset, repage) {
+    const { mainSearch } = this.props
+    const { setting, config, arr_field, search, orderBy, BID, pageIndex, pageSize, BData } = this.state
+
+    if (setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
+      this.setState({
+        data: [],
+        total: 0
+      })
+      reset && MKEmitter.emit('resetTable', config.uuid, repage) // 鍒楄〃閲嶇疆
+      return
+    }
+
+    let searches = fromJS(search).toJS()
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      let keys = searches.map(item => item.key.toLowerCase())
+      mainSearch.forEach(item => {
+        if (!keys.includes(item.key.toLowerCase())) {
+          searches.push(item)
+        }
+      })
+    }
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
+    }
+
+    this.setState({
+      loading: true
+    })
+
+    let _orderBy = orderBy || setting.order
+    let param = UtilsDM.getQueryDataParams(setting, arr_field, searches, _orderBy, pageIndex, pageSize, BID, this.props.menuType)
+
+    let result = await Api.genericInterface(param)
+    if (result.status) {
+      reset && MKEmitter.emit('resetTable', config.uuid, repage) // 鍒楄〃閲嶇疆
+
+      let start = 1
+      if (setting.laypage) {
+        start = pageSize * (pageIndex - 1) + 1
+      }
+
+      this.setState({
+        data: result.data.map((item, index) => {
+          item.key = index
+          item.$$uuid = item[setting.primaryKey] || ''
+          item.$$BID = BID || ''
+          item.$$BData = BData || ''
+          item.$Index = start + index + ''
+          return item
+        }),
+        total: result.total,
+        loading: false
+      })
+    } else {
+      this.setState({
+        loading: false
+      })
+      notification.error({
+        top: 92,
+        message: result.message,
+        duration: 10
+      })
+    }
+  }
+
+  /**
+   * @description 鑾峰彇鍚堣瀛楁鍊�
+   */
+  getStatFieldsValue = () => {
+    const { mainSearch } = this.props
+    const { setting, config, search, BID, orderBy } = this.state
+
+    if (setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
+      this.setState({
+        statFValue: []
+      })
+      return
+    }
+
+    if (config.statFields.length === 0 || setting.interType !== 'system' || !setting.dataresource) return
+
+    let searches = fromJS(search).toJS()
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      let keys = searches.map(item => item.key.toLowerCase())
+      mainSearch.forEach(item => {
+        if (!keys.includes(item.key.toLowerCase())) {
+          searches.push(item)
+        }
+      })
+    }
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
+    }
+
+    let _orderBy = orderBy || setting.order
+    let param = UtilsDM.getStatQueryDataParams(setting, config.statFields, searches, _orderBy, BID, this.props.menuType)
+
+    Api.genericInterface(param).then(res => {
+      if (res.status) {
+        let _data = res.data[0]
+        let values = []
+
+        if (_data) {
+          config.statFields.forEach(item => {
+            if (_data[item.field] || _data[item.field] === 0) {
+              let val = +_data[item.field]
+              if (isNaN(val)) {
+                val = 0
+              }
+              val = val.toFixed(item.decimal)
+              values.push({label: item.label, value: val})
+            }
+          })
+        }
+        this.setState({
+          statFValue: values
+        })
+      } else {
+        this.setState({
+          statFValue: []
+        })
+        notification.error({
+          top: 92,
+          message: res.message,
+          duration: 10
+        })
+      }
+    })
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢鏀瑰彉鏃讹紝閲嶇疆琛ㄦ牸鏁版嵁
+   * 鍚湁鍒濆涓嶅姞杞界殑椤甸潰锛屼慨鏀硅缃�
+   */
+  refreshbysearch = (searches) => {
+    const { setting } = this.state
+
+    if (setting.onload === 'false') {
+      this.setState({
+        pageIndex: 1,
+        search: searches,
+        setting: {...setting, onload: 'true'}
+      }, () => {
+        this.loadmaindata()
+        this.getStatFieldsValue()
+      })
+    } else {
+      this.setState({
+        pageIndex: 1,
+        search: searches
+      }, () => {
+        this.loadmaindata(true, 'true')
+        this.getStatFieldsValue()
+      })
+    }
+  }
+
+  /**
+   * @description 琛ㄦ牸鏉′欢鏀瑰彉鏃堕噸缃暟鎹紙鍒嗛〉鎴栨帓搴忥級
+   */
+  refreshbytable = (pagination, filters, sorter) => {
+    if (sorter.order) {
+      let _chg = {
+        ascend: 'asc',
+        descend: 'desc'
+      }
+      sorter.order = _chg[sorter.order]
+    }
+
+    this.setState({
+      pageIndex: pagination.current,
+      pageSize: pagination.pageSize,
+      orderBy: (sorter.field && sorter.order) ? `${sorter.field} ${sorter.order}` : ''
+    }, () => {
+      this.loadmaindata()
+    })
+  }
+
+  /**
+   * @description 琛ㄦ牸鍒锋柊
+   */
+  reloadtable = (btn) => {
+    if (!btn || btn.resetPageIndex !== 'false') {
+      this.setState({
+        pageIndex: 1
+      }, () => {
+        this.loadmaindata(true, 'true')
+        this.getStatFieldsValue()
+      })
+    } else {
+      this.loadmaindata(true, 'false')
+      this.getStatFieldsValue()
+    }
+  }
+
+  /**
+   * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
+   */
+  queryModuleParam = (menuId, btnId) => {
+    const { mainSearch } = this.props
+    const { arr_field, config, orderBy, search, setting} = this.state
+
+    if (config.uuid !== menuId) return
+
+    let searches = search ? fromJS(search).toJS() : []
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      let keys = searches.map(item => item.key.toLowerCase())
+      mainSearch.forEach(item => {
+        if (!keys.includes(item.key.toLowerCase())) {
+          searches.push(item)
+        }
+      })
+    }
+
+    MKEmitter.emit('returnModuleParam', config.uuid, btnId, {
+      arr_field: arr_field,
+      orderBy: orderBy || setting.order,
+      search: searches,
+      menuName: config.name
+    })
+  }
+
+  reloadData = (menuId, id) => {
+    const { config } = this.state
+
+    if (config.uuid !== menuId) return
+
+    this.reloadtable()
+  }
+
+  resetParentParam = (MenuID, id, data) => {
+    const { setting } = this.state
+
+    if (!setting.supModule || setting.supModule !== MenuID) return
+    if (id !== this.state.BID) {
+      this.setState({
+        pageIndex: 1,
+        BID: id,
+        BData: data
+      }, () => {
+        this.loadmaindata(true, 'true')
+        this.getStatFieldsValue()
+      })
+    }
+  }
+
+  /**
+   * @description 鎸夐挳鎵ц瀹屾垚鍚庨〉闈㈠埛鏂�
+   * @param {*} menuId     // 鑿滃崟Id
+   * @param {*} position   // 鍒锋柊浣嶇疆
+   * @param {*} btn        // 鎵ц鐨勬寜閽�
+   */
+  refreshByButtonResult = (menuId, position, btn) => {
+    const { config, BID } = this.state
+
+    if (config.uuid !== menuId) return
+
+    this.reloadtable(btn)                                                      // 鏁版嵁鍒锋柊
+
+    if (btn.syncComponentId && btn.syncComponentId !== config.uuid && btn.syncComponentId !== config.setting.supModule) {
+      MKEmitter.emit('reloadData', btn.syncComponentId)                        // 鍚岀骇鏍囩鍒锋柊
+    }
+
+    if (position === 'mainline' && config.setting.supModule) {                 // 涓昏〃琛屽埛鏂�
+      MKEmitter.emit('reloadData', config.setting.supModule, (BID || 'empty'))
+    } else if (position === 'popclose') {                                      // 鏍囩鍏抽棴鍒锋柊
+      config.setting.supModule && MKEmitter.emit('reloadData', config.setting.supModule, (BID || 'empty'))
+      btn.$tabId && MKEmitter.emit('refreshPopButton', btn.$tabId)
+    }
+  }
+
+  UNSAFE_componentWillReceiveProps(nextProps) {
+    const { sync, config, BID, BData } = this.state
+
+    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
+      let _data = []
+      if (nextProps.data && nextProps.data[config.dataName]) {
+        _data = nextProps.data[config.dataName] || []
+        _data = _data.map((item, index) => {
+          item.key = index
+          item.$$uuid = item[config.setting.primaryKey] || ''
+          item.$$BID = BID || ''
+          item.$$BData = BData || ''
+          item.$Index = index + 1 + ''
+          return item
+        })
+      }
+
+      this.setState({sync: false, data: _data})
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({pageIndex: 1}, () => {
+        this.reloadtable()
+      })
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
+    MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
+    MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
+  }
+
+  render() {
+    const { BID, setting, searchlist, actions, config, columns, BData } = this.state
+
+    return (
+      <div className="custom-edit-table" style={config.style}>
+        <NormalHeader config={config}/>
+        {searchlist && searchlist.length ?
+          <MainSearch BID={BID} setting={config.wrap} searchlist={searchlist} menuType={this.props.menuType} refreshdata={this.refreshbysearch}/> : null
+        }
+        <MainAction
+          BID={BID}
+          setting={setting}
+          actions={actions}
+          BData={BData}
+          columns={config.columns}
+          selectedData={[]}
+        />
+        <div className={'main-table-box ' + (!actions || actions.length === 0 ? 'no-action' : '')}>
+          <MainTable
+            setting={setting}
+            columns={columns}
+            MenuID={config.uuid}
+            data={this.state.data}
+            fields={config.columns}
+            total={this.state.total}
+            lineMarks={config.lineMarks}
+            loading={this.state.loading}
+            refreshdata={this.refreshbytable}
+            statFValue={this.state.statFValue}
+          />
+        </div>
+      </div>
+    )
+  }
+}
+
+const mapStateToProps = (state) => {
+  return {
+    menuType: state.editLevel
+  }
+}
+
+const mapDispatchToProps = () => {
+  return {}
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(EditableTable)
\ No newline at end of file
diff --git a/src/tabviews/custom/components/table/edit-table/index.scss b/src/tabviews/custom/components/table/edit-table/index.scss
new file mode 100644
index 0000000..b62652b
--- /dev/null
+++ b/src/tabviews/custom/components/table/edit-table/index.scss
@@ -0,0 +1,96 @@
+.custom-edit-table {
+  position: relative;
+  background-color: #fff;
+
+  .normal-header {
+    margin-bottom: 10px;
+  }
+  .top-search {
+    border-bottom: 1px solid #efefef;
+  }
+  >.button-list.toolbar-button {
+    padding: 0;
+    line-height: 45px;
+    padding-right: 60px;
+    button {
+      margin-right: 0px;
+      margin-bottom: 0px;
+      min-height: 28px;
+      height: auto;
+    }
+  }
+  .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);
+    }
+  }
+  .main-table-box {
+    position: relative;
+    min-height: 150px;
+    .main-pickup {
+      position: absolute;
+      right: 5px;
+      top: -22px;
+      z-index: 2;
+    }
+    .custom-control {
+      position: absolute;
+      z-index: 1;
+      right: 0px;
+      top: -23px;
+      font-size: 18px;
+      padding: 3px;
+      cursor: pointer;
+    }
+    >.async-spin {
+      line-height: 150px!important;
+    }
+  }
+  .no-action.main-table-box {
+    .main-pickup {
+      position: relative;
+      right: 0px;
+      top: 0px;
+      z-index: 2;
+      float: right;
+    }
+  }
+  .ant-collapse {
+    background-color: transparent;
+    border-radius: 0px;
+    > .ant-collapse-item {
+      border: 0;
+      >.ant-collapse-header {
+        padding: 0;
+        .normal-header {
+          padding-right: 40px;
+        }
+      }
+    }
+    .ant-collapse-item:last-child > .ant-collapse-content {
+      border-radius: 0;
+      .ant-collapse-content-box {
+        padding: 0;
+        >.button-list.toolbar-button {
+          padding: 0;
+          line-height: 45px;
+          padding-right: 60px;
+          button {
+            margin-right: 0px;
+            margin-bottom: 0px;
+            min-height: 28px;
+            height: auto;
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/table/edit-table/normalTable/index.jsx b/src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
new file mode 100644
index 0000000..d667402
--- /dev/null
+++ b/src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
@@ -0,0 +1,553 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Table, Typography, Icon, Switch, Input, InputNumber } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import MKEmitter from '@/utils/events.js'
+import zhCN from '@/locales/zh-CN/main.js'
+import enUS from '@/locales/en-US/main.js'
+import '@/assets/css/table.scss'
+import './index.scss'
+
+const { Paragraph } = Typography
+const CardCellComponent = asyncComponent(() => import('@/tabviews/custom/components/card/cardcellList'))
+
+class BodyRow extends React.Component {
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props.data), fromJS(nextProps.data))
+  }
+
+  render() {
+    let { lineMarks, data, ...resProps } = this.props
+    let style = {}
+    let className = ''
+
+    lineMarks && lineMarks.some(mark => {
+      let originVal = data[mark.field[0]] + ''
+      let contrastVal = ''
+      let result = false
+
+      if (mark.field[1] === 'static') {
+        contrastVal = mark.contrastValue + ''
+      } else {
+        contrastVal = data[mark.field[2]] + ''
+      }
+
+      if (mark.match === '=') {
+        result = originVal === contrastVal
+      } else if (mark.match === '!=') {
+        result = originVal !== contrastVal
+      } else if (mark.match === 'like') {
+        result = originVal.indexOf(contrastVal) > -1
+      } else if (mark.match === '>') {
+        try {
+          originVal = parseFloat(originVal)
+          contrastVal = parseFloat(contrastVal)
+        } catch (e) {
+          originVal = NaN
+        }
+
+        if (!isNaN(originVal) && !isNaN(contrastVal) && originVal > contrastVal) {
+          result = true
+        }
+      } else if (mark.match === '<') {
+        try {
+          originVal = parseFloat(originVal)
+          contrastVal = parseFloat(contrastVal)
+        } catch (e) {
+          originVal = NaN
+        }
+
+        if (!isNaN(originVal) && !isNaN(contrastVal) && originVal < contrastVal) {
+          result = true
+        }
+      }
+
+      if (result) {
+        if (mark.signType[0] === 'font') {
+          style.color = mark.color
+        } else if (mark.signType[0] === 'background') {
+          style.background = mark.color
+          if (mark.fontColor) {
+            style.color = mark.fontColor
+          }
+          className = 'background'
+        } else if (mark.signType[0] === 'underline') {
+          style.textDecoration = 'underline'
+          style.color = mark.color
+        } else if (mark.signType[0] === 'line-through') {
+          style.textDecoration = 'line-through'
+          style.color = mark.color
+        }
+      }
+
+      return result
+    })
+
+    return <tr {...resProps} className={className} style={style}/>
+  }
+}
+
+class BodyCell extends React.Component {
+  state = {
+    editing: false
+  }
+
+  getMark = (record, marks, style, content) => {
+    marks.some(mark => {
+      let originVal = record[mark.field[0]] + ''
+      let contrastVal = ''
+      let result = false
+
+      if (mark.field[1] === 'static') {
+        contrastVal = mark.contrastValue + ''
+      } else {
+        contrastVal = record[mark.field[2]] + ''
+      }
+
+      if (mark.match === '=') {
+        result = originVal === contrastVal
+      } else if (mark.match === '!=') {
+        result = originVal !== contrastVal
+      } else if (mark.match === 'like') {
+        result = originVal.indexOf(contrastVal) > -1
+      } else if (mark.match === '>') {
+        try {
+          originVal = parseFloat(originVal)
+          contrastVal = parseFloat(contrastVal)
+        } catch (e) {
+          originVal = NaN
+        }
+
+        if (!isNaN(originVal) && !isNaN(contrastVal) && originVal > contrastVal) {
+          result = true
+        }
+      } else if (mark.match === '<') {
+        try {
+          originVal = parseFloat(originVal)
+          contrastVal = parseFloat(contrastVal)
+        } catch (e) {
+          originVal = NaN
+        }
+
+        if (!isNaN(originVal) && !isNaN(contrastVal) && originVal < contrastVal) {
+          result = true
+        }
+      }
+
+      if (result) {
+        if (mark.signType[0] === 'font') {
+          style.color = mark.color
+        } else if (mark.signType[0] === 'background') {
+          style.background = mark.color
+          if (mark.fontColor) {
+            style.color = mark.fontColor
+          }
+        } else if (mark.signType[0] === 'underline') {
+          style.textDecoration = 'underline'
+          style.color = mark.color
+        } else if (mark.signType[0] === 'line-through') {
+          style.textDecoration = 'line-through'
+          style.color = mark.color
+        } else if (mark.signType[0] === 'icon') {
+          let icon = (<Icon style={{color: mark.color}} type={mark.signType[3]} />)
+          if (mark.signType[1] === 'front') {
+            content = <span>{icon} {content}</span>
+          } else {
+            content = <span>{content} {icon}</span>
+          }
+        }
+      }
+      return result
+    })
+
+    return content
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props.record), fromJS(nextProps.record)) || nextState.editing !== this.state.editing
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('tdFocus', this.tdFocus)
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('tdFocus', this.tdFocus)
+  }
+
+  tdFocus = (id) => {
+    const { col, record } = this.props
+    if (id !== col.uuid + record.$Index) return
+    this.focus()
+  }
+
+  enterPress = () => {
+    const { col, record } = this.props
+    this.setState({editing: false})
+    if (col.enter === '$next') {
+      MKEmitter.emit('nextLine', col, record.$Index)
+    } else {
+      MKEmitter.emit('tdFocus', col.enter + record.$Index)
+    }
+  }
+
+  focus = () => {
+    const { col, record } = this.props
+
+    this.setState({editing: true, value: record[col.field] !== undefined ? record[col.field] : ''}, () => {
+      let node = document.getElementById(col.uuid + record.$Index)
+      node && node.select()
+    })
+  }
+
+  onBlur = () => {
+    this.setState({editing: false})
+  }
+
+  render() {
+    let { col, config, record, style, className } = this.props
+    const { editing, value } = this.state
+
+    let children = null
+    if (col.type === 'text') {
+      let content = ''
+      if (record[col.field] !== undefined) {
+        content = `${record[col.field]}`
+      }
+
+      if (content !== '') {
+        if (col.textFormat === 'YYYY-MM-DD' && /^[1-9]\d{3}(-|\/)(0[1-9]|1[0-2])(-|\/)(0[1-9]|[1-2][0-9]|3[0-1])/.test(content)) {
+          content = `${content.substr(0, 4)}-${content.substr(5, 2)}-${content.substr(8, 2)}`
+        } else if (col.textFormat === 'YYYY-MM-DD HH:mm:ss' && /^[1-9]\d{3}(-|\/)(0[1-9]|1[0-2])(-|\/)(0[1-9]|[1-2][0-9]|3[0-1]).([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]/.test(content)) {
+          content = `${content.substr(0, 4)}-${content.substr(5, 2)}-${content.substr(8, 2)} ${content.substr(11, 2)}:${content.substr(14, 2)}:${content.substr(17, 2)}`
+        }
+
+        content = (col.prefix || '') + content + (col.postfix || '')
+      }
+
+      if (col.marks) {
+        style = style || {}
+        content = this.getMark(record, col.marks, style, content)
+      }
+
+      if (col.editable === 'true') {
+        if (editing) {
+          return (<td className="editing_table_cell">
+            <Input id={col.uuid + record.$Index} defaultValue={value} onChange={(e) => this.setState({value: e.target.value})} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
+          </td>)
+        } else {
+          return (<td className={className + ' pointer'} style={style}><div className="mk-mask" onClick={this.focus}></div>{content}</td>)
+        }
+      } else {
+        children = content
+      }
+    } else if (col.type === 'number') {
+      let content = ''
+      try {
+        content = parseFloat(record[col.field])
+        if (isNaN(content)) {
+          content = ''
+        }
+      } catch (e) {
+        content = ''
+      }
+
+      if (content !== '') {
+        let decimal = col.decimal || 0
+        if (col.format === 'percent') {
+          content = content * 100
+          decimal = decimal > 2 ? decimal - 2 : 0
+        }
+  
+        content = content.toFixed(decimal)
+  
+        if (col.format === 'thdSeparator') {
+          content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
+        }
+  
+        content = col.prefix + content + col.postfix
+      }
+
+      if (col.marks) {
+        style = style || {}
+        content = this.getMark(record, col.marks, style, content)
+      }
+
+      if (col.editable === 'true') {
+        if (editing) {
+          return (<td className="editing_table_cell">
+            <InputNumber id={col.uuid + record.$Index} defaultValue={value} onChange={(val) => this.setState({value: val})} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
+          </td>)
+        } else {
+          return (<td className={className + ' pointer'} style={style}><div className="mk-mask" onClick={this.focus}></div>{content}</td>)
+        }
+      } else {
+        children = content
+      }
+    } else if (col.type === 'textarea') {
+      let content = ''
+      if (record[col.field] !== undefined) {
+        content = `${record[col.field]}`
+      }
+
+      if (content) {
+        content = col.prefix + content + col.postfix
+      }
+
+      children = (
+        <div>
+          {content ? <Paragraph copyable ellipsis={{ rows: 3, expandable: true }}>{content}</Paragraph> : null }
+        </div>
+      )
+    } else if (col.type === 'custom') {
+      style.padding = '0px'
+      if (col.style) {
+        style = {...style, ...col.style}
+      }
+
+      children = (
+        <CardCellComponent data={record} cards={config} elements={col.elements}/>
+      )
+    } else if (col.type === 'action') {
+      style.padding = '0px 5px'
+      children = (
+        <CardCellComponent data={record} cards={config} elements={col.elements}/>
+      )
+    }
+
+    return (<td className={className} style={style}>{children}</td>)
+  }
+}
+
+class NormalTable extends Component {
+  static propTpyes = {
+    statFValue: PropTypes.any,       // 鍚堣瀛楁鏁版嵁
+    MenuID: PropTypes.string,        // 鑿滃崟Id
+    setting: PropTypes.object,       // 琛ㄦ牸鍏ㄥ眬璁剧疆锛歵ableType锛堣〃鏍兼槸鍚﹀彲閫夈�佸崟閫夈�佸閫夛級銆乧olumnfixed锛堝垪鍥哄畾锛夈�乤ctionfixed锛堟寜閽浐瀹氾級
+    columns: PropTypes.array,        // 琛ㄦ牸鍒�
+    lineMarks: PropTypes.any,        // 琛屾爣璁�
+    fields: PropTypes.array,         // 缁勪欢瀛楁闆�
+    BData: PropTypes.any,            // 涓昏〃鏁版嵁
+    data: PropTypes.any,             // 琛ㄦ牸鏁版嵁
+    total: PropTypes.any,            // 鎬绘暟
+    loading: PropTypes.bool,         // 琛ㄦ牸鍔犺浇涓�
+    refreshdata: PropTypes.func,     // 琛ㄦ牸涓帓搴忓垪銆侀〉鐮佺殑鍙樺寲鏃跺埛鏂�
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    data: [],
+    tableId: '',          // 琛ㄦ牸ID
+    pageIndex: 1,         // 鍒濆椤甸潰绱㈠紩
+    pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
+    columns: null,        // 鏄剧ず鍒�
+    pickup: false,        // 鏀惰捣鏈�夋嫨椤�
+    orderfields: {}       // 鎺掑簭id涓巉ield杞崲
+  }
+
+  UNSAFE_componentWillMount () {
+    const { setting, fields, columns } = this.props
+    let orderfields = {}
+    let initEditLine = null
+
+    let _columns = columns.map(item => {
+      if (item.type === 'index') {
+        item.field = '$Index'
+        item.type = 'text'
+      }
+      if (!initEditLine && item.editable === 'true') {
+        initEditLine = item
+      }
+
+      if (item.marks && item.marks.length === 0) {
+        item.marks = ''
+      }
+
+      if (item.field) {
+        orderfields[item.uuid] = item.field
+      }
+
+      return {
+        align: item.Align,
+        dataIndex: item.uuid,
+        title: item.label,
+        sorter: item.field && item.IsSort === 'true',
+        width: item.Width || 120,
+        onCell: record => ({
+          record,
+          col: item,
+          config: item.type === 'custom' || item.type === 'action' ? {setting, columns: fields} : null,
+        })
+      }
+    })
+
+    let tableId = (() => {
+      let uuid = []
+      let _options = 'abcdefghigklmnopqrstuv'
+      for (let i = 0; i < 19; i++) {
+        uuid.push(_options.substr(Math.floor(Math.random() * 0x20), 1))
+      }
+      return uuid.join('')
+    }) ()
+
+    if (setting.borderColor) { // 杈规棰滆壊
+      let style = `#${tableId} table, #${tableId} tr, #${tableId} th, #${tableId} td {border-color: ${setting.borderColor}}`
+      let ele = document.createElement('style')
+      ele.innerHTML = style
+      document.getElementsByTagName('head')[0].appendChild(ele)
+    }
+
+    this.setState({
+      columns: _columns,
+      tableId,
+      orderfields,
+      initEditLine
+    })
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('resetTable', this.resetTable)
+    MKEmitter.addListener('nextLine', this.nextLine)
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('resetTable', this.resetTable)
+    MKEmitter.removeListener('nextLine', this.nextLine)
+  }
+
+  UNSAFE_componentWillReceiveProps(nextProps) {
+    if (!is(fromJS(this.props.data), fromJS(nextProps.data))) {
+      this.setState({data: nextProps.data || []})
+    }
+  }
+  
+  nextLine = (col, index) => {
+    const { data, initEditLine } = this.state
+    index = +index
+
+    if (index < data.length && initEditLine) {
+      MKEmitter.emit('tdFocus', initEditLine.uuid + (index + 1))
+    }
+  }
+
+  changeTable = (pagination, filters, sorter) => {
+    const { orderfields } = this.state
+
+    this.setState({
+      pageIndex: pagination.current,
+      pageSize: pagination.pageSize,
+      pickup: false
+    })
+
+    sorter.field = orderfields[sorter.field] || ''
+
+    this.props.refreshdata(pagination, filters, sorter)
+  }
+
+  resetTable = (id, repage) => {
+    const { MenuID } = this.props
+
+    if (id !== MenuID) return
+
+    if (repage === 'false') {
+      this.setState({
+        pickup: false
+      })
+    } else {
+      this.setState({
+        pageIndex: 1,
+        pickup: false
+      })
+    }
+  }
+
+  pickupChange = () => {
+    this.setState({
+      pickup: !this.state.pickup
+    })
+  }
+
+  render() {
+    const { setting, statFValue, lineMarks } = this.props
+    const { pickup, tableId, data } = this.state
+
+    const components = {
+      body: {
+        row: BodyRow,
+        cell: BodyCell
+      }
+    }
+
+    // 鏁版嵁鏀惰捣鏃讹紝杩囨护宸查�夋暟鎹�
+    let _data = data || []
+
+    if (pickup) {
+      _data = _data.filter(item => !item.$deleted)
+    }
+    
+    let _pagination = false
+    if (setting.laypage !== 'false' && setting.laypage !== false) {
+      _pagination = {
+        current: this.state.pageIndex,
+        pageSize: this.state.pageSize,
+        pageSizeOptions: ['10', '25', '50', '100', '500', '1000'],
+        showSizeChanger: true,
+        total: this.props.total || 0,
+        showTotal: (total, range) => `${range[0]}-${range[1]} ${this.state.dict['main.pagination.of']} ${total} ${this.state.dict['main.pagination.items']}`
+      }
+    }
+
+    let _footer = ''
+
+    if (statFValue && statFValue.length > 0) {
+      _footer = statFValue.map(f => `${f.label}(鍚堣)锛�${f.value}`).join('锛�')
+    }
+
+    let height = setting.height || false
+
+    return (
+      <div className={`edit-custom-table ${pickup ? 'editable' : ''} ${setting.tableHeader || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''}`} id={tableId}>
+        <Switch title="缂栬緫" className="main-pickup" checkedChildren="寮�" unCheckedChildren="鍏�" checked={pickup} onChange={this.pickupChange} />
+        <Table
+          components={components}
+          style={setting.style}
+          size={setting.size || 'middle'}
+          bordered={setting.bordered !== 'false'}
+          columns={this.state.columns}
+          dataSource={_data}
+          loading={this.props.loading}
+          scroll={{ x: '100%', y: height }}
+          onRow={(record, index) => {
+            return {
+              lineMarks,
+              data: record
+            }
+          }}
+          onChange={this.changeTable}
+          pagination={_pagination}
+        />
+        {_footer ? <div className={'normal-table-footer ' + (_pagination ? 'pagination' : '')}>{_footer}</div> : null}
+      </div>
+    )
+  }
+}
+
+export default NormalTable
\ No newline at end of file
diff --git a/src/tabviews/custom/components/table/edit-table/normalTable/index.scss b/src/tabviews/custom/components/table/edit-table/normalTable/index.scss
new file mode 100644
index 0000000..0cbfb78
--- /dev/null
+++ b/src/tabviews/custom/components/table/edit-table/normalTable/index.scss
@@ -0,0 +1,294 @@
+.edit-custom-table {
+  position: relative;
+  padding: 0px;
+
+  .normal-table-footer {
+    padding: 10px 0px;
+    color: rgba(0, 0, 0, 0.65);
+  }
+  .normal-table-footer.pagination {
+    position: absolute;
+    bottom: 10px;
+  }
+  >.ant-table-wrapper {
+    position: relative;
+    z-index: 1;
+  }
+  .ant-table {
+    color: inherit;
+    font-size: inherit;
+  }
+
+  table {
+    max-width: 100%;
+    width: 100%;
+    .ant-table-thead {
+      tr {
+        th {
+          position: relative;
+        }
+      }
+    }
+    .ant-table-selection-column {
+      width: 60px;
+      min-width: 60px;
+      max-width: 60px;
+    }
+    .ant-table-tbody > tr.ant-table-row-selected:not(.background) td {
+      background-color: #c4ebfd;
+    }
+    .ant-table-tbody > tr.ant-table-row-selected:not(.background):hover .ant-table-column-sort {
+      background-color: #c4ebfd;
+    }
+    .ant-table-tbody > tr.background td {
+      background-color: unset!important;
+    }
+    // .ant-table-tbody > tr.mk-row-active:not(.background) td {
+    //   background-color: #91d5ff;
+    // }
+    // .ant-table-tbody > tr.ant-table-row-selected.mk-row-active:not(.background):hover .ant-table-column-sort {
+    //   background-color: #91d5ff;
+    // }
+    .ant-table-tbody > tr td .anticon.font {
+      background-color: unset;
+    }
+  }
+  .ant-table-body {
+    overflow-x: auto!important;
+    table {
+      .ant-table-tbody > tr > td {
+        // vertical-align: top;
+
+        .card-cell-list {
+          color: rgba(0, 0, 0, 0.85);
+        }
+        .ant-mk-picture {
+          position: relative;
+          background-position: center center;
+          background-size: cover;
+          margin: 2px;
+        }
+        .ant-mk-picture.scale {
+          cursor: zoom-in;
+        }
+        .action-col {
+          .ant-btn > .anticon + span {
+            margin-left: 3px;
+          }
+          button {
+            border: 0;
+            background-color: transparent;
+            color: #1890ff;
+            box-shadow: none;
+            padding: 0 5px;
+            .anticon-loading {
+              display: none;
+            }
+          }
+          > div {
+            margin: 0 3px;
+          }
+          > button {
+            margin: 0 3px;
+          }
+          .ant-btn.ant-btn-loading:not(.ant-btn-circle):not(.ant-btn-circle-outline):not(.ant-btn-icon-only) {
+            padding-left: 0px;
+          }
+        }
+      }
+      .ant-table-tbody > tr > td[rowspan] {
+        vertical-align: middle;
+      }
+      .ant-table-tbody > tr > td.ant-table-column-has-actions {
+        .content {
+          position: relative;
+          z-index: 1;
+          word-wrap: break-word;
+          word-break: break-word;
+        }
+      }
+      .ant-table-tbody > tr > td {
+        position: relative;
+        .link-menu {
+          position: absolute;
+          top: 0px;
+          left: 0px;
+          right: 0px;
+          bottom: 0px;
+          opacity: 0;
+          cursor: pointer;
+        }
+      }
+      .ant-table-tbody > tr > td .content {
+        p {
+          margin-bottom: 2px;
+        }
+        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-input {
+    border: none;
+    box-shadow: none!important;
+    height: auto;
+    border-radius: 0;
+  }
+  .ant-input-number {
+    border: none;
+    width: 100%;
+    box-shadow: none!important;
+    height: auto;
+    .ant-input-number-handler-wrap {
+      display: none;
+    }
+    .ant-input-number-input {
+      border-radius: 0;
+      padding: 0;
+      height: auto;
+    }
+  }
+  .editing_table_cell {
+    .ant-input {
+      padding: 0px;
+    }
+  }
+  td.pointer {
+    position: relative;
+  }
+  td.pointer {
+    .mk-mask {
+      display: none;
+      cursor: pointer;
+      position: absolute;
+      top: 0;
+      left: 0;
+      bottom: 0;
+      right: 0;
+    }
+  }
+}
+.edit-custom-table.editable {
+  td {
+    background-color: #ffffff!important;
+  }
+  td.pointer .mk-mask {
+    display: block;
+  }
+  .ant-pagination {
+    display: none;
+  }
+}
+.edit-custom-table:not(.fixed-height) {
+  .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);
+  }
+}
+.edit-custom-table.fixed-height {
+  .ant-table-body {
+    border-bottom: 1px solid rgba(0, 0, 0, .05);
+    .ant-table-fixed {
+      border-bottom: 0;
+    }
+  }
+}
+.edit-custom-table.hidden {
+  thead {
+    display: none;
+  }
+}
+.edit-custom-table.ghost {
+  .main-pickup {
+    display: none;
+  }
+  .ant-table-thead > tr {
+    > th {
+      color: inherit;
+      background: transparent;
+      .ant-table-column-sorter .ant-table-column-sorter-inner {
+        color: inherit;
+      }
+    }
+    > th:hover {
+      background: transparent;
+    }
+  }
+  .ant-table-body {
+    overflow-x: auto;
+    tr {
+      td {
+        background: transparent!important;
+      }
+    }
+    tr:hover td {
+      background: transparent!important;
+    }
+  }
+}
+.image-scale-modal {
+  width: 70vw;
+  min-height: 80vh;
+  top: 10vh;
+  .ant-modal-body {
+    min-height: calc(80vh - 110px);
+    line-height: calc(80vh - 160px);
+    text-align: center;
+  }
+  .ant-modal-footer {
+    text-align: center;
+    span {
+      display: inline-block;
+      color: #1890ff;
+      padding: 5px 15px;
+      cursor: pointer;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/table/normal-table/index.jsx b/src/tabviews/custom/components/table/normal-table/index.jsx
index 3173619..d1c9b60 100644
--- a/src/tabviews/custom/components/table/normal-table/index.jsx
+++ b/src/tabviews/custom/components/table/normal-table/index.jsx
@@ -650,9 +650,7 @@
 
 const mapStateToProps = (state) => {
   return {
-    menuType: state.editLevel,
-    permAction: state.permAction,
-    permMenus: state.permMenus
+    menuType: state.editLevel
   }
 }
 
diff --git a/src/tabviews/custom/index.jsx b/src/tabviews/custom/index.jsx
index 478a593..83da990 100644
--- a/src/tabviews/custom/index.jsx
+++ b/src/tabviews/custom/index.jsx
@@ -30,6 +30,7 @@
 const TableCard = asyncComponent(() => import('./components/card/table-card'))
 const MainSearch = asyncComponent(() => import('@/tabviews/zshare/topSearch'))
 const NormalTable = asyncComponent(() => import('./components/table/normal-table'))
+const EditTable = asyncComponent(() => import('./components/table/edit-table'))
 const NormalGroup = asyncComponent(() => import('./components/group/normal-group'))
 const BraftEditor = asyncComponent(() => import('./components/editor/braft-editor'))
 const SandBox = asyncComponent(() => import('./components/code/sand-box'))
@@ -522,7 +523,7 @@
         item.search = Utils.initSearchVal(item.search)
       }
 
-      if (item.type === 'table' && item.subtype === 'normaltable') {
+      if (item.type === 'table' && (item.subtype === 'normaltable' || item.subtype === 'editable')) {
         let statFields = []
         let getCols = (cols) => {
           return cols.filter(col => {
@@ -697,7 +698,7 @@
             return cell.eleType !== 'button' || skip || permAction[cell.uuid]
           })
         })
-      } else if (item.type === 'table' && item.subtype === 'normaltable') {
+      } else if (item.type === 'table' && (item.subtype === 'normaltable' || item.subtype === 'editable')) {
         item.cols = item.cols.filter(col => {
           if (col.type !== 'action') return true
           col.elements = col.elements.filter(cell => {
@@ -1104,6 +1105,12 @@
             <NormalTable config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'table' && item.subtype === 'editable') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <EditTable config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else if (item.type === 'group' && item.subtype === 'normalgroup') {
         return (
           <Col span={item.width} key={item.uuid}>
diff --git a/src/templates/sharecomponent/actioncomponent/actionform/index.jsx b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
index e5d20d3..460a648 100644
--- a/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
@@ -134,7 +134,7 @@
           } else if (['innerpage', 'tab', 'popview', 'excelIn'].includes(_opentype)) {
             item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
           } else if (card.sqlType === 'insert') {
-            item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl', 'required'].includes(op.value))
+            item.options = this.state.requireOptions.filter(op => ['notRequired'].includes(op.value))
           } else {
             item.options = this.state.requireOptions
           }
@@ -364,7 +364,7 @@
       this.setState({
         formlist: this.state.formlist.map(item => {
           if (item.key === 'Ot' && value === 'insert') {
-            item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl', 'required'].includes(op.value))
+            item.options = this.state.requireOptions.filter(op => ['notRequired'].includes(op.value))
           } else if (item.key === 'Ot') {
             item.options = this.state.requireOptions
           }

--
Gitblit v1.8.0