From 20185ab64a165df51515d9fa1c9b12a7a8c55f59 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期五, 07 四月 2023 23:11:04 +0800
Subject: [PATCH] 2023-04-07

---
 src/menu/components/card/cardcellcomponent/dragaction/index.scss                 |   17 +
 src/tabviews/custom/components/card/double-data-card/index.jsx                   |   34 +
 src/menu/components/card/cardcellcomponent/elementform/index.jsx                 |   22 +
 src/templates/sharecomponent/fieldscomponent/editcard/index.jsx                  |    5 
 src/views/menudesign/menuform/index.jsx                                          |  105 +++----
 src/tabviews/zshare/actionList/exceloutbutton/index.jsx                          |   15 +
 src/menu/components/card/cardcellcomponent/dragaction/card.jsx                   |   12 
 src/templates/sharecomponent/fieldscomponent/index.jsx                           |    9 
 src/menu/components/table/normal-table/columns/editColumn/index.jsx              |    2 
 src/tabviews/custom/index.scss                                                   |    5 
 src/components/paste/index.jsx                                                   |    4 
 src/menu/components/table/edit-table/columns/editColumn/index.jsx                |    2 
 src/menu/datasource/verifycard/index.jsx                                         |   13 
 src/tabviews/custom/components/card/data-card/index.jsx                          |   34 +
 src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx            |   13 
 src/tabviews/custom/components/card/cardcellList/index.jsx                       |   93 +++---
 src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx               |   13 
 src/menu/components/table/base-table/columns/editColumn/index.jsx                |    2 
 src/components/normalform/modalform/index.jsx                                    |    2 
 src/menu/components/card/cardcellcomponent/index.jsx                             |    2 
 src/menu/components/card/cardcomponent/index.jsx                                 |   53 +++
 src/tabviews/custom/components/card/tableHeader/index.scss                       |   45 +++
 src/menu/components/card/cardcellcomponent/formconfig.jsx                        |   36 ++
 src/tabviews/custom/index.jsx                                                    |    4 
 src/menu/components/card/cardcomponent/index.scss                                |    5 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx |   16 +
 src/menu/components/card/cardcomponent/options.jsx                               |   18 +
 src/tabviews/custom/components/card/tableHeader/index.jsx                        |  160 ++++++++++++
 28 files changed, 587 insertions(+), 154 deletions(-)

diff --git a/src/components/normalform/modalform/index.jsx b/src/components/normalform/modalform/index.jsx
index cae1d70..c3e3144 100644
--- a/src/components/normalform/modalform/index.jsx
+++ b/src/components/normalform/modalform/index.jsx
@@ -45,6 +45,8 @@
       
       item.hidden = false
 
+      if (item.forbid && item.del) return false
+
       if (item.forbid) {
         item.hidden = true
       }
diff --git a/src/components/paste/index.jsx b/src/components/paste/index.jsx
index bf998d5..ce96162 100644
--- a/src/components/paste/index.jsx
+++ b/src/components/paste/index.jsx
@@ -33,10 +33,10 @@
           })
           this.setState({visible: false})
         } else {
-          notification.success({
+          notification.warning({
             top: 92,
             message: result.message,
-            duration: 2
+            duration: 5
           })
         }
       })
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
index 8069bcf..6494683 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -1,7 +1,7 @@
 import React from 'react'
 import { useDrag, useDrop } from 'react-dnd'
 import { Popover } from 'antd'
-import { EditOutlined, CopyOutlined, CloseOutlined, FontColorsOutlined } from '@ant-design/icons'
+import { EditOutlined, CopyOutlined, CloseOutlined, FontColorsOutlined, CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons'
 
 import MkIcon from '@/components/mk-icon'
 import moment from 'moment'
@@ -84,6 +84,9 @@
       if (card.fixStyle === 'alone') {
         let _s = {fontSize: card.fixSize, color: card.fixColor, marginLeft: card.fixLeft, marginRight: card.fixRight}
         val = <><span style={_s}>{card.prefix || ''}</span>{`${card.datatype === 'static' ? (card.value || '') : (card.field || '')}`}<span style={_s}>{card.postfix || ''}</span></>
+      }
+      if (card.sortField) {
+        val = <><span>{val}</span><span className="sort-wrap"><CaretUpOutlined /><CaretDownOutlined /></span></>
       }
       return (
         <div className={'ant-mk-text line' + (card.height || '')} style={{height: card.innerHeight || 'auto'}}>{val}</div>
@@ -211,6 +214,11 @@
     _style_ = {clear: 'left'}
   }
 
+  let tableHCell = false
+  if (parent.setting && parent.setting.cardRole === 'header') {
+    tableHCell = true
+  }
+
   return (
     <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
       <div className="mk-popover-control" onDoubleClick={(e) => e.stopPropagation()}>
@@ -218,7 +226,7 @@
         <CopyOutlined className="copy" title="澶嶅埗" onClick={() => copyCard(id)} />
         <CloseOutlined className="close" title="鍒犻櫎" onClick={() => delCard(id)} />
         <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={() => changeStyle(id)}/>
-        {['text', 'number', 'slider', 'sequence', 'formula'].includes(card.eleType) ? <MarkColumn field={card.field || ''} columns={fields} type={card.eleType} marks={card.marks} onSubmit={(vals) => updateMarks({...card, marks: vals})} /> : null }
+        {['text', 'number', 'slider', 'sequence', 'formula'].includes(card.eleType) && !tableHCell ? <MarkColumn field={card.field || ''} columns={fields} type={card.eleType} marks={card.marks} onSubmit={(vals) => updateMarks({...card, marks: vals})} /> : null }
       </div>
     } trigger="hover">
       <div ref={node => drag(drop(node))} style={_style_} className={'ant-col card-cell ant-col-' + card.width}>
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/index.scss b/src/menu/components/card/cardcellcomponent/dragaction/index.scss
index 3d44552..51310de 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/index.scss
+++ b/src/menu/components/card/cardcellcomponent/dragaction/index.scss
@@ -214,4 +214,21 @@
     background-repeat: no-repeat;
     background-size: cover;
   }
+  .sort-wrap {
+    position: relative;
+    margin-left: 5px;
+    font-size: 12px;
+    color: #bfbfbf;
+    display: none;
+
+    .anticon-caret-up {
+      position: relative;
+      top: -4px;
+    }
+    .anticon-caret-down {
+      position: absolute;
+      top: 5px;
+      left: 0px;
+    }
+  }
 }
\ No newline at end of file
diff --git a/src/menu/components/card/cardcellcomponent/elementform/index.jsx b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
index e21fc1f..f8acf74 100644
--- a/src/menu/components/card/cardcellcomponent/elementform/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
@@ -15,7 +15,7 @@
 
 const cardTypeOptions = {
   sequence: ['eleType', 'width'],
-  text: ['eleType', 'datatype', 'format', 'width', 'height', 'prefix', 'postfix', 'link', 'anchors', 'noValue', 'bgImage', 'fixStyle', 'copyable', 'alignItems'],
+  text: ['eleType', 'datatype', 'format', 'width', 'height', 'prefix', 'postfix', 'link', 'anchors', 'noValue', 'bgImage', 'fixStyle', 'copyable', 'alignItems', 'sortField'],
   number: ['eleType', 'datatype', 'width', 'height', 'prefix', 'postfix', 'noValue', 'fixStyle', 'alignItems'],
   picture: ['eleType', 'datatype', 'width', 'lenWidRadio', 'maxWidth', 'link', 'noValue'],
   video: ['eleType', 'datatype', 'width', 'aspectRatio', 'autoPlay', 'loop', 'startTime', 'noValue', 'posterType'],
@@ -96,6 +96,26 @@
               }
             })
           }
