From 432b788acf901b0720184b8ee8bc81a2e6fa47e0 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期二, 28 九月 2021 18:22:02 +0800
Subject: [PATCH] 2021-09-28

---
 src/pc/transfer/index.jsx                                              |    1 
 src/tabviews/zshare/mutilform/mkRadio/index.jsx                        |    2 
 src/templates/zshare/modalform/index.jsx                               |    4 
 src/tabviews/zshare/mutilform/mkSwitch/index.jsx                       |    2 
 src/tabviews/zshare/topSearch/index.jsx                                |   27 
 src/tabviews/zshare/topSearch/mkSelect/index.jsx                       |    2 
 src/tabviews/zshare/mutilform/mkSelect/index.jsx                       |    2 
 src/menu/components/table/edit-table/options.jsx                       |  204 +++++
 src/menu/components/table/edit-table/columns/editColumn/index.scss     |   27 
 src/pc/quotecomponent/settingform/index.scss                           |   11 
 src/menu/menushell/card.jsx                                            |    3 
 src/components/paste/index.jsx                                         |    1 
 src/menu/components/table/edit-table/columns/editColumn/index.jsx      |  388 +++++++++
 src/menu/components/table/edit-table/index.jsx                         |  422 ++++++++++
 src/menu/modulesource/option.jsx                                       |    2 
 src/components/normalform/modalform/mkSelect/index.jsx                 |    1 
 src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx |  394 +++++++++
 src/menu/components/table/edit-table/index.scss                        |   80 ++
 src/templates/zshare/formconfig.jsx                                    |   28 
 src/pc/quotecomponent/settingform/index.jsx                            |    2 
 src/pc/menushell/card.jsx                                              |    3 
 src/components/normalform/modalform/mkRadio/index.jsx                  |    1 
 src/menu/components/group/groupcomponents/card.jsx                     |    3 
 src/tabviews/zshare/mutilform/index.jsx                                |    2 
 src/components/normalform/modalform/mkCheckbox/index.jsx               |    2 
 src/components/normalform/index.jsx                                    |    1 
 src/menu/components/table/edit-table/columns/index.scss                |  124 +++
 src/tabviews/zshare/mutilform/mkTextArea/index.jsx                     |    1 
 src/tabviews/zshare/mutilform/mkCheckbox/index.jsx                     |    2 
 src/tabviews/zshare/topSearch/mkDatePicker/index.jsx                   |    2 
 src/menu/components/tabs/tabcomponents/card.jsx                        |    3 
 src/tabviews/zshare/mutilform/mkDatePicker/index.jsx                   |    2 
 src/menu/components/table/edit-table/columns/index.jsx                 |  601 +++++++++++++++
 src/templates/sharecomponent/searchcomponent/searchform/index.jsx      |    4 
 34 files changed, 2,301 insertions(+), 53 deletions(-)

diff --git a/src/components/normalform/index.jsx b/src/components/normalform/index.jsx
index de675fb..5ef4c9d 100644
--- a/src/components/normalform/index.jsx
+++ b/src/components/normalform/index.jsx
@@ -6,7 +6,6 @@
 import zhCN from '@/locales/zh-CN/model.js'
 import enUS from '@/locales/en-US/model.js'
 import ModalForm from './modalform'