+        } else if (item.key === 'sortField' && !item.forbid) {
+          item.options = []
+
+          config.columns.forEach(col => {
+            let label = `${col.field}锛�${col.label}锛塦
+            item.options.push({
+              value: col.field,
+              text: label
+            })
+          })
+          
+          if (config.subColumns) {
+            config.subColumns.forEach(col => {
+              let label = `${col.field}锛�${col.label}锛塦
+              item.options.push({
+                value: col.field,
+                text: label
+              })
+            })
+          }
         } else if (item.key === 'value' && card.eleType === 'slider') {
           item.type = 'number'
           item.label = '鍊�'
diff --git a/src/menu/components/card/cardcellcomponent/formconfig.jsx b/src/menu/components/card/cardcellcomponent/formconfig.jsx
index 76739c9..3400840 100644
--- a/src/menu/components/card/cardcellcomponent/formconfig.jsx
+++ b/src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -43,6 +43,14 @@
     tooltip = '鍦ㄦ墿灞曞崱鐗囦腑锛屽姩鎬佹暟鎹樉绀哄�间负鑾峰彇鍒扮殑绗竴琛屾暟鎹��'
   }
 
+  let isHeader = false
+  if (cardCell.$cardType === 'extendCard' && cardCell.setting.cardRole === 'header') {
+    isHeader = true
+    anchors = null
+    card.link = ''
+    _options = [{ value: 'text', text: '鏂囨湰'}]
+  }
+
   let width = card.width || 12
   if (/x/.test(card.width)) {
     width = +width.replace(/x/, '.5')
@@ -193,7 +201,8 @@
         { value: 'MM鏈圖D鏃� ahh:mm', text: '鑷畾涔�2锛堜緥锛�12鏈�17鏃� 涓婂崍10:57锛�' },
         { value: 'calendar1', text: '鑷畾涔�3锛堜緥锛氫粖澶� 涓婂崍10:57锛�' },
         { value: 'calendar2', text: '鑷畾涔�4锛堜緥锛氬垰鍒氥�佹槰澶┿��5澶╁墠锛�' },
-      ]
+      ],
+      forbid: isHeader
     },
     {
       type: 'select',
@@ -359,7 +368,8 @@
       tooltip: '缁戝畾鏁版嵁婧愬瓧娈碉紝鍙牴鎹繑鍥炲�兼敼鍙樿儗鏅浘銆�',
       required: false,
       allowClear: true,
-      options: []
+      options: [],
+      forbid: isHeader
     },
     {
       type: 'cascader',
@@ -490,7 +500,8 @@
         { value: '', text: '鏃�' },
         { value: 'dynamic', text: '鍔ㄦ��' },
         { value: 'static', text: '闈欐��' }
-      ]
+      ],
+      forbid: isHeader
     },
     {
       type: 'radio',
@@ -584,7 +595,8 @@
         { value: '', text: '灞呬笂' },
         { value: 'center', text: '灞呬腑' },
         { value: 'end', text: '灞呬笅' }
-      ]
+      ],
+      forbid: isHeader
     },
     {
       type: 'radio',
@@ -596,7 +608,8 @@
       options: [
         { value: '', text: '缁熶竴鏍峰紡' },
         { value: 'alone', text: '鐙珛鏍峰紡' }
-      ]
+      ],
+      forbid: isHeader
     },
     {
       type: 'radio',
@@ -608,7 +621,8 @@
       options: [
         { value: 'true', text: '鏄�' },
         { value: 'false', text: '鍚�' }
-      ]
+      ],
+      forbid: isHeader
     },
     {
       type: 'number',
@@ -648,6 +662,16 @@
       tooltip: '鍓嶇紑銆佸悗缂�鐨勫彸杈硅窛銆�',
       required: false
     },
+    {
+      type: 'select',
+      key: 'sortField',
+      label: '鎺掑簭瀛楁',
+      initVal: card.sortField || '',
+      required: false,
+      allowClear: true,
+      options: [],
+      forbid: !isHeader
+    },
   ]
 
   return forms
diff --git a/src/menu/components/card/cardcellcomponent/index.jsx b/src/menu/components/card/cardcellcomponent/index.jsx
index f752e5a..f676322 100644
--- a/src/menu/components/card/cardcellcomponent/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/index.jsx
@@ -75,7 +75,7 @@
   }
 
   UNSAFE_componentWillReceiveProps(nextProps) {
-    if (this.props.side !== nextProps.side) {
+    if (this.props.side !== nextProps.side && nextProps.side) {
       this.setState({
         elements: fromJS(nextProps.elements).toJS()
       })
diff --git a/src/menu/components/card/cardcomponent/index.jsx b/src/menu/components/card/cardcomponent/index.jsx
index a7efb6a..db2c7f5 100644
--- a/src/menu/components/card/cardcomponent/index.jsx
+++ b/src/menu/components/card/cardcomponent/index.jsx
@@ -12,6 +12,8 @@
 import MKEmitter from '@/utils/events.js'
 import './index.scss'
 
+const { confirm } = Modal
+
 const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
 const CardCellComponent = asyncComponent(() => import('@/menu/components/card/cardcellcomponent'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
@@ -129,6 +131,10 @@
     newcard.datatype = 'dynamic'
     newcard.height = 1
 
+    if (card.$cardType === 'extendCard' && card.setting.cardRole === 'header') {
+      newcard.datatype = 'static'
+    }
+
     // 娉ㄥ唽浜嬩欢-娣诲姞鍏冪礌
     MKEmitter.emit('cardAddElement', card.uuid, newcard)
   }
@@ -188,6 +194,39 @@
   updateSetting = (res) => {
     const { card, side, appType } = this.state
 
+    if (card.$cardType === 'extendCard' && res.cardRole === 'header') {
+      let _card = {...card, setting: res}
+
+      let originLength = _card.elements.length
+      _card.elements = _card.elements.filter(item => item.eleType === 'text')
+      _card.backElements = []
+
+      delete _card.menus
+
+      if (_card.elements.length < originLength) {
+        const that = this
+
+        confirm({
+          title: '琛ㄦ牸澶翠粎鏀寔鏂囨湰锛岀‘瀹氳鍒囨崲鍗$墖瑙掕壊鍚�?',
+          content: '',
+          okText: '纭畾',
+          cancelText: '鍙栨秷',
+          onOk() {
+            that.setState({ card: _card, side: '', elements: fromJS(_card.elements).toJS() }, () => {
+              that.setState({ side: 'front' })
+            })
+            that.props.updateElement(_card)
+          },
+          onCancel() {}
+        })
+      } else {
+        this.setState({ card: _card, side: 'front' })
+        this.props.updateElement(_card)
+      }
+
+      return
+    }
+
     if (appType === '' && res.menu) {
       let list = null
       try {
@@ -237,6 +276,11 @@
 
     let _uuid = Utils.getuuid()
     
+    if (card.$cardType === 'extendCard' && card.setting.cardRole === 'header' && element.eleType !== 'text') {
+      resolve({status: false, message: '琛ㄦ牸澶翠粎鏀寔鏂囨湰鍏冪礌锛�'})
+      return
+    }
+
     if (element.copyType === 'action') {
       element.eleType = 'button'
     }
@@ -325,16 +369,21 @@
       }
     }
 
+    let tablerole = ''
+    if (card.$cardType === 'extendCard' && card.setting.cardRole === 'header') {
+      tablerole = ' mk-table-header'
+    }
+
     return (
       <Col span={card.setting.width || 6}>
-        <div className={'card-item ' + (card.setting.btnControl || '') + checkAll} style={_style} onDoubleClick={(e) => {e.stopPropagation(); this.doubleClickCard()}} id={card.uuid}>
+        <div className={'card-item ' + (card.setting.btnControl || '') + checkAll + tablerole} style={_style} onDoubleClick={(e) => {e.stopPropagation(); this.doubleClickCard()}} id={card.uuid}>
           <span className="circle-select"></span>
           <CardCellComponent cards={cards} cardCell={card} side={side} elements={elements} updateElement={this.updateCard}/>
           <div className="card-control" onDoubleClick={(e) => e.stopPropagation()}>
             <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
               <div className="mk-popover-control">
                 <PlusOutlined className="plus" title="娣诲姞鍏冪礌" onClick={this.addElement} />
-                <PlusSquareOutlined className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} />
+                {!tablerole ? <PlusSquareOutlined className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} /> : null}
                 <NormalForm title={cards.subtype === 'datacard' && card.$cardType !== 'extendCard' ? '寰幆鍗$墖璁剧疆' : '灞炴�у崱鐗囪缃�'} width={950} update={this.updateSetting} getForms={this.getSettingForms}>
                   <EditOutlined className="edit" title="缂栬緫"/>
                 </NormalForm>
diff --git a/src/menu/components/card/cardcomponent/index.scss b/src/menu/components/card/cardcomponent/index.scss
index 62291ee..930a06f 100644
--- a/src/menu/components/card/cardcomponent/index.scss
+++ b/src/menu/components/card/cardcomponent/index.scss
@@ -93,3 +93,8 @@
     border-radius: 0;
   }
 }
+.card-item.mk-table-header {
+  .sort-wrap {
+    display: inline;
+  }
+}
diff --git a/src/menu/components/card/cardcomponent/options.jsx b/src/menu/components/card/cardcomponent/options.jsx
index 32a1632..0e8c311 100644
--- a/src/menu/components/card/cardcomponent/options.jsx
+++ b/src/menu/components/card/cardcomponent/options.jsx
@@ -61,6 +61,24 @@
     },
     {
       type: 'radio',
+      field: 'cardRole',
+      label: '鍗$墖瑙掕壊',
+      initval: setting.cardRole || 'card',
+      required: false,
+      options: [
+        {value: 'card', label: '灞炴�у崱'},
+        {value: 'header', label: '琛ㄦ牸澶�'},
+      ],
+      controlFields: [
+        {field: 'type', values: ['card']},
+        {field: 'click', values: ['card']},
+        {field: 'btnControl', values: ['card']},
+      ],
+      del: true,
+      forbid: cardType !== 'extendCard'
+    },
+    {
+      type: 'radio',
       field: 'type',
       label: '鍗$墖绫诲瀷',
       initval: setting.type || 'simple',
diff --git a/src/menu/components/table/base-table/columns/editColumn/index.jsx b/src/menu/components/table/base-table/columns/editColumn/index.jsx
index 7af08ee..87fc195 100644
--- a/src/menu/components/table/base-table/columns/editColumn/index.jsx
+++ b/src/menu/components/table/base-table/columns/editColumn/index.jsx
@@ -17,7 +17,7 @@
   picture: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'fieldlength', 'blacklist', 'scale', 'lenWidRadio', 'backgroundSize', 'span'],
   video: ['label', 'field', 'type', 'Align', 'Hide', 'startTime', 'Width', 'fieldlength', 'blacklist', 'aspectRatio'],
   colspan: ['label', 'type', 'Align', 'Hide', 'blacklist'],
-  custom: ['label', 'type', 'Align', 'Hide', 'Width', 'blacklist'],
+  custom: ['label', 'type', 'Align', 'Width', 'blacklist'],
   action: ['label', 'type', 'Align', 'Width'],
   formula: ['label', 'type', 'Align', 'Hide', 'Width', 'prefix', 'postfix', 'eval', 'formula', 'blacklist'],
   index: ['label', 'type', 'Align', 'Width']
diff --git a/src/menu/components/table/edit-table/columns/editColumn/index.jsx b/src/menu/components/table/edit-table/columns/editColumn/index.jsx
index 00c47c3..9fe0f6d 100644
--- a/src/menu/components/table/edit-table/columns/editColumn/index.jsx
+++ b/src/menu/components/table/edit-table/columns/editColumn/index.jsx
@@ -16,7 +16,7 @@
   text: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'textFormat', 'editable', 'initval', 'blacklist'],
   number: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'decimal', 'format', 'prefix', 'postfix', 'editable', 'initval', 'sum', 'blacklist'],
   textarea: ['label', 'field', 'type', 'Align', 'Hide', 'Width', 'prefix', 'initval', 'postfix', 'blacklist'],