-import './index.scss'
 
 class NormalFormComponent extends Component {
   static propTpyes = {
diff --git a/src/components/normalform/modalform/mkCheckbox/index.jsx b/src/components/normalform/modalform/mkCheckbox/index.jsx
index 934eece..e8d95c8 100644
--- a/src/components/normalform/modalform/mkCheckbox/index.jsx
+++ b/src/components/normalform/modalform/mkCheckbox/index.jsx
@@ -3,8 +3,6 @@
 import { is, fromJS } from 'immutable'
 import { Checkbox } from 'antd'
 
-import './index.scss'
-
 class MKCheckbox extends Component {
   static propTpyes = {
     config: PropTypes.object,
diff --git a/src/components/normalform/modalform/mkRadio/index.jsx b/src/components/normalform/modalform/mkRadio/index.jsx
index c14b111..212df13 100644
--- a/src/components/normalform/modalform/mkRadio/index.jsx
+++ b/src/components/normalform/modalform/mkRadio/index.jsx
@@ -4,7 +4,6 @@
 import { Radio } from 'antd'
 
 import MKEmitter from '@/utils/events.js'
-import './index.scss'
 
 class MKRadio extends Component {
   static propTpyes = {
diff --git a/src/components/normalform/modalform/mkSelect/index.jsx b/src/components/normalform/modalform/mkSelect/index.jsx
index c5c6ad4..25c5984 100644
--- a/src/components/normalform/modalform/mkSelect/index.jsx
+++ b/src/components/normalform/modalform/mkSelect/index.jsx
@@ -3,7 +3,6 @@
 import { Select } from 'antd'
 
 import MKEmitter from '@/utils/events.js'
-import './index.scss'
 
 class MKSelect extends Component {
   constructor(props) {
diff --git a/src/components/paste/index.jsx b/src/components/paste/index.jsx
index 4760c22..5efc6b6 100644
--- a/src/components/paste/index.jsx
+++ b/src/components/paste/index.jsx
@@ -3,7 +3,6 @@
 import { Icon, Modal, notification } from 'antd'
 
 import asyncComponent from '@/utils/asyncComponent'
-import './index.scss'
 
 const PasteForm = asyncComponent(() => import('@/templates/zshare/pasteform'))
 
diff --git a/src/menu/components/group/groupcomponents/card.jsx b/src/menu/components/group/groupcomponents/card.jsx
index 4f58886..cec20ff 100644
--- a/src/menu/components/group/groupcomponents/card.jsx
+++ b/src/menu/components/group/groupcomponents/card.jsx
@@ -11,6 +11,7 @@
 const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
 const NormalTree = asyncComponent(() => import('@/menu/components/tree/antd-tree'))
 const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
+const EditTable = asyncComponent(() => import('@/menu/components/table/edit-table'))
 const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
 const AntvScatter = asyncComponent(() => import('@/menu/components/chart/antv-scatter'))
 const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
@@ -77,6 +78,8 @@
       return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'table' && card.subtype === 'normaltable') {
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'table' && card.subtype === 'editable') {
+      return (<EditTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'carousel' && card.subtype === 'datacard') {
       return (<CarouselDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'carousel' && card.subtype === 'propcard') {
diff --git a/src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx b/src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
new file mode 100644
index 0000000..e2b4ae1
--- /dev/null
+++ b/src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
@@ -0,0 +1,394 @@
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+
+const Formdict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
+
+/**
+ * @description 鑾峰彇鏄剧ず鍒楄〃鍗曢厤缃俊鎭�
+ * @param {object} card       // 鎼滅储鏉′欢瀵硅薄
+ */
+export function getColumnForm (card, fields = []) {
+  let appType = sessionStorage.getItem('appType')
+  let roleList = sessionStorage.getItem('sysRoles')
+  if (roleList) {
+    try {
+      roleList = JSON.parse(roleList)
+    } catch (e) {
+      roleList = []
+    }
+  } else {
+    roleList = []
+  }
+
+  let menulist = []
+
+  if (appType === 'pc') {
+    menulist = sessionStorage.getItem('appMenus')
+  } else if (!appType) {
+    menulist = sessionStorage.getItem('fstMenuList')
+  }
+
+  if (menulist) {
+    try {
+      menulist = JSON.parse(menulist)
+    } catch (e) {
+      menulist = []
+    }
+  } else {
+    menulist = []
+  }
+
+  let options = [{
+    value: 'text',
+    text: Formdict['model.form.text']
+  }, {
+    value: 'number',
+    text: Formdict['model.form.number']
+  }, {
+    value: 'picture',
+    text: Formdict['model.form.picture']
+  }, {
+    value: 'link',
+    text: Formdict['model.form.href']
+  }, {
+    value: 'textarea',
+    text: Formdict['model.form.textarea']
+  }, {
+    value: 'custom',
+    text: '鑷畾涔夊垪'
+  }, {
+    value: 'colspan',
+    text: '鍚堝苟鍒�'
+  }, {
+    value: 'index',
+    text: '搴忓彿'
+  }]
+
+  if (!card.isSub) {
+    options.push({
+      value: 'action',
+      text: '鎿嶄綔'
+    })
+  }
+
+  if (!card.linkurl && (!card.linkmenu || card.linkmenu.length === 0)) {
+    card.perspective = ''
+  }
+
+  return [
+    {
+      type: 'text',
+      key: 'label',
+      label: '鍒楀ご鏂囧瓧',
+      initVal: card.label,
+      required: true
+    },
+    {
+      type: 'select',
+      key: 'type',
+      label: Formdict['model.form.type'],
+      initVal: card.type,
+      required: true,
+      options: options
+    },
+    {
+      type: 'select',
+      key: 'field',
+      label: Formdict['model.form.field'],
+      initVal: card.field,
+      required: true,
+      options: fields
+    },
+    {
+      type: 'select',
+      key: 'nameField',
+      label: Formdict['model.name'] + Formdict['model.form.field'],
+      initVal: card.nameField || '',
+      required: false,
+      options: [{uuid: 'empty', field: '', label: '绌�'}, ...fields]
+    },
+    {
+      type: 'number',
+      key: 'Width',
+      min: 20,
+      max: 1000,
+      decimal: 0,
+      label: Formdict['model.form.columnWidth'],
+      initVal: card.Width || 120,
+      required: true
+    },
+    {
+      type: 'radio',
+      key: 'joint',
+      label: Formdict['model.form.paramJoint'],
+      initVal: card.joint || 'true',
+      required: true,
+      options: [{
+        value: 'true',
+        text: Formdict['model.true']
+      }, {
+        value: 'false',
+        text: Formdict['model.false']
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'Hide',
+      label: Formdict['model.hidden'],
+      initVal: card.Hide || 'false',
+      required: true,
+      options: [{
+        value: 'true',
+        text: Formdict['model.true']
+      }, {
+        value: 'false',
+        text: Formdict['model.false']
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'IsSort',
+      label: Formdict['model.sort'],
+      initVal: card.IsSort || 'true',
+      required: true,
+      forbidden: card.isSub,
+      options: [{
+        value: 'true',
+        text: Formdict['model.true']
+      }, {
+        value: 'false',
+        text: Formdict['model.false']
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'Align',
+      label: Formdict['model.form.align'],
+      initVal: card.Align || 'left',
+      required: true,
+      options: [{
+        value: 'left',
+        text: Formdict['model.form.alignLeft']
+      }, {
+        value: 'center',
+        text: Formdict['model.form.alignCenter']
+      }, {
+        value: 'right',
+        text: Formdict['model.form.alignRight']
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'rowspan',
+      label: '琛屽悎骞�',
+      initVal: card.rowspan || 'false',
+      tooltip: '鐩搁偦琛屼俊鎭浉鍚屾椂锛屽崟鍏冩牸鍚堝苟銆�',
+      required: false,
+      options: [{
+        value: 'true',
+        text: Formdict['model.true']
+      }, {
+        value: 'false',
+        text: Formdict['model.false']
+      }]
+    },
+    {
+      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: 'number',
+      key: 'decimal',
+      min: 0,
+      max: 18,
+      decimal: 0,
+      label: Formdict['header.form.decimal'],
+      initVal: card.decimal || 0,
+      required: true
+    },
+    {
+      type: 'select',
+      key: 'format',
+      label: Formdict['header.form.format'],
+      initVal: card.format || 'none',
+      options: [{
+        value: 'none',
+        text: Formdict['model.empty']
+      }, {
+        value: 'thdSeparator',
+        text: Formdict['header.form.thdSeparator']
+      }, {
+        value: 'percent',
+        text: '鐧惧垎姣�'
+      }],
+      required: false
+    },
+    {
+      type: 'select',
+      key: 'textFormat',
+      label: Formdict['header.form.format'],
+      initVal: card.textFormat || 'none',
+      options: [{
+        value: 'none',
+        text: Formdict['model.empty']
+      }, {
+        value: 'YYYY-MM-DD',
+        text: 'YYYY-MM-DD'
+      }, {
+        value: 'YYYY-MM-DD HH:mm:ss',
+        text: 'YYYY-MM-DD HH:mm:ss'
+      }],
+      required: false
+    },
+    {
+      type: 'text',
+      key: 'prefix',
+      label: Formdict['header.form.prefix'],
+      initVal: card.prefix || '',
+      required: false,
+      readonly: false
+    },
+    {
+      type: 'text',
+      key: 'postfix',
+      label: Formdict['header.form.postfix'],
+      initVal: card.postfix || '',
+      required: false,
+      readonly: false
+    },
+    {
+      type: 'select',
+      key: 'lenWidRadio',
+      label: '闀垮姣�',
+      initVal: card.lenWidRadio || '1:1',
+      required: true,
+      options: [
+        { value: '1:1', text: '1:1' },
+        { value: '4:3', text: '4:3' },
+        { value: '3:2', text: '3:2' },
+        { value: '16:9', text: '16:9' },
+        { value: '2:1', text: '2:1' },
+        { value: '3:1', text: '3:1' },
+        { value: '4:1', text: '4:1' },
+        { value: '5:1', text: '5:1' },
+        { value: '6:1', text: '6:1' },
+        { value: '7:1', text: '7:1' },
+        { value: '8:1', text: '8:1' },
+        { value: '9:1', text: '9:1' },
+        { value: '10:1', text: '10:1' },
+        { value: '3:4', text: '3:4' },
+        { value: '2:3', text: '2:3' },
+        { value: '9:16', text: '9:16' },
+      ]
+    },
+    {
+      type: 'radio',
+      key: 'picSort',
+      label: '鍥剧墖鎺掑垪',
+      initVal: card.picSort || '1',
+      tooltip: '鍚屼竴鍗曞厓鏍煎唴锛屽惈鏈夊寮犲浘鐗囨椂鐨勫垪鏁般��',
+      required: false,
+      options: [{
+        value: '1',
+        text: '1'
+      }, {
+        value: '2',
+        text: '2'
+      }, {
+        value: '3',
+        text: '3'
+      }, {
+        value: '4',
+        text: '4'
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'scale',
+      label: Formdict['header.form.clickscale'],
+      initVal: card.scale || 'false',
+      required: false,
+      options: [{
+        value: 'true',
+        text: Formdict['model.true']
+      }, {
+        value: 'false',
+        text: Formdict['model.false']
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'perspective',
+      label: '瀛楁閫忚',
+      initVal: card.perspective || '',
+      options: [{
+        value: '',
+        text: '鏃�'
+      }, {
+        value: 'linkmenu',
+        text: '鑿滃崟'
+      }, {
+        value: 'linkurl',
+        text: '閾炬帴'
+      }],
+      forbidden: appType === 'mob'
+    },
+    {
+      type: appType === 'pc' ? 'select' : 'cascader',
+      key: 'linkmenu',
+      label: Formdict['model.menu'],
+      initVal: card.linkmenu || (appType === 'pc' ? '' : []),
+      required: true,
+      options: menulist,
+      forbidden: appType === 'mob'
+    },
+    {
+      type: 'textarea',
+      key: 'linkurl',
+      label: '閾炬帴鍦板潃',
+      initVal: card.linkurl || '',
+      required: true,
+      forbidden: appType === 'mob'
+    },
+    {
+      type: 'multiselect',
+      key: 'linkfields',
+      label: '鍏宠仈瀛楁',
+      initVal: card.linkfields || [],
+      required: false,
+      options: fields,
+      forbidden: appType === 'mob'
+    },
+    {
+      type: 'radio',
+      key: 'open',
+      label: '鎵撳紑鏂瑰紡',
+      initVal: card.open || 'blank',
+      required: false,
+      forbid: appType !== 'pc',
+      options: [
+        { value: 'blank', text: '鏂扮獥鍙�' },
+        { value: 'self', text: '褰撳墠绐楀彛' }
+      ]
+    },
+    {
+      type: 'multiselect',
+      key: 'blacklist',
+      label: Formdict['header.form.blacklist'],
+      initVal: card.blacklist || [],
+      required: false,
+      options: roleList
+    }
+  ]
+}
diff --git a/src/menu/components/table/edit-table/columns/editColumn/index.jsx b/src/menu/components/table/edit-table/columns/editColumn/index.jsx
new file mode 100644
index 0000000..81aed8a
--- /dev/null
+++ b/src/menu/components/table/edit-table/columns/editColumn/index.jsx
@@ -0,0 +1,388 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Form, Row, Col, Input, Select, InputNumber, Radio, Tooltip, Icon, Cascader, Modal } from 'antd'
+
+import { getColumnForm } from './formconfig'
+import { formRule } from '@/utils/option.js'
+import './index.scss'
+
+const { TextArea } = Input
+const columnTypeOptions = {
+  text: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'textFormat', 'blacklist', 'perspective', 'rowspan'],
+  number: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'decimal', 'format', 'prefix', 'postfix', 'blacklist', 'perspective', 'sum', 'rowspan'],
+  link: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'joint', 'Width', 'blacklist', 'nameField'],
+  textarea: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'blacklist'],
+  picture: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'blacklist', 'scale', 'lenWidRadio', 'picSort'],
+  colspan: ['label', 'type', 'Align', 'Hide', 'blacklist'],
+  custom: ['label', 'type', 'Align', 'Hide', 'Width', 'blacklist'],
+  action: ['label', 'type', 'Align', 'Width'],
+  index: ['label', 'type', 'Align', 'Width']
+}
+
+class MainSearch extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,     // 瀛楀吀椤�
+    visible: PropTypes.bool,
+    column: PropTypes.object,
+    fields: PropTypes.array,
+    submitCol: PropTypes.func,  // 鎻愪氦浜嬩欢
+    cancelCol: PropTypes.func   // 鍙栨秷鏃跺垹闄や簨浠�
+  }
+
+  state = {
+    visible: false,
+    formlist: null
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    if (nextProps.column && !is(fromJS(this.props.column), fromJS(nextProps.column))) {
+      this.editColumn(nextProps.column)
+    }
+  }
+
+  editColumn = (column) => {
+    let formlist = getColumnForm(column, this.props.fields)
+    let _options = fromJS(columnTypeOptions[column.type]).toJS()
+    if (column.type === 'text' || column.type === 'number') {
+      if (column.perspective === 'linkmenu') {
+        _options.push('linkmenu', 'linkfields', 'open')
+      } else if (column.perspective === 'linkurl') {
+        _options.push('linkurl', 'linkfields', 'open')
+      }
+    }
+
+    this.setState({
+      visible: true,
+      type: column.type,
+      formlist: formlist.map(item => {
+        item.hidden = !_options.includes(item.key)
+
+        return item
+      })
+    }, () => {
+      if (column.focus) {
+        try {
+          let _form = document.getElementById('label')
+          _form && _form.select()
+        } catch (e) {
+          console.warn('琛ㄥ崟focus澶辫触锛�')
+        }
+      }
+    })
+  }
+
+  typeChange = (key, value, option) => {
+    if (key === 'type') {
+      let _options = fromJS(columnTypeOptions[value]).toJS()
+
+      this.setState({
+        type: value,
+        formlist: this.state.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
+
+          return item
+        })
+      }, () => {
+        if (value === 'link' || value === 'textarea' || value === 'picture') {
+          this.props.form.setFieldsValue({IsSort: 'false'})
+        } else if (value === 'text' || value === 'number') {
+          this.props.form.setFieldsValue({perspective: ''})
+        } else if (value === 'action' || value === 'colspan') {
+          this.props.form.setFieldsValue({Align: 'center'})
+        }
+      })
+    } else if (key === 'field') {
+      let values = {label: option.props.children}
+      if (/Decimal|int/ig.test(option.props.datatype)) {
+        let decimal = 0
+        if (/Decimal/ig.test(option.props.datatype)) {
+          decimal = +option.props.datatype.replace(/Decimal\(18,/ig, '').replace(')', '')
+        }
+        values.type = 'number'
+        values.decimal = decimal
+      } else {
+        values.type = 'text'
+      }
+
+      if (values.type !== this.state.type) {
+        values.perspective = ''
+        let _options = fromJS(columnTypeOptions[values.type]).toJS()
+
+        this.setState({
+          type: values.type,
+          formlist: this.state.formlist.map(item => {
+            item.hidden = !_options.includes(item.key)
+
+            return item
+          })
+        }, () => {
+          this.props.form.setFieldsValue(values)
+        })
+      } else {
+        this.props.form.setFieldsValue(values)
+      }
+    } else if (key === 'format' && value === 'percent') {
+      this.props.form.setFieldsValue({postfix: '%'})
+    }
+  }
+
+  changeRadio = (key, value) => {
+    if (key === 'perspective') {
+      let _options = fromJS(columnTypeOptions[this.state.type]).toJS()
+
+      if (value === 'linkmenu') {
+        _options.push('linkmenu', 'linkfields', 'open')
+      } else if (value === 'linkurl') {
+        _options.push('linkurl', 'linkfields', 'open')
+      }
+
+      this.setState({
+        formlist: this.state.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
+
+          return item
+        })
+      })
+    }
+  }
+
+  getFields() {
+    const { getFieldDecorator } = this.props.form
+    const { formlist } = this.state
+    const fields = []
+
+    if (!formlist) return null
+
+    formlist.forEach((item, index) => {
+      if (item.hidden || item.forbidden) return
+
+      if (item.type === 'text') { // 鏂囨湰鎼滅储
+        let rules = []
+        if (item.key !== 'linkurl') {
+          rules = [{
+            max: formRule.input.max,
+            message: formRule.input.message
+          }]
+        }
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  },
+                  ...rules
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(item.unlimit ? <InputNumber onPressEnter={this.handleSubmit}/> :
+                  <InputNumber min={item.min} max={item.max} precision={item.decimal} onPressEnter={this.handleSubmit}/>)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select
+                  showSearch
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  onChange={(value, option) => {this.typeChange(item.key, value, option)}}
+                  getPopupContainer={() => document.getElementById('columnwinter')}
+                >
+                  {item.options.map((option, index) =>
+                    <Select.Option key={index} datatype={option.datatype || ''} value={(option.value || option.field || option.MenuID)}>
+                      {(option.text || option.label || option.MenuName)}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group onChange={(e) => {this.changeRadio(item.key, e.target.value)}}>
+                  {
+                    item.options.map(option => {
+                      return (
+                        <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                      )
+                    })
+                  }
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'multiselect') { // 澶氶��
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || []
+              })(
+                <Select
+                  showSearch
+                  mode="multiple"
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                >
+                  {item.options.map((option, i) =>
+                    <Select.Option id={i} key={i} value={option.value || option.field}>{option.text || option.label}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'cascader') { // 澶氶��
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || [],
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Cascader
+                  options={item.options}
+                  placeholder=""
+                  getPopupContainer={() => document.getElementById('columnwinter')}
+                />
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'textarea') { // 鏂囨湰鎼滅储
+        fields.push(
+          <Col span={24} key={index} className="textarea">
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<TextArea rows={2} disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    return fields
+  }
+
+  handleSubmit = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        this.setState({visible: false, formlist: null})
+        this.props.submitCol(values)
+      }
+    })
+  }
+
+  editModalCancel = () => {
+    this.setState({visible: false, formlist: null})
+
+    this.props.cancelCol()
+  }
+
+  render() {
+    const { visible } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+
+    return (
+      <div style={{display: 'inline-block'}}>
+        <Modal
+          title="鏄剧ず鍒楃紪杈�"
+          visible={visible}
+          width={800}
+          maskClosable={false}
+          onOk={this.handleSubmit}
+          onCancel={this.editModalCancel}
+          destroyOnClose
+        >
+          <Form {...formItemLayout} className="commontable-column-form" id="columnwinter">
+            <Row gutter={24}>{this.getFields()}</Row>
+          </Form>
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/menu/components/table/edit-table/columns/editColumn/index.scss b/src/menu/components/table/edit-table/columns/editColumn/index.scss
new file mode 100644
index 0000000..e450762
--- /dev/null
+++ b/src/menu/components/table/edit-table/columns/editColumn/index.scss
@@ -0,0 +1,27 @@
+.commontable-column-form {
+  min-height: 190px;
+  .ant-form-item {
+    .ant-input-number {
+      width: 100%;
+    }
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+  .ant-cascader-menus {
+    padding: 5px 0px;
+    .ant-cascader-menu:last-child {
+      padding-right: 3px;
+    }
+  }
+  .textarea {
+    .ant-form-item-label {
+      width: 12%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 88%;
+    }
+  }
+}
diff --git a/src/menu/components/table/edit-table/columns/index.jsx b/src/menu/components/table/edit-table/columns/index.jsx
new file mode 100644
index 0000000..c347313
--- /dev/null
+++ b/src/menu/components/table/edit-table/columns/index.jsx
@@ -0,0 +1,601 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { DndProvider, DragSource, DropTarget } from 'react-dnd'
+import { Table, Popover, Icon, Modal, message } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const { confirm } = Modal
+const EditColumn = asyncIconComponent(() => import('./editColumn'))
+const MarkColumn = asyncIconComponent(() => import('@/menu/components/share/markcomponent'))
+const CardCellComponent = asyncComponent(() => import('@/menu/components/card/cardcellcomponent'))
+
+class HeaderCol extends Component {
+  deleteCol = () => {
+    const _this = this
+
+    confirm({
+      content: '纭畾鍒犻櫎鏄剧ず鍒楀悧锛�',
+      onOk() {
+        _this.props.deleteCol(_this.props.column)
+      },
+      onCancel() {}
+    })
+  }
+
+  updateMarks = (vals) => {
+    const { column } = this.props
+    this.props.updateCol({...column, marks: vals})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+
+    if (this.props.rowSpan !== nextProps.rowSpan || this.props.colSpan !== nextProps.colSpan) {
+      return true
+    }
+
+    if (!nextProps.column) return false
+
+    return !is(fromJS(this.props.column), fromJS(nextProps.column)) ||
+      !is(fromJS(this.props.fields), fromJS(nextProps.fields)) ||
+      this.props.index !== nextProps.index
+  }
+
+  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', 'colspan', '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', 'colspan'].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>)
+    }
+  }
+}
+
+const rowSource = {
+  beginDrag(props) {
+    return {
+      index: props.index,
+    }
+  }
+}
+
+const ColTarget = {
+  drop(props, monitor) {
+    const dragIndex = monitor.getItem().index
+    const hoverIndex = props.index
+
+    if (dragIndex === undefined || hoverIndex === undefined || dragIndex === hoverIndex) {
+      return
+    }
+
+    props.moveCol(dragIndex, hoverIndex)
+    monitor.getItem().index = hoverIndex
+  },
+}
+
+const DragableHeaderCol = DropTarget('col', ColTarget, connect => ({
+  connectDropTarget: connect.dropTarget()
+}))(
+  DragSource('col', rowSource, connect => ({
+    connectDragSource: connect.dragSource(),
+  }))(HeaderCol),
+)
+
+class EditableColumnCell extends Component {
+  updateCard = (vals, btn) => {
+    const { column } = this.props
+    this.props.upComponent({...column, elements: vals}, btn)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    const { config, column } = this.props
+
+    if (!nextProps.column) return true
+
+    return !is(fromJS(column), fromJS(nextProps.column)) ||
+      !is(fromJS(config.columns), fromJS(nextProps.config.columns)) ||
+      !is(fromJS(config.action), fromJS(nextProps.config.action)) ||
+      !is(fromJS(config.search), fromJS(nextProps.config.search))
+  }
+
+  render() {
+    const { column, config, children, className, style } = this.props
+
+    if (column && column.type === 'custom') {
+      return (
+        <td style={{padding: 0, minWidth: column.Width || 100, ...(column.style || {})}} className={className}>
+          <CardCellComponent cards={config} cardCell={column} elements={column.elements} updateElement={this.updateCard}/>
+        </td>
+      )
+    } else if (column && column.type === 'action') {
+      return (
+        <td style={{padding: '0 5px', textAlign: column.Align, minWidth: column.Width || 100}} className={'action-column ' + className}>
+          <CardCellComponent cards={config} cardCell={column} elements={column.elements} updateElement={this.updateCard}/>
+        </td>
+      )
+    } else if (column) {
+      return (
+        <td style={{...style, minWidth: column.Width || 100}} className={className}>
+          {column.field || (column.type === 'index' ? '$Index' : '')}
+          {column.Hide === 'true' ? <Icon style={{marginLeft: '5px', color: 'orange', fontSize: '12px'}} type="close-circle" /> : null}
+          {column.marks && column.marks.length ? <Icon className="profile" type="ant-design"/> : null}
+        </td>
+      )
+    } else {
+      return (
+        <td style={style} className={className}>
+          {children}
+        </td>
+      )
+    }
+  }
+}
+
+class NormalTableColumns extends Component {
+  static propTpyes = {
+    config: PropTypes.object,       // 閰嶇疆淇℃伅
+    updatecolumn: PropTypes.func    // 鏁版嵁鍙樺寲
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
+    tableId: '',
+    data: [{uuid: Utils.getuuid()}],
+    refresh: false,    // 寮哄埗鍒锋柊
+    columns: [],
+    fields: [],
+    editStyleCard: null,
+    lineMarks: []
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    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 (config.wrap && config.wrap.borderColor) { // 杈规棰滆壊
+      let style = `#${tableId} table, #${tableId} tr, #${tableId} th, #${tableId} td {border-color: ${config.wrap.borderColor}}`
+      let ele = document.createElement('style')
+      ele.innerHTML = style
+      document.getElementsByTagName('head')[0].appendChild(ele)
+    }
+
+    this.setState({
+      tableId,
+      columns: fromJS(config.cols).toJS(),
+      fields: fromJS(config.columns).toJS(),
+      lineMarks: config.lineMarks ? fromJS(config.lineMarks).toJS() : []
+    })
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    if (!is(fromJS(this.state.columns), fromJS(nextProps.config.cols))) {
+      let _columns = fromJS(nextProps.config.cols).toJS()
+      this.setState({columns: _columns})
+      let lastcol = _columns.slice(-1)[0]
+      if (lastcol && lastcol.focus) {
+        this.editColumn(lastcol)
+      }
+    } else if (!is(fromJS(this.state.fields), fromJS(nextProps.config.columns))) {
+      this.setState({fields: fromJS(nextProps.config.columns).toJS()})
+    } else if (this.props.config.wrap.borderColor !== nextProps.config.wrap.borderColor) {
+      let style = `#${this.state.tableId} table, #${this.state.tableId} tr, #${this.state.tableId} th, #${this.state.tableId} td {border-color: ${nextProps.config.wrap.borderColor}}`
+      let ele = document.createElement('style')
+      ele.innerHTML = style
+      document.getElementsByTagName('head')[0].appendChild(ele)
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    const { config } = this.props
+
+    return !is(fromJS(this.state), fromJS(nextState)) ||
+      !is(fromJS(config.wrap), fromJS(nextProps.config.wrap)) ||
+      !is(fromJS(config.search), fromJS(nextProps.config.search)) ||
+      !is(fromJS(config.action), fromJS(nextProps.config.action)) ||
+      config.setting.laypage !== nextProps.config.setting.laypage
+  }
+
+  moveCol = (dragIndex, hoverIndex) => {
+    let _columns = fromJS(this.state.columns).toJS()
+
+    _columns.splice(hoverIndex, 0, ..._columns.splice(dragIndex, 1))
+
+    this.setState({
+      columns: _columns
+    }, () => {
+      this.props.updatecolumn({...this.props.config, cols: _columns})
+    })
+  }
+
+  loopCol = (columns, col) => {
+    return columns.map(column => {
+      if (column.type === 'colspan') {
+        column.subcols = this.loopCol(column.subcols, col)
+      }
+      if (column.uuid === col.uuid) {
+        return col
+      }
+      return column
+    })
+  }
+
+  updateCol = (col, btn) => {
+    let _columns = fromJS(this.state.columns).toJS()
+    _columns = this.loopCol(_columns, col)
+
+    this.setState({
+      columns: _columns,
+    }, () => {
+      let config = {...this.props.config, cols: _columns}
+      if (btn) {
+        config.action = config.action.filter(item => item.uuid !== btn.uuid)
+      }
+
+      this.props.updatecolumn(config)
+    })
+  }
+
+  editColumn = (col) => {
+    this.setState({
+      card: fromJS(col).toJS()
+    })
+  }
+
+  addElement = (col) => {
+    const { config } = this.props
+    let column = fromJS(col).toJS()
+
+    if (column.type === 'colspan') {
+      column.subcols = column.subcols || []
+      let subcol = { isSub: true, focus: true, uuid: Utils.getuuid(), label: 'label', field: '', type: 'text' }
+      column.subcols.push(subcol)
+
+      this.setState({
+        card: subcol
+      })
+      this.updateCol(column)
+    } else if (column.type === 'custom') {
+      let newcard = {uuid: Utils.getuuid(), focus: true, eleType: 'text', datatype: 'dynamic', style: {paddingLeft: '4px'}}
+  
+      // 娉ㄥ唽浜嬩欢-娣诲姞鍏冪礌
+      MKEmitter.emit('cardAddElement', [config.uuid, column.uuid], newcard)
+    } else if (column.type === 'action') {
+      let newcard = {
+        uuid: Utils.getuuid(),
+        focus: true,
+        eleType: 'button',
+        label: 'button',
+        OpenType: 'prompt',
+        class: 'primary',
+        intertype: 'system',
+        execSuccess: 'grid',
+        execError: 'never',
+        show: 'link',
+        $type: 'tableButton'
+      }
+
+      // 娉ㄥ唽浜嬩欢-娣诲姞鍏冪礌
+      MKEmitter.emit('cardAddElement', [config.uuid, column.uuid], newcard)
+    }
+  }
+
+  submitCol = (col) => {
+    const { card } = this.state
+
+    col.uuid = card.uuid
+    col.isSub = card.isSub === true
+    col.marks = card.marks || []
+    
+    if (col.type === 'colspan') {
+      col.subcols = card.subcols || []
+    } else if (col.type === 'custom') {
+      col.elements = card.type === 'custom' ? (card.elements || []) : []
+    } else if (col.type === 'action') {
+      col.elements = card.type === 'action' ? (card.elements || []) : []
+    }
+
+    this.setState({card: null})
+    this.updateCol(col)
+  }
+
+  changeStyle = (col) => {
+    this.setState({
+      editStyleCard: fromJS(col).toJS()
+    })
+
+    MKEmitter.emit('changeStyle', [col.uuid], ['font', 'padding'], col.style || {})
+  }
+
+  getStyle = (comIds, style) => {
+    const { editStyleCard } = this.state
+
+    if (!editStyleCard || comIds[0] !== editStyleCard.uuid || comIds.length !== 1) return
+
+    let _card = {...editStyleCard, style}
+    
+    this.updateCol(_card)
+  }
+
+  cancelCol = () => {
+    const { card } = this.state
+
+    if (card.focus) {
+      this.deleteCol(card)
+    }
+
+    this.setState({card: null})
+  }
+
+  loopDelCol = (columns, col) => {
+    return columns.filter(column => {
+      if (column.type === 'colspan') {
+        column.subcols = this.loopDelCol(column.subcols, col)
+      }
+      return column.uuid !== col.uuid
+    })
+  }
+
+  deleteCol = (col) => {
+    const { appType } = this.state
+    let _columns = fromJS(this.state.columns).toJS()
+
+    _columns = this.loopDelCol(_columns, col)
+
+    this.setState({
+      columns: _columns
+    }, () => {
+      this.props.updatecolumn({...this.props.config, cols: _columns})
+    })
+
+    if (col.type !== 'action' || appType === 'mob') return
+
+    let uuids = []
+    col.elements && col.elements.forEach(c => {
+      if (appType === 'pc' && c.OpenType !== 'popview') return
+
+      uuids.push(c.uuid)
+    })
+
+    if (uuids.length === 0) return
+    
+    MKEmitter.emit('delButtons', uuids)
+  }
+
+  updateLineMarks = (vals) => {
+    this.setState({
+      lineMarks: vals
+    }, () => {
+      this.props.updatecolumn({...this.props.config, lineMarks: vals})
+    })
+  }
+
+  /**
+   * @description 鏄剧ず鍒楀鍒�
+   */
+  copycolumn = () => {
+    const { columns } = this.state
+
+    let oInput = document.createElement('input')
+    let val = {
+      copyType: 'cols',
+      cols: columns.filter(col => !col.origin)
+    }
+
+    oInput.value = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
+    document.body.appendChild(oInput)
+    oInput.select()
+    document.execCommand('Copy')
+    oInput.className = 'oInput'
+    oInput.style.display = 'none'
+
+    message.success('澶嶅埗鎴愬姛銆�')
+
+    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()
+
+    columns = columns.filter(c => !c.origin)
+
+    let keys = columns.map(col => col.field)
+
+    fields.forEach(item => {
+      if (keys.includes(item.field)) return
+
+      let cell = { uuid: Utils.getuuid(), label: item.label, field: item.field, Align: 'left', Hide: 'false', IsSort: 'true', Width: 120, blacklist: [], postfix: '', prefix: '', linkmenu: [], marks: [], perspective: 'linkmenu' }
+      
+      if (/Nvarchar/ig.test(item.datatype)) {
+        cell.type = 'text'
+        cell.rowspan = 'false'
+        cell.textFormat = 'none'
+      } else {
+        cell.type = 'number'
+        cell.format = 'none'
+        cell.sum = 'false'
+        cell.decimal = item.decimal || 0
+      }
+
+      columns.push(cell)
+    })
+
+    const _this = this
+
+    confirm({
+      content: '纭畾鍚屾瀛楁闆嗗悧锛�',
+      onOk() {
+        _this.setState({columns}, () => {
+          _this.props.updatecolumn({..._this.props.config, cols: columns})
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  clear = () => {
+    const _this = this
+
+    confirm({
+      content: '纭畾娓呯┖鏄剧ず鍒楀悧锛�',
+      onOk() {
+        _this.setState({columns: []}, () => {
+          _this.props.updatecolumn({..._this.props.config, cols: []})
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+  }
+
+  render() {
+    const { config } = this.props
+    const { fields, card, lineMarks, dict, tableId } = this.state
+    const components = {
+      header: {
+        cell: DragableHeaderCol
+      },
+      body: {
+        cell: EditableColumnCell
+      }
+    }
+
+    const columns = this.handlecolumns(this.state.columns, fields, config)
+
+    let style = {}
+    if (config.wrap.color) {
+      style.color = config.wrap.color
+    }
+    if (config.wrap.fontSize) {
+      style.fontSize = config.wrap.fontSize
+    }
+
+    return (
+      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${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} />
+          <Icon title="鍚屾瀛楁闆�" type="file-sync" onClick={this.syncfield} />
+          <Icon title="娓呯┖鏄剧ず鍒�" type="delete" onClick={this.clear}/>
+        </div>
+        <DndProvider>
+          <Table
+            rowKey="uuid"
+            size={config.wrap.size || 'middle'}
+            rowClassName="editable-row"
+            style={style}
+            bordered={config.wrap.bordered !== 'false'}
+            components={components}
+            dataSource={this.state.data}
+            rowSelection={config.wrap.tableType ? { type: 'radio' } : null}
+            columns={columns}
+            pagination={{
+              current: 1,
+              pageSize: 10,
+              pageSizeOptions: ['10', '25', '50', '100', '500', '1000'],
+              showSizeChanger: true,
+              total: 58,
+              showTotal: (total, range) => `${range[0]}-${range[1]} 鍏� ${total} 鏉
+            }}
+          />
+        </DndProvider>
+        <EditColumn column={card} dict={dict} fields={fields} submitCol={this.submitCol} cancelCol={this.cancelCol}/>
+      </div>
+    )
+  }
+}
+
+export default NormalTableColumns
\ No newline at end of file
diff --git a/src/menu/components/table/edit-table/columns/index.scss b/src/menu/components/table/edit-table/columns/index.scss
new file mode 100644
index 0000000..f376b55
--- /dev/null
+++ b/src/menu/components/table/edit-table/columns/index.scss
@@ -0,0 +1,124 @@
+.normal-table-columns {
+  position: relative;
+  .ant-table {
+    color: inherit;
+    font-size: inherit;
+  }
+  .ant-table-body {
+    overflow-x: auto;
+    tr {
+      td {
+        background: #ffffff;
+      }
+      td:not(.ant-table-selection-column) {
+        position: relative;
+        padding: 12px 8px;
+        >.profile {
+          position: absolute;
+          top: 2px;
+          right: 2px;
+          color: purple;
+          font-size: 12px;
+        }
+      }
+    }
+    .action-column {
+      .card-detail-row:empty {
+        min-height: 40px;
+      }
+    }
+    tr:hover td {
+      background: #ffffff!important;
+    }
+  }
+
+  .ant-table-thead {
+    th {
+      position: relative;
+      .ant-table-column-sorter::before {
+        position: absolute;
+        top: 0;
+        right: 0;
+        bottom: 0;
+        left: 0;
+        content: '';
+      }
+    }
+    > tr > th {
+      padding: 12px 8px;
+      .ant-table-column-sorter .ant-table-column-sorter-inner {
+        .ant-table-column-sorter-up.on, .ant-table-column-sorter-down.on {
+          color: unset;
+        }
+      }
+    }
+  }
+  .col-control {
+    position: absolute;
+    z-index: 2;
+    right: 0;
+    top: -25px;
+    >i, >div > i {
+      font-size: 16px;
+      margin-right: 10px;
+      cursor: pointer;
+    }
+    >.anticon-copy {
+      color: #26C281;
+    }
+    >.anticon-delete {
+      color: #ff4d4f;
+    }
+    >.anticon-file-sync {
+      color: #1890ff;
+    }
+    >div >.profile {
+      color: purple;
+    }
+  }
+  .ant-table-small > .ant-table-content > .ant-table-body {
+    margin: 0;
+  }
+}
+.normal-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 {
+  .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;
+      }
+    }
+    tr:hover td {
+      background: transparent!important;
+    }
+  }
+}
diff --git a/src/menu/components/table/edit-table/index.jsx b/src/menu/components/table/edit-table/index.jsx
new file mode 100644
index 0000000..00d7aac
--- /dev/null
+++ b/src/menu/components/table/edit-table/index.jsx
@@ -0,0 +1,422 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover, notification } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import { resetStyle } from '@/utils/utils-custom.js'
+import MKEmitter from '@/utils/events.js'
+import getWrapForm from './options'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+
+import './index.scss'
+
+const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
+const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
+const SearchComponent = asyncComponent(() => import('@/templates/sharecomponent/searchcomponent'))
+const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent'))
+const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
+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 {
+  static propTpyes = {
+    card: PropTypes.object,
+    deletecomponent: PropTypes.func,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
+    card: null,
+    back: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        tabId: card.tabId || '',
+        parentId: card.parentId || '',
+        format: 'array',    // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: true,     // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: true,   // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        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' },
+        style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px' },
+        headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
+        columns: [],
+        cols: [
+          { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label1', field: '', Hide: 'false', type: 'text', Width: 120 },
+          { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label2', field: '', Hide: 'false', IsSort: 'true', type: 'text', Width: 120 },
+          { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label3', field: '', Hide: 'false', IsSort: 'true', type: 'text', Width: 120 },
+        ],
+        scripts: [],
+        btnlog: [],
+        isNew: true
+      }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.wrap = config.wrap
+        _card.wrap.name = card.name
+        _card.style = config.style
+        _card.headerStyle = config.headerStyle
+
+        let oriUids = {}
+        _card.action = config.action.map(item => {
+          let _uuid = Utils.getuuid()
+          oriUids[item.uuid] = _uuid
+          item.uuid = _uuid
+          return item
+        })
+        _card.search = config.search.map(item => {
+          item.uuid = Utils.getuuid()
+          return item
+        })
+        _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) {
+            col.elements = col.elements.map(cell => {
+              cell.uuid = Utils.getuuid()
+              return cell
+            })
+          } else if (col.type === 'action' && col.elements) {
+            col.elements = col.elements.map(cell => {
+              cell.uuid = Utils.getuuid()
+              return cell
+            })
+          }
+          return col
+        })
+        
+        if (_card.wrap.doubleClick) {
+          _card.wrap.doubleClick = oriUids[_card.wrap.doubleClick] || ''
+        }
+      }
+      
+      this.setState({
+        card: _card
+      })
+
+      this.filterOrigin(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+    MKEmitter.addListener('submitModal', this.handleSave)
+    MKEmitter.addListener('logButton', this.logButton)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    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
+
+      this.props.updateConfig(item)
+    } else {
+      this.props.updateConfig(component)
+    }
+  }
+
+  /**
+   * @description 鍗$墖琛屽灞備俊鎭洿鏂帮紙鏁版嵁婧愶紝鏍峰紡绛夛級
+   */
+  updateComponent = (component) => {
+    this.setState({
+      card: component
+    })
+
+    component.width = component.wrap.width
+    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 = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'border', 'padding', 'margin', 'shadow'], card.style)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds[0] !== card.uuid) return
+
+    let _card = {}
+    if (comIds.length === 1) {
+      _card = {...card, style}
+    } else {
+      return
+    }
+
+    this.setState({
+      card: _card
+    })
+    
+    this.filterOrigin(_card)
+  }
+
+  addColumns = () => {
+    let card = fromJS(this.state.card).toJS()
+
+    card.cols.push({ focus: true, uuid: Utils.getuuid(), label: 'label', field: '', type: 'text' })
+
+    this.setState({card})
+  }
+
+  addSearch = () => {
+    let card = fromJS(this.state.card).toJS()
+
+    card.search.push({uuid: Utils.getuuid(), focus: true, label: 'label', type: 'text', match: '='})
+
+    this.setState({card})
+  }
+
+  addButton = () => {
+    const { card } = this.state
+
+    let newcard = {}
+    newcard.uuid = Utils.getuuid()
+    newcard.focus = true
+    
+    newcard.label = 'label'
+    newcard.sqlType = ''
+    newcard.Ot = 'requiredSgl'
+    newcard.OpenType = 'pop'
+    newcard.icon = ''
+    newcard.class = 'green'
+    newcard.intertype = card.setting.interType || 'system'
+    newcard.innerFunc = card.setting.innerFunc || ''
+    newcard.sysInterface = card.setting.sysInterface || ''
+    newcard.outerFunc = card.setting.outerFunc || ''
+    newcard.interface = card.setting.interface || ''
+    newcard.execSuccess = 'grid'
+    newcard.execError = 'never'
+    newcard.verify = null
+    newcard.show = 'button'
+    newcard.style = {marginRight: '15px'}
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鎸夐挳
+    MKEmitter.emit('addButton', card.uuid, newcard)
+  }
+
+  /**
+   * @description 鏇存柊鎼滅储鏉′欢閰嶇疆淇℃伅
+   */
+  updateconfig = (config) => {
+    this.setState({
+      card: config
+    })
+    this.filterOrigin(config)
+  }
+
+  setSubConfig = (item) => {
+    const { card, appType } = this.state
+    let btn = fromJS(item).toJS()
+
+    if (btn.OpenType === 'pop' || btn.execMode === 'pop') {
+      if (!btn.modal) {
+        btn.modal = {
+          setting: { title: btn.label, width: appType === 'mob' ? 100 : 60, cols: '2', container: 'view', focus: '', finish: 'close', clickouter: 'unclose', display: 'modal' },
+          tables: [],
+          groups: [],
+          fields: []
+        }
+      }
+      MKEmitter.emit('changeModal', card, btn)
+    } else if (btn.OpenType === 'popview') {
+      MKEmitter.emit('changePopview', card, btn)
+    }
+  }
+
+  handleSave = (_cards, btn, modal) => {
+    let card = fromJS(this.state.card).toJS()
+
+    if (card.uuid !== _cards.uuid) return
+
+    let _index = card.action.findIndex(cell => cell.uuid === btn.uuid)
+
+    if (_index === -1) return
+
+    card.action = card.action.map(cell => {
+      if (cell.uuid === btn.uuid) {
+        cell.modal = modal
+      }
+
+      return cell
+    })
+
+    this.setState({card})
+    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
+
+    return getWrapForm(wrap, action)
+  }
+
+  updateWrap = (res) => {
+    this.updateComponent({...this.state.card, wrap: res})
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card)
+    }
+  }
+
+  render() {
+    const { card, appType } = this.state
+    let _style = resetStyle(card.style)
+
+    return (
+      <div className="menu-normal-table-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
+        <NormalHeader defaultshow="hidden" hideSearch="true" config={card} updateComponent={this.updateComponent}/>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <Icon className="plus" title="娣诲姞鍒�" onClick={this.addColumns} type="plus" />
+            {appType !== 'mob' ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" /> : null}
+            <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" />
+            <NormalForm title="琛ㄦ牸璁剧疆" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
+              <Icon type="edit" style={{color: '#1890ff'}} title="缂栬緫"/>
+            </NormalForm>
+            <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} />
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
+        <SearchComponent config={card} updatesearch={this.updateconfig}/>
+        <ActionComponent config={card} setSubConfig={this.setSubConfig} updateaction={this.updateComponent}/>
+        <ColumnComponent config={card} updatecolumn={this.updateconfig}/>
+      </div>
+    )
+  }
+}
+
+export default TableCardEditComponent
\ No newline at end of file
diff --git a/src/menu/components/table/edit-table/index.scss b/src/menu/components/table/edit-table/index.scss
new file mode 100644
index 0000000..f933a19
--- /dev/null
+++ b/src/menu/components/table/edit-table/index.scss
@@ -0,0 +1,80 @@
+.menu-normal-table-edit-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 100px;
+  
+  .model-table-search-list {
+    padding: 10px 0px 15px;
+    min-height: 65px;
+    border-bottom: 1px solid #f0f0f0;
+    >.anticon-question-circle {
+      display: none;
+    }
+    .page-card {
+      background: transparent;
+    }
+    .quickly-add {
+      display: inline-block;
+      position: absolute;
+      z-index: 3;
+      right: 70px;
+      bottom: 5px;
+      .ant-btn-block {
+        background-color: transparent;
+        color: #1890ff;
+        border: none;
+        box-shadow: none !important;
+        height: 18px;
+        padding: 0 10px;
+      }
+    }
+  }
+  .model-table-search-list.length0 {
+    display: none;
+  }
+  .anticon-tool {
+    position: absolute;
+    z-index: 2;
+    font-size: 16px;
+    right: 1px;
+    top: 1px;
+    cursor: pointer;
+    padding: 5px;
+    background: rgba(255, 255, 255, 0.55);
+  }
+  .model-menu-action-list {
+    line-height: 55px;
+    padding: 0px;
+    min-height: 55px;
+    >.ant-row {
+      min-height: 30px;
+    }
+  }
+  .card-add-button {
+    text-align: right;
+    clear: left;
+    .anticon-plus {
+      font-size: 20px;
+      color: #26C281;
+      padding: 5px;
+      margin-right: 10px;
+    }
+  }
+
+  .ant-btn.mk-link {
+    padding: 0;
+  }
+}
+.menu-normal-table-edit-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.menu-normal-table-edit-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
diff --git a/src/menu/components/table/edit-table/options.jsx b/src/menu/components/table/edit-table/options.jsx
new file mode 100644
index 0000000..acfc1be
--- /dev/null
+++ b/src/menu/components/table/edit-table/options.jsx
@@ -0,0 +1,204 @@
+/**
+ * @description Wrap琛ㄥ崟閰嶇疆淇℃伅
+ */
+export default function (wrap, action = []) {
+  let roleList = sessionStorage.getItem('sysRoles')
+  let appType = sessionStorage.getItem('appType')
+
+  if (roleList) {
+    try {
+      roleList = JSON.parse(roleList)
+    } catch (e) {
+      roleList = []
+    }
+  } else {
+    roleList = []
+  }
+
+  const wrapForm = [
+    {
+      type: 'text',
+      field: 'title',
+      label: '鏍囬',
+      initval: wrap.title || '',
+      required: false
+    },
+    {
+      type: 'text',
+      field: 'name',
+      label: '缁勪欢鍚嶇О',
+      initval: wrap.name || '',
+      tooltip: '鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�',
+      required: true
+    },
+    {
+      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',
+      required: false,
+      options: [
+        {value: 'true', label: '鏈�'},
+        {value: 'false', label: '鏃�'},
+      ]
+    },
+    {
+      type: 'radio',
+      field: 'tableHeader',
+      label: '琛ㄥご',
+      initval: wrap.tableHeader || 'show',
+      required: false,
+      options: [
+        {value: 'show', label: '鏄剧ず'},
+        {value: 'hidden', label: '闅愯棌'},
+      ]
+    },
+    {
+      type: 'radio',
+      field: 'size',
+      label: '琛ㄦ牸澶у皬',
+      initval: wrap.size || 'middle',
+      tooltip: '琛ㄦ牸鐨勫唴杈硅窛锛屼粠澶у埌灏忎緷娆¢�掑噺銆�',
+      required: false,
+      options: [
+        {value: 'default', label: '澶�'},
+        {value: 'middle', label: '涓�'},
+        {value: 'small', label: '灏�'},
+        // {value: 'mini', label: '寰�'},
+      ]
+    },
+    {
+      type: 'radio',
+      field: 'mode',
+      label: '妯″紡',
+      initval: wrap.mode || 'default',
+      required: false,
+      options: [
+        {value: 'default', label: '甯歌'},
+        {value: 'ghost', label: '閫忔槑'},
+      ]
+    },
+    {
+      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',
+      tooltip: '鎼滅储鏉′欢瀛樺湪鏃讹紝鍙�夋嫨鏄惁鏄剧ず鎼滅储鎸夐挳銆�',
+      required: false,
+      options: [
+        {value: 'true', label: '鏄剧ず'},
+        {value: 'false', label: '闅愯棌'},
+      ]
+    },
+    {
+      type: 'color',
+      field: 'borderColor',
+      label: '杈规棰滆壊',
+      initval: wrap.borderColor || '#e8e8e8',
+      tooltip: '榛樿鍊� #e8e8e8銆�',
+      required: false
+    },
+    {
+      type: 'color',
+      field: 'color',
+      label: '瀛椾綋棰滆壊',
+      initval: wrap.color || 'rgba(0, 0, 0, 0.65)',
+      tooltip: '榛樿鍊� rgba(0, 0, 0, 0.65)銆�',
+      required: false
+    },
+    {
+      type: 'number',
+      field: 'width',
+      label: '瀹藉害',
+      initval: wrap.width || 24,
+      tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��',
+      min: 1,
+      max: 24,
+      precision: 0,
+      required: true
+    },
+    {
+      type: 'number',
+      field: 'fontSize',
+      label: '瀛椾綋澶у皬',
+      initval: wrap.fontSize || 14,
+      min: 12,
+      max: 30,
+      precision: 0,
+      required: false
+    },
+    {
+      type: 'number',
+      field: 'height',
+      label: '楂樺害',
+      initval: wrap.height || '',
+      tooltip: '琛ㄦ牸楂樺害锛岀┖鍊兼椂楂樺害鑷�傚簲銆�',
+      min: 10,
+      max: 3000,
+      precision: 0,
+      required: false,
+      forbid: appType === 'mob'
+    },
+    {
+      type: 'number',
+      field: 'advanceWidth',
+      label: '楂樼骇鎼滅储',
+      initval: wrap.advanceWidth || 1000,
+      tooltip: '楂樼骇鎼滅储寮圭獥鐨勫搴︼紝娉細褰撳搴﹀�煎皬浜�100鏃惰〃绀哄崰绐楀彛鐨勭櫨鍒嗘瘮锛屽ぇ浜�100鏃惰〃绀哄搴︾殑缁濆鍊笺��',
+      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'
+    },
+    {
+      type: 'multiselect',
+      field: 'blacklist',
+      label: '榛戝悕鍗�',
+      initval: wrap.blacklist || [],
+      required: false,
+      options: roleList,
+      forbid: !!appType
+    },
+  ]
+
+  return wrapForm
+} 
\ No newline at end of file
diff --git a/src/menu/components/tabs/tabcomponents/card.jsx b/src/menu/components/tabs/tabcomponents/card.jsx
index bfc1471..e80787f 100644
--- a/src/menu/components/tabs/tabcomponents/card.jsx
+++ b/src/menu/components/tabs/tabcomponents/card.jsx
@@ -20,6 +20,7 @@
 const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
 const TabForm = asyncComponent(() => import('@/menu/components/form/tab-form'))
 const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
+const EditTable = asyncComponent(() => import('@/menu/components/table/edit-table'))
 const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
 const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
 const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
@@ -88,6 +89,8 @@
       return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'table' && card.subtype === 'normaltable') {
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'table' && card.subtype === 'editable') {
+      return (<EditTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
       return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
diff --git a/src/menu/menushell/card.jsx b/src/menu/menushell/card.jsx
index 327482c..8195ed1 100644
--- a/src/menu/menushell/card.jsx
+++ b/src/menu/menushell/card.jsx
@@ -18,6 +18,7 @@
 const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
 const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
+const EditTable = asyncComponent(() => import('@/menu/components/table/edit-table'))
 const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
 const TabForm = asyncComponent(() => import('@/menu/components/form/tab-form'))
 const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
@@ -88,6 +89,8 @@
       return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'table' && card.subtype === 'normaltable') {
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'table' && card.subtype === 'editable') {
+      return (<EditTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
       return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
diff --git a/src/menu/modulesource/option.jsx b/src/menu/modulesource/option.jsx
index dfdb100..55bebce 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: 'normaltable', 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/pc/menushell/card.jsx b/src/pc/menushell/card.jsx
index 6e114c7..45a2108 100644
--- a/src/pc/menushell/card.jsx
+++ b/src/pc/menushell/card.jsx
@@ -15,6 +15,7 @@
 const NormalTree = asyncComponent(() => import('@/menu/components/tree/antd-tree'))
 const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
+const EditTable = asyncComponent(() => import('@/menu/components/table/edit-table'))
 const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
 const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
 const TabForm = asyncComponent(() => import('@/menu/components/form/tab-form'))
@@ -108,6 +109,8 @@
       return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'table' && card.subtype === 'normaltable') {
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'table' && card.subtype === 'editable') {
+      return (<EditTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
       return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
diff --git a/src/pc/quotecomponent/settingform/index.jsx b/src/pc/quotecomponent/settingform/index.jsx
index e575e0d..96a871f 100644
--- a/src/pc/quotecomponent/settingform/index.jsx
+++ b/src/pc/quotecomponent/settingform/index.jsx
@@ -2,8 +2,6 @@
 import PropTypes from 'prop-types'
 import { Form, Row, Col, Select } from 'antd'
 
-import './index.scss'
-
 class SettingForm extends Component {
   static propTpyes = {
     dict: PropTypes.object,      // 瀛楀吀椤�
diff --git a/src/pc/quotecomponent/settingform/index.scss b/src/pc/quotecomponent/settingform/index.scss
index 159130b..e69de29 100644
--- a/src/pc/quotecomponent/settingform/index.scss
+++ b/src/pc/quotecomponent/settingform/index.scss
@@ -1,11 +0,0 @@
-.model-menu-setting-form {
-  position: relative;
-
-  .anticon-question-circle {
-    color: #c49f47;
-    margin-right: 3px;
-  }
-  .ant-input-number {
-    width: 100%;
-  }
-}
\ No newline at end of file
diff --git a/src/pc/transfer/index.jsx b/src/pc/transfer/index.jsx
index d2fb44e..655e0a9 100644
--- a/src/pc/transfer/index.jsx
+++ b/src/pc/transfer/index.jsx
@@ -7,7 +7,6 @@
 import enUS from '@/locales/en-US/model.js'
 import SettingForm from './settingform'
 import Api from '@/api'
-import './index.scss'
 
 class TransferWrap extends Component {
   static propTpyes = {
diff --git a/src/tabviews/zshare/mutilform/index.jsx b/src/tabviews/zshare/mutilform/index.jsx
index 2525408..184bddf 100644
--- a/src/tabviews/zshare/mutilform/index.jsx
+++ b/src/tabviews/zshare/mutilform/index.jsx
@@ -535,7 +535,7 @@
   }
 
   resetFormList = (result) => {
-    let _formlist = this.state.formlist.map(item => {
+    let _formlist = fromJS(this.state.formlist).toJS().map(item => {
       if (['select', 'link', 'radio', 'checkbox', 'checkcard', 'multiselect'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
         let options = []
         result[item.field].forEach(cell => {
diff --git a/src/tabviews/zshare/mutilform/mkCheckbox/index.jsx b/src/tabviews/zshare/mutilform/mkCheckbox/index.jsx
index 12091c4..5742e0b 100644
--- a/src/tabviews/zshare/mutilform/mkCheckbox/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkCheckbox/index.jsx
@@ -2,8 +2,6 @@
 import PropTypes from 'prop-types'
 import { Checkbox } from 'antd'
 
-import './index.scss'
-
 class MKCheckbox extends Component {
   static propTpyes = {
     config: PropTypes.object,
diff --git a/src/tabviews/zshare/mutilform/mkDatePicker/index.jsx b/src/tabviews/zshare/mutilform/mkDatePicker/index.jsx
index ad7558d..3d4377b 100644
--- a/src/tabviews/zshare/mutilform/mkDatePicker/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkDatePicker/index.jsx
@@ -3,8 +3,6 @@
 import { DatePicker } from 'antd'
 import moment from 'moment'
 
-import './index.scss'
-
 const { MonthPicker } = DatePicker
 
 /**
diff --git a/src/tabviews/zshare/mutilform/mkRadio/index.jsx b/src/tabviews/zshare/mutilform/mkRadio/index.jsx
index 05efa5d..6ce1ef3 100644
--- a/src/tabviews/zshare/mutilform/mkRadio/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkRadio/index.jsx
@@ -2,8 +2,6 @@
 import PropTypes from 'prop-types'
 import { Radio } from 'antd'
 
-import './index.scss'
-
 class MKRadio extends Component {
   static propTpyes = {
     config: PropTypes.object,
diff --git a/src/tabviews/zshare/mutilform/mkSelect/index.jsx b/src/tabviews/zshare/mutilform/mkSelect/index.jsx
index 1caeb6f..3e73927 100644
--- a/src/tabviews/zshare/mutilform/mkSelect/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkSelect/index.jsx
@@ -3,7 +3,6 @@
 import { Select } from 'antd'
 
 import MKEmitter from '@/utils/events.js'
-import './index.scss'
 
 class MKSelect extends Component {
   constructor(props) {
@@ -160,6 +159,7 @@
           allowClear
           id={config.uuid}
           value={value}
+          dropdownMatchSelectWidth={config.dropdown !== 'false'}
           filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
           onSelect={this.selectChange}
           onChange={(val) => val === undefined && this.selectChange('')}
diff --git a/src/tabviews/zshare/mutilform/mkSwitch/index.jsx b/src/tabviews/zshare/mutilform/mkSwitch/index.jsx
index b3eff86..6d3d178 100644
--- a/src/tabviews/zshare/mutilform/mkSwitch/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkSwitch/index.jsx
@@ -2,8 +2,6 @@
 import PropTypes from 'prop-types'
 import { Switch } from 'antd'
 
-import './index.scss'
-
 class MKSwitch extends Component {
   static propTpyes = {
     config: PropTypes.object,
diff --git a/src/tabviews/zshare/mutilform/mkTextArea/index.jsx b/src/tabviews/zshare/mutilform/mkTextArea/index.jsx
index 04886c9..444d185 100644
--- a/src/tabviews/zshare/mutilform/mkTextArea/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkTextArea/index.jsx
@@ -3,7 +3,6 @@
 import { Input } from 'antd'
 
 import MKEmitter from '@/utils/events.js'
-import './index.scss'
 
 const { TextArea } = Input
 
diff --git a/src/tabviews/zshare/topSearch/index.jsx b/src/tabviews/zshare/topSearch/index.jsx
index d2c6e39..c2cf4ad 100644
--- a/src/tabviews/zshare/topSearch/index.jsx
+++ b/src/tabviews/zshare/topSearch/index.jsx
@@ -366,7 +366,7 @@
   }
 
   resetSearch = (result) => {
-    let _searchlist = this.state.searchlist.map(item => {
+    let _searchlist = fromJS(this.state.searchlist).toJS().map(item => {
       if (['select', 'link', 'multiselect', 'checkcard'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
         let options = []
         result[item.field].forEach(cell => {
@@ -394,23 +394,22 @@
 
         item.oriOptions = [...item.oriOptions, ...options]
       }
+
+      if (item.type === 'link') {
+        if (item.supInitVal) {
+          item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal || option.Value === '')
+        } else {
+          item.options = item.oriOptions
+        }
+      } else if (item.type === 'select' || item.type === 'multiselect' || item.type === 'checkcard') {
+        item.options = item.oriOptions
+      }
+
       return item
     })
 
     this.setState({
-      searchlist: _searchlist.map(item => {
-        if (item.type === 'link') {
-          if (item.supInitVal) {
-            item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal || option.Value === '')
-          } else {
-            item.options = item.oriOptions
-          }
-        } else if (item.type === 'select' || item.type === 'multiselect' || item.type === 'checkcard') {
-          item.options = item.oriOptions
-        }
-
-        return item
-      })
+      searchlist: _searchlist
     })
   }
 
diff --git a/src/tabviews/zshare/topSearch/mkDatePicker/index.jsx b/src/tabviews/zshare/topSearch/mkDatePicker/index.jsx
index 036049b..4ebc9b2 100644
--- a/src/tabviews/zshare/topSearch/mkDatePicker/index.jsx
+++ b/src/tabviews/zshare/topSearch/mkDatePicker/index.jsx
@@ -3,8 +3,6 @@
 import { DatePicker } from 'antd'
 import moment from 'moment'
 
-import './index.scss'
-
 const { MonthPicker, WeekPicker, RangePicker } = DatePicker
 
 /**
diff --git a/src/tabviews/zshare/topSearch/mkSelect/index.jsx b/src/tabviews/zshare/topSearch/mkSelect/index.jsx
index 53d6385..a090007 100644
--- a/src/tabviews/zshare/topSearch/mkSelect/index.jsx
+++ b/src/tabviews/zshare/topSearch/mkSelect/index.jsx
@@ -3,7 +3,6 @@
 import { Select } from 'antd'
 
 import MKEmitter from '@/utils/events.js'
-import './index.scss'
 
 class MKSearchSelect extends Component {
   constructor(props) {
@@ -106,6 +105,7 @@
       <Select
         showSearch
         mode={config.type === 'multiselect' ? 'multiple' : ''}
+        dropdownMatchSelectWidth={config.dropdown !== 'false'}
         value={value}
         filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
         onChange={this.selectChange}
diff --git a/src/templates/sharecomponent/searchcomponent/searchform/index.jsx b/src/templates/sharecomponent/searchcomponent/searchform/index.jsx
index 377235b..e8faf2e 100644
--- a/src/templates/sharecomponent/searchcomponent/searchform/index.jsx
+++ b/src/templates/sharecomponent/searchcomponent/searchform/index.jsx
@@ -88,9 +88,9 @@
 
 const searchTypeOptions = {
   text: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'inputType', 'advanced'],
-  select: ['label', 'field', 'resourceType', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced', 'setAll'],
+  select: ['label', 'field', 'resourceType', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced', 'setAll', 'dropdown'],
   multiselect: ['label', 'field', 'resourceType', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
-  link: ['label', 'field', 'resourceType', 'initval', 'type', 'linkField', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced', 'setAll'],
+  link: ['label', 'field', 'resourceType', 'initval', 'type', 'linkField', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced', 'setAll', 'dropdown'],
   date: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
   checkcard: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'resourceType', 'display', 'width', 'multiple', 'borderColor', 'required', 'Hide', 'labelShow', 'advanced'],
   dateweek: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
diff --git a/src/templates/zshare/formconfig.jsx b/src/templates/zshare/formconfig.jsx
index e143d8b..c9c8963 100644
--- a/src/templates/zshare/formconfig.jsx
+++ b/src/templates/zshare/formconfig.jsx
@@ -746,6 +746,20 @@
     },
     {
       type: 'radio',
+      key: 'dropdown',
+      label: '涓嬫媺妗�',
+      initVal: card.dropdown || 'true',
+      forbid: appType === 'mob',
+      options: [{
+        value: 'true',
+        text: '瀹氬'
+      }, {
+        value: 'false',
+        text: '鑷�傚簲'
+      }]
+    },
+    {
+      type: 'radio',
       key: 'inputType',
       label: '杈撳叆鏍峰紡',
       initVal: card.inputType || 'input',
@@ -2783,6 +2797,20 @@
     },
     {
       type: 'radio',
+      key: 'dropdown',
+      label: '涓嬫媺妗�',
+      initVal: card.dropdown || 'true',
+      forbid: appType === 'mob',
+      options: [{
+        value: 'true',
+        text: '瀹氬'
+      }, {
+        value: 'false',
+        text: '鑷�傚簲'
+      }]
+    },
+    {
+      type: 'radio',
       key: 'hidelabel',
       label: '闅愯棌鍚嶇О',
       initVal: card.hidelabel || 'false',
diff --git a/src/templates/zshare/modalform/index.jsx b/src/templates/zshare/modalform/index.jsx
index aae44be..1e0b392 100644
--- a/src/templates/zshare/modalform/index.jsx
+++ b/src/templates/zshare/modalform/index.jsx
@@ -18,12 +18,12 @@
 const modalTypeOptions = {
   text: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'regular', 'interception', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'scan', 'splitline', 'placeholder'],
   number: ['initval', 'readonly', 'hidden', 'decimal', 'min', 'max', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'splitline'],
-  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline'],
+  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline', 'dropdown'],
   checkbox: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'arrange'],
   radio: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'setAll', 'emptyText', 'splitline', 'arrange'],
   checkcard: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'linkSubField', 'fieldlength', 'span', 'labelwidth', 'display', 'tooltip', 'extra', 'width', 'multiple', 'borderColor', 'splitline'],
   multiselect: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra'],
-  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkField', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline'],
+  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkField', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline', 'dropdown'],
   fileupload: ['readonly', 'required', 'readin', 'fieldlength', 'maxfile', 'fileType', 'span', 'labelwidth', 'tooltip', 'extra', 'compress', 'splitline'],
   switch: ['initval', 'openVal', 'closeVal', 'openText', 'closeText', 'readonly', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline'],
   date: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline'],

--
Gitblit v1.8.0