-  custom: ['label', 'type', 'Align', 'Hide', 'Width', 'blacklist'],
+  custom: ['label', 'type', 'Align', 'Width', 'blacklist'],
   colspan: ['label', 'type', 'Align', 'Hide', 'blacklist'],
   action: ['label', 'type', 'Align', 'Width'],
   formula: ['label', 'type', 'Align', 'Hide', 'Width', 'prefix', 'postfix', 'eval', 'formula', 'blacklist'],
diff --git a/src/menu/components/table/normal-table/columns/editColumn/index.jsx b/src/menu/components/table/normal-table/columns/editColumn/index.jsx
index d299f89..d580db8 100644
--- a/src/menu/components/table/normal-table/columns/editColumn/index.jsx
+++ b/src/menu/components/table/normal-table/columns/editColumn/index.jsx
@@ -17,7 +17,7 @@
   picture: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'blacklist', 'scale', 'lenWidRadio', 'backgroundSize', 'span'],
   video: ['label', 'field', 'type', 'Align', 'Hide', 'startTime', 'Width', 'blacklist', 'aspectRatio'],
   colspan: ['label', 'type', 'Align', 'Hide', 'blacklist'],
-  custom: ['label', 'type', 'Align', 'Hide', 'Width', 'blacklist'],
+  custom: ['label', 'type', 'Align', 'Width', 'blacklist'],
   action: ['label', 'type', 'Align', 'Width'],
   formula: ['label', 'type', 'Align', 'Hide', 'Width', 'prefix', 'postfix', 'eval', 'formula', 'blacklist'],
   index: ['label', 'type', 'Align', 'Width']
diff --git a/src/menu/datasource/verifycard/index.jsx b/src/menu/datasource/verifycard/index.jsx
index 814c6df..a8e1e0f 100644
--- a/src/menu/datasource/verifycard/index.jsx
+++ b/src/menu/datasource/verifycard/index.jsx
@@ -4,6 +4,7 @@
 import { Form, Tabs, Popconfirm, notification, Modal, Typography, Spin, message, Button, Input } from 'antd'
 import { StopOutlined, CheckCircleOutlined, EditOutlined, SwapOutlined, DeleteOutlined, CopyOutlined, BorderOutlined, SnippetsOutlined } from '@ant-design/icons'
 import moment from 'moment'
+import md5 from 'md5'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -33,6 +34,7 @@
 
   state = {
     columns: [],
+    debugId: '',
     subColumns: [],
     activeKey: 'setting',
     loading: false,
@@ -653,7 +655,7 @@
   }
 
   sqlverify = (resolve, reject, change = false, testScripts) => {
-    const { columns, setting, scripts, searches, defaultSearch } = this.state
+    const { columns, setting, scripts, searches, defaultSearch, debugId } = this.state
 
     let _scripts = scripts.filter(item => item.status !== 'false')
 
@@ -678,6 +680,13 @@
     if ((setting.interType === 'system' && setting.execute !== 'false') || _scripts.length > 0) {
       let timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
       let r = SettingUtils.getDebugSql(setting, _scripts, columns, searches, defaultSearch, timestamp)
+
+      let _debugId = md5(r.sql)
+
+      if (debugId === _debugId) {
+        resolve()
+        return
+      }
 
       if (r.errors) {
         notification.warning({
@@ -713,6 +722,7 @@
           if (sumParam) {
             Api.genericInterface(sumParam).then(res => {
               if (res.status) {
+                this.setState({debugId: _debugId})
                 resolve()
               } else {
                 reject()
@@ -722,6 +732,7 @@
               }
             })
           } else {
+            this.setState({debugId: _debugId})
             resolve()
           }
         } else {
diff --git a/src/tabviews/custom/components/card/cardcellList/index.jsx b/src/tabviews/custom/components/card/cardcellList/index.jsx
index 94c16f6..d997633 100644
--- a/src/tabviews/custom/components/card/cardcellList/index.jsx
+++ b/src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -249,11 +249,11 @@
           className = mark.signType
         }
         contents.push(
-          <Col key={card.uuid} style={_style_} span={card.width}>
+          <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
             <div style={card.style}>
               <div className={'ant-mk-text line1' + className} style={{height: card.innerHeight || 'auto'}}><span className="sequence-wrap" style={_style}>{data.$Index || ''}</span></div>
             </div>
-          </Col>
+          </div>
         )
       } else if (card.eleType === 'text') {
         let val = ''
@@ -409,11 +409,11 @@
         }
   
         contents.push(
-          <Col key={card.uuid} style={_style_} span={card.width}>
+          <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
             <div style={_style} onClick={(e) => {this.openNewView(e, card)}}>
               <div className={'ant-mk-text line' + (card.height || '') + className} style={lineStyle}>{val}</div>
             </div>
-          </Col>
+          </div>
         )
       } else if (card.eleType === 'number') {
         let val = ''
@@ -486,11 +486,11 @@
         }
   
         contents.push(
-          <Col key={card.uuid} style={_style_} span={card.width}>
+          <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
             <div style={_style}>
               <div className={'ant-mk-text line' + (card.height || '') + className} style={lineStyle}>{val}</div>
             </div>
-          </Col>
+          </div>
         )
       } else if (card.eleType === 'icon') {
         let val = ''
@@ -528,13 +528,13 @@
         }
   
         contents.push(
-          <Col key={card.uuid} style={_style_} span={card.width}>
+          <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
             <div style={card.style}>
               {val ? <Tooltip title={val}>
                 <MkIcon className="ant-mk-icon" style={{height: height}} type={icon}/>
               </Tooltip> : <MkIcon className="ant-mk-icon" style={{height: height}} type={icon}/>}
             </div>
-          </Col>
+          </div>
         )
       } else if (card.eleType === 'slider') {
         let val = 0
@@ -558,11 +558,11 @@
         }
   
         contents.push(
-          <Col key={card.uuid} style={_style_} span={card.width}>
+          <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
             <div style={card.style}>
               <MkProgress value={val} config={card} color={color}/>
             </div>
-          </Col>
+          </div>
         )
       } else if (card.eleType === 'picture') {
         let _imagestyle = {}
@@ -610,22 +610,22 @@
         let urls = url ? url.split(',').filter(Boolean) : ['']
 
         urls.forEach((u, i) => {
-          contents.push(<Col key={card.uuid + i} style={_style_} span={card.width}>
+          contents.push(<div className={'ant-col ant-col-' + card.width} key={card.uuid + i} style={_style_} span={card.width}>
             <div style={_style} onClick={(e) => {this.openNewView(e, card)}}>
               <MkPicture style={_imagestyle} scale={scale} url={u} urls={urls}/>
             </div>
-          </Col>)
+          </div>)
         })
       } else if (card.eleType === 'splitline') {
         let _borderWidth = card.borderWidth === undefined ? 1 : card.borderWidth
         _style_ = _style_ || {}
         _style_.minHeight = _borderWidth
         contents.push(
-          <Col key={card.uuid} span={card.width} style={_style_}>
+          <div className={'ant-col ant-col-' + card.width} key={card.uuid} span={card.width} style={_style_}>
             <div style={card.style}>
               <div className="ant-mk-splitline" style={{borderColor: card.color, borderWidth: _borderWidth}}></div>
             </div>
-          </Col>
+          </div>
         )
       } else if (card.eleType === 'barcode') {
         let val = ''
@@ -641,13 +641,13 @@
         }
   
         contents.push(
-          <Col key={card.uuid} style={_style_} span={card.width}>
+          <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
             <div style={card.style}>
               <div style={{height: card.innerHeight || 25}}>
                 {val ? <BarCode card={card} value={val}/> : null}
               </div>
             </div>
-          </Col>
+          </div>
         )
       } else if (card.eleType === 'video') {
         let url = ''
@@ -674,11 +674,11 @@
   
         urls.forEach((u, i) => {
           contents.push(
-            <Col key={card.uuid + i} style={_style_} span={card.width}>
+            <div className={'ant-col ant-col-' + card.width} key={card.uuid + i} style={_style_} span={card.width}>
               <div className="video-wrap" style={card.style}>
                 <Video card={card} poster={poster} value={u}/>
               </div>
-            </Col>
+            </div>
           )
         })
       } else if (card.eleType === 'qrcode') {
@@ -695,13 +695,13 @@
         }
   
         contents.push(
-          <Col key={card.uuid} style={_style_} span={card.width}>
+          <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
             <div style={card.style}>
               <div style={{minHeight: card.qrWidth || 50}}>
                 {val ? <QrCode card={card} value={val}/> : null}
               </div>
             </div>
-          </Col>
+          </div>
         )
       } else if (card.eleType === 'currentDate') {
         let val = moment().format(card.dateFormat || 'YYYY-MM-DD')
@@ -714,11 +714,11 @@
         }
   
         contents.push(
-          <Col key={card.uuid} style={_style_} span={card.width}>
+          <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
             <div style={card.style}>
               <div className="ant-mk-text line1" style={{height: card.innerHeight || 'auto'}}>{val}</div>
             </div>
-          </Col>
+          </div>
         )
       } else if (card.eleType === 'formula') {
         let val = 0
@@ -812,11 +812,11 @@
         }
   
         contents.push(
-          <Col key={card.uuid} style={_style_} span={card.width}>
+          <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
             <div style={_style}>
               <div className={'ant-mk-text line' + (card.height || '') + className} style={lineStyle}>{val}</div>
             </div>
-          </Col>
+          </div>
         )
       } else if (card.eleType === 'color') {
         let color = ''
@@ -844,7 +844,7 @@
         }
 
         contents.push(
-          <Col key={card.uuid} style={_style_} span={card.width}>
+          <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
             <div className="ant-mk-color" style={card.style}>
               <div style={_bgstyle} onClick={(e) => {
                 if (card.copyable === 'true') {
@@ -861,7 +861,7 @@
                 }
               }}></div>
             </div>
-          </Col>
+          </div>
         )
       } else if (card.eleType === 'button') {
         let _disabled = data.$disabled
@@ -882,7 +882,7 @@
   
         if (['exec', 'prompt', 'pop', 'form'].includes(card.OpenType)) {
           contents.push(
-            <Col key={card.uuid} className="mk-cell-btn" style={_style_} span={card.width}>
+            <div className={'ant-col mk-cell-btn ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
               <NormalButton
                 btn={card}
                 BID={data.$$BID}
@@ -892,11 +892,11 @@
                 columns={cards.columns}
                 selectedData={_data}
               />
-            </Col>
+            </div>
           )
         } else if (card.OpenType === 'excelIn') {
           contents.push(
-            <Col key={card.uuid} className="mk-cell-btn" style={_style_} span={card.width}>
+            <div className={'ant-col mk-cell-btn ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
               <ExcelInButton
                 btn={card}
                 BID={data.$$BID}
@@ -905,11 +905,11 @@
                 setting={cards.setting}
                 selectedData={_data}
               />
-            </Col>
+            </div>
           )
         } else if (card.OpenType === 'excelOut') {
           contents.push(
-            <Col key={card.uuid} className="mk-cell-btn" style={_style_} span={card.width}>
+            <div className={'ant-col mk-cell-btn ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
               <ExcelOutButton
                 btn={card}
                 BID={data.$$BID}
@@ -918,11 +918,11 @@
                 setting={cards.setting}
                 selectedData={_data}
               />
-            </Col>
+            </div>
           )
         } else if (card.OpenType === 'popview') {
           contents.push(
-            <Col key={card.uuid} className="mk-cell-btn" style={_style_} span={card.width}>
+            <div className={'ant-col mk-cell-btn ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
               <PopupButton
                 btn={card}
                 BID={data.$$BID}
@@ -931,11 +931,11 @@
                 setting={cards.setting}
                 selectedData={_data}
               />
-            </Col>
+            </div>
           )
         } else if (card.OpenType === 'tab') {
           contents.push(
-            <Col key={card.uuid} className="mk-cell-btn" style={_style_} span={card.width}>
+            <div className={'ant-col mk-cell-btn ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
               <TabButton
                 btn={card}
                 BID={data.$$BID}
@@ -943,23 +943,23 @@
                 disabled={_disabled}
                 selectedData={_data}
               />
-            </Col>
+            </div>
           )
         } else if (card.OpenType === 'innerpage') {
           contents.push(
-            <Col key={card.uuid} className="mk-cell-btn" style={_style_} span={card.width}>
+            <div className={'ant-col mk-cell-btn ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
               <NewPageButton
                 btn={card}
                 BData={data.$$BData || ''}
                 disabled={_disabled}
                 selectedData={_data}
               />
-            </Col>
+            </div>
           )
         } else if (card.OpenType === 'funcbutton') {
           if (card.funcType === 'changeuser' || card.funcType === 'closetab') {
             contents.push(
-              <Col key={card.uuid} className="mk-cell-btn" style={_style_} span={card.width}>
+              <div className={'ant-col mk-cell-btn ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
                 <ChangeUserButton
                   btn={card}
                   BID={data.$$BID}
@@ -968,11 +968,11 @@
                   setting={cards.setting}
                   selectedData={_data}
                 />
-              </Col>
+              </div>
             )
           } else if (card.funcType === 'print') {
             contents.push(
-              <Col key={card.uuid} className="mk-cell-btn" style={_style_} span={card.width}>
+              <div className={'ant-col mk-cell-btn ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
                 <PrintButton
                   btn={card}
                   BID={data.$$BID}
@@ -982,11 +982,11 @@
                   columns={cards.columns}
                   selectedData={_data}
                 />
-              </Col>
+              </div>
             )
           } else if (card.funcType === 'megvii') {
             contents.push(
-              <Col key={card.uuid} className="mk-cell-btn" style={_style_} span={card.width}>
+              <div className={'ant-col mk-cell-btn ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
                 <FuncMegvii
                   btn={card}
                   BID={data.$$BID}
@@ -994,11 +994,11 @@
                   setting={cards.setting}
                   selectedData={_data}
                 />
-              </Col>
+              </div>
             )
           } else if (card.funcType === 'filezip') {
             contents.push(
-              <Col key={card.uuid} className="mk-cell-btn" style={_style_} span={card.width}>
+              <div className={'ant-col mk-cell-btn ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
                 <FuncZip
                   btn={card}
                   BID={data.$$BID}
@@ -1006,7 +1006,7 @@
                   setting={cards.setting}
                   selectedData={_data}
                 />
-              </Col>
+              </div>
             )
           }
         }
@@ -1022,6 +1022,7 @@
     return (
       <div className={'card-cell-list ' + (cardCell && cardCell.setting && cardCell.setting.layout === 'flex' ? 'mk-flex' : '')}>
         {this.getContent()}
+        <Col style={{display: 'none'}} span={24}></Col>
       </div>
     )
   }
diff --git a/src/tabviews/custom/components/card/data-card/index.jsx b/src/tabviews/custom/components/card/data-card/index.jsx
index f4023d3..1fee1e4 100644
--- a/src/tabviews/custom/components/card/data-card/index.jsx
+++ b/src/tabviews/custom/components/card/data-card/index.jsx
@@ -15,6 +15,7 @@
 import './index.scss'
 
 const CardItem = asyncComponent(() => import('../cardItem'))
+const TableHeader = asyncComponent(() => import('../tableHeader'))
 const MainAction = asyncComponent(() => import('@/tabviews/zshare/actionList'))
 const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader'))
 
@@ -32,6 +33,7 @@
     search: null,              // 鎼滅储鏉′欢
     pageIndex: 1,              // 椤电爜
     pageSize: 10,
+    orderBy: '',
     pageOptions: [],
     activeKey: '',             // 閫変腑鍗�
     selectKeys: [],            // 澶氶�夋椂閫変腑鍗$墖
@@ -578,7 +580,7 @@
    */
   queryModuleParam = (menuId, callback) => {
     const { mainSearch } = this.props
-    const { arr_field, config, search } = this.state
+    const { arr_field, config, search, orderBy } = this.state
 
     if (config.uuid !== menuId) return
 
@@ -594,7 +596,7 @@
 
     callback({
       arr_field: arr_field,
-      orderBy: config.setting.order || '',
+      orderBy: orderBy ||config.setting.order || '',
       search: searches,
       menuName: config.name
     })
@@ -602,7 +604,7 @@
 
   async loadData (id, type) {
     const { mainSearch } = this.props
-    const { config, arr_field, pageIndex, pageSize, search, BID, BData, selected } = this.state
+    const { config, arr_field, pageIndex, pageSize, search, BID, BData, selected, orderBy } = this.state
 
     if (config.setting.supModule && !BID && config.wrap.supKey !== 'false') { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
       this.loaded = true
@@ -654,7 +656,7 @@
       })
     }
 
-    let _orderBy = config.setting.order || ''
+    let _orderBy = orderBy || config.setting.order || ''
     let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, pageIndex, pageSize, BID)
 
     let result = await Api.genericInterface(param)
@@ -757,7 +759,7 @@
    */ 
   async loadLinedata (id) {
     const { mainSearch } = this.props
-    const { config, arr_field, pageIndex, pageSize, search, BID, BData } = this.state
+    const { config, arr_field, pageIndex, pageSize, search, BID, BData, orderBy } = this.state
 
     let searches = fromJS(search).toJS()
     if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
@@ -773,7 +775,7 @@
       loading: true
     })
 
-    let _orderBy = config.setting.order || ''
+    let _orderBy = orderBy || config.setting.order || ''
     let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, pageIndex, pageSize, BID, id)
 
     let result = await Api.genericInterface(param)
@@ -928,6 +930,14 @@
     }
   }
 
+  refreshByHeader = (sorter) => {
+    this.setState({
+      orderBy: sorter || ''
+    }, () => {
+      this.loadData()
+    })
+  }
+
   render() {
     const { config, precards, nextcards, loading, data, pageIndex, pageSize, total, card, activeKey, BID, BData, selectedData, selectKeys } = this.state
 
@@ -977,9 +987,11 @@
           <Row className={'card-row-list ' + config.wrap.layout}>
             {precards.map((item, index) => (
               <Col key={'pre' + index} className="extend-card" span={item.setting.width || 6}>
-                <CardItem card={item} cards={config} data={extendData}>
+                {item.setting.cardRole === 'header' ? <TableHeader card={item} data={extendData} refresh={this.refreshByHeader}>
                   {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
-                </CardItem>
+                </TableHeader> : <CardItem card={item} cards={config} data={extendData}>
+                  {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
+                </CardItem>}
               </Col>
             ))}
             {data && data.map((item, index) => {
@@ -1007,9 +1019,11 @@
             })}
             {nextcards.map((item, index) => (
               <Col key={'next' + index} className="extend-card" span={item.setting.width || 6}>
-                <CardItem card={item} cards={config} data={extendData}>
+                {item.setting.cardRole === 'header' ? <TableHeader card={item} data={extendData} refresh={this.refreshByHeader}>
                   {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
-                </CardItem>
+                </TableHeader> : <CardItem card={item} cards={config} data={extendData}>
+                  {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
+                </CardItem>}
               </Col>
             ))}
           </Row>
diff --git a/src/tabviews/custom/components/card/double-data-card/index.jsx b/src/tabviews/custom/components/card/double-data-card/index.jsx
index b06a81c..917346e 100644
--- a/src/tabviews/custom/components/card/double-data-card/index.jsx
+++ b/src/tabviews/custom/components/card/double-data-card/index.jsx
@@ -13,6 +13,7 @@
 import './index.scss'
 
 const CardItem = asyncComponent(() => import('../cardItem'))
+const TableHeader = asyncComponent(() => import('../tableHeader'))
 const MainAction = asyncComponent(() => import('@/tabviews/zshare/actionList'))
 const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader'))
 
@@ -29,6 +30,7 @@
     search: null,              // 鎼滅储鏉′欢
     pageIndex: 1,              // 椤电爜
     pageSize: 10,
+    orderBy: '',
     pageOptions: [],
     activeKey: '',             // 閫変腑鍗�
     selectKeys: [],            // 澶氶�夋椂閫変腑鍗$墖
@@ -445,7 +447,7 @@
    */
   queryModuleParam = (menuId, callback) => {
     const { mainSearch } = this.props
-    const { arr_field, config, search } = this.state
+    const { arr_field, config, search, orderBy } = this.state
 
     if (config.uuid !== menuId) return
 
@@ -461,7 +463,7 @@
 
     callback({
       arr_field: arr_field,
-      orderBy: config.setting.order || '',
+      orderBy: orderBy || config.setting.order || '',
       search: searches,
       menuName: config.name
     })
@@ -469,7 +471,7 @@
 
   async loadData (id, type) {
     const { mainSearch } = this.props
-    const { config, arr_field, pageIndex, pageSize, search, BID, BData, selected, card } = this.state
+    const { config, arr_field, pageIndex, pageSize, search, BID, BData, selected, card, orderBy } = this.state
 
     if (config.setting.supModule && !BID && config.wrap.supKey !== 'false') { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
       this.loaded = true
@@ -519,7 +521,7 @@
       })
     }
 
-    let _orderBy = config.setting.order || ''
+    let _orderBy = orderBy || config.setting.order || ''
     let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, pageIndex, pageSize, BID)
 
     let result = await Api.genericInterface(param)
@@ -674,7 +676,7 @@
    */ 
   async loadLinedata (id) {
     const { mainSearch } = this.props
-    const { config, arr_field, pageIndex, pageSize, search, BID, BData } = this.state
+    const { config, arr_field, pageIndex, pageSize, search, BID, BData, orderBy } = this.state
 
     let searches = fromJS(search).toJS()
     if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
@@ -690,7 +692,7 @@
       loading: true
     })
 
-    let _orderBy = config.setting.order || ''
+    let _orderBy = orderBy || config.setting.order || ''
     let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, pageIndex, pageSize, BID, id)
 
     let result = await Api.genericInterface(param)
@@ -874,6 +876,14 @@
     }
   }
 
+  refreshByHeader = (sorter) => {
+    this.setState({
+      orderBy: sorter || ''
+    }, () => {
+      this.loadData()
+    })
+  }
+
   render() {
     const { config, precards, nextcards, loading, data, pageIndex, pageSize, total, card, activeKey, BID, BData, selectedData, selectKeys, subcard, subconfig, wrapStyle, opens } = this.state
 
@@ -922,9 +932,11 @@
             <Row className={'card-row-list '}>
               {precards.map((item, index) => (
                 <Col key={'pre' + index} className="extend-card" span={item.setting.width || 6}>
-                  <CardItem card={item} cards={config} data={extendData}>
+                  {item.setting.cardRole === 'header' ? <TableHeader card={item} data={extendData} refresh={this.refreshByHeader}>
                     {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
-                  </CardItem>
+                  </TableHeader> : <CardItem card={item} cards={config} data={extendData}>
+                    {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
+                  </CardItem>}
                 </Col>
               ))}
               {data && data.map((item, index) => {
@@ -969,9 +981,11 @@
               })}
               {nextcards.map((item, index) => (
                 <Col key={'next' + index} className="extend-card" span={item.setting.width || 6}>
-                  <CardItem card={item} cards={config} data={extendData}>
+                  {item.setting.cardRole === 'header' ? <TableHeader card={item} data={extendData} refresh={this.refreshByHeader}>
                     {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
-                  </CardItem>
+                  </TableHeader> : <CardItem card={item} cards={config} data={extendData}>
+                    {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
+                  </CardItem>}
                 </Col>
               ))}
             </Row>
diff --git a/src/tabviews/custom/components/card/tableHeader/index.jsx b/src/tabviews/custom/components/card/tableHeader/index.jsx
new file mode 100644
index 0000000..c3e229f
--- /dev/null
+++ b/src/tabviews/custom/components/card/tableHeader/index.jsx
@@ -0,0 +1,160 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons'
+
+import './index.scss'
+
+class TableHeader extends Component {
+  static propTpyes = {
+    card: PropTypes.object,     // 鍗$墖閰嶇疆淇℃伅
+    data: PropTypes.object,
+    refresh: PropTypes.func
+  }
+
+  state = {
+    sortField: '',
+    order: ''
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢鍒濆鍖�
+   */
+  UNSAFE_componentWillMount () {
+
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState)) || !is(fromJS(this.props), fromJS(nextProps))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  triggerHeader = (item) => {
+    const { sortField, order } = this.state
+
+    if (!item.sortField) return
+
+    if (item.sortField !== sortField) {
+      this.setState({sortField: item.sortField, order: 'asc'})
+
+      this.props.refresh(item.sortField + ' asc')
+    } else {
+      if (order === 'asc') {
+        this.setState({order: 'desc'})
+        this.props.refresh(item.sortField + ' desc')
+      } else if (order === 'desc') {
+        this.setState({sortField: '', order: ''})
+        this.props.refresh('')
+      }
+    }
+  }
+
+  getContent = () => {
+    const { data, card } = this.props
+    const { sortField, order } = this.state
+
+    let contents = []
+
+    card.elements.forEach(item => {
+      if (item.eleType !== 'text') return
+
+      let _style_ = null
+
+      if (item.style && item.style.clear === 'left') {
+        _style_ = {clear: 'left'}
+      }
+
+      let val = ''
+      let _style = item.style ? {...item.style} : {}
+
+      if (item.datatype === 'static') {
+        val = item.value || ''
+        if (/@username@|@fullName@|@mk_city@|@bid@/ig.test(val)) {
+          let userName = sessionStorage.getItem('User_Name') || ''
+          let fullName = sessionStorage.getItem('Full_Name') || ''
+          let city = sessionStorage.getItem('city') || ''
+          let bid = data.$$BID || ''
+          val = val.replace(/@username@/ig, userName).replace(/@fullName@/ig, fullName).replace(/@mk_city@/ig, city).replace(/@bid@/ig, bid)
+        } else if (/@month@/ig.test(val)) {
+          val = val.replace(/@month@/ig, new Date().toLocaleString('en-US', { month: 'long' }))
+        } else if (/@week@/ig.test(val)) {
+          val = val.replace(/@week@/ig, (() => {
+            let day = new Date().getDay()
+            let weeks = ['鏄熸湡鏃�', '鏄熸湡涓�', '鏄熸湡浜�', '鏄熸湡涓�', '鏄熸湡鍥�', '鏄熸湡浜�', '鏄熸湡鍏�']
+            return weeks[day]
+          })())
+        } else if (/@day@/ig.test(val)) {
+          val = val.replace(/@day@/ig, (() => {
+            let day = new Date().getDate()
+            return day < 10 ? '0' + day : day
+          })())
+        }
+      } else if (data.hasOwnProperty(item.field)) {
+        val = data[item.field]
+      }
+
+      if (val === '' && item.noValue === 'hide') { // 绌哄�奸殣钘�
+        return null
+      }
+
+      if (val !== '') {
+        if (item.sortField) {
+          val = <>
+            <span className="mk-content">{item.prefix || ''}{val}{item.postfix || ''}</span>
+            <span className="sort-wrap"><CaretUpOutlined /><CaretDownOutlined /></span>
+          </>
+        } else {
+          val = <span>{item.prefix || ''}{val}{item.postfix || ''}</span>
+        }
+      }
+
+      let lineStyle = {height: item.innerHeight || 'auto', display: 'flex', alignItems: 'center', justifyContent: _style.textAlign || 'left'}
+
+      let extra = ''
+      if (item.sortField) {
+        extra = ' sortable'
+
+        if (item.sortField === sortField) {
+          if (order === 'asc') {
+            extra += ' up-sort'
+          } else {
+            extra += ' down-sort'
+          }
+        }
+      }
+
+      contents.push(
+        <div className={'ant-col ant-col-' + item.width + extra} onClick={() => this.triggerHeader(item)} key={item.uuid} style={_style_} span={item.width}>
+          <div style={_style}>
+            <div className={'ant-mk-text mk-header-cell line' + (item.height || '')} style={lineStyle}>{val}</div>
+          </div>
+        </div>
+      )
+    })
+
+    return contents
+  }
+
+  render() {
+    const { card, children } = this.props
+
+    return (
+      <div className={'card-item-box mk-table-header'} style={card.style}>
+        {children}
+        <div className={'card-cell-list ' + (card.setting.layout === 'flex' ? 'mk-flex' : '')}>
+          {this.getContent()}
+        </div>
+      </div>
+    )
+  }
+}
+
+export default TableHeader
\ No newline at end of file
diff --git a/src/tabviews/custom/components/card/tableHeader/index.scss b/src/tabviews/custom/components/card/tableHeader/index.scss
new file mode 100644
index 0000000..5abc071
--- /dev/null
+++ b/src/tabviews/custom/components/card/tableHeader/index.scss
@@ -0,0 +1,45 @@
+.card-item-box.mk-table-header {
+  position: relative;
+  overflow: hidden;
+
+  .mk-content {
+    display: inline-block;
+    white-space: normal;
+    max-width: calc(100% - 20px);
+  }
+  .sort-wrap {
+    position: relative;
+    margin-left: 10px;
+    font-size: 12px;
+    color: #bfbfbf;
+    display: inline-block;
+
+    .anticon-caret-up {
+      position: relative;
+      top: -3px;
+    }
+    .anticon-caret-down {
+      position: absolute;
+      top: 7px;
+      left: 0px;
+    }
+  }
+  .sortable {
+    cursor: pointer;
+  }
+  .sortable.up-sort {
+    .anticon-caret-up {
+      color: var(--mk-sys-color);
+    }
+  }
+  .sortable.down-sort {
+    .anticon-caret-down {
+      color: var(--mk-sys-color);
+    }
+  }
+  .sortable:hover {
+    .mk-content {
+      color: var(--mk-sys-color);
+    }
+  }
+}
diff --git a/src/tabviews/custom/index.jsx b/src/tabviews/custom/index.jsx
index cbf6415..01ff70b 100644
--- a/src/tabviews/custom/index.jsx
+++ b/src/tabviews/custom/index.jsx
@@ -1384,9 +1384,9 @@
     const { loadingview, viewlost, config, loading, shortcuts, BID } = this.state
 
     return (
-      <div className={'custom-page-wrap ' + (loadingview || loading ? 'loading' : '')} id={this.state.ContainerId} style={config ? config.style : null}>
+      <div className={`custom-page-wrap ${config && config.minWidth ? 'mk-scroll' : ''} ${loadingview || loading ? 'loading' : ''}`} id={this.state.ContainerId} style={config ? config.style : null}>
         {(loadingview || (loading && !config.$cache)) ? <Spin className="view-spin" size="large" /> : null}
-        <Row id={config ? 'menu' + config.uuid : ''} className="component-wrap">{this.getComponents()}</Row>
+        <Row id={config ? 'menu' + config.uuid : ''} style={config && config.minWidth ? {minWidth: config.minWidth} : null} className="component-wrap">{this.getComponents()}</Row>
         {config && config.interfaces.length > 0 ? <MkInterfaces BID={BID} interfaces={config.interfaces}/> : null}
         {config && window.GLOB.breakpoint ? <DebugTable /> : null}
         {!window.GLOB.mkHS && window.GLOB.systemType !== 'production' ? <TableNodes config={config} /> : null}
diff --git a/src/tabviews/custom/index.scss b/src/tabviews/custom/index.scss
index 6799e47..2c2a5fe 100644
--- a/src/tabviews/custom/index.scss
+++ b/src/tabviews/custom/index.scss
@@ -49,3 +49,8 @@
     display: none;
   }
 }
+.custom-page-wrap.mk-scroll {
+  height: calc(100vh - 93px);
+  overflow: auto;
+  margin: 0!important;
+}
diff --git a/src/tabviews/zshare/actionList/exceloutbutton/index.jsx b/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
index b96ad92..2192239 100644
--- a/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
@@ -713,6 +713,21 @@
           })
         }
 
+        if (btn.verify.wrapText === 'true' && data) {
+          let lines = data.length + 1
+          let start = 2
+          if (btn.verify.merge === 'true') {
+            lines = data.length + 2
+          }
+          for (let n = 0; n < cols.length; n++) {
+            for (let m = start; m <= lines; m++) {
+              if (ws[cols[n] + m] && !ws[cols[n] + m].s) {
+                ws[cols[n] + m].s = {alignment: { wrapText: true }}
+              }
+            }
+          }
+        }
+
         // ws["A1"].s = {fill: { bgColor: { rgb: "FFFFAA"  }}, font: { color: { rgb: "1890FF" } }}
 
         const wb = XLSX.utils.book_new()
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
index 09e0fe5..4919af0 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
@@ -282,6 +282,22 @@
                 </Radio.Group>)}
               </Form.Item>
             </Col> : null}
+            {btnType !== 'print' ? <Col span={8}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="Excel鍐呭鍖烘槸鍚﹁嚜鍔ㄦ崲琛屻��">
+                  <QuestionCircleOutlined className="mk-form-tip" />
+                  鑷姩鎹㈣
+                </Tooltip>
+              }>
+                {getFieldDecorator('wrapText', {
+                  initialValue: setting.wrapText || 'false'
+                })(
+                <Radio.Group>
+                  <Radio value="false">鍚�</Radio>
+                  <Radio value="true">鏄�</Radio>
+                </Radio.Group>)}
+              </Form.Item>
+            </Col> : null}
           </Row>
         </Form>
       </div>
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
index e307490..1ea9109 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -4,6 +4,7 @@
 import { Form, Tabs, Row, Col, Button, notification, Modal, message, InputNumber, Radio, Spin, Typography, Popconfirm } from 'antd'
 import { EditOutlined, StopOutlined, CheckCircleOutlined, SwapOutlined, DeleteOutlined } from '@ant-design/icons'
 import moment from 'moment'
+import md5 from 'md5'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -28,6 +29,7 @@
 
   state = {
     verify: {},
+    debugId: '',
     activeKey: 'setting',
     defaultscript: '', // 鑷畾涔夎剼鏈�
     excelColumns: [
@@ -995,7 +997,7 @@
   }
 
   sqlverify = (_resolve, _reject, scripts) => {
-    const { searches, verify } = this.state
+    const { searches, verify, debugId } = this.state
 
     if (verify.dataType !== 'custom') {
       _resolve()
@@ -1004,6 +1006,14 @@
 
     let timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
     let sql = SettingUtils.getDebugSql(verify, scripts, (verify.useSearch === 'true' ? searches : []), Utils, timestamp)
+
+    let _debugId = md5(sql)
+
+    if (debugId === _debugId) {
+      _resolve()
+      return
+    }
+
     let param = {
       func: 's_debug_sql',
       exec_type: 'y',
@@ -1015,6 +1025,7 @@
 
     Api.genericInterface(param).then(result => {
       if (result.status) {
+        this.setState({debugId: _debugId})
         _resolve()
       } else {
         _reject()
diff --git a/src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
index 832945f..83c35bc 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
@@ -4,6 +4,7 @@
 import { Form, Tabs, Row, Col, Button, notification, Modal, message, InputNumber, Input, Select, Radio, Tooltip, Typography, Popconfirm, Spin } from 'antd'
 import { QuestionCircleOutlined, EditOutlined, StopOutlined, CheckCircleOutlined, SwapOutlined, DeleteOutlined } from '@ant-design/icons'
 import moment from 'moment'
+import md5 from 'md5'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -33,6 +34,7 @@
 
   state = {
     verify: {},
+    debugId: '',
     templates: [],
     loading: false,
     activeKey: 'base',
@@ -611,10 +613,18 @@
   }
 
   sqlverify = (_resolve, _reject, scripts) => {
-    const { verify, declareSql } = this.state
+    const { verify, declareSql, debugId } = this.state
 
     let timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
     let sql = SettingUtils.getDebugSql(verify.setting || {}, verify.columns, scripts, declareSql, timestamp)
+
+    let _debugId = md5(sql)
+
+    if (debugId === _debugId) {
+      _resolve()
+      return
+    }
+
     let param = {
       func: 's_debug_sql',
       exec_type: 'y',
@@ -626,6 +636,7 @@
 
     Api.genericInterface(param).then(result => {
       if (result.status) {
+        this.setState({debugId: _debugId})
         _resolve()
       } else {
         _reject()
diff --git a/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx b/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
index d4eb344..4387911 100644
--- a/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
+++ b/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
@@ -18,7 +18,9 @@
           _type = 'text'
         }
       } else if (props.type === 'search') {
-        if (_type !== 'select') {
+        if (_type === 'date' || _type === 'datetime') {
+          _type = 'date'
+        } else if (_type !== 'select') {
           _type = 'text'
         }
       } else if (props.type === 'form') {
@@ -83,6 +85,7 @@
           <Radio.Group onChange={this.changeType} value={card.type} disabled={!card.selected || card.origin}>
             <Radio value="text">text</Radio>
             <Radio value="select">select</Radio>
+            <Radio value="date">date</Radio>
           </Radio.Group> : null
         }
         {type === 'columns' ?
diff --git a/src/templates/sharecomponent/fieldscomponent/index.jsx b/src/templates/sharecomponent/fieldscomponent/index.jsx
index 590e699..4d8d96f 100644
--- a/src/templates/sharecomponent/fieldscomponent/index.jsx
+++ b/src/templates/sharecomponent/fieldscomponent/index.jsx
@@ -106,10 +106,13 @@
       selectCards.forEach(item => {
         let _match = ''
         let initval = ''
-        if (item.type === 'select') {
+        let _type = item.type
+        if (item.type === 'date') {
+          _type = 'daterange'
+        } else if (item.type === 'select') {
           _match = '='
         } else {
-          item.type = 'text'
+          _type = 'text'
           _match = 'like'
         }
 
@@ -118,7 +121,7 @@
           label: item.label,
           field: item.field,
           initval: initval,
-          type: item.type,
+          type: _type,
           resourceType: '0',
           options: [],
           orderType: 'asc',
diff --git a/src/views/menudesign/menuform/index.jsx b/src/views/menudesign/menuform/index.jsx
index 7c8be79..0f4433b 100644
--- a/src/views/menudesign/menuform/index.jsx
+++ b/src/views/menudesign/menuform/index.jsx
@@ -193,47 +193,14 @@
         this.props.form.setFieldsValue({parentId: _id})
         this.props.updateConfig({...config, fstMenuId: value, parentId: _id})
       })
-    } else if (key === 'parentId') {
-      this.props.updateConfig({...config, parentId: value})
-    } else if (key === 'cacheUseful') {
-      this.props.updateConfig({...config, cacheUseful: value})
-    } else if (key === 'timeUnit') {
-      this.props.updateConfig({...config, timeUnit: value})
-    } else if (key === 'OpenType') {
-      this.props.updateConfig({...config, OpenType: value})
-    } else if (key === 'hidden') {
-      this.props.updateConfig({...config, hidden: value})
-    } else if (key === 'permission') {
-      this.props.updateConfig({...config, permission: value})
-    } else if (key === 'cacheLocal') {
-      this.props.updateConfig({...config, cacheLocal: value})
+    } else {
+      if (key === 'cacheTime' || key === 'minWidth') {
+        if (typeof(value) !== 'number') {
+          value = ''
+        }
+      }
+      this.props.updateConfig({...config, [key]: value})
     }
-  }
-
-  // 鑿滃崟鍚嶇О
-  changeName = (e) => {
-    this.props.updateConfig({...this.props.config, MenuName: e.target.value})
-  }
-
-  // 鑿滃崟鍙傛暟
-  changeNo = (e) => {
-    this.props.updateConfig({...this.props.config, MenuNo: e.target.value})
-  }
-
-  // 鍔╄鐮�
-  changeEasyCode = (e) => {
-    this.props.updateConfig({...this.props.config, easyCode: e.target.value})
-  }
-
-  changeRemark = (e) => {
-    this.props.updateConfig({...this.props.config, Remark: e.target.value})
-  }
-
-  changeCacheDay = (val) => {
-    if (typeof(val) !== 'number') {
-      val = ''
-    }
-    this.props.updateConfig({...this.props.config, cacheTime: val})
   }
 
   render() {
@@ -306,7 +273,7 @@
                     message: '璇疯緭鍏ヨ彍鍗曞悕绉�!'
                   }
                 ]
-              })(<Input placeholder="" autoComplete="off" onChange={this.changeName}/>)}
+              })(<Input placeholder="" autoComplete="off" onChange={(e) => {this.selectChange('MenuName', e.target.value)}}/>)}
             </Form.Item>
           </Col>
           <Col span={24}>
@@ -319,7 +286,7 @@
                     message: '璇疯緭鍏ヨ彍鍗曞弬鏁�!'
                   }
                 ]
-              })(<Input placeholder="" autoComplete="off" onChange={this.changeNo}/>)}
+              })(<Input placeholder="" autoComplete="off" onChange={(e) => {this.selectChange('MenuNo', e.target.value)}}/>)}
             </Form.Item>
           </Col>
           <Col span={24}>
@@ -336,6 +303,23 @@
                 <Radio.Group onChange={(e) => {this.selectChange('OpenType', e.target.value)}}>
                   <Radio value="newtab">鏍囩椤�</Radio>
                   <Radio value="newpage">鏂伴〉闈�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={24}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="璺宠繃鏉冮檺楠岃瘉鏃讹紝椤甸潰涓粍浠跺強鎸夐挳涓嶅湪杩涜鏉冮檺鎺у埗銆�">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鏉冮檺楠岃瘉
+              </Tooltip>
+            }>
+              {getFieldDecorator('permission', {
+                initialValue: config.permission || 'true'
+              })(
+                <Radio.Group onChange={(e) => {this.selectChange('permission', e.target.value)}}>
+                  <Radio value="true">浣跨敤</Radio>
+                  <Radio value="false">涓嶄娇鐢�</Radio>
                 </Radio.Group>
               )}
             </Form.Item>
@@ -374,23 +358,6 @@
               )}
             </Form.Item>
           </Col>
-          <Col span={24}>
-            <Form.Item label={
-              <Tooltip placement="topLeft" title="璺宠繃鏉冮檺楠岃瘉鏃讹紝椤甸潰涓粍浠跺強鎸夐挳涓嶅湪杩涜鏉冮檺鎺у埗銆�">
-                <QuestionCircleOutlined className="mk-form-tip" />
-                鏉冮檺楠岃瘉
-              </Tooltip>
-            }>
-              {getFieldDecorator('permission', {
-                initialValue: config.permission || 'true'
-              })(
-                <Radio.Group onChange={(e) => {this.selectChange('permission', e.target.value)}}>
-                  <Radio value="true">浣跨敤</Radio>
-                  <Radio value="false">涓嶄娇鐢�</Radio>
-                </Radio.Group>
-              )}
-            </Form.Item>
-          </Col>
           {config.cacheUseful === 'true' ? <Col span={24}>
             <Form.Item label="鍗曚綅">
               {getFieldDecorator('timeUnit', {
@@ -414,15 +381,29 @@
                   }
                 ]
               })(
-                <InputNumber min={1} max={config.timeUnit !== 'hour' ? 7 : 23} precision={0} onChange={this.changeCacheDay}/>
+                <InputNumber min={1} max={config.timeUnit !== 'hour' ? 7 : 23} precision={0} onChange={(val) => {this.selectChange('cacheTime', val)}}/>
               )}
             </Form.Item>
           </Col> : null}
           <Col span={24}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="濡傛灉椤甸潰鍐呭鍦ㄧ獥鍙d腑鏃犳硶瀹屽叏灞曠ず锛屽彲璁剧疆鏈�灏忓搴︼紝瀹炵幇椤甸潰鐨勬í鍚戞粴鍔ㄣ��">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鏈�灏忓搴�
+              </Tooltip>
+            }>
+              {getFieldDecorator('minWidth', {
+                initialValue: config.minWidth
+              })(
+                <InputNumber min={0} precision={0} onChange={(val) => {this.selectChange('minWidth', val)}}/>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={24}>
             <Form.Item label="鍔╄鐮�">
               {getFieldDecorator('easyCode', {
                 initialValue: config.easyCode
-              })(<Input placeholder="" autoComplete="off" onChange={this.changeEasyCode}/>)}
+              })(<Input placeholder="" autoComplete="off" onChange={(e) => {this.selectChange('easyCode', e.target.value)}}/>)}
             </Form.Item>
           </Col>
           <Col span={24}>
@@ -442,7 +423,7 @@
                     message: '澶囨敞鏈�澶�512涓瓧绗︼紒'
                   }
                 ]
-              })(<TextArea rows={2} placeholder={''} onChange={this.changeRemark} />)}
+              })(<TextArea rows={2} placeholder={''} onChange={(e) => {this.selectChange('Remark', e.target.value)}}/>)}
             </Form.Item>
           </Col>
         </Row>

--
Gitblit v1.8.0